@jirawatpyk/aura-react 5.30.0 → 5.31.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 +5 -0
- package/dist/aura.bundle.js +53 -3
- package/dist/cjs/index.cjs +53 -3
- package/dist/esm/Field.js +21 -2
- package/dist/esm/TextField.js +3 -2
- package/dist/esm/Textarea.js +3 -2
- package/dist/esm/theme.js +31 -0
- package/dist/index.d.cts +17 -0
- package/dist/index.d.ts +17 -0
- package/dist/server/index.cjs +31 -0
- package/dist/server/index.js +31 -0
- package/dist/styles.css +3 -1
- package/dist/styles.layer.css +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -186,6 +186,11 @@ 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.31 — Chamber-OS addenda 41–42
|
|
190
|
+
|
|
191
|
+
- **`labelAddon` on TextField, Textarea and PasswordField** (item 138): a node between the label and the box, in the field's 6px gap — e.g. the phrase to type on a typed confirmation, as a chip with a copy button, so it is read before the box and can be copied. The hint and error stay below the box. The addon's box is `.aura-field__addon` with the id `{id}-addon`, and that id comes first in the input's `aria-describedby` (then the error or hint, then your own `aria-describedby` ids), so a screen reader reads it after the label; keep any button names in it short ("Copy"). `labelAddonDescribes={false}` keeps it out — for an addon that isn't a description (a "Forgot password?" link), or to name only part of it (give that part an id and pass it in `aria-describedby`); ids are never repeated. A focusable control in it comes before the input in tab order; clicking the label still focuses the input. `Field` takes `labelAddon` too, for a custom control (add `{id}-addon` to that control's `aria-describedby` yourself). The other fields (Select, Combobox, NumberField, the pickers, FileUpload) don't take it yet. Unset, nothing changes.
|
|
192
|
+
- **"Chosen" follows the brand** (item 139): `createTheme`, `<ThemeStyle>` and `npx aura-theme --brand` now emit `--aura-control-checked-bg` / `-fg` for light and dark, so a themed product's checked box, radio dot, switch, active tab underline, current page, selected day and year, completed step and checked menu item match its links and focus instead of staying violet. Light is the theme's accent itself; dark is the brand's 300 step, lightened to at least 3:1 on the dark surface and canvas (as AURA's own violet-300). The mark on it is white or ink, whichever reads better; both are in the theme's contrast checks (fill 3:1 on surface and canvas, mark 4.5:1 on the fill). In aura.css the light `--aura-control-checked-bg` is now `var(--aura-accent-violet)` (the same violet-700 by default), so a hand-written `:root` override of the accent carries it too; a scoped override needs the generator, or both tokens. Unthemed, nothing changes. Remove any hand-written `--aura-control-checked-*` stand-in after regenerating the theme.
|
|
193
|
+
|
|
189
194
|
## 5.30 — Visual polish (audit, Oct 2026) and Chamber-OS addenda 38–40
|
|
190
195
|
|
|
191
196
|
One release: everything below ships together in 5.30.0.
|
package/dist/aura.bundle.js
CHANGED
|
@@ -1755,6 +1755,7 @@ window.Aura = (() => {
|
|
|
1755
1755
|
props.required ? /* @__PURE__ */ React12.createElement("span", { className: "aura-field__req", "aria-hidden": true }, " *") : null,
|
|
1756
1756
|
props.optional ? /* @__PURE__ */ React12.createElement("span", { className: "aura-field__opt" }, " (" + t.optional + ")") : null
|
|
1757
1757
|
) : null,
|
|
1758
|
+
hasAddon(props.labelAddon) ? /* @__PURE__ */ React12.createElement("div", { className: "aura-field__addon", id: props.id + "-addon" }, props.labelAddon) : null,
|
|
1758
1759
|
props.children,
|
|
1759
1760
|
props.error ? /* @__PURE__ */ React12.createElement("p", { className: "aura-field__error", id: props.id + "-error" }, /* @__PURE__ */ React12.createElement(Icon, { name: /* @__PURE__ */ React12.createElement(IconCircleAlert, null), size: 14 }), props.error) : props.hint ? /* @__PURE__ */ React12.createElement("p", { className: "aura-field__hint", id: props.id + "-hint" }, props.hint) : null
|
|
1760
1761
|
);
|
|
@@ -1762,6 +1763,20 @@ window.Aura = (() => {
|
|
|
1762
1763
|
function describedBy(id, p) {
|
|
1763
1764
|
return p.error ? id + "-error" : p.hint ? id + "-hint" : void 0;
|
|
1764
1765
|
}
|
|
1766
|
+
function hasAddon(n3) {
|
|
1767
|
+
return n3 != null && typeof n3 !== "boolean" && n3 !== "";
|
|
1768
|
+
}
|
|
1769
|
+
function joinDescribedBy(id, p, own) {
|
|
1770
|
+
const ids = [
|
|
1771
|
+
hasAddon(p.labelAddon) && p.labelAddonDescribes !== false ? id + "-addon" : "",
|
|
1772
|
+
describedBy(id, p) || ""
|
|
1773
|
+
].concat(typeof own === "string" ? own.split(/\s+/) : []);
|
|
1774
|
+
const out = [];
|
|
1775
|
+
ids.forEach(function(x) {
|
|
1776
|
+
if (x && out.indexOf(x) < 0) out.push(x);
|
|
1777
|
+
});
|
|
1778
|
+
return out.join(" ") || void 0;
|
|
1779
|
+
}
|
|
1765
1780
|
var FIELD_KEYS = [
|
|
1766
1781
|
"label",
|
|
1767
1782
|
"hint",
|
|
@@ -1774,7 +1789,9 @@ window.Aura = (() => {
|
|
|
1774
1789
|
"suffix",
|
|
1775
1790
|
"options",
|
|
1776
1791
|
"placeholder",
|
|
1777
|
-
"touchHeight"
|
|
1792
|
+
"touchHeight",
|
|
1793
|
+
"labelAddon",
|
|
1794
|
+
"labelAddonDescribes"
|
|
1778
1795
|
];
|
|
1779
1796
|
|
|
1780
1797
|
// src/TextField.tsx
|
|
@@ -1791,6 +1808,7 @@ window.Aura = (() => {
|
|
|
1791
1808
|
error: props.error,
|
|
1792
1809
|
required: props.required,
|
|
1793
1810
|
optional: props.optional,
|
|
1811
|
+
labelAddon: props.labelAddon,
|
|
1794
1812
|
disabled: props.disabled,
|
|
1795
1813
|
className: cx(touchClass(props.touchHeight), props.className)
|
|
1796
1814
|
},
|
|
@@ -1805,7 +1823,7 @@ window.Aura = (() => {
|
|
|
1805
1823
|
placeholder: props.placeholder,
|
|
1806
1824
|
required: props.required,
|
|
1807
1825
|
"aria-invalid": props.error ? true : rest["aria-invalid"],
|
|
1808
|
-
"aria-describedby":
|
|
1826
|
+
"aria-describedby": joinDescribedBy(id, props, rest["aria-describedby"])
|
|
1809
1827
|
}
|
|
1810
1828
|
), props.suffix ? /* @__PURE__ */ React13.createElement("span", { className: "aura-input__suffix" }, props.suffix) : null)
|
|
1811
1829
|
);
|
|
@@ -1825,6 +1843,7 @@ window.Aura = (() => {
|
|
|
1825
1843
|
error: props.error,
|
|
1826
1844
|
required: props.required,
|
|
1827
1845
|
optional: props.optional,
|
|
1846
|
+
labelAddon: props.labelAddon,
|
|
1828
1847
|
disabled: props.disabled,
|
|
1829
1848
|
className: cx(touchClass(props.touchHeight), props.className)
|
|
1830
1849
|
},
|
|
@@ -1839,7 +1858,7 @@ window.Aura = (() => {
|
|
|
1839
1858
|
placeholder: props.placeholder,
|
|
1840
1859
|
required: props.required,
|
|
1841
1860
|
"aria-invalid": props.error ? true : rest["aria-invalid"],
|
|
1842
|
-
"aria-describedby":
|
|
1861
|
+
"aria-describedby": joinDescribedBy(id, props, rest["aria-describedby"])
|
|
1843
1862
|
}
|
|
1844
1863
|
)
|
|
1845
1864
|
);
|
|
@@ -8582,6 +8601,13 @@ window.Aura = (() => {
|
|
|
8582
8601
|
D["accent-lime"] = s[200];
|
|
8583
8602
|
D["mesh-to"] = s[200];
|
|
8584
8603
|
}
|
|
8604
|
+
function onFill(bg) {
|
|
8605
|
+
return contrast(ZINC[0], bg) >= contrast(INK, bg) ? ZINC[0] : INK;
|
|
8606
|
+
}
|
|
8607
|
+
L["control-checked-bg"] = L["accent-violet"];
|
|
8608
|
+
L["control-checked-fg"] = onFill(L["control-checked-bg"]);
|
|
8609
|
+
D["control-checked-bg"] = fit(b[300], darkGrounds, 3, 1);
|
|
8610
|
+
D["control-checked-fg"] = onFill(D["control-checked-bg"]);
|
|
8585
8611
|
const shadowLight = INK, shadowDark = D["accent-violet"];
|
|
8586
8612
|
if (o.primary === "brand") {
|
|
8587
8613
|
L["button-primary-bg"] = fit(b[600], [ZINC[0]], 4.5, -1);
|
|
@@ -8664,6 +8690,30 @@ window.Aura = (() => {
|
|
|
8664
8690
|
);
|
|
8665
8691
|
}
|
|
8666
8692
|
if (s) check("light", "ink", "accent-lime (signal)", 4.5, INK, s[200]);
|
|
8693
|
+
[
|
|
8694
|
+
[
|
|
8695
|
+
"light",
|
|
8696
|
+
L,
|
|
8697
|
+
[
|
|
8698
|
+
["bg-surface", ZINC[0]],
|
|
8699
|
+
["bg-canvas", ZINC[50]]
|
|
8700
|
+
]
|
|
8701
|
+
],
|
|
8702
|
+
[
|
|
8703
|
+
"dark",
|
|
8704
|
+
D,
|
|
8705
|
+
[
|
|
8706
|
+
["bg-surface", ZINC[900]],
|
|
8707
|
+
["bg-canvas", ZINC[950]]
|
|
8708
|
+
]
|
|
8709
|
+
]
|
|
8710
|
+
].forEach(function(g) {
|
|
8711
|
+
const t = g[0], m = g[1];
|
|
8712
|
+
g[2].forEach(function(gr) {
|
|
8713
|
+
check(t, "control-checked-bg", gr[0], 3, m["control-checked-bg"], gr[1]);
|
|
8714
|
+
});
|
|
8715
|
+
check(t, "control-checked-fg", "control-checked-bg", 4.5, m["control-checked-fg"], m["control-checked-bg"]);
|
|
8716
|
+
});
|
|
8667
8717
|
function css(selector) {
|
|
8668
8718
|
if (selector !== void 0 && /[<{};@\r\n]|\/\*|\*\//.test(selector))
|
|
8669
8719
|
throw new Error('createTheme: "' + selector + '" is not a plain CSS selector');
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -1737,6 +1737,7 @@ var Field = React12.forwardRef(function Field2(props, ref) {
|
|
|
1737
1737
|
props.required ? /* @__PURE__ */ React12.createElement("span", { className: "aura-field__req", "aria-hidden": true }, " *") : null,
|
|
1738
1738
|
props.optional ? /* @__PURE__ */ React12.createElement("span", { className: "aura-field__opt" }, " (" + t.optional + ")") : null
|
|
1739
1739
|
) : null,
|
|
1740
|
+
hasAddon(props.labelAddon) ? /* @__PURE__ */ React12.createElement("div", { className: "aura-field__addon", id: props.id + "-addon" }, props.labelAddon) : null,
|
|
1740
1741
|
props.children,
|
|
1741
1742
|
props.error ? /* @__PURE__ */ React12.createElement("p", { className: "aura-field__error", id: props.id + "-error" }, /* @__PURE__ */ React12.createElement(Icon, { name: /* @__PURE__ */ React12.createElement(IconCircleAlert, null), size: 14 }), props.error) : props.hint ? /* @__PURE__ */ React12.createElement("p", { className: "aura-field__hint", id: props.id + "-hint" }, props.hint) : null
|
|
1742
1743
|
);
|
|
@@ -1744,6 +1745,20 @@ var Field = React12.forwardRef(function Field2(props, ref) {
|
|
|
1744
1745
|
function describedBy(id, p) {
|
|
1745
1746
|
return p.error ? id + "-error" : p.hint ? id + "-hint" : void 0;
|
|
1746
1747
|
}
|
|
1748
|
+
function hasAddon(n3) {
|
|
1749
|
+
return n3 != null && typeof n3 !== "boolean" && n3 !== "";
|
|
1750
|
+
}
|
|
1751
|
+
function joinDescribedBy(id, p, own) {
|
|
1752
|
+
const ids = [
|
|
1753
|
+
hasAddon(p.labelAddon) && p.labelAddonDescribes !== false ? id + "-addon" : "",
|
|
1754
|
+
describedBy(id, p) || ""
|
|
1755
|
+
].concat(typeof own === "string" ? own.split(/\s+/) : []);
|
|
1756
|
+
const out = [];
|
|
1757
|
+
ids.forEach(function(x) {
|
|
1758
|
+
if (x && out.indexOf(x) < 0) out.push(x);
|
|
1759
|
+
});
|
|
1760
|
+
return out.join(" ") || void 0;
|
|
1761
|
+
}
|
|
1747
1762
|
var FIELD_KEYS = [
|
|
1748
1763
|
"label",
|
|
1749
1764
|
"hint",
|
|
@@ -1756,7 +1771,9 @@ var FIELD_KEYS = [
|
|
|
1756
1771
|
"suffix",
|
|
1757
1772
|
"options",
|
|
1758
1773
|
"placeholder",
|
|
1759
|
-
"touchHeight"
|
|
1774
|
+
"touchHeight",
|
|
1775
|
+
"labelAddon",
|
|
1776
|
+
"labelAddonDescribes"
|
|
1760
1777
|
];
|
|
1761
1778
|
|
|
1762
1779
|
// src/TextField.tsx
|
|
@@ -1773,6 +1790,7 @@ var TextField = React13.forwardRef(function TextField2(props, ref) {
|
|
|
1773
1790
|
error: props.error,
|
|
1774
1791
|
required: props.required,
|
|
1775
1792
|
optional: props.optional,
|
|
1793
|
+
labelAddon: props.labelAddon,
|
|
1776
1794
|
disabled: props.disabled,
|
|
1777
1795
|
className: cx(touchClass(props.touchHeight), props.className)
|
|
1778
1796
|
},
|
|
@@ -1787,7 +1805,7 @@ var TextField = React13.forwardRef(function TextField2(props, ref) {
|
|
|
1787
1805
|
placeholder: props.placeholder,
|
|
1788
1806
|
required: props.required,
|
|
1789
1807
|
"aria-invalid": props.error ? true : rest["aria-invalid"],
|
|
1790
|
-
"aria-describedby":
|
|
1808
|
+
"aria-describedby": joinDescribedBy(id, props, rest["aria-describedby"])
|
|
1791
1809
|
}
|
|
1792
1810
|
), props.suffix ? /* @__PURE__ */ React13.createElement("span", { className: "aura-input__suffix" }, props.suffix) : null)
|
|
1793
1811
|
);
|
|
@@ -1807,6 +1825,7 @@ var Textarea = React14.forwardRef(function Textarea2(props, ref) {
|
|
|
1807
1825
|
error: props.error,
|
|
1808
1826
|
required: props.required,
|
|
1809
1827
|
optional: props.optional,
|
|
1828
|
+
labelAddon: props.labelAddon,
|
|
1810
1829
|
disabled: props.disabled,
|
|
1811
1830
|
className: cx(touchClass(props.touchHeight), props.className)
|
|
1812
1831
|
},
|
|
@@ -1821,7 +1840,7 @@ var Textarea = React14.forwardRef(function Textarea2(props, ref) {
|
|
|
1821
1840
|
placeholder: props.placeholder,
|
|
1822
1841
|
required: props.required,
|
|
1823
1842
|
"aria-invalid": props.error ? true : rest["aria-invalid"],
|
|
1824
|
-
"aria-describedby":
|
|
1843
|
+
"aria-describedby": joinDescribedBy(id, props, rest["aria-describedby"])
|
|
1825
1844
|
}
|
|
1826
1845
|
)
|
|
1827
1846
|
);
|
|
@@ -8564,6 +8583,13 @@ function createTheme(opts) {
|
|
|
8564
8583
|
D["accent-lime"] = s[200];
|
|
8565
8584
|
D["mesh-to"] = s[200];
|
|
8566
8585
|
}
|
|
8586
|
+
function onFill(bg) {
|
|
8587
|
+
return contrast(ZINC[0], bg) >= contrast(INK, bg) ? ZINC[0] : INK;
|
|
8588
|
+
}
|
|
8589
|
+
L["control-checked-bg"] = L["accent-violet"];
|
|
8590
|
+
L["control-checked-fg"] = onFill(L["control-checked-bg"]);
|
|
8591
|
+
D["control-checked-bg"] = fit(b[300], darkGrounds, 3, 1);
|
|
8592
|
+
D["control-checked-fg"] = onFill(D["control-checked-bg"]);
|
|
8567
8593
|
const shadowLight = INK, shadowDark = D["accent-violet"];
|
|
8568
8594
|
if (o.primary === "brand") {
|
|
8569
8595
|
L["button-primary-bg"] = fit(b[600], [ZINC[0]], 4.5, -1);
|
|
@@ -8646,6 +8672,30 @@ function createTheme(opts) {
|
|
|
8646
8672
|
);
|
|
8647
8673
|
}
|
|
8648
8674
|
if (s) check("light", "ink", "accent-lime (signal)", 4.5, INK, s[200]);
|
|
8675
|
+
[
|
|
8676
|
+
[
|
|
8677
|
+
"light",
|
|
8678
|
+
L,
|
|
8679
|
+
[
|
|
8680
|
+
["bg-surface", ZINC[0]],
|
|
8681
|
+
["bg-canvas", ZINC[50]]
|
|
8682
|
+
]
|
|
8683
|
+
],
|
|
8684
|
+
[
|
|
8685
|
+
"dark",
|
|
8686
|
+
D,
|
|
8687
|
+
[
|
|
8688
|
+
["bg-surface", ZINC[900]],
|
|
8689
|
+
["bg-canvas", ZINC[950]]
|
|
8690
|
+
]
|
|
8691
|
+
]
|
|
8692
|
+
].forEach(function(g) {
|
|
8693
|
+
const t = g[0], m = g[1];
|
|
8694
|
+
g[2].forEach(function(gr) {
|
|
8695
|
+
check(t, "control-checked-bg", gr[0], 3, m["control-checked-bg"], gr[1]);
|
|
8696
|
+
});
|
|
8697
|
+
check(t, "control-checked-fg", "control-checked-bg", 4.5, m["control-checked-fg"], m["control-checked-bg"]);
|
|
8698
|
+
});
|
|
8649
8699
|
function css(selector) {
|
|
8650
8700
|
if (selector !== void 0 && /[<{};@\r\n]|\/\*|\*\//.test(selector))
|
|
8651
8701
|
throw new Error('createTheme: "' + selector + '" is not a plain CSS selector');
|
package/dist/esm/Field.js
CHANGED
|
@@ -20,6 +20,7 @@ const Field = React.forwardRef(function Field2(props, ref) {
|
|
|
20
20
|
props.required ? /* @__PURE__ */ React.createElement("span", { className: "aura-field__req", "aria-hidden": true }, " *") : null,
|
|
21
21
|
props.optional ? /* @__PURE__ */ React.createElement("span", { className: "aura-field__opt" }, " (" + t.optional + ")") : null
|
|
22
22
|
) : null,
|
|
23
|
+
hasAddon(props.labelAddon) ? /* @__PURE__ */ React.createElement("div", { className: "aura-field__addon", id: props.id + "-addon" }, props.labelAddon) : null,
|
|
23
24
|
props.children,
|
|
24
25
|
props.error ? /* @__PURE__ */ React.createElement("p", { className: "aura-field__error", id: props.id + "-error" }, /* @__PURE__ */ React.createElement(Icon, { name: /* @__PURE__ */ React.createElement(IconCircleAlert, null), size: 14 }), props.error) : props.hint ? /* @__PURE__ */ React.createElement("p", { className: "aura-field__hint", id: props.id + "-hint" }, props.hint) : null
|
|
25
26
|
);
|
|
@@ -27,6 +28,20 @@ const Field = React.forwardRef(function Field2(props, ref) {
|
|
|
27
28
|
function describedBy(id, p) {
|
|
28
29
|
return p.error ? id + "-error" : p.hint ? id + "-hint" : void 0;
|
|
29
30
|
}
|
|
31
|
+
function hasAddon(n) {
|
|
32
|
+
return n != null && typeof n !== "boolean" && n !== "";
|
|
33
|
+
}
|
|
34
|
+
function joinDescribedBy(id, p, own) {
|
|
35
|
+
const ids = [
|
|
36
|
+
hasAddon(p.labelAddon) && p.labelAddonDescribes !== false ? id + "-addon" : "",
|
|
37
|
+
describedBy(id, p) || ""
|
|
38
|
+
].concat(typeof own === "string" ? own.split(/\s+/) : []);
|
|
39
|
+
const out = [];
|
|
40
|
+
ids.forEach(function(x) {
|
|
41
|
+
if (x && out.indexOf(x) < 0) out.push(x);
|
|
42
|
+
});
|
|
43
|
+
return out.join(" ") || void 0;
|
|
44
|
+
}
|
|
30
45
|
const FIELD_KEYS = [
|
|
31
46
|
"label",
|
|
32
47
|
"hint",
|
|
@@ -39,10 +54,14 @@ const FIELD_KEYS = [
|
|
|
39
54
|
"suffix",
|
|
40
55
|
"options",
|
|
41
56
|
"placeholder",
|
|
42
|
-
"touchHeight"
|
|
57
|
+
"touchHeight",
|
|
58
|
+
"labelAddon",
|
|
59
|
+
"labelAddonDescribes"
|
|
43
60
|
];
|
|
44
61
|
export {
|
|
45
62
|
FIELD_KEYS,
|
|
46
63
|
Field,
|
|
47
|
-
describedBy
|
|
64
|
+
describedBy,
|
|
65
|
+
hasAddon,
|
|
66
|
+
joinDescribedBy
|
|
48
67
|
};
|
package/dist/esm/TextField.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import * as React from "react";
|
|
3
|
-
import { FIELD_KEYS, Field,
|
|
3
|
+
import { FIELD_KEYS, Field, joinDescribedBy } from "./Field.js";
|
|
4
4
|
import { Icon } from "./Icon.js";
|
|
5
5
|
import { cx, omit, touchClass, uid } from "./internal.js";
|
|
6
6
|
const TextField = React.forwardRef(function TextField2(props, ref) {
|
|
@@ -15,6 +15,7 @@ const TextField = React.forwardRef(function TextField2(props, ref) {
|
|
|
15
15
|
error: props.error,
|
|
16
16
|
required: props.required,
|
|
17
17
|
optional: props.optional,
|
|
18
|
+
labelAddon: props.labelAddon,
|
|
18
19
|
disabled: props.disabled,
|
|
19
20
|
className: cx(touchClass(props.touchHeight), props.className)
|
|
20
21
|
},
|
|
@@ -29,7 +30,7 @@ const TextField = React.forwardRef(function TextField2(props, ref) {
|
|
|
29
30
|
placeholder: props.placeholder,
|
|
30
31
|
required: props.required,
|
|
31
32
|
"aria-invalid": props.error ? true : rest["aria-invalid"],
|
|
32
|
-
"aria-describedby":
|
|
33
|
+
"aria-describedby": joinDescribedBy(id, props, rest["aria-describedby"])
|
|
33
34
|
}
|
|
34
35
|
), props.suffix ? /* @__PURE__ */ React.createElement("span", { className: "aura-input__suffix" }, props.suffix) : null)
|
|
35
36
|
);
|
package/dist/esm/Textarea.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import * as React from "react";
|
|
3
|
-
import { FIELD_KEYS, Field,
|
|
3
|
+
import { FIELD_KEYS, Field, joinDescribedBy } from "./Field.js";
|
|
4
4
|
import { cx, omit, touchClass, uid } from "./internal.js";
|
|
5
5
|
const Textarea = React.forwardRef(function Textarea2(props, ref) {
|
|
6
6
|
const auto = uid(), id = props.id || auto;
|
|
@@ -14,6 +14,7 @@ const Textarea = React.forwardRef(function Textarea2(props, ref) {
|
|
|
14
14
|
error: props.error,
|
|
15
15
|
required: props.required,
|
|
16
16
|
optional: props.optional,
|
|
17
|
+
labelAddon: props.labelAddon,
|
|
17
18
|
disabled: props.disabled,
|
|
18
19
|
className: cx(touchClass(props.touchHeight), props.className)
|
|
19
20
|
},
|
|
@@ -28,7 +29,7 @@ const Textarea = React.forwardRef(function Textarea2(props, ref) {
|
|
|
28
29
|
placeholder: props.placeholder,
|
|
29
30
|
required: props.required,
|
|
30
31
|
"aria-invalid": props.error ? true : rest["aria-invalid"],
|
|
31
|
-
"aria-describedby":
|
|
32
|
+
"aria-describedby": joinDescribedBy(id, props, rest["aria-describedby"])
|
|
32
33
|
}
|
|
33
34
|
)
|
|
34
35
|
);
|
package/dist/esm/theme.js
CHANGED
|
@@ -162,6 +162,13 @@ function createTheme(opts) {
|
|
|
162
162
|
D["accent-lime"] = s[200];
|
|
163
163
|
D["mesh-to"] = s[200];
|
|
164
164
|
}
|
|
165
|
+
function onFill(bg) {
|
|
166
|
+
return contrast(ZINC[0], bg) >= contrast(INK, bg) ? ZINC[0] : INK;
|
|
167
|
+
}
|
|
168
|
+
L["control-checked-bg"] = L["accent-violet"];
|
|
169
|
+
L["control-checked-fg"] = onFill(L["control-checked-bg"]);
|
|
170
|
+
D["control-checked-bg"] = fit(b[300], darkGrounds, 3, 1);
|
|
171
|
+
D["control-checked-fg"] = onFill(D["control-checked-bg"]);
|
|
165
172
|
const shadowLight = INK, shadowDark = D["accent-violet"];
|
|
166
173
|
if (o.primary === "brand") {
|
|
167
174
|
L["button-primary-bg"] = fit(b[600], [ZINC[0]], 4.5, -1);
|
|
@@ -244,6 +251,30 @@ function createTheme(opts) {
|
|
|
244
251
|
);
|
|
245
252
|
}
|
|
246
253
|
if (s) check("light", "ink", "accent-lime (signal)", 4.5, INK, s[200]);
|
|
254
|
+
[
|
|
255
|
+
[
|
|
256
|
+
"light",
|
|
257
|
+
L,
|
|
258
|
+
[
|
|
259
|
+
["bg-surface", ZINC[0]],
|
|
260
|
+
["bg-canvas", ZINC[50]]
|
|
261
|
+
]
|
|
262
|
+
],
|
|
263
|
+
[
|
|
264
|
+
"dark",
|
|
265
|
+
D,
|
|
266
|
+
[
|
|
267
|
+
["bg-surface", ZINC[900]],
|
|
268
|
+
["bg-canvas", ZINC[950]]
|
|
269
|
+
]
|
|
270
|
+
]
|
|
271
|
+
].forEach(function(g) {
|
|
272
|
+
const t = g[0], m = g[1];
|
|
273
|
+
g[2].forEach(function(gr) {
|
|
274
|
+
check(t, "control-checked-bg", gr[0], 3, m["control-checked-bg"], gr[1]);
|
|
275
|
+
});
|
|
276
|
+
check(t, "control-checked-fg", "control-checked-bg", 4.5, m["control-checked-fg"], m["control-checked-bg"]);
|
|
277
|
+
});
|
|
247
278
|
function css(selector) {
|
|
248
279
|
if (selector !== void 0 && /[<{};@\r\n]|\/\*|\*\//.test(selector))
|
|
249
280
|
throw new Error('createTheme: "' + selector + '" is not a plain CSS selector');
|
package/dist/index.d.cts
CHANGED
|
@@ -415,6 +415,13 @@ export interface TextFieldProps extends FieldProps, Omit<React$1.InputHTMLAttrib
|
|
|
415
415
|
icon?: IconInput | undefined;
|
|
416
416
|
/** Trailing unit, e.g. "THB". */
|
|
417
417
|
suffix?: React$1.ReactNode | undefined;
|
|
418
|
+
/** 5.31 (Chamber-OS addendum 41): a node between the label and the box — e.g. the phrase to type, with a copy
|
|
419
|
+
* button, on a typed confirmation. The hint and error stay below. Its box's id (`{id}-addon`) comes first in the
|
|
420
|
+
* input's `aria-describedby`, so its text is read after the label; keep any button names in it short. */
|
|
421
|
+
labelAddon?: React$1.ReactNode | undefined;
|
|
422
|
+
/** `false` keeps the addon out of `aria-describedby` — for one that isn't a description (a "Forgot password?"
|
|
423
|
+
* link), or to name only part of it: give that part an id and pass it in `aria-describedby`. Default `true`. */
|
|
424
|
+
labelAddonDescribes?: boolean | undefined;
|
|
418
425
|
/** 44px box (5.30, Chamber-OS 135): `true` below 640px or on a coarse pointer, as Button's `touchHeight`; `'always'`
|
|
419
426
|
* at every width, also with a mouse in compact density — for a form whose spec asks for 44px targets everywhere.
|
|
420
427
|
* Default: the density's input height. */
|
|
@@ -540,6 +547,13 @@ export interface CommandProps {
|
|
|
540
547
|
className?: string | undefined;
|
|
541
548
|
}
|
|
542
549
|
export interface TextareaProps extends FieldProps, Omit<React$1.TextareaHTMLAttributes<HTMLTextAreaElement>, "required"> {
|
|
550
|
+
/** 5.31 (Chamber-OS addendum 41): a node between the label and the box — e.g. the phrase to type, with a copy
|
|
551
|
+
* button, on a typed confirmation. The hint and error stay below. Its box's id (`{id}-addon`) comes first in the
|
|
552
|
+
* input's `aria-describedby`, so its text is read after the label; keep any button names in it short. */
|
|
553
|
+
labelAddon?: React$1.ReactNode | undefined;
|
|
554
|
+
/** `false` keeps the addon out of `aria-describedby` — for one that isn't a description (a "Forgot password?"
|
|
555
|
+
* link), or to name only part of it: give that part an id and pass it in `aria-describedby`. Default `true`. */
|
|
556
|
+
labelAddonDescribes?: boolean | undefined;
|
|
543
557
|
/** Accepted like the other fields' (5.30, Chamber-OS 135), so a form can pass it to every field. A Textarea is
|
|
544
558
|
* always at least 96px tall, well over the 44px target, so it changes nothing you can see. */
|
|
545
559
|
touchHeight?: TouchHeight | undefined;
|
|
@@ -1634,6 +1648,9 @@ export interface FieldComponentProps extends Omit<FieldPropsPublic, "label"> {
|
|
|
1634
1648
|
/** The control's id: the label points at it, and the hint/error ids derive from it. */
|
|
1635
1649
|
id?: string | undefined;
|
|
1636
1650
|
children?: React$1.ReactNode | undefined;
|
|
1651
|
+
/** 5.31 (Chamber-OS addendum 41): a node between the label and the control, in a `.aura-field__addon` box with the
|
|
1652
|
+
* id `{id}-addon`. TextField and Textarea add that id to the input's `aria-describedby`; a custom control should too. */
|
|
1653
|
+
labelAddon?: React$1.ReactNode | undefined;
|
|
1637
1654
|
/** Render the label as another element (e.g. `span` for a group of controls) with this id. */
|
|
1638
1655
|
labelAs?: string | undefined;
|
|
1639
1656
|
labelId?: string | undefined;
|
package/dist/index.d.ts
CHANGED
|
@@ -415,6 +415,13 @@ export interface TextFieldProps extends FieldProps, Omit<React$1.InputHTMLAttrib
|
|
|
415
415
|
icon?: IconInput | undefined;
|
|
416
416
|
/** Trailing unit, e.g. "THB". */
|
|
417
417
|
suffix?: React$1.ReactNode | undefined;
|
|
418
|
+
/** 5.31 (Chamber-OS addendum 41): a node between the label and the box — e.g. the phrase to type, with a copy
|
|
419
|
+
* button, on a typed confirmation. The hint and error stay below. Its box's id (`{id}-addon`) comes first in the
|
|
420
|
+
* input's `aria-describedby`, so its text is read after the label; keep any button names in it short. */
|
|
421
|
+
labelAddon?: React$1.ReactNode | undefined;
|
|
422
|
+
/** `false` keeps the addon out of `aria-describedby` — for one that isn't a description (a "Forgot password?"
|
|
423
|
+
* link), or to name only part of it: give that part an id and pass it in `aria-describedby`. Default `true`. */
|
|
424
|
+
labelAddonDescribes?: boolean | undefined;
|
|
418
425
|
/** 44px box (5.30, Chamber-OS 135): `true` below 640px or on a coarse pointer, as Button's `touchHeight`; `'always'`
|
|
419
426
|
* at every width, also with a mouse in compact density — for a form whose spec asks for 44px targets everywhere.
|
|
420
427
|
* Default: the density's input height. */
|
|
@@ -540,6 +547,13 @@ export interface CommandProps {
|
|
|
540
547
|
className?: string | undefined;
|
|
541
548
|
}
|
|
542
549
|
export interface TextareaProps extends FieldProps, Omit<React$1.TextareaHTMLAttributes<HTMLTextAreaElement>, "required"> {
|
|
550
|
+
/** 5.31 (Chamber-OS addendum 41): a node between the label and the box — e.g. the phrase to type, with a copy
|
|
551
|
+
* button, on a typed confirmation. The hint and error stay below. Its box's id (`{id}-addon`) comes first in the
|
|
552
|
+
* input's `aria-describedby`, so its text is read after the label; keep any button names in it short. */
|
|
553
|
+
labelAddon?: React$1.ReactNode | undefined;
|
|
554
|
+
/** `false` keeps the addon out of `aria-describedby` — for one that isn't a description (a "Forgot password?"
|
|
555
|
+
* link), or to name only part of it: give that part an id and pass it in `aria-describedby`. Default `true`. */
|
|
556
|
+
labelAddonDescribes?: boolean | undefined;
|
|
543
557
|
/** Accepted like the other fields' (5.30, Chamber-OS 135), so a form can pass it to every field. A Textarea is
|
|
544
558
|
* always at least 96px tall, well over the 44px target, so it changes nothing you can see. */
|
|
545
559
|
touchHeight?: TouchHeight | undefined;
|
|
@@ -1634,6 +1648,9 @@ export interface FieldComponentProps extends Omit<FieldPropsPublic, "label"> {
|
|
|
1634
1648
|
/** The control's id: the label points at it, and the hint/error ids derive from it. */
|
|
1635
1649
|
id?: string | undefined;
|
|
1636
1650
|
children?: React$1.ReactNode | undefined;
|
|
1651
|
+
/** 5.31 (Chamber-OS addendum 41): a node between the label and the control, in a `.aura-field__addon` box with the
|
|
1652
|
+
* id `{id}-addon`. TextField and Textarea add that id to the input's `aria-describedby`; a custom control should too. */
|
|
1653
|
+
labelAddon?: React$1.ReactNode | undefined;
|
|
1637
1654
|
/** Render the label as another element (e.g. `span` for a group of controls) with this id. */
|
|
1638
1655
|
labelAs?: string | undefined;
|
|
1639
1656
|
labelId?: string | undefined;
|
package/dist/server/index.cjs
CHANGED
|
@@ -768,6 +768,13 @@ function createTheme(opts) {
|
|
|
768
768
|
D["accent-lime"] = s[200];
|
|
769
769
|
D["mesh-to"] = s[200];
|
|
770
770
|
}
|
|
771
|
+
function onFill(bg) {
|
|
772
|
+
return contrast(ZINC[0], bg) >= contrast(INK, bg) ? ZINC[0] : INK;
|
|
773
|
+
}
|
|
774
|
+
L["control-checked-bg"] = L["accent-violet"];
|
|
775
|
+
L["control-checked-fg"] = onFill(L["control-checked-bg"]);
|
|
776
|
+
D["control-checked-bg"] = fit(b[300], darkGrounds, 3, 1);
|
|
777
|
+
D["control-checked-fg"] = onFill(D["control-checked-bg"]);
|
|
771
778
|
const shadowLight = INK, shadowDark = D["accent-violet"];
|
|
772
779
|
if (o.primary === "brand") {
|
|
773
780
|
L["button-primary-bg"] = fit(b[600], [ZINC[0]], 4.5, -1);
|
|
@@ -850,6 +857,30 @@ function createTheme(opts) {
|
|
|
850
857
|
);
|
|
851
858
|
}
|
|
852
859
|
if (s) check("light", "ink", "accent-lime (signal)", 4.5, INK, s[200]);
|
|
860
|
+
[
|
|
861
|
+
[
|
|
862
|
+
"light",
|
|
863
|
+
L,
|
|
864
|
+
[
|
|
865
|
+
["bg-surface", ZINC[0]],
|
|
866
|
+
["bg-canvas", ZINC[50]]
|
|
867
|
+
]
|
|
868
|
+
],
|
|
869
|
+
[
|
|
870
|
+
"dark",
|
|
871
|
+
D,
|
|
872
|
+
[
|
|
873
|
+
["bg-surface", ZINC[900]],
|
|
874
|
+
["bg-canvas", ZINC[950]]
|
|
875
|
+
]
|
|
876
|
+
]
|
|
877
|
+
].forEach(function(g) {
|
|
878
|
+
const t = g[0], m = g[1];
|
|
879
|
+
g[2].forEach(function(gr) {
|
|
880
|
+
check(t, "control-checked-bg", gr[0], 3, m["control-checked-bg"], gr[1]);
|
|
881
|
+
});
|
|
882
|
+
check(t, "control-checked-fg", "control-checked-bg", 4.5, m["control-checked-fg"], m["control-checked-bg"]);
|
|
883
|
+
});
|
|
853
884
|
function css(selector) {
|
|
854
885
|
if (selector !== void 0 && /[<{};@\r\n]|\/\*|\*\//.test(selector))
|
|
855
886
|
throw new Error('createTheme: "' + selector + '" is not a plain CSS selector');
|
package/dist/server/index.js
CHANGED
|
@@ -708,6 +708,13 @@ function createTheme(opts) {
|
|
|
708
708
|
D["accent-lime"] = s[200];
|
|
709
709
|
D["mesh-to"] = s[200];
|
|
710
710
|
}
|
|
711
|
+
function onFill(bg) {
|
|
712
|
+
return contrast(ZINC[0], bg) >= contrast(INK, bg) ? ZINC[0] : INK;
|
|
713
|
+
}
|
|
714
|
+
L["control-checked-bg"] = L["accent-violet"];
|
|
715
|
+
L["control-checked-fg"] = onFill(L["control-checked-bg"]);
|
|
716
|
+
D["control-checked-bg"] = fit(b[300], darkGrounds, 3, 1);
|
|
717
|
+
D["control-checked-fg"] = onFill(D["control-checked-bg"]);
|
|
711
718
|
const shadowLight = INK, shadowDark = D["accent-violet"];
|
|
712
719
|
if (o.primary === "brand") {
|
|
713
720
|
L["button-primary-bg"] = fit(b[600], [ZINC[0]], 4.5, -1);
|
|
@@ -790,6 +797,30 @@ function createTheme(opts) {
|
|
|
790
797
|
);
|
|
791
798
|
}
|
|
792
799
|
if (s) check("light", "ink", "accent-lime (signal)", 4.5, INK, s[200]);
|
|
800
|
+
[
|
|
801
|
+
[
|
|
802
|
+
"light",
|
|
803
|
+
L,
|
|
804
|
+
[
|
|
805
|
+
["bg-surface", ZINC[0]],
|
|
806
|
+
["bg-canvas", ZINC[50]]
|
|
807
|
+
]
|
|
808
|
+
],
|
|
809
|
+
[
|
|
810
|
+
"dark",
|
|
811
|
+
D,
|
|
812
|
+
[
|
|
813
|
+
["bg-surface", ZINC[900]],
|
|
814
|
+
["bg-canvas", ZINC[950]]
|
|
815
|
+
]
|
|
816
|
+
]
|
|
817
|
+
].forEach(function(g) {
|
|
818
|
+
const t = g[0], m = g[1];
|
|
819
|
+
g[2].forEach(function(gr) {
|
|
820
|
+
check(t, "control-checked-bg", gr[0], 3, m["control-checked-bg"], gr[1]);
|
|
821
|
+
});
|
|
822
|
+
check(t, "control-checked-fg", "control-checked-bg", 4.5, m["control-checked-fg"], m["control-checked-bg"]);
|
|
823
|
+
});
|
|
793
824
|
function css(selector) {
|
|
794
825
|
if (selector !== void 0 && /[<{};@\r\n]|\/\*|\*\//.test(selector))
|
|
795
826
|
throw new Error('createTheme: "' + selector + '" is not a plain CSS selector');
|
package/dist/styles.css
CHANGED
|
@@ -474,6 +474,8 @@ a.aura-icon-btn { text-decoration: none; }
|
|
|
474
474
|
.aura-field__hint, .aura-field__error { display: flex; align-items: flex-start; gap: var(--aura-space-1); margin: 0; font-size: 12px; line-height: 1.5; color: var(--aura-fg-secondary); }
|
|
475
475
|
.aura-field__error { color: var(--aura-fg-danger); }
|
|
476
476
|
.aura-field__error .aura-icon { margin-top: 2px; }
|
|
477
|
+
/* 5.31 (Chamber-OS addendum 41): TextField/Textarea `labelAddon`, between the label and the box, in the field's gap. */
|
|
478
|
+
.aura-field__addon { min-width: 0; font-size: 13px; line-height: 1.5; color: var(--aura-fg-primary); }
|
|
477
479
|
.aura-field.is-disabled .aura-field__label { color: var(--aura-fg-secondary); }
|
|
478
480
|
|
|
479
481
|
.aura-input {
|
|
@@ -2077,7 +2079,7 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
|
|
|
2077
2079
|
/* 5.30 (audit D): field labels, hints and errors and choice descriptions get Thai line room; a stacked card's field
|
|
2078
2080
|
* labels are 12px in the sans face (the mono face has no Thai), and a stacked DataTable card's values sit on a set
|
|
2079
2081
|
* 1.6 line, so a loading card (its bars follow 1lh) is as tall as one with Thai text. */
|
|
2080
|
-
.aura-field__label:lang(th), .aura-field__hint:lang(th), .aura-field__error:lang(th) { line-height: 1.6; }
|
|
2082
|
+
.aura-field__label:lang(th), .aura-field__hint:lang(th), .aura-field__error:lang(th), .aura-field__addon:lang(th) { line-height: 1.6; }
|
|
2081
2083
|
.aura-choice__desc:lang(th), .aura-check__desc:lang(th) { font-size: 13px; line-height: 1.6; }
|
|
2082
2084
|
.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: 12px; line-height: 18px; }
|
|
2083
2085
|
.aura-table--stacked .aura-table__td[data-label]:lang(th) { line-height: 1.6; }
|
package/dist/styles.layer.css
CHANGED
|
@@ -476,6 +476,8 @@ a.aura-icon-btn { text-decoration: none; }
|
|
|
476
476
|
.aura-field__hint, .aura-field__error { display: flex; align-items: flex-start; gap: var(--aura-space-1); margin: 0; font-size: 12px; line-height: 1.5; color: var(--aura-fg-secondary); }
|
|
477
477
|
.aura-field__error { color: var(--aura-fg-danger); }
|
|
478
478
|
.aura-field__error .aura-icon { margin-top: 2px; }
|
|
479
|
+
/* 5.31 (Chamber-OS addendum 41): TextField/Textarea `labelAddon`, between the label and the box, in the field's gap. */
|
|
480
|
+
.aura-field__addon { min-width: 0; font-size: 13px; line-height: 1.5; color: var(--aura-fg-primary); }
|
|
479
481
|
.aura-field.is-disabled .aura-field__label { color: var(--aura-fg-secondary); }
|
|
480
482
|
|
|
481
483
|
.aura-input {
|
|
@@ -2079,7 +2081,7 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
|
|
|
2079
2081
|
/* 5.30 (audit D): field labels, hints and errors and choice descriptions get Thai line room; a stacked card's field
|
|
2080
2082
|
* labels are 12px in the sans face (the mono face has no Thai), and a stacked DataTable card's values sit on a set
|
|
2081
2083
|
* 1.6 line, so a loading card (its bars follow 1lh) is as tall as one with Thai text. */
|
|
2082
|
-
.aura-field__label:lang(th), .aura-field__hint:lang(th), .aura-field__error:lang(th) { line-height: 1.6; }
|
|
2084
|
+
.aura-field__label:lang(th), .aura-field__hint:lang(th), .aura-field__error:lang(th), .aura-field__addon:lang(th) { line-height: 1.6; }
|
|
2083
2085
|
.aura-choice__desc:lang(th), .aura-check__desc:lang(th) { font-size: 13px; line-height: 1.6; }
|
|
2084
2086
|
.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: 12px; line-height: 18px; }
|
|
2085
2087
|
.aura-table--stacked .aura-table__td[data-label]:lang(th) { line-height: 1.6; }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jirawatpyk/aura-react",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.31.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",
|