@yamada-ui/react
Version:
React UI components of the Yamada, by the Yamada, for the Yamada built with React and Emotion
143 lines (139 loc) • 5.22 kB
JavaScript
"use client";
import { mergeRefs } from "../../utils/ref.js";
import { utils_exports } from "../../utils/index.js";
import { styled } from "../../core/system/factory.js";
import { mergeCSS } from "../../core/css/merge-css.js";
import { getClassName } from "../../core/components/utils.js";
import { createComponent } from "../../core/components/create-component.js";
import { getLoadingComponent, isLoadingScheme } from "../loading/use-loading-component.js";
import { buttonStyle } from "./button.style.js";
import { Ripple } from "../ripple/ripple.js";
import { useRipple } from "../ripple/use-ripple.js";
import { Children, cloneElement, isValidElement, useCallback, useMemo, useRef } from "react";
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
//#region src/components/button/button.tsx
const useButtonType = (value) => {
const buttonRef = useRef(!value);
return {
ref: useCallback((node) => {
if (node) buttonRef.current = node.tagName === "BUTTON";
}, []),
type: buttonRef.current ? "button" : void 0
};
};
const { component, ComponentContext, PropsContext: ButtonPropsContext, useComponentContext, usePropsContext: useButtonPropsContext, withContext } = createComponent("button", buttonStyle);
/**
* `Button` is an interactive component that allows users to perform actions such as submitting forms and toggling modals.
*
* @see https://yamada-ui.com/docs/components/button
*/
const Button = withContext(({ ref, as, active, children, disabled, disableRipple, endIcon = null, loading, loadingIcon = "oval", loadingMessage, loadingPlacement = "start", startIcon = null, iconProps, loadingProps,...rest }) => {
const trulyDisabled = disabled || loading;
const { ref: buttonRef, type } = useButtonType(as);
const { onClick,...rippleProps } = useRipple({
...rest,
disabled: disableRipple || trulyDisabled
});
const startLoading = loading && loadingPlacement === "start";
const endLoading = loading && loadingPlacement === "end";
return /* @__PURE__ */ jsx(ComponentContext, {
value: useMemo(() => ({
endIcon,
loadingIcon,
loadingMessage,
startIcon,
iconProps
}), [
loadingIcon,
loadingMessage,
startIcon,
endIcon,
iconProps
]),
children: /* @__PURE__ */ jsxs(styled.button, {
ref: mergeRefs(ref, buttonRef),
as,
type,
"data-active": (0, utils_exports.dataAttr)(active),
"data-loading": (0, utils_exports.dataAttr)(loading),
disabled: trulyDisabled,
...rest,
onClick,
children: [
startLoading ? /* @__PURE__ */ jsx(ButtonStartLoading, { ...loadingProps }) : null,
loading ? loadingMessage || /* @__PURE__ */ jsx(styled.span, {
opacity: 0,
children: /* @__PURE__ */ jsx(ButtonContent, { children })
}) : /* @__PURE__ */ jsx(ButtonContent, { children }),
endLoading ? /* @__PURE__ */ jsx(ButtonEndLoading, { ...loadingProps }) : null,
/* @__PURE__ */ jsx(Ripple, { ...rippleProps })
]
})
});
})();
const ButtonContent = component(({ children }) => {
const { endIcon, startIcon, iconProps } = useComponentContext();
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
startIcon ? /* @__PURE__ */ jsx(ButtonStartIcon, {
...iconProps,
children: startIcon
}) : null,
children,
endIcon ? /* @__PURE__ */ jsx(ButtonEndIcon, {
...iconProps,
children: endIcon
}) : null
] });
}, {
name: "ButtonContent",
className: getClassName((0, utils_exports.bem)("button", "content"))
})();
const ButtonLoading = component((props) => {
const { loadingIcon, loadingMessage } = useComponentContext();
const css = useMemo(() => ({ position: loadingMessage ? "relative" : "absolute" }), [loadingMessage]);
if (isLoadingScheme(loadingIcon)) return /* @__PURE__ */ jsx(getLoadingComponent(loadingIcon), {
color: "currentColor",
...props,
css: mergeCSS(css, props.css)
});
if (isValidElement(loadingIcon)) return cloneElement(loadingIcon, {
...props,
...loadingIcon.props,
css: mergeCSS(css, props.css, loadingIcon.props.css)
});
return null;
}, {
name: "ButtonLoading",
className: getClassName((0, utils_exports.bem)("button", "loading"))
})();
const ButtonStartLoading = component(ButtonLoading, {
name: "ButtonStartLoading",
className: getClassName((0, utils_exports.bem)("button", "loading", "start"))
})();
const ButtonEndLoading = component(ButtonLoading, {
name: "ButtonEndLoading",
className: getClassName((0, utils_exports.bem)("button", "loading", "end"))
})();
const ButtonIcon = component(({ children,...rest }) => {
if (isValidElement(children)) return cloneElement(children, {
"aria-hidden": true,
role: "img",
...rest,
...children.props
});
return Children.count(children) > 1 ? Children.only(null) : null;
}, {
name: "ButtonIcon",
className: getClassName((0, utils_exports.bem)("button", "icon"))
})();
const ButtonStartIcon = component(ButtonIcon, {
name: "ButtonStartIcon",
className: getClassName((0, utils_exports.bem)("button", "icon", "start"))
})();
const ButtonEndIcon = component(ButtonIcon, {
name: "ButtonEndIcon",
className: getClassName((0, utils_exports.bem)("button", "icon", "end"))
})();
//#endregion
export { Button, ButtonPropsContext, useButtonPropsContext };
//# sourceMappingURL=button.js.map