@jirawatpyk/aura-react 5.5.0 → 5.7.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/index.d.ts CHANGED
@@ -124,6 +124,11 @@ export interface DataTableProps<Row extends Record<string, any> = Record<string,
124
124
  onSortChange?: ((sort: DataTableSort | null) => void) | undefined;
125
125
  /** Adds a checkbox column. */
126
126
  selectable?: boolean | undefined;
127
+ /** Which rows can be selected (5.6). A row it rejects shows no checkbox (the cell stays, so columns line up), is
128
+ * skipped by select-all, Space and the count, and never appears in `onSelectionChange` — even if passed in. */
129
+ isRowSelectable?: RowCallback<boolean, Row> | undefined;
130
+ /** Accessible name for a rejected row's empty cell, e.g. `(r) => 'Not awaiting review'` (5.6). */
131
+ rowSelectDisabledLabel?: RowCallback<string, Row> | undefined;
127
132
  /** Controlled selection (row keys); pair with onSelectionChange. */
128
133
  selected?: Array<string | number> | undefined;
129
134
  /** Initial selection when uncontrolled. */
@@ -305,6 +310,9 @@ export interface MenuProps {
305
310
  autoFocus?: boolean | undefined;
306
311
  /** Router link for items with `href`; defaults to AuraProvider's `linkComponent`, then `<a>`. (4.19) */
307
312
  linkComponent?: React$1.ElementType | undefined;
313
+ /** Content above the items (5.7), e.g. who is signed in. Not an item: arrow keys skip it; it is the menu's
314
+ * accessible description, read once when the menu opens. */
315
+ header?: React$1.ReactNode | undefined;
308
316
  }
