Skip to content

Commit

Permalink
Copy-paste chakra's button fixing fragments chrome issue
Browse files Browse the repository at this point in the history
I'm not happy at all with this, since it's just a copy-paste of the
original Button component, but changing the fragments with span.

Ideally this should be fixed in upstream, see: chakra-ui/chakra-ui#8238

refs #136
  • Loading branch information
elboletaire committed Jan 29, 2024
1 parent d1c1ffa commit 878ecae
Show file tree
Hide file tree
Showing 9 changed files with 185 additions and 10 deletions.
4 changes: 4 additions & 0 deletions packages/chakra-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
"@chakra-ui/progress": "^2.2.0",
"@chakra-ui/radio": "^2.1.2",
"@chakra-ui/react-use-disclosure": "^2.1.0",
"@chakra-ui/react-use-merge-refs": "^2.1.0",
"@chakra-ui/shared-utils": "^2.0.4",
"@chakra-ui/spinner": "^2.1.0",
"@chakra-ui/system": "2.6.2",
"@chakra-ui/table": "^2.1.0",
Expand All @@ -64,6 +66,8 @@
"@chakra-ui/progress": "^2.2.0",
"@chakra-ui/radio": "^2.1.2",
"@chakra-ui/react-use-disclosure": "^2.1.0",
"@chakra-ui/react-use-merge-refs": "^2.1.0",
"@chakra-ui/shared-utils": "^2.0.4",
"@chakra-ui/spinner": "^2.1.0",
"@chakra-ui/system": "2.6.2",
"@chakra-ui/table": "^2.1.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { IconButtonProps } from '@chakra-ui/button'
import { chakra, forwardRef } from '@chakra-ui/system'
import { forwardRef } from '@chakra-ui/system'
import { useActions, useClient, useElection } from '@vocdoni/react-providers'
import { areEqualHexStrings, ElectionStatus } from '@vocdoni/sdk'
import { Button } from '../../layout'

