@aurora-ds/components 1.5.0 → 1.6.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/dist/cjs/index.js +115 -19
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +107 -20
- package/dist/esm/index.js.map +1 -1
- package/dist/index.d.ts +228 -3
- package/package.json +1 -1
package/dist/cjs/index.js
CHANGED
|
@@ -379,8 +379,8 @@ const buildActionButtonRootStyle = (theme, variant, color, focusOptions) => {
|
|
|
379
379
|
backgroundColor: intent.main,
|
|
380
380
|
borderColor: intent.main,
|
|
381
381
|
color: intent.on,
|
|
382
|
-
':hover:not(:disabled)': { backgroundColor: intent.hover
|
|
383
|
-
':active:not(:disabled)': { backgroundColor: intent.active
|
|
382
|
+
':hover:not(:disabled)': { backgroundColor: intent.hover },
|
|
383
|
+
':active:not(:disabled)': { backgroundColor: intent.active },
|
|
384
384
|
}
|
|
385
385
|
: variant === 'outlined'
|
|
386
386
|
? {
|
|
@@ -388,7 +388,7 @@ const buildActionButtonRootStyle = (theme, variant, color, focusOptions) => {
|
|
|
388
388
|
borderColor: intent.border,
|
|
389
389
|
color: intent.fg,
|
|
390
390
|
':hover:not(:disabled)': { backgroundColor: intent.subtleHover, color: intent.fgHover },
|
|
391
|
-
':active:not(:disabled)': { backgroundColor: intent.subtleActive,
|
|
391
|
+
':active:not(:disabled)': { backgroundColor: intent.subtleActive, color: intent.active },
|
|
392
392
|
}
|
|
393
393
|
: {
|
|
394
394
|
backgroundColor: 'transparent',
|
|
@@ -410,7 +410,7 @@ const buildActionButtonRootStyle = (theme, variant, color, focusOptions) => {
|
|
|
410
410
|
height: DEFAULT_BUTTON_HEIGHT,
|
|
411
411
|
cursor: 'pointer',
|
|
412
412
|
outline: 'none',
|
|
413
|
-
transition: `background-color ${theme.transition.normal},
|
|
413
|
+
transition: `background-color ${theme.transition.normal}, color ${theme.transition.normal}`,
|
|
414
414
|
...colorVariantStyles,
|
|
415
415
|
':focus-visible': getFocusRingStyles(theme, focusOptions),
|
|
416
416
|
':disabled': { cursor: 'not-allowed', opacity: theme.opacity.high },
|
|
@@ -3298,17 +3298,17 @@ const TEXTFIELD_WRAPPER_VARIANTS = theme.createVariants((theme) => {
|
|
|
3298
3298
|
return {
|
|
3299
3299
|
base: {
|
|
3300
3300
|
display: 'flex',
|
|
3301
|
-
|
|
3302
|
-
|
|
3301
|
+
// `stretch` lets the inner input fill the full height of the box so
|
|
3302
|
+
// clicking anywhere (including the vertical padding area) hits it.
|
|
3303
|
+
alignItems: 'stretch',
|
|
3303
3304
|
boxSizing: 'border-box',
|
|
3304
3305
|
borderWidth: '1px',
|
|
3305
3306
|
borderStyle: 'solid',
|
|
3306
3307
|
borderRadius: theme.radius.md,
|
|
3307
3308
|
backgroundColor: c.surfacePaper,
|
|
3309
|
+
// No focus ring on text inputs: focus is conveyed by the status
|
|
3310
|
+
// border colour change (see the `status` variants below).
|
|
3308
3311
|
transition: `border-color ${theme.transition.fast}`,
|
|
3309
|
-
// Full, always-visible focus ring when the inner input is focused
|
|
3310
|
-
// (single source of truth) — complements the status border colour.
|
|
3311
|
-
':focus-within': getFocusRingStyles(theme),
|
|
3312
3312
|
'&[data-disabled]': {
|
|
3313
3313
|
opacity: theme.opacity.high,
|
|
3314
3314
|
backgroundColor: c.disabledMain,
|
|
@@ -3317,10 +3317,12 @@ const TEXTFIELD_WRAPPER_VARIANTS = theme.createVariants((theme) => {
|
|
|
3317
3317
|
},
|
|
3318
3318
|
variants: {
|
|
3319
3319
|
size: {
|
|
3320
|
+
// Horizontal padding lives on the input itself (see TEXTFIELD_INPUT_VARIANTS),
|
|
3321
|
+
// not here, so the whole bordered area is part of the clickable input.
|
|
3320
3322
|
// Font-size is set on the wrapper so the native input inherits it via `fontSize: 'inherit'`.
|
|
3321
|
-
sm: { height: '2rem',
|
|
3322
|
-
md: { height: '2.5rem',
|
|
3323
|
-
lg: { height: '3rem',
|
|
3323
|
+
sm: { height: '2rem', fontSize: theme.fontSize.xs },
|
|
3324
|
+
md: { height: '2.5rem', fontSize: theme.fontSize.sm },
|
|
3325
|
+
lg: { height: '3rem', fontSize: theme.fontSize.md },
|
|
3324
3326
|
},
|
|
3325
3327
|
status: {
|
|
3326
3328
|
default: {
|
|
@@ -3345,11 +3347,17 @@ const TEXTFIELD_WRAPPER_VARIANTS = theme.createVariants((theme) => {
|
|
|
3345
3347
|
defaultVariants: { size: 'md', status: 'default' },
|
|
3346
3348
|
};
|
|
3347
3349
|
}, { id: 'textfield-wrapper' });
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3350
|
+
/**
|
|
3351
|
+
* The native input carries the horizontal padding and fills 100% of the
|
|
3352
|
+
* wrapper height, so the entire bordered box is part of the clickable input
|
|
3353
|
+
* (no dead zone between the text and the border).
|
|
3354
|
+
*/
|
|
3355
|
+
const TEXTFIELD_INPUT_VARIANTS = theme.createVariants((theme) => ({
|
|
3356
|
+
base: {
|
|
3351
3357
|
flex: 1,
|
|
3352
3358
|
minWidth: 0,
|
|
3359
|
+
height: '100%',
|
|
3360
|
+
boxSizing: 'border-box',
|
|
3353
3361
|
border: 'none',
|
|
3354
3362
|
outline: 'none',
|
|
3355
3363
|
background: 'transparent',
|
|
@@ -3357,15 +3365,25 @@ const TEXTFIELD_STYLES = theme.createStyles((theme) => ({
|
|
|
3357
3365
|
fontFamily: 'inherit',
|
|
3358
3366
|
fontSize: 'inherit',
|
|
3359
3367
|
lineHeight: 'normal',
|
|
3360
|
-
padding: '0',
|
|
3361
3368
|
'&::placeholder': { color: theme.colors.textTertiary },
|
|
3362
3369
|
'&:disabled': { cursor: 'not-allowed', color: theme.colors.textDisabled },
|
|
3363
3370
|
},
|
|
3371
|
+
variants: {
|
|
3372
|
+
size: {
|
|
3373
|
+
sm: { paddingLeft: theme.spacing.sm, paddingRight: theme.spacing.sm },
|
|
3374
|
+
md: { paddingLeft: theme.spacing.sm, paddingRight: theme.spacing.sm },
|
|
3375
|
+
lg: { paddingLeft: theme.spacing.md, paddingRight: theme.spacing.md },
|
|
3376
|
+
},
|
|
3377
|
+
},
|
|
3378
|
+
defaultVariants: { size: 'md' },
|
|
3379
|
+
}), { id: 'textfield-input' });
|
|
3380
|
+
const TEXTFIELD_STYLES = theme.createStyles((theme) => ({
|
|
3364
3381
|
/** Wrapper for the start icon — aligned with the input baseline. Clickable to focus the input. */
|
|
3365
3382
|
startIconWrap: {
|
|
3366
3383
|
display: 'flex',
|
|
3367
3384
|
alignItems: 'center',
|
|
3368
3385
|
flexShrink: 0,
|
|
3386
|
+
paddingLeft: theme.spacing.sm,
|
|
3369
3387
|
cursor: 'pointer',
|
|
3370
3388
|
},
|
|
3371
3389
|
/** Wrapper for end actions (custom content + optional password toggle). */
|
|
@@ -3373,6 +3391,7 @@ const TEXTFIELD_STYLES = theme.createStyles((theme) => ({
|
|
|
3373
3391
|
display: 'flex',
|
|
3374
3392
|
alignItems: 'center',
|
|
3375
3393
|
flexShrink: 0,
|
|
3394
|
+
paddingRight: theme.spacing.xs,
|
|
3376
3395
|
gap: theme.spacing['2xs'],
|
|
3377
3396
|
},
|
|
3378
3397
|
}), { id: 'textfield-extra' });
|
|
@@ -3433,7 +3452,11 @@ const useTextField = ({ id, ref, type, size, endAction, }) => {
|
|
|
3433
3452
|
*/
|
|
3434
3453
|
const TextField = ({ ref, label, helperText, size = 'md', status = 'default', startIcon: StartIcon, endAction, type, id, disabled, required, ...rest }) => {
|
|
3435
3454
|
const { fieldId, helperId, mergedRef, isPassword, showPassword, togglePassword, resolvedType, iconSize, iconButtonSize, hasEndSection, focusInput, } = useTextField({ id, ref, type, size, endAction });
|
|
3436
|
-
|
|
3455
|
+
// Associate the label with the input via `aria-labelledby` (and NOT `htmlFor`)
|
|
3456
|
+
// so the label stays accessible without natively focusing the input on click —
|
|
3457
|
+
// only clicking inside the bordered box should focus the field.
|
|
3458
|
+
const labelId = `${fieldId}-label`;
|
|
3459
|
+
return (jsxRuntime.jsxs(Stack, { flexDirection: 'column', gap: 'xs', children: [label !== undefined && (jsxRuntime.jsxs(Text, { variant: 'label', fontSize: 'sm', fontWeight: 'medium', color: 'textSecondary', id: labelId, children: [label, required && (jsxRuntime.jsx(Text, { variant: 'span', color: 'errorMain', "aria-hidden": true, children: ' *' }))] })), jsxRuntime.jsxs("div", { className: TEXTFIELD_WRAPPER_VARIANTS({ size, status }), "data-disabled": disabled || undefined, children: [StartIcon && (jsxRuntime.jsx("span", { className: TEXTFIELD_STYLES.startIconWrap, onClick: focusInput, "aria-hidden": true, children: jsxRuntime.jsx(Icon, { icon: StartIcon, size: iconSize, strokeColor: 'textSecondary' }) })), jsxRuntime.jsx("input", { ref: mergedRef, id: fieldId, type: resolvedType, disabled: disabled, required: required, "aria-required": required || undefined, "aria-invalid": status === 'error' || undefined, "aria-labelledby": label !== undefined ? labelId : undefined, "aria-describedby": helperText !== undefined ? helperId : undefined, "aria-errormessage": status === 'error' && helperText !== undefined ? helperId : undefined, className: TEXTFIELD_INPUT_VARIANTS({ size }), ...rest }), hasEndSection && (jsxRuntime.jsxs("span", { className: TEXTFIELD_STYLES.endActionWrap, children: [endAction, isPassword && (jsxRuntime.jsx(IconButton, { icon: showPassword ? EyeSlashIcon : EyeIcon, ariaLabel: showPassword ? 'Hide password' : 'Show password', variant: 'text', color: 'neutral', size: iconButtonSize, type: 'button', onClick: togglePassword }))] }))] }), helperText !== undefined && (jsxRuntime.jsx(FormHelperText, { id: helperId, status: status, children: helperText }))] }));
|
|
3437
3460
|
};
|
|
3438
3461
|
TextField.displayName = 'TextField';
|
|
3439
3462
|
|
|
@@ -4026,8 +4049,8 @@ const SELECT_TRIGGER_VARIANTS = theme.createVariants((theme) => {
|
|
|
4026
4049
|
transition: `border-color ${theme.transition.fast}`,
|
|
4027
4050
|
outline: 'none',
|
|
4028
4051
|
fontFamily: 'inherit',
|
|
4029
|
-
//
|
|
4030
|
-
|
|
4052
|
+
// No focus ring on the trigger: focus is conveyed by the border
|
|
4053
|
+
// colour change (see the `status` variants below).
|
|
4031
4054
|
'&[data-open]': {
|
|
4032
4055
|
borderColor: c.primaryMain,
|
|
4033
4056
|
},
|
|
@@ -4064,6 +4087,9 @@ const SELECT_TRIGGER_VARIANTS = theme.createVariants((theme) => {
|
|
|
4064
4087
|
':hover:not([data-disabled]):not([data-open])': {
|
|
4065
4088
|
borderColor: c.borderStrong,
|
|
4066
4089
|
},
|
|
4090
|
+
'&:focus-visible:not([data-open])': {
|
|
4091
|
+
borderColor: c.primaryMain,
|
|
4092
|
+
},
|
|
4067
4093
|
},
|
|
4068
4094
|
error: {
|
|
4069
4095
|
borderColor: c.errorMain,
|
|
@@ -6766,6 +6792,67 @@ const Dialog = DialogBase;
|
|
|
6766
6792
|
Dialog.Header = DialogHeader;
|
|
6767
6793
|
Dialog.Body = DialogBody;
|
|
6768
6794
|
|
|
6795
|
+
/**
|
|
6796
|
+
* Manages keyboard navigation for a listbox-style menu.
|
|
6797
|
+
*
|
|
6798
|
+
* Binds ArrowDown, ArrowUp, Home, End, and Enter using `useKeyPress`.
|
|
6799
|
+
* Automatically skips disabled items and optionally wraps around (loop).
|
|
6800
|
+
* Resets focus when `enabled` toggles.
|
|
6801
|
+
*/
|
|
6802
|
+
const useListKeyNav = ({ itemCount, enabled, onSelect, isDisabled, loop = true, initialIndex = 0, }) => {
|
|
6803
|
+
const [focusedIndex, setFocusedIndex] = React.useState(-1);
|
|
6804
|
+
const initialIndexRef = React.useRef(initialIndex);
|
|
6805
|
+
React.useEffect(() => {
|
|
6806
|
+
initialIndexRef.current = initialIndex;
|
|
6807
|
+
}, [initialIndex]);
|
|
6808
|
+
React.useEffect(() => {
|
|
6809
|
+
setFocusedIndex(enabled ? initialIndexRef.current : -1);
|
|
6810
|
+
}, [enabled]);
|
|
6811
|
+
const getNextIndex = React.useCallback((current, direction) => {
|
|
6812
|
+
if (itemCount === 0) {
|
|
6813
|
+
return -1;
|
|
6814
|
+
}
|
|
6815
|
+
let next = current + direction;
|
|
6816
|
+
for (let i = 0; i < itemCount; i++) {
|
|
6817
|
+
if (next < 0) {
|
|
6818
|
+
next = loop ? itemCount - 1 : 0;
|
|
6819
|
+
}
|
|
6820
|
+
if (next >= itemCount) {
|
|
6821
|
+
next = loop ? 0 : itemCount - 1;
|
|
6822
|
+
}
|
|
6823
|
+
if (!isDisabled?.(next)) {
|
|
6824
|
+
return next;
|
|
6825
|
+
}
|
|
6826
|
+
next += direction;
|
|
6827
|
+
}
|
|
6828
|
+
return current;
|
|
6829
|
+
}, [itemCount, loop, isDisabled]);
|
|
6830
|
+
useKeyPress({
|
|
6831
|
+
ArrowDown: (e) => {
|
|
6832
|
+
e.preventDefault();
|
|
6833
|
+
setFocusedIndex((prev) => getNextIndex(prev, 1));
|
|
6834
|
+
},
|
|
6835
|
+
ArrowUp: (e) => {
|
|
6836
|
+
e.preventDefault();
|
|
6837
|
+
setFocusedIndex((prev) => getNextIndex(prev, -1));
|
|
6838
|
+
},
|
|
6839
|
+
Home: (e) => {
|
|
6840
|
+
e.preventDefault();
|
|
6841
|
+
setFocusedIndex(getNextIndex(-1, 1));
|
|
6842
|
+
},
|
|
6843
|
+
End: (e) => {
|
|
6844
|
+
e.preventDefault();
|
|
6845
|
+
setFocusedIndex(getNextIndex(itemCount, -1));
|
|
6846
|
+
},
|
|
6847
|
+
Enter: () => {
|
|
6848
|
+
if (focusedIndex >= 0) {
|
|
6849
|
+
onSelect(focusedIndex);
|
|
6850
|
+
}
|
|
6851
|
+
},
|
|
6852
|
+
}, { enabled });
|
|
6853
|
+
return { focusedIndex, setFocusedIndex };
|
|
6854
|
+
};
|
|
6855
|
+
|
|
6769
6856
|
const lightPalette = {
|
|
6770
6857
|
// Surface
|
|
6771
6858
|
surfaceBackground: '#f8fafc',
|
|
@@ -7226,5 +7313,14 @@ exports.ToggleIconButton = ToggleIconButton;
|
|
|
7226
7313
|
exports.Tooltip = Tooltip;
|
|
7227
7314
|
exports.darkTheme = darkTheme;
|
|
7228
7315
|
exports.lightTheme = lightTheme;
|
|
7316
|
+
exports.useBodyScrollLock = useBodyScrollLock;
|
|
7317
|
+
exports.useControllableState = useControllableState;
|
|
7229
7318
|
exports.useDrawerContext = useDrawerContext;
|
|
7319
|
+
exports.useFocusTrap = useFocusTrap;
|
|
7320
|
+
exports.useKeyPress = useKeyPress;
|
|
7321
|
+
exports.useListKeyNav = useListKeyNav;
|
|
7322
|
+
exports.useMenuPosition = useMenuPosition;
|
|
7323
|
+
exports.useMergedRefs = useMergedRefs;
|
|
7324
|
+
exports.useTooltipPosition = useTooltipPosition;
|
|
7325
|
+
exports.useTransitionRender = useTransitionRender;
|
|
7230
7326
|
//# sourceMappingURL=index.js.map
|