309
317
  export interface FieldProps {
310
318
  /** Visible label; also the accessible name. */
@@ -487,14 +495,23 @@ export interface AlertProps {
487
495
  onDismiss?: (() => void) | undefined;
488
496
  className?: string | undefined;
489
497
  }
498
+ /** A button (or, with `href`, a link through AuraProvider's `linkComponent`) on a toast (5.6: `href`, `dismiss`). */
499
+ export interface ToastAction {
500
+ label: string;
501
+ onClick?: (() => void) | undefined;
502
+ /** Makes the action a link (routes through `linkComponent`, so `next/link` navigates client-side). */
503
+ href?: string | undefined;
504
+ /** Default true: the toast closes when the action runs. `false` keeps it (a list of items to work through). */
505
+ dismiss?: boolean | undefined;
506
+ }
490
507
  export interface ToastOptions {
491
508
  title: string;
492
- description?: string | undefined;
509
+ /** Text, or (5.6) rich content — lines with their own links, read once inside the toast's live region. */
510
+ description?: React$1.ReactNode | undefined;
493
511
  tone?: FeedbackTone | undefined;
494
- action?: {
495
- label: string;
496
- onClick?: (() => void) | undefined;
497
- } | undefined;
512
+ action?: ToastAction | undefined;
513
+ /** Up to two actions in a row (5.6); used instead of `action` when given. */
514
+ actions?: ToastAction[] | undefined;
498
515
  /** ms before it closes itself. Default 5000; Infinity keeps it until dismissed. */
499
516
  duration?: number | undefined;
500
517
  /** Reuse an id to replace a toast in place (same position, timer restarts) — never a second toast. */
@@ -533,6 +550,9 @@ export interface DialogProps {
533
550
  size?: "sm" | "md" | "lg" | undefined;
534
551
  /** Default true. False hides the close button and ignores Escape and scrim clicks. */
535
552
  dismissible?: boolean | undefined;
553
+ /** Whether a click on the scrim closes it (5.7). Default true, false for `role="alertdialog"`: a stray click
554
+ * outside shouldn't throw away a typed reason. Escape and the close button still close it. */
555
+ dismissOnScrim?: boolean | undefined;
536
556
  /** Use `alertdialog` for destructive confirmations. */
537
557
  role?: "dialog" | "alertdialog" | undefined;
538
558
  /** Default true. Turn off only for static demos. */
@@ -624,6 +644,7 @@ export interface SideNavProps {
624
644
  }
625
645
  export interface BreadcrumbProps {
626
646
  /** Root first; the last item is the current page. */
647
+ /** An item with neither `href` nor `onClick` is plain text (5.7), for a segment with no page of its own. */
627
648
  items: Array<{
628
649
  label: string;
629
650
  href?: string | undefined;
@@ -651,6 +672,9 @@ export interface DropdownMenuProps {
651
672
  label?: string | undefined;
652
673
  /** Router link for items with `href`. (4.19) */
653
674
  linkComponent?: React$1.ElementType | undefined;
675
+ /** Content above the items (5.7), e.g. name, email and role in an account menu. Not an item: arrow keys skip
676
+ * it; it is the menu's accessible description (`aria-describedby`). */
677
+ header?: React$1.ReactNode | undefined;
654
678
  }
655
679
  export interface ComboboxOption {
656
680
  value: string;
@@ -851,6 +875,8 @@ export interface DrawerProps {
851
875
  footer?: React$1.ReactNode | undefined;
852
876
  /** Scrim click and Escape close it. Default true. */
853
877
  dismissible?: boolean | undefined;
878
+ /** Whether a click on the scrim closes it (5.7). Default true; Escape and the close button still close it. */
879
+ dismissOnScrim?: boolean | undefined;
854
880
  /** Default true: focus moves to the element with `data-autofocus`, else the first control in the body. False only for static demos. */
855
881
  autoFocus?: boolean | undefined;
856
882
  /** Needed when there is no title. */
@@ -891,7 +917,8 @@ export interface AppShellProps {
891
917
  children?: React$1.ReactNode | undefined;
892
918
  navLabel?: string | undefined;
893
919
  menuLabel?: string | undefined;
894
- /** id of `<main>`, for a skip link. Default `main`. */
920
+ /** id of `<main>`, for a skip link. Default `main`. `<main>` has `tabIndex={-1}` (5.7), so a skip link or
921
+ * `document.getElementById(mainId).focus()` moves focus there (no ring is drawn on it). */
895
922
  mainId?: string | undefined;
896
923
  /** A BottomNav for phones (4.19). Shown below its `hideFrom` breakpoint; the content keeps room for it, and a
897
924
  * viewport ActionBar sits on top of it. With a `bottomNav` and no `nav`, there is no menu button. */
@@ -965,6 +992,9 @@ export interface BottomNavItem {
965
992
  badge?: boolean | undefined;
966
993
  /** Read after the label when `badge` is set, e.g. "new". */
967
994
  badgeLabel?: string | undefined;
995
+ /** The full name for screen readers when `label` is shortened to fit (5.7), e.g. label "Konto", ariaLabel
996
+ * "Mitt konto". Include the visible label in it (WCAG 2.5.3). The count or badge is still appended. */
997
+ ariaLabel?: string | undefined;
968
998
  }
969
999
  export interface BottomNavProps {
970
1000
  /** 2–5 items. */
@@ -1285,10 +1315,18 @@ export declare namespace toast {
1285
1315
  var dismiss: (id: string) => void;
1286
1316
  }
1287
1317
  export interface ToasterProps {
1288
- /** Default `bottom`. */
1289
- position?: "bottom" | "top" | undefined;
1290
- }
1291
- export declare function Toaster(props: ToasterProps): React$1.ReactElement | null;
1318
+ /** Default `bottom` (bottom right). `top` is top right; `top-center` / `bottom-center` centre the stack (5.6).
1319
+ * Below 640px toasts span the width either way. */
1320
+ position?: "bottom" | "bottom-right" | "bottom-center" | "top" | "top-right" | "top-center" | undefined;
1321
+ /** Distance from the top or bottom edge (5.6), e.g. `64` to clear a 56px top bar; px or any CSS length. Sets
1322
+ * `--aura-toaster-offset`; the safe-area inset is added on top. Default 24px (16px below 640px). */
1323
+ offset?: number | string | undefined;
1324
+ /** Keyboard shortcut to the newest toast (5.6): focuses its action, else its close button, and pauses its timer;
1325
+ * Escape closes it and returns focus. Default `"Alt+T"` (matched on the physical key, so macOS Option+T works);
1326
+ * `false` turns it off. */
1327
+ hotkey?: string | false | undefined;
1328
+ }
1329
+ export declare function Toaster(props?: ToasterProps): React$1.ReactElement | null;
1292
1330
  export declare const PasswordField: React$1.ForwardRefExoticComponent<PasswordFieldProps & React$1.RefAttributes<HTMLInputElement>>;
1293
1331
  export declare const FormErrorSummary: React$1.ForwardRefExoticComponent<FormErrorSummaryProps & React$1.RefAttributes<HTMLDivElement>>;
1294
1332
  export declare const FilterBar: React$1.ForwardRefExoticComponent<FilterBarProps & React$1.RefAttributes<HTMLDivElement>>;
package/dist/styles.css CHANGED
@@ -247,6 +247,12 @@ a.aura-menu__item { text-decoration: none; box-sizing: border-box; }
247
247
  }
248
248
  .aura-menu__radio.is-on { border-color: var(--aura-button-primary-bg); }
249
249
  .aura-menu__radio.is-on::after { content: ''; width: 8px; height: 8px; border-radius: var(--aura-radius-full); background: var(--aura-button-primary-bg); }
250
+ /* 5.7: a header above the items (who is signed in), set off by a hairline like a separator. */
251
+ .aura-menu__header { margin: calc(-1 * var(--aura-space-1)) calc(-1 * var(--aura-space-1)) var(--aura-space-1); padding: var(--aura-space-3); border-bottom: 1px solid var(--aura-border-default); color: var(--aura-fg-secondary); font-size: 12px; line-height: 18px; overflow-wrap: anywhere; }
252
+ .aura-menu__header > * { margin: 0; }
253
+ /* Stays in view when a long menu scrolls. */
254
+ .aura-menu.has-header .aura-menu__header { position: sticky; top: calc(-1 * var(--aura-space-1)); z-index: 1; background: var(--aura-bg-surface); }
255
+ .aura-menu__header strong, .aura-menu__header b { color: var(--aura-fg-primary); font-weight: 500; font-size: 13px; }
250
256
  .aura-menu__sep { height: 1px; margin: var(--aura-space-1) calc(-1 * var(--aura-space-1)); background: var(--aura-border-default); }
251
257
 
252
258
  /* Footer + pager */
@@ -496,7 +502,9 @@ a.aura-icon-btn { text-decoration: none; }
496
502
  display: flex; flex-direction: column; gap: var(--aura-space-2); width: min(380px, calc(100vw - 2 * var(--aura-space-4)));
497
503
  font-family: var(--font-sans);
498
504
  }
499
- .aura-toaster.is-top { bottom: auto; top: var(--aura-space-6); }
505
+ .aura-toaster.is-top { bottom: auto; top: calc(var(--aura-toaster-offset, var(--aura-space-6)) + env(safe-area-inset-top, 0px)); }
506
+ /* 5.6: top-center / bottom-center; `offset` (or --aura-toaster-offset) clears an app's top bar. */
507
+ .aura-toaster.is-center { right: auto; left: 50%; transform: translateX(-50%); }
500
508
  .aura-toast {
501
509
  display: flex; align-items: flex-start; gap: var(--aura-space-3); padding: var(--aura-space-3) var(--aura-space-2) var(--aura-space-3) var(--aura-space-4);
502
510
  background: var(--aura-bg-surface); color: var(--aura-fg-primary);
@@ -511,10 +519,27 @@ a.aura-icon-btn { text-decoration: none; }
511
519
  .aura-toast__body { flex: 1; min-width: 0; padding-top: 1px; }
512
520
  .aura-toast__title { margin: 0; font-size: 14px; font-weight: 500; line-height: 20px; }
513
521
  .aura-toast__text { margin: 2px 0 0; font-size: 13px; line-height: 1.5; color: var(--aura-fg-secondary); }
522
+ .aura-toast__text > * { margin: 0; }
523
+ .aura-toast__text a { color: var(--aura-fg-accent); text-underline-offset: 2px; }
524
+ .aura-toast__text a:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: 1px; border-radius: var(--aura-radius-xs); }
525
+ .aura-toast__actions { flex: none; align-self: center; display: flex; gap: var(--aura-space-1); }
526
+ /* Two actions, or one under a description (5.6): the actions take a row of their own below the text, lined up with it
527
+ * (the action's own padding sits left of the text column), so the text keeps the toast's width. */
528
+ .aura-toast.has-action-row { flex-wrap: wrap; row-gap: var(--aura-space-1); }
529
+ .aura-toast.has-action-row .aura-toast__body { flex-basis: 0; }
530
+ .aura-toast.has-action-row .aura-toast__actions { order: 3; flex-basis: 100%; flex-wrap: wrap; margin-left: calc(16px + var(--aura-space-3) - var(--aura-space-2)); margin-bottom: calc(-1 * var(--aura-space-1)); }
514
531
  .aura-toast__action {
515
532
  flex: none; align-self: center; height: var(--aura-control-sm); padding: 0 var(--aura-space-2);
516
533
  border: 0; border-radius: var(--aura-radius-sm); background: transparent; color: var(--aura-fg-accent);
517
534
  font: inherit; font-size: 13px; font-weight: 500; cursor: pointer;
535
+ display: inline-flex; align-items: center; text-decoration: none; white-space: nowrap;
536
+ }
537
+ /* Touch (5.6): the 32px action gets a 44px hit area, as IconButton does. Links in the text only get a little padding —
538
+ * lines sit 20px apart, so a 44px box would overlap the next line's link. */
539
+ @media (pointer: coarse) {
540
+ .aura-toast__action { position: relative; }
541
+ .aura-toast__action::after { content: ''; position: absolute; top: 50%; left: 50%; width: max(100%, var(--aura-touch-target)); height: max(100%, var(--aura-touch-target)); transform: translate(-50%, -50%); }
542
+ .aura-toast__text a { padding-block: 2px; }
518
543
  }
519
544
  .aura-toast__action:hover { background: var(--aura-bg-surface-hover); }
520
545
  .aura-toast__action:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: 0; }
@@ -625,6 +650,8 @@ a.aura-tab { text-decoration: none; }
625
650
  .aura-nav__item.is-active { background: var(--aura-bg-selected); color: var(--aura-fg-primary); }
626
651
  .aura-nav__item.is-active .aura-icon { color: var(--aura-fg-accent); }
627
652
  .aura-nav__item:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: -2px; }
653
+ /* Touch (5.7): rows are 44px on coarse pointers (AppShell's phone drawer); desktop keeps 36px. */
654
+ @media (pointer: coarse) { .aura-nav__item { height: auto; min-height: var(--aura-touch-target); } }
628
655
  .aura-nav__label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
629
656
  .aura-nav__count { font-size: 11px; font-variant-numeric: tabular-nums; color: var(--aura-fg-secondary); }
630
657
  .aura-nav__badge { display: inline-flex; align-items: center; flex: none; }
@@ -670,6 +697,8 @@ a.aura-tab { text-decoration: none; }
670
697
  .aura-crumbs a:hover, .aura-crumbs button:hover { color: var(--aura-fg-primary); text-decoration: underline; text-underline-offset: 3px; }
671
698
  .aura-crumbs a:focus-visible, .aura-crumbs button:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: 2px; }
672
699
  .aura-crumbs__current { color: var(--aura-fg-primary); font-weight: 500; }
700
+ /* 5.7: a segment with no page of its own — the links' colour, not interactive. */
701
+ .aura-crumbs__text { color: var(--aura-fg-secondary); }
673
702
  .aura-crumbs__sep { color: var(--aura-fg-tertiary); }
674
703
 
675
704
  /* ---------- Avatar ---------- */
@@ -865,6 +894,8 @@ a.aura-tab { text-decoration: none; }
865
894
  }
866
895
  .aura-shell__bar-content { flex: 1; min-width: 0; display: flex; align-items: center; gap: var(--aura-space-3); }
867
896
  .aura-shell__content { flex: 1; min-width: 0; padding: var(--aura-space-6) var(--aura-space-4); }
897
+ /* 5.7: <main> takes focus (tabIndex -1) for skip links and "the row you acted on is gone"; a landmark gets no ring. */
898
+ .aura-shell__content:focus { outline: none; }
868
899
  @media (min-width: 640px) { .aura-shell__content { padding: var(--aura-space-6); } }
869
900
  @media (min-width: 1024px) { .aura-shell__content { padding: var(--aura-space-8); } }
870
901
  /* The shell already pads its content: a Container directly inside only caps the width. */
@@ -1203,6 +1234,8 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
1203
1234
  .aura-dialog__foot > * { width: 100%; }
1204
1235
  .aura-drawer:not(.aura-drawer--nav) { max-width: none; }
1205
1236
  .aura-toaster { left: var(--aura-space-4); right: var(--aura-space-4); bottom: var(--aura-space-4); width: auto; }
1237
+ .aura-toaster.is-center { left: var(--aura-space-4); right: var(--aura-space-4); transform: none; }
1238
+ .aura-toaster.is-top { top: calc(var(--aura-toaster-offset, var(--aura-space-4)) + env(safe-area-inset-top, 0px)); }
1206
1239
  .aura-card { padding: var(--aura-space-4); }
1207
1240
  .aura-stat { padding: var(--aura-space-4); }
1208
1241
  .aura-stat__value { font-size: 24px; }
@@ -1385,9 +1418,9 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
1385
1418
  @media (max-width: 767.98px) { :root:has(.aura-bottomnav--below-md) { --aura-bottomnav-offset: calc(var(--aura-bottomnav-height) + env(safe-area-inset-bottom, 0px)); } }
1386
1419
  @media (max-width: 1023.98px) { :root:has(.aura-bottomnav--below-lg) { --aura-bottomnav-offset: calc(var(--aura-bottomnav-height) + env(safe-area-inset-bottom, 0px)); } }
1387
1420
  @media (max-width: 1279.98px) { :root:has(.aura-bottomnav--below-xl) { --aura-bottomnav-offset: calc(var(--aura-bottomnav-height) + env(safe-area-inset-bottom, 0px)); } }
1388
- /* Toasts clear a BottomNav wherever it shows (phones and tablets). */
1389
- .aura-toaster:not(.is-top) { bottom: calc(var(--aura-space-6) + var(--aura-bottomnav-offset, 0px)); }
1390
- @media (max-width: 639.98px) { .aura-toaster:not(.is-top) { bottom: calc(var(--aura-space-4) + var(--aura-bottomnav-offset, 0px)); } }
1421
+ /* Toasts clear a BottomNav wherever it shows (phones and tablets), else the bottom safe-area inset (5.6). */
1422
+ .aura-toaster:not(.is-top) { bottom: calc(var(--aura-toaster-offset, var(--aura-space-6)) + var(--aura-bottomnav-offset, env(safe-area-inset-bottom, 0px))); }
1423
+ @media (max-width: 639.98px) { .aura-toaster:not(.is-top) { bottom: calc(var(--aura-toaster-offset, var(--aura-space-4)) + var(--aura-bottomnav-offset, env(safe-area-inset-bottom, 0px))); } }
1391
1424
 
1392
1425
  /* ---------- 4.19: ActionBar ---------- */
1393
1426
  /* Sticky, not fixed: it keeps its place at the end of its parent, so it never covers the last field. */
@@ -249,6 +249,12 @@ a.aura-menu__item { text-decoration: none; box-sizing: border-box; }
249
249
  }
250
250
  .aura-menu__radio.is-on { border-color: var(--aura-button-primary-bg); }
251
251
  .aura-menu__radio.is-on::after { content: ''; width: 8px; height: 8px; border-radius: var(--aura-radius-full); background: var(--aura-button-primary-bg); }
252
+ /* 5.7: a header above the items (who is signed in), set off by a hairline like a separator. */
253
+ .aura-menu__header { margin: calc(-1 * var(--aura-space-1)) calc(-1 * var(--aura-space-1)) var(--aura-space-1); padding: var(--aura-space-3); border-bottom: 1px solid var(--aura-border-default); color: var(--aura-fg-secondary); font-size: 12px; line-height: 18px; overflow-wrap: anywhere; }
254
+ .aura-menu__header > * { margin: 0; }
255
+ /* Stays in view when a long menu scrolls. */
256
+ .aura-menu.has-header .aura-menu__header { position: sticky; top: calc(-1 * var(--aura-space-1)); z-index: 1; background: var(--aura-bg-surface); }
257
+ .aura-menu__header strong, .aura-menu__header b { color: var(--aura-fg-primary); font-weight: 500; font-size: 13px; }
252
258
  .aura-menu__sep { height: 1px; margin: var(--aura-space-1) calc(-1 * var(--aura-space-1)); background: var(--aura-border-default); }
253
259
 
254
260
  /* Footer + pager */
@@ -498,7 +504,9 @@ a.aura-icon-btn { text-decoration: none; }
498
504
  display: flex; flex-direction: column; gap: var(--aura-space-2); width: min(380px, calc(100vw - 2 * var(--aura-space-4)));
499
505
  font-family: var(--font-sans);
500
506
  }