export const ActionCancel = forwardRef<IconButtonProps, 'button'>((props, ref) => {
const { account, localize } = useClient()
Expand All @@ -15,7 +16,7 @@ export const ActionCancel = forwardRef<IconButtonProps, 'button'>((props, ref) =
if (!election || (election && !areEqualHexStrings(election.organizationId, account?.address))) return null

return (
<chakra.button
<Button
ref={ref}
isLoading={loading}
onClick={cancel}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { IconButtonProps } from '@chakra-ui/button'
import { chakra, forwardRef } from '@chakra-ui/system'
import { forwardRef } from '@chakra-ui/system'
import { useActions, useClient, useElection } from '@vocdoni/react-providers'
import { areEqualHexStrings, ElectionStatus } from '@vocdoni/sdk'
import { Button } from '../../layout'

export const ActionContinue = forwardRef<IconButtonProps, 'button'>((props, ref) => {
const { account, localize } = useClient()
Expand All @@ -15,7 +16,7 @@ export const ActionContinue = forwardRef<IconButtonProps, 'button'>((props, ref)
if (!election || (election && !areEqualHexStrings(election.organizationId, account?.address))) return null

return (
<chakra.button
<Button
ref={ref}
isLoading={loading}
onClick={resume}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { IconButtonProps } from '@chakra-ui/button'
import { chakra, forwardRef } from '@chakra-ui/system'
import { forwardRef } from '@chakra-ui/system'
import { useActions, useClient, useElection } from '@vocdoni/react-providers'
import { areEqualHexStrings, ElectionStatus } from '@vocdoni/sdk'
import { Button } from '../../layout'

export const ActionEnd = forwardRef<IconButtonProps, 'button'>((props, ref) => {
const { account, localize } = useClient()
Expand All @@ -15,7 +16,7 @@ export const ActionEnd = forwardRef<IconButtonProps, 'button'>((props, ref) => {
if (!election || (election && !areEqualHexStrings(election.organizationId, account?.address))) return null

return (
<chakra.button
<Button
ref={ref}
isLoading={loading}
onClick={end}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { IconButtonProps } from '@chakra-ui/button'
import { chakra, forwardRef } from '@chakra-ui/system'
import { forwardRef } from '@chakra-ui/system'
import { useActions, useClient, useElection } from '@vocdoni/react-providers'
import { areEqualHexStrings, ElectionStatus } from '@vocdoni/sdk'
import { Button } from '../../layout'

export const ActionPause = forwardRef<IconButtonProps, 'button'>((props, ref) => {
const { account, localize } = useClient()
Expand All @@ -15,7 +16,7 @@ export const ActionPause = forwardRef<IconButtonProps, 'button'>((props, ref) =>
if (!election || (election && !areEqualHexStrings(election.organizationId, account?.address))) return null

return (
<chakra.button
<Button
ref={ref}
isLoading={loading}
onClick={pause}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Button } from '@chakra-ui/button'
import { FormControl, FormErrorMessage, FormHelperText, FormLabel } from '@chakra-ui/form-control'
import { Input } from '@chakra-ui/input'
import {
Expand All @@ -18,6 +17,7 @@ import { errorToString, useClient, useElection, walletFromRow } from '@vocdoni/r
import { ArchivedElection, dotobject, VocdoniSDKClient } from '@vocdoni/sdk'
import { useEffect, useState } from 'react'
import { useForm } from 'react-hook-form'
import { Button } from '../layout/Button'

export const SpreadsheetAccess = (rest: ChakraProps) => {
const { isOpen, onOpen, onClose } = useDisclosure()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Button, ButtonProps } from '@chakra-ui/button'
import { ButtonProps } from '@chakra-ui/button'
import { Signer } from '@ethersproject/abstract-signer'
import { useClient, useElection } from '@vocdoni/react-providers'
import { ArchivedElection, ElectionStatus, InvalidElection } from '@vocdoni/sdk'
import { useState } from 'react'
import { Button } from '../layout/Button'
import { SpreadsheetAccess } from './SpreadsheetAccess'

export const VoteButton = (props: ButtonProps) => {
Expand Down
165 changes: 165 additions & 0 deletions packages/chakra-components/src/components/layout/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
import { ButtonOptions, ButtonSpinner, useButtonGroup } from '@chakra-ui/button'
import { useMergeRefs } from '@chakra-ui/react-use-merge-refs'
import { cx, dataAttr } from '@chakra-ui/shared-utils'
import {
chakra,
forwardRef,
HTMLChakraProps,
omitThemingProps,
SystemStyleObject,
ThemingProps,
useStyleConfig,
} from '@chakra-ui/system'
import { cloneElement, isValidElement, useCallback, useMemo, useState } from 'react'

export interface ButtonProps extends HTMLChakraProps<'button'>, ButtonOptions, ThemingProps<'Button'> {}

/**
* Button component is used to trigger an action or event, such as submitting a form, opening a Dialog, canceling an action, or performing a delete operation.
*
* @see Docs https://chakra-ui.com/docs/components/button
* @see WAI-ARIA https://www.w3.org/WAI/ARIA/apg/patterns/button/
*/
export const Button = forwardRef<ButtonProps, 'button'>((props, ref) => {
const group = useButtonGroup()
const styles = useStyleConfig('Button', { ...group, ...props })

const {
isDisabled = group?.isDisabled,
isLoading,
isActive,
children,
leftIcon,
rightIcon,
loadingText,
iconSpacing = '0.5rem',
type,
spinner,
spinnerPlacement = 'start',
className,
as,
...rest
} = omitThemingProps(props)

/**
* When button is used within ButtonGroup (i.e. flushed with sibling buttons),
* it is important to add a `zIndex` on focus.
*
* So let's read the component styles and then add `zIndex` to it.
*/
const buttonStyles: SystemStyleObject = useMemo(() => {
// @ts-ignore
const _focus = { ...styles?.['_focus'], zIndex: 1 }
return {
display: 'inline-flex',
appearance: 'none',
alignItems: 'center',
justifyContent: 'center',
userSelect: 'none',
position: 'relative',
whiteSpace: 'nowrap',
verticalAlign: 'middle',
outline: 'none',
...styles,
...(!!group && { _focus }),
}
}, [styles, group])

const { ref: _ref, type: defaultType } = useButtonType(as)

const contentProps = { rightIcon, leftIcon, iconSpacing, children }

return (
<chakra.button
ref={useMergeRefs(ref, _ref)}
as={as}
type={type ?? defaultType}
data-active={dataAttr(isActive)}
data-loading={dataAttr(isLoading)}
__css={buttonStyles}
className={cx('chakra-button', className)}
{...rest}
disabled={isDisabled || isLoading}
>
{isLoading && spinnerPlacement === 'start' && (
<ButtonSpinner
className='chakra-button__spinner--start'
label={loadingText}
placement='start'
spacing={iconSpacing}
>
{spinner}
</ButtonSpinner>
)}

{isLoading ? (
loadingText || (
<chakra.span opacity={0}>
<ButtonContent {...contentProps} />
</chakra.span>
)
) : (
<ButtonContent {...contentProps} />
)}

{isLoading && spinnerPlacement === 'end' && (
<ButtonSpinner
className='chakra-button__spinner--end'
label={loadingText}
placement='end'
spacing={iconSpacing}
>
{spinner}
</ButtonSpinner>
)}
</chakra.button>
)
})

Button.displayName = 'Button'

type ButtonContentProps = Pick<ButtonProps, 'leftIcon' | 'rightIcon' | 'children' | 'iconSpacing'>

function ButtonContent(props: ButtonContentProps) {
const { leftIcon, rightIcon, children, iconSpacing } = props

// using fragments here causes google chrome to crash while using translate
return (
<span>
{leftIcon && <ButtonIcon marginEnd={iconSpacing}>{leftIcon}</ButtonIcon>}
{children}
{rightIcon && <ButtonIcon marginStart={iconSpacing}>{rightIcon}</ButtonIcon>}
</span>
)
}

export function ButtonIcon(props: HTMLChakraProps<'span'>) {
const { children, className, ...rest } = props

const _children = isValidElement(children)
? cloneElement<any>(children, {
'aria-hidden': true,
focusable: false,
})
: children

const _className = cx('chakra-button__icon', className)

return (
<chakra.span display='inline-flex' alignSelf='center' flexShrink={0} {...rest} className={_className}>
{_children}
</chakra.span>
)
}

ButtonIcon.displayName = 'ButtonIcon'

export function useButtonType(value?: React.ElementType) {
const [isButton, setIsButton] = useState(!value)
const refCallback = useCallback((node: HTMLElement | null) => {
if (!node) return
setIsButton(node.tagName === 'BUTTON')
}, [])
const type = isButton ? 'button' : undefined
return { ref: refCallback, type } as const
}
1 change: 1 addition & 0 deletions packages/chakra-components/src/components/layout/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './Button'
export * from './ConfirmModal'
export * from './HR'
export * from './Image'
Expand Down

0 comments on commit 878ecae

Please sign in to comment.