@jirawatpyk/aura-react 5.58.0 → 5.60.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/README.md CHANGED
@@ -186,6 +186,19 @@ DataTable with sort and page in the URL (4.17): `onStateChange={({ sort, page })
186
186
  - **Time zone**: `timeZone` on AuraProvider, DatePicker, DateRangePicker and Calendar decides "today" (the marker, `min`/`max="today"`, the first month shown); or pass `today` as an ISO date. `todayIn('Asia/Bangkok')` is exported from the root and `/server`.
187
187
  - **Toasts** queue past three instead of dropping: six in a row all show, in order, three at a time.
188
188
 
189
+ ## 5.60 — Chamber-OS addenda 74–76 (#173, #174, #175)
190
+
191
+ - **`linkClass` lays a link out at every width:** a link with `touchHeight` — and any `<button>` or `<summary>` with the class — is now `inline-flex` with a mouse too, not only under the touch query: vertically centred, a 4px gap before an icon, `min-width: 0` and `max-width: 100%`, so `<a className={linkClass({ touchHeight: true })}><span className="truncate">…</span><Icon/></a>` truncates inside its parent with a visible gap, and a `<summary>` is as wide as its content (its marker is hidden; add your own chevron). Under the touch query it is still at least 44×44. A plain `<a>` without `touchHeight` stays inline, so it still wraps in a sentence; a `touchHeight` link whose label wraps now wraps inside its own box (its second line starts under the link, not at the line's start), as it already did on touch. The layout is one class strong, so it beats an element reset (`summary { display: list-item }`) and your own `hidden` / `block` class wins when it comes later (or in a later layer, e.g. with `styles.layer.css` under Tailwind v4). A link with an icon as a direct child is centred on the line (within 2px; an icon inside a wrapper span isn't detected). The `<button>` reset is one class strong too, so a margin, padding or font class of yours on the button wins when it comes later. In a DataTable grid cell a touch link stays inline (no icon gap) so the cell keeps its ellipsis; in DataTable cards it is laid out under the touch query.
192
+ - **Label at the start:** the 44px box keeps its label at the start (`justify-content: flex-start`, was centred), so a link stretched by a flex column or a grid cell no longer centres its text away from the column. A short label in its own 44px box sits at the box's start.
193
+ - **A type class on the link applies:** `font: inherit` and the other resets now apply to the `<button>` form only, so `<a className={linkClass() + ' aura-text-label'}>` keeps the label scale (13px/500). On a `<button>`, a type class of yours wins when it comes after AURA's styles (or in a later layer); otherwise put it on a child.
194
+ - Drop the hand-written `inline-flex items-center`, `min-w-0`, `self-start` / `justify-start` and `flex w-fit` added for 5.59.
195
+ - **Table cells wrap words whole** (#174): a static Table's cells use `overflow-wrap: break-word` instead of `anywhere`, which made every cell's min-content one character wide, so an auto-layout table squeezed a text column until "Diamond Partnership" broke inside a word. Words now wrap whole. **Change:** in a table a long unbroken string (an email, a URL) widens its column instead of breaking — the table then scrolls sideways in its box (in stacked cards it still breaks to fit). A `stickyHeader` table that starts scrolling sideways this way also stops pinning its header to the page (see #175). Give such a cell `wrap="anywhere"` (new on `Td` and `Th`) for the old behaviour, or `wrap="none"` to keep a cell on one line (a document number; stacked cards still wrap). Drop `[overflow-wrap:normal]` stand-ins.
196
+ - **A wide sticky header sits above the first row** (#175): with `stickyHeader`, a Table wider than its box (it scrolls sideways there) pinned its header to that box with the page's offset (`--aura-shell-bar-height`), so the header covered the first row. Such a table can't pin to the page anyway; its header now sits in flow above the first row.
197
+
198
+ ## 5.59 — Chamber-OS addendum 73 (#172)
199
+
200
+ - **`linkClass()` — a text link with the touch rule:** the class list for a link that reads as text, not a button, from the root and `/server` (as `buttonClass`): `<Link href={url} className={linkClass({ touchHeight: true })}>INV-2041</Link>`. `tone`: `accent` (default, the link colour) or `inherit`; `underline`: `always` (default) or `hover`; `className` is appended. With `touchHeight` the link is at least 44×44 below 640px or on a coarse pointer (`'always'`: at every width) — `inline-flex`, the label centred — with no fill, border or padding, so it looks the same; with a mouse from 640px its size and line height don't change. It works on a `<button>` too (an action that opens a modal rather than navigating): the button's chrome is reset — no fill, border or padding, the surrounding font and line height, a pointer — so a button and an `<a>` with the class look the same at rest, on hover (the underline thickens, or appears with `underline: 'hover'`) and on keyboard focus (Button's focus ring). The button form is for an action on its own line: a `<button>` never wraps mid-sentence the way an `<a>` does. In a DataTable's grid cells (any `rowHeight`) the row is the tap target and the cell truncates with an ellipsis, so there the link stays inline whatever `touchHeight` says (and a utility class can't override it); in its stacked cards (`stackBelow`) the 44px target applies again. Use it on a link that stands on its own line (a row title, a "View all"); in the middle of a sentence a 44px box would open up the line, so leave `touchHeight` off there. Drop hand-written `inline-flex items-center max-sm:min-h-11 pointer-coarse:min-h-11`.
201
+
189
202
  ## 5.58 — Chamber-OS addendum 72 (#171)
190
203
 
191
204
  - **A short touchHeight tab is a 44×44 target:** with `touchHeight`, below 640px or on a coarse pointer (or always, with `'always'`) each tab is now at least 44px wide as well as 44px tall, its label centred, so a one-word tab such as "Tax" is 44×44. Tabs with longer labels keep their width and the gap between tabs is unchanged; a short tab's underline spans its 44px. With a mouse from 640px nothing changes. Inside its breakpoint a `fullWidth` row sizes its own tabs (equal shares, 12px either side of the label), so it is unchanged there; a one-letter tab in a full-width row that overflows and scrolls can stay under 44px wide.
@@ -134,6 +134,7 @@ window.Aura = (() => {
134
134
  formatBytes: () => formatBytes,
135
135
  formatDate: () => formatDate,
136
136
  iconNames: () => iconNames,
137
+ linkClass: () => linkClass,
137
138
  parseDate: () => parseDate,
138
139
  parseTime: () => parseTime,
139
140
  registerIcons: () => registerIcons,
@@ -883,6 +884,15 @@ window.Aura = (() => {
883
884
  opts.className
884
885
  );
885
886
  }
887
+ function linkClass(opts = {}) {
888
+ return cx(
889
+ "aura-link",
890
+ opts.tone === "inherit" && "aura-link--inherit",
891
+ opts.underline === "hover" && "aura-link--hover-underline",
892
+ opts.touchHeight === "always" ? "aura-link--touch-always" : opts.touchHeight && "aura-link--touch",
893
+ opts.className
894
+ );
895
+ }
886
896
 
887
897
  // src/locale.tsx
888
898
  var React5 = __toESM(require_react(), 1);
@@ -8999,12 +9009,15 @@ window.Aura = (() => {
8999
9009
  align === "end" && "is-end",
9000
9010
  align === "center" && "is-center",
9001
9011
  p.numeric && "is-numeric",
9012
+ /* 5.60 (Chamber-OS 174) */
9013
+ p.wrap === "anywhere" && "is-wrap-anywhere",
9014
+ p.wrap === "none" && "is-nowrap",
9002
9015
  p.mono && "aura-table__mono",
9003
9016
  p.className
9004
9017
  );
9005
9018
  }
9006
9019
  var Th = React52.forwardRef(function Th2(props, ref) {
9007
- const { align, numeric, mono, className, scope, label, card, skeleton, skeletonWidth, ...rest } = props;
9020
+ const { align, numeric, mono, className, scope, label, card, skeleton, skeletonWidth, wrap, ...rest } = props;
9008
9021
  const stacked = React52.useContext(StackLabels) != null;
9009
9022
  return /* @__PURE__ */ React52.createElement(
9010
9023
  "th",
@@ -9019,7 +9032,7 @@ window.Aura = (() => {
9019
9032
  );
9020
9033
  });
9021
9034
  var Td = React52.forwardRef(function Td2(props, ref) {
9022
- const { align, numeric, mono, className, scope, label, card, skeleton, skeletonWidth, ...rest } = props;
9035
+ const { align, numeric, mono, className, scope, label, card, skeleton, skeletonWidth, wrap, ...rest } = props;
9023
9036
  const labels = React52.useContext(StackLabels), col = React52.useContext(ColumnIndex);
9024
9037
  const slot = labels && (card === "title" || card === "action") ? card : void 0;
9025
9038
  const shown = labels && !slot ? label != null ? label : col >= 0 ? labels[col] : void 0 : void 0;
@@ -115,6 +115,7 @@ __export(index_exports, {
115
115
  formatBytes: () => formatBytes,
116
116
  formatDate: () => formatDate,
117
117
  iconNames: () => iconNames,
118
+ linkClass: () => linkClass,
118
119
  parseDate: () => parseDate,
119
120
  parseTime: () => parseTime,
120
121
  registerIcons: () => registerIcons,
@@ -865,6 +866,15 @@ function buttonClass(opts = {}) {
865
866
  opts.className
866
867
  );
867
868
  }
869
+ function linkClass(opts = {}) {
870
+ return cx(
871
+ "aura-link",
872
+ opts.tone === "inherit" && "aura-link--inherit",
873
+ opts.underline === "hover" && "aura-link--hover-underline",
874
+ opts.touchHeight === "always" ? "aura-link--touch-always" : opts.touchHeight && "aura-link--touch",
875
+ opts.className
876
+ );
877
+ }
868
878
 
869
879
  // src/locale.tsx
870
880
  var React5 = __toESM(require("react"), 1);
@@ -8981,12 +8991,15 @@ function cellClass(base, p) {
8981
8991
  align === "end" && "is-end",
8982
8992
  align === "center" && "is-center",
8983
8993
  p.numeric && "is-numeric",
8994
+ /* 5.60 (Chamber-OS 174) */
8995
+ p.wrap === "anywhere" && "is-wrap-anywhere",
8996
+ p.wrap === "none" && "is-nowrap",
8984
8997
  p.mono && "aura-table__mono",
8985
8998
  p.className
8986
8999
  );
8987
9000
  }
8988
9001
  var Th = React52.forwardRef(function Th2(props, ref) {
8989
- const { align, numeric, mono, className, scope, label, card, skeleton, skeletonWidth, ...rest } = props;
9002
+ const { align, numeric, mono, className, scope, label, card, skeleton, skeletonWidth, wrap, ...rest } = props;
8990
9003
  const stacked = React52.useContext(StackLabels) != null;
8991
9004
  return /* @__PURE__ */ React52.createElement(
8992
9005
  "th",
@@ -9001,7 +9014,7 @@ var Th = React52.forwardRef(function Th2(props, ref) {
9001
9014
  );
9002
9015
  });
9003
9016
  var Td = React52.forwardRef(function Td2(props, ref) {
9004
- const { align, numeric, mono, className, scope, label, card, skeleton, skeletonWidth, ...rest } = props;
9017
+ const { align, numeric, mono, className, scope, label, card, skeleton, skeletonWidth, wrap, ...rest } = props;
9005
9018
  const labels = React52.useContext(StackLabels), col = React52.useContext(ColumnIndex);
9006
9019
  const slot = labels && (card === "title" || card === "action") ? card : void 0;
9007
9020
  const shown = labels && !slot ? label != null ? label : col >= 0 ? labels[col] : void 0 : void 0;
package/dist/esm/Table.js CHANGED
@@ -234,12 +234,15 @@ function cellClass(base, p) {
234
234
  align === "end" && "is-end",
235
235
  align === "center" && "is-center",
236
236
  p.numeric && "is-numeric",
237
+ /* 5.60 (Chamber-OS 174) */
238
+ p.wrap === "anywhere" && "is-wrap-anywhere",
239
+ p.wrap === "none" && "is-nowrap",
237
240
  p.mono && "aura-table__mono",
238
241
  p.className
239
242
  );
240
243
  }
241
244
  const Th = React.forwardRef(function Th2(props, ref) {
242
- const { align, numeric, mono, className, scope, label, card, skeleton, skeletonWidth, ...rest } = props;
245
+ const { align, numeric, mono, className, scope, label, card, skeleton, skeletonWidth, wrap, ...rest } = props;
243
246
  const stacked = React.useContext(StackLabels) != null;
244
247
  return /* @__PURE__ */ React.createElement(
245
248
  "th",
@@ -254,7 +257,7 @@ const Th = React.forwardRef(function Th2(props, ref) {
254
257
  );
255
258
  });
256
259
  const Td = React.forwardRef(function Td2(props, ref) {
257
- const { align, numeric, mono, className, scope, label, card, skeleton, skeletonWidth, ...rest } = props;
260
+ const { align, numeric, mono, className, scope, label, card, skeleton, skeletonWidth, wrap, ...rest } = props;
258
261
  const labels = React.useContext(StackLabels), col = React.useContext(ColumnIndex);
259
262
  const slot = labels && (card === "title" || card === "action") ? card : void 0;
260
263
  const shown = labels && !slot ? label != null ? label : col >= 0 ? labels[col] : void 0 : void 0;
@@ -255,6 +255,15 @@ function buttonClass(opts = {}) {
255
255
  opts.className
256
256
  );
257
257
  }
258
+ function linkClass(opts = {}) {
259
+ return cx(
260
+ "aura-link",
261
+ opts.tone === "inherit" && "aura-link--inherit",
262
+ opts.underline === "hover" && "aura-link--hover-underline",
263
+ opts.touchHeight === "always" ? "aura-link--touch-always" : opts.touchHeight && "aura-link--touch",
264
+ opts.className
265
+ );
266
+ }
258
267
  function ServerAlert(props) {
259
268
  return alertElement(props, void 0, null);
260
269
  }
@@ -291,6 +300,7 @@ export {
291
300
  buttonClass,
292
301
  cardElement,
293
302
  emptyStateElement,
303
+ linkClass,
294
304
  statElement,
295
305
  statusPillElement
296
306
  };
package/dist/esm/index.js CHANGED
@@ -27,7 +27,7 @@ import { Tooltip } from "./Tooltip.js";
27
27
  import { Dialog, Drawer, useDialogClose } from "./Dialog.js";
28
28
  import { DataTable } from "./DataTable.js";
29
29
  import { Card } from "./Card.js";
30
- import { buttonClass } from "./display.js";
30
+ import { buttonClass, linkClass } from "./display.js";
31
31
  import { Tabs } from "./Tabs.js";
32
32
  import { SideNav } from "./SideNav.js";
33
33
  import { Breadcrumb } from "./Breadcrumb.js";
@@ -149,6 +149,7 @@ export {
149
149
  formatBytes,
150
150
  formatDate,
151
151
  iconNames,
152
+ linkClass,
152
153
  parseDate,
153
154
  parseTime,
154
155
  registerIcons,
package/dist/index.d.cts CHANGED
@@ -1435,6 +1435,11 @@ export interface TableCellProps extends Omit<React$1.TdHTMLAttributes<HTMLTableC
1435
1435
  numeric?: boolean | undefined;
1436
1436
  /** IDs and codes in the mono face. */
1437
1437
  mono?: boolean | undefined;
1438
+ /** How the cell's text wraps (5.60, Chamber-OS 174). Default `word` (`overflow-wrap: break-word`): between words; a
1439
+ * long unbroken string widens its column (the table then scrolls sideways; in stacked cards it breaks to fit).
1440
+ * `anywhere`: may break inside a word, so the column can shrink (URLs, emails; the rule before 5.60). `none`: on one
1441
+ * line (a document number); stacked cards still wrap. */
1442
+ wrap?: "word" | "anywhere" | "none" | undefined;
1438
1443
  /** Th only. Default `col`. */
1439
1444
  scope?: "col" | "row" | "colgroup" | "rowgroup" | undefined;
1440
1445
  /** The label this cell shows when its table is stacked (`stackBelow`, 5.8). Default: the matching header's text. */
@@ -1946,6 +1951,20 @@ export declare function buttonClass(opts?: {
1946
1951
  touchHeight?: boolean | undefined;
1947
1952
  className?: string | undefined;
1948
1953
  }): string;
1954
+ /** The class list of a text link (5.59, Chamber-OS 172) — a link that reads as text, not a button. Put it on your own
1955
+ * `<a>` or `<Link>`, also in a Server Component: `<Link href={url} className={linkClass({ touchHeight: true })}>`.
1956
+ * `tone`: `accent` (default) or `inherit` (the surrounding colour). `underline`: `always` (default) or `hover`.
1957
+ * `touchHeight`: at least 44×44 below 640px or on a coarse pointer (`true`) or at every width (`'always'`), the label
1958
+ * at the start and its look unchanged — for a link on its own line, not mid-sentence. 5.60: with `touchHeight` (and
1959
+ * on a `<button>` or `<summary>`) it is `inline-flex` at every width — a 4px gap before an icon, `min-width: 0` so a
1960
+ * truncating child ends in an ellipsis. On a `<button>` (an action that opens something) the button's chrome is
1961
+ * reset, so it looks like the link; put a type class on a child there. Hover and Button's focus ring included. */
1962
+ export declare function linkClass(opts?: {
1963
+ tone?: "accent" | "inherit" | undefined;
1964
+ underline?: "always" | "hover" | undefined;
1965
+ touchHeight?: boolean | "always" | undefined;
1966
+ className?: string | undefined;
1967
+ }): string;
1949
1968
  export declare const Alert: React$1.ForwardRefExoticComponent<AlertProps & React$1.RefAttributes<HTMLDivElement>>;
1950
1969
  /** Show a toast; returns its id. Needs `<Toaster />` mounted once. */
1951
1970
  export declare function toast(opts: ToastOptions | string): string;
package/dist/index.d.ts CHANGED
@@ -1435,6 +1435,11 @@ export interface TableCellProps extends Omit<React$1.TdHTMLAttributes<HTMLTableC
1435
1435
  numeric?: boolean | undefined;
1436
1436
  /** IDs and codes in the mono face. */
1437
1437
  mono?: boolean | undefined;
1438
+ /** How the cell's text wraps (5.60, Chamber-OS 174). Default `word` (`overflow-wrap: break-word`): between words; a
1439
+ * long unbroken string widens its column (the table then scrolls sideways; in stacked cards it breaks to fit).
1440
+ * `anywhere`: may break inside a word, so the column can shrink (URLs, emails; the rule before 5.60). `none`: on one
1441
+ * line (a document number); stacked cards still wrap. */
1442
+ wrap?: "word" | "anywhere" | "none" | undefined;
1438
1443
  /** Th only. Default `col`. */
1439
1444
  scope?: "col" | "row" | "colgroup" | "rowgroup" | undefined;
1440
1445
  /** The label this cell shows when its table is stacked (`stackBelow`, 5.8). Default: the matching header's text. */
@@ -1946,6 +1951,20 @@ export declare function buttonClass(opts?: {
1946
1951
  touchHeight?: boolean | undefined;
1947
1952
  className?: string | undefined;
1948
1953
  }): string;
1954
+ /** The class list of a text link (5.59, Chamber-OS 172) — a link that reads as text, not a button. Put it on your own
1955
+ * `<a>` or `<Link>`, also in a Server Component: `<Link href={url} className={linkClass({ touchHeight: true })}>`.
1956
+ * `tone`: `accent` (default) or `inherit` (the surrounding colour). `underline`: `always` (default) or `hover`.
1957
+ * `touchHeight`: at least 44×44 below 640px or on a coarse pointer (`true`) or at every width (`'always'`), the label
1958
+ * at the start and its look unchanged — for a link on its own line, not mid-sentence. 5.60: with `touchHeight` (and
1959
+ * on a `<button>` or `<summary>`) it is `inline-flex` at every width — a 4px gap before an icon, `min-width: 0` so a
1960
+ * truncating child ends in an ellipsis. On a `<button>` (an action that opens something) the button's chrome is
1961
+ * reset, so it looks like the link; put a type class on a child there. Hover and Button's focus ring included. */
1962
+ export declare function linkClass(opts?: {
1963
+ tone?: "accent" | "inherit" | undefined;
1964
+ underline?: "always" | "hover" | undefined;
1965
+ touchHeight?: boolean | "always" | undefined;
1966
+ className?: string | undefined;
1967
+ }): string;
1949
1968
  export declare const Alert: React$1.ForwardRefExoticComponent<AlertProps & React$1.RefAttributes<HTMLDivElement>>;
1950
1969
  /** Show a toast; returns its id. Needs `<Toaster />` mounted once. */
1951
1970
  export declare function toast(opts: ToastOptions | string): string;
@@ -54,6 +54,7 @@ __export(server_exports, {
54
54
  formatBytes: () => formatBytes,
55
55
  formatDate: () => formatDate,
56
56
  fromISO: () => fromISO,
57
+ linkClass: () => linkClass,
57
58
  parseDate: () => parseDate,
58
59
  parseTime: () => parseTime,
59
60
  registerIcons: () => registerIcons,
@@ -1411,6 +1412,15 @@ function buttonClass(opts = {}) {
1411
1412
  opts.className
1412
1413
  );
1413
1414
  }
1415
+ function linkClass(opts = {}) {
1416
+ return cx(
1417
+ "aura-link",
1418
+ opts.tone === "inherit" && "aura-link--inherit",
1419
+ opts.underline === "hover" && "aura-link--hover-underline",
1420
+ opts.touchHeight === "always" ? "aura-link--touch-always" : opts.touchHeight && "aura-link--touch",
1421
+ opts.className
1422
+ );
1423
+ }
1414
1424
  function ServerAlert(props) {
1415
1425
  return alertElement(props, void 0, null);
1416
1426
  }
@@ -496,6 +496,20 @@ export declare function buttonClass(opts?: {
496
496
  touchHeight?: boolean | undefined;
497
497
  className?: string | undefined;
498
498
  }): string;
499
+ /** The class list of a text link (5.59, Chamber-OS 172) — a link that reads as text, not a button. Put it on your own
500
+ * `<a>` or `<Link>`, also in a Server Component: `<Link href={url} className={linkClass({ touchHeight: true })}>`.
501
+ * `tone`: `accent` (default) or `inherit` (the surrounding colour). `underline`: `always` (default) or `hover`.
502
+ * `touchHeight`: at least 44×44 below 640px or on a coarse pointer (`true`) or at every width (`'always'`), the label
503
+ * at the start and its look unchanged — for a link on its own line, not mid-sentence. 5.60: with `touchHeight` (and
504
+ * on a `<button>` or `<summary>`) it is `inline-flex` at every width — a 4px gap before an icon, `min-width: 0` so a
505
+ * truncating child ends in an ellipsis. On a `<button>` (an action that opens something) the button's chrome is
506
+ * reset, so it looks like the link; put a type class on a child there. Hover and Button's focus ring included. */
507
+ export declare function linkClass(opts?: {
508
+ tone?: "accent" | "inherit" | undefined;
509
+ underline?: "always" | "hover" | undefined;
510
+ touchHeight?: boolean | "always" | undefined;
511
+ className?: string | undefined;
512
+ }): string;
499
513
  declare function ServerAlert(props: Omit<AlertProps, "onDismiss">): React$1.ReactElement;
500
514
  declare function ServerCard(props: CardProps): React$1.ReactElement;
501
515
  declare function ServerStatusPill(props: StatusPillProps): React$1.ReactElement;
@@ -496,6 +496,20 @@ export declare function buttonClass(opts?: {
496
496
  touchHeight?: boolean | undefined;
497
497
  className?: string | undefined;
498
498
  }): string;
499
+ /** The class list of a text link (5.59, Chamber-OS 172) — a link that reads as text, not a button. Put it on your own
500
+ * `<a>` or `<Link>`, also in a Server Component: `<Link href={url} className={linkClass({ touchHeight: true })}>`.
501
+ * `tone`: `accent` (default) or `inherit` (the surrounding colour). `underline`: `always` (default) or `hover`.
502
+ * `touchHeight`: at least 44×44 below 640px or on a coarse pointer (`true`) or at every width (`'always'`), the label
503
+ * at the start and its look unchanged — for a link on its own line, not mid-sentence. 5.60: with `touchHeight` (and
504
+ * on a `<button>` or `<summary>`) it is `inline-flex` at every width — a 4px gap before an icon, `min-width: 0` so a
505
+ * truncating child ends in an ellipsis. On a `<button>` (an action that opens something) the button's chrome is
506
+ * reset, so it looks like the link; put a type class on a child there. Hover and Button's focus ring included. */
507
+ export declare function linkClass(opts?: {
508
+ tone?: "accent" | "inherit" | undefined;
509
+ underline?: "always" | "hover" | undefined;
510
+ touchHeight?: boolean | "always" | undefined;
511
+ className?: string | undefined;
512
+ }): string;
499
513
  declare function ServerAlert(props: Omit<AlertProps, "onDismiss">): React$1.ReactElement;
500
514
  declare function ServerCard(props: CardProps): React$1.ReactElement;
501
515
  declare function ServerStatusPill(props: StatusPillProps): React$1.ReactElement;
@@ -1346,6 +1346,15 @@ function buttonClass(opts = {}) {
1346
1346
  opts.className
1347
1347
  );
1348
1348
  }
1349
+ function linkClass(opts = {}) {
1350
+ return cx(
1351
+ "aura-link",
1352
+ opts.tone === "inherit" && "aura-link--inherit",
1353
+ opts.underline === "hover" && "aura-link--hover-underline",
1354
+ opts.touchHeight === "always" ? "aura-link--touch-always" : opts.touchHeight && "aura-link--touch",
1355
+ opts.className
1356
+ );
1357
+ }
1349
1358
  function ServerAlert(props) {
1350
1359
  return alertElement(props, void 0, null);
1351
1360
  }
@@ -1858,6 +1867,7 @@ export {
1858
1867
  formatBytes,
1859
1868
  formatDate,
1860
1869
  fromISO,
1870
+ linkClass,
1861
1871
  parseDate,
1862
1872
  parseTime,
1863
1873
  registerIcons,
package/dist/styles.css CHANGED
@@ -184,7 +184,7 @@ button.aura-btn--creative[aria-disabled='true']:hover { box-shadow: var(--aura-s
184
184
  .aura-table__td { overflow: clip; overflow-clip-margin: var(--aura-space-1); }
185
185
  }
186
186
  @supports not (overflow-clip-margin: 1px) {
187
- .aura-table__td :focus-visible { outline-offset: calc(-1 * var(--aura-focus-ring-width)); }
187
+ .aura-table__td :focus-visible, .aura-table__td .aura-link:focus-visible { outline-offset: calc(-1 * var(--aura-focus-ring-width)); }
188
188
  }
189
189
  /* 5.11 rowHeight="auto" (never virtualized): a row grows to fit what wraps in it; each cell centres its content.
190
190
  * The padding only shows once content is taller than the row: a small Button or IconButton (32px), a pill or one line
@@ -1101,6 +1101,63 @@ a.aura-tab { text-decoration: none; }
1101
1101
  .aura-actionbar__start > .aura-icon-btn, .aura-actionbar__start > * > .aura-icon-btn:only-child { width: var(--aura-touch-target); height: var(--aura-touch-target); }
1102
1102
  }
1103
1103
 
1104
+ /* ---------- Text link (5.59, Chamber-OS 172; 5.60, 173) ---------- */
1105
+ /* linkClass(): a link that reads as text. accent (default) or inherit colour; underlined, or only on hover; hover
1106
+ * thickens an underline that is always there. Focus is Button's ring.
1107
+ * 5.60 (Chamber-OS 173): a link with touchHeight — and any <button> or <summary> with the class — is laid out at every
1108
+ * width, not only under the touch query: inline-flex, centred vertically, a 4px gap before an icon, label at the start,
1109
+ * and min-width 0 / max-width 100% so a truncating child ends in an ellipsis inside its parent. Under the touch query
1110
+ * (or always) it is at least 44×44; a box stretched by its parent keeps its label at the start. A plain <a> without
1111
+ * touchHeight stays inline, so it can wrap in a sentence. The type of an <a> is its own (a type class such as
1112
+ * aura-text-label on it applies); a <button> takes the surrounding font — put a type class on a child there. */
1113
+ .aura-link {
1114
+ color: var(--aura-fg-accent); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 2px;
1115
+ border-radius: var(--aura-radius-xs); cursor: pointer;
1116
+ }
1117
+ /* the <button> form: its chrome reset so it looks like the <a>. One class strong (0,1,0), so an app's own margin,
1118
+ * padding or font class on the button wins when it comes later. */
1119
+ .aura-link:where(button) {
1120
+ -webkit-appearance: none; appearance: none; margin: 0; padding: 0; border: 0; background: none;
1121
+ font: inherit; line-height: inherit; letter-spacing: inherit; word-spacing: inherit; text-align: inherit;
1122
+ text-transform: inherit; text-indent: inherit; text-shadow: inherit;
1123
+ }
1124
+ /* One class's worth of specificity (0,1,0): it beats an element reset (summary { display: list-item }) and ties with
1125
+ * an app's own class (hidden, block), which wins when it comes later or in a later layer. */
1126
+ .aura-link:where(.aura-link--touch, .aura-link--touch-always, button, summary) {
1127
+ display: inline-flex; align-items: center; justify-content: flex-start; gap: var(--aura-space-1);
1128
+ min-width: 0; max-width: 100%;
1129
+ }
1130
+ /* A leading icon would give the box its baseline (the icon's bottom); centre the box on the line instead (about 1px
1131
+ * either way at any line height). */
1132
+ .aura-link:where(.aura-link--touch, .aura-link--touch-always, button, summary):has(> svg:first-child) { vertical-align: middle; }
1133
+ summary.aura-link { list-style: none; }
1134
+ summary.aura-link::-webkit-details-marker { display: none; }
1135
+ .aura-link:hover { text-decoration-thickness: 2px; }
1136
+ .aura-link--inherit { color: inherit; }
1137
+ .aura-link--hover-underline { text-decoration: none; }
1138
+ .aura-link--hover-underline:hover { text-decoration: underline; text-decoration-thickness: 1px; }
1139
+ .aura-link:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: var(--aura-focus-ring-offset); }
1140
+ .aura-link:disabled, .aura-link[aria-disabled="true"] { opacity: var(--aura-disabled-opacity); cursor: not-allowed; text-decoration-thickness: 1px; }
1141
+ .aura-link--hover-underline:is(:disabled, [aria-disabled="true"]):hover { text-decoration: none; }
1142
+ /* Forced colours: a <button> would take ButtonText; both forms read as a link. */
1143
+ @media (forced-colors: active) {
1144
+ .aura-link { color: LinkText; }
1145
+ .aura-link:is(:disabled, [aria-disabled="true"]) { color: GrayText; }
1146
+ }
1147
+ .aura-link.aura-link--touch-always { min-height: var(--aura-touch-target); min-width: var(--aura-touch-target); }
1148
+ @media (max-width: 639.98px), (pointer: coarse) {
1149
+ .aura-link.aura-link--touch { min-height: var(--aura-touch-target); min-width: var(--aura-touch-target); }
1150
+ }
1151
+ /* In a DataTable grid cell the row is the target and the cell clips with an ellipsis: the link stays inline there.
1152
+ * In DataTable's stacked cards nothing clips, so the 44px target comes back (container query: right before hydration). */
1153
+ .aura-table__td .aura-link.aura-link:is(.aura-link--touch, .aura-link--touch-always) { display: inline; min-height: 0; min-width: 0; }
1154
+ @container aura-stack (width < 9999.5px) {
1155
+ .aura-table__td .aura-link.aura-link.aura-link--touch-always { display: inline-flex; min-height: var(--aura-touch-target); min-width: var(--aura-touch-target); }
1156
+ @media (max-width: 639.98px), (pointer: coarse) {
1157
+ .aura-table__td .aura-link.aura-link.aura-link--touch { display: inline-flex; min-height: var(--aura-touch-target); min-width: var(--aura-touch-target); }
1158
+ }
1159
+ }
1160
+
1104
1161
  /* ---------- Dropdown ---------- */
1105
1162
  .aura-dropdown { display: inline-flex; }
1106
1163
 
@@ -2214,7 +2271,14 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
2214
2271
  .aura-tbl__caption { caption-side: top; padding: var(--aura-space-4) var(--aura-space-6) var(--aura-space-3); text-align: left; font-size: max(14px, .875rem); font-weight: 600; }
2215
2272
  /* 5.30: from 640px a cell is at least 10ch wide, so the table never squeezes a column to one letter; a longer word (an
2216
2273
  * email, a URL) still breaks to fit instead of widening the table. Phones keep fitting the box: use stackBelow there. */
2217
- .aura-tbl__th, .aura-tbl__td { padding: var(--aura-tbl-cell-py, var(--aura-space-3)) var(--aura-space-4); text-align: left; vertical-align: top; overflow-wrap: anywhere; }
2274
+ .aura-tbl__th, .aura-tbl__td { padding: var(--aura-tbl-cell-py, var(--aura-space-3)) var(--aura-space-4); text-align: left; vertical-align: top; overflow-wrap: break-word; }
2275
+ /* 5.60 (Chamber-OS 174): break-word, not anywhere — `anywhere` made every cell's min-content one character wide, so an
2276
+ * auto-layout table squeezed a text column until "Diamond Partnership" broke inside a word. With break-word words wrap
2277
+ * whole; a long unbroken string widens its column (the table scrolls sideways; stacked cards still break it). Td/Th
2278
+ * `wrap`: `anywhere` (the old rule, for URLs and emails that may shrink the column) or `none` (one line; stacked cards
2279
+ * wrap as usual). */
2280
+ .aura-tbl__th.is-wrap-anywhere, .aura-tbl__td.is-wrap-anywhere { overflow-wrap: anywhere; }
2281
+ .aura-tbl__th.is-nowrap, .aura-tbl__td.is-nowrap { white-space: nowrap; }
2218
2282
  @media (min-width: 640px) { .aura-tbl__th, .aura-tbl__td { min-width: 10ch; } }
2219
2283
  .aura-tbl__th:first-child, .aura-tbl__td:first-child { padding-left: var(--aura-space-6); }
2220
2284
  .aura-tbl__th:last-child, .aura-tbl__td:last-child { padding-right: var(--aura-space-6); }
@@ -2248,6 +2312,10 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
2248
2312
  }
2249
2313
  }
2250
2314
  .aura-tbl-wrap.is-sticky-box > .aura-tbl > .aura-tbl__head .aura-tbl__th { top: 0; }
2315
+ /* 5.60 (Chamber-OS 175): a table wider than its box scrolls sideways inside it, and that scroll box is what a sticky
2316
+ * header pins to — so the page offset (the shell bar) pushed the header down over the first row. Such a table can't
2317
+ * pin to the page: its header sits in flow (top 0 in a box that doesn't scroll down). */
2318
+ .aura-tbl-wrap.is-sticky-page.is-wide > .aura-tbl > .aura-tbl__head .aura-tbl__th { top: 0; }
2251
2319
  .aura-tbl-wrap:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: 2px; }
2252
2320
  /* 5.13 (Chamber-OS 81): align="middle" centres body and footer cells on their row; bordered={false} drops the frame and
2253
2321
  * the outer cells' side padding, so the table lines up with what's around it (a Card's heading). */
@@ -186,7 +186,7 @@ button.aura-btn--creative[aria-disabled='true']:hover { box-shadow: var(--aura-s
186
186
  .aura-table__td { overflow: clip; overflow-clip-margin: var(--aura-space-1); }
187
187
  }
188
188
  @supports not (overflow-clip-margin: 1px) {
189
- .aura-table__td :focus-visible { outline-offset: calc(-1 * var(--aura-focus-ring-width)); }
189
+ .aura-table__td :focus-visible, .aura-table__td .aura-link:focus-visible { outline-offset: calc(-1 * var(--aura-focus-ring-width)); }
190
190
  }
191
191
  /* 5.11 rowHeight="auto" (never virtualized): a row grows to fit what wraps in it; each cell centres its content.
192
192
  * The padding only shows once content is taller than the row: a small Button or IconButton (32px), a pill or one line
@@ -1103,6 +1103,63 @@ a.aura-tab { text-decoration: none; }
1103
1103
  .aura-actionbar__start > .aura-icon-btn, .aura-actionbar__start > * > .aura-icon-btn:only-child { width: var(--aura-touch-target); height: var(--aura-touch-target); }
1104
1104
  }
1105
1105
 
1106
+ /* ---------- Text link (5.59, Chamber-OS 172; 5.60, 173) ---------- */
1107
+ /* linkClass(): a link that reads as text. accent (default) or inherit colour; underlined, or only on hover; hover
1108
+ * thickens an underline that is always there. Focus is Button's ring.
1109
+ * 5.60 (Chamber-OS 173): a link with touchHeight — and any <button> or <summary> with the class — is laid out at every
1110
+ * width, not only under the touch query: inline-flex, centred vertically, a 4px gap before an icon, label at the start,
1111
+ * and min-width 0 / max-width 100% so a truncating child ends in an ellipsis inside its parent. Under the touch query
1112
+ * (or always) it is at least 44×44; a box stretched by its parent keeps its label at the start. A plain <a> without
1113
+ * touchHeight stays inline, so it can wrap in a sentence. The type of an <a> is its own (a type class such as
1114
+ * aura-text-label on it applies); a <button> takes the surrounding font — put a type class on a child there. */
1115
+ .aura-link {
1116
+ color: var(--aura-fg-accent); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 2px;
1117
+ border-radius: var(--aura-radius-xs); cursor: pointer;
1118
+ }
1119
+ /* the <button> form: its chrome reset so it looks like the <a>. One class strong (0,1,0), so an app's own margin,
1120
+ * padding or font class on the button wins when it comes later. */
1121
+ .aura-link:where(button) {
1122
+ -webkit-appearance: none; appearance: none; margin: 0; padding: 0; border: 0; background: none;
1123
+ font: inherit; line-height: inherit; letter-spacing: inherit; word-spacing: inherit; text-align: inherit;
1124
+ text-transform: inherit; text-indent: inherit; text-shadow: inherit;
1125
+ }
1126
+ /* One class's worth of specificity (0,1,0): it beats an element reset (summary { display: list-item }) and ties with
1127
+ * an app's own class (hidden, block), which wins when it comes later or in a later layer. */
1128
+ .aura-link:where(.aura-link--touch, .aura-link--touch-always, button, summary) {
1129
+ display: inline-flex; align-items: center; justify-content: flex-start; gap: var(--aura-space-1);
1130
+ min-width: 0; max-width: 100%;
1131
+ }
1132
+ /* A leading icon would give the box its baseline (the icon's bottom); centre the box on the line instead (about 1px
1133
+ * either way at any line height). */
1134
+ .aura-link:where(.aura-link--touch, .aura-link--touch-always, button, summary):has(> svg:first-child) { vertical-align: middle; }
1135
+ summary.aura-link { list-style: none; }
1136
+ summary.aura-link::-webkit-details-marker { display: none; }
1137
+ .aura-link:hover { text-decoration-thickness: 2px; }
1138
+ .aura-link--inherit { color: inherit; }
1139
+ .aura-link--hover-underline { text-decoration: none; }
1140
+ .aura-link--hover-underline:hover { text-decoration: underline; text-decoration-thickness: 1px; }
1141
+ .aura-link:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: var(--aura-focus-ring-offset); }
1142
+ .aura-link:disabled, .aura-link[aria-disabled="true"] { opacity: var(--aura-disabled-opacity); cursor: not-allowed; text-decoration-thickness: 1px; }
1143
+ .aura-link--hover-underline:is(:disabled, [aria-disabled="true"]):hover { text-decoration: none; }
1144
+ /* Forced colours: a <button> would take ButtonText; both forms read as a link. */
1145
+ @media (forced-colors: active) {
1146
+ .aura-link { color: LinkText; }
1147
+ .aura-link:is(:disabled, [aria-disabled="true"]) { color: GrayText; }
1148
+ }
1149
+ .aura-link.aura-link--touch-always { min-height: var(--aura-touch-target); min-width: var(--aura-touch-target); }
1150
+ @media (max-width: 639.98px), (pointer: coarse) {
1151
+ .aura-link.aura-link--touch { min-height: var(--aura-touch-target); min-width: var(--aura-touch-target); }
1152
+ }
1153
+ /* In a DataTable grid cell the row is the target and the cell clips with an ellipsis: the link stays inline there.
1154
+ * In DataTable's stacked cards nothing clips, so the 44px target comes back (container query: right before hydration). */
1155
+ .aura-table__td .aura-link.aura-link:is(.aura-link--touch, .aura-link--touch-always) { display: inline; min-height: 0; min-width: 0; }
1156
+ @container aura-stack (width < 9999.5px) {
1157
+ .aura-table__td .aura-link.aura-link.aura-link--touch-always { display: inline-flex; min-height: var(--aura-touch-target); min-width: var(--aura-touch-target); }
1158
+ @media (max-width: 639.98px), (pointer: coarse) {
1159
+ .aura-table__td .aura-link.aura-link.aura-link--touch { display: inline-flex; min-height: var(--aura-touch-target); min-width: var(--aura-touch-target); }
1160
+ }
1161
+ }
1162
+
1106
1163
  /* ---------- Dropdown ---------- */
1107
1164
  .aura-dropdown { display: inline-flex; }
1108
1165
 
@@ -2216,7 +2273,14 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
2216
2273
  .aura-tbl__caption { caption-side: top; padding: var(--aura-space-4) var(--aura-space-6) var(--aura-space-3); text-align: left; font-size: max(14px, .875rem); font-weight: 600; }
2217
2274
  /* 5.30: from 640px a cell is at least 10ch wide, so the table never squeezes a column to one letter; a longer word (an
2218
2275
  * email, a URL) still breaks to fit instead of widening the table. Phones keep fitting the box: use stackBelow there. */
2219
- .aura-tbl__th, .aura-tbl__td { padding: var(--aura-tbl-cell-py, var(--aura-space-3)) var(--aura-space-4); text-align: left; vertical-align: top; overflow-wrap: anywhere; }
2276
+ .aura-tbl__th, .aura-tbl__td { padding: var(--aura-tbl-cell-py, var(--aura-space-3)) var(--aura-space-4); text-align: left; vertical-align: top; overflow-wrap: break-word; }
2277
+ /* 5.60 (Chamber-OS 174): break-word, not anywhere — `anywhere` made every cell's min-content one character wide, so an
2278
+ * auto-layout table squeezed a text column until "Diamond Partnership" broke inside a word. With break-word words wrap
2279
+ * whole; a long unbroken string widens its column (the table scrolls sideways; stacked cards still break it). Td/Th
2280
+ * `wrap`: `anywhere` (the old rule, for URLs and emails that may shrink the column) or `none` (one line; stacked cards
2281
+ * wrap as usual). */
2282
+ .aura-tbl__th.is-wrap-anywhere, .aura-tbl__td.is-wrap-anywhere { overflow-wrap: anywhere; }
2283
+ .aura-tbl__th.is-nowrap, .aura-tbl__td.is-nowrap { white-space: nowrap; }
2220
2284
  @media (min-width: 640px) { .aura-tbl__th, .aura-tbl__td { min-width: 10ch; } }
2221
2285
  .aura-tbl__th:first-child, .aura-tbl__td:first-child { padding-left: var(--aura-space-6); }
2222
2286
  .aura-tbl__th:last-child, .aura-tbl__td:last-child { padding-right: var(--aura-space-6); }
@@ -2250,6 +2314,10 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
2250
2314
  }
2251
2315
  }
2252
2316
  .aura-tbl-wrap.is-sticky-box > .aura-tbl > .aura-tbl__head .aura-tbl__th { top: 0; }
2317
+ /* 5.60 (Chamber-OS 175): a table wider than its box scrolls sideways inside it, and that scroll box is what a sticky
2318
+ * header pins to — so the page offset (the shell bar) pushed the header down over the first row. Such a table can't
2319
+ * pin to the page: its header sits in flow (top 0 in a box that doesn't scroll down). */
2320
+ .aura-tbl-wrap.is-sticky-page.is-wide > .aura-tbl > .aura-tbl__head .aura-tbl__th { top: 0; }
2253
2321
  .aura-tbl-wrap:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: 2px; }
2254
2322
  /* 5.13 (Chamber-OS 81): align="middle" centres body and footer cells on their row; bordered={false} drops the frame and
2255
2323
  * the outer cells' side padding, so the table lines up with what's around it (a Card's heading). */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jirawatpyk/aura-react",
3
- "version": "5.58.0",
3
+ "version": "5.60.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",