UNPKG

@yamada-ui/react

Version:

React UI components of the Yamada, by the Yamada, for the Yamada built with React and Emotion

1 lines 10.5 kB
{"version":3,"file":"button.cjs","names":["createComponent","buttonStyle","useRipple","styled","mergeRefs","Ripple","getClassName","isLoadingScheme","getLoadingComponent","mergeCSS","Children"],"sources":["../../../../src/components/button/button.tsx"],"sourcesContent":["\"use client\"\n\nimport type { ElementType, PropsWithChildren, ReactNode } from \"react\"\nimport type {\n CSSObject,\n HTMLProps,\n HTMLStyledProps,\n ThemeProps,\n} from \"../../core\"\nimport type { Loading } from \"../loading\"\nimport type { ButtonStyle } from \"./button.style\"\nimport {\n Children,\n cloneElement,\n isValidElement,\n useCallback,\n useMemo,\n useRef,\n} from \"react\"\nimport { createComponent, getClassName, mergeCSS, styled } from \"../../core\"\nimport { bem, dataAttr, mergeRefs } from \"../../utils\"\nimport { getLoadingComponent, isLoadingScheme } from \"../loading\"\nimport { Ripple, useRipple } from \"../ripple\"\nimport { buttonStyle } from \"./button.style\"\n\ninterface ComponentContext\n extends Pick<\n ButtonProps,\n \"endIcon\" | \"iconProps\" | \"loadingIcon\" | \"loadingMessage\" | \"startIcon\"\n > {}\n\nconst useButtonType = (value?: ElementType) => {\n const buttonRef = useRef(!value)\n\n const ref = useCallback((node: HTMLElement | null) => {\n if (node) buttonRef.current = node.tagName === \"BUTTON\"\n }, [])\n\n const type = buttonRef.current ? \"button\" : undefined\n\n return { ref, type } as const\n}\n\nexport interface ButtonProps\n extends HTMLStyledProps<\"button\">,\n ThemeProps<ButtonStyle> {\n /**\n * The type of button. Accepts `button`, `reset`, or `submit`.\n *\n * @default 'button'\n */\n type?: HTMLProps<\"button\">[\"type\"]\n /**\n * If `true`, the button is represented as active.\n *\n * @default false\n */\n active?: boolean\n /**\n * If `true`, the button is disabled.\n *\n * @default false\n */\n disabled?: boolean\n /**\n * If `true`, disable ripple effects when pressing a element.\n *\n * @default false\n */\n disableRipple?: boolean\n /**\n * The icon to display at the end side of the button.\n */\n endIcon?: ReactNode\n /**\n * If `true`, the loading state of the button is represented.\n *\n * @default false\n */\n loading?: boolean\n /**\n * The icon to display when the button is loading.\n *\n * @default 'oval'\n */\n loadingIcon?: Loading.Scheme | ReactNode\n /**\n * The message to display when the button is loading.\n */\n loadingMessage?: ReactNode\n /**\n * The placement of the loading indicator. Accepts `start` or `end`.\n *\n * @default 'start'\n */\n loadingPlacement?: \"end\" | \"start\"\n /**\n * The icon to display at the start side of the button.\n */\n startIcon?: ReactNode\n /**\n * The props of the icon element.\n */\n iconProps?: ButtonIconProps\n /**\n * The props of the loading icon element.\n */\n loadingProps?: ButtonLoadingProps\n}\n\nconst {\n component,\n ComponentContext,\n PropsContext: ButtonPropsContext,\n useComponentContext,\n usePropsContext: useButtonPropsContext,\n withContext,\n} = createComponent<ButtonProps, ButtonStyle, ComponentContext>(\n \"button\",\n buttonStyle,\n)\n\nexport { ButtonPropsContext, useButtonPropsContext }\n\n/**\n * `Button` is an interactive component that allows users to perform actions such as submitting forms and toggling modals.\n *\n * @see https://yamada-ui.com/docs/components/button\n */\nexport const Button = withContext<\"button\", ButtonProps>(\n ({\n ref,\n as,\n active,\n children,\n disabled,\n disableRipple,\n endIcon = null,\n loading,\n loadingIcon = \"oval\",\n loadingMessage,\n loadingPlacement = \"start\",\n startIcon = null,\n iconProps,\n loadingProps,\n ...rest\n }) => {\n const trulyDisabled = disabled || loading\n const { ref: buttonRef, type } = useButtonType(as)\n const { onClick, ...rippleProps } = useRipple({\n ...rest,\n disabled: disableRipple || trulyDisabled,\n })\n const startLoading = loading && loadingPlacement === \"start\"\n const endLoading = loading && loadingPlacement === \"end\"\n\n const context = useMemo(\n () => ({ endIcon, loadingIcon, loadingMessage, startIcon, iconProps }),\n [loadingIcon, loadingMessage, startIcon, endIcon, iconProps],\n )\n\n return (\n <ComponentContext value={context}>\n <styled.button\n ref={mergeRefs(ref, buttonRef)}\n as={as}\n type={type}\n data-active={dataAttr(active)}\n data-loading={dataAttr(loading)}\n disabled={trulyDisabled}\n {...rest}\n onClick={onClick}\n >\n {startLoading ? <ButtonStartLoading {...loadingProps} /> : null}\n\n {loading ? (\n loadingMessage || (\n <styled.span opacity={0}>\n <ButtonContent>{children}</ButtonContent>\n </styled.span>\n )\n ) : (\n <ButtonContent>{children}</ButtonContent>\n )}\n\n {endLoading ? <ButtonEndLoading {...loadingProps} /> : null}\n\n <Ripple {...rippleProps} />\n </styled.button>\n </ComponentContext>\n )\n },\n)()\n\nconst ButtonContent = component<\"fragment\", PropsWithChildren>(\n ({ children }) => {\n const { endIcon, startIcon, iconProps } = useComponentContext()\n\n return (\n <>\n {startIcon ? (\n <ButtonStartIcon {...iconProps}>{startIcon}</ButtonStartIcon>\n ) : null}\n {children}\n {endIcon ? (\n <ButtonEndIcon {...iconProps}>{endIcon}</ButtonEndIcon>\n ) : null}\n </>\n )\n },\n { name: \"ButtonContent\", className: getClassName(bem(\"button\", \"content\")) },\n)()\n\ninterface ButtonLoadingProps extends HTMLStyledProps<\"svg\"> {}\n\nconst ButtonLoading = component<\"svg\", ButtonLoadingProps>(\n (props) => {\n const { loadingIcon, loadingMessage } = useComponentContext()\n\n const css = useMemo<CSSObject>(\n () => ({\n position: loadingMessage ? \"relative\" : \"absolute\",\n }),\n [loadingMessage],\n )\n\n if (isLoadingScheme(loadingIcon)) {\n const Component = getLoadingComponent(loadingIcon)\n\n return (\n <Component\n color=\"currentColor\"\n {...props}\n css={mergeCSS(css, props.css)}\n />\n )\n }\n\n if (isValidElement<HTMLStyledProps<\"svg\">>(loadingIcon))\n return cloneElement(loadingIcon, {\n ...props,\n ...loadingIcon.props,\n css: mergeCSS(css, props.css, loadingIcon.props.css),\n })\n\n return null\n },\n { name: \"ButtonLoading\", className: getClassName(bem(\"button\", \"loading\")) },\n)()\n\nconst ButtonStartLoading = component<\"svg\", ButtonLoadingProps>(ButtonLoading, {\n name: \"ButtonStartLoading\",\n className: getClassName(bem(\"button\", \"loading\", \"start\")),\n})()\n\nconst ButtonEndLoading = component<\"svg\", ButtonLoadingProps>(ButtonLoading, {\n name: \"ButtonEndLoading\",\n className: getClassName(bem(\"button\", \"loading\", \"end\")),\n})()\n\ninterface ButtonIconProps extends HTMLStyledProps<\"svg\"> {}\n\nconst ButtonIcon = component<\"svg\", ButtonIconProps>(\n ({ children, ...rest }) => {\n if (isValidElement<HTMLProps<\"svg\">>(children))\n return cloneElement(children, {\n \"aria-hidden\": true,\n role: \"img\",\n ...rest,\n ...children.props,\n })\n\n return Children.count(children) > 1 ? Children.only(null) : null\n },\n { name: \"ButtonIcon\", className: getClassName(bem(\"button\", \"icon\")) },\n)()\n\nconst ButtonStartIcon = component<\"svg\", ButtonIconProps>(ButtonIcon, {\n name: \"ButtonStartIcon\",\n className: getClassName(bem(\"button\", \"icon\", \"start\")),\n})()\n\nconst ButtonEndIcon = component<\"svg\", ButtonIconProps>(ButtonIcon, {\n name: \"ButtonEndIcon\",\n className: getClassName(bem(\"button\", \"icon\", \"end\")),\n})()\n"],"mappings":"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"}