@aurora-ds/components 0.10.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -5
- package/dist/cjs/components/actions/button/Button.props.d.ts +2 -2
- package/dist/cjs/components/actions/icon-button/IconButton.props.d.ts +2 -2
- package/dist/cjs/components/data-display/avatar/Avatar.d.ts +9 -0
- package/dist/cjs/components/data-display/avatar/Avatar.props.d.ts +25 -0
- package/dist/cjs/components/data-display/avatar/Avatar.styles.d.ts +10 -0
- package/dist/cjs/components/data-display/avatar/AvatarGroup.d.ts +9 -0
- package/dist/cjs/components/data-display/avatar/avatar-group/AvatarGroup.d.ts +9 -0
- package/dist/cjs/components/data-display/avatar/avatar-group/AvatarGroup.props.d.ts +10 -0
- package/dist/cjs/components/data-display/avatar/avatar-group/AvatarGroup.styles.d.ts +14 -0
- package/dist/cjs/components/data-display/avatar/index.d.ts +4 -0
- package/dist/cjs/components/index.d.ts +4 -0
- package/dist/cjs/components/layout/separator/Separator.d.ts +9 -0
- package/dist/cjs/components/layout/separator/Separator.props.d.ts +17 -0
- package/dist/cjs/components/layout/separator/Separator.styles.d.ts +7 -0
- package/dist/cjs/components/layout/separator/index.d.ts +2 -0
- package/dist/cjs/components/navigation/tabs/Tabs.d.ts +7 -0
- package/dist/cjs/components/navigation/tabs/Tabs.props.d.ts +12 -0
- package/dist/cjs/components/navigation/tabs/Tabs.styles.d.ts +7 -0
- package/dist/cjs/components/navigation/tabs/index.d.ts +4 -0
- package/dist/cjs/components/navigation/tabs/tab-item/TabItem.d.ts +7 -0
- package/dist/cjs/components/navigation/tabs/tab-item/TabItem.props.d.ts +10 -0
- package/dist/cjs/components/navigation/tabs/tab-item/TabItem.styles.d.ts +6 -0
- package/dist/cjs/components/overlay/menu/Menu.d.ts +4 -0
- package/dist/cjs/components/overlay/menu/Menu.props.d.ts +8 -0
- package/dist/cjs/components/overlay/menu/Menu.styles.d.ts +4 -0
- package/dist/cjs/components/overlay/menu/index.d.ts +2 -0
- package/dist/cjs/constants/globalConstants.d.ts +1 -0
- package/dist/cjs/hooks/index.d.ts +5 -0
- package/dist/cjs/hooks/useAnchorPosition.d.ts +17 -0
- package/dist/cjs/hooks/useAnchorPosition.types.d.ts +5 -0
- package/dist/cjs/hooks/useClickOutside.d.ts +8 -0
- package/dist/cjs/hooks/useTransitionRender.d.ts +7 -0
- package/dist/cjs/hooks/useTransitionRender.types.d.ts +4 -0
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.js +381 -33
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/interfaces/avatar.types.d.ts +2 -0
- package/dist/cjs/interfaces/index.d.ts +1 -0
- package/dist/cjs/utils/ui/components/data-display/avatar/getAvatarSizes.utils.d.ts +11 -0
- package/dist/esm/components/actions/button/Button.props.d.ts +2 -2
- package/dist/esm/components/actions/icon-button/IconButton.props.d.ts +2 -2
- package/dist/esm/components/data-display/avatar/Avatar.d.ts +9 -0
- package/dist/esm/components/data-display/avatar/Avatar.props.d.ts +25 -0
- package/dist/esm/components/data-display/avatar/Avatar.styles.d.ts +10 -0
- package/dist/esm/components/data-display/avatar/AvatarGroup.d.ts +9 -0
- package/dist/esm/components/data-display/avatar/avatar-group/AvatarGroup.d.ts +9 -0
- package/dist/esm/components/data-display/avatar/avatar-group/AvatarGroup.props.d.ts +10 -0
- package/dist/esm/components/data-display/avatar/avatar-group/AvatarGroup.styles.d.ts +14 -0
- package/dist/esm/components/data-display/avatar/index.d.ts +4 -0
- package/dist/esm/components/index.d.ts +4 -0
- package/dist/esm/components/layout/separator/Separator.d.ts +9 -0
- package/dist/esm/components/layout/separator/Separator.props.d.ts +17 -0
- package/dist/esm/components/layout/separator/Separator.styles.d.ts +7 -0
- package/dist/esm/components/layout/separator/index.d.ts +2 -0
- package/dist/esm/components/navigation/tabs/Tabs.d.ts +7 -0
- package/dist/esm/components/navigation/tabs/Tabs.props.d.ts +12 -0
- package/dist/esm/components/navigation/tabs/Tabs.styles.d.ts +7 -0
- package/dist/esm/components/navigation/tabs/index.d.ts +4 -0
- package/dist/esm/components/navigation/tabs/tab-item/TabItem.d.ts +7 -0
- package/dist/esm/components/navigation/tabs/tab-item/TabItem.props.d.ts +10 -0
- package/dist/esm/components/navigation/tabs/tab-item/TabItem.styles.d.ts +6 -0
- package/dist/esm/components/overlay/menu/Menu.d.ts +4 -0
- package/dist/esm/components/overlay/menu/Menu.props.d.ts +8 -0
- package/dist/esm/components/overlay/menu/Menu.styles.d.ts +4 -0
- package/dist/esm/components/overlay/menu/index.d.ts +2 -0
- package/dist/esm/constants/globalConstants.d.ts +1 -0
- package/dist/esm/hooks/index.d.ts +5 -0
- package/dist/esm/hooks/useAnchorPosition.d.ts +17 -0
- package/dist/esm/hooks/useAnchorPosition.types.d.ts +5 -0
- package/dist/esm/hooks/useClickOutside.d.ts +8 -0
- package/dist/esm/hooks/useTransitionRender.d.ts +7 -0
- package/dist/esm/hooks/useTransitionRender.types.d.ts +4 -0
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +341 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/interfaces/avatar.types.d.ts +2 -0
- package/dist/esm/interfaces/index.d.ts +1 -0
- package/dist/esm/utils/ui/components/data-display/avatar/getAvatarSizes.utils.d.ts +11 -0
- package/dist/index.d.ts +146 -5
- package/package.json +1 -1
package/dist/cjs/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
-
var
|
|
4
|
+
var React = require('react');
|
|
5
5
|
var theme = require('@aurora-ds/theme');
|
|
6
6
|
|
|
7
7
|
const ICON_STYLES = theme.createStyles((theme) => ({
|
|
@@ -58,9 +58,9 @@ const ICON_STYLES = theme.createStyles((theme) => ({
|
|
|
58
58
|
*/
|
|
59
59
|
const Icon = ({ children, size, color, backgroundColor, padding, borderRadius, ariaLabel, ariaLabelledBy, ariaDescribedBy, role, tabIndex, }) => {
|
|
60
60
|
// Clone child element to apply width and height
|
|
61
|
-
const child =
|
|
62
|
-
const styledChild =
|
|
63
|
-
?
|
|
61
|
+
const child = React.Children.only(children);
|
|
62
|
+
const styledChild = React.isValidElement(child)
|
|
63
|
+
? React.cloneElement(child, {
|
|
64
64
|
width: '100%',
|
|
65
65
|
height: '100%',
|
|
66
66
|
})
|
|
@@ -183,7 +183,7 @@ const parseTextWithBold = (children) => {
|
|
|
183
183
|
if (match.index > lastIndex) {
|
|
184
184
|
parts.push(children.slice(lastIndex, match.index));
|
|
185
185
|
}
|
|
186
|
-
parts.push(
|
|
186
|
+
parts.push(React.createElement('strong', { key: match.index }, match[1]));
|
|
187
187
|
lastIndex = match.index + match[0].length;
|
|
188
188
|
}
|
|
189
189
|
if (parts.length === 0) {
|
|
@@ -192,7 +192,7 @@ const parseTextWithBold = (children) => {
|
|
|
192
192
|
if (lastIndex < children.length) {
|
|
193
193
|
parts.push(children.slice(lastIndex));
|
|
194
194
|
}
|
|
195
|
-
return
|
|
195
|
+
return React.createElement(React.Fragment, null, ...parts);
|
|
196
196
|
};
|
|
197
197
|
|
|
198
198
|
/**
|
|
@@ -214,10 +214,10 @@ const parseTextWithBold = (children) => {
|
|
|
214
214
|
*/
|
|
215
215
|
const Text = ({ children, variant = 'span', color, fontSize, fontFamily, maxLines, underline, preserveWhitespace, ariaLabel, ariaLabelledBy, ariaDescribedBy, role, tabIndex, }) => {
|
|
216
216
|
const theme$1 = theme.useTheme();
|
|
217
|
-
const variantStyles =
|
|
217
|
+
const variantStyles = React.useMemo(() => getTextVariantStyles(theme$1), [theme$1]);
|
|
218
218
|
const tag = variantStyles[variant].tag;
|
|
219
|
-
const parsedChildren =
|
|
220
|
-
return
|
|
219
|
+
const parsedChildren = React.useMemo(() => parseTextWithBold(children), [children]);
|
|
220
|
+
return React.createElement(tag, {
|
|
221
221
|
className: TEXT_STYLES.root({ variant, color, fontSize, fontFamily, maxLines, underline, preserveWhitespace }),
|
|
222
222
|
'aria-label': ariaLabel,
|
|
223
223
|
'aria-labelledby': ariaLabelledBy,
|
|
@@ -420,6 +420,119 @@ Chip.displayName = 'Chip';
|
|
|
420
420
|
|
|
421
421
|
const BUTTON_SIZE = 36;
|
|
422
422
|
const DRAWER_ITEM_HEIGHT = 32;
|
|
423
|
+
const DEFAULT_TRANSITION_DURATION_MS = 150;
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Get avatar sizes configuration based on the theme
|
|
427
|
+
* @param theme
|
|
428
|
+
*/
|
|
429
|
+
const getAvatarSizes = (theme) => ({
|
|
430
|
+
small: { size: BUTTON_SIZE - 8, fontSize: 'xs', overlap: `-${theme.spacing.md}` },
|
|
431
|
+
medium: { size: BUTTON_SIZE, fontSize: 'sm', overlap: `-${theme.spacing.md}` },
|
|
432
|
+
large: { size: BUTTON_SIZE + 8, fontSize: 'sm', overlap: `-${theme.spacing.lg}` },
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Avatar styles using createStyles from @aurora-ds/theme
|
|
437
|
+
*/
|
|
438
|
+
const AVATAR_STYLES = theme.createStyles((theme) => {
|
|
439
|
+
const AVATAR_SIZES = getAvatarSizes(theme);
|
|
440
|
+
return {
|
|
441
|
+
root: ({ hasImage = false, clickable = false, size = 'medium', color, borderColor, backgroundColor }) => {
|
|
442
|
+
const sizeConfig = AVATAR_SIZES[size];
|
|
443
|
+
return {
|
|
444
|
+
width: sizeConfig.size,
|
|
445
|
+
height: sizeConfig.size,
|
|
446
|
+
borderRadius: theme.radius.full,
|
|
447
|
+
backgroundColor: backgroundColor || (hasImage ? 'transparent' : theme.colors.surfaceHover),
|
|
448
|
+
display: 'flex',
|
|
449
|
+
alignItems: 'center',
|
|
450
|
+
justifyContent: 'center',
|
|
451
|
+
cursor: clickable ? 'pointer' : 'default',
|
|
452
|
+
border: hasImage && !borderColor ? 'none' : `1px solid ${borderColor || theme.colors.border}`,
|
|
453
|
+
overflow: 'hidden',
|
|
454
|
+
flexShrink: 0,
|
|
455
|
+
color: color || theme.colors.textSecondary,
|
|
456
|
+
fontWeight: theme.fontWeight.medium,
|
|
457
|
+
};
|
|
458
|
+
},
|
|
459
|
+
image: {
|
|
460
|
+
width: '100%',
|
|
461
|
+
height: '100%',
|
|
462
|
+
objectFit: 'cover',
|
|
463
|
+
},
|
|
464
|
+
};
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Avatar component
|
|
469
|
+
*
|
|
470
|
+
* Displays a user's avatar with optional image or fallback text.
|
|
471
|
+
*/
|
|
472
|
+
const Avatar = ({ image, label, onClick, size = 'medium', color, borderColor, backgroundColor, }) => {
|
|
473
|
+
// hooks
|
|
474
|
+
const theme$1 = theme.useTheme();
|
|
475
|
+
// variables
|
|
476
|
+
const AVATAR_SIZES = getAvatarSizes(theme$1);
|
|
477
|
+
const hasImage = !!image;
|
|
478
|
+
const clickable = !!onClick;
|
|
479
|
+
return (jsxRuntime.jsx("div", { className: AVATAR_STYLES.root({ hasImage, clickable, size, color, borderColor, backgroundColor }), onClick: onClick, children: hasImage ? (jsxRuntime.jsx("img", { src: image, alt: label || 'Avatar', className: AVATAR_STYLES.image })) : (jsxRuntime.jsx(Text, { variant: 'label', fontSize: AVATAR_SIZES[size].fontSize, children: label || '?' })) }));
|
|
480
|
+
};
|
|
481
|
+
Avatar.displayName = 'Avatar';
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* AvatarGroup styles using createStyles from @aurora-ds/theme
|
|
485
|
+
*/
|
|
486
|
+
const AVATAR_GROUP_STYLES = theme.createStyles((theme) => {
|
|
487
|
+
const AVATAR_SIZES = getAvatarSizes(theme);
|
|
488
|
+
return {
|
|
489
|
+
root: {
|
|
490
|
+
display: 'flex',
|
|
491
|
+
alignItems: 'center',
|
|
492
|
+
},
|
|
493
|
+
child: ({ size = 'medium' }) => ({
|
|
494
|
+
marginLeft: AVATAR_SIZES[size].overlap,
|
|
495
|
+
}),
|
|
496
|
+
firstChild: {
|
|
497
|
+
marginLeft: '0',
|
|
498
|
+
},
|
|
499
|
+
more: ({ size = 'medium' }) => {
|
|
500
|
+
const sizeConfig = AVATAR_SIZES[size];
|
|
501
|
+
return {
|
|
502
|
+
width: sizeConfig.size,
|
|
503
|
+
height: sizeConfig.size,
|
|
504
|
+
borderRadius: theme.radius.full,
|
|
505
|
+
backgroundColor: theme.colors.surfaceHover,
|
|
506
|
+
border: `1px solid ${theme.colors.border}`,
|
|
507
|
+
display: 'flex',
|
|
508
|
+
alignItems: 'center',
|
|
509
|
+
justifyContent: 'center',
|
|
510
|
+
color: theme.colors.textSecondary,
|
|
511
|
+
fontSize: sizeConfig.fontSize,
|
|
512
|
+
fontWeight: theme.fontWeight.medium,
|
|
513
|
+
flexShrink: 0,
|
|
514
|
+
marginLeft: AVATAR_SIZES[size].overlap,
|
|
515
|
+
};
|
|
516
|
+
},
|
|
517
|
+
};
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* AvatarGroup component
|
|
522
|
+
*
|
|
523
|
+
* Groups multiple avatars with overlapping display and optional limit.
|
|
524
|
+
*/
|
|
525
|
+
const AvatarGroup = ({ children, limit, size = 'medium' }) => {
|
|
526
|
+
// hooks
|
|
527
|
+
const theme$1 = theme.useTheme();
|
|
528
|
+
// variables
|
|
529
|
+
const AVATAR_SIZES = getAvatarSizes(theme$1);
|
|
530
|
+
const childArray = React.Children.toArray(children);
|
|
531
|
+
const displayedChildren = limit ? childArray.slice(0, limit) : childArray;
|
|
532
|
+
const moreCount = limit && childArray.length > limit ? childArray.length - limit : 0;
|
|
533
|
+
return (jsxRuntime.jsxs("div", { className: AVATAR_GROUP_STYLES.root, children: [displayedChildren.map((child, index) => (jsxRuntime.jsx("div", { className: index === 0 ? AVATAR_GROUP_STYLES.firstChild : AVATAR_GROUP_STYLES.child({ size }), children: child }, index))), moreCount > 0 && (jsxRuntime.jsx("div", { className: AVATAR_GROUP_STYLES.more({ size }), children: jsxRuntime.jsxs(Text, { variant: 'label', fontSize: AVATAR_SIZES[size].fontSize, children: ["+", moreCount] }) }))] }));
|
|
534
|
+
};
|
|
535
|
+
AvatarGroup.displayName = 'AvatarGroup';
|
|
423
536
|
|
|
424
537
|
const getButtonSizeStyles = () => ({
|
|
425
538
|
small: {
|
|
@@ -653,14 +766,14 @@ const FORM_STYLES = theme.createStyles(() => ({
|
|
|
653
766
|
* Form component - A transparent wrapper for form elements with automatic preventDefault handling
|
|
654
767
|
*/
|
|
655
768
|
const Form = ({ children, onSubmit, ariaLabel, }) => {
|
|
656
|
-
const handleSubmit =
|
|
769
|
+
const handleSubmit = React.useCallback((e) => {
|
|
657
770
|
e.preventDefault();
|
|
658
771
|
onSubmit?.(e);
|
|
659
772
|
}, [onSubmit]);
|
|
660
773
|
return (jsxRuntime.jsx("form", { onSubmit: handleSubmit, className: FORM_STYLES.root, "aria-label": ariaLabel, children: children }));
|
|
661
774
|
};
|
|
662
775
|
Form.displayName = 'Form';
|
|
663
|
-
var Form_default =
|
|
776
|
+
var Form_default = React.memo(Form);
|
|
664
777
|
|
|
665
778
|
/**
|
|
666
779
|
* Input styles using createStyles from @aurora-ds/theme
|
|
@@ -800,8 +913,8 @@ const MoreHorizontalIcon = () => {
|
|
|
800
913
|
/**
|
|
801
914
|
* Input component
|
|
802
915
|
*/
|
|
803
|
-
const Input =
|
|
804
|
-
const [showPassword, setShowPassword] =
|
|
916
|
+
const Input = React.forwardRef(({ value, onChange, label, mandatory = false, placeholder, disabled = false, type = 'text', ariaLabel, startIcon, endIcon, width, }, ref) => {
|
|
917
|
+
const [showPassword, setShowPassword] = React.useState(false);
|
|
805
918
|
const handleChange = (event) => {
|
|
806
919
|
onChange(event.target.value);
|
|
807
920
|
};
|
|
@@ -810,7 +923,7 @@ const Input = react.forwardRef(({ value, onChange, label, mandatory = false, pla
|
|
|
810
923
|
return (jsxRuntime.jsxs(Stack, { direction: 'column', gap: 'xs', align: 'stretch', width: width ?? '100%', children: [label && (jsxRuntime.jsxs(Stack, { direction: 'row', gap: 'xs', align: 'center', children: [jsxRuntime.jsx(Text, { variant: 'label', fontSize: 'sm', children: label }), mandatory && (jsxRuntime.jsx(Text, { variant: 'label', fontSize: 'sm', color: 'error', children: "*" }))] })), jsxRuntime.jsxs("div", { className: `${INPUT_STYLES.container({ width })} ${disabled ? 'disabled' : ''}`, children: [jsxRuntime.jsx("input", { ref: ref, type: inputType, value: value, onChange: handleChange, placeholder: placeholder, disabled: disabled, className: INPUT_STYLES.root({ disabled, hasStartIcon: !!startIcon, hasEndIcon: !!endIcon, hasPasswordToggle }), "aria-label": ariaLabel || label }), startIcon && (jsxRuntime.jsx("div", { className: INPUT_STYLES.startIcon, children: jsxRuntime.jsx(Icon, { color: 'textTertiary', children: startIcon }) })), endIcon && (jsxRuntime.jsx("div", { className: hasPasswordToggle ? INPUT_STYLES.endIconShifted : INPUT_STYLES.endIcon, children: jsxRuntime.jsx(Icon, { color: 'textTertiary', children: endIcon }) })), hasPasswordToggle && (jsxRuntime.jsx("div", { className: INPUT_STYLES.passwordToggle, children: jsxRuntime.jsx(IconButton, { icon: showPassword ? jsxRuntime.jsx(EyeOffIcon, {}) : jsxRuntime.jsx(EyeIcon, {}), onClick: () => setShowPassword(!showPassword), disabled: disabled, ariaLabel: ariaLabel || label, variant: 'text', size: 'small', textColor: 'textSecondary' }) }))] })] }));
|
|
811
924
|
});
|
|
812
925
|
Input.displayName = 'Input';
|
|
813
|
-
var Input_default =
|
|
926
|
+
var Input_default = React.memo(Input);
|
|
814
927
|
|
|
815
928
|
/**
|
|
816
929
|
* TextArea styles using createStyles from @aurora-ds/theme
|
|
@@ -860,10 +973,10 @@ const TEXTAREA_STYLES = theme.createStyles((theme) => ({
|
|
|
860
973
|
/**
|
|
861
974
|
* TextArea component with auto-expanding height based on content
|
|
862
975
|
*/
|
|
863
|
-
const TextArea =
|
|
864
|
-
const internalRef =
|
|
976
|
+
const TextArea = React.forwardRef(({ value, onChange, label, mandatory = false, placeholder, disabled = false, ariaLabel, width, minRows = 3, maxRows, }, ref) => {
|
|
977
|
+
const internalRef = React.useRef(null);
|
|
865
978
|
const textareaRef = ref || internalRef;
|
|
866
|
-
const adjustHeight =
|
|
979
|
+
const adjustHeight = React.useCallback(() => {
|
|
867
980
|
const textarea = textareaRef.current;
|
|
868
981
|
if (textarea) {
|
|
869
982
|
// Reset height to calculate the correct scrollHeight
|
|
@@ -879,7 +992,7 @@ const TextArea = react.forwardRef(({ value, onChange, label, mandatory = false,
|
|
|
879
992
|
textarea.style.overflowY = textarea.scrollHeight > maxHeight ? 'auto' : 'hidden';
|
|
880
993
|
}
|
|
881
994
|
}, [minRows, maxRows, textareaRef]);
|
|
882
|
-
|
|
995
|
+
React.useEffect(() => {
|
|
883
996
|
adjustHeight();
|
|
884
997
|
}, [value, adjustHeight]);
|
|
885
998
|
const handleChange = (event) => {
|
|
@@ -888,7 +1001,7 @@ const TextArea = react.forwardRef(({ value, onChange, label, mandatory = false,
|
|
|
888
1001
|
return (jsxRuntime.jsxs(Stack, { direction: 'column', gap: 'xs', align: 'stretch', width: width ?? '100%', children: [label && (jsxRuntime.jsxs(Stack, { direction: 'row', gap: 'xs', align: 'center', children: [jsxRuntime.jsx(Text, { variant: 'label', fontSize: 'sm', children: label }), mandatory && (jsxRuntime.jsx(Text, { variant: 'label', fontSize: 'sm', color: 'error', children: "*" }))] })), jsxRuntime.jsx("div", { className: `${TEXTAREA_STYLES.container({ width })} ${disabled ? 'disabled' : ''}`, children: jsxRuntime.jsx("textarea", { ref: textareaRef, value: value, onChange: handleChange, placeholder: placeholder, disabled: disabled, className: TEXTAREA_STYLES.root({ disabled }), "aria-label": ariaLabel || label, rows: minRows }) })] }));
|
|
889
1002
|
});
|
|
890
1003
|
TextArea.displayName = 'TextArea';
|
|
891
|
-
var TextArea_default =
|
|
1004
|
+
var TextArea_default = React.memo(TextArea);
|
|
892
1005
|
|
|
893
1006
|
/**
|
|
894
1007
|
* Card styles using createStyles from @aurora-ds/theme
|
|
@@ -1009,6 +1122,34 @@ const Grid = ({ children, columns = 1, rows, gap = 'sm', columnGap, rowGap, widt
|
|
|
1009
1122
|
};
|
|
1010
1123
|
Grid.displayName = 'Grid';
|
|
1011
1124
|
|
|
1125
|
+
/**
|
|
1126
|
+
* Separator styles using createStyles from @aurora-ds/theme
|
|
1127
|
+
*/
|
|
1128
|
+
const SEPARATOR_STYLES = theme.createStyles((theme) => ({
|
|
1129
|
+
root: ({ direction = 'horizontal', color = 'border', width, height }) => ({
|
|
1130
|
+
backgroundColor: theme.colors[color],
|
|
1131
|
+
...(direction === 'horizontal' ? {
|
|
1132
|
+
width: '100%',
|
|
1133
|
+
height: '1px',
|
|
1134
|
+
} : {
|
|
1135
|
+
width: '1px',
|
|
1136
|
+
height: '100%',
|
|
1137
|
+
}),
|
|
1138
|
+
...(width !== undefined && { width }),
|
|
1139
|
+
...(height !== undefined && { height }),
|
|
1140
|
+
}),
|
|
1141
|
+
}));
|
|
1142
|
+
|
|
1143
|
+
/**
|
|
1144
|
+
* Separator component
|
|
1145
|
+
*
|
|
1146
|
+
* A simple separator line for horizontal or vertical division.
|
|
1147
|
+
*/
|
|
1148
|
+
const Separator = ({ direction = 'horizontal', width, height, color = 'border', }) => {
|
|
1149
|
+
return (jsxRuntime.jsx("div", { className: SEPARATOR_STYLES.root({ direction, color, width, height }) }));
|
|
1150
|
+
};
|
|
1151
|
+
Separator.displayName = 'Separator';
|
|
1152
|
+
|
|
1012
1153
|
const PAGE_SECTION_STYLES = theme.createStyles((theme) => ({
|
|
1013
1154
|
root: ({ gap, paddingHorizontal, paddingVertical, alignItems = 'center', maxWidth, minHeight }) => ({
|
|
1014
1155
|
display: 'flex',
|
|
@@ -1106,7 +1247,7 @@ const ACCORDION_STYLES = theme.createStyles((theme) => {
|
|
|
1106
1247
|
* Supports controlled and uncontrolled modes.
|
|
1107
1248
|
*/
|
|
1108
1249
|
const Accordion = ({ title, children, expanded, defaultExpanded = false, onChange, disabled = false, icon, backgroundColor, width, headerPadding, contentPadding, ariaLabel, ariaLabelledBy, ariaDescribedBy, role, tabIndex, }) => {
|
|
1109
|
-
const [internalExpanded, setInternalExpanded] =
|
|
1250
|
+
const [internalExpanded, setInternalExpanded] = React.useState(defaultExpanded);
|
|
1110
1251
|
// Use controlled value if provided, otherwise use internal state
|
|
1111
1252
|
const isExpanded = expanded !== undefined ? expanded : internalExpanded;
|
|
1112
1253
|
const handleToggle = () => {
|
|
@@ -1123,6 +1264,141 @@ const Accordion = ({ title, children, expanded, defaultExpanded = false, onChang
|
|
|
1123
1264
|
};
|
|
1124
1265
|
Accordion.displayName = 'Accordion';
|
|
1125
1266
|
|
|
1267
|
+
const MENU_STYLES = theme.createStyles((theme) => ({
|
|
1268
|
+
root: (isFadingIn, anchorOrigin, position) => ({
|
|
1269
|
+
position: 'absolute',
|
|
1270
|
+
zIndex: theme.zIndex.dropdown,
|
|
1271
|
+
marginTop: theme.spacing.xs,
|
|
1272
|
+
backgroundColor: theme.colors.surface,
|
|
1273
|
+
borderRadius: theme.radius.md,
|
|
1274
|
+
border: `1px solid ${theme.colors.border}`,
|
|
1275
|
+
boxShadow: theme.shadows.md,
|
|
1276
|
+
minWidth: 150,
|
|
1277
|
+
opacity: isFadingIn ? 1 : 0,
|
|
1278
|
+
transform: isFadingIn ? 'scale(1)' : 'scale(0.95)',
|
|
1279
|
+
transformOrigin: anchorOrigin === 'right' ? 'top right' : 'top left',
|
|
1280
|
+
transition: `opacity ${DEFAULT_TRANSITION_DURATION_MS}ms ease-out, transform ${DEFAULT_TRANSITION_DURATION_MS}ms ease-out`,
|
|
1281
|
+
top: position?.top ?? 0,
|
|
1282
|
+
left: position?.left ?? 0,
|
|
1283
|
+
visibility: position ? 'visible' : 'hidden',
|
|
1284
|
+
}),
|
|
1285
|
+
}));
|
|
1286
|
+
|
|
1287
|
+
/**
|
|
1288
|
+
* Hook pour calculer la position d'un élément par rapport à son ancre
|
|
1289
|
+
* @param anchor - Élément HTML servant d'ancre
|
|
1290
|
+
* @param menuRef - Référence vers l'élément à positionner
|
|
1291
|
+
* @param anchorOrigin - Origine de l'ancrage ('left' ou 'right')
|
|
1292
|
+
* @param isVisible - Si l'élément est visible (pour recalculer la position)
|
|
1293
|
+
*/
|
|
1294
|
+
const useAnchorPosition = ({ anchor, menuRef, anchorOrigin = 'right', isVisible }) => {
|
|
1295
|
+
const [position, setPosition] = React.useState(null);
|
|
1296
|
+
React.useLayoutEffect(() => {
|
|
1297
|
+
if (anchor && isVisible) {
|
|
1298
|
+
const anchorRect = anchor.getBoundingClientRect();
|
|
1299
|
+
const menuWidth = menuRef.current?.offsetWidth || 150;
|
|
1300
|
+
const left = anchorOrigin === 'right'
|
|
1301
|
+
? anchorRect.right - menuWidth + window.scrollX
|
|
1302
|
+
: anchorRect.left + window.scrollX;
|
|
1303
|
+
setPosition({
|
|
1304
|
+
top: anchorRect.bottom + window.scrollY,
|
|
1305
|
+
left
|
|
1306
|
+
});
|
|
1307
|
+
}
|
|
1308
|
+
else {
|
|
1309
|
+
setPosition(null);
|
|
1310
|
+
}
|
|
1311
|
+
}, [anchor, anchorOrigin, isVisible, menuRef]);
|
|
1312
|
+
return position;
|
|
1313
|
+
};
|
|
1314
|
+
|
|
1315
|
+
/**
|
|
1316
|
+
* Gestion d'un click en dehors d'un ou plusieurs éléments
|
|
1317
|
+
* @param refs Tableau de références à écouter
|
|
1318
|
+
* @param onClickOutside Callback si clic à l'extérieur
|
|
1319
|
+
* @param shouldTrigger Activation du comportement
|
|
1320
|
+
*/
|
|
1321
|
+
const useClickOutside = (refs, onClickOutside, shouldTrigger = true) => {
|
|
1322
|
+
React.useEffect(() => {
|
|
1323
|
+
if (!shouldTrigger) {
|
|
1324
|
+
return;
|
|
1325
|
+
}
|
|
1326
|
+
const handleClick = (event) => {
|
|
1327
|
+
const isInside = refs.some(ref => ref.current?.contains(event.target));
|
|
1328
|
+
if (!isInside) {
|
|
1329
|
+
onClickOutside();
|
|
1330
|
+
}
|
|
1331
|
+
};
|
|
1332
|
+
document.addEventListener('mousedown', handleClick);
|
|
1333
|
+
return () => {
|
|
1334
|
+
document.removeEventListener('mousedown', handleClick);
|
|
1335
|
+
};
|
|
1336
|
+
}, [refs, onClickOutside, shouldTrigger]);
|
|
1337
|
+
};
|
|
1338
|
+
|
|
1339
|
+
/**
|
|
1340
|
+
* Hook pour gérer les animations de transition lors des renders
|
|
1341
|
+
* @param isOpen - État d'ouverture
|
|
1342
|
+
* @param duration - Durée de la transition en ms
|
|
1343
|
+
*/
|
|
1344
|
+
const useTransitionRender = (isOpen, duration = DEFAULT_TRANSITION_DURATION_MS) => {
|
|
1345
|
+
const [isVisible, setIsVisible] = React.useState(false);
|
|
1346
|
+
const [isFadingIn, setIsFadingIn] = React.useState(false);
|
|
1347
|
+
React.useEffect(() => {
|
|
1348
|
+
if (isOpen) {
|
|
1349
|
+
setIsVisible(true);
|
|
1350
|
+
const timeout = setTimeout(() => {
|
|
1351
|
+
setIsFadingIn(true);
|
|
1352
|
+
}, 10);
|
|
1353
|
+
return () => {
|
|
1354
|
+
clearTimeout(timeout);
|
|
1355
|
+
};
|
|
1356
|
+
}
|
|
1357
|
+
else {
|
|
1358
|
+
setIsFadingIn(false);
|
|
1359
|
+
const timeout = setTimeout(() => {
|
|
1360
|
+
setIsVisible(false);
|
|
1361
|
+
}, duration);
|
|
1362
|
+
return () => {
|
|
1363
|
+
clearTimeout(timeout);
|
|
1364
|
+
};
|
|
1365
|
+
}
|
|
1366
|
+
}, [isOpen, duration]);
|
|
1367
|
+
return {
|
|
1368
|
+
isVisible,
|
|
1369
|
+
isFadingIn
|
|
1370
|
+
};
|
|
1371
|
+
};
|
|
1372
|
+
|
|
1373
|
+
const Menu = ({ anchor, onClose, children, anchorOrigin = 'right' }) => {
|
|
1374
|
+
// refs
|
|
1375
|
+
const menuRef = React.useRef(null);
|
|
1376
|
+
const anchorRef = React.useRef(null);
|
|
1377
|
+
// variables
|
|
1378
|
+
const isOpen = Boolean(anchor);
|
|
1379
|
+
const refs = React.useMemo(() => [menuRef, anchorRef], []);
|
|
1380
|
+
// hooks
|
|
1381
|
+
const { isVisible, isFadingIn } = useTransitionRender(isOpen);
|
|
1382
|
+
const position = useAnchorPosition({ anchor: anchorRef.current, menuRef, anchorOrigin, isVisible });
|
|
1383
|
+
// useEffects
|
|
1384
|
+
React.useEffect(() => {
|
|
1385
|
+
if (anchor) {
|
|
1386
|
+
anchorRef.current = anchor;
|
|
1387
|
+
}
|
|
1388
|
+
}, [anchor]);
|
|
1389
|
+
React.useEffect(() => {
|
|
1390
|
+
if (!isVisible) {
|
|
1391
|
+
anchorRef.current = null;
|
|
1392
|
+
}
|
|
1393
|
+
}, [isVisible]);
|
|
1394
|
+
useClickOutside(refs, onClose, isVisible);
|
|
1395
|
+
if (!isVisible) {
|
|
1396
|
+
return null;
|
|
1397
|
+
}
|
|
1398
|
+
return (jsxRuntime.jsx("div", { ref: menuRef, className: MENU_STYLES.root(isFadingIn, anchorOrigin, position), children: children }));
|
|
1399
|
+
};
|
|
1400
|
+
Menu.displayName = 'Menu';
|
|
1401
|
+
|
|
1126
1402
|
/**
|
|
1127
1403
|
* DrawerItem styles using createStyles from @aurora-ds/theme
|
|
1128
1404
|
*/
|
|
@@ -1226,8 +1502,8 @@ const insertSeparators = (items, SeparatorComponent) => {
|
|
|
1226
1502
|
const result = [];
|
|
1227
1503
|
items.forEach((item, index) => {
|
|
1228
1504
|
// Add the item with a key
|
|
1229
|
-
const itemWithKey =
|
|
1230
|
-
?
|
|
1505
|
+
const itemWithKey = React.isValidElement(item)
|
|
1506
|
+
? React.cloneElement(item, { key: `item-${index}` })
|
|
1231
1507
|
: item;
|
|
1232
1508
|
result.push(itemWithKey);
|
|
1233
1509
|
// Add separator after each item except the last one
|
|
@@ -1253,8 +1529,8 @@ const buildBreadcrumbChildren = (items, maxItems, EllipsisComponent, SeparatorCo
|
|
|
1253
1529
|
// Build the result: first + separator + ellipsis + separator + last items with separators between them
|
|
1254
1530
|
const result = [];
|
|
1255
1531
|
// Add first item with key
|
|
1256
|
-
const firstWithKey =
|
|
1257
|
-
?
|
|
1532
|
+
const firstWithKey = React.isValidElement(firstItem)
|
|
1533
|
+
? React.cloneElement(firstItem, { key: 'first' })
|
|
1258
1534
|
: firstItem;
|
|
1259
1535
|
result.push(firstWithKey);
|
|
1260
1536
|
// Add separator + ellipsis + separator
|
|
@@ -1263,8 +1539,8 @@ const buildBreadcrumbChildren = (items, maxItems, EllipsisComponent, SeparatorCo
|
|
|
1263
1539
|
result.push(jsxRuntime.jsx(SeparatorComponent, {}, 'sep-ellipsis-after'));
|
|
1264
1540
|
// Add last items with separators between them
|
|
1265
1541
|
lastItems.forEach((item, index) => {
|
|
1266
|
-
const itemWithKey =
|
|
1267
|
-
?
|
|
1542
|
+
const itemWithKey = React.isValidElement(item)
|
|
1543
|
+
? React.cloneElement(item, { key: `last-${index}` })
|
|
1268
1544
|
: item;
|
|
1269
1545
|
result.push(itemWithKey);
|
|
1270
1546
|
// Add separator between items (but not after the last one)
|
|
@@ -1280,8 +1556,8 @@ const buildBreadcrumbChildren = (items, maxItems, EllipsisComponent, SeparatorCo
|
|
|
1280
1556
|
*/
|
|
1281
1557
|
const flattenChildren = (children) => {
|
|
1282
1558
|
const result = [];
|
|
1283
|
-
|
|
1284
|
-
if (
|
|
1559
|
+
React.Children.forEach(children, (child) => {
|
|
1560
|
+
if (React.isValidElement(child) && child.type === React.Fragment) {
|
|
1285
1561
|
result.push(...flattenChildren(child.props.children));
|
|
1286
1562
|
}
|
|
1287
1563
|
else {
|
|
@@ -1295,7 +1571,7 @@ const flattenChildren = (children) => {
|
|
|
1295
1571
|
* Checks if a React element is a BreadcrumbSeparator
|
|
1296
1572
|
*/
|
|
1297
1573
|
const isSeparator = (child) => {
|
|
1298
|
-
return
|
|
1574
|
+
return React.isValidElement(child) && child.type?.displayName === 'BreadcrumbSeparator';
|
|
1299
1575
|
};
|
|
1300
1576
|
|
|
1301
1577
|
/**
|
|
@@ -1307,11 +1583,11 @@ const isSeparator = (child) => {
|
|
|
1307
1583
|
* @param children
|
|
1308
1584
|
* @param props
|
|
1309
1585
|
*/
|
|
1310
|
-
const Breadcrumb =
|
|
1586
|
+
const Breadcrumb = React.memo(({ maxItems, children, ...props }) => {
|
|
1311
1587
|
const allChildren = flattenChildren(children);
|
|
1312
1588
|
// Filter out any manually added separators (in case user added them)
|
|
1313
1589
|
const items = allChildren.filter(child => !isSeparator(child));
|
|
1314
|
-
const renderedChildren =
|
|
1590
|
+
const renderedChildren = React.useMemo(() => buildBreadcrumbChildren(items, maxItems, BreadcrumbEllipsis, BreadcrumbSeparator), [items, maxItems]);
|
|
1315
1591
|
return (jsxRuntime.jsx("nav", { "aria-label": 'breadcrumb', ...props, children: jsxRuntime.jsx("ol", { className: BREADCRUMB_STYLES.list, children: renderedChildren }) }));
|
|
1316
1592
|
});
|
|
1317
1593
|
Breadcrumb.displayName = 'Breadcrumb';
|
|
@@ -1343,7 +1619,7 @@ const BREADCRUMB_LINK_STYLES = theme.createStyles((theme) => ({
|
|
|
1343
1619
|
* BreadcrumbLink component
|
|
1344
1620
|
* Renders a clickable breadcrumb item with a link
|
|
1345
1621
|
*/
|
|
1346
|
-
const BreadcrumbLink =
|
|
1622
|
+
const BreadcrumbLink = React.memo((props) => {
|
|
1347
1623
|
const { children, onClick } = props;
|
|
1348
1624
|
return (jsxRuntime.jsx("li", { className: BREADCRUMB_LINK_STYLES.item, children: jsxRuntime.jsx("a", { className: BREADCRUMB_LINK_STYLES.link, onClick: onClick, children: jsxRuntime.jsx(Text, { variant: 'span', fontSize: 'sm', children: children }) }) }));
|
|
1349
1625
|
});
|
|
@@ -1368,10 +1644,75 @@ const BREADCRUMB_PAGE_STYLES = theme.createStyles((theme) => ({
|
|
|
1368
1644
|
* BreadcrumbPage component
|
|
1369
1645
|
* Renders the current page (non-clickable) in the breadcrumb
|
|
1370
1646
|
*/
|
|
1371
|
-
const BreadcrumbPage =
|
|
1647
|
+
const BreadcrumbPage = React.memo(({ children }) => (jsxRuntime.jsx("li", { className: BREADCRUMB_PAGE_STYLES.item, children: jsxRuntime.jsx("span", { className: BREADCRUMB_PAGE_STYLES.page, children: jsxRuntime.jsx(Text, { variant: 'span', fontSize: 'sm', color: 'primary', children: children }) }) })));
|
|
1372
1648
|
BreadcrumbPage.displayName = 'BreadcrumbPage';
|
|
1373
1649
|
|
|
1650
|
+
/**
|
|
1651
|
+
* Tabs styles using createStyles from @aurora-ds/theme
|
|
1652
|
+
*/
|
|
1653
|
+
const TABS_STYLES = theme.createStyles((theme) => ({
|
|
1654
|
+
root: ({ width = '100%' }) => ({
|
|
1655
|
+
display: 'flex',
|
|
1656
|
+
width,
|
|
1657
|
+
backgroundColor: theme.colors.surfaceHover,
|
|
1658
|
+
borderRadius: theme.radius.md,
|
|
1659
|
+
overflow: 'hidden',
|
|
1660
|
+
padding: theme.spacing.xs,
|
|
1661
|
+
height: `calc(2 * ${theme.spacing.xs} + ${BUTTON_SIZE}px)`,
|
|
1662
|
+
}),
|
|
1663
|
+
}));
|
|
1664
|
+
|
|
1665
|
+
/**
|
|
1666
|
+
* Tabs component for navigation between multiple sections
|
|
1667
|
+
*/
|
|
1668
|
+
const Tabs = ({ children, activeTab, width = '100%', }) => {
|
|
1669
|
+
return (jsxRuntime.jsx("div", { className: TABS_STYLES.root({ width }), children: React.Children.map(children, (child, index) => {
|
|
1670
|
+
if (React.isValidElement(child)) {
|
|
1671
|
+
const tabValue = child.props.value;
|
|
1672
|
+
const isActive = activeTab === tabValue || (activeTab === undefined && index === 0);
|
|
1673
|
+
return React.cloneElement(child, {
|
|
1674
|
+
isActive,
|
|
1675
|
+
});
|
|
1676
|
+
}
|
|
1677
|
+
return child;
|
|
1678
|
+
}) }));
|
|
1679
|
+
};
|
|
1680
|
+
Tabs.displayName = 'Tabs';
|
|
1681
|
+
|
|
1682
|
+
/**
|
|
1683
|
+
* Tabs styles using createStyles from @aurora-ds/theme
|
|
1684
|
+
*/
|
|
1685
|
+
const TAB_ITEM_STYLES = theme.createStyles((theme) => ({
|
|
1686
|
+
tab: (isActive) => ({
|
|
1687
|
+
flex: 1,
|
|
1688
|
+
padding: theme.spacing.sm,
|
|
1689
|
+
height: BUTTON_SIZE,
|
|
1690
|
+
borderRadius: theme.radius.sm,
|
|
1691
|
+
cursor: 'pointer',
|
|
1692
|
+
transition: `background-color ${theme.transition.fast}, color ${theme.transition.fast}, boxShadow ${theme.transition.fast}`,
|
|
1693
|
+
display: 'flex',
|
|
1694
|
+
alignItems: 'center',
|
|
1695
|
+
justifyContent: 'center',
|
|
1696
|
+
backgroundColor: isActive ? theme.colors.background : 'transparent',
|
|
1697
|
+
color: isActive ? theme.colors.text : theme.colors.textSecondary,
|
|
1698
|
+
boxShadow: isActive ? theme.shadows.sm : undefined,
|
|
1699
|
+
':hover': {
|
|
1700
|
+
backgroundColor: !isActive ? theme.colors.secondaryActive : undefined,
|
|
1701
|
+
},
|
|
1702
|
+
}),
|
|
1703
|
+
}));
|
|
1704
|
+
|
|
1705
|
+
/**
|
|
1706
|
+
* TabItem component for use inside Tabs
|
|
1707
|
+
*/
|
|
1708
|
+
const TabItem = ({ label, isActive = false, onClick, }) => {
|
|
1709
|
+
return (jsxRuntime.jsx("div", { className: TAB_ITEM_STYLES.tab(isActive), onClick: onClick, children: jsxRuntime.jsx(Text, { variant: 'label', preserveWhitespace: true, maxLines: 1, children: label }) }));
|
|
1710
|
+
};
|
|
1711
|
+
TabItem.displayName = 'TabItem';
|
|
1712
|
+
|
|
1374
1713
|
exports.Accordion = Accordion;
|
|
1714
|
+
exports.Avatar = Avatar;
|
|
1715
|
+
exports.AvatarGroup = AvatarGroup;
|
|
1375
1716
|
exports.Breadcrumb = Breadcrumb;
|
|
1376
1717
|
exports.BreadcrumbEllipsis = BreadcrumbEllipsis;
|
|
1377
1718
|
exports.BreadcrumbLink = BreadcrumbLink;
|
|
@@ -1386,9 +1727,16 @@ exports.Grid = Grid;
|
|
|
1386
1727
|
exports.Icon = Icon;
|
|
1387
1728
|
exports.IconButton = IconButton;
|
|
1388
1729
|
exports.Input = Input_default;
|
|
1730
|
+
exports.Menu = Menu;
|
|
1389
1731
|
exports.Page = Page;
|
|
1390
1732
|
exports.PageSection = PageSection;
|
|
1733
|
+
exports.Separator = Separator;
|
|
1391
1734
|
exports.Stack = Stack;
|
|
1735
|
+
exports.TabItem = TabItem;
|
|
1736
|
+
exports.Tabs = Tabs;
|
|
1392
1737
|
exports.Text = Text;
|
|
1393
1738
|
exports.TextArea = TextArea_default;
|
|
1739
|
+
exports.useAnchorPosition = useAnchorPosition;
|
|
1740
|
+
exports.useClickOutside = useClickOutside;
|
|
1741
|
+
exports.useTransitionRender = useTransitionRender;
|
|
1394
1742
|
//# sourceMappingURL=index.js.map
|