@jirawatpyk/aura-react 5.69.0 → 5.71.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.
@@ -8,6 +8,8 @@ import { IconLoaderCircle } from "./icons.js";
8
8
  function ButtonLink(props, ref, Link) {
9
9
  const variant = props.variant || "primary";
10
10
  const disabled = !!props.disabled;
11
+ const ad = props["aria-disabled"];
12
+ const gated = !disabled && (ad === true || ad === "true");
11
13
  const rest = omit(props, [
12
14
  "variant",
13
15
  "className",
@@ -29,7 +31,7 @@ function ButtonLink(props, ref, Link) {
29
31
  ref,
30
32
  href: disabled ? void 0 : props.href,
31
33
  role: disabled ? "link" : void 0,
32
- "aria-disabled": disabled || void 0,
34
+ "aria-disabled": disabled || gated || void 0,
33
35
  tabIndex: disabled ? -1 : props.tabIndex,
34
36
  className: buttonClass({
35
37
  variant,
@@ -38,7 +40,9 @@ function ButtonLink(props, ref, Link) {
38
40
  touchHeight: props.touchHeight,
39
41
  className: props.className
40
42
  }),
41
- onClick: disabled ? void 0 : props.onClick
43
+ onClick: disabled ? void 0 : gated ? function(e) {
44
+ e.preventDefault();
45
+ } : props.onClick
42
46
  },
43
47
  props.icon ? /* @__PURE__ */ React.createElement(Icon, { name: props.icon }) : null,
44
48
  props.children,
@@ -56,6 +60,8 @@ const Button = React.forwardRef(
56
60
  const loading = !!props.loading;
57
61
  const ad = props["aria-disabled"];
58
62
  const blocked = loading || ad === true || ad === "true";
63
+ const ab = props["aria-busy"];
64
+ const busy = loading || ab === true || ab === "true";
59
65
  const rest = omit(props, [
60
66
  "variant",
61
67
  "className",
@@ -83,7 +89,7 @@ const Button = React.forwardRef(
83
89
  loading,
84
90
  className: props.className
85
91
  }),
86
- "aria-busy": loading || void 0,
92
+ "aria-busy": busy || void 0,
87
93
  "aria-disabled": blocked || void 0,
88
94
  onClick: blocked ? function(e) {
89
95
  e.preventDefault();
@@ -5,8 +5,10 @@ import { useStrings } from "./locale.js";
5
5
  import { Icon } from "./Icon.js";
6
6
  import { IconButton } from "./IconButton.js";
7
7
  import { Field } from "./Field.js";
8
+ import { Button } from "./Button.js";
9
+ import { Progress } from "./Progress.js";
8
10
  import { formatBytes } from "./text.js";
9
- import { IconCircleAlert, IconCircleCheck, IconCloudUpload, IconFile, IconImage, IconX } from "./icons.js";
11
+ import { IconCircleAlert, IconCircleCheck, IconCloudUpload, IconFile, IconImage, IconUpload, IconX } from "./icons.js";
10
12
  function matches(file, accept) {
11
13
  if (!accept) return true;
12
14
  const name = (file.name || "").toLowerCase(), type = (file.type || "").toLowerCase();
@@ -40,6 +42,22 @@ const FileUpload = React.forwardRef(function FileUpload2(props, ref) {
40
42
  const urls = React.useRef({});
41
43
  const maxFiles = props.multiple ? props.maxFiles : 1;
42
44
  const note = t.accepts(describeAccept(props.accept, t), props.maxSize ? formatBytes(props.maxSize) : "");
45
+ const pickState = React.useState(null);
46
+ const buttonRef = React.useRef(null);
47
+ const buttonMode = props.variant === "button";
48
+ React.useEffect(
49
+ function() {
50
+ const el = inputRef.current;
51
+ if (!buttonMode || !el) return;
52
+ el.focus = function(o) {
53
+ if (buttonRef.current) buttonRef.current.focus(o);
54
+ };
55
+ return function() {
56
+ delete el.focus;
57
+ };
58
+ },
59
+ [buttonMode]
60
+ );
43
61
  React.useEffect(function() {
44
62
  return function() {
45
63
  Object.keys(urls.current).forEach(function(k) {
@@ -107,6 +125,95 @@ const FileUpload = React.forwardRef(function FileUpload2(props, ref) {
107
125
  if (inputRef.current) inputRef.current.focus();
108
126
  }
109
127
  const error = props.error;
128
+ if (props.variant === "button") {
129
+ const err = error || pickState[0];
130
+ const desc = [err ? id + "-error" : props.hint ? id + "-hint" : null, note ? id + "-note" : null].filter(Boolean).join(" ") || void 0;
131
+ return /* @__PURE__ */ React.createElement(
132
+ Field,
133
+ {
134
+ id,
135
+ label: props.label,
136
+ labelAs: "span",
137
+ labelId: id + "-label",
138
+ hint: props.hint,
139
+ error: err,
140
+ required: props.required,
141
+ optional: props.optional,
142
+ disabled: props.disabled,
143
+ className: cx("aura-upload-field", props.className)
144
+ },
145
+ /* @__PURE__ */ React.createElement("div", { className: "aura-upload-button" }, /* @__PURE__ */ React.createElement(
146
+ Button,
147
+ {
148
+ ref: buttonRef,
149
+ id: id + "-button",
150
+ variant: "secondary",
151
+ icon: /* @__PURE__ */ React.createElement(IconUpload, null),
152
+ touchHeight: props.touchHeight,
153
+ disabled: props.disabled,
154
+ "aria-labelledby": props.label ? id + "-label " + id + "-button" : void 0,
155
+ "aria-describedby": desc,
156
+ onClick: function() {
157
+ if (inputRef.current) inputRef.current.click();
158
+ }
159
+ },
160
+ props.buttonLabel != null ? props.buttonLabel : props.multiple ? t.browse : t.browseOne
161
+ ), /* @__PURE__ */ React.createElement(
162
+ "input",
163
+ {
164
+ ref: inputMerged,
165
+ id,
166
+ type: "file",
167
+ className: "aura-upload__input",
168
+ tabIndex: -1,
169
+ "aria-hidden": true,
170
+ accept: props.accept,
171
+ multiple: !!props.multiple,
172
+ disabled: props.disabled,
173
+ name: props.name,
174
+ required: props.name ? props.required : void 0,
175
+ onInvalid: function(e) {
176
+ e.preventDefault();
177
+ pickState[1](props.multiple ? t.browse : t.browseOne);
178
+ if (buttonRef.current) buttonRef.current.focus();
179
+ },
180
+ onChange: function(e) {
181
+ const files = Array.prototype.slice.call(e.target.files || []);
182
+ if (!files.length) return;
183
+ let refused = null;
184
+ const ok = files.filter(function(f) {
185
+ const why = !matches(f, props.accept) ? t.fileWrongType : props.maxSize && f.size > props.maxSize ? t.fileTooBig(formatBytes(props.maxSize)) : null;
186
+ if (why && !refused) refused = why;
187
+ return !why;
188
+ });
189
+ pickState[1](refused);
190
+ if (!props.name) e.target.value = "";
191
+ else if (refused) {
192
+ try {
193
+ const dt = new DataTransfer();
194
+ ok.forEach(function(f) {
195
+ dt.items.add(f);
196
+ });
197
+ e.target.files = dt.files;
198
+ } catch (x) {
199
+ e.target.value = "";
200
+ }
201
+ }
202
+ if (ok.length && props.onSelect) props.onSelect(ok);
203
+ }
204
+ }
205
+ ), note ? /* @__PURE__ */ React.createElement("span", { className: "aura-upload__note", id: id + "-note" }, note) : null),
206
+ props.progress !== void 0 ? /* @__PURE__ */ React.createElement(
207
+ Progress,
208
+ {
209
+ className: "aura-upload-button__progress",
210
+ size: "sm",
211
+ value: props.progress == null ? void 0 : props.progress,
212
+ label: t.uploading
213
+ }
214
+ ) : null
215
+ );
216
+ }
110
217
  return /* @__PURE__ */ React.createElement(
111
218
  Field,
112
219
  {
@@ -7,6 +7,8 @@ const IconButton = React.forwardRef(function IconButton2(props, ref) {
7
7
  const rest = omit(props, ["icon", "label", "className", "size", "tone", "touchHeight", "variant", "pressed"]);
8
8
  useAutoTip();
9
9
  const own = props.title !== void 0;
10
+ const ad = props["aria-disabled"];
11
+ const blocked = ad === true || ad === "true";
10
12
  return /* @__PURE__ */ React.createElement(
11
13
  "button",
12
14
  {
@@ -16,6 +18,9 @@ const IconButton = React.forwardRef(function IconButton2(props, ref) {
16
18
  "aria-label": props.label,
17
19
  "aria-pressed": props.pressed != null ? props.pressed : props["aria-pressed"],
18
20
  "data-aura-tip": own ? void 0 : props.label,
21
+ onClick: blocked ? function(e) {
22
+ e.preventDefault();
23
+ } : props.onClick,
19
24
  className: cx(
20
25
  "aura-icon-btn",
21
26
  props.tone === "danger" && "aura-icon-btn--danger",
@@ -57,7 +57,10 @@ const PageHeader = React.forwardRef(function PageHeader2(props, ref) {
57
57
  props.title
58
58
  );
59
59
  const hasActions = props.actions != null && props.actions !== false;
60
- const bar = hasActions && (props.actionsBarBelow === "sm" || props.actionsBarBelow === "md") ? props.actionsBarBelow : null;
60
+ const hasBarActions = props.actionsBar != null && props.actionsBar !== false;
61
+ const bar = (hasActions || hasBarActions) && (props.actionsBarBelow === "sm" || props.actionsBarBelow === "md") ? props.actionsBarBelow : null;
62
+ const split = !!bar && hasBarActions;
63
+ const status = bar && props.actionsStatus != null && props.actionsStatus !== false ? h("div", { className: "aura-page-header__status", role: "status" }, props.actionsStatus) : null;
61
64
  return h(
62
65
  "div",
63
66
  Object.assign(attrs, {
@@ -89,12 +92,12 @@ const PageHeader = React.forwardRef(function PageHeader2(props, ref) {
89
92
  shown(props.subtitle) ? h("div", { className: "aura-page-header__subtitle" }, props.subtitle) : null,
90
93
  props.meta != null && props.meta !== false ? h("div", { className: cx("aura-page-header__meta", richMeta && "aura-page-header__meta--rich") }, props.meta) : null
91
94
  ),
92
- props.actions != null && props.actions !== false ? h(
95
+ hasActions || hasBarActions ? split ? h(
93
96
  "div",
94
- { className: "aura-page-header__actions" },
95
- bar && props.actionsStatus != null && props.actionsStatus !== false ? h("div", { className: "aura-page-header__status", role: "status" }, props.actionsStatus) : null,
96
- props.actions
97
- ) : null
97
+ { className: "aura-page-header__actions is-split" },
98
+ props.actions,
99
+ h("div", { className: "aura-page-header__bar" }, status, props.actionsBar)
100
+ ) : h("div", { className: "aura-page-header__actions" }, status, props.actions, props.actionsBar) : null
98
101
  );
99
102
  });
100
103
  export {
@@ -8,11 +8,14 @@ const PageHeader = React.forwardRef(function PageHeader2(props, ref) {
8
8
  const own = React.useRef(null);
9
9
  const merged = useMergedRef(ref, own);
10
10
  const bar = props.actionsBarBelow;
11
- const hasActions = props.actions != null && props.actions !== false;
11
+ const hasActions = props.actions != null && props.actions !== false || props.actionsBar != null && props.actionsBar !== false;
12
+ const split = props.actionsBar != null && props.actionsBar !== false;
12
13
  React.useEffect(
13
14
  function() {
14
15
  if (bar !== "sm" && bar !== "md" || !hasActions || !own.current) return;
15
- const el = own.current.querySelector(":scope > .aura-page-header__actions");
16
+ const el = own.current.querySelector(
17
+ split ? ":scope > .aura-page-header__actions > .aura-page-header__bar" : ":scope > .aura-page-header__actions"
18
+ );
16
19
  if (!el) return;
17
20
  const root = document.documentElement;
18
21
  let checked = false;
@@ -45,7 +48,7 @@ const PageHeader = React.forwardRef(function PageHeader2(props, ref) {
45
48
  else root.style.removeProperty(NAME);
46
49
  };
47
50
  },
48
- [bar, hasActions]
51
+ [bar, hasActions, split]
49
52
  );
50
53
  const focusTitle = !!props.focusTitleOnMount;
51
54
  React.useEffect(function() {
@@ -25,9 +25,56 @@ function pageList(page, count, sib) {
25
25
  if (count > 1) out.push(count);
26
26
  return out;
27
27
  }
28
- const Pagination = React.forwardRef(function Pagination2(props, ref) {
28
+ function cursorNav(props, ref, Link, t) {
29
+ const links = props.firstHref != null || props.previousHref != null || props.nextHref != null;
30
+ function step(key, href, on, has, label, rel, icon, after) {
31
+ const body = /* @__PURE__ */ React.createElement(React.Fragment, null, icon && !after ? /* @__PURE__ */ React.createElement(Icon, { name: icon, size: "sm" }) : null, /* @__PURE__ */ React.createElement("span", null, label), icon && after ? /* @__PURE__ */ React.createElement(Icon, { name: icon, size: "sm" }) : null);
32
+ const cls = "aura-page aura-page--step";
33
+ if (has === false || !href && !on)
34
+ return links ? /* @__PURE__ */ React.createElement("span", { key, className: cls, role: "link", "aria-disabled": true }, body) : /* @__PURE__ */ React.createElement("button", { key, type: "button", className: cls, disabled: true }, body);
35
+ if (href != null)
36
+ return /* @__PURE__ */ React.createElement(
37
+ Link,
38
+ {
39
+ key,
40
+ href,
41
+ rel,
42
+ className: cls,
43
+ onClick: function(e) {
44
+ if (on && plainClick(e)) {
45
+ e.preventDefault();
46
+ on();
47
+ }
48
+ }
49
+ },
50
+ body
51
+ );
52
+ return /* @__PURE__ */ React.createElement("button", { key, type: "button", className: cls, onClick: on }, body);
53
+ }
54
+ return /* @__PURE__ */ React.createElement(
55
+ "nav",
56
+ {
57
+ ref,
58
+ className: cx("aura-pagination", "aura-pagination--cursor", props.className),
59
+ "aria-label": props.label || t.pagination
60
+ },
61
+ props.status != null && props.status !== false && props.status !== "" ? /* @__PURE__ */ React.createElement("span", { className: "aura-pagination__status" }, props.status) : null,
62
+ /* @__PURE__ */ React.createElement("span", { className: "aura-pagination__steps" }, props.showFirst === false ? null : step("first", props.firstHref, props.onFirst, props.hasFirst, t.firstPage, void 0, null, false), step(
63
+ "prev",
64
+ props.previousHref,
65
+ props.onPrevious,
66
+ props.hasPrevious,
67
+ t.prevPage,
68
+ "prev",
69
+ /* @__PURE__ */ React.createElement(IconChevronLeft, null),
70
+ false
71
+ ), step("next", props.nextHref, props.onNext, props.hasNext, t.nextPage, "next", /* @__PURE__ */ React.createElement(IconChevronRight, null), true))
72
+ );
73
+ }
74
+ const Pagination = React.forwardRef(function Pagination2(all, ref) {
29
75
  const t = useStrings();
30
76
  useAutoTip();
77
+ const props = all;
31
78
  const count = Math.max(1, props.pageCount || 1);
32
79
  const st = useMaybeControlled(props.page, props.defaultPage || 1, props.onChange);
33
80
  const page = Math.min(count, Math.max(1, st[0]));
@@ -36,6 +83,7 @@ const Pagination = React.forwardRef(function Pagination2(props, ref) {
36
83
  }
37
84
  const link = props.getHref;
38
85
  const Link = useLinkComponent(props.linkComponent);
86
+ if (all.mode === "cursor") return cursorNav(all, ref, Link, t);
39
87
  function item(p, label, extra) {
40
88
  const common = Object.assign(
41
89
  {
@@ -0,0 +1,9 @@
1
+ 'use client';
2
+ import * as React from "react";
3
+ import { spinnerElement } from "./display.js";
4
+ const Spinner = React.forwardRef(function Spinner2(props, ref) {
5
+ return spinnerElement(props, ref);
6
+ });
7
+ export {
8
+ Spinner
9
+ };
package/dist/esm/Table.js CHANGED
@@ -1,7 +1,9 @@
1
1
  'use client';
2
2
  import * as React from "react";
3
3
  import { cx, devWarnOnce, uid, useIsoLayoutEffect } from "./internal.js";
4
- import { useDensity } from "./locale.js";
4
+ import { useDensity, useLinkComponent } from "./locale.js";
5
+ import { Icon } from "./Icon.js";
6
+ import { IconArrowDown, IconArrowUp, IconArrowUpDown } from "./icons.js";
5
7
  import { inertProps, skeletonBody, skeletonColgroup } from "./TableSkeleton.js";
6
8
  const StackLabels = React.createContext(null);
7
9
  const ColumnIndex = React.createContext(-1);
@@ -242,8 +244,39 @@ function cellClass(base, p) {
242
244
  );
243
245
  }
244
246
  const Th = React.forwardRef(function Th2(props, ref) {
245
- const { align, numeric, mono, className, scope, label, card, skeleton, skeletonWidth, wrap, ...rest } = props;
247
+ const {
248
+ align,
249
+ numeric,
250
+ mono,
251
+ className,
252
+ scope,
253
+ label,
254
+ card,
255
+ skeleton,
256
+ skeletonWidth,
257
+ wrap,
258
+ sort,
259
+ onSort,
260
+ sortHref,
261
+ linkComponent,
262
+ ...rest
263
+ } = props;
246
264
  const stacked = React.useContext(StackLabels) != null;
265
+ const Link = useLinkComponent(linkComponent);
266
+ const sortable = !!onSort || sortHref != null;
267
+ const ariaSort = sort || (sortable ? "none" : void 0);
268
+ let children = props.children;
269
+ if (sortable) {
270
+ const icon = /* @__PURE__ */ React.createElement(
271
+ Icon,
272
+ {
273
+ name: sort === "ascending" ? /* @__PURE__ */ React.createElement(IconArrowUp, null) : sort === "descending" ? /* @__PURE__ */ React.createElement(IconArrowDown, null) : /* @__PURE__ */ React.createElement(IconArrowUpDown, null),
274
+ size: 12
275
+ }
276
+ );
277
+ const cls = cx("aura-table__sort", sort && sort !== "none" && "is-active");
278
+ children = sortHref != null ? /* @__PURE__ */ React.createElement(Link, { href: sortHref, className: cls }, props.children, icon) : /* @__PURE__ */ React.createElement("button", { type: "button", className: cls, onClick: onSort }, props.children, icon);
279
+ }
247
280
  return /* @__PURE__ */ React.createElement(
248
281
  "th",
249
282
  {
@@ -252,8 +285,10 @@ const Th = React.forwardRef(function Th2(props, ref) {
252
285
  className: cellClass("aura-tbl__th", props),
253
286
  role: stacked ? scope === "row" ? "rowheader" : "columnheader" : void 0,
254
287
  "data-card": stacked && (card === "title" || card === "action") ? card : void 0,
288
+ "aria-sort": ariaSort,
255
289
  ...rest
256
- }
290
+ },
291
+ children
257
292
  );
258
293
  });
259
294
  const Td = React.forwardRef(function Td2(props, ref) {
@@ -11,6 +11,7 @@ import {
11
11
  IconCircleDotDashed,
12
12
  IconInbox,
13
13
  IconInfo,
14
+ IconLoaderCircle,
14
15
  IconMinus,
15
16
  IconTrendingDown,
16
17
  IconTrendingUp,
@@ -101,7 +102,7 @@ const PILL_ICON = {
101
102
  };
102
103
  function statusPillElement(props, ref) {
103
104
  const tone = props.tone || toneFor(props.children);
104
- const rest = omit(props, ["tone", "className", "children", "wrap"]);
105
+ const rest = omit(props, ["tone", "className", "children", "wrap", "busy"]);
105
106
  return /* @__PURE__ */ React.createElement(
106
107
  "span",
107
108
  {
@@ -109,10 +110,26 @@ function statusPillElement(props, ref) {
109
110
  ref,
110
111
  className: cx("aura-pill", "aura-pill--" + tone, props.wrap && "is-wrap", props.className)
111
112
  },
112
- /* @__PURE__ */ React.createElement(Icon, { name: h(PILL_ICON[tone] || IconCircle), size: 12 }),
113
+ props.busy ? /* @__PURE__ */ React.createElement(Icon, { name: h(IconLoaderCircle), size: 12, className: "aura-spin" }) : /* @__PURE__ */ React.createElement(Icon, { name: h(PILL_ICON[tone] || IconCircle), size: 12 }),
113
114
  props.wrap ? /* @__PURE__ */ React.createElement("span", { className: "aura-pill__text" }, props.children) : props.children
114
115
  );
115
116
  }
117
+ function spinnerElement(props, ref) {
118
+ const rest = omit(props, ["size", "label", "className"]);
119
+ const label = props.label;
120
+ return /* @__PURE__ */ React.createElement(
121
+ "span",
122
+ {
123
+ ...rest,
124
+ ref,
125
+ className: cx("aura-spinner", "aura-spinner--" + (props.size || "md"), props.className),
126
+ role: label ? "status" : void 0,
127
+ "aria-hidden": label ? void 0 : true
128
+ },
129
+ /* @__PURE__ */ React.createElement(Icon, { name: h(IconLoaderCircle), size: props.size || "md", className: "aura-spin" }),
130
+ label ? /* @__PURE__ */ React.createElement("span", { className: "aura-sr-only" }, label) : null
131
+ );
132
+ }
116
133
  function badgeElement(props, ref) {
117
134
  const rest = omit(props, ["tone", "variant", "icon", "className", "children"]);
118
135
  return /* @__PURE__ */ React.createElement(
@@ -273,6 +290,9 @@ function ServerCard(props) {
273
290
  function ServerStatusPill(props) {
274
291
  return statusPillElement(props, void 0);
275
292
  }
293
+ function ServerSpinner(props) {
294
+ return spinnerElement(props, void 0);
295
+ }
276
296
  function ServerBadge(props) {
277
297
  return badgeElement(props, void 0);
278
298
  }
@@ -292,6 +312,7 @@ export {
292
312
  ServerBadge,
293
313
  ServerCard,
294
314
  ServerEmptyState,
315
+ ServerSpinner,
295
316
  ServerStat,
296
317
  ServerStatusPill,
297
318
  alertElement,
@@ -301,6 +322,7 @@ export {
301
322
  cardElement,
302
323
  emptyStateElement,
303
324
  linkClass,
325
+ spinnerElement,
304
326
  statElement,
305
327
  statusPillElement
306
328
  };
package/dist/esm/index.js CHANGED
@@ -60,6 +60,7 @@ import { Progress } from "./Progress.js";
60
60
  import { Skeleton } from "./Skeleton.js";
61
61
  import { EmptyState } from "./EmptyState.js";
62
62
  import { Pagination } from "./Pagination.js";
63
+ import { Spinner } from "./Spinner.js";
63
64
  import { Accordion } from "./Accordion.js";
64
65
  import { Popover } from "./Popover.js";
65
66
  import { NumberField } from "./NumberField.js";
@@ -117,6 +118,7 @@ export {
117
118
  SideNav,
118
119
  Skeleton,
119
120
  Sparkline,
121
+ Spinner,
120
122
  Stack,
121
123
  Stat,
122
124
  StatusPill,
@@ -134,6 +134,7 @@ const STRINGS = {
134
134
  statusUnknown: "No data",
135
135
  opensInNewTab: "opens in a new tab",
136
136
  required: "required",
137
+ firstPage: "First page",
137
138
  filtersApplied: function(n2) {
138
139
  return "Filters, " + n2.toLocaleString("en") + " applied";
139
140
  },
@@ -130,6 +130,7 @@ const sv = {
130
130
  statusUnknown: "Ingen data",
131
131
  opensInNewTab: "\xF6ppnas i en ny flik",
132
132
  required: "obligatoriskt",
133
+ firstPage: "F\xF6rsta sidan",
133
134
  filtersApplied: function(n) {
134
135
  return "Filter, " + n.toLocaleString("sv-SE") + " aktiva";
135
136
  },
@@ -130,6 +130,7 @@ const th = {
130
130
  statusUnknown: "\u0E22\u0E31\u0E07\u0E44\u0E21\u0E48\u0E21\u0E35\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25",
131
131
  opensInNewTab: "\u0E40\u0E1B\u0E34\u0E14\u0E43\u0E19\u0E41\u0E17\u0E47\u0E1A\u0E43\u0E2B\u0E21\u0E48",
132
132
  required: "\u0E08\u0E33\u0E40\u0E1B\u0E47\u0E19",
133
+ firstPage: "\u0E2B\u0E19\u0E49\u0E32\u0E41\u0E23\u0E01",
133
134
  filtersApplied: function(n2) {
134
135
  return "\u0E15\u0E31\u0E27\u0E01\u0E23\u0E2D\u0E07, \u0E43\u0E0A\u0E49\u0E2D\u0E22\u0E39\u0E48 " + n2.toLocaleString("en") + " \u0E23\u0E32\u0E22\u0E01\u0E32\u0E23";
135
136
  },
package/dist/index.d.cts 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;
@@ -2175,6 +2245,11 @@ export interface PageHeaderProps extends Pick<React$1.HTMLAttributes<HTMLElement
2175
2245
  /** 5.45: the bar's status line ("Total 10,700.00 THB incl. VAT · due 22 Oct 2026"), shown only while the actions are
2176
2246
  * a bar, in a polite live region. */
2177
2247
  actionsStatus?: React$1.ReactNode | undefined;
2248
+ /** 5.71 (Chamber-OS 191): with `actionsBarBelow`, only these become the phone bar — `actions` stay in the page (and
2249
+ * `actionsFullWidthBelow` still applies to them). From the breakpoint up, and on a short screen, they sit after
2250
+ * `actions` in the header row. Each node is rendered once at every width, never cloned. Without `actionsBarBelow`
2251
+ * they are simply more actions, after `actions`. */
2252
+ actionsBar?: React$1.ReactNode | undefined;
2178
2253
  /** Default 1. Use 2 when the page already has an h1 (e.g. in the AppShell bar). */
2179
2254
  headingLevel?: 1 | 2 | 3 | undefined;
2180
2255
  /** The heading's id, for `aria-labelledby` on the page's region. */
@@ -2287,6 +2362,8 @@ export interface AuraStrings {
2287
2362
  opensInNewTab: string;
2288
2363
  /** 5.67: read after a CheckboxGroup's legend when `required` (its `*` is hidden from screen readers). */
2289
2364
  required: string;
2365
+ /** 5.70: a cursor Pagination's link back to the start. */
2366
+ firstPage: string;
2290
2367
  /** 5.42: FilterBar's collapsed-filters button, read with its count ("Filters, 2 applied"). */
2291
2368
  filtersApplied: (n: number) => string;
2292
2369
  /** 5.42: closes FilterBar's "Filters" sheet. */
@@ -2412,7 +2489,8 @@ export declare const Tag: React$1.ForwardRefExoticComponent<TagProps & React$1.R
2412
2489
  export declare const Progress: React$1.ForwardRefExoticComponent<ProgressProps & React$1.RefAttributes<HTMLDivElement>>;
2413
2490
  export declare const Skeleton: React$1.ForwardRefExoticComponent<SkeletonProps & React$1.RefAttributes<HTMLSpanElement>>;
2414
2491
  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>>;
2492
+ export declare const Pagination: React$1.ForwardRefExoticComponent<AnyPaginationProps & React$1.RefAttributes<HTMLElement>>;
2493
+ export declare const Spinner: React$1.ForwardRefExoticComponent<SpinnerProps & React$1.RefAttributes<HTMLSpanElement>>;
2416
2494
  export declare const Accordion: React$1.ForwardRefExoticComponent<AccordionProps & React$1.RefAttributes<HTMLDivElement>>;
2417
2495
  export declare const Popover: React$1.ForwardRefExoticComponent<PopoverProps & React$1.RefAttributes<HTMLDivElement>>;
2418
2496
  /** Number input with thousands separators, +/− buttons and arrow keys (ARIA spinbutton). */