@jirawatpyk/aura-react 5.28.0 → 5.29.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,14 @@ 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.29 — Chamber-OS addendum 37
190
+
191
+ - **DataTable loading rows match the rows they stand in for** (item 134), so the layout doesn't jump when the rows arrive:
192
+ - **Height:** with `rowHeight="auto"` skeleton rows get the same `--auto` class and minimum height as real rows. A column's new **`skeletonLines`** (default 1, at most 10; a `pill` column keeps one pill) draws that many bars, one per text line — `skeletonLines: 2` for a reason and its evidence. On an `align: 'end'` column they line up at the end. Each bar sits on a 20px body line in the grid (a caption line is 16–18px, so a row can come out a few px taller than the real one) and on the 15px value line in a card.
193
+ - **Stacked cards:** skeleton cards keep each field's label (`data-label`) above its bar, as a real card does.
194
+ - **Row actions:** an `actions` cell draws one square and a `card: 'footer'` cell a bar across the cell (in a card, the full row, as a Button there fills it), at the small button's height (32px), in the grid as well as in cards. When the column's buttons use `touchHeight`, give the column the new **`skeletonTouch`**: its bars are then 44px below 640px and on a coarse pointer, as those buttons are. A footer that holds only an IconButton still gets the full-width bar; the heights match.
195
+ - **Unchanged:** skeleton rows stay `aria-hidden`, the pulse stops under reduced motion, `skeletonRows`, `bleed` / `bleedEnd`. Without `rowHeight="auto"` the grid's skeleton rows keep the fixed row height.
196
+
189
197
  ## 5.28 — Chamber-OS addenda 35–36
190
198
 
191
199
  - **Applied-filter chips show their whole text** (item 132): in `FilterBar`'s chips row a chip takes its text's own width ("Submitted: 28 Aug – 3 Sept 2026", "Member: Midsommar Hospitality Co., Ltd."); only a chip wider than the row is cut, with an ellipsis, and a long chip never widens the FilterBar or its parents (the chips row takes its width from the bar; a bar holding only chips needs a width from its parent, as a block has). A Tag outside FilterBar keeps its 24ch cap. **Whenever a Tag's text is cut** — the 24ch cap or the row — the full text shows on hover (`title`) and, on a removable Tag, in a Tooltip on the remove button's hover and focus; the remove button's name already carries the full text for screen readers. On touch screens a cut chip can't be hovered — keep labels short enough for a phone row where you can.