501
- .aura-toaster.is-top { bottom: auto; top: var(--aura-space-6); }
507
+ .aura-toaster.is-top { bottom: auto; top: calc(var(--aura-toaster-offset, var(--aura-space-6)) + env(safe-area-inset-top, 0px)); }
508
+ /* 5.6: top-center / bottom-center; `offset` (or --aura-toaster-offset) clears an app's top bar. */
509
+ .aura-toaster.is-center { right: auto; left: 50%; transform: translateX(-50%); }
502
510
  .aura-toast {
503
511
  display: flex; align-items: flex-start; gap: var(--aura-space-3); padding: var(--aura-space-3) var(--aura-space-2) var(--aura-space-3) var(--aura-space-4);
504
512
  background: var(--aura-bg-surface); color: var(--aura-fg-primary);
@@ -513,10 +521,27 @@ a.aura-icon-btn { text-decoration: none; }
513
521
  .aura-toast__body { flex: 1; min-width: 0; padding-top: 1px; }
514
522
  .aura-toast__title { margin: 0; font-size: 14px; font-weight: 500; line-height: 20px; }
515
523
  .aura-toast__text { margin: 2px 0 0; font-size: 13px; line-height: 1.5; color: var(--aura-fg-secondary); }
524
+ .aura-toast__text > * { margin: 0; }
525
+ .aura-toast__text a { color: var(--aura-fg-accent); text-underline-offset: 2px; }
526
+ .aura-toast__text a:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: 1px; border-radius: var(--aura-radius-xs); }
527
+ .aura-toast__actions { flex: none; align-self: center; display: flex; gap: var(--aura-space-1); }
528
+ /* Two actions, or one under a description (5.6): the actions take a row of their own below the text, lined up with it
529
+ * (the action's own padding sits left of the text column), so the text keeps the toast's width. */
530
+ .aura-toast.has-action-row { flex-wrap: wrap; row-gap: var(--aura-space-1); }
531
+ .aura-toast.has-action-row .aura-toast__body { flex-basis: 0; }
532
+ .aura-toast.has-action-row .aura-toast__actions { order: 3; flex-basis: 100%; flex-wrap: wrap; margin-left: calc(16px + var(--aura-space-3) - var(--aura-space-2)); margin-bottom: calc(-1 * var(--aura-space-1)); }
516
533
  .aura-toast__action {
517
534
  flex: none; align-self: center; height: var(--aura-control-sm); padding: 0 var(--aura-space-2);
518
535
  border: 0; border-radius: var(--aura-radius-sm); background: transparent; color: var(--aura-fg-accent);
519
536
  font: inherit; font-size: 13px; font-weight: 500; cursor: pointer;
537
+ display: inline-flex; align-items: center; text-decoration: none; white-space: nowrap;
538
+ }
539
+ /* Touch (5.6): the 32px action gets a 44px hit area, as IconButton does. Links in the text only get a little padding —
540
+ * lines sit 20px apart, so a 44px box would overlap the next line's link. */
541
+ @media (pointer: coarse) {
542
+ .aura-toast__action { position: relative; }
543
+ .aura-toast__action::after { content: ''; position: absolute; top: 50%; left: 50%; width: max(100%, var(--aura-touch-target)); height: max(100%, var(--aura-touch-target)); transform: translate(-50%, -50%); }
544
+ .aura-toast__text a { padding-block: 2px; }
520
545
  }
