@jirawatpyk/aura-tokens 4.10.0 → 4.11.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/aura-tailwind.css CHANGED
@@ -1,4 +1,4 @@
1
- /* AURA v4.10.0 — Tailwind v4 theme. GENERATED by scripts/build-tokens.js from tokens.json. Do not edit by hand.
1
+ /* AURA v4.11.0 — Tailwind v4 theme. GENERATED by scripts/build-tokens.js from tokens.json. Do not edit by hand.
2
2
  * @import "tailwindcss";
3
3
  * @import "@jirawatpyk/aura-tokens/tailwind.css";
4
4
  * Gives bg-bg-surface, text-fg-primary, border-border-strong, p-aura-6, rounded-aura-xl, shadow-aura-overlay,
package/aura.css CHANGED
@@ -1,4 +1,4 @@
1
- /* AURA v4.10.0 — GENERATED by scripts/build-tokens.js from tokens.json. Do not edit by hand. */
1
+ /* AURA v4.11.0 — GENERATED by scripts/build-tokens.js from tokens.json. Do not edit by hand. */
2
2
  /* Fonts: load aura-fonts.css (or the <link> tags in README) separately, so a blocked Google Fonts never breaks this file. */
3
3
 
4
4
  :root, [data-theme="light"] {
@@ -122,6 +122,8 @@
122
122
  --aura-button-creative-bg: var(--aura-white);
123
123
  --aura-button-creative-border: var(--aura-zinc-900);
124
124
  --aura-card-border: var(--aura-zinc-200);
125
+ --aura-progress-track: var(--aura-bg-skeleton);
126
+ --aura-progress-track-edge: var(--aura-button-secondary-border);
125
127
  --aura-shadow-enterprise: 0 1px 2px rgba(0,0,0,0.05);
126
128
  --aura-shadow-overlay: 0 16px 48px rgba(8,8,10,0.16), 0 2px 8px rgba(8,8,10,0.08);
127
129
  --aura-shadow-creative: 4px 4px 0px #18181b;
@@ -148,6 +150,10 @@
148
150
  --aura-focus-ring: var(--aura-violet-400);
149
151
  --aura-status-neutral-bg: var(--aura-zinc-800);
150
152
  --aura-status-neutral-fg: var(--aura-zinc-300);
153
+ --aura-status-progress-bg: #2f2647;
154
+ --aura-status-progress-fg: var(--aura-violet-300);
155
+ --aura-status-ready-bg: #2b351f;
156
+ --aura-status-ready-fg: var(--aura-lime-300);
151
157
  --aura-bg-selected: #2c283a;
152
158
  --aura-border-control: var(--aura-zinc-400);
153
159
  --aura-bg-skeleton: var(--aura-zinc-700);
@@ -213,6 +219,10 @@
213
219
  --aura-focus-ring: var(--aura-violet-400);
214
220
  --aura-status-neutral-bg: var(--aura-zinc-800);
215
221
  --aura-status-neutral-fg: var(--aura-zinc-300);
222
+ --aura-status-progress-bg: #2f2647;
223
+ --aura-status-progress-fg: var(--aura-violet-300);
224
+ --aura-status-ready-bg: #2b351f;
225
+ --aura-status-ready-fg: var(--aura-lime-300);
216
226
  --aura-bg-selected: #2c283a;
217
227
  --aura-border-control: var(--aura-zinc-400);
218
228
  --aura-bg-skeleton: var(--aura-zinc-700);
@@ -308,6 +318,8 @@
308
318
  --aura-container-narrow: 720px;
309
319
  --aura-cal-cell: 36px;
310
320
  --aura-popover-max-height: 320px;
321
+ --aura-input-font-size: 14px;
322
+ --aura-touch-target: 44px;
311
323
  --aura-bp-sm: 640px;
312
324
  --aura-bp-md: 768px;
313
325
  --aura-bp-lg: 1024px;
@@ -602,7 +602,8 @@ window.Aura = (() => {
602
602
  "iconRight",
603
603
  "disabled",
604
604
  "linkComponent",
605
- "href"
605
+ "href",
606
+ "fullWidth"
606
607
  ]);
607
608
  const Tag3 = disabled ? "a" : Link;
608
609
  return /* @__PURE__ */ React4.createElement(
@@ -614,7 +615,7 @@ window.Aura = (() => {
614
615
  role: disabled ? "link" : void 0,
615
616
  "aria-disabled": disabled || void 0,
616
617
  tabIndex: disabled ? -1 : props.tabIndex,
617
- className: cx("aura-btn", "aura-btn--" + variant, props.className),
618
+ className: cx("aura-btn", "aura-btn--" + variant, props.fullWidth && "aura-btn--full", props.className),
618
619
  onClick: disabled ? void 0 : props.onClick
619
620
  },
620
621
  props.icon ? /* @__PURE__ */ React4.createElement(Icon, { name: props.icon }) : null,
@@ -631,14 +632,30 @@ window.Aura = (() => {
631
632
  const props = all;
632
633
  const variant = props.variant || "primary";
633
634
  const loading = !!props.loading;
634
- const rest = omit(props, ["variant", "className", "children", "type", "icon", "iconRight", "loading", "onClick"]);
635
+ const rest = omit(props, [
636
+ "variant",
637
+ "className",
638
+ "children",
639
+ "type",
640
+ "icon",
641
+ "iconRight",
642
+ "loading",
643
+ "onClick",
644
+ "fullWidth"
645
+ ]);
635
646
  return /* @__PURE__ */ React4.createElement(
636
647
  "button",
637
648
  {
638
649
  ...rest,
639
650
  ref,
640
651
  type: props.type || "button",
641
- className: cx("aura-btn", "aura-btn--" + variant, loading && "is-loading", props.className),
652
+ className: cx(
653
+ "aura-btn",
654
+ "aura-btn--" + variant,
655
+ props.fullWidth && "aura-btn--full",
656
+ loading && "is-loading",
657
+ props.className
658
+ ),
642
659
  "aria-busy": loading || void 0,
643
660
  "aria-disabled": loading || void 0,
644
661
  onClick: loading ? function(e) {
@@ -1081,25 +1098,37 @@ window.Aura = (() => {
1081
1098
  const auto = uid(), id = props.id || auto;
1082
1099
  const st = useMaybeControlled(props.checked, !!props.defaultChecked, props.onChange);
1083
1100
  const on = !!st[0];
1084
- return /* @__PURE__ */ React15.createElement("div", { className: cx("aura-switch-row", props.disabled && "is-disabled", props.className) }, /* @__PURE__ */ React15.createElement(
1085
- "button",
1101
+ return /* @__PURE__ */ React15.createElement(
1102
+ "div",
1086
1103
  {
1087
- ref,
1088
- type: "button",
1089
- role: "switch",
1090
- id,
1091
- "aria-checked": on,
1092
- disabled: props.disabled,
1093
- "aria-labelledby": props.label ? id + "-label" : void 0,
1094
- "aria-label": props.label ? void 0 : props["aria-label"],
1095
- "aria-describedby": props.description ? id + "-desc" : void 0,
1096
- className: cx("aura-switch", on && "is-on"),
1097
- onClick: function() {
1104
+ className: cx("aura-switch-row", props.disabled && "is-disabled", props.className),
1105
+ onClick: function(e) {
1106
+ const t = e.target;
1107
+ if (props.disabled || t.closest("button, label, a, input")) return;
1098
1108
  st[1](!on);
1099
1109
  }
1100
1110
  },
1101
- /* @__PURE__ */ React15.createElement("span", { className: "aura-switch__thumb" })
1102
- ), props.label ? /* @__PURE__ */ React15.createElement("span", { className: "aura-choice__text" }, /* @__PURE__ */ React15.createElement("label", { className: "aura-choice__label", id: id + "-label", htmlFor: id }, props.label), props.description ? /* @__PURE__ */ React15.createElement("span", { className: "aura-choice__desc", id: id + "-desc" }, props.description) : null) : null);
1111
+ /* @__PURE__ */ React15.createElement(
1112
+ "button",
1113
+ {
1114
+ ref,
1115
+ type: "button",
1116
+ role: "switch",
1117
+ id,
1118
+ "aria-checked": on,
1119
+ disabled: props.disabled,
1120
+ "aria-labelledby": props.label ? id + "-label" : void 0,
1121
+ "aria-label": props.label ? void 0 : props["aria-label"],
1122
+ "aria-describedby": props.description ? id + "-desc" : void 0,
1123
+ className: cx("aura-switch", on && "is-on"),
1124
+ onClick: function() {
1125
+ st[1](!on);
1126
+ }
1127
+ },
1128
+ /* @__PURE__ */ React15.createElement("span", { className: "aura-switch__thumb" })
1129
+ ),
1130
+ props.label ? /* @__PURE__ */ React15.createElement("span", { className: "aura-choice__text" }, /* @__PURE__ */ React15.createElement("label", { className: "aura-choice__label", id: id + "-label", htmlFor: id }, props.label), props.description ? /* @__PURE__ */ React15.createElement("span", { className: "aura-choice__desc", id: id + "-desc" }, props.description) : null) : null
1131
+ );
1103
1132
  });
1104
1133
 
1105
1134
  // src/Combobox.tsx
@@ -1473,11 +1502,11 @@ window.Aura = (() => {
1473
1502
  }
1474
1503
  var TAGS = { th: "th-TH", en: "en-GB", sv: "sv-SE" };
1475
1504
  function defaultCalendar(locale) {
1476
- return locale === "sv" ? "gregory" : "buddhist";
1505
+ return locale === "th" ? "buddhist" : "gregory";
1477
1506
  }
1478
1507
  function localeTag(locale, calendar) {
1479
1508
  const cal = calendar || defaultCalendar(locale);
1480
- return (TAGS[locale || "th"] || "th-TH") + "-u-ca-" + (cal === "gregory" ? "gregory" : "buddhist");
1509
+ return (TAGS[locale || "en"] || "en-GB") + "-u-ca-" + (cal === "gregory" ? "gregory" : "buddhist");
1481
1510
  }
1482
1511
  var DATE_TEXT = {
1483
1512
  th: {
@@ -1505,11 +1534,11 @@ window.Aura = (() => {
1505
1534
  today: "Today",
1506
1535
  clear: "Clear",
1507
1536
  chooseDate: "Choose date",
1508
- datePlaceholder: "dd/mm/yyyy",
1537
+ datePlaceholder: "DD/MM/YYYY",
1509
1538
  clearDate: "Clear date",
1510
1539
  openCalendar: "Open calendar",
1511
1540
  chooseDates: "Choose dates",
1512
- rangePlaceholder: "dd/mm/yyyy \u2013 dd/mm/yyyy",
1541
+ rangePlaceholder: "DD/MM/YYYY \u2013 DD/MM/YYYY",
1513
1542
  clearDates: "Clear dates",
1514
1543
  chooseStart: "Choose the start date",
1515
1544
  chooseEnd: "Choose the end date"
@@ -1533,7 +1562,7 @@ window.Aura = (() => {
1533
1562
  }
1534
1563
  };
1535
1564
  function dateText(locale) {
1536
- return DATE_TEXT[locale || "th"] || DATE_TEXT.th;
1565
+ return DATE_TEXT[locale || "en"] || DATE_TEXT.en;
1537
1566
  }
1538
1567
  var fmtCache = {};
1539
1568
  var PRESETS = {
@@ -1550,7 +1579,8 @@ window.Aura = (() => {
1550
1579
  const o = opts || {}, d = fromISO(iso);
1551
1580
  if (!d) return "";
1552
1581
  const f = typeof o.format === "object" ? o.format : PRESETS[o.format || "short"];
1553
- return fmt(localeTag(o.locale, o.calendar), f, d).replace(ERA, "");
1582
+ const loc = o.locale || "th";
1583
+ return fmt(localeTag(loc, o.calendar || defaultCalendar(loc)), f, d).replace(ERA, "");
1554
1584
  }
1555
1585
  var MONTHS = null;
1556
1586
  function monthIndex(word) {
@@ -1590,7 +1620,7 @@ window.Aura = (() => {
1590
1620
  return dt.getMonth() === mo - 1 && dt.getDate() === d ? toISO(dt) : null;
1591
1621
  }
1592
1622
  var Calendar = React17.forwardRef(function Calendar2(props, ref) {
1593
- const ctx = useAuraLocale(), locale = props.locale || ctx.locale || "th", calendar = props.calendar || ctx.calendar || defaultCalendar(locale), tag = localeTag(locale, calendar);
1623
+ const ctx = useAuraLocale(), locale = props.locale || ctx.locale || "en", calendar = props.calendar || ctx.calendar || defaultCalendar(locale), tag = localeTag(locale, calendar);
1594
1624
  const weekStart = props.weekStartsOn == null ? locale === "sv" ? 1 : 0 : props.weekStartsOn;
1595
1625
  let today = /* @__PURE__ */ new Date();
1596
1626
  today = new Date(today.getFullYear(), today.getMonth(), today.getDate());
@@ -1775,6 +1805,7 @@ window.Aura = (() => {
1775
1805
  tabIndex: same(d, focusDate) ? 0 : -1,
1776
1806
  disabled: dis,
1777
1807
  "aria-label": fmt(tag, { weekday: "long", day: "numeric", month: "long", year: "numeric" }, d),
1808
+ suppressHydrationWarning: true,
1778
1809
  "aria-current": same(d, today) ? "date" : void 0,
1779
1810
  "aria-pressed": sel || void 0,
1780
1811
  className: cx(
@@ -1933,7 +1964,7 @@ window.Aura = (() => {
1933
1964
  }
1934
1965
  var DatePicker = React17.forwardRef(function DatePicker2(props, ref) {
1935
1966
  const auto = uid(), id = props.id || auto, dialogId = id + "-cal";
1936
- const ctx = useAuraLocale(), locale = props.locale || ctx.locale || "th", calendar = props.calendar || ctx.calendar || defaultCalendar(locale), dt = dateText(locale);
1967
+ const ctx = useAuraLocale(), locale = props.locale || ctx.locale || "en", calendar = props.calendar || ctx.calendar || defaultCalendar(locale), dt = dateText(locale);
1937
1968
  const st = useMaybeControlled(
1938
1969
  props.value,
1939
1970
  props.defaultValue == null ? null : props.defaultValue,
@@ -2028,7 +2059,7 @@ window.Aura = (() => {
2028
2059
  var DateRangePicker = React17.forwardRef(
2029
2060
  function DateRangePicker2(props, ref) {
2030
2061
  const auto = uid(), id = props.id || auto, dialogId = id + "-cal";
2031
- const ctx = useAuraLocale(), locale = props.locale || ctx.locale || "th", calendar = props.calendar || ctx.calendar || defaultCalendar(locale), dt = dateText(locale);
2062
+ const ctx = useAuraLocale(), locale = props.locale || ctx.locale || "en", calendar = props.calendar || ctx.calendar || defaultCalendar(locale), dt = dateText(locale);
2032
2063
  const st = useMaybeControlled(
2033
2064
  props.value,
2034
2065
  props.defaultValue || { start: null, end: null },
@@ -4666,8 +4697,8 @@ window.Aura = (() => {
4666
4697
  D["alert-info-bg"] = D["bg-selected"];
4667
4698
  D["alert-info-fg"] = fit(b[300], [D["alert-info-bg"]], 4.5, 1);
4668
4699
  D["alert-info-border"] = mix(ZINC[900], b[400], 0.4);
4669
- D["status-progress-bg"] = b[100];
4670
- D["status-progress-fg"] = L["status-progress-fg"];
4700
+ D["status-progress-bg"] = mix(ZINC[900], b[500], 0.2);
4701
+ D["status-progress-fg"] = fit(b[300], [D["status-progress-bg"]], 4.5, 1);
4671
4702
  if (s) {
4672
4703
  L["accent-dot"] = s[200];
4673
4704
  L["accent-lime"] = s[200];
@@ -4734,6 +4765,7 @@ window.Aura = (() => {
4734
4765
  check("light", "fg-primary", "bg-selected", 4.5, INK, L["bg-selected"]);
4735
4766
  check("dark", "fg-primary", "bg-selected", 4.5, "#ffffff", D["bg-selected"]);
4736
4767
  check("light", "status-progress-fg", "status-progress-bg", 4.5, L["status-progress-fg"], L["status-progress-bg"]);
4768
+ check("dark", "status-progress-fg", "status-progress-bg", 4.5, D["status-progress-fg"], D["status-progress-bg"]);
4737
4769
  check("light", "alert-info-fg", "alert-info-bg", 4.5, L["alert-info-fg"], L["alert-info-bg"]);
4738
4770
  check("dark", "alert-info-fg", "alert-info-bg", 4.5, D["alert-info-fg"], D["alert-info-bg"]);
4739
4771
  if (o.primary === "brand") {
@@ -28,6 +28,11 @@
28
28
  .aura-btn:active { transform: scale(0.98); }
29
29
  .aura-btn:disabled, a.aura-btn[aria-disabled='true'] { opacity: var(--aura-disabled-opacity); pointer-events: none; }
30
30
  a.aura-btn { text-decoration: none; }
31
+ /* fullWidth: fills the row and wraps a long label (Thai and Swedish run ~30% longer) instead of overflowing. */
32
+ .aura-btn--full {
33
+ width: 100%; height: auto; min-height: var(--aura-button-height); white-space: normal; flex-shrink: 1;
34
+ padding-block: var(--aura-space-2); line-height: 1.35; text-align: center; overflow-wrap: anywhere;
35
+ }
31
36
  .aura-btn.is-loading { cursor: progress; }
32
37
  .aura-btn.is-loading:active { transform: none; }
33
38
 
@@ -243,6 +248,11 @@ a.aura-btn { text-decoration: none; }
243
248
  .aura-icon-btn--danger:hover { background: var(--aura-alert-danger-bg); }
244
249
  .aura-icon-btn:disabled { opacity: var(--aura-disabled-opacity); pointer-events: none; }
245
250
  .aura-icon-btn:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: var(--aura-focus-ring-offset); }
251
+ /* Touch: same 32px look, a 44px hit area around it (WCAG 2.5.5). */
252
+ @media (pointer: coarse) {
253
+ .aura-icon-btn { position: relative; }
254
+ .aura-icon-btn::after { content: ''; position: absolute; top: 50%; left: 50%; width: max(100%, var(--aura-touch-target)); height: max(100%, var(--aura-touch-target)); transform: translate(-50%, -50%); }
255
+ }
246
256
 
247
257
  /* Skeleton */
248
258
  @keyframes aura-pulse { 50% { opacity: 0.6; } }
@@ -361,9 +371,11 @@ a.aura-btn { text-decoration: none; }
361
371
  min-height: var(--aura-input-height);
362
372
  background: var(--aura-bg-input); color: var(--aura-fg-primary);
363
373
  border: 1px solid var(--aura-border-control); border-radius: var(--aura-radius-md);
364
- font-family: var(--font-sans); font-size: 14px;
374
+ font-family: var(--font-sans); font-size: var(--aura-input-font-size);
365
375
  transition: border-color var(--aura-duration-fast) var(--aura-ease);
366
376
  }
377
+ /* Phones: iOS Safari zooms into any focused control under 16px and does not zoom back. */
378
+ @media (max-width: 639.98px) { .aura-input { font-size: max(16px, var(--aura-input-font-size)); } }
367
379
  .aura-input:hover { border-color: var(--aura-fg-secondary); }
368
380
  .aura-input:focus-within { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: 1px; border-color: var(--aura-border-strong); }
369
381
  .aura-input__control {
@@ -859,7 +871,7 @@ button.aura-stat { font: inherit; width: 100%; cursor: pointer; }
859
871
  .aura-upload__name { font-size: 13px; font-weight: 500; color: var(--aura-fg-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
860
872
  .aura-upload__sub { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; color: var(--aura-fg-secondary); }
861
873
  .aura-upload__item.is-error .aura-upload__sub { color: var(--aura-fg-danger); }
862
- .aura-upload__bar { display: block; height: 4px; border-radius: var(--aura-radius-full); background: var(--aura-bg-skeleton); overflow: hidden; }
874
+ .aura-upload__bar { display: block; height: 4px; border-radius: var(--aura-radius-full); background: var(--aura-progress-track); box-shadow: inset 0 0 0 1px var(--aura-progress-track-edge); overflow: hidden; }
863
875
  .aura-upload__bar > span { display: block; height: 100%; background: var(--aura-fg-accent); transition: width var(--aura-duration-base) var(--aura-ease); }
864
876
 
865
877
  /* ---------- Checkbox with a visible label ---------- */
@@ -908,7 +920,7 @@ button.aura-stat { font: inherit; width: 100%; cursor: pointer; }
908
920
  .aura-progress__head { display: flex; justify-content: space-between; gap: var(--aura-space-2); font-size: 13px; }
909
921
  .aura-progress__label { font-weight: 500; color: var(--aura-fg-primary); }
910
922
  .aura-progress__value { color: var(--aura-fg-secondary); font-variant-numeric: tabular-nums; }
911
- .aura-progress__track { position: relative; height: 8px; border-radius: var(--aura-radius-full); background: var(--aura-bg-skeleton); overflow: hidden; }
923
+ .aura-progress__track { position: relative; height: 8px; border-radius: var(--aura-radius-full); background: var(--aura-progress-track); box-shadow: inset 0 0 0 1px var(--aura-progress-track-edge); overflow: hidden; }
912
924
  .aura-progress.is-sm .aura-progress__track { height: 4px; }
913
925
  .aura-progress__bar { position: absolute; inset: 0 auto 0 0; border-radius: inherit; background: var(--aura-fg-accent); transition: width var(--aura-duration-base) var(--aura-ease); }
914
926
  .aura-progress--success .aura-progress__bar { background: var(--aura-fg-positive); }
@@ -1116,3 +1128,16 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
1116
1128
  .aura-tabs__list { gap: var(--aura-space-4); }
1117
1129
  }
1118
1130
  @keyframes aura-sheet-in { from { transform: translateY(24px); opacity: 0; } }
1131
+
1132
+ /* Touch (pointer: coarse): Radio, Checkbox and Switch rows are at least 44px tall (WCAG 2.5.5), padded above and
1133
+ * below a one-line 20px label; the whole row is the target (label rows natively, Switch rows by a click handler). */
1134
+ @media (pointer: coarse) {
1135
+ .aura-choice, .aura-check--labelled, .aura-switch-row {
1136
+ box-sizing: border-box; min-height: var(--aura-touch-target);
1137
+ padding-block: calc((var(--aura-touch-target) - 20px) / 2);
1138
+ }
1139
+ .aura-check--labelled .aura-check__input { top: calc((var(--aura-touch-target) - 20px) / 2 + 3px); }
1140
+ .aura-switch-row:not(.is-disabled) { cursor: pointer; }
1141
+ .aura-radio-group__list { gap: 0; }
1142
+ .aura-radio-group__list.is-horizontal { gap: 0 var(--aura-space-6); }
1143
+ }
@@ -14,6 +14,8 @@ export interface ButtonProps extends React$1.ButtonHTMLAttributes<HTMLButtonElem
14
14
  iconRight?: IconInput;
15
15
  /** Shows a spinner in place of the leading icon, sets aria-busy and swallows clicks. Keeps the label and width. */
16
16
  loading?: boolean;
17
+ /** Fills its container and lets a long label wrap onto more lines (at least 44px tall) — phones, Thai and Swedish labels. */
18
+ fullWidth?: boolean;
17
19
  }
18
20
  /** A link that looks like a Button: give `Button` an `href` and it renders an `<a>` (navigation, not actions). */
19
21
  export interface ButtonLinkProps extends Omit<React$1.AnchorHTMLAttributes<HTMLAnchorElement>, "children"> {
@@ -28,6 +30,8 @@ export interface ButtonLinkProps extends Omit<React$1.AnchorHTMLAttributes<HTMLA
28
30
  iconRight?: IconInput;
29
31
  /** Looks unavailable and can't be followed: no href, `aria-disabled`, out of the Tab order. */
30
32
  disabled?: boolean;
33
+ /** Fills its container and lets a long label wrap (at least 44px tall). */
34
+ fullWidth?: boolean;
31
35
  /** A router's link to render instead of `<a>`, e.g. `Link` from `next/link` (client-side navigation). It gets `href`, `className`, the children and the ref. */
32
36
  linkComponent?: React$1.ElementType;
33
37
  }
@@ -174,9 +178,9 @@ export interface SurfaceProps extends React$1.HTMLAttributes<HTMLElement> {
174
178
  }
175
179
  /** Sets the language of built-in labels (pagination, close buttons, empty states…) and the default date display for everything inside. */
176
180
  export interface AuraProviderProps {
177
- /** Built-in labels and date display. `sv` = Swedish labels, `sv-SE` dates, Monday weeks and the Gregorian calendar. Default `en` strings when there is no provider (dates still default to Thai / พ.ศ.). */
181
+ /** Built-in labels and date display. `sv` = Swedish labels, `sv-SE` dates, Monday weeks and the Gregorian calendar. Without a provider everything is English: labels, `en-GB` dates, Gregorian years. */
178
182
  locale?: "th" | "en" | "sv";
179
- /** Default calendar for DatePicker / DateRangePicker / Calendar / formatDate callers that read it. Unset: `buddhist` for `th` and `en` (unchanged), `gregory` for `sv`. */
183
+ /** Default calendar for DatePicker / DateRangePicker / Calendar / formatDate callers that read it. Unset: `buddhist` (พ.ศ.) for `th`, `gregory` for `en` and `sv`. */
180
184
  calendar?: "buddhist" | "gregory";
181
185
  /** Override individual strings. */
182
186
  strings?: Partial<Record<string, string | ((...args: any[]) => string)>>;
@@ -580,9 +584,9 @@ export interface SegmentedControlProps {
580
584
  /** ISO date string, `YYYY-MM-DD` (Gregorian — the era is display only). */
581
585
  export type ISODate = string;
582
586
  export interface DateDisplayOptions {
583
- /** `th` (default), `en` or `sv`. */
587
+ /** Components: the AuraProvider's locale, else `en`. `formatDate()` (no provider to read): `th` unless given. */
584
588
  locale?: "th" | "en" | "sv";
585
- /** `buddhist` (พ.ศ.; default for th and en) or `gregory` (ค.ศ.; default for sv). */
589
+ /** `buddhist` (พ.ศ.; default for th) or `gregory` (ค.ศ.; default for en and sv). */
586
590
  calendar?: "buddhist" | "gregory";
587
591
  }
588
592
  export interface CalendarProps extends DateDisplayOptions {
@@ -965,7 +969,7 @@ export declare function formatDate(iso: ISODate | null | undefined, opts?: Forma
965
969
  /** Parse typed text: dd/mm/yyyy (Buddhist years ≥ 2400 are converted), d-m-yyyy, d.m.yyyy, yyyy-mm-dd or '18 ก.ย. 2569' / '18 Sep 2026'. */
966
970
  export declare function parseDate(text: string | null | undefined): ISODate | null;
967
971
  export declare const Calendar: React$1.ForwardRefExoticComponent<CalendarProps & React$1.RefAttributes<HTMLDivElement>>;
968
- /** Typed date field + calendar popover. Shows Buddhist-era dates (18 ก.ย. 2569); accepts dd/mm/yyyy in พ.ศ. or ค.ศ. and yyyy-mm-dd. */
972
+ /** Typed date field + calendar popover. English / Gregorian unless a locale is set; `th` shows Buddhist-era dates (18 ก.ย. 2569) and accepts พ.ศ. or ค.ศ. years. The value is always a Gregorian ISO date. */
969
973
  export declare const DatePicker: React$1.ForwardRefExoticComponent<DatePickerProps & React$1.RefAttributes<HTMLInputElement>>;
970
974
  export declare const DateRangePicker: React$1.ForwardRefExoticComponent<DateRangePickerProps & React$1.RefAttributes<HTMLInputElement>>;
971
975
  export declare const Alert: React$1.ForwardRefExoticComponent<AlertProps & React$1.RefAttributes<HTMLDivElement>>;
@@ -67,10 +67,10 @@ semantic/on-texture,color,light,{primitive/ink},"Text and icons on a mesh or gra
67
67
  semantic/grain,color,light,{primitive/ink},"Grain speckle colour, drawn at aura-grain-opacity. Visible only on light grounds.",ALL_FILLS
68
68
  semantic/status-neutral-bg,color,light,{primitive/zinc/100},"Status pill fill for not-started / unknown states (To Do, Draft). Dark theme uses a quiet zinc-800 fill so it sits below the coloured states. ADDED.",ALL_FILLS
69
69
  semantic/status-neutral-fg,color,light,{primitive/zinc/700},"Label and icon on aura-status-neutral-bg (light 9.5:1, dark zinc-300 on zinc-800).",ALL_FILLS
70
- semantic/status-progress-bg,color,light,{primitive/violet/100},"Status pill fill for work under way (In Progress, In Review). ADDED.",ALL_FILLS
71
- semantic/status-progress-fg,color,light,{primitive/violet/800},Label and icon on aura-status-progress-bg (7.6:1).,ALL_FILLS
72
- semantic/status-ready-bg,color,light,{primitive/lime/200},"Status pill fill for finished / good states (Ready, Done). The source's lime pill. ADDED as a named token.",ALL_FILLS
73
- semantic/status-ready-fg,color,light,{primitive/ink},Label and icon on aura-status-ready-bg (15.2:1).,ALL_FILLS
70
+ semantic/status-progress-bg,color,light,{primitive/violet/100},"Status pill fill for work under way (In Progress, In Review). Dark: a quiet violet-tinted fill (violet-500 at 20% over zinc-900) so the pill sits below the row text. ADDED; dark 4.11.",ALL_FILLS
71
+ semantic/status-progress-fg,color,light,{primitive/violet/800},"Label and icon on aura-status-progress-bg (light 7.6:1; dark violet-300, 7.6:1).",ALL_FILLS
72
+ semantic/status-ready-bg,color,light,{primitive/lime/200},"Status pill fill for finished / good states (Ready, Done). The source's lime pill. Dark: a lime-tinted fill (lime-400 at 14% over zinc-900). ADDED as a named token; dark 4.11.",ALL_FILLS
73
+ semantic/status-ready-fg,color,light,{primitive/ink},"Label and icon on aura-status-ready-bg (light 15.2:1; dark lime-300, 9.9:1).",ALL_FILLS
74
74
  semantic/status-blocked-bg,color,light,{primitive/red/700},"Status pill fill for stopped / failed states (Blocked, Failed). Dark on purpose: 5.5:1 lighter-to-darker against the lime Ready fill, so Ready and Blocked differ by lightness, not only red vs green. ADDED.",ALL_FILLS
75
75
  semantic/status-blocked-fg,color,light,{primitive/white},Label and icon on aura-status-blocked-bg (6.5:1).,ALL_FILLS
76
76
  semantic/bg-selected,color,light,{primitive/violet/50},"Selected table rows and list items. Opaque so pinned columns can sit on it (dark = a 14% violet-400 wash over zinc-900, flattened). aura-fg-primary on it ≥14.2:1, aura-fg-secondary ≥5.5:1, focus ring ≥5.2:1 in both themes. ADDED.",FRAME_FILL
@@ -133,10 +133,10 @@ semantic/on-texture,color,dark,{primitive/ink},"Text and icons on a mesh or grai
133
133
  semantic/grain,color,dark,{primitive/ink},"Grain speckle colour, drawn at aura-grain-opacity. Visible only on light grounds.",ALL_FILLS
134
134
  semantic/status-neutral-bg,color,dark,{primitive/zinc/800},"Status pill fill for not-started / unknown states (To Do, Draft). Dark theme uses a quiet zinc-800 fill so it sits below the coloured states. ADDED.",ALL_FILLS
135
135
  semantic/status-neutral-fg,color,dark,{primitive/zinc/300},"Label and icon on aura-status-neutral-bg (light 9.5:1, dark zinc-300 on zinc-800).",ALL_FILLS
136
- semantic/status-progress-bg,color,dark,{primitive/violet/100},"Status pill fill for work under way (In Progress, In Review). ADDED.",ALL_FILLS
137
- semantic/status-progress-fg,color,dark,{primitive/violet/800},Label and icon on aura-status-progress-bg (7.6:1).,ALL_FILLS
138
- semantic/status-ready-bg,color,dark,{primitive/lime/200},"Status pill fill for finished / good states (Ready, Done). The source's lime pill. ADDED as a named token.",ALL_FILLS
139
- semantic/status-ready-fg,color,dark,{primitive/ink},Label and icon on aura-status-ready-bg (15.2:1).,ALL_FILLS
136
+ semantic/status-progress-bg,color,dark,#2f2647,"Status pill fill for work under way (In Progress, In Review). Dark: a quiet violet-tinted fill (violet-500 at 20% over zinc-900) so the pill sits below the row text. ADDED; dark 4.11.",ALL_FILLS
137
+ semantic/status-progress-fg,color,dark,{primitive/violet/300},"Label and icon on aura-status-progress-bg (light 7.6:1; dark violet-300, 7.6:1).",ALL_FILLS
138
+ semantic/status-ready-bg,color,dark,#2b351f,"Status pill fill for finished / good states (Ready, Done). The source's lime pill. Dark: a lime-tinted fill (lime-400 at 14% over zinc-900). ADDED as a named token; dark 4.11.",ALL_FILLS
139
+ semantic/status-ready-fg,color,dark,{primitive/lime/300},"Label and icon on aura-status-ready-bg (light 15.2:1; dark lime-300, 9.9:1).",ALL_FILLS
140
140
  semantic/status-blocked-bg,color,dark,{primitive/red/700},"Status pill fill for stopped / failed states (Blocked, Failed). Dark on purpose: 5.5:1 lighter-to-darker against the lime Ready fill, so Ready and Blocked differ by lightness, not only red vs green. ADDED.",ALL_FILLS
141
141
  semantic/status-blocked-fg,color,dark,{primitive/white},Label and icon on aura-status-blocked-bg (6.5:1).,ALL_FILLS
142
142
  semantic/bg-selected,color,dark,#2c283a,"Selected table rows and list items. Opaque so pinned columns can sit on it (dark = a 14% violet-400 wash over zinc-900, flattened). aura-fg-primary on it ≥14.2:1, aura-fg-secondary ≥5.5:1, focus ring ≥5.2:1 in both themes. ADDED.",FRAME_FILL
@@ -185,6 +185,8 @@ component/button-danger-fg,color,light,{primitive/white},Component: label on the
185
185
  component/button-creative-bg,color,light,{primitive/white},Component: Creative button fill (white in every theme). Label in aura-ink.,ALL_FILLS
186
186
  component/button-creative-border,color,light,{primitive/zinc/900},Component: Creative button 2px border.,ALL_FILLS
187
187
  component/card-border,color,light,{primitive/zinc/200},Component: card outline (light value; use aura-border-default where the card must follow theme).,ALL_FILLS
188
+ component/progress-track,color,light,{semantic/bg-skeleton},Empty part of Progress and FileUpload bars (fill). Its edge carries the 3:1. ADDED 4.11.,ALL_FILLS
189
+ component/progress-track-edge,color,light,{component/button-secondary-border},"1px inset edge of Progress / upload tracks: ≥3:1 on bg-surface and bg-canvas in both themes (WCAG 1.4.11), so the track reads without the fill. ADDED 4.11.",ALL_FILLS
188
190
  component/button-primary-bg,color,dark,{primitive/zinc/0},"Component: Enterprise (primary) button fill — ink in light, white in dark, as the Storybook story renders it (tokens.json pins it to the light value, which disappears on the dark surface).",ALL_FILLS
189
191
  component/button-primary-fg,color,dark,{primitive/zinc/900},Component: primary button label on aura-button-primary-bg (17.7:1 both themes).,ALL_FILLS
190
192
  component/button-primary-bg-hover,color,dark,{primitive/zinc/200},"Component: primary button hover. Light zinc-800 is the source value; dark zinc-200 is an ADDED value (the source has none — its zinc-800 hover hides the dark label at 1.19:1). Label 14.9:1 light, 14.0:1 dark.",ALL_FILLS
@@ -195,6 +197,8 @@ component/button-danger-fg,color,dark,{primitive/white},Component: label on the
195
197
  component/button-creative-bg,color,dark,{primitive/white},Component: Creative button fill (white in every theme). Label in aura-ink.,ALL_FILLS
196
198
  component/button-creative-border,color,dark,{primitive/zinc/900},Component: Creative button 2px border.,ALL_FILLS
197
199
  component/card-border,color,dark,{primitive/zinc/200},Component: card outline (light value; use aura-border-default where the card must follow theme).,ALL_FILLS
200
+ component/progress-track,color,dark,{semantic/bg-skeleton},Empty part of Progress and FileUpload bars (fill). Its edge carries the 3:1. ADDED 4.11.,ALL_FILLS
201
+ component/progress-track-edge,color,dark,{component/button-secondary-border},"1px inset edge of Progress / upload tracks: ≥3:1 on bg-surface and bg-canvas in both themes (WCAG 1.4.11), so the track reads without the fill. ADDED 4.11.",ALL_FILLS
198
202
  spacing/space-0,number,light,0,,GAP
199
203
  spacing/space-1,number,light,4,,GAP
200
204
  spacing/space-2,number,light,8,,GAP
@@ -243,3 +247,5 @@ size/container-max,number,light,1280,Container max width — matches aura-bp-xl.
243
247
  size/container-narrow,number,light,720,Narrow container for forms and reading. ADDED 4.2.,GAP
244
248
  size/cal-cell,number,light,36,Calendar day cell (DatePicker). 40px on touch screens via media query. ADDED 4.2.,GAP
245
249
  size/popover-max-height,number,light,320,Max height of Combobox listbox and DatePicker popover lists. ADDED 4.2.,GAP
250
+ size/input-font-size,number,light,14,"Text size in inputs, textareas, selects and pickers. Phones (<640px) use at least 16px so iOS Safari does not zoom on focus. ADDED 4.11.",GAP
251
+ size/touch-target,number,light,44,"Minimum hit area on touch screens (pointer: coarse): IconButton, and Radio / Checkbox / Switch rows (WCAG 2.5.5). ADDED 4.11.",GAP
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jirawatpyk/aura-tokens",
3
- "version": "4.10.0",
3
+ "version": "4.11.0",
4
4
  "description": "AURA Design System — tokens (CSS variables, Tailwind preset, Figma variables), theme contrast checks and token lint.",
5
5
  "main": "tailwind.tokens.cjs",
6
6
  "types": "components/index.d.ts",
@@ -67,6 +67,9 @@ for (const bg of ['bg-surface', 'bg-canvas']) {
67
67
  pairs.push(['chart-axis', bg, TEXT]);
68
68
  }
69
69
  for (let i = 1; i < 8; i++) pairs.push([`chart-${i}`, `chart-${i + 1}`, NEIGHBOUR]);
70
+ /* Progress / upload tracks: the edge shows the empty part at 3:1; the bar colours also clear 3:1 on the track fill. */
71
+ for (const bg of ['bg-surface', 'bg-canvas']) pairs.push(['progress-track-edge', bg, UI]);
72
+ for (const fg of ['fg-accent', 'fg-positive', 'fg-danger', 'fg-secondary']) pairs.push([fg, 'progress-track', UI]);
70
73
 
71
74
  const results = [], fails = [];
72
75
  for (const theme of ['light', 'dark']) for (const [fg, bg, min] of pairs) {
package/tokens.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "4.10.0",
2
+ "version": "4.11.0",
3
3
  "meta": {
4
4
  "name": "AURA Design System",
5
5
  "tier": "3-tier",
@@ -160,10 +160,10 @@
160
160
  "grain": "{primitive.ink}",
161
161
  "status-neutral-bg": "{primitive.zinc.800}",
162
162
  "status-neutral-fg": "{primitive.zinc.300}",
163
- "status-progress-bg": "{primitive.violet.100}",
164
- "status-progress-fg": "{primitive.violet.800}",
165
- "status-ready-bg": "{primitive.lime.200}",
166
- "status-ready-fg": "{primitive.ink}",
163
+ "status-progress-bg": "#2f2647",
164
+ "status-progress-fg": "{primitive.violet.300}",
165
+ "status-ready-bg": "#2b351f",
166
+ "status-ready-fg": "{primitive.lime.300}",
167
167
  "status-blocked-bg": "{primitive.red.700}",
168
168
  "status-blocked-fg": "{primitive.white}",
169
169
  "bg-selected": "#2c283a",
@@ -215,7 +215,9 @@
215
215
  "button-danger-fg": "{primitive.white}",
216
216
  "button-creative-bg": "{primitive.white}",
217
217
  "button-creative-border": "{primitive.zinc.900}",
218
- "card-border": "{primitive.zinc.200}"
218
+ "card-border": "{primitive.zinc.200}",
219
+ "progress-track": "{semantic.bg-skeleton}",
220
+ "progress-track-edge": "{component.button-secondary-border}"
219
221
  },
220
222
  "dark": {
221
223
  "button-primary-bg": "{primitive.zinc.0}",
@@ -227,7 +229,9 @@
227
229
  "button-danger-fg": "{primitive.white}",
228
230
  "button-creative-bg": "{primitive.white}",
229
231
  "button-creative-border": "{primitive.zinc.900}",
230
- "card-border": "{primitive.zinc.200}"
232
+ "card-border": "{primitive.zinc.200}",
233
+ "progress-track": "{semantic.bg-skeleton}",
234
+ "progress-track-edge": "{component.button-secondary-border}"
231
235
  }
232
236
  },
233
237
  "spacing": {
@@ -282,7 +286,9 @@
282
286
  "container-max": "1280px",
283
287
  "container-narrow": "720px",
284
288
  "cal-cell": "36px",
285
- "popover-max-height": "320px"
289
+ "popover-max-height": "320px",
290
+ "input-font-size": "14px",
291
+ "touch-target": "44px"
286
292
  },
287
293
  "breakpoint": {
288
294
  "bp-sm": "640px",
@@ -486,10 +492,10 @@
486
492
  "grain": "Grain speckle colour, drawn at aura-grain-opacity. Visible only on light grounds.",
487
493
  "status-neutral-bg": "Status pill fill for not-started / unknown states (To Do, Draft). Dark theme uses a quiet zinc-800 fill so it sits below the coloured states. ADDED.",
488
494
  "status-neutral-fg": "Label and icon on aura-status-neutral-bg (light 9.5:1, dark zinc-300 on zinc-800).",
489
- "status-progress-bg": "Status pill fill for work under way (In Progress, In Review). ADDED.",
490
- "status-progress-fg": "Label and icon on aura-status-progress-bg (7.6:1).",
491
- "status-ready-bg": "Status pill fill for finished / good states (Ready, Done). The source's lime pill. ADDED as a named token.",
492
- "status-ready-fg": "Label and icon on aura-status-ready-bg (15.2:1).",
495
+ "status-progress-bg": "Status pill fill for work under way (In Progress, In Review). Dark: a quiet violet-tinted fill (violet-500 at 20% over zinc-900) so the pill sits below the row text. ADDED; dark 4.11.",
496
+ "status-progress-fg": "Label and icon on aura-status-progress-bg (light 7.6:1; dark violet-300, 7.6:1).",
497
+ "status-ready-bg": "Status pill fill for finished / good states (Ready, Done). The source's lime pill. Dark: a lime-tinted fill (lime-400 at 14% over zinc-900). ADDED as a named token; dark 4.11.",
498
+ "status-ready-fg": "Label and icon on aura-status-ready-bg (light 15.2:1; dark lime-300, 9.9:1).",
493
499
  "status-blocked-bg": "Status pill fill for stopped / failed states (Blocked, Failed). Dark on purpose: 5.5:1 lighter-to-darker against the lime Ready fill, so Ready and Blocked differ by lightness, not only red vs green. ADDED.",
494
500
  "status-blocked-fg": "Label and icon on aura-status-blocked-bg (6.5:1).",
495
501
  "bg-selected": "Selected table rows and list items. Opaque so pinned columns can sit on it (dark = a 14% violet-400 wash over zinc-900, flattened). aura-fg-primary on it ≥14.2:1, aura-fg-secondary ≥5.5:1, focus ring ≥5.2:1 in both themes. ADDED.",
@@ -529,6 +535,10 @@
529
535
  "chart-1": "Categorical chart colours chart-1…8, in this order: violet, teal, orange, blue, magenta, green, gold, rose. Every one is ≥3:1 on bg-surface and bg-canvas in both themes (WCAG 1.4.11), and neighbours alternate dark/mid lightness (about 2:1 apart) so they stay apart under colour-blindness. chart-1 follows the brand in createTheme. Label series too; colour is never the only cue. ADDED 4.10.",
530
536
  "chart-seq-1": "Sequential ramp chart-seq-1…5 (low → high) for heatmaps and ordered buckets. seq-1 is the value closest to the surface; every step ≥3:1 on bg-surface. Brand hue in createTheme. ADDED 4.10.",
531
537
  "chart-grid": "Chart grid lines. Decorative, no contrast target. ADDED 4.10.",
532
- "chart-axis": "Axis lines, ticks and tick labels (text: 4.5:1 on bg-surface and bg-canvas). ADDED 4.10."
538
+ "chart-axis": "Axis lines, ticks and tick labels (text: 4.5:1 on bg-surface and bg-canvas). ADDED 4.10.",
539
+ "progress-track": "Empty part of Progress and FileUpload bars (fill). Its edge carries the 3:1. ADDED 4.11.",
540
+ "progress-track-edge": "1px inset edge of Progress / upload tracks: ≥3:1 on bg-surface and bg-canvas in both themes (WCAG 1.4.11), so the track reads without the fill. ADDED 4.11.",
541
+ "input-font-size": "Text size in inputs, textareas, selects and pickers. Phones (<640px) use at least 16px so iOS Safari does not zoom on focus. ADDED 4.11.",
542
+ "touch-target": "Minimum hit area on touch screens (pointer: coarse): IconButton, and Radio / Checkbox / Switch rows (WCAG 2.5.5). ADDED 4.11."
533
543
  }
534
544
  }