@jirawatpyk/aura-react 5.69.0 → 5.70.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
@@ -332,10 +332,24 @@ export interface StatusPillProps extends Omit<React$1.HTMLAttributes<HTMLSpanEle
332
332
  /** 5.51 (Chamber-OS 158): in a box narrower than the words, the text wraps inside the pill (still rounded, the icon
333
333
  * on the first line) instead of running out of it. Without it a pill stays on one line. */
334
334
  wrap?: boolean | undefined;
335
+ /** 5.70 (Chamber-OS 189): the spinner in the icon slot, for a state still in progress ("Waiting for payment").
336
+ * The words still say it; the tone is unchanged. */
337
+ busy?: boolean | undefined;
335
338
  /** Force a tone. Default: matched from the word (Ready/Done → ready, In Progress/In Review → progress, Warning/Problem/Degraded/At risk → warning (5.1), Blocked/Failed → blocked, anything else → neutral). */
336
339
  tone?: StatusTone | undefined;
337
340
  className?: string | undefined;
338
341
  }
342
+ /** 5.70 (Chamber-OS 189): Button's loading spinner on its own, for "working" outside a button. */
343
+ export interface SpinnerProps extends Omit<React$1.HTMLAttributes<HTMLSpanElement>, "children"> {
344
+ /** `sm` 16px (Button's spinner) · `md` 20px (default) · `lg` 24px — the icon sizes. It takes the text colour. */
345
+ size?: "sm" | "md" | "lg" | undefined;
346
+ /** Without it the spinner is `aria-hidden`: the text beside it, or your live region, says what is happening. With it
347
+ * the spinner is `role="status"` with this text (visually hidden), for a spinner standing alone: it names it for
348
+ * browse mode, but a status inserted with its text already in it is often not announced — to announce the change,
349
+ * keep a live region on the page and put the words in it. */
350
+ label?: string | undefined;
351
+ className?: string | undefined;
352
+ }
339
353
  /** 16px checkbox with 4px corners; ink when checked, a dash when indeterminate. */
340
354
  export interface CheckboxProps extends Omit<React$1.InputHTMLAttributes<HTMLInputElement>, "onChange" | "type" | "checked" | "defaultChecked"> {
341
355
  /** Controlled state; pair with onChange. Or use defaultChecked. */
@@ -1497,6 +1511,16 @@ export interface TableCellProps extends Omit<React$1.TdHTMLAttributes<HTMLTableC
1497
1511
  /** Th in the head only (5.52): this column's width while loading — a share such as `'22%'` — when the loaded table
1498
1512
  * sizes it from its content. Default: the cell's `width`, else an even share. */
1499
1513
  skeletonWidth?: string | number | undefined;
1514
+ /** Th only (5.70, Chamber-OS 188): this column's order — `aria-sort` on the header. With `onSort` or `sortHref` the
1515
+ * label becomes a button or link holding AURA's sort icon (up, down, or both ways for `none`), as DataTable's
1516
+ * sortable header; alone, it only says the order. */
1517
+ sort?: "ascending" | "descending" | "none" | undefined;
1518
+ /** Th only (5.70): the header becomes a button that calls this — flip the order yourself. */
1519
+ onSort?: (() => void) | undefined;
1520
+ /** Th only (5.70): the header becomes a link (through `linkComponent`) to this, for a server-sorted page. */
1521
+ sortHref?: string | undefined;
1522
+ /** Th only (5.70): your router's link for `sortHref`; defaults to AuraProvider's `linkComponent`, then `<a>`. */
1523
+ linkComponent?: React$1.ElementType | undefined;
1500
1524
  className?: string | undefined;
1501
1525
  }