521
546
  .aura-toast__action:hover { background: var(--aura-bg-surface-hover); }
522
547
  .aura-toast__action:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: 0; }
@@ -627,6 +652,8 @@ a.aura-tab { text-decoration: none; }
627
652
  .aura-nav__item.is-active { background: var(--aura-bg-selected); color: var(--aura-fg-primary); }
628
653
  .aura-nav__item.is-active .aura-icon { color: var(--aura-fg-accent); }
629
654
  .aura-nav__item:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: -2px; }
655
+ /* Touch (5.7): rows are 44px on coarse pointers (AppShell's phone drawer); desktop keeps 36px. */
656
+ @media (pointer: coarse) { .aura-nav__item { height: auto; min-height: var(--aura-touch-target); } }
630
657
  .aura-nav__label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
631
658
  .aura-nav__count { font-size: 11px; font-variant-numeric: tabular-nums; color: var(--aura-fg-secondary); }
632
659
  .aura-nav__badge { display: inline-flex; align-items: center; flex: none; }
@@ -672,6 +699,8 @@ a.aura-tab { text-decoration: none; }
672
699
  .aura-crumbs a:hover, .aura-crumbs button:hover { color: var(--aura-fg-primary); text-decoration: underline; text-underline-offset: 3px; }
673
700
  .aura-crumbs a:focus-visible, .aura-crumbs button:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: 2px; }
