@jirawatpyk/aura-react 5.16.1 → 5.17.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 +6 -0
- package/dist/aura.bundle.js +24 -7
- package/dist/cjs/index.cjs +24 -7
- package/dist/esm/Progress.js +1 -1
- package/dist/esm/display.js +23 -6
- package/dist/index.d.cts +12 -1
- package/dist/index.d.ts +12 -1
- package/dist/server/index.cjs +23 -6
- package/dist/server/index.d.cts +13 -1
- package/dist/server/index.d.ts +13 -1
- package/dist/server/index.js +23 -6
- package/dist/styles.css +14 -0
- package/dist/styles.layer.css +14 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -186,6 +186,12 @@ 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.17 — Chamber-OS addendum 18
|
|
190
|
+
|
|
191
|
+
- **Stat attributes, status line and a link on the label** (item 110): `id`, `data-*`, `aria-*`, `style`, `lang` and `dir` go on the `.aura-stat` root, from the root package and `/server` — a `data-testid`, or `aria-hidden` on a loading placeholder. `status` is a line under the value ("Active · renews 1 Jan" with its tone icon), hidden while loading. With `href`, `linkArea="label"` puts the link on the label (inside the heading when there is one) and stretches its hit area over the tile: a click anywhere follows it, the tile shows the focus ring and hover edge, and other controls in the tile (links, buttons, fields, anything focusable) stay clickable above it. `aria-label`, `aria-labelledby`, `aria-describedby` and `aria-current` then go on the link, and an `onClick` too. Text in such a tile can't be selected by dragging (the click belongs to the link). The default (`tile`) is unchanged. Only the documented attributes reach the root; anything else passed is dropped, as before.
|
|
192
|
+
- **Progress `valueText`** (item 111): what screen readers hear (`aria-valuetext`), apart from the shown `valueLabel` — show "2 of 6 used", read "2 used, 1 reserved, 3 remaining of 6".
|
|
193
|
+
- The CSS budget is 26 kB (was 25).
|
|
194
|
+
|
|
189
195
|
## 5.16.1 — Select ground (Chamber-OS 109)
|
|
190
196
|
|
|
191
197
|
- **A custom Select keeps the input ground.** The read-only rule for text fields matched the Select's trigger button too (`:read-only` matches anything not editable), so every custom Select showed the disabled ground and looked disabled. It now applies to a read-only `input` only; a read-only TextField still takes the disabled ground, and a read-only Textarea now does too.
|
package/dist/aura.bundle.js
CHANGED
|
@@ -717,8 +717,17 @@ window.Aura = (() => {
|
|
|
717
717
|
const tone2 = ch && (ch.tone || (dir === "up" ? "positive" : dir === "down" ? "negative" : "neutral"));
|
|
718
718
|
const v = props.value;
|
|
719
719
|
const numeric = typeof v === "number" || typeof v === "string" && /\d/.test(v) && /^[\s\d.,:+\-\u2212%()\u0E3F$\u20AC\u00A3\u00A5kKmMbB]+$/.test(v.replace(/\b[A-Z]{3}\b/g, ""));
|
|
720
|
-
const
|
|
720
|
+
const labelLink = !!props.href && props.linkArea === "label";
|
|
721
|
+
const Tag3 = labelLink ? "div" : props.href ? Link : props.onClick ? "button" : "div";
|
|
721
722
|
const interactive = !!(props.href || props.onClick);
|
|
723
|
+
const LINK_ARIA = ["aria-label", "aria-labelledby", "aria-describedby", "aria-current"];
|
|
724
|
+
const root = {}, toLink = {};
|
|
725
|
+
Object.keys(props).forEach(function(k) {
|
|
726
|
+
const v2 = props[k];
|
|
727
|
+
if (labelLink && LINK_ARIA.indexOf(k) >= 0) toLink[k] = v2;
|
|
728
|
+
else if (k === "id" || k === "style" || k === "lang" || k === "dir" || /^(aria|data)-/.test(k)) root[k] = v2;
|
|
729
|
+
});
|
|
730
|
+
const busy = props.loading || props["aria-busy"] || void 0;
|
|
722
731
|
if (props.headingLevel && Tag3 === "button")
|
|
723
732
|
devWarnOnce(
|
|
724
733
|
"stat-heading-button",
|
|
@@ -729,15 +738,23 @@ window.Aura = (() => {
|
|
|
729
738
|
return /* @__PURE__ */ React4.createElement(
|
|
730
739
|
Tag3,
|
|
731
740
|
{
|
|
741
|
+
...root,
|
|
732
742
|
ref,
|
|
733
|
-
className: cx(
|
|
734
|
-
|
|
735
|
-
|
|
743
|
+
className: cx(
|
|
744
|
+
"aura-stat",
|
|
745
|
+
interactive && "is-interactive",
|
|
746
|
+
labelLink && "aura-stat--label-link",
|
|
747
|
+
props.loading && "is-loading",
|
|
748
|
+
props.className
|
|
749
|
+
),
|
|
750
|
+
href: labelLink ? void 0 : props.href,
|
|
751
|
+
onClick: labelLink ? void 0 : props.onClick,
|
|
736
752
|
type: Tag3 === "button" ? "button" : void 0,
|
|
737
|
-
"aria-busy":
|
|
753
|
+
"aria-busy": busy
|
|
738
754
|
},
|
|
739
|
-
/* @__PURE__ */ React4.createElement(HeadTag, { className: "aura-stat__head" }, /* @__PURE__ */ React4.createElement(LabelTag, { className: "aura-stat__label" }, props.label), props.icon ? /* @__PURE__ */ React4.createElement("span", { className: "aura-stat__icon" }, /* @__PURE__ */ React4.createElement(Icon, { name: props.icon })) : null),
|
|
755
|
+
/* @__PURE__ */ React4.createElement(HeadTag, { className: "aura-stat__head" }, /* @__PURE__ */ React4.createElement(LabelTag, { className: "aura-stat__label" }, labelLink ? /* @__PURE__ */ React4.createElement(Link, { ...toLink, href: props.href, onClick: props.onClick, className: "aura-stat__link" }, props.label) : props.label), props.icon ? /* @__PURE__ */ React4.createElement("span", { className: "aura-stat__icon" }, /* @__PURE__ */ React4.createElement(Icon, { name: props.icon })) : null),
|
|
740
756
|
props.loading ? /* @__PURE__ */ React4.createElement("span", { className: "aura-stat__value" }, /* @__PURE__ */ React4.createElement("span", { className: "aura-skel aura-stat__skel" })) : /* @__PURE__ */ React4.createElement("span", { className: cx("aura-stat__value", numeric && "is-numeric") }, props.value, props.unit ? /* @__PURE__ */ React4.createElement("span", { className: "aura-stat__unit" }, props.unit) : null),
|
|
757
|
+
props.status != null && props.status !== false && props.status !== "" && !props.loading ? /* @__PURE__ */ React4.createElement("span", { className: "aura-stat__status" }, props.status) : null,
|
|
741
758
|
ch && !props.loading || props.caption ? /* @__PURE__ */ React4.createElement("span", { className: "aura-stat__foot" }, ch && !props.loading ? /* @__PURE__ */ React4.createElement("span", { className: cx("aura-stat__change", "is-" + tone2) }, /* @__PURE__ */ React4.createElement(
|
|
742
759
|
Icon,
|
|
743
760
|
{
|
|
@@ -8344,7 +8361,7 @@ window.Aura = (() => {
|
|
|
8344
8361
|
const pct = det ? Math.max(0, Math.min(100, props.value / max * 100)) : 0;
|
|
8345
8362
|
const sec = det && props.secondaryValue != null && props.secondaryValue > 0 ? props.secondaryValue : 0;
|
|
8346
8363
|
const spct = sec ? Math.max(0, Math.min(100 - pct, sec / max * 100)) : 0;
|
|
8347
|
-
const valueText = props.valueLabel != null ? String(props.valueLabel) : sec ? t.progressReserved(props.value, sec, max) : void 0;
|
|
8364
|
+
const valueText = props.valueText != null ? props.valueText : props.valueLabel != null ? String(props.valueLabel) : sec ? t.progressReserved(props.value, sec, max) : void 0;
|
|
8348
8365
|
const shown = props.valueLabel != null ? props.valueLabel : det ? Math.round(pct) + "%" : null;
|
|
8349
8366
|
return /* @__PURE__ */ React53.createElement(
|
|
8350
8367
|
"div",
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -699,8 +699,17 @@ function statElement(props, ref, Link) {
|
|
|
699
699
|
const tone2 = ch && (ch.tone || (dir === "up" ? "positive" : dir === "down" ? "negative" : "neutral"));
|
|
700
700
|
const v = props.value;
|
|
701
701
|
const numeric = typeof v === "number" || typeof v === "string" && /\d/.test(v) && /^[\s\d.,:+\-\u2212%()\u0E3F$\u20AC\u00A3\u00A5kKmMbB]+$/.test(v.replace(/\b[A-Z]{3}\b/g, ""));
|
|
702
|
-
const
|
|
702
|
+
const labelLink = !!props.href && props.linkArea === "label";
|
|
703
|
+
const Tag3 = labelLink ? "div" : props.href ? Link : props.onClick ? "button" : "div";
|
|
703
704
|
const interactive = !!(props.href || props.onClick);
|
|
705
|
+
const LINK_ARIA = ["aria-label", "aria-labelledby", "aria-describedby", "aria-current"];
|
|
706
|
+
const root = {}, toLink = {};
|
|
707
|
+
Object.keys(props).forEach(function(k) {
|
|
708
|
+
const v2 = props[k];
|
|
709
|
+
if (labelLink && LINK_ARIA.indexOf(k) >= 0) toLink[k] = v2;
|
|
710
|
+
else if (k === "id" || k === "style" || k === "lang" || k === "dir" || /^(aria|data)-/.test(k)) root[k] = v2;
|
|
711
|
+
});
|
|
712
|
+
const busy = props.loading || props["aria-busy"] || void 0;
|
|
704
713
|
if (props.headingLevel && Tag3 === "button")
|
|
705
714
|
devWarnOnce(
|
|
706
715
|
"stat-heading-button",
|
|
@@ -711,15 +720,23 @@ function statElement(props, ref, Link) {
|
|
|
711
720
|
return /* @__PURE__ */ React4.createElement(
|
|
712
721
|
Tag3,
|
|
713
722
|
{
|
|
723
|
+
...root,
|
|
714
724
|
ref,
|
|
715
|
-
className: cx(
|
|
716
|
-
|
|
717
|
-
|
|
725
|
+
className: cx(
|
|
726
|
+
"aura-stat",
|
|
727
|
+
interactive && "is-interactive",
|
|
728
|
+
labelLink && "aura-stat--label-link",
|
|
729
|
+
props.loading && "is-loading",
|
|
730
|
+
props.className
|
|
731
|
+
),
|
|
732
|
+
href: labelLink ? void 0 : props.href,
|
|
733
|
+
onClick: labelLink ? void 0 : props.onClick,
|
|
718
734
|
type: Tag3 === "button" ? "button" : void 0,
|
|
719
|
-
"aria-busy":
|
|
735
|
+
"aria-busy": busy
|
|
720
736
|
},
|
|
721
|
-
/* @__PURE__ */ React4.createElement(HeadTag, { className: "aura-stat__head" }, /* @__PURE__ */ React4.createElement(LabelTag, { className: "aura-stat__label" }, props.label), props.icon ? /* @__PURE__ */ React4.createElement("span", { className: "aura-stat__icon" }, /* @__PURE__ */ React4.createElement(Icon, { name: props.icon })) : null),
|
|
737
|
+
/* @__PURE__ */ React4.createElement(HeadTag, { className: "aura-stat__head" }, /* @__PURE__ */ React4.createElement(LabelTag, { className: "aura-stat__label" }, labelLink ? /* @__PURE__ */ React4.createElement(Link, { ...toLink, href: props.href, onClick: props.onClick, className: "aura-stat__link" }, props.label) : props.label), props.icon ? /* @__PURE__ */ React4.createElement("span", { className: "aura-stat__icon" }, /* @__PURE__ */ React4.createElement(Icon, { name: props.icon })) : null),
|
|
722
738
|
props.loading ? /* @__PURE__ */ React4.createElement("span", { className: "aura-stat__value" }, /* @__PURE__ */ React4.createElement("span", { className: "aura-skel aura-stat__skel" })) : /* @__PURE__ */ React4.createElement("span", { className: cx("aura-stat__value", numeric && "is-numeric") }, props.value, props.unit ? /* @__PURE__ */ React4.createElement("span", { className: "aura-stat__unit" }, props.unit) : null),
|
|
739
|
+
props.status != null && props.status !== false && props.status !== "" && !props.loading ? /* @__PURE__ */ React4.createElement("span", { className: "aura-stat__status" }, props.status) : null,
|
|
723
740
|
ch && !props.loading || props.caption ? /* @__PURE__ */ React4.createElement("span", { className: "aura-stat__foot" }, ch && !props.loading ? /* @__PURE__ */ React4.createElement("span", { className: cx("aura-stat__change", "is-" + tone2) }, /* @__PURE__ */ React4.createElement(
|
|
724
741
|
Icon,
|
|
725
742
|
{
|
|
@@ -8326,7 +8343,7 @@ var Progress = React53.forwardRef(function Progress2(props, ref) {
|
|
|
8326
8343
|
const pct = det ? Math.max(0, Math.min(100, props.value / max * 100)) : 0;
|
|
8327
8344
|
const sec = det && props.secondaryValue != null && props.secondaryValue > 0 ? props.secondaryValue : 0;
|
|
8328
8345
|
const spct = sec ? Math.max(0, Math.min(100 - pct, sec / max * 100)) : 0;
|
|
8329
|
-
const valueText = props.valueLabel != null ? String(props.valueLabel) : sec ? t.progressReserved(props.value, sec, max) : void 0;
|
|
8346
|
+
const valueText = props.valueText != null ? props.valueText : props.valueLabel != null ? String(props.valueLabel) : sec ? t.progressReserved(props.value, sec, max) : void 0;
|
|
8330
8347
|
const shown = props.valueLabel != null ? props.valueLabel : det ? Math.round(pct) + "%" : null;
|
|
8331
8348
|
return /* @__PURE__ */ React53.createElement(
|
|
8332
8349
|
"div",
|
package/dist/esm/Progress.js
CHANGED
|
@@ -9,7 +9,7 @@ const Progress = React.forwardRef(function Progress2(props, ref) {
|
|
|
9
9
|
const pct = det ? Math.max(0, Math.min(100, props.value / max * 100)) : 0;
|
|
10
10
|
const sec = det && props.secondaryValue != null && props.secondaryValue > 0 ? props.secondaryValue : 0;
|
|
11
11
|
const spct = sec ? Math.max(0, Math.min(100 - pct, sec / max * 100)) : 0;
|
|
12
|
-
const valueText = props.valueLabel != null ? String(props.valueLabel) : sec ? t.progressReserved(props.value, sec, max) : void 0;
|
|
12
|
+
const valueText = props.valueText != null ? props.valueText : props.valueLabel != null ? String(props.valueLabel) : sec ? t.progressReserved(props.value, sec, max) : void 0;
|
|
13
13
|
const shown = props.valueLabel != null ? props.valueLabel : det ? Math.round(pct) + "%" : null;
|
|
14
14
|
return /* @__PURE__ */ React.createElement(
|
|
15
15
|
"div",
|
package/dist/esm/display.js
CHANGED
|
@@ -146,8 +146,17 @@ function statElement(props, ref, Link) {
|
|
|
146
146
|
const tone = ch && (ch.tone || (dir === "up" ? "positive" : dir === "down" ? "negative" : "neutral"));
|
|
147
147
|
const v = props.value;
|
|
148
148
|
const numeric = typeof v === "number" || typeof v === "string" && /\d/.test(v) && /^[\s\d.,:+\-\u2212%()\u0E3F$\u20AC\u00A3\u00A5kKmMbB]+$/.test(v.replace(/\b[A-Z]{3}\b/g, ""));
|
|
149
|
-
const
|
|
149
|
+
const labelLink = !!props.href && props.linkArea === "label";
|
|
150
|
+
const Tag = labelLink ? "div" : props.href ? Link : props.onClick ? "button" : "div";
|
|
150
151
|
const interactive = !!(props.href || props.onClick);
|
|
152
|
+
const LINK_ARIA = ["aria-label", "aria-labelledby", "aria-describedby", "aria-current"];
|
|
153
|
+
const root = {}, toLink = {};
|
|
154
|
+
Object.keys(props).forEach(function(k) {
|
|
155
|
+
const v2 = props[k];
|
|
156
|
+
if (labelLink && LINK_ARIA.indexOf(k) >= 0) toLink[k] = v2;
|
|
157
|
+
else if (k === "id" || k === "style" || k === "lang" || k === "dir" || /^(aria|data)-/.test(k)) root[k] = v2;
|
|
158
|
+
});
|
|
159
|
+
const busy = props.loading || props["aria-busy"] || void 0;
|
|
151
160
|
if (props.headingLevel && Tag === "button")
|
|
152
161
|
devWarnOnce(
|
|
153
162
|
"stat-heading-button",
|
|
@@ -158,15 +167,23 @@ function statElement(props, ref, Link) {
|
|
|
158
167
|
return /* @__PURE__ */ React.createElement(
|
|
159
168
|
Tag,
|
|
160
169
|
{
|
|
170
|
+
...root,
|
|
161
171
|
ref,
|
|
162
|
-
className: cx(
|
|
163
|
-
|
|
164
|
-
|
|
172
|
+
className: cx(
|
|
173
|
+
"aura-stat",
|
|
174
|
+
interactive && "is-interactive",
|
|
175
|
+
labelLink && "aura-stat--label-link",
|
|
176
|
+
props.loading && "is-loading",
|
|
177
|
+
props.className
|
|
178
|
+
),
|
|
179
|
+
href: labelLink ? void 0 : props.href,
|
|
180
|
+
onClick: labelLink ? void 0 : props.onClick,
|
|
165
181
|
type: Tag === "button" ? "button" : void 0,
|
|
166
|
-
"aria-busy":
|
|
182
|
+
"aria-busy": busy
|
|
167
183
|
},
|
|
168
|
-
/* @__PURE__ */ React.createElement(HeadTag, { className: "aura-stat__head" }, /* @__PURE__ */ React.createElement(LabelTag, { className: "aura-stat__label" }, props.label), props.icon ? /* @__PURE__ */ React.createElement("span", { className: "aura-stat__icon" }, /* @__PURE__ */ React.createElement(Icon, { name: props.icon })) : null),
|
|
184
|
+
/* @__PURE__ */ React.createElement(HeadTag, { className: "aura-stat__head" }, /* @__PURE__ */ React.createElement(LabelTag, { className: "aura-stat__label" }, labelLink ? /* @__PURE__ */ React.createElement(Link, { ...toLink, href: props.href, onClick: props.onClick, className: "aura-stat__link" }, props.label) : props.label), props.icon ? /* @__PURE__ */ React.createElement("span", { className: "aura-stat__icon" }, /* @__PURE__ */ React.createElement(Icon, { name: props.icon })) : null),
|
|
169
185
|
props.loading ? /* @__PURE__ */ React.createElement("span", { className: "aura-stat__value" }, /* @__PURE__ */ React.createElement("span", { className: "aura-skel aura-stat__skel" })) : /* @__PURE__ */ React.createElement("span", { className: cx("aura-stat__value", numeric && "is-numeric") }, props.value, props.unit ? /* @__PURE__ */ React.createElement("span", { className: "aura-stat__unit" }, props.unit) : null),
|
|
186
|
+
props.status != null && props.status !== false && props.status !== "" && !props.loading ? /* @__PURE__ */ React.createElement("span", { className: "aura-stat__status" }, props.status) : null,
|
|
170
187
|
ch && !props.loading || props.caption ? /* @__PURE__ */ React.createElement("span", { className: "aura-stat__foot" }, ch && !props.loading ? /* @__PURE__ */ React.createElement("span", { className: cx("aura-stat__change", "is-" + tone) }, /* @__PURE__ */ React.createElement(
|
|
171
188
|
Icon,
|
|
172
189
|
{
|
package/dist/index.d.cts
CHANGED
|
@@ -1215,7 +1215,8 @@ export interface StatChange {
|
|
|
1215
1215
|
/** e.g. "vs last month". */
|
|
1216
1216
|
label?: React$1.ReactNode | undefined;
|
|
1217
1217
|
}
|
|
1218
|
-
|
|
1218
|
+
/** `id`, `data-*`, `aria-*`, `style`, `lang` and `dir` go on the `.aura-stat` root (5.17, Chamber-OS 110). */
|
|
1219
|
+
export interface StatProps extends Pick<React$1.HTMLAttributes<HTMLElement>, "id" | "style" | "lang" | "dir">, React$1.AriaAttributes, DataAttributes {
|
|
1219
1220
|
/** Your router's link (e.g. `Link` from `next/link`) for this component; defaults to AuraProvider's `linkComponent`, then `<a>`. */
|
|
1220
1221
|
linkComponent?: React$1.ElementType | undefined;
|
|
1221
1222
|
label: React$1.ReactNode;
|
|
@@ -1233,6 +1234,13 @@ export interface StatProps {
|
|
|
1233
1234
|
/** The label as a heading of this level (5.14), when the tile titles its section. Not with `onClick` (a heading
|
|
1234
1235
|
* can't sit in a button); a link is fine. Default: a plain label. */
|
|
1235
1236
|
headingLevel?: 2 | 3 | 4 | 5 | 6 | undefined;
|
|
1237
|
+
/** A status line under the value — "Active · renews 1 Jan" with its tone icon (5.17, Chamber-OS 110). Hidden while
|
|
1238
|
+
* `loading`. */
|
|
1239
|
+
status?: React$1.ReactNode | undefined;
|
|
1240
|
+
/** With `href`: `tile` (default) makes the whole tile the link; `label` puts the link on the label (inside its
|
|
1241
|
+
* heading) and stretches its hit area over the tile, so a click anywhere follows it and the tile shows the focus
|
|
1242
|
+
* ring (5.17, Chamber-OS 110). Other links or buttons in the tile stay clickable above it. */
|
|
1243
|
+
linkArea?: "tile" | "label" | undefined;
|
|
1236
1244
|
className?: string | undefined;
|
|
1237
1245
|
}
|
|
1238
1246
|
export interface TimePickerProps extends FieldProps {
|
|
@@ -1316,6 +1324,9 @@ export interface ProgressProps {
|
|
|
1316
1324
|
showValue?: boolean | undefined;
|
|
1317
1325
|
/** Replaces the % text, e.g. "3 of 5 files". Also read out as aria-valuetext. */
|
|
1318
1326
|
valueLabel?: React$1.ReactNode | undefined;
|
|
1327
|
+
/** What screen readers hear (`aria-valuetext`), apart from the shown `valueLabel` (5.17, Chamber-OS 111): show
|
|
1328
|
+
* "2 of 6 used", read "2 used, 1 reserved, 3 remaining of 6". */
|
|
1329
|
+
valueText?: string | undefined;
|
|
1319
1330
|
/** A reserved amount drawn after `value` as a striped segment of the same tone — queued sends on a quota
|
|
1320
1331
|
* (5.15, Chamber-OS 89). Both counts are read out ("2 of 6 used, 1 reserved") unless `valueLabel` is given. */
|
|
1321
1332
|
secondaryValue?: number | undefined;
|
package/dist/index.d.ts
CHANGED
|
@@ -1215,7 +1215,8 @@ export interface StatChange {
|
|
|
1215
1215
|
/** e.g. "vs last month". */
|
|
1216
1216
|
label?: React$1.ReactNode | undefined;
|
|
1217
1217
|
}
|
|
1218
|
-
|
|
1218
|
+
/** `id`, `data-*`, `aria-*`, `style`, `lang` and `dir` go on the `.aura-stat` root (5.17, Chamber-OS 110). */
|
|
1219
|
+
export interface StatProps extends Pick<React$1.HTMLAttributes<HTMLElement>, "id" | "style" | "lang" | "dir">, React$1.AriaAttributes, DataAttributes {
|
|
1219
1220
|
/** Your router's link (e.g. `Link` from `next/link`) for this component; defaults to AuraProvider's `linkComponent`, then `<a>`. */
|
|
1220
1221
|
linkComponent?: React$1.ElementType | undefined;
|
|
1221
1222
|
label: React$1.ReactNode;
|
|
@@ -1233,6 +1234,13 @@ export interface StatProps {
|
|
|
1233
1234
|
/** The label as a heading of this level (5.14), when the tile titles its section. Not with `onClick` (a heading
|
|
1234
1235
|
* can't sit in a button); a link is fine. Default: a plain label. */
|
|
1235
1236
|
headingLevel?: 2 | 3 | 4 | 5 | 6 | undefined;
|
|
1237
|
+
/** A status line under the value — "Active · renews 1 Jan" with its tone icon (5.17, Chamber-OS 110). Hidden while
|
|
1238
|
+
* `loading`. */
|
|
1239
|
+
status?: React$1.ReactNode | undefined;
|
|
1240
|
+
/** With `href`: `tile` (default) makes the whole tile the link; `label` puts the link on the label (inside its
|
|
1241
|
+
* heading) and stretches its hit area over the tile, so a click anywhere follows it and the tile shows the focus
|
|
1242
|
+
* ring (5.17, Chamber-OS 110). Other links or buttons in the tile stay clickable above it. */
|
|
1243
|
+
linkArea?: "tile" | "label" | undefined;
|
|
1236
1244
|
className?: string | undefined;
|
|
1237
1245
|
}
|
|
1238
1246
|
export interface TimePickerProps extends FieldProps {
|
|
@@ -1316,6 +1324,9 @@ export interface ProgressProps {
|
|
|
1316
1324
|
showValue?: boolean | undefined;
|
|
1317
1325
|
/** Replaces the % text, e.g. "3 of 5 files". Also read out as aria-valuetext. */
|
|
1318
1326
|
valueLabel?: React$1.ReactNode | undefined;
|
|
1327
|
+
/** What screen readers hear (`aria-valuetext`), apart from the shown `valueLabel` (5.17, Chamber-OS 111): show
|
|
1328
|
+
* "2 of 6 used", read "2 used, 1 reserved, 3 remaining of 6". */
|
|
1329
|
+
valueText?: string | undefined;
|
|
1319
1330
|
/** A reserved amount drawn after `value` as a striped segment of the same tone — queued sends on a quota
|
|
1320
1331
|
* (5.15, Chamber-OS 89). Both counts are read out ("2 of 6 used, 1 reserved") unless `valueLabel` is given. */
|
|
1321
1332
|
secondaryValue?: number | undefined;
|
package/dist/server/index.cjs
CHANGED
|
@@ -1212,8 +1212,17 @@ function statElement(props, ref, Link) {
|
|
|
1212
1212
|
const tone2 = ch && (ch.tone || (dir === "up" ? "positive" : dir === "down" ? "negative" : "neutral"));
|
|
1213
1213
|
const v = props.value;
|
|
1214
1214
|
const numeric = typeof v === "number" || typeof v === "string" && /\d/.test(v) && /^[\s\d.,:+\-\u2212%()\u0E3F$\u20AC\u00A3\u00A5kKmMbB]+$/.test(v.replace(/\b[A-Z]{3}\b/g, ""));
|
|
1215
|
-
const
|
|
1215
|
+
const labelLink = !!props.href && props.linkArea === "label";
|
|
1216
|
+
const Tag = labelLink ? "div" : props.href ? Link : props.onClick ? "button" : "div";
|
|
1216
1217
|
const interactive = !!(props.href || props.onClick);
|
|
1218
|
+
const LINK_ARIA = ["aria-label", "aria-labelledby", "aria-describedby", "aria-current"];
|
|
1219
|
+
const root = {}, toLink = {};
|
|
1220
|
+
Object.keys(props).forEach(function(k) {
|
|
1221
|
+
const v2 = props[k];
|
|
1222
|
+
if (labelLink && LINK_ARIA.indexOf(k) >= 0) toLink[k] = v2;
|
|
1223
|
+
else if (k === "id" || k === "style" || k === "lang" || k === "dir" || /^(aria|data)-/.test(k)) root[k] = v2;
|
|
1224
|
+
});
|
|
1225
|
+
const busy = props.loading || props["aria-busy"] || void 0;
|
|
1217
1226
|
if (props.headingLevel && Tag === "button")
|
|
1218
1227
|
devWarnOnce(
|
|
1219
1228
|
"stat-heading-button",
|
|
@@ -1224,15 +1233,23 @@ function statElement(props, ref, Link) {
|
|
|
1224
1233
|
return /* @__PURE__ */ React3.createElement(
|
|
1225
1234
|
Tag,
|
|
1226
1235
|
{
|
|
1236
|
+
...root,
|
|
1227
1237
|
ref,
|
|
1228
|
-
className: cx(
|
|
1229
|
-
|
|
1230
|
-
|
|
1238
|
+
className: cx(
|
|
1239
|
+
"aura-stat",
|
|
1240
|
+
interactive && "is-interactive",
|
|
1241
|
+
labelLink && "aura-stat--label-link",
|
|
1242
|
+
props.loading && "is-loading",
|
|
1243
|
+
props.className
|
|
1244
|
+
),
|
|
1245
|
+
href: labelLink ? void 0 : props.href,
|
|
1246
|
+
onClick: labelLink ? void 0 : props.onClick,
|
|
1231
1247
|
type: Tag === "button" ? "button" : void 0,
|
|
1232
|
-
"aria-busy":
|
|
1248
|
+
"aria-busy": busy
|
|
1233
1249
|
},
|
|
1234
|
-
/* @__PURE__ */ React3.createElement(HeadTag, { className: "aura-stat__head" }, /* @__PURE__ */ React3.createElement(LabelTag, { className: "aura-stat__label" }, props.label), props.icon ? /* @__PURE__ */ React3.createElement("span", { className: "aura-stat__icon" }, /* @__PURE__ */ React3.createElement(Icon, { name: props.icon })) : null),
|
|
1250
|
+
/* @__PURE__ */ React3.createElement(HeadTag, { className: "aura-stat__head" }, /* @__PURE__ */ React3.createElement(LabelTag, { className: "aura-stat__label" }, labelLink ? /* @__PURE__ */ React3.createElement(Link, { ...toLink, href: props.href, onClick: props.onClick, className: "aura-stat__link" }, props.label) : props.label), props.icon ? /* @__PURE__ */ React3.createElement("span", { className: "aura-stat__icon" }, /* @__PURE__ */ React3.createElement(Icon, { name: props.icon })) : null),
|
|
1235
1251
|
props.loading ? /* @__PURE__ */ React3.createElement("span", { className: "aura-stat__value" }, /* @__PURE__ */ React3.createElement("span", { className: "aura-skel aura-stat__skel" })) : /* @__PURE__ */ React3.createElement("span", { className: cx("aura-stat__value", numeric && "is-numeric") }, props.value, props.unit ? /* @__PURE__ */ React3.createElement("span", { className: "aura-stat__unit" }, props.unit) : null),
|
|
1252
|
+
props.status != null && props.status !== false && props.status !== "" && !props.loading ? /* @__PURE__ */ React3.createElement("span", { className: "aura-stat__status" }, props.status) : null,
|
|
1236
1253
|
ch && !props.loading || props.caption ? /* @__PURE__ */ React3.createElement("span", { className: "aura-stat__foot" }, ch && !props.loading ? /* @__PURE__ */ React3.createElement("span", { className: cx("aura-stat__change", "is-" + tone2) }, /* @__PURE__ */ React3.createElement(
|
|
1237
1254
|
Icon,
|
|
1238
1255
|
{
|
package/dist/server/index.d.cts
CHANGED
|
@@ -107,6 +107,10 @@ export interface DateDisplayOptions {
|
|
|
107
107
|
/** `buddhist` (พ.ศ.; default for th) or `gregory` (ค.ศ.; default for en and sv). */
|
|
108
108
|
calendar?: "buddhist" | "gregory" | undefined;
|
|
109
109
|
}
|
|
110
|
+
/** `data-*` attributes in an object prop (TypeScript checks object literals, where JSX would allow them anyway). */
|
|
111
|
+
export type DataAttributes = {
|
|
112
|
+
[key: `data-${string}`]: string | number | boolean | undefined;
|
|
113
|
+
};
|
|
110
114
|
export interface StatChange {
|
|
111
115
|
/** Shown as written, e.g. "+12%" or "−3". */
|
|
112
116
|
value: React$1.ReactNode;
|
|
@@ -116,7 +120,8 @@ export interface StatChange {
|
|
|
116
120
|
/** e.g. "vs last month". */
|
|
117
121
|
label?: React$1.ReactNode | undefined;
|
|
118
122
|
}
|
|
119
|
-
|
|
123
|
+
/** `id`, `data-*`, `aria-*`, `style`, `lang` and `dir` go on the `.aura-stat` root (5.17, Chamber-OS 110). */
|
|
124
|
+
export interface StatProps extends Pick<React$1.HTMLAttributes<HTMLElement>, "id" | "style" | "lang" | "dir">, React$1.AriaAttributes, DataAttributes {
|
|
120
125
|
/** Your router's link (e.g. `Link` from `next/link`) for this component; defaults to AuraProvider's `linkComponent`, then `<a>`. */
|
|
121
126
|
linkComponent?: React$1.ElementType | undefined;
|
|
122
127
|
label: React$1.ReactNode;
|
|
@@ -134,6 +139,13 @@ export interface StatProps {
|
|
|
134
139
|
/** The label as a heading of this level (5.14), when the tile titles its section. Not with `onClick` (a heading
|
|
135
140
|
* can't sit in a button); a link is fine. Default: a plain label. */
|
|
136
141
|
headingLevel?: 2 | 3 | 4 | 5 | 6 | undefined;
|
|
142
|
+
/** A status line under the value — "Active · renews 1 Jan" with its tone icon (5.17, Chamber-OS 110). Hidden while
|
|
143
|
+
* `loading`. */
|
|
144
|
+
status?: React$1.ReactNode | undefined;
|
|
145
|
+
/** With `href`: `tile` (default) makes the whole tile the link; `label` puts the link on the label (inside its
|
|
146
|
+
* heading) and stretches its hit area over the tile, so a click anywhere follows it and the tile shows the focus
|
|
147
|
+
* ring (5.17, Chamber-OS 110). Other links or buttons in the tile stay clickable above it. */
|
|
148
|
+
linkArea?: "tile" | "label" | undefined;
|
|
137
149
|
className?: string | undefined;
|
|
138
150
|
}
|
|
139
151
|
export type Tone = "neutral" | "accent" | "success" | "warning" | "danger";
|
package/dist/server/index.d.ts
CHANGED
|
@@ -107,6 +107,10 @@ export interface DateDisplayOptions {
|
|
|
107
107
|
/** `buddhist` (พ.ศ.; default for th) or `gregory` (ค.ศ.; default for en and sv). */
|
|
108
108
|
calendar?: "buddhist" | "gregory" | undefined;
|
|
109
109
|
}
|
|
110
|
+
/** `data-*` attributes in an object prop (TypeScript checks object literals, where JSX would allow them anyway). */
|
|
111
|
+
export type DataAttributes = {
|
|
112
|
+
[key: `data-${string}`]: string | number | boolean | undefined;
|
|
113
|
+
};
|
|
110
114
|
export interface StatChange {
|
|
111
115
|
/** Shown as written, e.g. "+12%" or "−3". */
|
|
112
116
|
value: React$1.ReactNode;
|
|
@@ -116,7 +120,8 @@ export interface StatChange {
|
|
|
116
120
|
/** e.g. "vs last month". */
|
|
117
121
|
label?: React$1.ReactNode | undefined;
|
|
118
122
|
}
|
|
119
|
-
|
|
123
|
+
/** `id`, `data-*`, `aria-*`, `style`, `lang` and `dir` go on the `.aura-stat` root (5.17, Chamber-OS 110). */
|
|
124
|
+
export interface StatProps extends Pick<React$1.HTMLAttributes<HTMLElement>, "id" | "style" | "lang" | "dir">, React$1.AriaAttributes, DataAttributes {
|
|
120
125
|
/** Your router's link (e.g. `Link` from `next/link`) for this component; defaults to AuraProvider's `linkComponent`, then `<a>`. */
|
|
121
126
|
linkComponent?: React$1.ElementType | undefined;
|
|
122
127
|
label: React$1.ReactNode;
|
|
@@ -134,6 +139,13 @@ export interface StatProps {
|
|
|
134
139
|
/** The label as a heading of this level (5.14), when the tile titles its section. Not with `onClick` (a heading
|
|
135
140
|
* can't sit in a button); a link is fine. Default: a plain label. */
|
|
136
141
|
headingLevel?: 2 | 3 | 4 | 5 | 6 | undefined;
|
|
142
|
+
/** A status line under the value — "Active · renews 1 Jan" with its tone icon (5.17, Chamber-OS 110). Hidden while
|
|
143
|
+
* `loading`. */
|
|
144
|
+
status?: React$1.ReactNode | undefined;
|
|
145
|
+
/** With `href`: `tile` (default) makes the whole tile the link; `label` puts the link on the label (inside its
|
|
146
|
+
* heading) and stretches its hit area over the tile, so a click anywhere follows it and the tile shows the focus
|
|
147
|
+
* ring (5.17, Chamber-OS 110). Other links or buttons in the tile stay clickable above it. */
|
|
148
|
+
linkArea?: "tile" | "label" | undefined;
|
|
137
149
|
className?: string | undefined;
|
|
138
150
|
}
|
|
139
151
|
export type Tone = "neutral" | "accent" | "success" | "warning" | "danger";
|
package/dist/server/index.js
CHANGED
|
@@ -1153,8 +1153,17 @@ function statElement(props, ref, Link) {
|
|
|
1153
1153
|
const tone2 = ch && (ch.tone || (dir === "up" ? "positive" : dir === "down" ? "negative" : "neutral"));
|
|
1154
1154
|
const v = props.value;
|
|
1155
1155
|
const numeric = typeof v === "number" || typeof v === "string" && /\d/.test(v) && /^[\s\d.,:+\-\u2212%()\u0E3F$\u20AC\u00A3\u00A5kKmMbB]+$/.test(v.replace(/\b[A-Z]{3}\b/g, ""));
|
|
1156
|
-
const
|
|
1156
|
+
const labelLink = !!props.href && props.linkArea === "label";
|
|
1157
|
+
const Tag = labelLink ? "div" : props.href ? Link : props.onClick ? "button" : "div";
|
|
1157
1158
|
const interactive = !!(props.href || props.onClick);
|
|
1159
|
+
const LINK_ARIA = ["aria-label", "aria-labelledby", "aria-describedby", "aria-current"];
|
|
1160
|
+
const root = {}, toLink = {};
|
|
1161
|
+
Object.keys(props).forEach(function(k) {
|
|
1162
|
+
const v2 = props[k];
|
|
1163
|
+
if (labelLink && LINK_ARIA.indexOf(k) >= 0) toLink[k] = v2;
|
|
1164
|
+
else if (k === "id" || k === "style" || k === "lang" || k === "dir" || /^(aria|data)-/.test(k)) root[k] = v2;
|
|
1165
|
+
});
|
|
1166
|
+
const busy = props.loading || props["aria-busy"] || void 0;
|
|
1158
1167
|
if (props.headingLevel && Tag === "button")
|
|
1159
1168
|
devWarnOnce(
|
|
1160
1169
|
"stat-heading-button",
|
|
@@ -1165,15 +1174,23 @@ function statElement(props, ref, Link) {
|
|
|
1165
1174
|
return /* @__PURE__ */ React3.createElement(
|
|
1166
1175
|
Tag,
|
|
1167
1176
|
{
|
|
1177
|
+
...root,
|
|
1168
1178
|
ref,
|
|
1169
|
-
className: cx(
|
|
1170
|
-
|
|
1171
|
-
|
|
1179
|
+
className: cx(
|
|
1180
|
+
"aura-stat",
|
|
1181
|
+
interactive && "is-interactive",
|
|
1182
|
+
labelLink && "aura-stat--label-link",
|
|
1183
|
+
props.loading && "is-loading",
|
|
1184
|
+
props.className
|
|
1185
|
+
),
|
|
1186
|
+
href: labelLink ? void 0 : props.href,
|
|
1187
|
+
onClick: labelLink ? void 0 : props.onClick,
|
|
1172
1188
|
type: Tag === "button" ? "button" : void 0,
|
|
1173
|
-
"aria-busy":
|
|
1189
|
+
"aria-busy": busy
|
|
1174
1190
|
},
|
|
1175
|
-
/* @__PURE__ */ React3.createElement(HeadTag, { className: "aura-stat__head" }, /* @__PURE__ */ React3.createElement(LabelTag, { className: "aura-stat__label" }, props.label), props.icon ? /* @__PURE__ */ React3.createElement("span", { className: "aura-stat__icon" }, /* @__PURE__ */ React3.createElement(Icon, { name: props.icon })) : null),
|
|
1191
|
+
/* @__PURE__ */ React3.createElement(HeadTag, { className: "aura-stat__head" }, /* @__PURE__ */ React3.createElement(LabelTag, { className: "aura-stat__label" }, labelLink ? /* @__PURE__ */ React3.createElement(Link, { ...toLink, href: props.href, onClick: props.onClick, className: "aura-stat__link" }, props.label) : props.label), props.icon ? /* @__PURE__ */ React3.createElement("span", { className: "aura-stat__icon" }, /* @__PURE__ */ React3.createElement(Icon, { name: props.icon })) : null),
|
|
1176
1192
|
props.loading ? /* @__PURE__ */ React3.createElement("span", { className: "aura-stat__value" }, /* @__PURE__ */ React3.createElement("span", { className: "aura-skel aura-stat__skel" })) : /* @__PURE__ */ React3.createElement("span", { className: cx("aura-stat__value", numeric && "is-numeric") }, props.value, props.unit ? /* @__PURE__ */ React3.createElement("span", { className: "aura-stat__unit" }, props.unit) : null),
|
|
1193
|
+
props.status != null && props.status !== false && props.status !== "" && !props.loading ? /* @__PURE__ */ React3.createElement("span", { className: "aura-stat__status" }, props.status) : null,
|
|
1177
1194
|
ch && !props.loading || props.caption ? /* @__PURE__ */ React3.createElement("span", { className: "aura-stat__foot" }, ch && !props.loading ? /* @__PURE__ */ React3.createElement("span", { className: cx("aura-stat__change", "is-" + tone2) }, /* @__PURE__ */ React3.createElement(
|
|
1178
1195
|
Icon,
|
|
1179
1196
|
{
|
package/dist/styles.css
CHANGED
|
@@ -1032,6 +1032,20 @@ button.aura-stat { font: inherit; width: 100%; cursor: pointer; }
|
|
|
1032
1032
|
.aura-stat__change.is-negative { color: var(--aura-fg-danger); }
|
|
1033
1033
|
.aura-stat__change.is-neutral { color: var(--aura-fg-secondary); }
|
|
1034
1034
|
.aura-stat__caption { color: var(--aura-fg-secondary); }
|
|
1035
|
+
/* 5.17 (Chamber-OS 110): a status line under the value, and a link on the label that covers the tile. */
|
|
1036
|
+
.aura-stat__status { display: flex; flex-wrap: wrap; align-items: center; gap: var(--aura-space-1) var(--aura-space-2); font-size: 13px; color: var(--aura-fg-secondary); }
|
|
1037
|
+
.aura-stat--label-link { position: relative; }
|
|
1038
|
+
.aura-stat__link { color: inherit; text-decoration: none; }
|
|
1039
|
+
.aura-stat__link::after { content: ''; position: absolute; inset: 0; border-radius: var(--aura-card-radius); }
|
|
1040
|
+
/* The ring is drawn on the tile where :has() works; elsewhere the link keeps its own. */
|
|
1041
|
+
.aura-stat__link:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: 2px; }
|
|
1042
|
+
@supports selector(:has(*)) {
|
|
1043
|
+
.aura-stat__link:focus-visible { outline: none; }
|
|
1044
|
+
.aura-stat--label-link:has(.aura-stat__link:focus-visible) { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: var(--aura-focus-ring-offset); }
|
|
1045
|
+
}
|
|
1046
|
+
.aura-stat--label-link:hover .aura-stat__link { text-decoration: underline; text-underline-offset: 3px; }
|
|
1047
|
+
/* Anything else interactive in the tile sits above the stretched link. No specificity, so a control's own position wins. */
|
|
1048
|
+
:where(.aura-stat--label-link) :where(a, button, input, select, textarea, label, summary, [tabindex]):not(:where(.aura-stat__link)) { position: relative; z-index: 1; }
|
|
1035
1049
|
|
|
1036
1050
|
/* ---------- TimePicker ---------- */
|
|
1037
1051
|
.aura-time__popover { min-width: 160px; }
|
package/dist/styles.layer.css
CHANGED
|
@@ -1034,6 +1034,20 @@ button.aura-stat { font: inherit; width: 100%; cursor: pointer; }
|
|
|
1034
1034
|
.aura-stat__change.is-negative { color: var(--aura-fg-danger); }
|
|
1035
1035
|
.aura-stat__change.is-neutral { color: var(--aura-fg-secondary); }
|
|
1036
1036
|
.aura-stat__caption { color: var(--aura-fg-secondary); }
|
|
1037
|
+
/* 5.17 (Chamber-OS 110): a status line under the value, and a link on the label that covers the tile. */
|
|
1038
|
+
.aura-stat__status { display: flex; flex-wrap: wrap; align-items: center; gap: var(--aura-space-1) var(--aura-space-2); font-size: 13px; color: var(--aura-fg-secondary); }
|
|
1039
|
+
.aura-stat--label-link { position: relative; }
|
|
1040
|
+
.aura-stat__link { color: inherit; text-decoration: none; }
|
|
1041
|
+
.aura-stat__link::after { content: ''; position: absolute; inset: 0; border-radius: var(--aura-card-radius); }
|
|
1042
|
+
/* The ring is drawn on the tile where :has() works; elsewhere the link keeps its own. */
|
|
1043
|
+
.aura-stat__link:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: 2px; }
|
|
1044
|
+
@supports selector(:has(*)) {
|
|
1045
|
+
.aura-stat__link:focus-visible { outline: none; }
|
|
1046
|
+
.aura-stat--label-link:has(.aura-stat__link:focus-visible) { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: var(--aura-focus-ring-offset); }
|
|
1047
|
+
}
|
|
1048
|
+
.aura-stat--label-link:hover .aura-stat__link { text-decoration: underline; text-underline-offset: 3px; }
|
|
1049
|
+
/* Anything else interactive in the tile sits above the stretched link. No specificity, so a control's own position wins. */
|
|
1050
|
+
:where(.aura-stat--label-link) :where(a, button, input, select, textarea, label, summary, [tabindex]):not(:where(.aura-stat__link)) { position: relative; z-index: 1; }
|
|
1037
1051
|
|
|
1038
1052
|
/* ---------- TimePicker ---------- */
|
|
1039
1053
|
.aura-time__popover { min-width: 160px; }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jirawatpyk/aura-react",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.17.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",
|