1502
1526
  export interface ActionBarProps {
@@ -1668,6 +1692,22 @@ export interface FileUploadProps extends FieldProps {
1668
1692
  name?: string | undefined;
1669
1693
  disabled?: boolean | undefined;
1670
1694
  className?: string | undefined;
1695
+ /** 5.70 (Chamber-OS 190): `dropzone` (default) is the drop area with its file list. `button` is a Button that opens
1696
+ * the picker, for a file the app sends itself (a logo, a certificate): it checks `accept` and `maxSize` with the same
1697
+ * messages, calls `onSelect` with the accepted files and keeps no list (`value` / `onChange` are not used). The
1698
+ * label, hint and error are Field's, as before; the Button is named by the label and its own text. */
1699
+ variant?: "dropzone" | "button" | undefined;
1700
+ /** `variant="button"`: the accepted files of a pick (none is passed when every file was refused; the error shows).
1701
+ * With a `name` the input posts only the accepted files, and `required` is checked by the browser on submit. The
1702
+ * forwarded ref is the input, but its `focus()` moves to the Button. */
1703
+ onSelect?: ((files: File[]) => void) | undefined;
1704
+ /** `variant="button"`: the Button's text. Default "Choose a file" ("Choose files" with `multiple`). */
1705
+ buttonLabel?: React$1.ReactNode | undefined;
1706
+ /** `variant="button"`: an upload in progress under the Button — 0–100, or `null` for indeterminate; leave it out
1707
+ * when nothing is uploading. */
1708
+ progress?: number | null | undefined;
1709
+ /** `variant="button"`: Button's `touchHeight` (44px below 640px or on a coarse pointer). */
1710
+ touchHeight?: boolean | undefined;
1671
1711
  }
1672
1712
  export type Tone = "neutral" | "accent" | "success" | "warning" | "danger";
1673
1713
  export interface BadgeProps extends React$1.HTMLAttributes<HTMLSpanElement> {
@@ -1749,7 +1789,37 @@ export interface EmptyStateProps extends Omit<React$1.HTMLAttributes<HTMLDivElem
1749
1789
  headingLevel?: 2 | 3 | 4 | 5 | 6 | false | undefined;
1750
1790
  className?: string | undefined;
1751
1791
  }
1792
+ /** 5.70 (Chamber-OS 187): keyset / cursor lists — no page count, only whether there is a first, previous and next
1793
+ * page. Pass an href (rendered through `linkComponent`) or a callback for each end; one with neither, or with its
1794
+ * `has…` false, is shown disabled (out of the tab order). */
1795
+ export interface CursorPaginationProps {
1796
+ mode: "cursor";
1797
+ firstHref?: string | undefined;
1798
+ previousHref?: string | undefined;
1799
+ nextHref?: string | undefined;
1800
+ /** Run instead of following the href on a plain click, or as a button's action without one. */
1801
+ onFirst?: (() => void) | undefined;
1802
+ onPrevious?: (() => void) | undefined;
1803
+ onNext?: (() => void) | undefined;
1804
+ /** `false` disables that end even with an href or callback (default: enabled when it has one). */
1805
+ hasFirst?: boolean | undefined;
1806
+ hasPrevious?: boolean | undefined;
1807
+ hasNext?: boolean | undefined;
1808
+ /** Default true. `false` leaves the First link out (a list that only goes forward). */
1809
+ showFirst?: boolean | undefined;
1810
+ /** A line at the start, e.g. "Showing 50 of 1,240". Not a live region. */
1811
+ status?: React$1.ReactNode | undefined;
1812
+ /** Name of the nav. Default "Pagination". */
1813
+ label?: string | undefined;
1814
+ linkComponent?: React$1.ElementType | undefined;
1815
+ className?: string | undefined;
1816
+ }
1817
+ /** Either kind of Pagination's props (5.70). `PaginationProps` stays the numbered one, so wrappers that extend or
1818
+ * pick from it keep compiling. */
1819
+ export type AnyPaginationProps = PaginationProps | CursorPaginationProps;
1752
1820
  export interface PaginationProps {
1821
+ /** `pages` (default): numbered pages. `cursor` (5.70): see CursorPaginationProps. */
1822
+ mode?: "pages" | undefined;
1753
1823
  pageCount: number;
1754
1824
  /** 1-based, controlled; pair with onChange. Or defaultPage. */
1755
1825
  page?: number | undefined;
@@ -2287,6 +2357,8 @@ export interface AuraStrings {
2287
2357
  opensInNewTab: string;
2288
2358
  /** 5.67: read after a CheckboxGroup's legend when `required` (its `*` is hidden from screen readers). */
2289
2359
  required: string;
2360
+ /** 5.70: a cursor Pagination's link back to the start. */
2361
+ firstPage: string;
2290
2362
  /** 5.42: FilterBar's collapsed-filters button, read with its count ("Filters, 2 applied"). */
2291
2363
  filtersApplied: (n: number) => string;
2292
2364
  /** 5.42: closes FilterBar's "Filters" sheet. */
@@ -2412,7 +2484,8 @@ export declare const Tag: React$1.ForwardRefExoticComponent<TagProps & React$1.R
2412
2484
  export declare const Progress: React$1.ForwardRefExoticComponent<ProgressProps & React$1.RefAttributes<HTMLDivElement>>;
2413
2485
  export declare const Skeleton: React$1.ForwardRefExoticComponent<SkeletonProps & React$1.RefAttributes<HTMLSpanElement>>;
2414
2486
  export declare const EmptyState: React$1.ForwardRefExoticComponent<EmptyStateProps & React$1.RefAttributes<HTMLDivElement>>;
2415
- export declare const Pagination: React$1.ForwardRefExoticComponent<PaginationProps & React$1.RefAttributes<HTMLElement>>;
2487
+ export declare const Pagination: React$1.ForwardRefExoticComponent<AnyPaginationProps & React$1.RefAttributes<HTMLElement>>;
2488
+ export declare const Spinner: React$1.ForwardRefExoticComponent<SpinnerProps & React$1.RefAttributes<HTMLSpanElement>>;
2416
2489
  export declare const Accordion: React$1.ForwardRefExoticComponent<AccordionProps & React$1.RefAttributes<HTMLDivElement>>;
2417
2490
  export declare const Popover: React$1.ForwardRefExoticComponent<PopoverProps & React$1.RefAttributes<HTMLDivElement>>;
2418
2491
  /** Number input with thousands separators, +/− buttons and arrow keys (ARIA spinbutton). */
@@ -155,6 +155,7 @@ var sv = {
155
155
  statusUnknown: "Ingen data",
156
156
  opensInNewTab: "\xF6ppnas i en ny flik",
157
157
  required: "obligatoriskt",
158
+ firstPage: "F\xF6rsta sidan",
158
159
  filtersApplied: function(n) {
159
160
  return "Filter, " + n.toLocaleString("sv-SE") + " aktiva";
160
161
  },
@@ -100,6 +100,8 @@ export interface AuraStrings {
100
100
  opensInNewTab: string;
101
101
  /** 5.67: read after a CheckboxGroup's legend when `required` (its `*` is hidden from screen readers). */
102
102
  required: string;
103
+ /** 5.70: a cursor Pagination's link back to the start. */
104
+ firstPage: string;
103
105
  /** 5.42: FilterBar's collapsed-filters button, read with its count ("Filters, 2 applied"). */
104
106
  filtersApplied: (n: number) => string;
105
107
  /** 5.42: closes FilterBar's "Filters" sheet. */
@@ -100,6 +100,8 @@ export interface AuraStrings {
100
100
  opensInNewTab: string;
101
101
  /** 5.67: read after a CheckboxGroup's legend when `required` (its `*` is hidden from screen readers). */
102
102
  required: string;
103
+ /** 5.70: a cursor Pagination's link back to the start. */
104
+ firstPage: string;
103
105
  /** 5.42: FilterBar's collapsed-filters button, read with its count ("Filters, 2 applied"). */
104
106
  filtersApplied: (n: number) => string;
105
107
  /** 5.42: closes FilterBar's "Filters" sheet. */
@@ -155,6 +155,7 @@ var th = {
155
155
  statusUnknown: "\u0E22\u0E31\u0E07\u0E44\u0E21\u0E48\u0E21\u0E35\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25",
156
156
  opensInNewTab: "\u0E40\u0E1B\u0E34\u0E14\u0E43\u0E19\u0E41\u0E17\u0E47\u0E1A\u0E43\u0E2B\u0E21\u0E48",
157
157
  required: "\u0E08\u0E33\u0E40\u0E1B\u0E47\u0E19",
158
+ firstPage: "\u0E2B\u0E19\u0E49\u0E32\u0E41\u0E23\u0E01",
158
159
  filtersApplied: function(n2) {
159
160
  return "\u0E15\u0E31\u0E27\u0E01\u0E23\u0E2D\u0E07, \u0E43\u0E0A\u0E49\u0E2D\u0E22\u0E39\u0E48 " + n2.toLocaleString("en") + " \u0E23\u0E32\u0E22\u0E01\u0E32\u0E23";
160
161
  },
@@ -100,6 +100,8 @@ export interface AuraStrings {
100
100
  opensInNewTab: string;
101
101
  /** 5.67: read after a CheckboxGroup's legend when `required` (its `*` is hidden from screen readers). */
102
102
  required: string;
103
+ /** 5.70: a cursor Pagination's link back to the start. */
104
+ firstPage: string;
103
105
  /** 5.42: FilterBar's collapsed-filters button, read with its count ("Filters, 2 applied"). */
104
106
  filtersApplied: (n: number) => string;
105
107
  /** 5.42: closes FilterBar's "Filters" sheet. */
@@ -100,6 +100,8 @@ export interface AuraStrings {
100
100
  opensInNewTab: string;
101
101
  /** 5.67: read after a CheckboxGroup's legend when `required` (its `*` is hidden from screen readers). */
102
102
  required: string;
103
+ /** 5.70: a cursor Pagination's link back to the start. */
104
+ firstPage: string;
103
105
  /** 5.42: FilterBar's collapsed-filters button, read with its count ("Filters, 2 applied"). */
104
106
  filtersApplied: (n: number) => string;
105
107
  /** 5.42: closes FilterBar's "Filters" sheet. */
@@ -40,6 +40,7 @@ __export(server_exports, {
40
40
  PageHeader: () => PageHeader,
41
41
  STRINGS: () => STRINGS,
42
42
  Sparkline: () => Sparkline,
43
+ Spinner: () => ServerSpinner,
43
44
  Stat: () => ServerStat,
44
45
  StatusPill: () => ServerStatusPill,
45
46
  StatusTile: () => ServerStatusTile,
@@ -346,6 +347,7 @@ var th = {
346
347
  statusUnknown: "\u0E22\u0E31\u0E07\u0E44\u0E21\u0E48\u0E21\u0E35\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25",
347
348
  opensInNewTab: "\u0E40\u0E1B\u0E34\u0E14\u0E43\u0E19\u0E41\u0E17\u0E47\u0E1A\u0E43\u0E2B\u0E21\u0E48",
348
349
  required: "\u0E08\u0E33\u0E40\u0E1B\u0E47\u0E19",
350
+ firstPage: "\u0E2B\u0E19\u0E49\u0E32\u0E41\u0E23\u0E01",
349
351
  filtersApplied: function(n3) {
350
352
  return "\u0E15\u0E31\u0E27\u0E01\u0E23\u0E2D\u0E07, \u0E43\u0E0A\u0E49\u0E2D\u0E22\u0E39\u0E48 " + n3.toLocaleString("en") + " \u0E23\u0E32\u0E22\u0E01\u0E32\u0E23";
351
353
  },
@@ -488,6 +490,7 @@ var sv = {
488
490
  statusUnknown: "Ingen data",
489
491
  opensInNewTab: "\xF6ppnas i en ny flik",
490
492
  required: "obligatoriskt",
493
+ firstPage: "F\xF6rsta sidan",
491
494
  filtersApplied: function(n3) {
492
495
  return "Filter, " + n3.toLocaleString("sv-SE") + " aktiva";
493
496
  },
@@ -631,6 +634,7 @@ var STRINGS = {
631
634
  statusUnknown: "No data",
632
635
  opensInNewTab: "opens in a new tab",
633
636
  required: "required",
637
+ firstPage: "First page",
634
638
  filtersApplied: function(n3) {
635
639
  return "Filters, " + n3.toLocaleString("en") + " applied";
636
640
  },
@@ -1116,6 +1120,9 @@ var iconNames = Object.keys(map);
1116
1120
 
1117
1121
  // src/icons.ts
1118
1122
  var IconMinus = /* @__PURE__ */ defineIcon("minus", [["path", { d: "M5 12h14" }]]);
1123
+ var IconLoaderCircle = /* @__PURE__ */ defineIcon("loader-circle", [
1124
+ ["path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }]
1125
+ ]);
1119
1126
  var IconCircleAlert = /* @__PURE__ */ defineIcon("circle-alert", [
1120
1127
  ["circle", { cx: "12", cy: "12", r: "10" }],
1121
1128
  ["line", { x1: "12", x2: "12", y1: "8", y2: "12" }],
@@ -1261,7 +1268,7 @@ var PILL_ICON = {
1261
1268
  };
1262
1269
  function statusPillElement(props, ref) {
1263
1270
  const tone2 = props.tone || toneFor(props.children);
1264
- const rest = omit(props, ["tone", "className", "children", "wrap"]);
1271
+ const rest = omit(props, ["tone", "className", "children", "wrap", "busy"]);
1265
1272
  return /* @__PURE__ */ React3.createElement(
1266
1273
  "span",
1267
1274
  {
@@ -1269,10 +1276,26 @@ function statusPillElement(props, ref) {
1269
1276
  ref,
1270
1277
  className: cx("aura-pill", "aura-pill--" + tone2, props.wrap && "is-wrap", props.className)
1271
1278
  },
1272
- /* @__PURE__ */ React3.createElement(Icon, { name: h2(PILL_ICON[tone2] || IconCircle), size: 12 }),
1279
+ props.busy ? /* @__PURE__ */ React3.createElement(Icon, { name: h2(IconLoaderCircle), size: 12, className: "aura-spin" }) : /* @__PURE__ */ React3.createElement(Icon, { name: h2(PILL_ICON[tone2] || IconCircle), size: 12 }),
1273
1280
  props.wrap ? /* @__PURE__ */ React3.createElement("span", { className: "aura-pill__text" }, props.children) : props.children
1274
1281
  );
1275
1282
  }
1283
+ function spinnerElement(props, ref) {
1284
+ const rest = omit(props, ["size", "label", "className"]);
1285
+ const label = props.label;
1286
+ return /* @__PURE__ */ React3.createElement(
1287
+ "span",
1288
+ {
1289
+ ...rest,
1290
+ ref,
1291
+ className: cx("aura-spinner", "aura-spinner--" + (props.size || "md"), props.className),
1292
+ role: label ? "status" : void 0,
1293
+ "aria-hidden": label ? void 0 : true
1294
+ },
1295
+ /* @__PURE__ */ React3.createElement(Icon, { name: h2(IconLoaderCircle), size: props.size || "md", className: "aura-spin" }),
1296
+ label ? /* @__PURE__ */ React3.createElement("span", { className: "aura-sr-only" }, label) : null
1297
+ );
1298
+ }
1276
1299
  function badgeElement(props, ref) {
1277
1300
  const rest = omit(props, ["tone", "variant", "icon", "className", "children"]);
1278
1301
  return /* @__PURE__ */ React3.createElement(
@@ -1433,6 +1456,9 @@ function ServerCard(props) {
1433
1456
  function ServerStatusPill(props) {
1434
1457
  return statusPillElement(props, void 0);
1435
1458
  }
1459
+ function ServerSpinner(props) {
1460
+ return spinnerElement(props, void 0);
1461
+ }
1436
1462
  function ServerBadge(props) {
1437
1463
  return badgeElement(props, void 0);
1438
1464
  }
@@ -51,10 +51,24 @@ export interface StatusPillProps extends Omit<React$1.HTMLAttributes<HTMLSpanEle
51
51
  /** 5.51 (Chamber-OS 158): in a box narrower than the words, the text wraps inside the pill (still rounded, the icon
52
52
  * on the first line) instead of running out of it. Without it a pill stays on one line. */
53
53
  wrap?: boolean | undefined;
54
+ /** 5.70 (Chamber-OS 189): the spinner in the icon slot, for a state still in progress ("Waiting for payment").
55
+ * The words still say it; the tone is unchanged. */
56
+ busy?: boolean | undefined;
54
57
  /** Force a tone. Default: matched from the word (Ready/Done → ready, In Progress/In Review → progress, Warning/Problem/Degraded/At risk → warning (5.1), Blocked/Failed → blocked, anything else → neutral). */
55
58
  tone?: StatusTone | undefined;
56
59
  className?: string | undefined;
57
60
  }
61
+ /** 5.70 (Chamber-OS 189): Button's loading spinner on its own, for "working" outside a button. */
62
+ export interface SpinnerProps extends Omit<React$1.HTMLAttributes<HTMLSpanElement>, "children"> {
63
+ /** `sm` 16px (Button's spinner) · `md` 20px (default) · `lg` 24px — the icon sizes. It takes the text colour. */
64
+ size?: "sm" | "md" | "lg" | undefined;
65
+ /** Without it the spinner is `aria-hidden`: the text beside it, or your live region, says what is happening. With it
66
+ * the spinner is `role="status"` with this text (visually hidden), for a spinner standing alone: it names it for
67
+ * browse mode, but a status inserted with its text already in it is often not announced — to announce the change,
68
+ * keep a live region on the page and put the words in it. */
69
+ label?: string | undefined;
70
+ className?: string | undefined;
71
+ }
58
72
  export type FeedbackTone = "info" | "success" | "warning" | "danger";
59
73
  export interface AlertProps extends Omit<React$1.HTMLAttributes<HTMLDivElement>, "title" | "role"> {
60
74
  tone?: FeedbackTone | undefined;
@@ -434,6 +448,8 @@ export interface AuraStrings {
434
448
  opensInNewTab: string;
435
449
  /** 5.67: read after a CheckboxGroup's legend when `required` (its `*` is hidden from screen readers). */
436
450
  required: string;
451
+ /** 5.70: a cursor Pagination's link back to the start. */
452
+ firstPage: string;
437
453
  /** 5.42: FilterBar's collapsed-filters button, read with its count ("Filters, 2 applied"). */
438
454
  filtersApplied: (n: number) => string;
439
455
  /** 5.42: closes FilterBar's "Filters" sheet. */
@@ -515,6 +531,7 @@ export declare function linkClass(opts?: {
515
531
  declare function ServerAlert(props: Omit<AlertProps, "onDismiss">): React$1.ReactElement;
516
532
  declare function ServerCard(props: CardProps): React$1.ReactElement;
517
533
  declare function ServerStatusPill(props: StatusPillProps): React$1.ReactElement;
534
+ declare function ServerSpinner(props: SpinnerProps): React$1.ReactElement;
518
535
  declare function ServerBadge(props: BadgeProps): React$1.ReactElement;
519
536
  declare function ServerEmptyState(props: EmptyStateProps): React$1.ReactElement;
520
537
  /** Stat for Server Components (5.14): no `onClick` (a button needs the client); `href` renders `linkComponent`, else `<a>`. */
@@ -637,6 +654,7 @@ export {
637
654
  ServerBadge as Badge,
638
655
  ServerCard as Card,
639
656
  ServerEmptyState as EmptyState,
657
+ ServerSpinner as Spinner,
640
658
  ServerStat as Stat,
641
659
  ServerStatusPill as StatusPill,
642
660
  ServerStatusTile as StatusTile,
@@ -51,10 +51,24 @@ export interface StatusPillProps extends Omit<React$1.HTMLAttributes<HTMLSpanEle
51
51
  /** 5.51 (Chamber-OS 158): in a box narrower than the words, the text wraps inside the pill (still rounded, the icon
52
52
  * on the first line) instead of running out of it. Without it a pill stays on one line. */
53
53
  wrap?: boolean | undefined;
54
+ /** 5.70 (Chamber-OS 189): the spinner in the icon slot, for a state still in progress ("Waiting for payment").
55
+ * The words still say it; the tone is unchanged. */
56
+ busy?: boolean | undefined;
54
57
  /** Force a tone. Default: matched from the word (Ready/Done → ready, In Progress/In Review → progress, Warning/Problem/Degraded/At risk → warning (5.1), Blocked/Failed → blocked, anything else → neutral). */
55
58
  tone?: StatusTone | undefined;
56
59
  className?: string | undefined;
57
60
  }
61
+ /** 5.70 (Chamber-OS 189): Button's loading spinner on its own, for "working" outside a button. */
62
+ export interface SpinnerProps extends Omit<React$1.HTMLAttributes<HTMLSpanElement>, "children"> {
63
+ /** `sm` 16px (Button's spinner) · `md` 20px (default) · `lg` 24px — the icon sizes. It takes the text colour. */
64
+ size?: "sm" | "md" | "lg" | undefined;
65
+ /** Without it the spinner is `aria-hidden`: the text beside it, or your live region, says what is happening. With it
66
+ * the spinner is `role="status"` with this text (visually hidden), for a spinner standing alone: it names it for
67
+ * browse mode, but a status inserted with its text already in it is often not announced — to announce the change,
68
+ * keep a live region on the page and put the words in it. */
69
+ label?: string | undefined;
70
+ className?: string | undefined;
71
+ }
58
72
  export type FeedbackTone = "info" | "success" | "warning" | "danger";
59
73
  export interface AlertProps extends Omit<React$1.HTMLAttributes<HTMLDivElement>, "title" | "role"> {
60
74
  tone?: FeedbackTone | undefined;
@@ -434,6 +448,8 @@ export interface AuraStrings {
434
448
  opensInNewTab: string;
435
449
  /** 5.67: read after a CheckboxGroup's legend when `required` (its `*` is hidden from screen readers). */
436
450
  required: string;
451
+ /** 5.70: a cursor Pagination's link back to the start. */
452
+ firstPage: string;
437
453
  /** 5.42: FilterBar's collapsed-filters button, read with its count ("Filters, 2 applied"). */
438
454
  filtersApplied: (n: number) => string;
439
455
  /** 5.42: closes FilterBar's "Filters" sheet. */
@@ -515,6 +531,7 @@ export declare function linkClass(opts?: {
515
531
  declare function ServerAlert(props: Omit<AlertProps, "onDismiss">): React$1.ReactElement;
516
532
  declare function ServerCard(props: CardProps): React$1.ReactElement;
517
533
  declare function ServerStatusPill(props: StatusPillProps): React$1.ReactElement;
534
+ declare function ServerSpinner(props: SpinnerProps): React$1.ReactElement;
518
535
  declare function ServerBadge(props: BadgeProps): React$1.ReactElement;
519
536
  declare function ServerEmptyState(props: EmptyStateProps): React$1.ReactElement;
520
537
  /** Stat for Server Components (5.14): no `onClick` (a button needs the client); `href` renders `linkComponent`, else `<a>`. */
@@ -637,6 +654,7 @@ export {
637
654
  ServerBadge as Badge,
638
655
  ServerCard as Card,
639
656
  ServerEmptyState as EmptyState,
657
+ ServerSpinner as Spinner,
640
658
  ServerStat as Stat,
641
659
  ServerStatusPill as StatusPill,
642
660
  ServerStatusTile as StatusTile,
@@ -280,6 +280,7 @@ var th = {
280
280
  statusUnknown: "\u0E22\u0E31\u0E07\u0E44\u0E21\u0E48\u0E21\u0E35\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25",
281
281
  opensInNewTab: "\u0E40\u0E1B\u0E34\u0E14\u0E43\u0E19\u0E41\u0E17\u0E47\u0E1A\u0E43\u0E2B\u0E21\u0E48",
282
282
  required: "\u0E08\u0E33\u0E40\u0E1B\u0E47\u0E19",
283
+ firstPage: "\u0E2B\u0E19\u0E49\u0E32\u0E41\u0E23\u0E01",
283
284
  filtersApplied: function(n3) {
284
285
  return "\u0E15\u0E31\u0E27\u0E01\u0E23\u0E2D\u0E07, \u0E43\u0E0A\u0E49\u0E2D\u0E22\u0E39\u0E48 " + n3.toLocaleString("en") + " \u0E23\u0E32\u0E22\u0E01\u0E32\u0E23";
285
286
  },
@@ -422,6 +423,7 @@ var sv = {
422
423
  statusUnknown: "Ingen data",
423
424
  opensInNewTab: "\xF6ppnas i en ny flik",
424
425
  required: "obligatoriskt",
426
+ firstPage: "F\xF6rsta sidan",
425
427
  filtersApplied: function(n3) {
426
428
  return "Filter, " + n3.toLocaleString("sv-SE") + " aktiva";
427
429
  },
@@ -565,6 +567,7 @@ var STRINGS = {
565
567
  statusUnknown: "No data",
566
568
  opensInNewTab: "opens in a new tab",
567
569
  required: "required",
570
+ firstPage: "First page",
568
571
  filtersApplied: function(n3) {
569
572
  return "Filters, " + n3.toLocaleString("en") + " applied";
570
573
  },
@@ -1050,6 +1053,9 @@ var iconNames = Object.keys(map);
1050
1053
 
1051
1054
  // src/icons.ts
1052
1055
  var IconMinus = /* @__PURE__ */ defineIcon("minus", [["path", { d: "M5 12h14" }]]);
1056
+ var IconLoaderCircle = /* @__PURE__ */ defineIcon("loader-circle", [
1057
+ ["path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }]
1058
+ ]);
1053
1059
  var IconCircleAlert = /* @__PURE__ */ defineIcon("circle-alert", [
1054
1060
  ["circle", { cx: "12", cy: "12", r: "10" }],
1055
1061
  ["line", { x1: "12", x2: "12", y1: "8", y2: "12" }],
@@ -1195,7 +1201,7 @@ var PILL_ICON = {
1195
1201
  };
1196
1202
  function statusPillElement(props, ref) {
1197
1203
  const tone2 = props.tone || toneFor(props.children);
1198
- const rest = omit(props, ["tone", "className", "children", "wrap"]);
1204
+ const rest = omit(props, ["tone", "className", "children", "wrap", "busy"]);
1199
1205
  return /* @__PURE__ */ React3.createElement(
1200
1206
  "span",
1201
1207
  {
@@ -1203,10 +1209,26 @@ function statusPillElement(props, ref) {
1203
1209
  ref,
1204
1210
  className: cx("aura-pill", "aura-pill--" + tone2, props.wrap && "is-wrap", props.className)
1205
1211
  },
1206
- /* @__PURE__ */ React3.createElement(Icon, { name: h2(PILL_ICON[tone2] || IconCircle), size: 12 }),
1212
+ props.busy ? /* @__PURE__ */ React3.createElement(Icon, { name: h2(IconLoaderCircle), size: 12, className: "aura-spin" }) : /* @__PURE__ */ React3.createElement(Icon, { name: h2(PILL_ICON[tone2] || IconCircle), size: 12 }),
1207
1213
  props.wrap ? /* @__PURE__ */ React3.createElement("span", { className: "aura-pill__text" }, props.children) : props.children
1208
1214
  );
1209
1215
  }
1216
+ function spinnerElement(props, ref) {
1217
+ const rest = omit(props, ["size", "label", "className"]);
1218
+ const label = props.label;
1219
+ return /* @__PURE__ */ React3.createElement(
1220
+ "span",
1221
+ {
1222
+ ...rest,
1223
+ ref,
1224
+ className: cx("aura-spinner", "aura-spinner--" + (props.size || "md"), props.className),
1225
+ role: label ? "status" : void 0,
1226
+ "aria-hidden": label ? void 0 : true
1227
+ },
1228
+ /* @__PURE__ */ React3.createElement(Icon, { name: h2(IconLoaderCircle), size: props.size || "md", className: "aura-spin" }),
1229
+ label ? /* @__PURE__ */ React3.createElement("span", { className: "aura-sr-only" }, label) : null
1230
+ );
1231
+ }
1210
1232
  function badgeElement(props, ref) {
1211
1233
  const rest = omit(props, ["tone", "variant", "icon", "className", "children"]);
1212
1234
  return /* @__PURE__ */ React3.createElement(
@@ -1367,6 +1389,9 @@ function ServerCard(props) {
1367
1389
  function ServerStatusPill(props) {
1368
1390
  return statusPillElement(props, void 0);
1369
1391
  }
1392
+ function ServerSpinner(props) {
1393
+ return spinnerElement(props, void 0);
1394
+ }
1370
1395
  function ServerBadge(props) {
1371
1396
  return badgeElement(props, void 0);
1372
1397
  }
@@ -1884,6 +1909,7 @@ export {
1884
1909
  PageHeader,
1885
1910
  STRINGS,
1886
1911
  Sparkline,
1912
+ ServerSpinner as Spinner,
1887
1913
  ServerStat as Stat,
1888
1914
  ServerStatusPill as StatusPill,
1889
1915
  ServerStatusTile as StatusTile,
package/dist/styles.css CHANGED
@@ -251,6 +251,12 @@ button.aura-btn--creative[aria-disabled='true']:hover { box-shadow: var(--aura-s
251
251
  transition: color var(--aura-duration-fast) var(--aura-ease);
252
252
  }
253
253
  .aura-table__sort:hover, .aura-table__sort.is-active { color: var(--aura-fg-primary); }
254
+ /* 5.70 (Chamber-OS 188): the same control in a plain Table's Th — a button or a link, with its own focus ring (a
255
+ * DataTable header ring is on the cell, which roves). */
256
+ a.aura-table__sort { text-decoration: none; }
257
+ .aura-tbl__th .aura-table__sort { white-space: normal; text-align: inherit; }
258
+ .aura-tbl__th .aura-table__sort:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: var(--aura-focus-ring-offset); }
259
+ .aura-tbl__th.is-end .aura-table__sort { flex-direction: row-reverse; }
254
260
 
255
261
  /* Column menu trigger — shows on header hover or focus */
256
262
  .aura-table__menu-btn {
@@ -363,6 +369,9 @@ a.aura-icon-btn { text-decoration: none; }
363
369
  .aura-icon-btn--outline { box-sizing: border-box; border: 1px solid var(--aura-button-secondary-border); } /* 5.44 (Chamber-OS 149): reads as a button beside outlined ones */
364
370
  .aura-icon-btn--danger:hover { background: var(--aura-alert-danger-bg); }
365
371
  .aura-icon-btn:disabled { opacity: var(--aura-disabled-opacity); pointer-events: none; }
372
+ /* 5.70 (Chamber-OS 186): aria-disabled keeps it focusable (a cooldown); it looks unavailable and hover changes nothing. */
373
+ .aura-icon-btn[aria-disabled="true"] { opacity: var(--aura-disabled-opacity); cursor: not-allowed; }
374
+ .aura-icon-btn[aria-disabled="true"]:hover { background: transparent; }
366
375
  /* 5.65 (Chamber-OS 180): a toggle (aria-pressed="true", or the pressed prop) looks on — the selected fill and the
367
376
  * accent icon — and hover still shows on top of it (an accent hairline inside). Outline toggles take an accent border.
368
377
  * The focus ring is unchanged. Not inside a field: PasswordField's reveal eye (aria-pressed) stays quiet (5.30 #14).
@@ -482,6 +491,8 @@ a.aura-icon-btn { text-decoration: none; }
482
491
  /* Loading spinner */
483
492
  @keyframes aura-spin { to { transform: rotate(360deg); } }
484
493
  .aura-spin { animation: aura-spin var(--aura-duration-spin) linear infinite; }
494
+ /* 5.70 (Chamber-OS 189): Spinner — the same glyph and spin, inline with the text. */
495
+ .aura-spinner { display: inline-flex; flex: none; vertical-align: middle; color: inherit; line-height: 0; }
485
496
  @media (prefers-reduced-motion: reduce) {
486
497
  .aura-spin { animation-duration: calc(var(--aura-duration-spin) * 3); }
487
498
  }
@@ -1513,6 +1524,10 @@ button.aura-stat { font: inherit; width: 100%; cursor: pointer; }
1513
1524
  .aura-time__option { min-height: 36px; font-variant-numeric: tabular-nums; }
1514
1525
 
1515
1526
  /* ---------- FileUpload ---------- */
1527
+ /* 5.70 (Chamber-OS 190): FileUpload variant="button" — the Button, the accepted types and size beside it (wrapping
1528
+ * under on a narrow field), an optional Progress under them. */
1529
+ .aura-upload-button { position: relative; display: flex; flex-wrap: wrap; align-items: center; gap: var(--aura-space-2) var(--aura-space-3); }
1530
+ .aura-upload-button > .aura-upload__note { flex-basis: auto; font-size: max(12px, .75rem); color: var(--aura-fg-secondary); }
1516
1531
  .aura-upload {
1517
1532
  position: relative; box-sizing: border-box; display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: var(--aura-space-2);
1518
1533
  min-height: 96px; padding: var(--aura-space-5); text-align: center; cursor: pointer;
@@ -1649,6 +1664,14 @@ a.aura-upload__name:focus-visible { outline: var(--aura-focus-ring-width) solid
1649
1664
  .aura-page:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: var(--aura-focus-ring-offset); }
1650
1665
  .aura-pagination__gap { min-width: 24px; text-align: center; color: var(--aura-fg-secondary); }
1651
1666
  .aura-pagination__compact { display: none; padding: 0 var(--aura-space-2); color: var(--aura-fg-secondary); font-variant-numeric: tabular-nums; }
1667
+ /* 5.70 (Chamber-OS 187): cursor mode — a status line at the start, First / Previous / Next at the end, each an
1668
+ * .aura-page with text (44px on touch, as the numbers); a disabled end is dimmed and takes no clicks. */
1669
+ .aura-pagination--cursor { flex-wrap: wrap; justify-content: flex-end; gap: var(--aura-space-1) var(--aura-space-3); }
1670
+ .aura-pagination__status { flex: 1 1 auto; min-width: 0; color: var(--aura-fg-secondary); font-variant-numeric: tabular-nums; }
1671
+ .aura-pagination__steps { display: flex; flex-wrap: wrap; align-items: center; gap: 2px; margin-inline-start: auto; }
1672
+ .aura-page--step { gap: var(--aura-space-1); padding: 0 var(--aura-space-3); white-space: nowrap; }
1673
+ .aura-page--step:is(:disabled, [aria-disabled="true"]) { opacity: var(--aura-disabled-opacity); cursor: not-allowed; }
1674
+ .aura-page--step:is(:disabled, [aria-disabled="true"]):hover { background: transparent; }
1652
1675
  @media (max-width: 639.98px) {
1653
1676
  .aura-pagination__list { display: none; }
1654
1677
  .aura-pagination__compact { display: inline; }
@@ -253,6 +253,12 @@ button.aura-btn--creative[aria-disabled='true']:hover { box-shadow: var(--aura-s
253
253
  transition: color var(--aura-duration-fast) var(--aura-ease);
254
254
  }
255
255
  .aura-table__sort:hover, .aura-table__sort.is-active { color: var(--aura-fg-primary); }
256
+ /* 5.70 (Chamber-OS 188): the same control in a plain Table's Th — a button or a link, with its own focus ring (a
257
+ * DataTable header ring is on the cell, which roves). */
258
+ a.aura-table__sort { text-decoration: none; }
259
+ .aura-tbl__th .aura-table__sort { white-space: normal; text-align: inherit; }
260
+ .aura-tbl__th .aura-table__sort:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: var(--aura-focus-ring-offset); }
261
+ .aura-tbl__th.is-end .aura-table__sort { flex-direction: row-reverse; }
256
262
 
257
263
  /* Column menu trigger — shows on header hover or focus */
258
264
  .aura-table__menu-btn {
@@ -365,6 +371,9 @@ a.aura-icon-btn { text-decoration: none; }
365
371
  .aura-icon-btn--outline { box-sizing: border-box; border: 1px solid var(--aura-button-secondary-border); } /* 5.44 (Chamber-OS 149): reads as a button beside outlined ones */
366
372
  .aura-icon-btn--danger:hover { background: var(--aura-alert-danger-bg); }
367
373
  .aura-icon-btn:disabled { opacity: var(--aura-disabled-opacity); pointer-events: none; }
374
+ /* 5.70 (Chamber-OS 186): aria-disabled keeps it focusable (a cooldown); it looks unavailable and hover changes nothing. */
375
+ .aura-icon-btn[aria-disabled="true"] { opacity: var(--aura-disabled-opacity); cursor: not-allowed; }
376
+ .aura-icon-btn[aria-disabled="true"]:hover { background: transparent; }
368
377
  /* 5.65 (Chamber-OS 180): a toggle (aria-pressed="true", or the pressed prop) looks on — the selected fill and the
369
378
  * accent icon — and hover still shows on top of it (an accent hairline inside). Outline toggles take an accent border.
370
379
  * The focus ring is unchanged. Not inside a field: PasswordField's reveal eye (aria-pressed) stays quiet (5.30 #14).
@@ -484,6 +493,8 @@ a.aura-icon-btn { text-decoration: none; }
484
493
  /* Loading spinner */
485
494
  @keyframes aura-spin { to { transform: rotate(360deg); } }
486
495
  .aura-spin { animation: aura-spin var(--aura-duration-spin) linear infinite; }
496
+ /* 5.70 (Chamber-OS 189): Spinner — the same glyph and spin, inline with the text. */
497
+ .aura-spinner { display: inline-flex; flex: none; vertical-align: middle; color: inherit; line-height: 0; }
487
498
  @media (prefers-reduced-motion: reduce) {
488
499
  .aura-spin { animation-duration: calc(var(--aura-duration-spin) * 3); }
489
500
  }
@@ -1515,6 +1526,10 @@ button.aura-stat { font: inherit; width: 100%; cursor: pointer; }
1515
1526
  .aura-time__option { min-height: 36px; font-variant-numeric: tabular-nums; }
1516
1527
 
1517
1528
  /* ---------- FileUpload ---------- */
1529
+ /* 5.70 (Chamber-OS 190): FileUpload variant="button" — the Button, the accepted types and size beside it (wrapping
1530
+ * under on a narrow field), an optional Progress under them. */
1531
+ .aura-upload-button { position: relative; display: flex; flex-wrap: wrap; align-items: center; gap: var(--aura-space-2) var(--aura-space-3); }
1532
+ .aura-upload-button > .aura-upload__note { flex-basis: auto; font-size: max(12px, .75rem); color: var(--aura-fg-secondary); }
1518
1533
  .aura-upload {
1519
1534
  position: relative; box-sizing: border-box; display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: var(--aura-space-2);
1520
1535
  min-height: 96px; padding: var(--aura-space-5); text-align: center; cursor: pointer;
@@ -1651,6 +1666,14 @@ a.aura-upload__name:focus-visible { outline: var(--aura-focus-ring-width) solid
1651
1666
  .aura-page:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: var(--aura-focus-ring-offset); }
1652
1667
  .aura-pagination__gap { min-width: 24px; text-align: center; color: var(--aura-fg-secondary); }
1653
1668
  .aura-pagination__compact { display: none; padding: 0 var(--aura-space-2); color: var(--aura-fg-secondary); font-variant-numeric: tabular-nums; }
1669
+ /* 5.70 (Chamber-OS 187): cursor mode — a status line at the start, First / Previous / Next at the end, each an
1670
+ * .aura-page with text (44px on touch, as the numbers); a disabled end is dimmed and takes no clicks. */
1671
+ .aura-pagination--cursor { flex-wrap: wrap; justify-content: flex-end; gap: var(--aura-space-1) var(--aura-space-3); }
1672
+ .aura-pagination__status { flex: 1 1 auto; min-width: 0; color: var(--aura-fg-secondary); font-variant-numeric: tabular-nums; }
1673
+ .aura-pagination__steps { display: flex; flex-wrap: wrap; align-items: center; gap: 2px; margin-inline-start: auto; }
1674
+ .aura-page--step { gap: var(--aura-space-1); padding: 0 var(--aura-space-3); white-space: nowrap; }
1675
+ .aura-page--step:is(:disabled, [aria-disabled="true"]) { opacity: var(--aura-disabled-opacity); cursor: not-allowed; }
1676
+ .aura-page--step:is(:disabled, [aria-disabled="true"]):hover { background: transparent; }
1654
1677
  @media (max-width: 639.98px) {
1655
1678
  .aura-pagination__list { display: none; }
1656
1679
  .aura-pagination__compact { display: inline; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jirawatpyk/aura-react",
3
- "version": "5.69.0",
3
+ "version": "5.70.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",