674
701
  .aura-crumbs__current { color: var(--aura-fg-primary); font-weight: 500; }
702
+ /* 5.7: a segment with no page of its own — the links' colour, not interactive. */
703
+ .aura-crumbs__text { color: var(--aura-fg-secondary); }
675
704
  .aura-crumbs__sep { color: var(--aura-fg-tertiary); }
676
705
 
677
706
  /* ---------- Avatar ---------- */
@@ -867,6 +896,8 @@ a.aura-tab { text-decoration: none; }
867
896
  }
868
897
  .aura-shell__bar-content { flex: 1; min-width: 0; display: flex; align-items: center; gap: var(--aura-space-3); }
869
898
  .aura-shell__content { flex: 1; min-width: 0; padding: var(--aura-space-6) var(--aura-space-4); }
899
+ /* 5.7: <main> takes focus (tabIndex -1) for skip links and "the row you acted on is gone"; a landmark gets no ring. */
900
+ .aura-shell__content:focus { outline: none; }
870
901
  @media (min-width: 640px) { .aura-shell__content { padding: var(--aura-space-6); } }
871
902
  @media (min-width: 1024px) { .aura-shell__content { padding: var(--aura-space-8); } }
872
903
  /* The shell already pads its content: a Container directly inside only caps the width. */
