@nex-ui/react
Version:
🎉 A beautiful, modern, and reliable React component library.
175 lines (171 loc) • 6.01 kB
JavaScript
"use client";
;
var jsxRuntime = require('react/jsx-runtime');
var icons = require('@nex-ui/icons');
var hooks = require('@nex-ui/hooks');
var styled = require('@nex-ui/styled');
var react = require('react');
var utils = require('@nex-ui/utils');
var Context = require('../provider/Context.cjs');
var useDefaultProps = require('../utils/useDefaultProps.cjs');
var useStyles = require('../utils/useStyles.cjs');
var useSlotProps = require('../utils/useSlotProps.cjs');
var Ripple = require('../utils/ripple/Ripple.cjs');
var composeClasses = require('../utils/composeClasses.cjs');
var button = require('../../theme/recipes/button.cjs');
var getUtilityClass = require('../utils/getUtilityClass.cjs');
const useSlotClasses = (ownerState)=>{
const { prefix } = Context.useNexUI();
const btnRoot = `${prefix}-btn`;
const { color, variant, radius, size, iconOnly, loading, disabled, fullWidth, classes, disableRipple } = ownerState;
const slots = {
root: [
'root',
`variant-${variant}`,
`radius-${radius}`,
`size-${size}`,
`color-${color}`,
iconOnly && `icon-only`,
loading && `loading`,
disabled && `disabled`,
fullWidth && `full-width`,
disableRipple && 'disable-ripple'
],
startIcon: [
`icon`,
`start-icon`,
`icon-size-${size}`,
loading && `icon-loading`
],
endIcon: [
`icon`,
`end-icon`,
`icon-size-${size}`
]
};
const composedClasses = composeClasses.composeClasses(slots, getUtilityClass.getUtilityClass(btnRoot), classes);
return composedClasses;
};
const useSlotAriaProps = (ownerState)=>{
const { as, disabled: disabledProps, role, loading, tabIndex } = ownerState;
const disabled = disabledProps || loading;
let root = {
tabIndex: disabled ? -1 : tabIndex
};
if (as === 'button') {
root = {
...root,
disabled
};
} else {
root = {
...root,
role: role ?? 'button',
'aria-disabled': disabled || undefined
};
}
return {
root
};
};
const Button = (inProps)=>{
const { primaryThemeColor } = Context.useNexUI();
const props = useDefaultProps.useDefaultProps({
name: 'Button',
props: inProps
});
const { as, ref, children, slotProps, spinner, href, type = 'button', tabIndex = 0, color = primaryThemeColor, spinnerPlacement = 'start', variant = 'solid', size = 'md', radius = size, iconOnly = false, loading = false, disabled: disabledProp = false, fullWidth = false, disableRipple = false, startIcon: startIconProp, endIcon: endIconProp, ...remainingProps } = props;
const btnRef = react.useRef(null);
const mergedRefs = utils.mergeRefs(btnRef, ref);
const disabled = loading || disabledProp;
const rootElement = as !== undefined ? as : typeof href === 'string' && href ? 'a' : 'button';
const ownerState = {
...props,
type,
tabIndex,
variant,
size,
radius,
iconOnly,
loading,
fullWidth,
color,
disableRipple,
disabled: disabledProp,
as: rootElement
};
const [focusVisible] = hooks.useFocusVisible({
ref: btnRef
});
const classes = useSlotClasses(ownerState);
const styles = useStyles.useStyles({
ownerState: {
...ownerState,
disabled
},
name: 'Button',
recipe: button.buttonRecipe
});
const handleKeyDown = hooks.useEvent((event)=>{
// Limit the repeated triggering of the click event when the Enter key is pressed.
if (focusVisible && rootElement === 'button' && event.code === 'Enter') {
event.preventDefault();
}
});
const handleKeyUp = hooks.useEvent((event)=>{
// Keyboard accessibility for non interactive elements
if (focusVisible && as !== 'button' && (event.code === 'Space' || event.code === 'Enter')) {
event.currentTarget.click();
}
});
const slotAriaProps = useSlotAriaProps(ownerState);
const rootProps = useSlotProps.useSlotProps({
ownerState,
externalForwardedProps: remainingProps,
classNames: classes.root,
sx: styles.root,
additionalProps: {
href,
type,
onKeyUp: handleKeyUp,
onKeyDown: handleKeyDown,
ref: mergedRefs,
as: rootElement,
...slotAriaProps.root
}
});
const startIconProps = useSlotProps.useSlotProps({
ownerState,
externalSlotProps: slotProps?.startIcon,
classNames: classes.startIcon,
sx: styles.startIcon
});
const endIconProps = useSlotProps.useSlotProps({
ownerState,
externalSlotProps: slotProps?.endIcon,
classNames: classes.endIcon,
sx: styles.endIcon
});
const loadingIcon = spinner ?? /*#__PURE__*/ jsxRuntime.jsx(icons.LoadingOutlined, {});
const startIcon = (spinnerPlacement === 'start' && loading || startIconProp) && /*#__PURE__*/ jsxRuntime.jsx(styled.nex.span, {
...startIconProps,
children: loading ? loadingIcon : startIconProp
});
const endIcon = (spinnerPlacement === 'end' && loading || endIconProp) && /*#__PURE__*/ jsxRuntime.jsx(styled.nex.span, {
...endIconProps,
children: loading ? loadingIcon : endIconProp
});
return /*#__PURE__*/ jsxRuntime.jsx(Ripple.Ripple, {
disabled: disableRipple ?? disabled,
children: /*#__PURE__*/ jsxRuntime.jsxs(styled.nex.button, {
...rootProps,
children: [
startIcon,
children,
endIcon
]
})
});
};
Button.displayName = 'Button';
exports.Button = Button;