Restructure useStyles hook
Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
This commit is contained in:
@@ -22,7 +22,7 @@ import { ChangelogComponent } from '@/components/ChangelogComponent';
|
||||
|
||||
<Snippet
|
||||
py={4}
|
||||
preview={<BoxSnippet story="Preview" />}
|
||||
preview={<BoxSnippet story="Default" />}
|
||||
code={boxPreviewSnippet}
|
||||
align="center"
|
||||
/>
|
||||
|
||||
@@ -36,35 +36,277 @@ const meta = {
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
const Card = () => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: '64px',
|
||||
height: '64px',
|
||||
background: '#eaf2fd',
|
||||
borderRadius: '4px',
|
||||
border: '1px solid #2563eb',
|
||||
color: '#2563eb',
|
||||
backgroundImage:
|
||||
'url("data:image/svg+xml,%3Csvg%20width%3D%226%22%20height%3D%226%22%20viewBox%3D%220%200%206%206%22%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%3E%3Cg%20fill%3D%22%232563eb%22%20fill-opacity%3D%220.3%22%20fill-rule%3D%22evenodd%22%3E%3Cpath%20d%3D%22M5%200h1L0%206V5zM6%205v1H5z%22/%3E%3C/g%3E%3C/svg%3E")',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
const diagonalStripePattern = (() => {
|
||||
const svg = `
|
||||
<svg width="6" height="6" viewBox="0 0 6 6" xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill="#2563eb" fill-opacity="0.6" fill-rule="evenodd">
|
||||
<path d="M5 0h1L0 6V5zM6 5v1H5z"/>
|
||||
</g>
|
||||
</svg>
|
||||
`.trim();
|
||||
return `data:image/svg+xml,${encodeURIComponent(svg)}`;
|
||||
})();
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
children: 'Hello World',
|
||||
mb: '4',
|
||||
width: '64px',
|
||||
height: '64px',
|
||||
style: {
|
||||
background: '#eaf2fd',
|
||||
borderRadius: '4px',
|
||||
border: '1px solid #2563eb',
|
||||
backgroundImage: `url("${diagonalStripePattern}")`,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
fontWeight: 'bold',
|
||||
color: '#2563eb',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Preview: Story = {
|
||||
args: {
|
||||
children: <Card />,
|
||||
display: 'inline',
|
||||
},
|
||||
export const Margin: Story = {
|
||||
args: { ...Default.args },
|
||||
render: args => (
|
||||
<Flex align="center">
|
||||
<Box style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} ml="6" children="ML" />
|
||||
</Box>
|
||||
<Box style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} mr="6" children="MR" />
|
||||
</Box>
|
||||
<Box style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} mx="6" children="MX" />
|
||||
</Box>
|
||||
<Box style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} mt="6" children="MT" />
|
||||
</Box>
|
||||
<Box style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} mb="6" children="MB" />
|
||||
</Box>
|
||||
<Box style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} my="6" children="MY" />
|
||||
</Box>
|
||||
</Flex>
|
||||
),
|
||||
};
|
||||
|
||||
export const ResponsiveMargin: Story = {
|
||||
args: { ...Default.args },
|
||||
render: args => (
|
||||
<Flex align="center">
|
||||
<Box style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} ml={{ initial: '2', sm: '6' }} children="ML" />
|
||||
</Box>
|
||||
<Box style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} mr={{ initial: '2', sm: '6' }} children="MR" />
|
||||
</Box>
|
||||
<Box style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} mx={{ initial: '2', sm: '6' }} children="MX" />
|
||||
</Box>
|
||||
<Box style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} mt={{ initial: '2', sm: '6' }} children="MT" />
|
||||
</Box>
|
||||
<Box style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} mb={{ initial: '2', sm: '6' }} children="MB" />
|
||||
</Box>
|
||||
<Box style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} my={{ initial: '2', sm: '6' }} children="MY" />
|
||||
</Box>
|
||||
</Flex>
|
||||
),
|
||||
};
|
||||
|
||||
export const CustomMargin: Story = {
|
||||
args: { ...Default.args },
|
||||
render: args => (
|
||||
<Flex align="center">
|
||||
<Box style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} ml="42px" children="ML" />
|
||||
</Box>
|
||||
<Box style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} mr="42px" children="MR" />
|
||||
</Box>
|
||||
<Box style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} mx="42px" children="MX" />
|
||||
</Box>
|
||||
<Box style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} mt="42px" children="MT" />
|
||||
</Box>
|
||||
<Box style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} mb="42px" children="MB" />
|
||||
</Box>
|
||||
<Box style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} my="42px" children="MY" />
|
||||
</Box>
|
||||
</Flex>
|
||||
),
|
||||
};
|
||||
|
||||
export const CustomResponsiveMargin: Story = {
|
||||
args: { ...Default.args },
|
||||
render: args => (
|
||||
<Flex align="center">
|
||||
<Box style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} ml={{ initial: '9px', sm: '42px' }} children="ML" />
|
||||
</Box>
|
||||
<Box style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} mr={{ initial: '9px', sm: '42px' }} children="MR" />
|
||||
</Box>
|
||||
<Box style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} mx={{ initial: '9px', sm: '42px' }} children="MX" />
|
||||
</Box>
|
||||
<Box style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} mt={{ initial: '9px', sm: '42px' }} children="MT" />
|
||||
</Box>
|
||||
<Box style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} mb={{ initial: '9px', sm: '42px' }} children="MB" />
|
||||
</Box>
|
||||
<Box style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} my={{ initial: '9px', sm: '42px' }} children="MY" />
|
||||
</Box>
|
||||
</Flex>
|
||||
),
|
||||
};
|
||||
|
||||
export const Padding: Story = {
|
||||
args: { ...Default.args },
|
||||
render: args => (
|
||||
<Flex align="center">
|
||||
<Box pl="6" style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} children="PL" />
|
||||
</Box>
|
||||
<Box pr="6" style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} children="PR" />
|
||||
</Box>
|
||||
<Box px="6" style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} children="PX" />
|
||||
</Box>
|
||||
<Box pt="6" style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} children="PT" />
|
||||
</Box>
|
||||
<Box pb="6" style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} children="PB" />
|
||||
</Box>
|
||||
<Box py="6" style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} children="PY" />
|
||||
</Box>
|
||||
</Flex>
|
||||
),
|
||||
};
|
||||
|
||||
export const ResponsivePadding: Story = {
|
||||
args: { ...Default.args },
|
||||
render: args => (
|
||||
<Flex align="center">
|
||||
<Box
|
||||
pl={{ initial: '2', sm: '6' }}
|
||||
style={{ border: '1px solid red', borderRadius: '5px' }}
|
||||
>
|
||||
<Box {...args} children="PL" />
|
||||
</Box>
|
||||
<Box
|
||||
pr={{ initial: '2', sm: '6' }}
|
||||
style={{ border: '1px solid red', borderRadius: '5px' }}
|
||||
>
|
||||
<Box {...args} children="PR" />
|
||||
</Box>
|
||||
<Box
|
||||
px={{ initial: '2', sm: '6' }}
|
||||
style={{ border: '1px solid red', borderRadius: '5px' }}
|
||||
>
|
||||
<Box {...args} children="PX" />
|
||||
</Box>
|
||||
<Box
|
||||
pt={{ initial: '2', sm: '6' }}
|
||||
style={{ border: '1px solid red', borderRadius: '5px' }}
|
||||
>
|
||||
<Box {...args} children="PT" />
|
||||
</Box>
|
||||
<Box
|
||||
pb={{ initial: '2', sm: '6' }}
|
||||
style={{ border: '1px solid red', borderRadius: '5px' }}
|
||||
>
|
||||
<Box {...args} children="PB" />
|
||||
</Box>
|
||||
<Box
|
||||
py={{ initial: '2', sm: '6' }}
|
||||
style={{ border: '1px solid red', borderRadius: '5px' }}
|
||||
>
|
||||
<Box {...args} children="PY" />
|
||||
</Box>
|
||||
</Flex>
|
||||
),
|
||||
};
|
||||
|
||||
export const CustomPadding: Story = {
|
||||
args: { ...Default.args },
|
||||
render: args => (
|
||||
<Flex align="center">
|
||||
<Box pl="42px" style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} children="PL" />
|
||||
</Box>
|
||||
<Box pr="42px" style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} children="PR" />
|
||||
</Box>
|
||||
<Box px="42px" style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} children="PX" />
|
||||
</Box>
|
||||
<Box pt="42px" style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} children="PT" />
|
||||
</Box>
|
||||
<Box pb="42px" style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} children="PB" />
|
||||
</Box>
|
||||
<Box py="42px" style={{ border: '1px solid red', borderRadius: '5px' }}>
|
||||
<Box {...args} children="PY" />
|
||||
</Box>
|
||||
</Flex>
|
||||
),
|
||||
};
|
||||
|
||||
export const CustomResponsivePadding: Story = {
|
||||
args: { ...Default.args },
|
||||
render: args => (
|
||||
<Flex align="center">
|
||||
<Box
|
||||
pl={{ initial: '9px', sm: '42px' }}
|
||||
style={{ border: '1px solid red', borderRadius: '5px' }}
|
||||
>
|
||||
<Box {...args} children="PL" />
|
||||
</Box>
|
||||
<Box
|
||||
pr={{ initial: '9px', sm: '42px' }}
|
||||
style={{ border: '1px solid red', borderRadius: '5px' }}
|
||||
>
|
||||
<Box {...args} children="PR" />
|
||||
</Box>
|
||||
<Box
|
||||
px={{ initial: '9px', sm: '42px' }}
|
||||
style={{ border: '1px solid red', borderRadius: '5px' }}
|
||||
>
|
||||
<Box {...args} children="PX" />
|
||||
</Box>
|
||||
<Box
|
||||
pt={{ initial: '9px', sm: '42px' }}
|
||||
style={{ border: '1px solid red', borderRadius: '5px' }}
|
||||
>
|
||||
<Box {...args} children="PT" />
|
||||
</Box>
|
||||
<Box
|
||||
pb={{ initial: '9px', sm: '42px' }}
|
||||
style={{ border: '1px solid red', borderRadius: '5px' }}
|
||||
>
|
||||
<Box {...args} children="PB" />
|
||||
</Box>
|
||||
<Box
|
||||
py={{ initial: '9px', sm: '42px' }}
|
||||
style={{ border: '1px solid red', borderRadius: '5px' }}
|
||||
>
|
||||
<Box {...args} children="PY" />
|
||||
</Box>
|
||||
</Flex>
|
||||
),
|
||||
};
|
||||
|
||||
const CardDisplay = ({ children }: { children?: ReactNode }) => {
|
||||
@@ -105,151 +347,3 @@ export const Display: Story = {
|
||||
</Flex>
|
||||
),
|
||||
};
|
||||
|
||||
const styleInsideBox = {
|
||||
background: 'rgb(196, 202, 251)',
|
||||
color: 'white',
|
||||
borderRadius: '4px',
|
||||
};
|
||||
|
||||
export const Padding: Story = {
|
||||
args: {
|
||||
style: {
|
||||
background: '#1f47ff',
|
||||
color: 'white',
|
||||
borderRadius: '4px',
|
||||
padding: '12px 12px',
|
||||
},
|
||||
},
|
||||
render: args => (
|
||||
<Flex direction="column" align="center" gap="4">
|
||||
<Flex gap="4" align="center">
|
||||
<Box p="3" style={styleInsideBox}>
|
||||
<Box {...args}>Padding</Box>
|
||||
</Box>
|
||||
<Box px="3" style={styleInsideBox}>
|
||||
<Box {...args}>Padding X</Box>
|
||||
</Box>
|
||||
<Box py="3" style={styleInsideBox}>
|
||||
<Box {...args}>Padding Y</Box>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Flex gap="4" align="center">
|
||||
<Box pt="3" style={styleInsideBox}>
|
||||
<Box {...args}>Padding Top</Box>
|
||||
</Box>
|
||||
<Box pr="3" style={styleInsideBox}>
|
||||
<Box {...args}>Padding Right</Box>
|
||||
</Box>
|
||||
<Box pb="3" style={styleInsideBox}>
|
||||
<Box {...args}>Padding Bottom</Box>
|
||||
</Box>
|
||||
<Box pl="3" style={styleInsideBox}>
|
||||
<Box {...args}>Padding Left</Box>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Flex gap="4" align="center">
|
||||
<Box p="10px" style={styleInsideBox}>
|
||||
<Box {...args}>Custom Padding</Box>
|
||||
</Box>
|
||||
<Box px="10px" style={styleInsideBox}>
|
||||
<Box {...args}>Custom Padding X</Box>
|
||||
</Box>
|
||||
<Box py="10px" style={styleInsideBox}>
|
||||
<Box {...args}>Custom Padding Y</Box>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Flex gap="4" align="center">
|
||||
<Box pt="10px" pb="10px" style={styleInsideBox}>
|
||||
<Box {...args}>Custom Padding Top Bottom</Box>
|
||||
</Box>
|
||||
<Box pl="10px" pr="10px" style={styleInsideBox}>
|
||||
<Box {...args}>Custom Padding Left Right</Box>
|
||||
</Box>
|
||||
</Flex>
|
||||
</Flex>
|
||||
),
|
||||
};
|
||||
|
||||
export const Margin: Story = {
|
||||
args: {
|
||||
style: {
|
||||
background: '#1f47ff',
|
||||
color: 'white',
|
||||
borderRadius: '4px',
|
||||
padding: '12px 12px',
|
||||
},
|
||||
},
|
||||
render: args => (
|
||||
<Flex direction="column" align="center" gap="4">
|
||||
<Flex align="center" gap="4">
|
||||
<Box style={styleInsideBox}>
|
||||
<Box m="3" {...args}>
|
||||
Margin
|
||||
</Box>
|
||||
</Box>
|
||||
<Box style={styleInsideBox}>
|
||||
<Box mx="3" {...args}>
|
||||
Margin X
|
||||
</Box>
|
||||
</Box>
|
||||
<Box style={styleInsideBox}>
|
||||
<Box my="3" {...args}>
|
||||
Margin Y
|
||||
</Box>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Flex align="center" gap="4">
|
||||
<Box style={styleInsideBox}>
|
||||
<Box mt="3" {...args}>
|
||||
Margin Top
|
||||
</Box>
|
||||
</Box>
|
||||
<Box style={styleInsideBox}>
|
||||
<Box mr="3" {...args}>
|
||||
Margin Right
|
||||
</Box>
|
||||
</Box>
|
||||
<Box style={styleInsideBox}>
|
||||
<Box mb="3" {...args}>
|
||||
Margin Bottom
|
||||
</Box>
|
||||
</Box>
|
||||
<Box style={styleInsideBox}>
|
||||
<Box ml="3" {...args}>
|
||||
Margin Left
|
||||
</Box>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Flex align="center" gap="4">
|
||||
<Box style={styleInsideBox}>
|
||||
<Box m="10px" {...args}>
|
||||
Custom Margin
|
||||
</Box>
|
||||
</Box>
|
||||
<Box style={styleInsideBox}>
|
||||
<Box mx="10px" {...args}>
|
||||
Custom Margin X
|
||||
</Box>
|
||||
</Box>
|
||||
<Box style={styleInsideBox}>
|
||||
<Box my="10px" {...args}>
|
||||
Custom Margin Y
|
||||
</Box>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Flex align="center" gap="4">
|
||||
<Box style={styleInsideBox}>
|
||||
<Box mt="10px" mb="10px" {...args}>
|
||||
Custom Margin Top Bottom
|
||||
</Box>
|
||||
</Box>
|
||||
<Box style={styleInsideBox}>
|
||||
<Box ml="10px" mr="10px" {...args}>
|
||||
Custom Margin Left Right
|
||||
</Box>
|
||||
</Box>
|
||||
</Flex>
|
||||
</Flex>
|
||||
),
|
||||
};
|
||||
|
||||
@@ -17,38 +17,27 @@
|
||||
import { createElement, forwardRef } from 'react';
|
||||
import { BoxProps } from './types';
|
||||
import clsx from 'clsx';
|
||||
import { extractProps } from '../../utils/extractProps';
|
||||
import { spacingPropDefs } from '../../props/spacing.props';
|
||||
import { boxPropDefs } from './Box.props';
|
||||
import { widthPropDefs } from '../../props/width.props';
|
||||
import { heightPropDefs } from '../../props/height.props';
|
||||
import { positionPropDefs } from '../../props/position.props';
|
||||
import { displayPropDefs } from '../../props/display.props';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
|
||||
/** @public */
|
||||
export const Box = forwardRef<HTMLDivElement, BoxProps>((props, ref) => {
|
||||
const { children } = props;
|
||||
const { classNames, utilityClasses, style, cleanedProps } = useStyles(
|
||||
'Box',
|
||||
props,
|
||||
);
|
||||
|
||||
const propDefs = {
|
||||
...spacingPropDefs,
|
||||
...widthPropDefs,
|
||||
...heightPropDefs,
|
||||
...positionPropDefs,
|
||||
...displayPropDefs,
|
||||
...boxPropDefs,
|
||||
};
|
||||
const { as = 'div', children, ...rest } = cleanedProps;
|
||||
|
||||
const { classNames } = useStyles('Box');
|
||||
const { className, style, dataProps } = extractProps(props, propDefs);
|
||||
|
||||
return createElement(props.as || 'div', {
|
||||
ref,
|
||||
className: clsx(classNames.root, className),
|
||||
...dataProps,
|
||||
style,
|
||||
return createElement(
|
||||
as,
|
||||
{
|
||||
ref,
|
||||
className: clsx(classNames.root, utilityClasses),
|
||||
style,
|
||||
...rest,
|
||||
},
|
||||
children,
|
||||
});
|
||||
);
|
||||
});
|
||||
|
||||
Box.displayName = 'Box';
|
||||
|
||||
@@ -14,24 +14,21 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { HeightProps } from '../../props/height.props';
|
||||
import type { WidthProps } from '../../props/width.props';
|
||||
import type { PositionProps } from '../../props/position.props';
|
||||
import type { DisplayProps } from '../../props/display.props';
|
||||
import type { SpaceProps } from '../../types';
|
||||
import type { BoxOwnProps } from './Box.props';
|
||||
import type { SpaceProps, Responsive } from '../../types';
|
||||
|
||||
/** @public */
|
||||
export interface BoxProps extends SpaceProps {
|
||||
display?: DisplayProps['display'];
|
||||
as?: BoxOwnProps['as'];
|
||||
width?: WidthProps['width'];
|
||||
minWidth?: WidthProps['minWidth'];
|
||||
maxWidth?: WidthProps['maxWidth'];
|
||||
height?: HeightProps['height'];
|
||||
minHeight?: HeightProps['minHeight'];
|
||||
maxHeight?: HeightProps['maxHeight'];
|
||||
position?: PositionProps['position'];
|
||||
display?: Responsive<'none' | 'flex' | 'block' | 'inline'>;
|
||||
as?: keyof JSX.IntrinsicElements;
|
||||
width?: Responsive<string>;
|
||||
minWidth?: Responsive<string>;
|
||||
maxWidth?: Responsive<string>;
|
||||
height?: Responsive<string>;
|
||||
minHeight?: Responsive<string>;
|
||||
maxHeight?: Responsive<string>;
|
||||
position?: Responsive<
|
||||
'static' | 'relative' | 'absolute' | 'fixed' | 'sticky'
|
||||
>;
|
||||
children?: React.ReactNode;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
|
||||
@@ -41,6 +41,7 @@ type Story = StoryObj<typeof meta>;
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
children: 'Button',
|
||||
className: 'caca',
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -23,21 +23,14 @@ import { useStyles } from '../../hooks/useStyles';
|
||||
/** @public */
|
||||
export const Button = forwardRef(
|
||||
(props: ButtonProps, ref: Ref<HTMLButtonElement>) => {
|
||||
const {
|
||||
size = 'small',
|
||||
variant = 'primary',
|
||||
iconStart,
|
||||
iconEnd,
|
||||
children,
|
||||
className,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
const { classNames, dataAttributes } = useStyles('Button', {
|
||||
size,
|
||||
variant,
|
||||
const { classNames, dataAttributes, cleanedProps } = useStyles('Button', {
|
||||
size: 'small',
|
||||
variant: 'primary',
|
||||
...props,
|
||||
});
|
||||
|
||||
const { children, className, iconStart, iconEnd, ...rest } = cleanedProps;
|
||||
|
||||
return (
|
||||
<RAButton
|
||||
className={clsx(classNames.root, className)}
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react-vite';
|
||||
import { ButtonIcon } from './ButtonIcon';
|
||||
import { Flex } from '../Flex';
|
||||
import { Text } from '../Text';
|
||||
import { Icon } from '../Icon';
|
||||
|
||||
const meta = {
|
||||
@@ -84,42 +83,3 @@ export const Responsive: Story = {
|
||||
},
|
||||
render: args => <ButtonIcon {...args} icon={<Icon name="cloud" />} />,
|
||||
};
|
||||
|
||||
const variants = ['primary', 'secondary'] as const;
|
||||
const sizes = ['small', 'medium'] as const;
|
||||
|
||||
export const Playground: Story = {
|
||||
render: args => (
|
||||
<Flex direction="column">
|
||||
{variants.map(variant => (
|
||||
<Flex direction="column" key={variant}>
|
||||
<Text>{variant}</Text>
|
||||
{sizes.map(size => (
|
||||
<Flex align="center" key={size}>
|
||||
<ButtonIcon
|
||||
{...args}
|
||||
variant={variant}
|
||||
size={size}
|
||||
icon={<Icon name="cloud" />}
|
||||
/>
|
||||
<ButtonIcon
|
||||
{...args}
|
||||
icon={<Icon name="chevron-right" />}
|
||||
aria-label="Chevron right icon button"
|
||||
variant={variant}
|
||||
size={size}
|
||||
/>
|
||||
<ButtonIcon
|
||||
{...args}
|
||||
icon={<Icon name="chevron-right" />}
|
||||
aria-label="Chevron right icon button"
|
||||
variant={variant}
|
||||
size={size}
|
||||
/>
|
||||
</Flex>
|
||||
))}
|
||||
</Flex>
|
||||
))}
|
||||
</Flex>
|
||||
),
|
||||
};
|
||||
|
||||
@@ -23,22 +23,16 @@ import { useStyles } from '../../hooks/useStyles';
|
||||
/** @public */
|
||||
export const ButtonIcon = forwardRef(
|
||||
(props: ButtonIconProps, ref: Ref<HTMLButtonElement>) => {
|
||||
const {
|
||||
size = 'small',
|
||||
variant = 'primary',
|
||||
icon,
|
||||
className,
|
||||
style,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
const { classNames, dataAttributes } = useStyles('Button', {
|
||||
size,
|
||||
variant,
|
||||
const { classNames, dataAttributes, cleanedProps } = useStyles('Button', {
|
||||
size: 'small',
|
||||
variant: 'primary',
|
||||
...props,
|
||||
});
|
||||
|
||||
const { classNames: classNamesButtonIcon } = useStyles('ButtonIcon');
|
||||
|
||||
const { className, icon, ...rest } = cleanedProps;
|
||||
|
||||
return (
|
||||
<RAButton
|
||||
className={clsx(classNames.root, classNamesButtonIcon.root, className)}
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
import type { Meta, StoryFn, StoryObj } from '@storybook/react-vite';
|
||||
import { ButtonLink } from './ButtonLink';
|
||||
import { Flex } from '../Flex';
|
||||
import { Text } from '../Text';
|
||||
import { Icon } from '../Icon';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
||||
@@ -162,70 +161,3 @@ export const Responsive: Story = {
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const variants = ['primary', 'secondary'] as const;
|
||||
const sizes = ['small', 'medium'] as const;
|
||||
|
||||
export const Playground: Story = {
|
||||
args: {
|
||||
children: 'Button',
|
||||
},
|
||||
render: () => (
|
||||
<Flex direction="column">
|
||||
{variants.map(variant => (
|
||||
<Flex direction="column" key={variant}>
|
||||
<Text>{variant}</Text>
|
||||
{sizes.map(size => (
|
||||
<Flex align="center" key={size}>
|
||||
<ButtonLink variant={variant} size={size}>
|
||||
Button
|
||||
</ButtonLink>
|
||||
<ButtonLink
|
||||
iconStart={<Icon name="cloud" />}
|
||||
variant={variant}
|
||||
size={size}
|
||||
>
|
||||
Button
|
||||
</ButtonLink>
|
||||
<ButtonLink
|
||||
iconEnd={<Icon name="chevron-right" />}
|
||||
variant={variant}
|
||||
size={size}
|
||||
>
|
||||
Button
|
||||
</ButtonLink>
|
||||
<ButtonLink
|
||||
iconStart={<Icon name="cloud" />}
|
||||
iconEnd={<Icon name="chevron-right" />}
|
||||
style={{ width: '200px' }}
|
||||
variant={variant}
|
||||
size={size}
|
||||
>
|
||||
Button
|
||||
</ButtonLink>
|
||||
<ButtonLink variant={variant} size={size} isDisabled>
|
||||
Button
|
||||
</ButtonLink>
|
||||
<ButtonLink
|
||||
iconStart={<Icon name="cloud" />}
|
||||
variant={variant}
|
||||
size={size}
|
||||
isDisabled
|
||||
>
|
||||
Button
|
||||
</ButtonLink>
|
||||
<ButtonLink
|
||||
iconEnd={<Icon name="chevron-right" />}
|
||||
variant={variant}
|
||||
size={size}
|
||||
isDisabled
|
||||
>
|
||||
Button
|
||||
</ButtonLink>
|
||||
</Flex>
|
||||
))}
|
||||
</Flex>
|
||||
))}
|
||||
</Flex>
|
||||
),
|
||||
};
|
||||
|
||||
@@ -26,24 +26,18 @@ import { isExternalLink } from '../../utils/isExternalLink';
|
||||
export const ButtonLink = forwardRef(
|
||||
(props: ButtonLinkProps, ref: Ref<HTMLAnchorElement>) => {
|
||||
const navigate = useNavigate();
|
||||
const {
|
||||
size = 'small',
|
||||
variant = 'primary',
|
||||
iconStart,
|
||||
iconEnd,
|
||||
children,
|
||||
className,
|
||||
href,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
const { classNames, dataAttributes } = useStyles('Button', {
|
||||
size,
|
||||
variant,
|
||||
const { classNames, dataAttributes, cleanedProps } = useStyles('Button', {
|
||||
size: 'small',
|
||||
variant: 'primary',
|
||||
...props,
|
||||
});
|
||||
|
||||
const { classNames: classNamesButtonLink } = useStyles('ButtonLink');
|
||||
|
||||
const { children, className, iconStart, iconEnd, href, ...rest } =
|
||||
cleanedProps;
|
||||
|
||||
const isExternal = isExternalLink(href);
|
||||
|
||||
// If it's an external link, render RALink without RouterProvider
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
/* Breakpoint xs */
|
||||
@media (min-width: 640px) {
|
||||
.xs\:bui-mb {
|
||||
margin-bottom: var(--pb-xs);
|
||||
margin-bottom: var(--mb-xs);
|
||||
}
|
||||
|
||||
.xs\:bui-mb-0\.5 {
|
||||
@@ -157,7 +157,7 @@
|
||||
/* Breakpoint sm */
|
||||
@media (min-width: 768px) {
|
||||
.sm\:bui-mb {
|
||||
margin-bottom: var(--pb-sm);
|
||||
margin-bottom: var(--mb-sm);
|
||||
}
|
||||
|
||||
.sm\:bui-mb-0\.5 {
|
||||
@@ -228,7 +228,7 @@
|
||||
/* Breakpoint md */
|
||||
@media (min-width: 1024px) {
|
||||
.md\:bui-mb {
|
||||
margin-bottom: var(--pb-md);
|
||||
margin-bottom: var(--mb-md);
|
||||
}
|
||||
|
||||
.md\:bui-mb-0\.5 {
|
||||
@@ -299,7 +299,7 @@
|
||||
/* Breakpoint lg */
|
||||
@media (min-width: 1280px) {
|
||||
.lg\:bui-mb {
|
||||
margin-bottom: var(--pb-lg);
|
||||
margin-bottom: var(--mb-lg);
|
||||
}
|
||||
|
||||
.lg\:bui-mb-0\.5 {
|
||||
@@ -370,7 +370,7 @@
|
||||
/* Breakpoint xl */
|
||||
@media (min-width: 1536px) {
|
||||
.xl\:bui-mb {
|
||||
margin-bottom: var(--pb-xl);
|
||||
margin-bottom: var(--mb-xl);
|
||||
}
|
||||
|
||||
.xl\:bui-mb-0\.5 {
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
/* Breakpoint xs */
|
||||
@media (min-width: 640px) {
|
||||
.xs\:bui-ml {
|
||||
margin-left: var(--pl-xs);
|
||||
margin-left: var(--ml-xs);
|
||||
}
|
||||
|
||||
.xs\:bui-ml-0\.5 {
|
||||
@@ -157,7 +157,7 @@
|
||||
/* Breakpoint sm */
|
||||
@media (min-width: 768px) {
|
||||
.sm\:bui-ml {
|
||||
margin-left: var(--pl-sm);
|
||||
margin-left: var(--ml-sm);
|
||||
}
|
||||
|
||||
.sm\:bui-ml-0\.5 {
|
||||
@@ -228,7 +228,7 @@
|
||||
/* Breakpoint md */
|
||||
@media (min-width: 1024px) {
|
||||
.md\:bui-ml {
|
||||
margin-left: var(--pl-md);
|
||||
margin-left: var(--ml-md);
|
||||
}
|
||||
|
||||
.md\:bui-ml-0\.5 {
|
||||
@@ -299,7 +299,7 @@
|
||||
/* Breakpoint lg */
|
||||
@media (min-width: 1280px) {
|
||||
.lg\:bui-ml {
|
||||
margin-left: var(--pl-lg);
|
||||
margin-left: var(--ml-lg);
|
||||
}
|
||||
|
||||
.lg\:bui-ml-0\.5 {
|
||||
@@ -370,7 +370,7 @@
|
||||
/* Breakpoint xl */
|
||||
@media (min-width: 1536px) {
|
||||
.xl\:bui-ml {
|
||||
margin-left: var(--pl-xl);
|
||||
margin-left: var(--ml-xl);
|
||||
}
|
||||
|
||||
.xl\:bui-ml-0\.5 {
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
/* Breakpoint xs */
|
||||
@media (min-width: 640px) {
|
||||
.xs\:bui-mr {
|
||||
margin-right: var(--pr-xs);
|
||||
margin-right: var(--mr-xs);
|
||||
}
|
||||
|
||||
.xs\:bui-mr-0\.5 {
|
||||
@@ -157,7 +157,7 @@
|
||||
/* Breakpoint sm */
|
||||
@media (min-width: 768px) {
|
||||
.sm\:bui-mr {
|
||||
margin-right: var(--pr-sm);
|
||||
margin-right: var(--mr-sm);
|
||||
}
|
||||
|
||||
.sm\:bui-mr-0\.5 {
|
||||
@@ -228,7 +228,7 @@
|
||||
/* Breakpoint md */
|
||||
@media (min-width: 1024px) {
|
||||
.md\:bui-mr {
|
||||
margin-right: var(--pr-md);
|
||||
margin-right: var(--mr-md);
|
||||
}
|
||||
|
||||
.md\:bui-mr-0\.5 {
|
||||
@@ -299,7 +299,7 @@
|
||||
/* Breakpoint lg */
|
||||
@media (min-width: 1280px) {
|
||||
.lg\:bui-mr {
|
||||
margin-right: var(--pr-lg);
|
||||
margin-right: var(--mr-lg);
|
||||
}
|
||||
|
||||
.lg\:bui-mr-0\.5 {
|
||||
@@ -370,7 +370,7 @@
|
||||
/* Breakpoint xl */
|
||||
@media (min-width: 1536px) {
|
||||
.xl\:bui-mr {
|
||||
margin-right: var(--pr-xl);
|
||||
margin-right: var(--mr-xl);
|
||||
}
|
||||
|
||||
.xl\:bui-mr-0\.5 {
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
/* Breakpoint xs */
|
||||
@media (min-width: 640px) {
|
||||
.xs\:bui-mt {
|
||||
margin-top: var(--pt-xs);
|
||||
margin-top: var(--mt-xs);
|
||||
}
|
||||
|
||||
.xs\:bui-mt-0\.5 {
|
||||
@@ -157,7 +157,7 @@
|
||||
/* Breakpoint sm */
|
||||
@media (min-width: 768px) {
|
||||
.sm\:bui-mt {
|
||||
margin-top: var(--pt-sm);
|
||||
margin-top: var(--mt-sm);
|
||||
}
|
||||
|
||||
.sm\:bui-mt-0\.5 {
|
||||
@@ -228,7 +228,7 @@
|
||||
/* Breakpoint md */
|
||||
@media (min-width: 1024px) {
|
||||
.md\:bui-mt {
|
||||
margin-top: var(--pt-md);
|
||||
margin-top: var(--mt-md);
|
||||
}
|
||||
|
||||
.md\:bui-mt-0\.5 {
|
||||
@@ -299,7 +299,7 @@
|
||||
/* Breakpoint lg */
|
||||
@media (min-width: 1280px) {
|
||||
.lg\:bui-mt {
|
||||
margin-top: var(--pt-lg);
|
||||
margin-top: var(--mt-lg);
|
||||
}
|
||||
|
||||
.lg\:bui-mt-0\.5 {
|
||||
@@ -370,7 +370,7 @@
|
||||
/* Breakpoint xl */
|
||||
@media (min-width: 1536px) {
|
||||
.xl\:bui-mt {
|
||||
margin-top: var(--pt-xl);
|
||||
margin-top: var(--mt-xl);
|
||||
}
|
||||
|
||||
.xl\:bui-mt-0\.5 {
|
||||
|
||||
@@ -103,8 +103,8 @@
|
||||
/* Breakpoint xs */
|
||||
@media (min-width: 640px) {
|
||||
.xs\:bui-mx {
|
||||
margin-left: var(--px-xs);
|
||||
margin-right: var(--px-xs);
|
||||
margin-left: var(--mx-xs);
|
||||
margin-right: var(--mx-xs);
|
||||
}
|
||||
|
||||
.xs\:bui-mx-0\.5 {
|
||||
@@ -191,8 +191,8 @@
|
||||
/* Breakpoint sm */
|
||||
@media (min-width: 768px) {
|
||||
.sm\:bui-mx {
|
||||
margin-left: var(--px-sm);
|
||||
margin-right: var(--px-sm);
|
||||
margin-left: var(--mx-sm);
|
||||
margin-right: var(--mx-sm);
|
||||
}
|
||||
|
||||
.sm\:bui-mx-0\.5 {
|
||||
@@ -279,8 +279,8 @@
|
||||
/* Breakpoint md */
|
||||
@media (min-width: 1024px) {
|
||||
.md\:bui-mx {
|
||||
margin-left: var(--px-md);
|
||||
margin-right: var(--px-md);
|
||||
margin-left: var(--mx-md);
|
||||
margin-right: var(--mx-md);
|
||||
}
|
||||
|
||||
.md\:bui-mx-0\.5 {
|
||||
@@ -367,8 +367,8 @@
|
||||
/* Breakpoint lg */
|
||||
@media (min-width: 1280px) {
|
||||
.lg\:bui-mx {
|
||||
margin-left: var(--px-lg);
|
||||
margin-right: var(--px-lg);
|
||||
margin-left: var(--mx-lg);
|
||||
margin-right: var(--mx-lg);
|
||||
}
|
||||
|
||||
.lg\:bui-mx-0\.5 {
|
||||
@@ -455,8 +455,8 @@
|
||||
/* Breakpoint xl */
|
||||
@media (min-width: 1536px) {
|
||||
.xl\:bui-mx {
|
||||
margin-left: var(--px-xl);
|
||||
margin-right: var(--px-xl);
|
||||
margin-left: var(--mx-xl);
|
||||
margin-right: var(--mx-xl);
|
||||
}
|
||||
|
||||
.xl\:bui-mx-0\.5 {
|
||||
|
||||
@@ -103,8 +103,8 @@
|
||||
/* Breakpoint xs */
|
||||
@media (min-width: 640px) {
|
||||
.xs\:bui-my {
|
||||
margin-top: var(--py-xs);
|
||||
margin-bottom: var(--py-xs);
|
||||
margin-top: var(--my-xs);
|
||||
margin-bottom: var(--my-xs);
|
||||
}
|
||||
|
||||
.xs\:bui-my-0\.5 {
|
||||
@@ -191,8 +191,8 @@
|
||||
/* Breakpoint sm */
|
||||
@media (min-width: 768px) {
|
||||
.sm\:bui-my {
|
||||
margin-top: var(--py-sm);
|
||||
margin-bottom: var(--py-sm);
|
||||
margin-top: var(--my-sm);
|
||||
margin-bottom: var(--my-sm);
|
||||
}
|
||||
|
||||
.sm\:bui-my-0\.5 {
|
||||
@@ -279,8 +279,8 @@
|
||||
/* Breakpoint md */
|
||||
@media (min-width: 1024px) {
|
||||
.md\:bui-my {
|
||||
margin-top: var(--py-md);
|
||||
margin-bottom: var(--py-md);
|
||||
margin-top: var(--my-md);
|
||||
margin-bottom: var(--my-md);
|
||||
}
|
||||
|
||||
.md\:bui-my-0\.5 {
|
||||
@@ -367,8 +367,8 @@
|
||||
/* Breakpoint lg */
|
||||
@media (min-width: 1280px) {
|
||||
.lg\:bui-my {
|
||||
margin-top: var(--py-lg);
|
||||
margin-bottom: var(--py-lg);
|
||||
margin-top: var(--my-lg);
|
||||
margin-bottom: var(--my-lg);
|
||||
}
|
||||
|
||||
.lg\:bui-my-0\.5 {
|
||||
@@ -455,8 +455,8 @@
|
||||
/* Breakpoint xl */
|
||||
@media (min-width: 1536px) {
|
||||
.xl\:bui-my {
|
||||
margin-top: var(--py-xl);
|
||||
margin-bottom: var(--py-xl);
|
||||
margin-top: var(--my-xl);
|
||||
margin-bottom: var(--my-xl);
|
||||
}
|
||||
|
||||
.xl\:bui-my-0\.5 {
|
||||
|
||||
@@ -17,6 +17,139 @@ import { useBreakpoint, breakpoints } from './useBreakpoint';
|
||||
import { componentDefinitions } from '../utils/componentDefinitions';
|
||||
import type { ComponentDefinitionName, ComponentClassNames } from '../types';
|
||||
|
||||
// Valid spacing values that have predefined utility classes
|
||||
const VALID_SPACING_VALUES = [
|
||||
'0.5',
|
||||
'1',
|
||||
'1.5',
|
||||
'2',
|
||||
'3',
|
||||
'4',
|
||||
'5',
|
||||
'6',
|
||||
'7',
|
||||
'8',
|
||||
'9',
|
||||
'10',
|
||||
'11',
|
||||
'12',
|
||||
'13',
|
||||
'14',
|
||||
] as const;
|
||||
|
||||
const utilityClassMap = {
|
||||
m: {
|
||||
class: 'bui-m',
|
||||
cssVar: '--m',
|
||||
values: VALID_SPACING_VALUES,
|
||||
},
|
||||
mb: {
|
||||
class: 'bui-mb',
|
||||
cssVar: '--mb',
|
||||
values: VALID_SPACING_VALUES,
|
||||
},
|
||||
ml: {
|
||||
class: 'bui-ml',
|
||||
cssVar: '--ml',
|
||||
values: VALID_SPACING_VALUES,
|
||||
},
|
||||
mr: {
|
||||
class: 'bui-mr',
|
||||
cssVar: '--mr',
|
||||
values: VALID_SPACING_VALUES,
|
||||
},
|
||||
mt: {
|
||||
class: 'bui-mt',
|
||||
cssVar: '--mt',
|
||||
values: VALID_SPACING_VALUES,
|
||||
},
|
||||
mx: {
|
||||
class: 'bui-mx',
|
||||
cssVar: '--mx',
|
||||
values: VALID_SPACING_VALUES,
|
||||
},
|
||||
my: {
|
||||
class: 'bui-my',
|
||||
cssVar: '--my',
|
||||
values: VALID_SPACING_VALUES,
|
||||
},
|
||||
p: {
|
||||
class: 'bui-p',
|
||||
cssVar: '--p',
|
||||
values: VALID_SPACING_VALUES,
|
||||
},
|
||||
pb: {
|
||||
class: 'bui-pb',
|
||||
cssVar: '--pb',
|
||||
values: VALID_SPACING_VALUES,
|
||||
},
|
||||
pl: {
|
||||
class: 'bui-pl',
|
||||
cssVar: '--pl',
|
||||
values: VALID_SPACING_VALUES,
|
||||
},
|
||||
pr: {
|
||||
class: 'bui-pr',
|
||||
cssVar: '--pr',
|
||||
values: VALID_SPACING_VALUES,
|
||||
},
|
||||
pt: {
|
||||
class: 'bui-pt',
|
||||
cssVar: '--pt',
|
||||
values: VALID_SPACING_VALUES,
|
||||
},
|
||||
px: {
|
||||
class: 'bui-px',
|
||||
cssVar: '--px',
|
||||
values: VALID_SPACING_VALUES,
|
||||
},
|
||||
py: {
|
||||
class: 'bui-py',
|
||||
cssVar: '--py',
|
||||
values: VALID_SPACING_VALUES,
|
||||
},
|
||||
width: {
|
||||
class: 'bui-w',
|
||||
cssVar: '--width',
|
||||
values: VALID_SPACING_VALUES,
|
||||
},
|
||||
minWidth: {
|
||||
class: 'bui-min-w',
|
||||
cssVar: '--min-width',
|
||||
values: VALID_SPACING_VALUES,
|
||||
},
|
||||
maxWidth: {
|
||||
class: 'bui-max-w',
|
||||
cssVar: '--max-width',
|
||||
values: VALID_SPACING_VALUES,
|
||||
},
|
||||
height: {
|
||||
class: 'bui-h',
|
||||
cssVar: '--height',
|
||||
values: VALID_SPACING_VALUES,
|
||||
},
|
||||
minHeight: {
|
||||
class: 'bui-min-h',
|
||||
cssVar: '--min-height',
|
||||
values: VALID_SPACING_VALUES,
|
||||
},
|
||||
maxHeight: {
|
||||
class: 'bui-max-h',
|
||||
cssVar: '--max-height',
|
||||
values: VALID_SPACING_VALUES,
|
||||
},
|
||||
position: {
|
||||
class: 'bui-position',
|
||||
cssVar: '--position',
|
||||
values: ['static', 'relative', 'absolute', 'fixed', 'sticky'],
|
||||
},
|
||||
display: {
|
||||
class: 'bui-display',
|
||||
cssVar: '--display',
|
||||
values: ['none', 'flex', 'block', 'inline'],
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolve a responsive value based on the current breakpoint
|
||||
* @param value - The responsive value (string or object with breakpoint keys)
|
||||
@@ -55,8 +188,8 @@ function resolveResponsiveValue(
|
||||
/**
|
||||
* React hook to get class names and data attributes for a component with responsive support
|
||||
* @param componentName - The name of the component
|
||||
* @param props - Object with prop values (can be responsive)
|
||||
* @returns Object with classNames and dataAttributes
|
||||
* @param props - All component props
|
||||
* @returns Object with classNames, dataAttributes, utilityClasses, style, and cleanedProps
|
||||
*/
|
||||
export function useStyles<T extends ComponentDefinitionName>(
|
||||
componentName: T,
|
||||
@@ -64,29 +197,125 @@ export function useStyles<T extends ComponentDefinitionName>(
|
||||
): {
|
||||
classNames: ComponentClassNames<T>;
|
||||
dataAttributes: Record<string, string>;
|
||||
resolvedProps: Record<string, string>;
|
||||
utilityClasses: string;
|
||||
style: React.CSSProperties;
|
||||
cleanedProps: Record<string, any>;
|
||||
} {
|
||||
const { breakpoint } = useBreakpoint();
|
||||
const classNames = componentDefinitions[componentName]
|
||||
.classNames as ComponentClassNames<T>;
|
||||
const componentDefinition = componentDefinitions[componentName];
|
||||
const classNames = componentDefinition.classNames as ComponentClassNames<T>;
|
||||
const utilityPropNames =
|
||||
('utilityProps' in componentDefinition
|
||||
? componentDefinition.utilityProps
|
||||
: []) || [];
|
||||
|
||||
// Resolve responsive values and generate data attributes
|
||||
// Extract data attribute names from component definition
|
||||
const dataAttributeNames =
|
||||
'dataAttributes' in componentDefinition
|
||||
? Object.keys(componentDefinition.dataAttributes || {})
|
||||
: [];
|
||||
|
||||
// Extract existing style from props
|
||||
const incomingStyle = props.style || {};
|
||||
|
||||
// Generate data attributes from component definition
|
||||
const dataAttributes: Record<string, string> = {};
|
||||
const resolvedProps: Record<string, string> = {};
|
||||
|
||||
for (const [key, value] of Object.entries(props)) {
|
||||
for (const key of dataAttributeNames) {
|
||||
const value = props[key];
|
||||
if (value !== undefined && value !== null) {
|
||||
const resolvedValue = resolveResponsiveValue(value, breakpoint);
|
||||
if (resolvedValue !== undefined) {
|
||||
resolvedProps[key] = resolvedValue;
|
||||
dataAttributes[`data-${key}`] = resolvedValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate utility classes and custom styles from component's allowed utility props
|
||||
const utilityClassList: string[] = [];
|
||||
const generatedStyle: React.CSSProperties = {};
|
||||
|
||||
const handleUtilityValue = (
|
||||
key: string,
|
||||
val: unknown,
|
||||
prefix: string = '',
|
||||
) => {
|
||||
// Get utility class configuration for this key
|
||||
const utilityConfig = utilityClassMap[key as keyof typeof utilityClassMap];
|
||||
|
||||
if (!utilityConfig) {
|
||||
// Skip if no config found for this key
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if value is in the list of valid values for this utility
|
||||
if (utilityConfig.values.includes(val as any)) {
|
||||
// Generate utility class with value suffix and optional breakpoint prefix
|
||||
const className = prefix
|
||||
? `${prefix}${utilityConfig.class}-${val}`
|
||||
: `${utilityConfig.class}-${val}`;
|
||||
utilityClassList.push(className);
|
||||
} else {
|
||||
// Custom value - add CSS custom property AND utility class name
|
||||
const cssVarKey = prefix
|
||||
? `${utilityConfig.cssVar}-${prefix.slice(0, -1)}`
|
||||
: utilityConfig.cssVar;
|
||||
// CSS custom properties need to be set as any since they're not part of CSSProperties
|
||||
(generatedStyle as any)[cssVarKey] = val;
|
||||
|
||||
// Add utility class name (without value suffix) with optional breakpoint prefix
|
||||
const className = prefix
|
||||
? `${prefix}${utilityConfig.class}`
|
||||
: utilityConfig.class;
|
||||
utilityClassList.push(className);
|
||||
}
|
||||
};
|
||||
|
||||
for (const key of utilityPropNames) {
|
||||
const value = props[key];
|
||||
if (value === undefined || value === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if value is a responsive object
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
const breakpointValues = value as { [key: string]: unknown };
|
||||
// Handle responsive object values
|
||||
for (const bp in breakpointValues) {
|
||||
const prefix = bp === 'initial' ? '' : `${bp}:`;
|
||||
handleUtilityValue(key, breakpointValues[bp], prefix);
|
||||
}
|
||||
} else {
|
||||
// Handle simple value
|
||||
handleUtilityValue(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
// Create cleaned props by excluding data attributes, utility props, and style
|
||||
// Component-specific props like 'as' and 'children' remain in cleanedProps
|
||||
const processedKeys = new Set([
|
||||
...dataAttributeNames,
|
||||
...utilityPropNames,
|
||||
'style',
|
||||
]);
|
||||
|
||||
const cleanedProps = Object.keys(props).reduce((acc, key) => {
|
||||
if (!processedKeys.has(key)) {
|
||||
acc[key] = props[key];
|
||||
}
|
||||
return acc;
|
||||
}, {} as Record<string, any>);
|
||||
|
||||
// Merge incoming style with generated styles (incoming styles take precedence)
|
||||
const mergedStyle = {
|
||||
...generatedStyle,
|
||||
...incomingStyle,
|
||||
};
|
||||
|
||||
return {
|
||||
classNames,
|
||||
dataAttributes,
|
||||
resolvedProps, // Also return resolved props for convenience
|
||||
utilityClasses: utilityClassList.join(' '),
|
||||
style: mergedStyle,
|
||||
cleanedProps,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -160,6 +160,7 @@ export type DataAttributesMap = Record<string, DataAttributeValues>;
|
||||
export interface ComponentDefinition {
|
||||
classNames: ClassNamesMap;
|
||||
dataAttributes?: DataAttributesMap;
|
||||
utilityProps?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -35,6 +35,30 @@ export const componentDefinitions = {
|
||||
classNames: {
|
||||
root: 'bui-Box',
|
||||
},
|
||||
utilityProps: [
|
||||
'm',
|
||||
'mb',
|
||||
'ml',
|
||||
'mr',
|
||||
'mt',
|
||||
'mx',
|
||||
'my',
|
||||
'p',
|
||||
'pb',
|
||||
'pl',
|
||||
'pr',
|
||||
'pt',
|
||||
'px',
|
||||
'py',
|
||||
'position',
|
||||
'display',
|
||||
'width',
|
||||
'minWidth',
|
||||
'maxWidth',
|
||||
'height',
|
||||
'minHeight',
|
||||
'maxHeight',
|
||||
],
|
||||
},
|
||||
Button: {
|
||||
classNames: {
|
||||
|
||||
Reference in New Issue
Block a user