@tensor_1/react 2.37.0 → 2.38.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 +3 -0
- package/dist/components/Stat.d.ts +7 -0
- package/dist/components/Stat.js +6 -3
- package/dist/index.cjs +6 -3
- package/dist/index.d.cts +7 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -198,12 +198,15 @@ Radial mode still shortens long labels to fit its ring, but every node carries i
|
|
|
198
198
|
- **`Tabs overflow="scroll"`** keeps a long tab row on one line that scrolls sideways. The selected tab is always scrolled into view, and edge buttons appear only on the side that has hidden tabs. The buttons are pointer-only: keyboard users move with Arrow, Home and End. Combine it with `TabPanel keepMounted` on a record page with many sections.
|
|
199
199
|
- **`Stat tone`** (`warning`, `danger`) draws a toned outline and value; the label stays muted, so the tone never replaces words. `size="compact"` fits dense fact bands.
|
|
200
200
|
- **`Stat onActivate`** makes the whole tile a button that opens an editor (`aria-haspopup="dialog"`). Pass `activateLabel` (e.g. "change") so the name reads "Priority: P1, change", and `expanded` while the editor is open. The ref points at the button, for anchoring a popover.
|
|
201
|
+
- **`Stat pending`** is for a tile whose action is still running (a save, a state change). The button gets `aria-busy="true"` and `aria-disabled="true"`, is dimmed with a progress cursor, and calls neither `onActivate` nor your `onClick` / `onKeyDown` until `pending` is false again. It is never natively `disabled`, so it keeps focus and a screen reader can still read it. Only a tile with `onActivate` has the state; a read-only tile and a link tile ignore the prop.
|
|
202
|
+
- **Tiles in one row line up.** A grid or flex row stretches its tiles to the tallest one. Read-only, button and link tiles all start their label and value at the same offset from the top edge, whatever the height (before 2.38.0 a button tile centred its rows).
|
|
201
203
|
- **`CopyButton`** copies `value`. Name it for what it copies (`label="Copy email"`), pass `copiedLabel`, and pass `failedLabel` so a refused copy is explained rather than silent.
|
|
202
204
|
|
|
203
205
|
```tsx
|
|
204
206
|
<Tabs value={tab} onChange={setTab} overflow="scroll">{tabs}</Tabs>
|
|
205
207
|
<Stat label={t('sla')} value={remaining} tone={breached ? 'danger' : 'neutral'} size="compact" />
|
|
206
208
|
<Stat ref={anchor} label={t('priority')} value="P1" onActivate={openEditor} activateLabel={t('change')} expanded={open} size="compact" />
|
|
209
|
+
<Stat label={t('state')} value={state} onActivate={resolve} activateLabel={t('resolve')} haspopup={false} pending={saving} size="compact" />
|
|
207
210
|
<CopyButton value={email} label={t('copyEmail')} copiedLabel={t('copied')} failedLabel={t('copyFailed')} />
|
|
208
211
|
```
|
|
209
212
|
|
|
@@ -33,6 +33,13 @@ interface StatProps extends HTMLAttributes<HTMLElement> {
|
|
|
33
33
|
};
|
|
34
34
|
/** Whether the editor this tile opens is currently open (`aria-expanded`). */
|
|
35
35
|
expanded?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* What the tile started is still running (HAR-1753). The button is announced as busy and
|
|
38
|
+
* unavailable (`aria-busy`, `aria-disabled`) and stays focusable; `onActivate`, `onClick` and
|
|
39
|
+
* `onKeyDown` are not called until it ends. Only with `onActivate`: a read-only tile and a
|
|
40
|
+
* link tile ignore it.
|
|
41
|
+
*/
|
|
42
|
+
pending?: boolean;
|
|
36
43
|
/**
|
|
37
44
|
* What `onActivate` opens, for `aria-haspopup` (HAR-1350; TENSOR B6). Default `'dialog'`;
|
|
38
45
|
* `'menu'` for a status menu; `false` for an in-place action (no chevron either).
|
package/dist/components/Stat.js
CHANGED
|
@@ -3,7 +3,7 @@ import { forwardRef, useId } from "react";
|
|
|
3
3
|
import { cx } from "../cx.js";
|
|
4
4
|
import { renderUixLink } from "../link.js";
|
|
5
5
|
const Chevron = () => /* @__PURE__ */ jsx("span", { className: "uix-stat__chevron", "aria-hidden": "true", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "m6 9 6 6 6-6" }) }) });
|
|
6
|
-
const Stat = forwardRef(function Stat2({ label, value, icon, meta, trend, tone = "neutral", size = "hero", onActivate, activateLabel, expanded, trendLabels, haspopup = "dialog", href, current, renderLink, className, onClick, ...props }, ref) {
|
|
6
|
+
const Stat = forwardRef(function Stat2({ label, value, icon, meta, trend, tone = "neutral", size = "hero", onActivate, activateLabel, expanded, trendLabels, haspopup = "dialog", href, current, renderLink, className, onClick, onKeyDown, pending = false, ...props }, ref) {
|
|
7
7
|
const id = useId();
|
|
8
8
|
const interactive = onActivate != null;
|
|
9
9
|
const linked = !interactive && href != null;
|
|
@@ -33,11 +33,11 @@ const Stat = forwardRef(function Stat2({ label, value, icon, meta, trend, tone =
|
|
|
33
33
|
] })
|
|
34
34
|
] });
|
|
35
35
|
if (linked) {
|
|
36
|
-
const linkProps = { ...props, href, className: classes, onClick, "aria-current": current ? "page" : void 0, children: body };
|
|
36
|
+
const linkProps = { ...props, href, className: classes, onClick, onKeyDown, "aria-current": current ? "page" : void 0, children: body };
|
|
37
37
|
return /* @__PURE__ */ jsx(Fragment, { children: renderLink ? renderUixLink(renderLink, linkProps) : /* @__PURE__ */ jsx("a", { ref, ...linkProps }) });
|
|
38
38
|
}
|
|
39
39
|
if (!interactive) {
|
|
40
|
-
return /* @__PURE__ */ jsx("div", { ref, className: classes, onClick, ...props, children: body });
|
|
40
|
+
return /* @__PURE__ */ jsx("div", { ref, className: classes, onClick, onKeyDown, ...props, children: body });
|
|
41
41
|
}
|
|
42
42
|
return /* @__PURE__ */ jsxs(
|
|
43
43
|
"button",
|
|
@@ -50,10 +50,13 @@ const Stat = forwardRef(function Stat2({ label, value, icon, meta, trend, tone =
|
|
|
50
50
|
"aria-expanded": expanded,
|
|
51
51
|
"aria-labelledby": `${id}-label ${id}-sep ${id}-value${activateLabel ? ` ${id}-action` : ""}`,
|
|
52
52
|
"aria-describedby": meta != null || trend != null ? `${id}-meta` : void 0,
|
|
53
|
+
...pending ? { "aria-busy": true, "aria-disabled": true } : null,
|
|
53
54
|
onClick: (e) => {
|
|
55
|
+
if (pending) return;
|
|
54
56
|
onClick?.(e);
|
|
55
57
|
if (!e.defaultPrevented) onActivate();
|
|
56
58
|
},
|
|
59
|
+
onKeyDown: pending ? void 0 : onKeyDown,
|
|
57
60
|
children: [
|
|
58
61
|
/* @__PURE__ */ jsx("span", { id: `${id}-sep`, className: "uix-visually-hidden", children: ":" }),
|
|
59
62
|
activateLabel && /* @__PURE__ */ jsxs("span", { id: `${id}-action`, className: "uix-visually-hidden", children: [
|
package/dist/index.cjs
CHANGED
|
@@ -6010,7 +6010,7 @@ function Meter({ value = 0, tone, label, toneLabels, className, ...props }) {
|
|
|
6010
6010
|
var import_react43 = require("react");
|
|
6011
6011
|
var import_jsx_runtime56 = require("react/jsx-runtime");
|
|
6012
6012
|
var Chevron3 = () => /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "uix-stat__chevron", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("path", { d: "m6 9 6 6 6-6" }) }) });
|
|
6013
|
-
var Stat = (0, import_react43.forwardRef)(function Stat2({ label, value, icon, meta, trend, tone = "neutral", size = "hero", onActivate, activateLabel, expanded, trendLabels, haspopup = "dialog", href, current, renderLink, className, onClick, ...props }, ref) {
|
|
6013
|
+
var Stat = (0, import_react43.forwardRef)(function Stat2({ label, value, icon, meta, trend, tone = "neutral", size = "hero", onActivate, activateLabel, expanded, trendLabels, haspopup = "dialog", href, current, renderLink, className, onClick, onKeyDown, pending = false, ...props }, ref) {
|
|
6014
6014
|
const id = (0, import_react43.useId)();
|
|
6015
6015
|
const interactive = onActivate != null;
|
|
6016
6016
|
const linked = !interactive && href != null;
|
|
@@ -6040,11 +6040,11 @@ var Stat = (0, import_react43.forwardRef)(function Stat2({ label, value, icon, m
|
|
|
6040
6040
|
] })
|
|
6041
6041
|
] });
|
|
6042
6042
|
if (linked) {
|
|
6043
|
-
const linkProps = { ...props, href, className: classes, onClick, "aria-current": current ? "page" : void 0, children: body };
|
|
6043
|
+
const linkProps = { ...props, href, className: classes, onClick, onKeyDown, "aria-current": current ? "page" : void 0, children: body };
|
|
6044
6044
|
return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_jsx_runtime56.Fragment, { children: renderLink ? renderUixLink(renderLink, linkProps) : /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("a", { ref, ...linkProps }) });
|
|
6045
6045
|
}
|
|
6046
6046
|
if (!interactive) {
|
|
6047
|
-
return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { ref, className: classes, onClick, ...props, children: body });
|
|
6047
|
+
return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { ref, className: classes, onClick, onKeyDown, ...props, children: body });
|
|
6048
6048
|
}
|
|
6049
6049
|
return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
|
|
6050
6050
|
"button",
|
|
@@ -6057,10 +6057,13 @@ var Stat = (0, import_react43.forwardRef)(function Stat2({ label, value, icon, m
|
|
|
6057
6057
|
"aria-expanded": expanded,
|
|
6058
6058
|
"aria-labelledby": `${id}-label ${id}-sep ${id}-value${activateLabel ? ` ${id}-action` : ""}`,
|
|
6059
6059
|
"aria-describedby": meta != null || trend != null ? `${id}-meta` : void 0,
|
|
6060
|
+
...pending ? { "aria-busy": true, "aria-disabled": true } : null,
|
|
6060
6061
|
onClick: (e) => {
|
|
6062
|
+
if (pending) return;
|
|
6061
6063
|
onClick?.(e);
|
|
6062
6064
|
if (!e.defaultPrevented) onActivate();
|
|
6063
6065
|
},
|
|
6066
|
+
onKeyDown: pending ? void 0 : onKeyDown,
|
|
6064
6067
|
children: [
|
|
6065
6068
|
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { id: `${id}-sep`, className: "uix-visually-hidden", children: ":" }),
|
|
6066
6069
|
activateLabel && /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("span", { id: `${id}-action`, className: "uix-visually-hidden", children: [
|
package/dist/index.d.cts
CHANGED
|
@@ -3990,6 +3990,13 @@ interface StatProps extends HTMLAttributes<HTMLElement> {
|
|
|
3990
3990
|
};
|
|
3991
3991
|
/** Whether the editor this tile opens is currently open (`aria-expanded`). */
|
|
3992
3992
|
expanded?: boolean;
|
|
3993
|
+
/**
|
|
3994
|
+
* What the tile started is still running (HAR-1753). The button is announced as busy and
|
|
3995
|
+
* unavailable (`aria-busy`, `aria-disabled`) and stays focusable; `onActivate`, `onClick` and
|
|
3996
|
+
* `onKeyDown` are not called until it ends. Only with `onActivate`: a read-only tile and a
|
|
3997
|
+
* link tile ignore it.
|
|
3998
|
+
*/
|
|
3999
|
+
pending?: boolean;
|
|
3993
4000
|
/**
|
|
3994
4001
|
* What `onActivate` opens, for `aria-haspopup` (HAR-1350; TENSOR B6). Default `'dialog'`;
|
|
3995
4002
|
* `'menu'` for a status menu; `false` for an in-place action (no chevron either).
|