@@ -1205,6 +1236,8 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
1205
1236
  .aura-dialog__foot > * { width: 100%; }
1206
1237
  .aura-drawer:not(.aura-drawer--nav) { max-width: none; }
1207
1238
  .aura-toaster { left: var(--aura-space-4); right: var(--aura-space-4); bottom: var(--aura-space-4); width: auto; }
1239
+ .aura-toaster.is-center { left: var(--aura-space-4); right: var(--aura-space-4); transform: none; }
1240
+ .aura-toaster.is-top { top: calc(var(--aura-toaster-offset, var(--aura-space-4)) + env(safe-area-inset-top, 0px)); }
1208
1241
  .aura-card { padding: var(--aura-space-4); }
1209
1242
  .aura-stat { padding: var(--aura-space-4); }
1210
1243
  .aura-stat__value { font-size: 24px; }
@@ -1387,9 +1420,9 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
1387
1420
  @media (max-width: 767.98px) { :root:has(.aura-bottomnav--below-md) { --aura-bottomnav-offset: calc(var(--aura-bottomnav-height) + env(safe-area-inset-bottom, 0px)); } }
1388
1421
  @media (max-width: 1023.98px) { :root:has(.aura-bottomnav--below-lg) { --aura-bottomnav-offset: calc(var(--aura-bottomnav-height) + env(safe-area-inset-bottom, 0px)); } }
