@jirawatpyk/aura-react 5.78.0 → 5.79.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.79 — visual audit, set 3 (component by component)
190
+
191
+ - **One disabled look for every Button variant:** a faint fill (`--aura-button-disabled-bg`: zinc-100 light, none in dark), a faint edge (`--aura-button-disabled-border` — the variant's own border, or 1px inside for primary and danger) and the tertiary label, at full opacity — primary, secondary, danger, creative and `aria-disabled` alike; a ghost button has neither fill nor edge. (5.30 gave filled buttons a grey fill that read as a To Do pill and faded outline ones.)
192
+ - **ActionBar `look="edge"` in an AppShell on a desktop** starts after the sidebar (the rail width when collapsed; the right edge in RTL) and lines its contents up with the content's 32px padding (not with `contentPadding={false}`), instead of running under the sidebar. It reads the sidebar's width from `--aura-sidenav-width` / `--aura-sidenav-rail-width`: to change it, set the token on `.aura-shell` or `:root`, not on the nav — and a custom `nav` set them to its width. Outside an AppShell it keeps the screen's width; `edgeBelow` is unchanged (no sidebar there).
193
+ - **A list box** (`<Select multiple>` or `size` > 1) shows its rows, as tall as they need, without the chevron.
194
+ - **Combobox `multiple`:** a chip no longer shrinks to "V.."; it keeps its label and moves to the next line (a label wider than the field still ends in "…").
195
+ - **Switch with an `icon`** (a locked, read-only switch): the lock sits 8px after the label, not at the row's far end. Its colours stay as 5.19 set them.
196
+ - **Menu / DropdownMenu:** a menu whose items have no icon, check box or radio has no empty icon column; it opens on its trigger's left edge when ending on its right would cross the screen (LTR; positioning stays physical, as before); and it is lifted with `--aura-shadow-overlay`, as Popover and the list boxes.
197
+ - **Small fixes:** FileUpload's hint names formats (PNG, JPEG, SVG, DOCX, XLSX), not "IMAGE/PNG"; an outline Badge has a quieter edge (its colour at 45%), so it doesn't read as a secondary Button; a date range is a violet-100 band in light (`--aura-calendar-range-bg`, the brand's 100 step in `createTheme`), visible on white; a disabled field's edge shows in dark (`--aura-input-disabled-border`, zinc-700).
198
+ - **Thai:** a Calendar with a Thai locale carries `lang="th"` and its weekday row is 13px; two-line Thai SideNav labels get room between lines; Combobox options have fixed line heights, so Thai and English rows are spaced alike.
199
+ - **PageHeader:** where `actionsFullWidthBelow` reaches wider than `actionsBarBelow`, every button in the row is `radius-md` between the two breakpoints (5.78 left the bar's buttons as pills there).
200
+ - **Stories:** the ⋯ beside outline buttons in action rows is `variant="outline"` (keep it so in an action row); the launch page shows with its own styles.
201
+
189
202
  ## 5.78 — visual audit, set 2 (phones)
190
203
 
191
204
  - **Bottom strips on a phone follow one rule:** ActionBar's edge strip (`look="edge"`, `edgeBelow`) now lays out as PageHeader's bar (5.48) — the status on its own row at the top, the actions sharing the row under it (an IconButton keeps its square; labels too long to share take a row each, as PageHeader's) — and both strips are 16px from either side, the page's phone gutter (they were 16 and 12). `edgeBelow="md"` follows it up to 768px. A single label wider than the screen still overflows, as in PageHeader's strip — keep bar labels short.
@@ -1929,7 +1929,8 @@ window.Aura = (() => {
1929
1929
  top = r2.top - above - 4;
1930
1930
  } else maxHeight = below2;
1931
1931
  }
1932
- const left = Math.max(8, Math.min(r2.right - mw, window.innerWidth - mw - 8));
1932
+ const endAligned = r2.right - mw;
1933
+ const left = Math.max(8, Math.min(endAligned >= 8 ? endAligned : r2.left, window.innerWidth - mw - 8));
1933
1934
  setPos(function(p) {
1934
1935
  return p && p.top === top && p.left === left && p.maxHeight === maxHeight ? p : { top, left, maxHeight };
1935
1936
  });
@@ -2028,12 +2029,15 @@ window.Aura = (() => {
2028
2029
  });
2029
2030
  return out;
2030
2031
  }
2032
+ const anyLead = items2.some(function(it) {
2033
+ return !it.separator && (!!it.icon || it.type === "radio" || it.checked !== void 0);
2034
+ });
2031
2035
  function renderItem(it, i) {
2032
2036
  if (it.separator) return /* @__PURE__ */ React9.createElement("div", { key: "s" + i, role: "separator", className: "aura-menu__sep" });
2033
2037
  const isRadio = it.type === "radio";
2034
2038
  const isCheck = !isRadio && it.checked !== void 0;
2035
2039
  const checkAtEnd = isCheck && !!it.icon && it.checkPlacement !== "start";
2036
- const lead = isRadio ? /* @__PURE__ */ React9.createElement("span", { className: cx("aura-menu__radio", it.checked && "is-on") }) : isCheck && !checkAtEnd ? /* @__PURE__ */ React9.createElement("span", { className: cx("aura-menu__check", it.checked && "is-on") }, it.checked ? /* @__PURE__ */ React9.createElement(Icon, { name: /* @__PURE__ */ React9.createElement(IconCheck, null), size: 12, strokeWidth: 3 }) : null) : it.icon ? /* @__PURE__ */ React9.createElement(Icon, { name: it.icon }) : /* @__PURE__ */ React9.createElement("span", { className: "aura-menu__blank" });
2040
+ const lead = isRadio ? /* @__PURE__ */ React9.createElement("span", { className: cx("aura-menu__radio", it.checked && "is-on") }) : isCheck && !checkAtEnd ? /* @__PURE__ */ React9.createElement("span", { className: cx("aura-menu__check", it.checked && "is-on") }, it.checked ? /* @__PURE__ */ React9.createElement(Icon, { name: /* @__PURE__ */ React9.createElement(IconCheck, null), size: 12, strokeWidth: 3 }) : null) : it.icon ? /* @__PURE__ */ React9.createElement(Icon, { name: it.icon }) : anyLead ? /* @__PURE__ */ React9.createElement("span", { className: "aura-menu__blank" }) : null;
2037
2041
  const body = [
2038
2042
  /* @__PURE__ */ React9.createElement(React9.Fragment, { key: "l" }, lead),
2039
2043
  /* @__PURE__ */ React9.createElement("span", { key: "t", className: "aura-menu__label" }, it.label),
@@ -3444,7 +3448,7 @@ window.Aura = (() => {
3444
3448
  setFocus(addMonths(focusDate, 1));
3445
3449
  }
3446
3450
  }
3447
- )), /* @__PURE__ */ React18.createElement("table", { role: "grid", className: "aura-cal__grid", "aria-label": monthTitle }, /* @__PURE__ */ React18.createElement("thead", null, /* @__PURE__ */ React18.createElement("tr", null, weekdayNames.map(function(n3, i) {
3451
+ )), /* @__PURE__ */ React18.createElement("table", { role: "grid", className: "aura-cal__grid", "aria-label": monthTitle, lang: th2 ? "th" : void 0 }, /* @__PURE__ */ React18.createElement("thead", null, /* @__PURE__ */ React18.createElement("tr", null, weekdayNames.map(function(n3, i) {
3448
3452
  return /* @__PURE__ */ React18.createElement("th", { key: i, scope: "col", abbr: n3.long }, /* @__PURE__ */ React18.createElement("span", { "aria-hidden": true }, n3.short));
3449
3453
  }))), /* @__PURE__ */ React18.createElement(
3450
3454
  "tbody",
@@ -10074,6 +10078,19 @@ window.Aura = (() => {
10074
10078
  a = a.trim();
10075
10079
  if (a === "image/*") return t.images;
10076
10080
  if (a === "application/pdf") return "PDF";
10081
+ const known = {
10082
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document": "DOCX",
10083
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "XLSX",
10084
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation": "PPTX",
10085
+ "application/msword": "DOC",
10086
+ "application/vnd.ms-excel": "XLS",
10087
+ "application/vnd.ms-powerpoint": "PPT",
10088
+ "text/plain": "TXT"
10089
+ };
10090
+ if (known[a]) return known[a];
10091
+ const slash = a.indexOf("/");
10092
+ if (slash > 0 && a.slice(slash + 1) !== "*")
10093
+ a = a.slice(slash + 1).replace(/^(?:vnd\.|x-)/, "").replace(/\+xml$/, "");
10077
10094
  return a.replace(/^\./, "").toUpperCase();
10078
10095
  }).filter(function(x, i, arr) {
10079
10096
  return arr.indexOf(x) === i;
@@ -10482,6 +10499,7 @@ window.Aura = (() => {
10482
10499
  L["accent-violet"] = L["fg-accent"];
10483
10500
  L["focus-ring"] = fit(b[700], lightGrounds.concat([b[50]]), 3, -1);
10484
10501
  L["bg-selected"] = b[50];
10502
+ L["calendar-range-bg"] = b[100];
10485
10503
  L["status-progress-bg"] = b[100];
10486
10504
  L["status-progress-fg"] = fit(b[800], [b[100]], 4.5, -1);
10487
10505
  L["alert-info-bg"] = b[50];
@@ -10521,6 +10539,7 @@ window.Aura = (() => {
10521
10539
  D["control-checked-bg"] = fit(b[300], darkGrounds, 3, 1);
10522
10540
  D["control-checked-fg"] = onFill(D["control-checked-bg"]);
10523
10541
  D["nav-active-edge"] = D["control-checked-bg"];
10542
+ D["calendar-range-bg"] = D["bg-selected"];
10524
10543
  const shadowLight = INK, shadowDark = D["accent-violet"];
10525
10544
  if (o.primary === "brand") {
10526
10545
  L["button-primary-bg"] = fit(b[600], [ZINC[0]], 4.5, -1);
@@ -10578,6 +10597,7 @@ window.Aura = (() => {
10578
10597
  check("dark", "chart-1", "chart-2 (lightness step)", 1.8, D["chart-1"], CHART_2);
10579
10598
  check("light", "fg-primary", "bg-selected", 4.5, INK, L["bg-selected"]);
10580
10599
  check("dark", "fg-primary", "bg-selected", 4.5, "#ffffff", D["bg-selected"]);
10600
+ check("light", "fg-primary", "calendar-range-bg", 4.5, INK, L["calendar-range-bg"]);
10581
10601
  check("light", "status-progress-fg", "status-progress-bg", 4.5, L["status-progress-fg"], L["status-progress-bg"]);
10582
10602
  check("dark", "status-progress-fg", "status-progress-bg", 4.5, D["status-progress-fg"], D["status-progress-bg"]);
10583
10603
  check("light", "alert-info-fg", "alert-info-bg", 4.5, L["alert-info-fg"], L["alert-info-bg"]);
@@ -1911,7 +1911,8 @@ var Menu = React9.forwardRef(function Menu2(props, ref) {
1911
1911
  top = r2.top - above - 4;
1912
1912
  } else maxHeight = below2;
1913
1913
  }
1914
- const left = Math.max(8, Math.min(r2.right - mw, window.innerWidth - mw - 8));
1914
+ const endAligned = r2.right - mw;
1915
+ const left = Math.max(8, Math.min(endAligned >= 8 ? endAligned : r2.left, window.innerWidth - mw - 8));
1915
1916
  setPos(function(p) {
1916
1917
  return p && p.top === top && p.left === left && p.maxHeight === maxHeight ? p : { top, left, maxHeight };
1917
1918
  });
@@ -2010,12 +2011,15 @@ var Menu = React9.forwardRef(function Menu2(props, ref) {
2010
2011
  });
2011
2012
  return out;
2012
2013
  }
2014
+ const anyLead = items2.some(function(it) {
2015
+ return !it.separator && (!!it.icon || it.type === "radio" || it.checked !== void 0);
2016
+ });
2013
2017
  function renderItem(it, i) {
2014
2018
  if (it.separator) return /* @__PURE__ */ React9.createElement("div", { key: "s" + i, role: "separator", className: "aura-menu__sep" });
2015
2019
  const isRadio = it.type === "radio";
2016
2020
  const isCheck = !isRadio && it.checked !== void 0;
2017
2021
  const checkAtEnd = isCheck && !!it.icon && it.checkPlacement !== "start";
2018
- const lead = isRadio ? /* @__PURE__ */ React9.createElement("span", { className: cx("aura-menu__radio", it.checked && "is-on") }) : isCheck && !checkAtEnd ? /* @__PURE__ */ React9.createElement("span", { className: cx("aura-menu__check", it.checked && "is-on") }, it.checked ? /* @__PURE__ */ React9.createElement(Icon, { name: /* @__PURE__ */ React9.createElement(IconCheck, null), size: 12, strokeWidth: 3 }) : null) : it.icon ? /* @__PURE__ */ React9.createElement(Icon, { name: it.icon }) : /* @__PURE__ */ React9.createElement("span", { className: "aura-menu__blank" });
2022
+ const lead = isRadio ? /* @__PURE__ */ React9.createElement("span", { className: cx("aura-menu__radio", it.checked && "is-on") }) : isCheck && !checkAtEnd ? /* @__PURE__ */ React9.createElement("span", { className: cx("aura-menu__check", it.checked && "is-on") }, it.checked ? /* @__PURE__ */ React9.createElement(Icon, { name: /* @__PURE__ */ React9.createElement(IconCheck, null), size: 12, strokeWidth: 3 }) : null) : it.icon ? /* @__PURE__ */ React9.createElement(Icon, { name: it.icon }) : anyLead ? /* @__PURE__ */ React9.createElement("span", { className: "aura-menu__blank" }) : null;
2019
2023
  const body = [
2020
2024
  /* @__PURE__ */ React9.createElement(React9.Fragment, { key: "l" }, lead),
2021
2025
  /* @__PURE__ */ React9.createElement("span", { key: "t", className: "aura-menu__label" }, it.label),
@@ -3426,7 +3430,7 @@ var Calendar = React18.forwardRef(function Calendar2(props, ref) {
3426
3430
  setFocus(addMonths(focusDate, 1));
3427
3431
  }
3428
3432
  }
3429
- )), /* @__PURE__ */ React18.createElement("table", { role: "grid", className: "aura-cal__grid", "aria-label": monthTitle }, /* @__PURE__ */ React18.createElement("thead", null, /* @__PURE__ */ React18.createElement("tr", null, weekdayNames.map(function(n3, i) {
3433
+ )), /* @__PURE__ */ React18.createElement("table", { role: "grid", className: "aura-cal__grid", "aria-label": monthTitle, lang: th2 ? "th" : void 0 }, /* @__PURE__ */ React18.createElement("thead", null, /* @__PURE__ */ React18.createElement("tr", null, weekdayNames.map(function(n3, i) {
3430
3434
  return /* @__PURE__ */ React18.createElement("th", { key: i, scope: "col", abbr: n3.long }, /* @__PURE__ */ React18.createElement("span", { "aria-hidden": true }, n3.short));
3431
3435
  }))), /* @__PURE__ */ React18.createElement(
3432
3436
  "tbody",
@@ -10056,6 +10060,19 @@ function describeAccept(accept, t) {
10056
10060
  a = a.trim();
10057
10061
  if (a === "image/*") return t.images;
10058
10062
  if (a === "application/pdf") return "PDF";
10063
+ const known = {
10064
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document": "DOCX",
10065
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "XLSX",
10066
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation": "PPTX",
10067
+ "application/msword": "DOC",
10068
+ "application/vnd.ms-excel": "XLS",
10069
+ "application/vnd.ms-powerpoint": "PPT",
10070
+ "text/plain": "TXT"
10071
+ };
10072
+ if (known[a]) return known[a];
10073
+ const slash = a.indexOf("/");
10074
+ if (slash > 0 && a.slice(slash + 1) !== "*")
10075
+ a = a.slice(slash + 1).replace(/^(?:vnd\.|x-)/, "").replace(/\+xml$/, "");
10059
10076
  return a.replace(/^\./, "").toUpperCase();
10060
10077
  }).filter(function(x, i, arr) {
10061
10078
  return arr.indexOf(x) === i;
@@ -10464,6 +10481,7 @@ function createTheme(opts) {
10464
10481
  L["accent-violet"] = L["fg-accent"];
10465
10482
  L["focus-ring"] = fit(b[700], lightGrounds.concat([b[50]]), 3, -1);
10466
10483
  L["bg-selected"] = b[50];
10484
+ L["calendar-range-bg"] = b[100];
10467
10485
  L["status-progress-bg"] = b[100];
10468
10486
  L["status-progress-fg"] = fit(b[800], [b[100]], 4.5, -1);
10469
10487
  L["alert-info-bg"] = b[50];
@@ -10503,6 +10521,7 @@ function createTheme(opts) {
10503
10521
  D["control-checked-bg"] = fit(b[300], darkGrounds, 3, 1);
10504
10522
  D["control-checked-fg"] = onFill(D["control-checked-bg"]);
10505
10523
  D["nav-active-edge"] = D["control-checked-bg"];
10524
+ D["calendar-range-bg"] = D["bg-selected"];
10506
10525
  const shadowLight = INK, shadowDark = D["accent-violet"];
10507
10526
  if (o.primary === "brand") {
10508
10527
  L["button-primary-bg"] = fit(b[600], [ZINC[0]], 4.5, -1);
@@ -10560,6 +10579,7 @@ function createTheme(opts) {
10560
10579
  check("dark", "chart-1", "chart-2 (lightness step)", 1.8, D["chart-1"], CHART_2);
10561
10580
  check("light", "fg-primary", "bg-selected", 4.5, INK, L["bg-selected"]);
10562
10581
  check("dark", "fg-primary", "bg-selected", 4.5, "#ffffff", D["bg-selected"]);
10582
+ check("light", "fg-primary", "calendar-range-bg", 4.5, INK, L["calendar-range-bg"]);
10563
10583
  check("light", "status-progress-fg", "status-progress-bg", 4.5, L["status-progress-fg"], L["status-progress-bg"]);
10564
10584
  check("dark", "status-progress-fg", "status-progress-bg", 4.5, D["status-progress-fg"], D["status-progress-bg"]);
10565
10585
  check("light", "alert-info-fg", "alert-info-bg", 4.5, L["alert-info-fg"], L["alert-info-bg"]);
@@ -226,7 +226,7 @@ const Calendar = React.forwardRef(function Calendar2(props, ref) {
226
226
  setFocus(addMonths(focusDate, 1));
227
227
  }
228
228
  }
229
- )), /* @__PURE__ */ React.createElement("table", { role: "grid", className: "aura-cal__grid", "aria-label": monthTitle }, /* @__PURE__ */ React.createElement("thead", null, /* @__PURE__ */ React.createElement("tr", null, weekdayNames.map(function(n, i) {
229
+ )), /* @__PURE__ */ React.createElement("table", { role: "grid", className: "aura-cal__grid", "aria-label": monthTitle, lang: th ? "th" : void 0 }, /* @__PURE__ */ React.createElement("thead", null, /* @__PURE__ */ React.createElement("tr", null, weekdayNames.map(function(n, i) {
230
230
  return /* @__PURE__ */ React.createElement("th", { key: i, scope: "col", abbr: n.long }, /* @__PURE__ */ React.createElement("span", { "aria-hidden": true }, n.short));
231
231
  }))), /* @__PURE__ */ React.createElement(
232
232
  "tbody",
@@ -26,6 +26,19 @@ function describeAccept(accept, t) {
26
26
  a = a.trim();
27
27
  if (a === "image/*") return t.images;
28
28
  if (a === "application/pdf") return "PDF";
29
+ const known = {
30
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document": "DOCX",
31
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "XLSX",
32
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation": "PPTX",
33
+ "application/msword": "DOC",
34
+ "application/vnd.ms-excel": "XLS",
35
+ "application/vnd.ms-powerpoint": "PPT",
36
+ "text/plain": "TXT"
37
+ };
38
+ if (known[a]) return known[a];
39
+ const slash = a.indexOf("/");
40
+ if (slash > 0 && a.slice(slash + 1) !== "*")
41
+ a = a.slice(slash + 1).replace(/^(?:vnd\.|x-)/, "").replace(/\+xml$/, "");
29
42
  return a.replace(/^\./, "").toUpperCase();
30
43
  }).filter(function(x, i, arr) {
31
44
  return arr.indexOf(x) === i;
package/dist/esm/Menu.js CHANGED
@@ -61,7 +61,8 @@ const Menu = React.forwardRef(function Menu2(props, ref) {
61
61
  top = r.top - above - 4;
62
62
  } else maxHeight = below;
63
63
  }
64
- const left = Math.max(8, Math.min(r.right - mw, window.innerWidth - mw - 8));
64
+ const endAligned = r.right - mw;
65
+ const left = Math.max(8, Math.min(endAligned >= 8 ? endAligned : r.left, window.innerWidth - mw - 8));
65
66
  setPos(function(p) {
66
67
  return p && p.top === top && p.left === left && p.maxHeight === maxHeight ? p : { top, left, maxHeight };
67
68
  });
@@ -160,12 +161,15 @@ const Menu = React.forwardRef(function Menu2(props, ref) {
160
161
  });
161
162
  return out;
162
163
  }
164
+ const anyLead = items.some(function(it) {
165
+ return !it.separator && (!!it.icon || it.type === "radio" || it.checked !== void 0);
166
+ });
163
167
  function renderItem(it, i) {
164
168
  if (it.separator) return /* @__PURE__ */ React.createElement("div", { key: "s" + i, role: "separator", className: "aura-menu__sep" });
165
169
  const isRadio = it.type === "radio";
166
170
  const isCheck = !isRadio && it.checked !== void 0;
167
171
  const checkAtEnd = isCheck && !!it.icon && it.checkPlacement !== "start";
168
- const lead = isRadio ? /* @__PURE__ */ React.createElement("span", { className: cx("aura-menu__radio", it.checked && "is-on") }) : isCheck && !checkAtEnd ? /* @__PURE__ */ React.createElement("span", { className: cx("aura-menu__check", it.checked && "is-on") }, it.checked ? /* @__PURE__ */ React.createElement(Icon, { name: /* @__PURE__ */ React.createElement(IconCheck, null), size: 12, strokeWidth: 3 }) : null) : it.icon ? /* @__PURE__ */ React.createElement(Icon, { name: it.icon }) : /* @__PURE__ */ React.createElement("span", { className: "aura-menu__blank" });
172
+ const lead = isRadio ? /* @__PURE__ */ React.createElement("span", { className: cx("aura-menu__radio", it.checked && "is-on") }) : isCheck && !checkAtEnd ? /* @__PURE__ */ React.createElement("span", { className: cx("aura-menu__check", it.checked && "is-on") }, it.checked ? /* @__PURE__ */ React.createElement(Icon, { name: /* @__PURE__ */ React.createElement(IconCheck, null), size: 12, strokeWidth: 3 }) : null) : it.icon ? /* @__PURE__ */ React.createElement(Icon, { name: it.icon }) : anyLead ? /* @__PURE__ */ React.createElement("span", { className: "aura-menu__blank" }) : null;
169
173
  const body = [
170
174
  /* @__PURE__ */ React.createElement(React.Fragment, { key: "l" }, lead),
171
175
  /* @__PURE__ */ React.createElement("span", { key: "t", className: "aura-menu__label" }, it.label),
package/dist/esm/theme.js CHANGED
@@ -131,6 +131,7 @@ function createTheme(opts) {
131
131
  L["accent-violet"] = L["fg-accent"];
132
132
  L["focus-ring"] = fit(b[700], lightGrounds.concat([b[50]]), 3, -1);
133
133
  L["bg-selected"] = b[50];
134
+ L["calendar-range-bg"] = b[100];
134
135
  L["status-progress-bg"] = b[100];
135
136
  L["status-progress-fg"] = fit(b[800], [b[100]], 4.5, -1);
136
137
  L["alert-info-bg"] = b[50];
@@ -170,6 +171,7 @@ function createTheme(opts) {
170
171
  D["control-checked-bg"] = fit(b[300], darkGrounds, 3, 1);
171
172
  D["control-checked-fg"] = onFill(D["control-checked-bg"]);
172
173
  D["nav-active-edge"] = D["control-checked-bg"];
174
+ D["calendar-range-bg"] = D["bg-selected"];
173
175
  const shadowLight = INK, shadowDark = D["accent-violet"];
174
176
  if (o.primary === "brand") {
175
177
  L["button-primary-bg"] = fit(b[600], [ZINC[0]], 4.5, -1);
@@ -227,6 +229,7 @@ function createTheme(opts) {
227
229
  check("dark", "chart-1", "chart-2 (lightness step)", 1.8, D["chart-1"], CHART_2);
228
230
  check("light", "fg-primary", "bg-selected", 4.5, INK, L["bg-selected"]);
229
231
  check("dark", "fg-primary", "bg-selected", 4.5, "#ffffff", D["bg-selected"]);
232
+ check("light", "fg-primary", "calendar-range-bg", 4.5, INK, L["calendar-range-bg"]);
230
233
  check("light", "status-progress-fg", "status-progress-bg", 4.5, L["status-progress-fg"], L["status-progress-bg"]);
231
234
  check("dark", "status-progress-fg", "status-progress-bg", 4.5, D["status-progress-fg"], D["status-progress-bg"]);
232
235
  check("light", "alert-info-fg", "alert-info-bg", 4.5, L["alert-info-fg"], L["alert-info-bg"]);
@@ -780,6 +780,7 @@ function createTheme(opts) {
780
780
  L["accent-violet"] = L["fg-accent"];
781
781
  L["focus-ring"] = fit(b[700], lightGrounds.concat([b[50]]), 3, -1);
782
782
  L["bg-selected"] = b[50];
783
+ L["calendar-range-bg"] = b[100];
783
784
  L["status-progress-bg"] = b[100];
784
785
  L["status-progress-fg"] = fit(b[800], [b[100]], 4.5, -1);
785
786
  L["alert-info-bg"] = b[50];
@@ -819,6 +820,7 @@ function createTheme(opts) {
819
820
  D["control-checked-bg"] = fit(b[300], darkGrounds, 3, 1);
820
821
  D["control-checked-fg"] = onFill(D["control-checked-bg"]);
821
822
  D["nav-active-edge"] = D["control-checked-bg"];
823
+ D["calendar-range-bg"] = D["bg-selected"];
822
824
  const shadowLight = INK, shadowDark = D["accent-violet"];
823
825
  if (o.primary === "brand") {
824
826
  L["button-primary-bg"] = fit(b[600], [ZINC[0]], 4.5, -1);
@@ -876,6 +878,7 @@ function createTheme(opts) {
876
878
  check("dark", "chart-1", "chart-2 (lightness step)", 1.8, D["chart-1"], CHART_2);
877
879
  check("light", "fg-primary", "bg-selected", 4.5, INK, L["bg-selected"]);
878
880
  check("dark", "fg-primary", "bg-selected", 4.5, "#ffffff", D["bg-selected"]);
881
+ check("light", "fg-primary", "calendar-range-bg", 4.5, INK, L["calendar-range-bg"]);
879
882
  check("light", "status-progress-fg", "status-progress-bg", 4.5, L["status-progress-fg"], L["status-progress-bg"]);
880
883
  check("dark", "status-progress-fg", "status-progress-bg", 4.5, D["status-progress-fg"], D["status-progress-bg"]);
881
884
  check("light", "alert-info-fg", "alert-info-bg", 4.5, L["alert-info-fg"], L["alert-info-bg"]);
@@ -713,6 +713,7 @@ function createTheme(opts) {
713
713
  L["accent-violet"] = L["fg-accent"];
714
714
  L["focus-ring"] = fit(b[700], lightGrounds.concat([b[50]]), 3, -1);
715
715
  L["bg-selected"] = b[50];
716
+ L["calendar-range-bg"] = b[100];
716
717
  L["status-progress-bg"] = b[100];
717
718
  L["status-progress-fg"] = fit(b[800], [b[100]], 4.5, -1);
718
719
  L["alert-info-bg"] = b[50];
@@ -752,6 +753,7 @@ function createTheme(opts) {
752
753
  D["control-checked-bg"] = fit(b[300], darkGrounds, 3, 1);
753
754
  D["control-checked-fg"] = onFill(D["control-checked-bg"]);
754
755
  D["nav-active-edge"] = D["control-checked-bg"];
756
+ D["calendar-range-bg"] = D["bg-selected"];
755
757
  const shadowLight = INK, shadowDark = D["accent-violet"];
756
758
  if (o.primary === "brand") {
757
759
  L["button-primary-bg"] = fit(b[600], [ZINC[0]], 4.5, -1);
@@ -809,6 +811,7 @@ function createTheme(opts) {
809
811
  check("dark", "chart-1", "chart-2 (lightness step)", 1.8, D["chart-1"], CHART_2);
810
812
  check("light", "fg-primary", "bg-selected", 4.5, INK, L["bg-selected"]);
811
813
  check("dark", "fg-primary", "bg-selected", 4.5, "#ffffff", D["bg-selected"]);
814
+ check("light", "fg-primary", "calendar-range-bg", 4.5, INK, L["calendar-range-bg"]);
812
815
  check("light", "status-progress-fg", "status-progress-bg", 4.5, L["status-progress-fg"], L["status-progress-bg"]);
813
816
  check("dark", "status-progress-fg", "status-progress-bg", 4.5, D["status-progress-fg"], D["status-progress-bg"]);
814
817
  check("light", "alert-info-fg", "alert-info-bg", 4.5, L["alert-info-fg"], L["alert-info-bg"]);
package/dist/styles.css CHANGED
@@ -50,18 +50,28 @@ button.aura-btn--secondary[aria-disabled='true']:hover, button.aura-btn--ghost[a
50
50
  button.aura-btn--danger-secondary[aria-disabled='true']:hover { background: transparent; }
51
51
  button.aura-btn--danger[aria-disabled='true']:hover { background: var(--aura-button-danger-bg); }
52
52
  button.aura-btn--creative[aria-disabled='true']:hover { box-shadow: var(--aura-shadow-creative); transform: none; }
53
- /* 5.30: a disabled filled button (primary, danger, creative) is a quiet grey fill with muted text, not a faded copy of
54
- * itself — faded ink read as a separate grey button, faded red as pink. Outline and ghost buttons keep the fade. */
55
- .aura-btn:is(.aura-btn--primary, .aura-btn--danger, .aura-btn--creative):is(:disabled, [aria-disabled='true']:not(.is-loading)),
56
- .aura-btn:is(.aura-btn--primary, .aura-btn--danger, .aura-btn--creative):is(:disabled, [aria-disabled='true']:not(.is-loading)):hover {
57
- opacity: 1; background: var(--aura-button-disabled-bg); color: var(--aura-button-disabled-fg); border-color: transparent; box-shadow: none;
58
- }
53
+ /* 5.30: a disabled button is not a faded copy of itself (faded ink read as a separate grey button, faded red as pink).
54
+ * 5.79: one look for every variant — see below. */
55
+ .aura-btn.aura-btn:is(:disabled, [aria-disabled='true']:not(.is-loading)),
56
+ .aura-btn.aura-btn:is(:disabled, [aria-disabled='true']:not(.is-loading)):hover {
57
+ opacity: 1; background: var(--aura-button-disabled-bg); color: var(--aura-button-disabled-fg); border-color: var(--aura-button-disabled-border); box-shadow: none;
58
+ }
59
+ /* …a variant without a border of its own (primary, danger) draws the same edge inside, so none is edgeless */
60
+ .aura-btn.aura-btn:is(.aura-btn--primary, .aura-btn--danger):is(:disabled, [aria-disabled='true']:not(.is-loading)),
61
+ .aura-btn.aura-btn:is(.aura-btn--primary, .aura-btn--danger):is(:disabled, [aria-disabled='true']:not(.is-loading)):hover {
62
+ box-shadow: inset 0 0 0 1px var(--aura-button-disabled-border);
63
+ }
64
+ /* 5.79 (visual audit 6): one disabled look for every variant — a faint fill, a faint edge, the tertiary label — so a
65
+ * disabled primary doesn't read as a To Do pill and a disabled outline button isn't a crisp white one in dark. A ghost
66
+ * button stays without fill or edge. */
67
+ .aura-btn.aura-btn.aura-btn--ghost:is(:disabled, [aria-disabled='true']:not(.is-loading)),
68
+ .aura-btn.aura-btn.aura-btn--ghost:is(:disabled, [aria-disabled='true']:not(.is-loading)):hover { background: transparent; border-color: transparent; box-shadow: none; }
59
69
  /* Forced colours drop the fills: filled buttons get a 1px edge (as outline buttons have), and a disabled or gated one
60
70
  * (still focusable) shows GrayText and keeps the fade, without changing size. */
61
71
  @media (forced-colors: active) {
62
72
  .aura-btn:is(.aura-btn--primary, .aura-btn--danger) { border: 1px solid ButtonText; }
63
- .aura-btn.aura-btn:is(:disabled, [aria-disabled='true']:not(.is-loading)),
64
- .aura-btn.aura-btn.aura-btn:is(:disabled, [aria-disabled='true']:not(.is-loading)):hover { color: GrayText; border-color: GrayText; opacity: var(--aura-disabled-opacity); }
73
+ .aura-btn.aura-btn.aura-btn:is(:disabled, [aria-disabled='true']:not(.is-loading)),
74
+ .aura-btn.aura-btn.aura-btn:is(:disabled, [aria-disabled='true']:not(.is-loading)):hover { color: GrayText; border-color: GrayText; opacity: var(--aura-disabled-opacity); } /* 5.79: one class more, over the ghost rule */
65
75
  }
66
76
  .aura-btn.is-loading:active { transform: none; }
67
77
 
@@ -295,7 +305,7 @@ a.aura-table__sort { text-decoration: none; }
295
305
  position: fixed; z-index: var(--aura-z-menu); min-width: 200px; padding: var(--aura-space-1); overflow-y: auto; overscroll-behavior: contain;
296
306
  background: var(--aura-bg-surface); color: var(--aura-fg-primary);
297
307
  border: 1px solid var(--aura-border-default); border-radius: var(--aura-radius-md);
298
- box-shadow: var(--aura-shadow-enterprise);
308
+ box-shadow: var(--aura-shadow-overlay); /* 5.79 (visual audit 18): lifted as Popover and the list boxes are; its light edge alone was faint */
299
309
  font-family: var(--font-sans); font-size: max(13px, .8125rem);
300
310
  }
301
311
  .aura-menu__item {
@@ -583,7 +593,7 @@ a.aura-icon-btn { text-decoration: none; }
583
593
  * Field). */
584
594
  .aura-field:not(.is-disabled) .aura-input:has(> .aura-input__control[aria-invalid="true"]:not(:disabled)),
585
595
  .aura-field:not(.is-disabled) .aura-textarea[aria-invalid="true"]:not(:disabled) { border-color: var(--aura-border-danger); }
586
- .aura-field.is-disabled .aura-input { background: var(--aura-bg-input-disabled); color: var(--aura-fg-secondary); border-color: var(--aura-border-default); }
596
+ .aura-field.is-disabled .aura-input { background: var(--aura-bg-input-disabled); color: var(--aura-fg-secondary); border-color: var(--aura-input-disabled-border); }
587
597
  .aura-field.is-disabled .aura-input__control { cursor: not-allowed; }
588
598
  /* A read-only text field. Only an input: `:read-only` also matches any element that isn't editable — a
589
599
  * Select's trigger <button> — which painted every custom Select with the disabled ground (5.16.1, Chamber-OS 109). */
@@ -593,13 +603,18 @@ a.aura-icon-btn { text-decoration: none; }
593
603
 
594
604
  .aura-textarea { display: block; padding: 10px var(--aura-space-3); min-height: 96px; line-height: 1.6; resize: vertical; outline: none; }
595
605
  .aura-textarea:focus { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: 1px; border-color: var(--aura-border-strong); }
596
- .aura-field.is-disabled .aura-textarea { background: var(--aura-bg-input-disabled); color: var(--aura-fg-secondary); border-color: var(--aura-border-default); }
606
+ .aura-field.is-disabled .aura-textarea { background: var(--aura-bg-input-disabled); color: var(--aura-fg-secondary); border-color: var(--aura-input-disabled-border); }
597
607
 
598
608
  .aura-select .aura-input__control { padding-right: calc(var(--aura-space-3) + var(--aura-icon-sm) + var(--aura-space-2)); cursor: pointer; }
599
609
  .aura-select__chevron { position: absolute; right: var(--aura-space-3); color: var(--aura-fg-secondary); pointer-events: none; }
600
610
  .aura-select select:invalid, .aura-select select:has(option[value=""]:checked) { color: var(--aura-fg-tertiary); }
601
611
  /* 5.3: the field is a button over an invisible <select> (forms, refs, events); the list is AURA's, like Combobox. */
602
612
  .aura-select option { color: var(--aura-fg-primary); background: var(--aura-bg-input); }
613
+ /* 5.79 (visual audit 15): a list box (multiple, or size > 1) shows its rows — as tall as they need, no chevron — instead
614
+ * of being squeezed into a one-line field with its third option cut in half. */
615
+ .aura-select .aura-input__control:is([multiple], [size]:not([size='0'], [size='1'])) { height: auto; padding: var(--aura-space-1) var(--aura-space-2); overflow-y: auto; cursor: default; }
616
+ .aura-select:has(> .aura-input__control:is([multiple], [size]:not([size='0'], [size='1']))) .aura-select__chevron { display: none; }
617
+ .aura-select .aura-input__control:is([multiple], [size]:not([size='0'], [size='1'])) option { padding: var(--aura-space-1) var(--aura-space-2); border-radius: var(--aura-radius-xs); }
603
618
  .aura-select--custom { position: relative; }
604
619
  .aura-select__native { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; padding: 0; border: 0; opacity: 0; pointer-events: none; appearance: none; }
605
620
  .aura-select__trigger { display: flex; align-items: center; text-align: start; background: none; border: 0; color: inherit; font: inherit; width: 100%; min-width: 0; }
@@ -659,7 +674,7 @@ a.aura-icon-btn { text-decoration: none; }
659
674
  /* 5.19 (Chamber-OS 113): a read-only switch keeps its colours (a locked "on" reads as on at full contrast) and stays
660
675
  * focusable; only the pointer says it won't change. The row's icon (a lock) sits at its end, like a field's icon. */
661
676
  .aura-switch-row.is-readonly, .aura-switch-row.is-readonly .aura-switch, .aura-switch-row.is-readonly .aura-choice__label { cursor: default; }
662
- .aura-switch-row__icon { flex: none; margin-inline-start: auto; margin-top: 2px; width: var(--aura-icon-sm); height: var(--aura-icon-sm); color: var(--aura-fg-secondary); }
677
+ .aura-switch-row__icon { flex: none; margin-inline-start: calc(-1 * var(--aura-space-1)); margin-top: 2px; /* 5.79 (visual audit 17): beside the label it belongs to, 8px after it, not at the row's far end */ width: var(--aura-icon-sm); height: var(--aura-icon-sm); color: var(--aura-fg-secondary); }
663
678
 
664
679
  /* ---------- Alerts & toasts ---------- */
665
680
  .aura-alert {
@@ -1051,8 +1066,8 @@ a.aura-tab { text-decoration: none; }
1051
1066
  .aura-combo__option.is-selected { font-weight: 500; }
1052
1067
  .aura-combo__option.is-disabled { opacity: var(--aura-disabled-opacity); cursor: default; }
1053
1068
  .aura-combo__text { flex: 1; min-width: 0; display: flex; flex-direction: column; }
1054
- .aura-combo__label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1055
- .aura-combo__desc { font-size: max(12px, .75rem); line-height: 1.5; color: var(--aura-fg-secondary); }
1069
+ .aura-combo__label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; line-height: max(20px, 1.25rem); }
1070
+ .aura-combo__desc { font-size: max(12px, .75rem); line-height: max(18px, 1.125rem); color: var(--aura-fg-secondary); } /* 5.79: fixed line heights, so a Thai row and an English row are spaced alike (normal follows each font) */
1056
1071
  /* Same specificity as `.aura-combo__option > .aura-icon` above and later in the file, so it wins by order (4.18). */
1057
1072
  .aura-combo__option > .aura-combo__check { color: var(--aura-fg-accent); }
1058
1073
  /* 5.16 (Chamber-OS 105): option groups under a heading. */
@@ -1095,9 +1110,9 @@ a.aura-tab { text-decoration: none; }
1095
1110
  .aura-cal__day.is-selected { background: var(--aura-control-checked-bg); color: var(--aura-control-checked-fg); box-shadow: none; }
1096
1111
  .aura-cal__day:disabled, .aura-cal__day[aria-disabled='true'] { opacity: var(--aura-disabled-opacity); cursor: not-allowed; background: transparent; text-decoration: line-through; }
1097
1112
  .aura-cal__day:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: 1px; }
1098
- .aura-cal__grid td.is-in-range { background: var(--aura-bg-selected); }
1099
- .aura-cal__grid td.is-range-start { background: linear-gradient(to right, transparent 50%, var(--aura-bg-selected) 50%); }
1100
- .aura-cal__grid td.is-range-end { background: linear-gradient(to left, transparent 50%, var(--aura-bg-selected) 50%); }
1113
+ .aura-cal__grid td.is-in-range { background: var(--aura-calendar-range-bg); } /* 5.79 (visual audit 19) */
1114
+ .aura-cal__grid td.is-range-start { background: linear-gradient(to right, transparent 50%, var(--aura-calendar-range-bg) 50%); }
1115
+ .aura-cal__grid td.is-range-end { background: linear-gradient(to left, transparent 50%, var(--aura-calendar-range-bg) 50%); }
1101
1116
  .aura-cal__grid td.is-range-start.is-range-end { background: none; }
1102
1117
  .aura-cal__years { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--aura-space-1); }
1103
1118
  .aura-cal__year {
@@ -1652,7 +1667,7 @@ a.aura-upload__name:focus-visible { outline: var(--aura-focus-ring-width) solid
1652
1667
  .aura-badge--success { background: var(--aura-alert-success-bg); color: var(--aura-alert-success-fg); }
1653
1668
  .aura-badge--warning { background: var(--aura-alert-warning-bg); color: var(--aura-alert-warning-fg); }
1654
1669
  .aura-badge--danger { background: var(--aura-alert-danger-bg); color: var(--aura-alert-danger-fg); }
1655
- .aura-badge.is-outline { background: transparent; border-color: currentColor; }
1670
+ .aura-badge.is-outline { background: transparent; border-color: currentColor; border-color: color-mix(in srgb, currentColor 45%, transparent); } /* 5.79 (visual audit 19): a quieter edge, so an outline badge doesn't read as a secondary button */
1656
1671
  .aura-badge--neutral.is-outline { border-color: var(--aura-border-control); }
1657
1672
  .aura-badge.is-solid { background: var(--aura-button-primary-bg); color: var(--aura-button-primary-fg); }
1658
1673
  .aura-badge--danger.is-solid { background: var(--aura-status-blocked-solid-bg); color: var(--aura-status-blocked-solid-fg); }
@@ -1791,6 +1806,7 @@ a.aura-upload__name:focus-visible { outline: var(--aura-focus-ring-width) solid
1791
1806
  .aura-combo__chips { display: contents; }
1792
1807
  .aura-combo__chip {
1793
1808
  display: inline-flex; align-items: center; gap: 2px; max-width: 100%; height: 28px; box-sizing: border-box;
1809
+ flex: none; /* 5.79 (visual audit 16): a chip keeps its label and goes to the next line, not shrunk to "V.." */
1794
1810
  padding: 0 2px 0 var(--aura-space-2); border-radius: var(--aura-radius-full);
1795
1811
  background: var(--aura-bg-selected); color: var(--aura-fg-primary); font-size: max(13px, .8125rem); font-weight: 500;
1796
1812
  }
@@ -2193,7 +2209,7 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
2193
2209
  .aura-filterselect__face:focus-visible { outline-style: solid; }
2194
2210
  /* Before hydration: the real <select>, invisible, over the face (16px so iOS doesn't zoom when it opens). */
2195
2211
  .aura-filterselect__native { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; padding: 0; border: 0; opacity: 0; font-size: max(16px, 1rem); cursor: pointer; appearance: none; }
2196
- .aura-filterselect.is-disabled .aura-filterselect__face { background: var(--aura-bg-input-disabled); color: var(--aura-fg-secondary); border-color: var(--aura-border-default); cursor: not-allowed; }
2212
+ .aura-filterselect.is-disabled .aura-filterselect__face { background: var(--aura-bg-input-disabled); color: var(--aura-fg-secondary); border-color: var(--aura-input-disabled-border); cursor: not-allowed; }
2197
2213
  .aura-filterselect.is-disabled .aura-filterselect__native { cursor: not-allowed; }
2198
2214
  /* 5.38 (Chamber-OS 140): touchHeight on FilterBar (its search and field-height controls) or on one FilterSelect —
2199
2215
  * 44px below 640px or on a coarse pointer (is-touch), or always. */
@@ -2393,6 +2409,25 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
2393
2409
  :root:has(.aura-actionbar--edge:not(.is-idle)) .aura-shell__content { padding-bottom: calc(var(--aura-space-6) + var(--aura-actionbar-space)); }
2394
2410
  :root:has(.aura-actionbar--edge:not(.is-idle)):not(:has(.aura-shell__content)) body { padding-bottom: var(--aura-actionbar-space); }
2395
2411
  }
2412
+ /* 5.79 (5.78 carry-over): where actionsFullWidthBelow reaches wider than actionsBarBelow, the bar isn't pinned between
2413
+ * the two breakpoints and its buttons sit in the same full-width row — every button there is radius-md, not some. */
2414
+ @media (min-width: 640px) and (max-width: 767.98px) {
2415
+ .aura-page-header--actions-full-below-md.aura-page-header--actions-bar-below-sm > .aura-page-header__actions .aura-btn:not(.aura-icon-btn) { border-radius: var(--aura-radius-md); }
2416
+ }
2417
+ @media (min-width: 640px) and (max-width: 1023.98px) {
2418
+ .aura-page-header--actions-full-below-lg.aura-page-header--actions-bar-below-sm > .aura-page-header__actions .aura-btn:not(.aura-icon-btn) { border-radius: var(--aura-radius-md); }
2419
+ }
2420
+ @media (min-width: 768px) and (max-width: 1023.98px) {
2421
+ .aura-page-header--actions-full-below-lg.aura-page-header--actions-bar-below-md > .aura-page-header__actions .aura-btn:not(.aura-icon-btn) { border-radius: var(--aura-radius-md); }
2422
+ }
2423
+ /* 5.79 (visual audit 10): in an AppShell on a desktop the edge strip starts where the content does — after the
2424
+ * sidebar (its rail width when collapsed; the right edge in RTL) — and its contents line up with the content's 32px
2425
+ * padding, instead of running under the sidebar. Outside an AppShell it keeps the screen's full width. */
2426
+ @media (min-width: 1024px) and (min-height: 30.00125rem) {
2427
+ .aura-shell:has(> .aura-shell__nav) .aura-actionbar--edge:not(.is-idle) { inset-inline-start: var(--aura-sidenav-width); }
2428
+ .aura-shell:has(> .aura-shell__nav .aura-nav--collapsed) .aura-actionbar--edge:not(.is-idle) { inset-inline-start: var(--aura-sidenav-rail-width); }
2429
+ .aura-shell:not(:has(.aura-shell__content.is-flush)) .aura-actionbar--edge:not(.is-idle) > .aura-actionbar__inner { padding-inline: var(--aura-space-8); } /* not with contentPadding={false} */
2430
+ }
2396
2431
  /* 5.78 (visual audit 9): one rule for the bottom strips on a phone, as PageHeader's (5.48) — the status on its own row
2397
2432
  * at the top, the actions sharing the row under it (an IconButton keeps its square; labels too long to share take a row
2398
2433
  * each), 16px both sides as the page. edgeBelow="md" follows it up to 768px, as PageHeader's md strip. */
@@ -2753,6 +2788,10 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
2753
2788
  * 1.6 line, so a loading card (its bars follow 1lh) is as tall as one with Thai text. */
2754
2789
  .aura-field__label:lang(th), .aura-field__hint:lang(th), .aura-field__error:lang(th), .aura-field__addon:lang(th) { line-height: 1.6; }
2755
2790
  .aura-choice__desc:lang(th), .aura-check__desc:lang(th) { font-size: max(13px, .8125rem); line-height: 1.6; }
2791
+ /* 5.79 (visual audit, Thai): the calendar's weekday row in Thai (อา จ อ …) at 13px — 12px was the hardest text on the
2792
+ * page to read; the grid carries lang="th" with a Thai locale. Two-line Thai nav labels get room between lines. */
2793
+ .aura-cal__grid:lang(th) th { font-size: max(13px, .8125rem); }
2794
+ .aura-nav__label:lang(th) { line-height: 1.5; }
2756
2795
  .aura-tbl__row > .aura-tbl__td[data-label]:lang(th)::before, .aura-table__td[data-label]:lang(th)::before { font-family: var(--font-sans); font-size: max(12px, .75rem); line-height: max(18px, 1.125rem); }
2757
2796
  .aura-table--stacked .aura-table__td[data-label]:lang(th) { line-height: 1.6; }
2758
2797
 
@@ -52,18 +52,28 @@ button.aura-btn--secondary[aria-disabled='true']:hover, button.aura-btn--ghost[a
52
52
  button.aura-btn--danger-secondary[aria-disabled='true']:hover { background: transparent; }
53
53
  button.aura-btn--danger[aria-disabled='true']:hover { background: var(--aura-button-danger-bg); }
54
54
  button.aura-btn--creative[aria-disabled='true']:hover { box-shadow: var(--aura-shadow-creative); transform: none; }
55
- /* 5.30: a disabled filled button (primary, danger, creative) is a quiet grey fill with muted text, not a faded copy of
56
- * itself — faded ink read as a separate grey button, faded red as pink. Outline and ghost buttons keep the fade. */
57
- .aura-btn:is(.aura-btn--primary, .aura-btn--danger, .aura-btn--creative):is(:disabled, [aria-disabled='true']:not(.is-loading)),
58
- .aura-btn:is(.aura-btn--primary, .aura-btn--danger, .aura-btn--creative):is(:disabled, [aria-disabled='true']:not(.is-loading)):hover {
59
- opacity: 1; background: var(--aura-button-disabled-bg); color: var(--aura-button-disabled-fg); border-color: transparent; box-shadow: none;
60
- }
55
+ /* 5.30: a disabled button is not a faded copy of itself (faded ink read as a separate grey button, faded red as pink).
56
+ * 5.79: one look for every variant — see below. */
57
+ .aura-btn.aura-btn:is(:disabled, [aria-disabled='true']:not(.is-loading)),
58
+ .aura-btn.aura-btn:is(:disabled, [aria-disabled='true']:not(.is-loading)):hover {
59
+ opacity: 1; background: var(--aura-button-disabled-bg); color: var(--aura-button-disabled-fg); border-color: var(--aura-button-disabled-border); box-shadow: none;
60
+ }
61
+ /* …a variant without a border of its own (primary, danger) draws the same edge inside, so none is edgeless */
62
+ .aura-btn.aura-btn:is(.aura-btn--primary, .aura-btn--danger):is(:disabled, [aria-disabled='true']:not(.is-loading)),
63
+ .aura-btn.aura-btn:is(.aura-btn--primary, .aura-btn--danger):is(:disabled, [aria-disabled='true']:not(.is-loading)):hover {
64
+ box-shadow: inset 0 0 0 1px var(--aura-button-disabled-border);
65
+ }
66
+ /* 5.79 (visual audit 6): one disabled look for every variant — a faint fill, a faint edge, the tertiary label — so a
67
+ * disabled primary doesn't read as a To Do pill and a disabled outline button isn't a crisp white one in dark. A ghost
68
+ * button stays without fill or edge. */
69
+ .aura-btn.aura-btn.aura-btn--ghost:is(:disabled, [aria-disabled='true']:not(.is-loading)),
70
+ .aura-btn.aura-btn.aura-btn--ghost:is(:disabled, [aria-disabled='true']:not(.is-loading)):hover { background: transparent; border-color: transparent; box-shadow: none; }
61
71
  /* Forced colours drop the fills: filled buttons get a 1px edge (as outline buttons have), and a disabled or gated one
62
72
  * (still focusable) shows GrayText and keeps the fade, without changing size. */
63
73
  @media (forced-colors: active) {
64
74
  .aura-btn:is(.aura-btn--primary, .aura-btn--danger) { border: 1px solid ButtonText; }
65
- .aura-btn.aura-btn:is(:disabled, [aria-disabled='true']:not(.is-loading)),
66
- .aura-btn.aura-btn.aura-btn:is(:disabled, [aria-disabled='true']:not(.is-loading)):hover { color: GrayText; border-color: GrayText; opacity: var(--aura-disabled-opacity); }
75
+ .aura-btn.aura-btn.aura-btn:is(:disabled, [aria-disabled='true']:not(.is-loading)),
76
+ .aura-btn.aura-btn.aura-btn:is(:disabled, [aria-disabled='true']:not(.is-loading)):hover { color: GrayText; border-color: GrayText; opacity: var(--aura-disabled-opacity); } /* 5.79: one class more, over the ghost rule */
67
77
  }
68
78
  .aura-btn.is-loading:active { transform: none; }
69
79
 
@@ -297,7 +307,7 @@ a.aura-table__sort { text-decoration: none; }
297
307
  position: fixed; z-index: var(--aura-z-menu); min-width: 200px; padding: var(--aura-space-1); overflow-y: auto; overscroll-behavior: contain;
298
308
  background: var(--aura-bg-surface); color: var(--aura-fg-primary);
299
309
  border: 1px solid var(--aura-border-default); border-radius: var(--aura-radius-md);
300
- box-shadow: var(--aura-shadow-enterprise);
310
+ box-shadow: var(--aura-shadow-overlay); /* 5.79 (visual audit 18): lifted as Popover and the list boxes are; its light edge alone was faint */
301
311
  font-family: var(--font-sans); font-size: max(13px, .8125rem);
302
312
  }
303
313
  .aura-menu__item {
@@ -585,7 +595,7 @@ a.aura-icon-btn { text-decoration: none; }
585
595
  * Field). */
586
596
  .aura-field:not(.is-disabled) .aura-input:has(> .aura-input__control[aria-invalid="true"]:not(:disabled)),
587
597
  .aura-field:not(.is-disabled) .aura-textarea[aria-invalid="true"]:not(:disabled) { border-color: var(--aura-border-danger); }
588
- .aura-field.is-disabled .aura-input { background: var(--aura-bg-input-disabled); color: var(--aura-fg-secondary); border-color: var(--aura-border-default); }
598
+ .aura-field.is-disabled .aura-input { background: var(--aura-bg-input-disabled); color: var(--aura-fg-secondary); border-color: var(--aura-input-disabled-border); }
589
599
  .aura-field.is-disabled .aura-input__control { cursor: not-allowed; }
590
600
  /* A read-only text field. Only an input: `:read-only` also matches any element that isn't editable — a
591
601
  * Select's trigger <button> — which painted every custom Select with the disabled ground (5.16.1, Chamber-OS 109). */
@@ -595,13 +605,18 @@ a.aura-icon-btn { text-decoration: none; }
595
605
 
596
606
  .aura-textarea { display: block; padding: 10px var(--aura-space-3); min-height: 96px; line-height: 1.6; resize: vertical; outline: none; }
597
607
  .aura-textarea:focus { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: 1px; border-color: var(--aura-border-strong); }
598
- .aura-field.is-disabled .aura-textarea { background: var(--aura-bg-input-disabled); color: var(--aura-fg-secondary); border-color: var(--aura-border-default); }
608
+ .aura-field.is-disabled .aura-textarea { background: var(--aura-bg-input-disabled); color: var(--aura-fg-secondary); border-color: var(--aura-input-disabled-border); }
599
609
 
600
610
  .aura-select .aura-input__control { padding-right: calc(var(--aura-space-3) + var(--aura-icon-sm) + var(--aura-space-2)); cursor: pointer; }
601
611
  .aura-select__chevron { position: absolute; right: var(--aura-space-3); color: var(--aura-fg-secondary); pointer-events: none; }
602
612
  .aura-select select:invalid, .aura-select select:has(option[value=""]:checked) { color: var(--aura-fg-tertiary); }
603
613
  /* 5.3: the field is a button over an invisible <select> (forms, refs, events); the list is AURA's, like Combobox. */
604
614
  .aura-select option { color: var(--aura-fg-primary); background: var(--aura-bg-input); }
615
+ /* 5.79 (visual audit 15): a list box (multiple, or size > 1) shows its rows — as tall as they need, no chevron — instead
616
+ * of being squeezed into a one-line field with its third option cut in half. */
617
+ .aura-select .aura-input__control:is([multiple], [size]:not([size='0'], [size='1'])) { height: auto; padding: var(--aura-space-1) var(--aura-space-2); overflow-y: auto; cursor: default; }
618
+ .aura-select:has(> .aura-input__control:is([multiple], [size]:not([size='0'], [size='1']))) .aura-select__chevron { display: none; }
619
+ .aura-select .aura-input__control:is([multiple], [size]:not([size='0'], [size='1'])) option { padding: var(--aura-space-1) var(--aura-space-2); border-radius: var(--aura-radius-xs); }
605
620
  .aura-select--custom { position: relative; }
606
621
  .aura-select__native { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; padding: 0; border: 0; opacity: 0; pointer-events: none; appearance: none; }
607
622
  .aura-select__trigger { display: flex; align-items: center; text-align: start; background: none; border: 0; color: inherit; font: inherit; width: 100%; min-width: 0; }
@@ -661,7 +676,7 @@ a.aura-icon-btn { text-decoration: none; }
661
676
  /* 5.19 (Chamber-OS 113): a read-only switch keeps its colours (a locked "on" reads as on at full contrast) and stays
662
677
  * focusable; only the pointer says it won't change. The row's icon (a lock) sits at its end, like a field's icon. */
663
678
  .aura-switch-row.is-readonly, .aura-switch-row.is-readonly .aura-switch, .aura-switch-row.is-readonly .aura-choice__label { cursor: default; }
664
- .aura-switch-row__icon { flex: none; margin-inline-start: auto; margin-top: 2px; width: var(--aura-icon-sm); height: var(--aura-icon-sm); color: var(--aura-fg-secondary); }
679
+ .aura-switch-row__icon { flex: none; margin-inline-start: calc(-1 * var(--aura-space-1)); margin-top: 2px; /* 5.79 (visual audit 17): beside the label it belongs to, 8px after it, not at the row's far end */ width: var(--aura-icon-sm); height: var(--aura-icon-sm); color: var(--aura-fg-secondary); }
665
680
 
666
681
  /* ---------- Alerts & toasts ---------- */
667
682
  .aura-alert {
@@ -1053,8 +1068,8 @@ a.aura-tab { text-decoration: none; }
1053
1068
  .aura-combo__option.is-selected { font-weight: 500; }
1054
1069
  .aura-combo__option.is-disabled { opacity: var(--aura-disabled-opacity); cursor: default; }
1055
1070
  .aura-combo__text { flex: 1; min-width: 0; display: flex; flex-direction: column; }
1056
- .aura-combo__label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1057
- .aura-combo__desc { font-size: max(12px, .75rem); line-height: 1.5; color: var(--aura-fg-secondary); }
1071
+ .aura-combo__label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; line-height: max(20px, 1.25rem); }
1072
+ .aura-combo__desc { font-size: max(12px, .75rem); line-height: max(18px, 1.125rem); color: var(--aura-fg-secondary); } /* 5.79: fixed line heights, so a Thai row and an English row are spaced alike (normal follows each font) */
1058
1073
  /* Same specificity as `.aura-combo__option > .aura-icon` above and later in the file, so it wins by order (4.18). */
1059
1074
  .aura-combo__option > .aura-combo__check { color: var(--aura-fg-accent); }
1060
1075
  /* 5.16 (Chamber-OS 105): option groups under a heading. */
@@ -1097,9 +1112,9 @@ a.aura-tab { text-decoration: none; }
1097
1112
  .aura-cal__day.is-selected { background: var(--aura-control-checked-bg); color: var(--aura-control-checked-fg); box-shadow: none; }
1098
1113
  .aura-cal__day:disabled, .aura-cal__day[aria-disabled='true'] { opacity: var(--aura-disabled-opacity); cursor: not-allowed; background: transparent; text-decoration: line-through; }
1099
1114
  .aura-cal__day:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: 1px; }
1100
- .aura-cal__grid td.is-in-range { background: var(--aura-bg-selected); }
1101
- .aura-cal__grid td.is-range-start { background: linear-gradient(to right, transparent 50%, var(--aura-bg-selected) 50%); }
1102
- .aura-cal__grid td.is-range-end { background: linear-gradient(to left, transparent 50%, var(--aura-bg-selected) 50%); }
1115
+ .aura-cal__grid td.is-in-range { background: var(--aura-calendar-range-bg); } /* 5.79 (visual audit 19) */
1116
+ .aura-cal__grid td.is-range-start { background: linear-gradient(to right, transparent 50%, var(--aura-calendar-range-bg) 50%); }
1117
+ .aura-cal__grid td.is-range-end { background: linear-gradient(to left, transparent 50%, var(--aura-calendar-range-bg) 50%); }
1103
1118
  .aura-cal__grid td.is-range-start.is-range-end { background: none; }
1104
1119
  .aura-cal__years { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--aura-space-1); }
1105
1120
  .aura-cal__year {
@@ -1654,7 +1669,7 @@ a.aura-upload__name:focus-visible { outline: var(--aura-focus-ring-width) solid
1654
1669
  .aura-badge--success { background: var(--aura-alert-success-bg); color: var(--aura-alert-success-fg); }
1655
1670
  .aura-badge--warning { background: var(--aura-alert-warning-bg); color: var(--aura-alert-warning-fg); }
1656
1671
  .aura-badge--danger { background: var(--aura-alert-danger-bg); color: var(--aura-alert-danger-fg); }
1657
- .aura-badge.is-outline { background: transparent; border-color: currentColor; }
1672
+ .aura-badge.is-outline { background: transparent; border-color: currentColor; border-color: color-mix(in srgb, currentColor 45%, transparent); } /* 5.79 (visual audit 19): a quieter edge, so an outline badge doesn't read as a secondary button */
1658
1673
  .aura-badge--neutral.is-outline { border-color: var(--aura-border-control); }
1659
1674
  .aura-badge.is-solid { background: var(--aura-button-primary-bg); color: var(--aura-button-primary-fg); }
1660
1675
  .aura-badge--danger.is-solid { background: var(--aura-status-blocked-solid-bg); color: var(--aura-status-blocked-solid-fg); }
@@ -1793,6 +1808,7 @@ a.aura-upload__name:focus-visible { outline: var(--aura-focus-ring-width) solid
1793
1808
  .aura-combo__chips { display: contents; }
1794
1809
  .aura-combo__chip {
1795
1810
  display: inline-flex; align-items: center; gap: 2px; max-width: 100%; height: 28px; box-sizing: border-box;
1811
+ flex: none; /* 5.79 (visual audit 16): a chip keeps its label and goes to the next line, not shrunk to "V.." */
1796
1812
  padding: 0 2px 0 var(--aura-space-2); border-radius: var(--aura-radius-full);
1797
1813
  background: var(--aura-bg-selected); color: var(--aura-fg-primary); font-size: max(13px, .8125rem); font-weight: 500;
1798
1814
  }
@@ -2195,7 +2211,7 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
2195
2211
  .aura-filterselect__face:focus-visible { outline-style: solid; }
2196
2212
  /* Before hydration: the real <select>, invisible, over the face (16px so iOS doesn't zoom when it opens). */
2197
2213
  .aura-filterselect__native { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; padding: 0; border: 0; opacity: 0; font-size: max(16px, 1rem); cursor: pointer; appearance: none; }
2198
- .aura-filterselect.is-disabled .aura-filterselect__face { background: var(--aura-bg-input-disabled); color: var(--aura-fg-secondary); border-color: var(--aura-border-default); cursor: not-allowed; }
2214
+ .aura-filterselect.is-disabled .aura-filterselect__face { background: var(--aura-bg-input-disabled); color: var(--aura-fg-secondary); border-color: var(--aura-input-disabled-border); cursor: not-allowed; }
2199
2215
  .aura-filterselect.is-disabled .aura-filterselect__native { cursor: not-allowed; }
2200
2216
  /* 5.38 (Chamber-OS 140): touchHeight on FilterBar (its search and field-height controls) or on one FilterSelect —
2201
2217
  * 44px below 640px or on a coarse pointer (is-touch), or always. */
@@ -2395,6 +2411,25 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
2395
2411
  :root:has(.aura-actionbar--edge:not(.is-idle)) .aura-shell__content { padding-bottom: calc(var(--aura-space-6) + var(--aura-actionbar-space)); }
2396
2412
  :root:has(.aura-actionbar--edge:not(.is-idle)):not(:has(.aura-shell__content)) body { padding-bottom: var(--aura-actionbar-space); }
2397
2413
  }
2414
+ /* 5.79 (5.78 carry-over): where actionsFullWidthBelow reaches wider than actionsBarBelow, the bar isn't pinned between
2415
+ * the two breakpoints and its buttons sit in the same full-width row — every button there is radius-md, not some. */
2416
+ @media (min-width: 640px) and (max-width: 767.98px) {
2417
+ .aura-page-header--actions-full-below-md.aura-page-header--actions-bar-below-sm > .aura-page-header__actions .aura-btn:not(.aura-icon-btn) { border-radius: var(--aura-radius-md); }
2418
+ }
2419
+ @media (min-width: 640px) and (max-width: 1023.98px) {
2420
+ .aura-page-header--actions-full-below-lg.aura-page-header--actions-bar-below-sm > .aura-page-header__actions .aura-btn:not(.aura-icon-btn) { border-radius: var(--aura-radius-md); }
2421
+ }
2422
+ @media (min-width: 768px) and (max-width: 1023.98px) {
2423
+ .aura-page-header--actions-full-below-lg.aura-page-header--actions-bar-below-md > .aura-page-header__actions .aura-btn:not(.aura-icon-btn) { border-radius: var(--aura-radius-md); }
2424
+ }
2425
+ /* 5.79 (visual audit 10): in an AppShell on a desktop the edge strip starts where the content does — after the
2426
+ * sidebar (its rail width when collapsed; the right edge in RTL) — and its contents line up with the content's 32px
2427
+ * padding, instead of running under the sidebar. Outside an AppShell it keeps the screen's full width. */
2428
+ @media (min-width: 1024px) and (min-height: 30.00125rem) {
2429
+ .aura-shell:has(> .aura-shell__nav) .aura-actionbar--edge:not(.is-idle) { inset-inline-start: var(--aura-sidenav-width); }
2430
+ .aura-shell:has(> .aura-shell__nav .aura-nav--collapsed) .aura-actionbar--edge:not(.is-idle) { inset-inline-start: var(--aura-sidenav-rail-width); }
2431
+ .aura-shell:not(:has(.aura-shell__content.is-flush)) .aura-actionbar--edge:not(.is-idle) > .aura-actionbar__inner { padding-inline: var(--aura-space-8); } /* not with contentPadding={false} */
2432
+ }
2398
2433
  /* 5.78 (visual audit 9): one rule for the bottom strips on a phone, as PageHeader's (5.48) — the status on its own row
2399
2434
  * at the top, the actions sharing the row under it (an IconButton keeps its square; labels too long to share take a row
2400
2435
  * each), 16px both sides as the page. edgeBelow="md" follows it up to 768px, as PageHeader's md strip. */
@@ -2755,6 +2790,10 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
2755
2790
  * 1.6 line, so a loading card (its bars follow 1lh) is as tall as one with Thai text. */
2756
2791
  .aura-field__label:lang(th), .aura-field__hint:lang(th), .aura-field__error:lang(th), .aura-field__addon:lang(th) { line-height: 1.6; }
2757
2792
  .aura-choice__desc:lang(th), .aura-check__desc:lang(th) { font-size: max(13px, .8125rem); line-height: 1.6; }
2793
+ /* 5.79 (visual audit, Thai): the calendar's weekday row in Thai (อา จ อ …) at 13px — 12px was the hardest text on the
2794
+ * page to read; the grid carries lang="th" with a Thai locale. Two-line Thai nav labels get room between lines. */
2795
+ .aura-cal__grid:lang(th) th { font-size: max(13px, .8125rem); }
2796
+ .aura-nav__label:lang(th) { line-height: 1.5; }
2758
2797
  .aura-tbl__row > .aura-tbl__td[data-label]:lang(th)::before, .aura-table__td[data-label]:lang(th)::before { font-family: var(--font-sans); font-size: max(12px, .75rem); line-height: max(18px, 1.125rem); }
2759
2798
  .aura-table--stacked .aura-table__td[data-label]:lang(th) { line-height: 1.6; }
2760
2799
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jirawatpyk/aura-react",
3
- "version": "5.78.0",
3
+ "version": "5.79.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",