@aurora-ds/components 0.15.4 → 0.16.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 +1 -0
- package/dist/cjs/components/data-display/skeleton/Skeleton.d.ts +4 -0
- package/dist/cjs/components/data-display/skeleton/Skeleton.props.d.ts +7 -0
- package/dist/cjs/components/data-display/skeleton/Skeleton.styles.d.ts +3 -0
- package/dist/cjs/components/data-display/skeleton/index.d.ts +2 -0
- package/dist/cjs/components/forms/select/Select.d.ts +7 -0
- package/dist/cjs/components/forms/select/Select.props.d.ts +31 -0
- package/dist/cjs/components/forms/select/Select.styles.d.ts +10 -0
- package/dist/cjs/components/forms/select/SelectItem/SelectItem.d.ts +7 -0
- package/dist/cjs/components/forms/select/SelectItem/SelectItem.props.d.ts +19 -0
- package/dist/cjs/components/forms/select/SelectItem/SelectItem.styles.d.ts +7 -0
- package/dist/cjs/components/forms/select/SelectItem/index.d.ts +2 -0
- package/dist/cjs/components/forms/select/index.d.ts +2 -0
- package/dist/cjs/components/index.d.ts +3 -0
- package/dist/cjs/components/overlay/modal/Modal.d.ts +4 -0
- package/dist/cjs/components/overlay/modal/Modal.props.d.ts +13 -0
- package/dist/cjs/components/overlay/modal/Modal.styles.d.ts +4 -0
- package/dist/cjs/components/overlay/modal/index.d.ts +2 -0
- package/dist/cjs/constants/animations.d.ts +1 -0
- package/dist/cjs/index.js +380 -169
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/interfaces/index.d.ts +1 -0
- package/dist/cjs/interfaces/select.types.d.ts +5 -0
- package/dist/cjs/resources/Icons.d.ts +2 -1
- package/dist/cjs/resources/icons/CloseIcon.d.ts +2 -0
- package/dist/esm/components/data-display/skeleton/Skeleton.d.ts +4 -0
- package/dist/esm/components/data-display/skeleton/Skeleton.props.d.ts +7 -0
- package/dist/esm/components/data-display/skeleton/Skeleton.styles.d.ts +3 -0
- package/dist/esm/components/data-display/skeleton/index.d.ts +2 -0
- package/dist/esm/components/forms/select/Select.d.ts +7 -0
- package/dist/esm/components/forms/select/Select.props.d.ts +31 -0
- package/dist/esm/components/forms/select/Select.styles.d.ts +10 -0
- package/dist/esm/components/forms/select/SelectItem/SelectItem.d.ts +7 -0
- package/dist/esm/components/forms/select/SelectItem/SelectItem.props.d.ts +19 -0
- package/dist/esm/components/forms/select/SelectItem/SelectItem.styles.d.ts +7 -0
- package/dist/esm/components/forms/select/SelectItem/index.d.ts +2 -0
- package/dist/esm/components/forms/select/index.d.ts +2 -0
- package/dist/esm/components/index.d.ts +3 -0
- package/dist/esm/components/overlay/modal/Modal.d.ts +4 -0
- package/dist/esm/components/overlay/modal/Modal.props.d.ts +13 -0
- package/dist/esm/components/overlay/modal/Modal.styles.d.ts +4 -0
- package/dist/esm/components/overlay/modal/index.d.ts +2 -0
- package/dist/esm/constants/animations.d.ts +1 -0
- package/dist/esm/index.js +381 -173
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/interfaces/index.d.ts +1 -0
- package/dist/esm/interfaces/select.types.d.ts +5 -0
- package/dist/esm/resources/Icons.d.ts +2 -1
- package/dist/esm/resources/icons/CloseIcon.d.ts +2 -0
- package/dist/index.d.ts +64 -3
- package/package.json +1 -1
package/dist/esm/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
1
|
+
import { jsx, jsxs, Fragment as Fragment$1 } from 'react/jsx-runtime';
|
|
2
2
|
import React, { Children, isValidElement, cloneElement, createElement, Fragment, useMemo, memo, useCallback, forwardRef, useState, useRef, useEffect, useLayoutEffect } from 'react';
|
|
3
|
-
import { createStyles, useTheme, colors } from '@aurora-ds/theme';
|
|
3
|
+
import { createStyles, useTheme, keyframes, colors } from '@aurora-ds/theme';
|
|
4
|
+
import { createPortal } from 'react-dom';
|
|
4
5
|
|
|
5
6
|
const ICON_STYLES = createStyles((theme) => ({
|
|
6
7
|
root: (size, color, backgroundColor, padding, borderRadius) => ({
|
|
@@ -533,6 +534,31 @@ const AvatarGroup = ({ children, limit, size = 'medium' }) => {
|
|
|
533
534
|
};
|
|
534
535
|
AvatarGroup.displayName = 'AvatarGroup';
|
|
535
536
|
|
|
537
|
+
const shimmerAnimation = keyframes({
|
|
538
|
+
'0%': {
|
|
539
|
+
backgroundPosition: '-200% 0',
|
|
540
|
+
},
|
|
541
|
+
'100%': {
|
|
542
|
+
backgroundPosition: '200% 0',
|
|
543
|
+
},
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
const SKELETON_STYLES = createStyles((theme) => ({
|
|
547
|
+
root: (width, height, borderRadius) => ({
|
|
548
|
+
width,
|
|
549
|
+
height,
|
|
550
|
+
borderRadius: borderRadius ? theme.radius[borderRadius] : theme.radius.md,
|
|
551
|
+
background: `linear-gradient(90deg, ${theme.colors.surfaceActive} 25%, ${theme.colors.surfaceHover} 50%, ${theme.colors.surfaceActive} 75%)`,
|
|
552
|
+
backgroundSize: '200% 100%',
|
|
553
|
+
animation: `${shimmerAnimation} 1.2s ease-in-out infinite`,
|
|
554
|
+
}),
|
|
555
|
+
}));
|
|
556
|
+
|
|
557
|
+
const Skeleton = ({ width, height, borderRadius }) => {
|
|
558
|
+
return (jsx("div", { className: SKELETON_STYLES.root(width, height, borderRadius) }));
|
|
559
|
+
};
|
|
560
|
+
Skeleton.displayName = 'Skeleton';
|
|
561
|
+
|
|
536
562
|
const getButtonSizeStyles = () => ({
|
|
537
563
|
small: {
|
|
538
564
|
height: BUTTON_SIZE - 8,
|
|
@@ -764,15 +790,15 @@ const FORM_STYLES = createStyles(() => ({
|
|
|
764
790
|
/**
|
|
765
791
|
* Form component - A transparent wrapper for form elements with automatic preventDefault handling
|
|
766
792
|
*/
|
|
767
|
-
const Form = ({ children, onSubmit, ariaLabel, }) => {
|
|
793
|
+
const Form$1 = ({ children, onSubmit, ariaLabel, }) => {
|
|
768
794
|
const handleSubmit = useCallback((e) => {
|
|
769
795
|
e.preventDefault();
|
|
770
796
|
onSubmit?.(e);
|
|
771
797
|
}, [onSubmit]);
|
|
772
798
|
return (jsx("form", { onSubmit: handleSubmit, className: FORM_STYLES.root, "aria-label": ariaLabel, children: children }));
|
|
773
799
|
};
|
|
774
|
-
Form.displayName = 'Form';
|
|
775
|
-
var
|
|
800
|
+
Form$1.displayName = 'Form';
|
|
801
|
+
var Form = memo(Form$1);
|
|
776
802
|
|
|
777
803
|
/**
|
|
778
804
|
* Input styles using createStyles from @aurora-ds/theme
|
|
@@ -897,6 +923,8 @@ const ChevronRightIcon = () => {
|
|
|
897
923
|
return (jsx("svg", { xmlns: 'http://www.w3.org/2000/svg', width: '24', height: '24', viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', "stroke-width": '2', "stroke-linecap": 'round', "stroke-linejoin": 'round', className: 'lucide lucide-chevron-right-icon lucide-chevron-right', children: jsx("path", { d: 'm9 18 6-6-6-6' }) }));
|
|
898
924
|
};
|
|
899
925
|
|
|
926
|
+
const CloseIcon = () => (jsx("svg", { width: '16', height: '16', viewBox: '0 0 16 16', fill: 'none', xmlns: 'http://www.w3.org/2000/svg', children: jsx("path", { d: 'M12 4L4 12M4 4l8 8', stroke: 'currentColor', strokeWidth: '2', strokeLinecap: 'round', strokeLinejoin: 'round' }) }));
|
|
927
|
+
|
|
900
928
|
const EyeIcon = () => {
|
|
901
929
|
return (jsxs("svg", { xmlns: 'http://www.w3.org/2000/svg', width: '24', height: '24', viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', "stroke-width": '2', "stroke-linecap": 'round', "stroke-linejoin": 'round', className: 'lucide lucide-eye-icon lucide-eye', children: [jsx("path", { d: 'M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0' }), jsx("circle", { cx: '12', cy: '12', r: '3' })] }));
|
|
902
930
|
};
|
|
@@ -1002,6 +1030,302 @@ const TextArea = forwardRef(({ value, onChange, label, mandatory = false, placeh
|
|
|
1002
1030
|
TextArea.displayName = 'TextArea';
|
|
1003
1031
|
var TextArea_default = memo(TextArea);
|
|
1004
1032
|
|
|
1033
|
+
/**
|
|
1034
|
+
* Select styles using createStyles from @aurora-ds/theme
|
|
1035
|
+
*/
|
|
1036
|
+
const SELECT_STYLES = createStyles((theme) => ({
|
|
1037
|
+
root: ({ disabled = false, width }) => ({
|
|
1038
|
+
position: 'relative',
|
|
1039
|
+
display: 'inline-flex',
|
|
1040
|
+
alignItems: 'center',
|
|
1041
|
+
justifyContent: 'space-between',
|
|
1042
|
+
boxSizing: 'border-box',
|
|
1043
|
+
width: width ?? '100%',
|
|
1044
|
+
padding: `${theme.spacing.sm} ${theme.spacing.md}`,
|
|
1045
|
+
border: `1px solid ${theme.colors.border}`,
|
|
1046
|
+
borderRadius: theme.radius.md,
|
|
1047
|
+
fontSize: theme.fontSize.md,
|
|
1048
|
+
fontFamily: 'inherit',
|
|
1049
|
+
backgroundColor: theme.colors.surface,
|
|
1050
|
+
color: theme.colors.text,
|
|
1051
|
+
cursor: disabled ? 'not-allowed' : 'pointer',
|
|
1052
|
+
transition: `border-color ${theme.transition.fast}`,
|
|
1053
|
+
outline: 'none',
|
|
1054
|
+
minHeight: BUTTON_SIZE,
|
|
1055
|
+
maxHeight: BUTTON_SIZE,
|
|
1056
|
+
gap: theme.spacing.md,
|
|
1057
|
+
lineHeight: theme.lineHeight.none,
|
|
1058
|
+
textOverflow: 'ellipsis',
|
|
1059
|
+
overflow: 'hidden',
|
|
1060
|
+
whiteSpace: 'nowrap',
|
|
1061
|
+
...(disabled && {
|
|
1062
|
+
color: theme.colors.disabled,
|
|
1063
|
+
cursor: 'not-allowed',
|
|
1064
|
+
opacity: theme.opacity.high
|
|
1065
|
+
}),
|
|
1066
|
+
...(!disabled && {
|
|
1067
|
+
':hover': {
|
|
1068
|
+
borderColor: theme.colors.primaryHover,
|
|
1069
|
+
},
|
|
1070
|
+
}),
|
|
1071
|
+
}),
|
|
1072
|
+
trigger: {
|
|
1073
|
+
display: 'flex',
|
|
1074
|
+
alignItems: 'center',
|
|
1075
|
+
gap: theme.spacing.sm,
|
|
1076
|
+
flex: 1
|
|
1077
|
+
},
|
|
1078
|
+
value: {
|
|
1079
|
+
flex: 1,
|
|
1080
|
+
fontSize: theme.fontSize.md,
|
|
1081
|
+
color: theme.colors.text
|
|
1082
|
+
},
|
|
1083
|
+
placeholder: {
|
|
1084
|
+
flex: 1,
|
|
1085
|
+
fontSize: theme.fontSize.md,
|
|
1086
|
+
color: theme.colors.textSecondary
|
|
1087
|
+
}
|
|
1088
|
+
}));
|
|
1089
|
+
|
|
1090
|
+
/**
|
|
1091
|
+
* SelectItem styles using createStyles from @aurora-ds/theme
|
|
1092
|
+
*/
|
|
1093
|
+
const SELECT_ITEM_STYLES = createStyles((theme) => ({
|
|
1094
|
+
root: ({ isSelected = false, disabled = false }) => ({
|
|
1095
|
+
display: 'flex',
|
|
1096
|
+
alignItems: 'center',
|
|
1097
|
+
gap: theme.spacing.sm,
|
|
1098
|
+
padding: theme.spacing.sm,
|
|
1099
|
+
borderRadius: theme.radius.sm,
|
|
1100
|
+
backgroundColor: isSelected ? theme.colors.primary : theme.colors.surface,
|
|
1101
|
+
outline: 'none',
|
|
1102
|
+
border: 'none',
|
|
1103
|
+
cursor: disabled ? 'not-allowed' : 'pointer',
|
|
1104
|
+
minHeight: MENU_ITEM_SIZE,
|
|
1105
|
+
maxHeight: MENU_ITEM_SIZE,
|
|
1106
|
+
flexShrink: 0,
|
|
1107
|
+
transition: 'background-color 150ms ease-in-out',
|
|
1108
|
+
color: disabled ? theme.colors.disabled : (isSelected ? theme.colors.surface : theme.colors.text),
|
|
1109
|
+
opacity: disabled ? 0.5 : 1,
|
|
1110
|
+
':hover': {
|
|
1111
|
+
backgroundColor: disabled ? theme.colors.surface : (isSelected ? theme.colors.primary : theme.colors.surfaceHover),
|
|
1112
|
+
},
|
|
1113
|
+
})
|
|
1114
|
+
}));
|
|
1115
|
+
|
|
1116
|
+
/**
|
|
1117
|
+
* SelectItem component for use inside Select dropdown
|
|
1118
|
+
*/
|
|
1119
|
+
const SelectItem = ({ option, isSelected = false, onSelect }) => {
|
|
1120
|
+
const handleClick = () => {
|
|
1121
|
+
if (!option.disabled && onSelect) {
|
|
1122
|
+
onSelect(option.value);
|
|
1123
|
+
}
|
|
1124
|
+
};
|
|
1125
|
+
return (jsx("button", { className: SELECT_ITEM_STYLES.root({ isSelected, disabled: option.disabled }), onClick: handleClick, role: 'option', "aria-selected": isSelected, children: jsx(Text, { variant: 'label', maxLines: 1, children: option.label }) }));
|
|
1126
|
+
};
|
|
1127
|
+
SelectItem.displayName = 'SelectItem';
|
|
1128
|
+
|
|
1129
|
+
const MENU_STYLES = createStyles((theme) => ({
|
|
1130
|
+
root: (isFadingIn, anchorOrigin, position, width) => ({
|
|
1131
|
+
position: 'absolute',
|
|
1132
|
+
zIndex: theme.zIndex.dropdown,
|
|
1133
|
+
marginTop: theme.spacing.xs,
|
|
1134
|
+
backgroundColor: theme.colors.surface,
|
|
1135
|
+
borderRadius: theme.radius.md,
|
|
1136
|
+
border: `1px solid ${theme.colors.border}`,
|
|
1137
|
+
boxShadow: theme.shadows.md,
|
|
1138
|
+
minWidth: 150,
|
|
1139
|
+
maxHeight: MENU_ITEM_SIZE * 8,
|
|
1140
|
+
overflowY: 'auto',
|
|
1141
|
+
width,
|
|
1142
|
+
opacity: isFadingIn ? 1 : 0,
|
|
1143
|
+
transform: isFadingIn ? 'scale(1)' : 'scale(0.95)',
|
|
1144
|
+
transformOrigin: anchorOrigin === 'right' ? 'top right' : 'top left',
|
|
1145
|
+
transition: `opacity ${DEFAULT_TRANSITION_DURATION_MS}ms ease-out, transform ${DEFAULT_TRANSITION_DURATION_MS}ms ease-out`,
|
|
1146
|
+
top: position?.top ?? 0,
|
|
1147
|
+
left: position?.left ?? 0,
|
|
1148
|
+
visibility: position ? 'visible' : 'hidden',
|
|
1149
|
+
}),
|
|
1150
|
+
}));
|
|
1151
|
+
|
|
1152
|
+
/**
|
|
1153
|
+
* Hook pour calculer la position d'un élément par rapport à son ancre
|
|
1154
|
+
* @param anchor - Élément HTML servant d'ancre
|
|
1155
|
+
* @param menuRef - Référence vers l'élément à positionner
|
|
1156
|
+
* @param anchorOrigin - Origine de l'ancrage ('left' ou 'right')
|
|
1157
|
+
* @param isVisible - Si l'élément est visible (pour recalculer la position)
|
|
1158
|
+
*/
|
|
1159
|
+
const useAnchorPosition = ({ anchor, menuRef, anchorOrigin = 'right', isVisible }) => {
|
|
1160
|
+
const [position, setPosition] = useState(null);
|
|
1161
|
+
useLayoutEffect(() => {
|
|
1162
|
+
if (anchor && isVisible) {
|
|
1163
|
+
const anchorRect = anchor.getBoundingClientRect();
|
|
1164
|
+
const menuWidth = menuRef.current?.offsetWidth || 150;
|
|
1165
|
+
const left = anchorOrigin === 'right'
|
|
1166
|
+
? anchorRect.right - menuWidth + window.scrollX
|
|
1167
|
+
: anchorRect.left + window.scrollX;
|
|
1168
|
+
setPosition({
|
|
1169
|
+
top: anchorRect.bottom + window.scrollY,
|
|
1170
|
+
left
|
|
1171
|
+
});
|
|
1172
|
+
}
|
|
1173
|
+
else {
|
|
1174
|
+
setPosition(null);
|
|
1175
|
+
}
|
|
1176
|
+
}, [anchor, anchorOrigin, isVisible, menuRef]);
|
|
1177
|
+
return position;
|
|
1178
|
+
};
|
|
1179
|
+
|
|
1180
|
+
/**
|
|
1181
|
+
* Gestion d'un click en dehors d'un ou plusieurs éléments
|
|
1182
|
+
* @param refs Tableau de références à écouter
|
|
1183
|
+
* @param onClickOutside Callback si clic à l'extérieur
|
|
1184
|
+
* @param shouldTrigger Activation du comportement
|
|
1185
|
+
*/
|
|
1186
|
+
const useClickOutside = (refs, onClickOutside, shouldTrigger = true) => {
|
|
1187
|
+
useEffect(() => {
|
|
1188
|
+
if (!shouldTrigger) {
|
|
1189
|
+
return;
|
|
1190
|
+
}
|
|
1191
|
+
const handleClick = (event) => {
|
|
1192
|
+
const isInside = refs.some(ref => ref.current?.contains(event.target));
|
|
1193
|
+
if (!isInside) {
|
|
1194
|
+
onClickOutside();
|
|
1195
|
+
}
|
|
1196
|
+
};
|
|
1197
|
+
document.addEventListener('mousedown', handleClick);
|
|
1198
|
+
return () => {
|
|
1199
|
+
document.removeEventListener('mousedown', handleClick);
|
|
1200
|
+
};
|
|
1201
|
+
}, [refs, onClickOutside, shouldTrigger]);
|
|
1202
|
+
};
|
|
1203
|
+
|
|
1204
|
+
/**
|
|
1205
|
+
* Hook pour gérer les animations de transition lors des renders
|
|
1206
|
+
* @param isOpen - État d'ouverture
|
|
1207
|
+
* @param duration - Durée de la transition en ms
|
|
1208
|
+
*/
|
|
1209
|
+
const useTransitionRender = (isOpen, duration = DEFAULT_TRANSITION_DURATION_MS) => {
|
|
1210
|
+
const [isVisible, setIsVisible] = useState(false);
|
|
1211
|
+
const [isFadingIn, setIsFadingIn] = useState(false);
|
|
1212
|
+
useEffect(() => {
|
|
1213
|
+
if (isOpen) {
|
|
1214
|
+
setIsVisible(true);
|
|
1215
|
+
const timeout = setTimeout(() => {
|
|
1216
|
+
setIsFadingIn(true);
|
|
1217
|
+
}, 10);
|
|
1218
|
+
return () => {
|
|
1219
|
+
clearTimeout(timeout);
|
|
1220
|
+
};
|
|
1221
|
+
}
|
|
1222
|
+
else {
|
|
1223
|
+
setIsFadingIn(false);
|
|
1224
|
+
const timeout = setTimeout(() => {
|
|
1225
|
+
setIsVisible(false);
|
|
1226
|
+
}, duration);
|
|
1227
|
+
return () => {
|
|
1228
|
+
clearTimeout(timeout);
|
|
1229
|
+
};
|
|
1230
|
+
}
|
|
1231
|
+
}, [isOpen, duration]);
|
|
1232
|
+
return {
|
|
1233
|
+
isVisible,
|
|
1234
|
+
isFadingIn
|
|
1235
|
+
};
|
|
1236
|
+
};
|
|
1237
|
+
|
|
1238
|
+
const Menu = ({ anchor, onClose, children, anchorOrigin = 'right', width }) => {
|
|
1239
|
+
// refs
|
|
1240
|
+
const menuRef = useRef(null);
|
|
1241
|
+
const anchorRef = useRef(null);
|
|
1242
|
+
// variables
|
|
1243
|
+
const isOpen = Boolean(anchor);
|
|
1244
|
+
const refs = useMemo(() => [menuRef, anchorRef], []);
|
|
1245
|
+
// hooks
|
|
1246
|
+
const { isVisible, isFadingIn } = useTransitionRender(isOpen);
|
|
1247
|
+
const position = useAnchorPosition({ anchor: anchorRef.current, menuRef, anchorOrigin, isVisible });
|
|
1248
|
+
// useEffects
|
|
1249
|
+
useEffect(() => {
|
|
1250
|
+
if (anchor) {
|
|
1251
|
+
anchorRef.current = anchor;
|
|
1252
|
+
}
|
|
1253
|
+
}, [anchor]);
|
|
1254
|
+
useEffect(() => {
|
|
1255
|
+
if (!isVisible) {
|
|
1256
|
+
anchorRef.current = null;
|
|
1257
|
+
}
|
|
1258
|
+
}, [isVisible]);
|
|
1259
|
+
useClickOutside(refs, onClose, isVisible);
|
|
1260
|
+
if (!isVisible) {
|
|
1261
|
+
return null;
|
|
1262
|
+
}
|
|
1263
|
+
return (jsx("div", { ref: menuRef, className: MENU_STYLES.root(isFadingIn, anchorOrigin, position, width), children: children }));
|
|
1264
|
+
};
|
|
1265
|
+
Menu.displayName = 'Menu';
|
|
1266
|
+
|
|
1267
|
+
const MENU_GROUP_STYLES = createStyles((theme) => ({
|
|
1268
|
+
root: {
|
|
1269
|
+
display: 'flex',
|
|
1270
|
+
flexDirection: 'column',
|
|
1271
|
+
padding: theme.spacing.xs,
|
|
1272
|
+
},
|
|
1273
|
+
}));
|
|
1274
|
+
|
|
1275
|
+
const MenuGroup = ({ children }) => {
|
|
1276
|
+
return (jsx("div", { className: MENU_GROUP_STYLES.root, children: children }));
|
|
1277
|
+
};
|
|
1278
|
+
MenuGroup.displayName = 'MenuGroup';
|
|
1279
|
+
|
|
1280
|
+
const MENU_ITEM_STYLES = createStyles((theme) => ({
|
|
1281
|
+
root: {
|
|
1282
|
+
display: 'flex',
|
|
1283
|
+
alignItems: 'center',
|
|
1284
|
+
gap: theme.spacing.sm,
|
|
1285
|
+
padding: theme.spacing.sm,
|
|
1286
|
+
borderRadius: theme.radius.sm,
|
|
1287
|
+
backgroundColor: theme.colors.surface,
|
|
1288
|
+
outline: 'none',
|
|
1289
|
+
border: 'none',
|
|
1290
|
+
cursor: 'pointer',
|
|
1291
|
+
minHeight: MENU_ITEM_SIZE,
|
|
1292
|
+
maxHeight: MENU_ITEM_SIZE,
|
|
1293
|
+
flexShrink: 0,
|
|
1294
|
+
transition: 'background-color 150ms ease-in-out',
|
|
1295
|
+
':hover': {
|
|
1296
|
+
backgroundColor: theme.colors.surfaceHover,
|
|
1297
|
+
},
|
|
1298
|
+
},
|
|
1299
|
+
}));
|
|
1300
|
+
|
|
1301
|
+
const MenuItem = ({ label, icon, onClick, textColor, iconColor }) => {
|
|
1302
|
+
return (jsxs("button", { className: MENU_ITEM_STYLES.root, onClick: onClick, children: [icon && (jsx(Icon, { color: iconColor ?? 'text', size: 'sm', children: icon })), jsx(Text, { variant: 'label', color: textColor ?? 'text', maxLines: 1, fontSize: 'sm', children: label })] }));
|
|
1303
|
+
};
|
|
1304
|
+
MenuItem.displayName = 'MenuItem';
|
|
1305
|
+
|
|
1306
|
+
/**
|
|
1307
|
+
* Select component that uses Menu for dropdown
|
|
1308
|
+
*/
|
|
1309
|
+
const Select = ({ options, value, onChange, placeholder = 'Select an option', disabled = false, width }) => {
|
|
1310
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
1311
|
+
const triggerRef = useRef(null);
|
|
1312
|
+
const selectedOption = options.find(option => option.value === value);
|
|
1313
|
+
const handleTriggerClick = () => {
|
|
1314
|
+
if (!disabled) {
|
|
1315
|
+
setIsOpen(!isOpen);
|
|
1316
|
+
}
|
|
1317
|
+
};
|
|
1318
|
+
const handleClose = () => {
|
|
1319
|
+
setIsOpen(false);
|
|
1320
|
+
};
|
|
1321
|
+
const handleSelect = (selectedValue) => {
|
|
1322
|
+
onChange?.(selectedValue);
|
|
1323
|
+
setIsOpen(false);
|
|
1324
|
+
};
|
|
1325
|
+
return (jsxs(Fragment$1, { children: [jsxs("div", { ref: triggerRef, className: SELECT_STYLES.root({ disabled, width }), onClick: handleTriggerClick, role: 'button', tabIndex: disabled ? -1 : 0, "aria-expanded": isOpen, "aria-haspopup": 'listbox', children: [jsx("div", { className: SELECT_STYLES.trigger, children: jsx(Text, { variant: 'p', maxLines: 1, color: selectedOption ? 'text' : 'textSecondary', children: selectedOption ? selectedOption.label : placeholder }) }), jsx(Icon, { children: jsx(ChevronDownIcon, {}) })] }), jsx(Menu, { anchor: isOpen ? triggerRef.current : null, onClose: handleClose, width: width, children: jsx(MenuGroup, { children: options.map(option => (jsx(SelectItem, { option: option, isSelected: option.value === value, onSelect: handleSelect }, option.value))) }) })] }));
|
|
1326
|
+
};
|
|
1327
|
+
Select.displayName = 'Select';
|
|
1328
|
+
|
|
1005
1329
|
/**
|
|
1006
1330
|
* Card styles using createStyles from @aurora-ds/theme
|
|
1007
1331
|
*/
|
|
@@ -1033,7 +1357,7 @@ const CARD_STYLES = createStyles((theme) => ({
|
|
|
1033
1357
|
* - `column`: Vertical layout (default)
|
|
1034
1358
|
* - `row`: Horizontal layout
|
|
1035
1359
|
*/
|
|
1036
|
-
const Card = ({ children, direction = 'column', padding = 'md', width, height, gap, radius = 'md', shadow = '
|
|
1360
|
+
const Card = ({ children, direction = 'column', padding = 'md', width, height, gap, radius = 'md', shadow = 'none', align, justify, backgroundColor = 'surface', borderColor = 'border', ariaLabel, ariaLabelledBy, ariaDescribedBy, role, tabIndex, }) => {
|
|
1037
1361
|
return (jsx("div", { className: CARD_STYLES.root({
|
|
1038
1362
|
direction,
|
|
1039
1363
|
padding,
|
|
@@ -1263,182 +1587,66 @@ const Accordion = ({ title, children, expanded, defaultExpanded = false, onChang
|
|
|
1263
1587
|
};
|
|
1264
1588
|
Accordion.displayName = 'Accordion';
|
|
1265
1589
|
|
|
1266
|
-
const
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1590
|
+
const MODAL_STYLES = createStyles((theme) => ({
|
|
1591
|
+
background: (isFadingIn) => ({
|
|
1592
|
+
background: 'rgba(0, 0, 0, 0.6)',
|
|
1593
|
+
display: 'flex',
|
|
1594
|
+
alignItems: 'center',
|
|
1595
|
+
justifyContent: 'center',
|
|
1596
|
+
position: 'fixed',
|
|
1597
|
+
top: 0,
|
|
1598
|
+
left: 0,
|
|
1599
|
+
zIndex: 999999,
|
|
1600
|
+
transition: 'opacity 150ms ease-in-out',
|
|
1601
|
+
width: '100vw',
|
|
1602
|
+
height: '100vh',
|
|
1279
1603
|
opacity: isFadingIn ? 1 : 0,
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1604
|
+
}),
|
|
1605
|
+
content: (isFadingIn) => ({
|
|
1606
|
+
width: '100%',
|
|
1607
|
+
maxWidth: 500,
|
|
1608
|
+
borderRadius: 8,
|
|
1609
|
+
position: 'absolute',
|
|
1610
|
+
left: '50%',
|
|
1611
|
+
top: '50%',
|
|
1612
|
+
transform: isFadingIn ? 'translate(-50%, -50%) scale(1)' : 'translate(-50%, -50%) scale(0.95)',
|
|
1613
|
+
transformOrigin: 'center center',
|
|
1614
|
+
transition: 'transform 150ms ease-in-out',
|
|
1615
|
+
backgroundColor: theme.colors.background,
|
|
1616
|
+
padding: theme.spacing.md,
|
|
1617
|
+
display: 'flex',
|
|
1618
|
+
flexDirection: 'column',
|
|
1619
|
+
height: 'fit-content',
|
|
1620
|
+
alignItems: 'flex-start',
|
|
1621
|
+
gap: theme.spacing.md,
|
|
1286
1622
|
}),
|
|
1287
1623
|
}));
|
|
1288
1624
|
|
|
1289
|
-
|
|
1290
|
-
* Hook pour calculer la position d'un élément par rapport à son ancre
|
|
1291
|
-
* @param anchor - Élément HTML servant d'ancre
|
|
1292
|
-
* @param menuRef - Référence vers l'élément à positionner
|
|
1293
|
-
* @param anchorOrigin - Origine de l'ancrage ('left' ou 'right')
|
|
1294
|
-
* @param isVisible - Si l'élément est visible (pour recalculer la position)
|
|
1295
|
-
*/
|
|
1296
|
-
const useAnchorPosition = ({ anchor, menuRef, anchorOrigin = 'right', isVisible }) => {
|
|
1297
|
-
const [position, setPosition] = useState(null);
|
|
1298
|
-
useLayoutEffect(() => {
|
|
1299
|
-
if (anchor && isVisible) {
|
|
1300
|
-
const anchorRect = anchor.getBoundingClientRect();
|
|
1301
|
-
const menuWidth = menuRef.current?.offsetWidth || 150;
|
|
1302
|
-
const left = anchorOrigin === 'right'
|
|
1303
|
-
? anchorRect.right - menuWidth + window.scrollX
|
|
1304
|
-
: anchorRect.left + window.scrollX;
|
|
1305
|
-
setPosition({
|
|
1306
|
-
top: anchorRect.bottom + window.scrollY,
|
|
1307
|
-
left
|
|
1308
|
-
});
|
|
1309
|
-
}
|
|
1310
|
-
else {
|
|
1311
|
-
setPosition(null);
|
|
1312
|
-
}
|
|
1313
|
-
}, [anchor, anchorOrigin, isVisible, menuRef]);
|
|
1314
|
-
return position;
|
|
1315
|
-
};
|
|
1316
|
-
|
|
1317
|
-
/**
|
|
1318
|
-
* Gestion d'un click en dehors d'un ou plusieurs éléments
|
|
1319
|
-
* @param refs Tableau de références à écouter
|
|
1320
|
-
* @param onClickOutside Callback si clic à l'extérieur
|
|
1321
|
-
* @param shouldTrigger Activation du comportement
|
|
1322
|
-
*/
|
|
1323
|
-
const useClickOutside = (refs, onClickOutside, shouldTrigger = true) => {
|
|
1324
|
-
useEffect(() => {
|
|
1325
|
-
if (!shouldTrigger) {
|
|
1326
|
-
return;
|
|
1327
|
-
}
|
|
1328
|
-
const handleClick = (event) => {
|
|
1329
|
-
const isInside = refs.some(ref => ref.current?.contains(event.target));
|
|
1330
|
-
if (!isInside) {
|
|
1331
|
-
onClickOutside();
|
|
1332
|
-
}
|
|
1333
|
-
};
|
|
1334
|
-
document.addEventListener('mousedown', handleClick);
|
|
1335
|
-
return () => {
|
|
1336
|
-
document.removeEventListener('mousedown', handleClick);
|
|
1337
|
-
};
|
|
1338
|
-
}, [refs, onClickOutside, shouldTrigger]);
|
|
1339
|
-
};
|
|
1340
|
-
|
|
1341
|
-
/**
|
|
1342
|
-
* Hook pour gérer les animations de transition lors des renders
|
|
1343
|
-
* @param isOpen - État d'ouverture
|
|
1344
|
-
* @param duration - Durée de la transition en ms
|
|
1345
|
-
*/
|
|
1346
|
-
const useTransitionRender = (isOpen, duration = DEFAULT_TRANSITION_DURATION_MS) => {
|
|
1347
|
-
const [isVisible, setIsVisible] = useState(false);
|
|
1348
|
-
const [isFadingIn, setIsFadingIn] = useState(false);
|
|
1349
|
-
useEffect(() => {
|
|
1350
|
-
if (isOpen) {
|
|
1351
|
-
setIsVisible(true);
|
|
1352
|
-
const timeout = setTimeout(() => {
|
|
1353
|
-
setIsFadingIn(true);
|
|
1354
|
-
}, 10);
|
|
1355
|
-
return () => {
|
|
1356
|
-
clearTimeout(timeout);
|
|
1357
|
-
};
|
|
1358
|
-
}
|
|
1359
|
-
else {
|
|
1360
|
-
setIsFadingIn(false);
|
|
1361
|
-
const timeout = setTimeout(() => {
|
|
1362
|
-
setIsVisible(false);
|
|
1363
|
-
}, duration);
|
|
1364
|
-
return () => {
|
|
1365
|
-
clearTimeout(timeout);
|
|
1366
|
-
};
|
|
1367
|
-
}
|
|
1368
|
-
}, [isOpen, duration]);
|
|
1369
|
-
return {
|
|
1370
|
-
isVisible,
|
|
1371
|
-
isFadingIn
|
|
1372
|
-
};
|
|
1373
|
-
};
|
|
1374
|
-
|
|
1375
|
-
const Menu = ({ anchor, onClose, children, anchorOrigin = 'right', width }) => {
|
|
1625
|
+
const Modal = ({ isOpen, onClose, label, children, isForm, action }) => {
|
|
1376
1626
|
// refs
|
|
1377
|
-
const
|
|
1378
|
-
const anchorRef = useRef(null);
|
|
1379
|
-
// variables
|
|
1380
|
-
const isOpen = Boolean(anchor);
|
|
1381
|
-
const refs = useMemo(() => [menuRef, anchorRef], []);
|
|
1627
|
+
const modalRef = useRef(null);
|
|
1382
1628
|
// hooks
|
|
1383
1629
|
const { isVisible, isFadingIn } = useTransitionRender(isOpen);
|
|
1384
|
-
const position = useAnchorPosition({ anchor: anchorRef.current, menuRef, anchorOrigin, isVisible });
|
|
1385
|
-
// useEffects
|
|
1386
1630
|
useEffect(() => {
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1631
|
+
const handleKeyDown = (event) => {
|
|
1632
|
+
if (event.key === 'Escape' && isOpen) {
|
|
1633
|
+
onClose();
|
|
1634
|
+
}
|
|
1635
|
+
};
|
|
1636
|
+
document.addEventListener('keydown', handleKeyDown);
|
|
1637
|
+
return () => document.removeEventListener('keydown', handleKeyDown);
|
|
1638
|
+
}, [isOpen, onClose]);
|
|
1639
|
+
// components
|
|
1640
|
+
const Wrapper = isForm ? Form : Fragment;
|
|
1641
|
+
const wrapperProps = isForm ? {
|
|
1642
|
+
onSubmit: (e) => {
|
|
1643
|
+
e.preventDefault();
|
|
1644
|
+
action?.onClick();
|
|
1394
1645
|
}
|
|
1395
|
-
}
|
|
1396
|
-
|
|
1397
|
-
if (!isVisible) {
|
|
1398
|
-
return null;
|
|
1399
|
-
}
|
|
1400
|
-
return (jsx("div", { ref: menuRef, className: MENU_STYLES.root(isFadingIn, anchorOrigin, position, width), children: children }));
|
|
1401
|
-
};
|
|
1402
|
-
Menu.displayName = 'Menu';
|
|
1403
|
-
|
|
1404
|
-
const MENU_GROUP_STYLES = createStyles((theme) => ({
|
|
1405
|
-
root: {
|
|
1406
|
-
display: 'flex',
|
|
1407
|
-
flexDirection: 'column',
|
|
1408
|
-
padding: theme.spacing.xs,
|
|
1409
|
-
},
|
|
1410
|
-
}));
|
|
1411
|
-
|
|
1412
|
-
const MenuGroup = ({ children }) => {
|
|
1413
|
-
return (jsx("div", { className: MENU_GROUP_STYLES.root, children: children }));
|
|
1646
|
+
} : {};
|
|
1647
|
+
return createPortal(jsx(Fragment, { children: isVisible ? (jsx("div", { className: MODAL_STYLES.background(isFadingIn), ref: modalRef, children: jsx("div", { className: MODAL_STYLES.content(isFadingIn), children: jsxs(Wrapper, { ...wrapperProps, children: [jsxs(Stack, { justify: 'space-between', height: BUTTON_SIZE, width: '100%', children: [jsx(Text, { variant: 'h3', children: label }), !action && (jsx(IconButton, { icon: jsx(CloseIcon, {}), onClick: onClose, size: 'small', variant: 'text', textColor: 'text' }))] }), children, action && (jsxs(Stack, { justify: 'flex-end', children: [jsx(Button, { label: 'Cancel', onClick: onClose, variant: 'outlined' }), jsx(Button, { label: action.label, onClick: !isForm ? action.onClick : undefined, type: isForm ? 'submit' : 'button', disabled: action.disabled })] }))] }) }) })) : null }), document.body);
|
|
1414
1648
|
};
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
const MENU_ITEM_STYLES = createStyles((theme) => ({
|
|
1418
|
-
root: {
|
|
1419
|
-
display: 'flex',
|
|
1420
|
-
alignItems: 'center',
|
|
1421
|
-
gap: theme.spacing.sm,
|
|
1422
|
-
padding: theme.spacing.sm,
|
|
1423
|
-
borderRadius: theme.radius.sm,
|
|
1424
|
-
backgroundColor: theme.colors.surface,
|
|
1425
|
-
outline: 'none',
|
|
1426
|
-
border: 'none',
|
|
1427
|
-
cursor: 'pointer',
|
|
1428
|
-
minHeight: MENU_ITEM_SIZE,
|
|
1429
|
-
maxHeight: MENU_ITEM_SIZE,
|
|
1430
|
-
flexShrink: 0,
|
|
1431
|
-
transition: 'background-color 150ms ease-in-out',
|
|
1432
|
-
':hover': {
|
|
1433
|
-
backgroundColor: theme.colors.surfaceHover,
|
|
1434
|
-
},
|
|
1435
|
-
},
|
|
1436
|
-
}));
|
|
1437
|
-
|
|
1438
|
-
const MenuItem = ({ label, icon, onClick, textColor, iconColor }) => {
|
|
1439
|
-
return (jsxs("button", { className: MENU_ITEM_STYLES.root, onClick: onClick, children: [icon && (jsx(Icon, { color: iconColor ?? 'text', size: 'sm', children: icon })), jsx(Text, { variant: 'label', color: textColor ?? 'text', maxLines: 1, fontSize: 'sm', children: label })] }));
|
|
1440
|
-
};
|
|
1441
|
-
MenuItem.displayName = 'MenuItem';
|
|
1649
|
+
Modal.displayName = 'Modal';
|
|
1442
1650
|
|
|
1443
1651
|
/**
|
|
1444
1652
|
* DrawerItem styles using createStyles from @aurora-ds/theme
|
|
@@ -1751,5 +1959,5 @@ const TabItem = ({ label, isActive = false, onClick, }) => {
|
|
|
1751
1959
|
};
|
|
1752
1960
|
TabItem.displayName = 'TabItem';
|
|
1753
1961
|
|
|
1754
|
-
export { Accordion, Avatar, AvatarGroup, Breadcrumb, BreadcrumbEllipsis, BreadcrumbLink, BreadcrumbPage, BreadcrumbSeparator, Button, Card, Chip, DrawerItem,
|
|
1962
|
+
export { Accordion, Avatar, AvatarGroup, Breadcrumb, BreadcrumbEllipsis, BreadcrumbLink, BreadcrumbPage, BreadcrumbSeparator, Button, Card, Chip, DrawerItem, Form, Grid, Icon, IconButton, Input_default as Input, Menu, MenuGroup, MenuItem, Modal, Page, PageSection, Select, Separator, Skeleton, Stack, TabItem, Tabs, Text, TextArea_default as TextArea, useAnchorPosition, useClickOutside, useTransitionRender };
|
|
1755
1963
|
//# sourceMappingURL=index.js.map
|