1389
1422
  @media (max-width: 1279.98px) { :root:has(.aura-bottomnav--below-xl) { --aura-bottomnav-offset: calc(var(--aura-bottomnav-height) + env(safe-area-inset-bottom, 0px)); } }
1390
- /* Toasts clear a BottomNav wherever it shows (phones and tablets). */
1391
- .aura-toaster:not(.is-top) { bottom: calc(var(--aura-space-6) + var(--aura-bottomnav-offset, 0px)); }
1392
- @media (max-width: 639.98px) { .aura-toaster:not(.is-top) { bottom: calc(var(--aura-space-4) + var(--aura-bottomnav-offset, 0px)); } }
1423
+ /* Toasts clear a BottomNav wherever it shows (phones and tablets), else the bottom safe-area inset (5.6). */
1424
+ .aura-toaster:not(.is-top) { bottom: calc(var(--aura-toaster-offset, var(--aura-space-6)) + var(--aura-bottomnav-offset, env(safe-area-inset-bottom, 0px))); }
1425
+ @media (max-width: 639.98px) { .aura-toaster:not(.is-top) { bottom: calc(var(--aura-toaster-offset, var(--aura-space-4)) + var(--aura-bottomnav-offset, env(safe-area-inset-bottom, 0px))); } }
1393
1426
 
1394
1427
  /* ---------- 4.19: ActionBar ---------- */
1395
1428
  /* Sticky, not fixed: it keeps its place at the end of its parent, so it never covers the last field. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jirawatpyk/aura-react",
3
- "version": "5.5.0",
3
+ "version": "5.7.0",
4
4
  "description": "AURA Design System — React components (Enterprise Standard, Human Creative). Thai-first: Buddhist-era dates, Thai collation.",
5
5
  "license": "MIT",
6
6
  "type": "module",