@@ -6339,23 +6339,45 @@ window.Aura = (() => {
6339
6339
  /* @__PURE__ */ React32.createElement("span", { key: "__sel", className: cx("aura-table__sel", nPinned && "is-pinned") }, /* @__PURE__ */ React32.createElement("span", { className: "aura-skel aura-skel--box" }))
6340
6340
  );
6341
6341
  vis.forEach(function(c, j) {
6342
+ const part = cardPart(c, j);
6343
+ const action = part === "footer" || part === "actions";
6344
+ const lines = c.pill ? 1 : Math.max(1, Math.min(10, Math.floor(Number(c.skeletonLines)) || 1));
6345
+ const bar = function(n4) {
6346
+ return /* @__PURE__ */ React32.createElement(
6347
+ "span",
6348
+ {
6349
+ key: n4,
6350
+ className: cx("aura-skel", c.pill && "aura-skel--pill", lines > 1 && "aura-skel--text"),
6351
+ style: c.pill ? void 0 : { width: SKELETON_WIDTHS[(i + j + n4) % SKELETON_WIDTHS.length] }
6352
+ }
6353
+ );
6354
+ };
6355
+ const bars = [];
6356
+ for (let b = 0; b < lines; b++) bars.push(bar(b));
6342
6357
  sk.push(
6343
6358
  /* @__PURE__ */ React32.createElement(
6344
6359
  "span",
6345
6360
  {
6346
6361
  key: c.key,
6347
- className: cx("aura-table__td", c.align === "end" && "is-end", isPinned(c) && "is-pinned"),
6362
+ className: cx(
6363
+ "aura-table__td",
6364
+ autoRows && "aura-table__td--auto",
6365
+ c.align === "end" && "is-end",
6366
+ isPinned(c) && "is-pinned"
6367
+ ),
6348
6368
  style: cellStyle(c, j),
6349
- ...cardAttrs(c, j),
6350
- "data-label": void 0
6369
+ ...cardAttrs(c, j)
6351
6370
  },
6352
- /* @__PURE__ */ React32.createElement(
6371
+ action ? /* @__PURE__ */ React32.createElement(
6353
6372
  "span",
6354
6373
  {
6355
- className: cx("aura-skel", c.pill && "aura-skel--pill"),
6356
- style: c.pill ? void 0 : { width: SKELETON_WIDTHS[(i + j) % SKELETON_WIDTHS.length] }
6374
+ className: cx(
6375
+ "aura-skel aura-skel--action",
6376
+ part === "footer" && "is-footer",
6377
+ c.skeletonTouch && "is-touch"
6378
+ )
6357
6379
  }
6358
- )
6380
+ ) : lines > 1 ? /* @__PURE__ */ React32.createElement("span", { className: "aura-skel-lines" }, bars) : bars[0]
6359
6381
  )
6360
6382
  );
6361
6383
  });
@@ -6364,7 +6386,16 @@ window.Aura = (() => {
6364
6386
  /* @__PURE__ */ React32.createElement("span", { key: "__gr", className: cx("aura-table__gutter aura-table__gutter--end", controls && "has-picker") })
6365
6387
  );
6366
6388
  skRows.push(
6367
- /* @__PURE__ */ React32.createElement("div", { key: "sk" + i, className: "aura-table__row aura-table__row--skeleton", "aria-hidden": true, style: rowStyle }, sk)
6389
+ /* @__PURE__ */ React32.createElement(
6390
+ "div",
6391
+ {
6392
+ key: "sk" + i,
6393
+ className: cx("aura-table__row aura-table__row--skeleton", autoRows && "aura-table__row--auto"),
6394
+ "aria-hidden": true,
6395
+ style: rowStyle
6396
+ },
6397
+ sk
6398
+ )
6368
6399
  );
6369
6400
  }
6370
6401
  } else if (!rows.length) {
@@ -6321,23 +6321,45 @@ var DataTableImpl = React32.forwardRef(function DataTable(props, ref) {
6321
6321
  /* @__PURE__ */ React32.createElement("span", { key: "__sel", className: cx("aura-table__sel", nPinned && "is-pinned") }, /* @__PURE__ */ React32.createElement("span", { className: "aura-skel aura-skel--box" }))
6322
6322
  );
6323
6323
  vis.forEach(function(c, j) {
6324
+ const part = cardPart(c, j);
6325
+ const action = part === "footer" || part === "actions";
6326
+ const lines = c.pill ? 1 : Math.max(1, Math.min(10, Math.floor(Number(c.skeletonLines)) || 1));
6327
+ const bar = function(n4) {
6328
+ return /* @__PURE__ */ React32.createElement(
6329
+ "span",
6330
+ {
6331
+ key: n4,
6332
+ className: cx("aura-skel", c.pill && "aura-skel--pill", lines > 1 && "aura-skel--text"),
6333
+ style: c.pill ? void 0 : { width: SKELETON_WIDTHS[(i + j + n4) % SKELETON_WIDTHS.length] }
6334
+ }
6335
+ );
6336
+ };
6337
+ const bars = [];
6338
+ for (let b = 0; b < lines; b++) bars.push(bar(b));
6324
6339
  sk.push(
6325
6340
  /* @__PURE__ */ React32.createElement(
6326
6341
  "span",
6327
6342
  {
6328
6343
  key: c.key,
6329
- className: cx("aura-table__td", c.align === "end" && "is-end", isPinned(c) && "is-pinned"),
6344
+ className: cx(
6345
+ "aura-table__td",
6346
+ autoRows && "aura-table__td--auto",
6347
+ c.align === "end" && "is-end",
6348
+ isPinned(c) && "is-pinned"
6349
+ ),
6330
6350
  style: cellStyle(c, j),
6331
- ...cardAttrs(c, j),
6332
- "data-label": void 0
6351
+ ...cardAttrs(c, j)
6333
6352
  },
6334
- /* @__PURE__ */ React32.createElement(
6353
+ action ? /* @__PURE__ */ React32.createElement(
6335
6354
  "span",
6336
6355
  {
6337
- className: cx("aura-skel", c.pill && "aura-skel--pill"),
6338
- style: c.pill ? void 0 : { width: SKELETON_WIDTHS[(i + j) % SKELETON_WIDTHS.length] }
6356
+ className: cx(
6357
+ "aura-skel aura-skel--action",
6358
+ part === "footer" && "is-footer",
6359
+ c.skeletonTouch && "is-touch"
6360
+ )
6339
6361
  }
6340
- )
6362
+ ) : lines > 1 ? /* @__PURE__ */ React32.createElement("span", { className: "aura-skel-lines" }, bars) : bars[0]
6341
6363
  )
6342
6364
  );
6343
6365
  });
@@ -6346,7 +6368,16 @@ var DataTableImpl = React32.forwardRef(function DataTable(props, ref) {
6346
6368
  /* @__PURE__ */ React32.createElement("span", { key: "__gr", className: cx("aura-table__gutter aura-table__gutter--end", controls && "has-picker") })
6347
6369
  );
6348
6370
  skRows.push(
6349
- /* @__PURE__ */ React32.createElement("div", { key: "sk" + i, className: "aura-table__row aura-table__row--skeleton", "aria-hidden": true, style: rowStyle }, sk)
6371
+ /* @__PURE__ */ React32.createElement(
6372
+ "div",
6373
+ {
6374
+ key: "sk" + i,
6375
+ className: cx("aura-table__row aura-table__row--skeleton", autoRows && "aura-table__row--auto"),
6376
+ "aria-hidden": true,
6377
+ style: rowStyle
6378
+ },
6379
+ sk
6380
+ )
6350
6381
  );
6351
6382
  }
6352
6383
  } else if (!rows.length) {
@@ -1125,23 +1125,45 @@ const DataTableImpl = React.forwardRef(function DataTable(props, ref) {
1125
1125
  /* @__PURE__ */ React.createElement("span", { key: "__sel", className: cx("aura-table__sel", nPinned && "is-pinned") }, /* @__PURE__ */ React.createElement("span", { className: "aura-skel aura-skel--box" }))
1126
1126
  );
1127
1127
  vis.forEach(function(c, j) {
1128
+ const part = cardPart(c, j);
1129
+ const action = part === "footer" || part === "actions";
1130
+ const lines = c.pill ? 1 : Math.max(1, Math.min(10, Math.floor(Number(c.skeletonLines)) || 1));
1131
+ const bar = function(n2) {
1132
+ return /* @__PURE__ */ React.createElement(
1133
+ "span",
1134
+ {
1135
+ key: n2,
1136
+ className: cx("aura-skel", c.pill && "aura-skel--pill", lines > 1 && "aura-skel--text"),
1137
+ style: c.pill ? void 0 : { width: SKELETON_WIDTHS[(i + j + n2) % SKELETON_WIDTHS.length] }
1138
+ }
1139
+ );
1140
+ };
1141
+ const bars = [];
1142
+ for (let b = 0; b < lines; b++) bars.push(bar(b));
1128
1143
  sk.push(
1129
1144
  /* @__PURE__ */ React.createElement(
1130
1145
  "span",
1131
1146
  {
1132
1147
  key: c.key,
1133
- className: cx("aura-table__td", c.align === "end" && "is-end", isPinned(c) && "is-pinned"),
1148
+ className: cx(
1149
+ "aura-table__td",
1150
+ autoRows && "aura-table__td--auto",
1151
+ c.align === "end" && "is-end",
1152
+ isPinned(c) && "is-pinned"
1153
+ ),
1134
1154
  style: cellStyle(c, j),
1135
- ...cardAttrs(c, j),
1136
- "data-label": void 0
1155
+ ...cardAttrs(c, j)
1137
1156
  },
1138
- /* @__PURE__ */ React.createElement(
1157
+ action ? /* @__PURE__ */ React.createElement(
1139
1158
  "span",
1140
1159
  {
1141
- className: cx("aura-skel", c.pill && "aura-skel--pill"),
1142
- style: c.pill ? void 0 : { width: SKELETON_WIDTHS[(i + j) % SKELETON_WIDTHS.length] }
1160
+ className: cx(
1161
+ "aura-skel aura-skel--action",
1162
+ part === "footer" && "is-footer",
1163
+ c.skeletonTouch && "is-touch"
1164
+ )
1143
1165
  }
1144
- )
1166
+ ) : lines > 1 ? /* @__PURE__ */ React.createElement("span", { className: "aura-skel-lines" }, bars) : bars[0]
1145
1167
  )
1146
1168
  );
1147
1169
  });
@@ -1150,7 +1172,16 @@ const DataTableImpl = React.forwardRef(function DataTable(props, ref) {
1150
1172
  /* @__PURE__ */ React.createElement("span", { key: "__gr", className: cx("aura-table__gutter aura-table__gutter--end", controls && "has-picker") })
1151
1173
  );
1152
1174
  skRows.push(
1153
- /* @__PURE__ */ React.createElement("div", { key: "sk" + i, className: "aura-table__row aura-table__row--skeleton", "aria-hidden": true, style: rowStyle }, sk)
1175
+ /* @__PURE__ */ React.createElement(
1176
+ "div",
1177
+ {
1178
+ key: "sk" + i,
1179
+ className: cx("aura-table__row aura-table__row--skeleton", autoRows && "aura-table__row--auto"),
1180
+ "aria-hidden": true,
1181
+ style: rowStyle
1182
+ },
1183
+ sk
1184
+ )
1154
1185
  );
1155
1186
  }
1156
1187
  } else if (!rows.length) {
package/dist/index.d.cts CHANGED
@@ -114,6 +114,14 @@ export interface DataTableColumn<Row extends Record<string, any> = Record<string
114
114
  * after the half-width fields (in column order; `cardOrder` doesn't move it), its label above and its text wrapping —
115
115
  * a reason with its evidence. Default: today's rule. The grid is unchanged by any of them. */
116
116
  card?: "hide" | "field" | "title" | "pill" | "footer" | "wide" | undefined;
117
+ /** How many text lines its loading skeleton draws (5.29, Chamber-OS 134) — 2 for a cell that shows two lines (a
118
+ * reason and its evidence), so the skeleton row is as tall as the real one with `rowHeight="auto"`. Default 1, at
119
+ * most 10; ignored on a `pill` column. */
120
+ skeletonLines?: number | undefined;
121
+ /** For a `card: 'footer'` or `actions` column whose buttons use `touchHeight` (5.29, Chamber-OS 134): its loading
122
+ * skeleton's bar is 44px below 640px and on a coarse pointer, as those buttons are. Without it the bar is the small
123
+ * button's 32px. */
124
+ skeletonTouch?: boolean | undefined;
117
125
  /** The order of fields in a stacked card (5.13), lowest first; the grid's column order is unchanged. Fields
118
126
  * without one sort by their column index (0-based). Screen readers and arrow keys follow the grid's order. */
119
127
  cardOrder?: number | undefined;
package/dist/index.d.ts CHANGED
@@ -114,6 +114,14 @@ export interface DataTableColumn<Row extends Record<string, any> = Record<string
114
114
  * after the half-width fields (in column order; `cardOrder` doesn't move it), its label above and its text wrapping —
115
115
  * a reason with its evidence. Default: today's rule. The grid is unchanged by any of them. */
116
116
  card?: "hide" | "field" | "title" | "pill" | "footer" | "wide" | undefined;
117
+ /** How many text lines its loading skeleton draws (5.29, Chamber-OS 134) — 2 for a cell that shows two lines (a
118
+ * reason and its evidence), so the skeleton row is as tall as the real one with `rowHeight="auto"`. Default 1, at
119
+ * most 10; ignored on a `pill` column. */
120
+ skeletonLines?: number | undefined;
121
+ /** For a `card: 'footer'` or `actions` column whose buttons use `touchHeight` (5.29, Chamber-OS 134): its loading
122
+ * skeleton's bar is 44px below 640px and on a coarse pointer, as those buttons are. Without it the bar is the small
123
+ * button's 32px. */
124
+ skeletonTouch?: boolean | undefined;
117
125
  /** The order of fields in a stacked card (5.13), lowest first; the grid's column order is unchanged. Fields
118
126
  * without one sort by their column index (0-based). Screen readers and arrow keys follow the grid's order. */
119
127
  cardOrder?: number | undefined;
package/dist/styles.css CHANGED
@@ -338,6 +338,16 @@ a.aura-icon-btn { text-decoration: none; }
338
338
  .aura-skel--pill { width: 72px; height: 20px; }
339
339
  .aura-skel--box { width: var(--aura-icon-sm); height: var(--aura-icon-sm); border-radius: var(--aura-radius-xs); }
340
340
  @media (prefers-reduced-motion: reduce) { .aura-skel { animation: none; } }
341
+ /* 5.29 (Chamber-OS 134): a DataTable skeleton row stands in for the real one — text lines (skeletonLines) on the 20px
342
+ * line, and a button-height bar where row actions go: 32px, or 44px under the touchHeight rule with the column's
343
+ * skeletonTouch; full width in a card footer. */
344
+ .aura-skel--action { flex: none; width: var(--aura-button-height-sm); height: var(--aura-button-height-sm); border-radius: var(--aura-radius-md); }
345
+ .aura-skel--action.is-footer { width: 100%; }
346
+ .aura-table__td.is-end > .aura-skel-lines { align-items: flex-end; }
347
+ @media (max-width: 639.98px), (pointer: coarse) {
348
+ .aura-skel--action.is-touch { height: var(--aura-touch-target); }
349
+ .aura-skel--action.is-touch:not(.is-footer) { width: var(--aura-touch-target); }
350
+ }
341
351
  .aura-sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
342
352
 
343
353
  /* Empty state */
@@ -1952,6 +1962,12 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
1952
1962
  /* 5.22: a footer row ends the card with no margin under it, so the card keeps its full 16px. */
1953
1963
  .aura-table__row:has(> [data-card='footer']:not(.is-blank)) { padding-bottom: var(--aura-space-4); }
1954
1964
  .aura-table__row--skeleton .aura-table__td { display: flex; }
1965
+ /* 5.29: a skeleton field shows its label above a bar on the field's value line (15px: 13px text, normal line
1966
+ * height — 1lh, so it follows the font), as a real field does; the title keeps the 20px line. */
1967
+ .aura-table__row--skeleton .aura-table__td[data-label] { flex-direction: column; align-items: stretch; }
1968
+ .aura-table__row--skeleton .aura-table__td > .aura-skel:not(.aura-skel--pill):not(.aura-skel--action) { margin: 5px 0; }
1969
+ .aura-table__row--skeleton .aura-table__td[data-label] .aura-skel:not(.aura-skel--pill):not(.aura-skel--action) { margin: 2.5px 0; margin: calc((1lh - 10px) / 2) 0; }
1970
+ .aura-table__row--skeleton .aura-table__td > .aura-skel-lines { align-items: flex-start; }
1955
1971
  .aura-table__total { background: var(--aura-bg-canvas); }
1956
1972
  .aura-table__total > .is-blank { display: none; }
1957
1973
  .aura-table__foot { border: 1px solid var(--aura-border-default); border-radius: var(--aura-radius-lg); margin-top: var(--aura-space-2); background: var(--aura-bg-surface); }
@@ -340,6 +340,16 @@ a.aura-icon-btn { text-decoration: none; }
340
340
  .aura-skel--pill { width: 72px; height: 20px; }
341
341
  .aura-skel--box { width: var(--aura-icon-sm); height: var(--aura-icon-sm); border-radius: var(--aura-radius-xs); }
342
342
  @media (prefers-reduced-motion: reduce) { .aura-skel { animation: none; } }
343
+ /* 5.29 (Chamber-OS 134): a DataTable skeleton row stands in for the real one — text lines (skeletonLines) on the 20px
344
+ * line, and a button-height bar where row actions go: 32px, or 44px under the touchHeight rule with the column's
345
+ * skeletonTouch; full width in a card footer. */
346
+ .aura-skel--action { flex: none; width: var(--aura-button-height-sm); height: var(--aura-button-height-sm); border-radius: var(--aura-radius-md); }
347
+ .aura-skel--action.is-footer { width: 100%; }
348
+ .aura-table__td.is-end > .aura-skel-lines { align-items: flex-end; }
349
+ @media (max-width: 639.98px), (pointer: coarse) {
350
+ .aura-skel--action.is-touch { height: var(--aura-touch-target); }
351
+ .aura-skel--action.is-touch:not(.is-footer) { width: var(--aura-touch-target); }
352
+ }
343
353
  .aura-sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
344
354
 
345
355
  /* Empty state */
@@ -1954,6 +1964,12 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
1954
1964
  /* 5.22: a footer row ends the card with no margin under it, so the card keeps its full 16px. */
1955
1965
  .aura-table__row:has(> [data-card='footer']:not(.is-blank)) { padding-bottom: var(--aura-space-4); }
1956
1966
  .aura-table__row--skeleton .aura-table__td { display: flex; }
1967
+ /* 5.29: a skeleton field shows its label above a bar on the field's value line (15px: 13px text, normal line
1968
+ * height — 1lh, so it follows the font), as a real field does; the title keeps the 20px line. */
1969
+ .aura-table__row--skeleton .aura-table__td[data-label] { flex-direction: column; align-items: stretch; }
1970
+ .aura-table__row--skeleton .aura-table__td > .aura-skel:not(.aura-skel--pill):not(.aura-skel--action) { margin: 5px 0; }
1971
+ .aura-table__row--skeleton .aura-table__td[data-label] .aura-skel:not(.aura-skel--pill):not(.aura-skel--action) { margin: 2.5px 0; margin: calc((1lh - 10px) / 2) 0; }
1972
+ .aura-table__row--skeleton .aura-table__td > .aura-skel-lines { align-items: flex-start; }
1957
1973
  .aura-table__total { background: var(--aura-bg-canvas); }
1958
1974
  .aura-table__total > .is-blank { display: none; }
1959
1975
  .aura-table__foot { border: 1px solid var(--aura-border-default); border-radius: var(--aura-radius-lg); margin-top: var(--aura-space-2); background: var(--aura-bg-surface); }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jirawatpyk/aura-react",
3
- "version": "5.28.0",
3
+ "version": "5.29.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",