@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/esm/index.js
CHANGED
|
@@ -359,8 +359,8 @@ const buildActionButtonRootStyle = (theme, variant, color, focusOptions) => {
|
|
|
359
359
|
backgroundColor: intent.main,
|
|
360
360
|
borderColor: intent.main,
|
|
361
361
|
color: intent.on,
|
|
362
|
-
':hover:not(:disabled)': { backgroundColor: intent.hover
|
|
363
|
-
':active:not(:disabled)': { backgroundColor: intent.active
|
|
362
|
+
':hover:not(:disabled)': { backgroundColor: intent.hover },
|
|
363
|
+
':active:not(:disabled)': { backgroundColor: intent.active },
|
|
364
364
|
}
|
|
365
365
|
: variant === 'outlined'
|
|
366
366
|
? {
|
|
@@ -368,7 +368,7 @@ const buildActionButtonRootStyle = (theme, variant, color, focusOptions) => {
|
|
|
368
368
|
borderColor: intent.border,
|
|
369
369
|
color: intent.fg,
|
|
370
370
|
':hover:not(:disabled)': { backgroundColor: intent.subtleHover, color: intent.fgHover },
|
|
371
|
-
':active:not(:disabled)': { backgroundColor: intent.subtleActive,
|
|
371
|
+
':active:not(:disabled)': { backgroundColor: intent.subtleActive, color: intent.active },
|
|
372
372
|
}
|
|
373
373
|
: {
|
|
374
374
|
backgroundColor: 'transparent',
|
|
@@ -390,7 +390,7 @@ const buildActionButtonRootStyle = (theme, variant, color, focusOptions) => {
|
|
|
390
390
|
height: DEFAULT_BUTTON_HEIGHT,
|
|
391
391
|
cursor: 'pointer',
|
|
392
392
|
outline: 'none',
|
|
393
|
-
transition: `background-color ${theme.transition.normal},
|
|
393
|
+
transition: `background-color ${theme.transition.normal}, color ${theme.transition.normal}`,
|
|
394
394
|
...colorVariantStyles,
|
|
395
395
|
':focus-visible': getFocusRingStyles(theme, focusOptions),
|
|
396
396
|
':disabled': { cursor: 'not-allowed', opacity: theme.opacity.high },
|
|
@@ -3278,17 +3278,17 @@ const TEXTFIELD_WRAPPER_VARIANTS = createVariants((theme) => {
|
|
|
3278
3278
|
return {
|
|
3279
3279
|
base: {
|
|
3280
3280
|
display: 'flex',
|
|
3281
|
-
|
|
3282
|
-
|
|
3281
|
+
// `stretch` lets the inner input fill the full height of the box so
|
|
3282
|
+
// clicking anywhere (including the vertical padding area) hits it.
|
|
3283
|
+
alignItems: 'stretch',
|
|
3283
3284
|
boxSizing: 'border-box',
|
|
3284
3285
|
borderWidth: '1px',
|
|
3285
3286
|
borderStyle: 'solid',
|
|
3286
3287
|
borderRadius: theme.radius.md,
|
|
3287
3288
|
backgroundColor: c.surfacePaper,
|
|
3289
|
+
// No focus ring on text inputs: focus is conveyed by the status
|
|
3290
|
+
// border colour change (see the `status` variants below).
|
|
3288
3291
|
transition: `border-color ${theme.transition.fast}`,
|
|
3289
|
-
// Full, always-visible focus ring when the inner input is focused
|
|
3290
|
-
// (single source of truth) — complements the status border colour.
|
|
3291
|
-
':focus-within': getFocusRingStyles(theme),
|
|
3292
3292
|
'&[data-disabled]': {
|
|
3293
3293
|
opacity: theme.opacity.high,
|
|
3294
3294
|
backgroundColor: c.disabledMain,
|
|
@@ -3297,10 +3297,12 @@ const TEXTFIELD_WRAPPER_VARIANTS = createVariants((theme) => {
|
|
|
3297
3297
|
},
|
|
3298
3298
|
variants: {
|
|
3299
3299
|
size: {
|
|
3300
|
+
// Horizontal padding lives on the input itself (see TEXTFIELD_INPUT_VARIANTS),
|
|
3301
|
+
// not here, so the whole bordered area is part of the clickable input.
|
|
3300
3302
|
// Font-size is set on the wrapper so the native input inherits it via `fontSize: 'inherit'`.
|
|
3301
|
-
sm: { height: '2rem',
|
|
3302
|
-
md: { height: '2.5rem',
|
|
3303
|
-
lg: { height: '3rem',
|
|
3303
|
+
sm: { height: '2rem', fontSize: theme.fontSize.xs },
|
|
3304
|
+
md: { height: '2.5rem', fontSize: theme.fontSize.sm },
|
|
3305
|
+
lg: { height: '3rem', fontSize: theme.fontSize.md },
|
|
3304
3306
|
},
|
|
3305
3307
|
status: {
|
|
3306
3308
|
default: {
|
|
@@ -3325,11 +3327,17 @@ const TEXTFIELD_WRAPPER_VARIANTS = createVariants((theme) => {
|
|
|
3325
3327
|
defaultVariants: { size: 'md', status: 'default' },
|
|
3326
3328
|
};
|
|
3327
3329
|
}, { id: 'textfield-wrapper' });
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3330
|
+
/**
|
|
3331
|
+
* The native input carries the horizontal padding and fills 100% of the
|
|
3332
|
+
* wrapper height, so the entire bordered box is part of the clickable input
|
|
3333
|
+
* (no dead zone between the text and the border).
|
|
3334
|
+
*/
|
|
3335
|
+
const TEXTFIELD_INPUT_VARIANTS = createVariants((theme) => ({
|
|
3336
|
+
base: {
|
|
3331
3337
|
flex: 1,
|
|
3332
3338
|
minWidth: 0,
|
|
3339
|
+
height: '100%',
|
|
3340
|
+
boxSizing: 'border-box',
|
|
3333
3341
|
border: 'none',
|
|
3334
3342
|
outline: 'none',
|
|
3335
3343
|
background: 'transparent',
|
|
@@ -3337,15 +3345,25 @@ const TEXTFIELD_STYLES = createStyles((theme) => ({
|
|
|
3337
3345
|
fontFamily: 'inherit',
|
|
3338
3346
|
fontSize: 'inherit',
|
|
3339
3347
|
lineHeight: 'normal',
|
|
3340
|
-
padding: '0',
|
|
3341
3348
|
'&::placeholder': { color: theme.colors.textTertiary },
|
|
3342
3349
|
'&:disabled': { cursor: 'not-allowed', color: theme.colors.textDisabled },
|
|
3343
3350
|
},
|
|
3351
|
+
variants: {
|
|
3352
|
+
size: {
|
|
3353
|
+
sm: { paddingLeft: theme.spacing.sm, paddingRight: theme.spacing.sm },
|
|
3354
|
+
md: { paddingLeft: theme.spacing.sm, paddingRight: theme.spacing.sm },
|
|
3355
|
+
lg: { paddingLeft: theme.spacing.md, paddingRight: theme.spacing.md },
|
|
3356
|
+
},
|
|
3357
|
+
},
|
|
3358
|
+
defaultVariants: { size: 'md' },
|
|
3359
|
+
}), { id: 'textfield-input' });
|
|
3360
|
+
const TEXTFIELD_STYLES = createStyles((theme) => ({
|
|
3344
3361
|
/** Wrapper for the start icon — aligned with the input baseline. Clickable to focus the input. */
|
|
3345
3362
|
startIconWrap: {
|
|
3346
3363
|
display: 'flex',
|
|
3347
3364
|
alignItems: 'center',
|
|
3348
3365
|
flexShrink: 0,
|
|
3366
|
+
paddingLeft: theme.spacing.sm,
|
|
3349
3367
|
cursor: 'pointer',
|
|
3350
3368
|
},
|
|
3351
3369
|
/** Wrapper for end actions (custom content + optional password toggle). */
|
|
@@ -3353,6 +3371,7 @@ const TEXTFIELD_STYLES = createStyles((theme) => ({
|
|
|
3353
3371
|
display: 'flex',
|
|
3354
3372
|
alignItems: 'center',
|
|
3355
3373
|
flexShrink: 0,
|
|
3374
|
+
paddingRight: theme.spacing.xs,
|
|
3356
3375
|
gap: theme.spacing['2xs'],
|
|
3357
3376
|
},
|
|
3358
3377
|
}), { id: 'textfield-extra' });
|
|
@@ -3413,7 +3432,11 @@ const useTextField = ({ id, ref, type, size, endAction, }) => {
|
|
|
3413
3432
|
*/
|
|
3414
3433
|
const TextField = ({ ref, label, helperText, size = 'md', status = 'default', startIcon: StartIcon, endAction, type, id, disabled, required, ...rest }) => {
|
|
3415
3434
|
const { fieldId, helperId, mergedRef, isPassword, showPassword, togglePassword, resolvedType, iconSize, iconButtonSize, hasEndSection, focusInput, } = useTextField({ id, ref, type, size, endAction });
|
|
3416
|
-
|
|
3435
|
+
// Associate the label with the input via `aria-labelledby` (and NOT `htmlFor`)
|
|
3436
|
+
// so the label stays accessible without natively focusing the input on click —
|
|
3437
|
+
// only clicking inside the bordered box should focus the field.
|
|
3438
|
+
const labelId = `${fieldId}-label`;
|
|
3439
|
+
return (jsxs(Stack, { flexDirection: 'column', gap: 'xs', children: [label !== undefined && (jsxs(Text, { variant: 'label', fontSize: 'sm', fontWeight: 'medium', color: 'textSecondary', id: labelId, children: [label, required && (jsx(Text, { variant: 'span', color: 'errorMain', "aria-hidden": true, children: ' *' }))] })), jsxs("div", { className: TEXTFIELD_WRAPPER_VARIANTS({ size, status }), "data-disabled": disabled || undefined, children: [StartIcon && (jsx("span", { className: TEXTFIELD_STYLES.startIconWrap, onClick: focusInput, "aria-hidden": true, children: jsx(Icon, { icon: StartIcon, size: iconSize, strokeColor: 'textSecondary' }) })), 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 && (jsxs("span", { className: TEXTFIELD_STYLES.endActionWrap, children: [endAction, isPassword && (jsx(IconButton, { icon: showPassword ? EyeSlashIcon : EyeIcon, ariaLabel: showPassword ? 'Hide password' : 'Show password', variant: 'text', color: 'neutral', size: iconButtonSize, type: 'button', onClick: togglePassword }))] }))] }), helperText !== undefined && (jsx(FormHelperText, { id: helperId, status: status, children: helperText }))] }));
|
|
3417
3440
|
};
|
|
3418
3441
|
TextField.displayName = 'TextField';
|
|
3419
3442
|
|
|
@@ -4006,8 +4029,8 @@ const SELECT_TRIGGER_VARIANTS = createVariants((theme) => {
|
|
|
4006
4029
|
transition: `border-color ${theme.transition.fast}`,
|
|
4007
4030
|
outline: 'none',
|
|
4008
4031
|
fontFamily: 'inherit',
|
|
4009
|
-
//
|
|
4010
|
-
|
|
4032
|
+
// No focus ring on the trigger: focus is conveyed by the border
|
|
4033
|
+
// colour change (see the `status` variants below).
|
|
4011
4034
|
'&[data-open]': {
|
|
4012
4035
|
borderColor: c.primaryMain,
|
|
4013
4036
|
},
|
|
@@ -4044,6 +4067,9 @@ const SELECT_TRIGGER_VARIANTS = createVariants((theme) => {
|
|
|
4044
4067
|
':hover:not([data-disabled]):not([data-open])': {
|
|
4045
4068
|
borderColor: c.borderStrong,
|
|
4046
4069
|
},
|
|
4070
|
+
'&:focus-visible:not([data-open])': {
|
|
4071
|
+
borderColor: c.primaryMain,
|
|
4072
|
+
},
|
|
4047
4073
|
},
|
|
4048
4074
|
error: {
|
|
4049
4075
|
borderColor: c.errorMain,
|
|
@@ -6746,6 +6772,67 @@ const Dialog = DialogBase;
|
|
|
6746
6772
|
Dialog.Header = DialogHeader;
|
|
6747
6773
|
Dialog.Body = DialogBody;
|
|
6748
6774
|
|
|
6775
|
+
/**
|
|
6776
|
+
* Manages keyboard navigation for a listbox-style menu.
|
|
6777
|
+
*
|
|
6778
|
+
* Binds ArrowDown, ArrowUp, Home, End, and Enter using `useKeyPress`.
|
|
6779
|
+
* Automatically skips disabled items and optionally wraps around (loop).
|
|
6780
|
+
* Resets focus when `enabled` toggles.
|
|
6781
|
+
*/
|
|
6782
|
+
const useListKeyNav = ({ itemCount, enabled, onSelect, isDisabled, loop = true, initialIndex = 0, }) => {
|
|
6783
|
+
const [focusedIndex, setFocusedIndex] = useState(-1);
|
|
6784
|
+
const initialIndexRef = useRef(initialIndex);
|
|
6785
|
+
useEffect(() => {
|
|
6786
|
+
initialIndexRef.current = initialIndex;
|
|
6787
|
+
}, [initialIndex]);
|
|
6788
|
+
useEffect(() => {
|
|
6789
|
+
setFocusedIndex(enabled ? initialIndexRef.current : -1);
|
|
6790
|
+
}, [enabled]);
|
|
6791
|
+
const getNextIndex = useCallback((current, direction) => {
|
|
6792
|
+
if (itemCount === 0) {
|
|
6793
|
+
return -1;
|
|
6794
|
+
}
|
|
6795
|
+
let next = current + direction;
|
|
6796
|
+
for (let i = 0; i < itemCount; i++) {
|
|
6797
|
+
if (next < 0) {
|
|
6798
|
+
next = loop ? itemCount - 1 : 0;
|
|
6799
|
+
}
|
|
6800
|
+
if (next >= itemCount) {
|
|
6801
|
+
next = loop ? 0 : itemCount - 1;
|
|
6802
|
+
}
|
|
6803
|
+
if (!isDisabled?.(next)) {
|
|
6804
|
+
return next;
|
|
6805
|
+
}
|
|
6806
|
+
next += direction;
|
|
6807
|
+
}
|
|
6808
|
+
return current;
|
|
6809
|
+
}, [itemCount, loop, isDisabled]);
|
|
6810
|
+
useKeyPress({
|
|
6811
|
+
ArrowDown: (e) => {
|
|
6812
|
+
e.preventDefault();
|
|
6813
|
+
setFocusedIndex((prev) => getNextIndex(prev, 1));
|
|
6814
|
+
},
|
|
6815
|
+
ArrowUp: (e) => {
|
|
6816
|
+
e.preventDefault();
|
|
6817
|
+
setFocusedIndex((prev) => getNextIndex(prev, -1));
|
|
6818
|
+
},
|
|
6819
|
+
Home: (e) => {
|
|
6820
|
+
e.preventDefault();
|
|
6821
|
+
setFocusedIndex(getNextIndex(-1, 1));
|
|
6822
|
+
},
|
|
6823
|
+
End: (e) => {
|
|
6824
|
+
e.preventDefault();
|
|
6825
|
+
setFocusedIndex(getNextIndex(itemCount, -1));
|
|
6826
|
+
},
|
|
6827
|
+
Enter: () => {
|
|
6828
|
+
if (focusedIndex >= 0) {
|
|
6829
|
+
onSelect(focusedIndex);
|
|
6830
|
+
}
|
|
6831
|
+
},
|
|
6832
|
+
}, { enabled });
|
|
6833
|
+
return { focusedIndex, setFocusedIndex };
|
|
6834
|
+
};
|
|
6835
|
+
|
|
6749
6836
|
const lightPalette = {
|
|
6750
6837
|
// Surface
|
|
6751
6838
|
surfaceBackground: '#f8fafc',
|
|
@@ -7154,5 +7241,5 @@ const darkTheme = createTheme({
|
|
|
7154
7241
|
breakpoints: themeBreakpoints,
|
|
7155
7242
|
});
|
|
7156
7243
|
|
|
7157
|
-
export { Accordion, Alert, Article, Aside, Avatar, AvatarGroup, Backdrop, Badge, Box, Breadcrumb, Button, Card, Checkbox, DatePicker, DefaultErrorFallback, Dialog, Drawer, ErrorBoundary, Fab, Footer, Form, Grid, Header, Icon, IconButton, Image, InfoBubble, Link, LoaderScreen, Main, Menu, Nav, Pagination, RadioButton, RadioGroup, Section, Select, Separator, Skeleton, Stack, SvgImage, Switch, Table, Tabs, Text, TextField, ToggleButton, ToggleGroup, ToggleIconButton, Tooltip, darkTheme, lightTheme, useDrawerContext };
|
|
7244
|
+
export { Accordion, Alert, Article, Aside, Avatar, AvatarGroup, Backdrop, Badge, Box, Breadcrumb, Button, Card, Checkbox, DatePicker, DefaultErrorFallback, Dialog, Drawer, ErrorBoundary, Fab, Footer, Form, Grid, Header, Icon, IconButton, Image, InfoBubble, Link, LoaderScreen, Main, Menu, Nav, Pagination, RadioButton, RadioGroup, Section, Select, Separator, Skeleton, Stack, SvgImage, Switch, Table, Tabs, Text, TextField, ToggleButton, ToggleGroup, ToggleIconButton, Tooltip, darkTheme, lightTheme, useBodyScrollLock, useControllableState, useDrawerContext, useFocusTrap, useKeyPress, useListKeyNav, useMenuPosition, useMergedRefs, useTooltipPosition, useTransitionRender };
|
|
7158
7245
|
//# sourceMappingURL=index.js.map
|