@dreamtree-org/twreact-ui 1.3.2 → 1.3.3
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/DESIGN.md +2 -2
- package/README.md +11 -5
- package/ai-skills/dreamtree-ui.md +3 -1
- package/bin/cli.mjs +72 -4
- package/dist/ai-schema.json +1 -1
- package/dist/charts/index.js +75 -47
- package/dist/components/charts/CartesianChart.d.ts.map +1 -1
- package/dist/components/charts/DonutChart.d.ts.map +1 -1
- package/dist/components/charts/Sparkline.d.ts.map +1 -1
- package/dist/components/charts/chartTheme.d.ts +13 -3
- package/dist/components/charts/chartTheme.d.ts.map +1 -1
- package/dist/components/core/Table/MobileCard.d.ts.map +1 -1
- package/dist/components/core/Table/MobileFilters.d.ts.map +1 -1
- package/dist/components/core/Table/Table.d.ts.map +1 -1
- package/dist/components/utility/Stepper.d.ts.map +1 -1
- package/dist/esm/components/blocks/StatCard.js +1 -1
- package/dist/esm/components/charts/CartesianChart.js +7 -2
- package/dist/esm/components/charts/DonutChart.js +4 -1
- package/dist/esm/components/charts/Sparkline.js +4 -1
- package/dist/esm/components/charts/chartTheme.js +65 -48
- package/dist/esm/components/core/Select.js +2 -2
- package/dist/esm/components/core/Table/MobileCard.js +5 -2
- package/dist/esm/components/core/Table/MobileFilters.js +10 -3
- package/dist/esm/components/core/Table/Table.js +10 -7
- package/dist/esm/components/utility/Stepper.js +6 -4
- package/dist/index.css +1 -1
- package/dist/index.esm.css +1 -1
- package/dist/index.esm.js +33 -18
- package/dist/index.js +33 -18
- package/dist/tokens/brands/practicepro.json +1 -0
- package/dist/tokens/brands/studio.json +1 -0
- package/mcp/catalog.snapshot.json +13 -13
- package/package.json +2 -1
- package/tokens/brand.schema.json +612 -0
- package/tokens/brands/practicepro.json +1 -0
- package/tokens/brands/studio.json +1 -0
- package/tokens/lib.cjs +131 -7
package/DESIGN.md
CHANGED
|
@@ -41,7 +41,7 @@ rounded:
|
|
|
41
41
|
spacing:
|
|
42
42
|
grid: 4px
|
|
43
43
|
steps: [4, 8, 12, 16, 20, 24, 32]
|
|
44
|
-
|
|
44
|
+
brand: dreamtree.brand.json in each product repo (build its CSS with `npx @dreamtree-org/twreact-ui brand build`)
|
|
45
45
|
---
|
|
46
46
|
|
|
47
47
|
<!-- Generated by twreact-ui scripts/build-tokens.mjs from tokens/tokens.json. Edit the tokens or this generator, not this file. -->
|
|
@@ -76,7 +76,7 @@ Every Dreamtree product screen, and every prototype generated by Dreamtree Studi
|
|
|
76
76
|
|
|
77
77
|
- **One accent per screen.** `primary` marks the primary action, the active nav item, the current step and progress. Red (`error`) is only for errors, overdue items and destructive actions.
|
|
78
78
|
- Badge and status fills use the 100 step with 800 text, which keeps contrast at or above 4.5:1.
|
|
79
|
-
-
|
|
79
|
+
- Each product keeps its look in its own repo, in **`dreamtree.brand.json`** (its `--dt-*` overrides: colour scales, roles, font). `npx @dreamtree-org/twreact-ui brand build` turns it into the CSS the product loads after twreact-ui's CSS. Never restyle a product with raw colours; change its brand file.
|
|
80
80
|
|
|
81
81
|
## 3. Type, space and shape
|
|
82
82
|
|
package/README.md
CHANGED
|
@@ -278,7 +278,7 @@ Advanced select component with search, multi-select, and grouping support.
|
|
|
278
278
|
- `selectAllOption`: boolean
|
|
279
279
|
- `closeOnSelect`: boolean
|
|
280
280
|
- `maxTagCount`: number (default: 3)
|
|
281
|
-
- `allowClear`: boolean
|
|
281
|
+
- `allowClear`: boolean (default: false; set it when the field may be emptied)
|
|
282
282
|
|
|
283
283
|
```jsx
|
|
284
284
|
<Select
|
|
@@ -836,14 +836,20 @@ See [doc/useApi.md](doc/useApi.md).
|
|
|
836
836
|
|
|
837
837
|
Every colour in the compiled CSS is a CSS variable (`--dt-primary-600`, `--dt-surface`, …) generated from `tokens/tokens.json` (W3C Design Tokens format). The defaults equal the classic palette, so nothing changes until you override a variable.
|
|
838
838
|
|
|
839
|
-
**
|
|
839
|
+
**Your brand lives in your repo.** Keep it in `dreamtree.brand.json` at the repo root (colour scales, roles, font, logo, and optional landing-page colours) and build the CSS from it. No Tailwind config is needed, and it works with the precompiled CSS:
|
|
840
|
+
|
|
841
|
+
```bash
|
|
842
|
+
npx @dreamtree-org/twreact-ui brand init --id acme --name "Acme" # starter file
|
|
843
|
+
npx @dreamtree-org/twreact-ui brand build --out app/brand.css # only the --dt-* variables you override
|
|
844
|
+
npx @dreamtree-org/twreact-ui brand build --out app/brand.css --check # in CI: fails if the CSS is stale
|
|
845
|
+
```
|
|
840
846
|
|
|
841
847
|
```css
|
|
842
848
|
@import "@dreamtree-org/twreact-ui/dist/index.css";
|
|
843
|
-
@import "
|
|
849
|
+
@import "./brand.css";
|
|
844
850
|
```
|
|
845
851
|
|
|
846
|
-
|
|
852
|
+
The file is checked against `tokens/brand.schema.json` (add `"$schema": "https://unpkg.com/@dreamtree-org/twreact-ui/tokens/brand.schema.json"` for editor help). `brand validate` lists every problem with its fix, and `--scope ".my-app"` limits the brand to part of a page. twreact-ui ships only `default`; the `practicepro` and `studio` brands are deprecated copies until 1.5.0.
|
|
847
853
|
|
|
848
854
|
**Use the same tokens in your own classes:**
|
|
849
855
|
|
|
@@ -872,7 +878,7 @@ This adds semantic utilities next to the palettes: `bg-surface`, `bg-background`
|
|
|
872
878
|
|
|
873
879
|
**Colour props are overrides, not defaults.** Without colour props, `ProgressBar`, `Checkbox`, `Rate` and `Skeleton` use token classes, so a brand file recolours them. Their HEX props (`color`, `bgColor`, `borderColor`, `activeColor`, `inactiveColor`) still work but are deprecated.
|
|
874
880
|
|
|
875
|
-
**SSR:** `Tabs`, `Tooltip` and `Switch` generate ids with `React.useId()`, so server-rendered pages (Next.js) hydrate without mismatches.
|
|
881
|
+
**SSR:** `Tabs`, `Tooltip` and `Switch` generate ids with `React.useId()`, so server-rendered pages (Next.js) hydrate without mismatches. The `/charts` components do the same for their SVG ids, and they render token colours and reduced-motion state the way the server did until hydration finishes.
|
|
876
882
|
|
|
877
883
|
## Dark Mode
|
|
878
884
|
|
|
@@ -205,7 +205,9 @@ When suggesting a component or new variant value, use this exact vocabulary.
|
|
|
205
205
|
**Tokens:** colours are CSS variables (`--dt-primary-600`, `--dt-surface`, …) generated from
|
|
206
206
|
`tokens/tokens.json`. Use semantic classes (`bg-primary-600`, `bg-surface`, `text-foreground`,
|
|
207
207
|
`text-muted`, `border-line`, `text-micro`, `rounded-card`) — never hex values or Tailwind's raw
|
|
208
|
-
palette (`bg-blue-500`). A product
|
|
208
|
+
palette (`bg-blue-500`). A product's brand lives in its own repo as `dreamtree.brand.json`;
|
|
209
|
+
`npx @dreamtree-org/twreact-ui brand build --out app/brand.css` turns it into the CSS to load after
|
|
210
|
+
twreact-ui's CSS. To change a product's colours, edit that file, never the components.
|
|
209
211
|
The full rule set for screens is `DESIGN.md` in the package root.
|
|
210
212
|
|
|
211
213
|
```jsx
|
package/bin/cli.mjs
CHANGED
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
|
|
18
18
|
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
|
|
19
19
|
import { fileURLToPath } from "node:url";
|
|
20
|
-
import { dirname, join, resolve } from "node:path";
|
|
20
|
+
import { dirname, join, resolve, relative } from "node:path";
|
|
21
|
+
import { createRequire } from "node:module";
|
|
21
22
|
|
|
22
23
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
23
24
|
const PKG_ROOT = resolve(__dirname, "..");
|
|
@@ -56,14 +57,20 @@ function printHelp() {
|
|
|
56
57
|
`${PKG} CLI (v${VERSION})\n\n` +
|
|
57
58
|
`Usage:\n` +
|
|
58
59
|
` npx ${PKG} init --ai <provider> [--out <path>] [--force]\n` +
|
|
59
|
-
` npx ${PKG} mcp\n
|
|
60
|
+
` npx ${PKG} mcp\n` +
|
|
61
|
+
` npx ${PKG} brand init|validate|build [dreamtree.brand.json] [options]\n\n` +
|
|
60
62
|
`Commands:\n` +
|
|
61
63
|
` init Install the AI-assistant skill (ai-skills/dreamtree-ui.md) so your\n` +
|
|
62
64
|
` coding agent knows this library's components, conventions, wiring.\n` +
|
|
63
65
|
` mcp Run the Model Context Protocol server over stdio — gives an MCP\n` +
|
|
64
66
|
` client live, queryable access to the library (list_components,\n` +
|
|
65
67
|
` get_component, search_components + docs + a compose_ui prompt).\n` +
|
|
66
|
-
` Wire it as: { "command": "npx", "args": ["-y", "${PKG}", "mcp"] }\n
|
|
68
|
+
` Wire it as: { "command": "npx", "args": ["-y", "${PKG}", "mcp"] }\n` +
|
|
69
|
+
` brand Your product's brand lives in your repo as dreamtree.brand.json.\n` +
|
|
70
|
+
` init write a starter file (--id <slug> --name <Name>)\n` +
|
|
71
|
+
` validate check it, with a fix for every problem\n` +
|
|
72
|
+
` build write the CSS to load after twreact-ui's CSS\n` +
|
|
73
|
+
` (--out app/brand.css, --scope <selector>, --check for CI)\n\n` +
|
|
67
74
|
`init options:\n` +
|
|
68
75
|
` --ai <provider> Target assistant: ${providers} (default: claude)\n` +
|
|
69
76
|
` --out <path> Write to this path instead of the provider default\n` +
|
|
@@ -74,12 +81,16 @@ function printHelp() {
|
|
|
74
81
|
}
|
|
75
82
|
|
|
76
83
|
function parseArgs(argv) {
|
|
77
|
-
const out = { _: [], ai: undefined, out: undefined, force: false, help: false, version: false };
|
|
84
|
+
const out = { _: [], ai: undefined, out: undefined, force: false, help: false, version: false, scope: undefined, check: false, id: undefined, name: undefined };
|
|
78
85
|
for (let i = 0; i < argv.length; i++) {
|
|
79
86
|
const a = argv[i];
|
|
80
87
|
if (a === "--ai") out.ai = argv[++i];
|
|
81
88
|
else if (a === "--out") out.out = argv[++i];
|
|
82
89
|
else if (a === "--force") out.force = true;
|
|
90
|
+
else if (a === "--scope") out.scope = argv[++i];
|
|
91
|
+
else if (a === "--check") out.check = true;
|
|
92
|
+
else if (a === "--id") out.id = argv[++i];
|
|
93
|
+
else if (a === "--name") out.name = argv[++i];
|
|
83
94
|
else if (a === "-h" || a === "--help") out.help = true;
|
|
84
95
|
else if (a === "-v" || a === "--version") out.version = true;
|
|
85
96
|
else out._.push(a);
|
|
@@ -117,6 +128,62 @@ function runInit(args) {
|
|
|
117
128
|
);
|
|
118
129
|
}
|
|
119
130
|
|
|
131
|
+
// `brand` — a product keeps its brand in its own repo (dreamtree.brand.json); these commands turn it into CSS.
|
|
132
|
+
// tokens/lib.cjs is CommonJS and dependency-free, so this stays a zero-dependency path.
|
|
133
|
+
const BRAND_FILE = "dreamtree.brand.json";
|
|
134
|
+
|
|
135
|
+
function runBrand(args) {
|
|
136
|
+
const lib = createRequire(import.meta.url)("../tokens/lib.cjs");
|
|
137
|
+
const sub = args._[1];
|
|
138
|
+
const file = resolve(process.cwd(), args._[2] || BRAND_FILE);
|
|
139
|
+
const shown = relative(process.cwd(), file) || BRAND_FILE;
|
|
140
|
+
|
|
141
|
+
if (sub === "init") {
|
|
142
|
+
if (existsSync(file) && !args.force) fail(`${shown} already exists. Re-run with --force to overwrite.`);
|
|
143
|
+
const id = (args.id || "my-product").toLowerCase();
|
|
144
|
+
const base = lib.scales(lib.loadTokens()).primary;
|
|
145
|
+
const starter = {
|
|
146
|
+
$schema: "https://unpkg.com/@dreamtree-org/twreact-ui/tokens/brand.schema.json",
|
|
147
|
+
id,
|
|
148
|
+
name: args.name || id,
|
|
149
|
+
color: { primary: base },
|
|
150
|
+
role: {},
|
|
151
|
+
marketing: {},
|
|
152
|
+
};
|
|
153
|
+
writeFileSync(file, JSON.stringify(starter, null, 2) + "\n");
|
|
154
|
+
process.stdout.write(`✓ wrote ${shown}. Change color.primary to your product's scale, then run: npx ${PKG} brand build\n`);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (sub === "validate" || sub === "build") {
|
|
159
|
+
let brand;
|
|
160
|
+
try {
|
|
161
|
+
brand = lib.loadBrand(file);
|
|
162
|
+
} catch (err) {
|
|
163
|
+
fail(err.message);
|
|
164
|
+
}
|
|
165
|
+
if (sub === "validate") {
|
|
166
|
+
process.stdout.write(`✓ ${shown} is a valid brand ("${lib.brandId(brand)}").\n`);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const css = lib.brandCss(lib.loadTokens(), brand, { scope: args.scope });
|
|
170
|
+
const outFile = resolve(process.cwd(), args.out || "brand.css");
|
|
171
|
+
const outShown = relative(process.cwd(), outFile);
|
|
172
|
+
if (args.check) {
|
|
173
|
+
const current = existsSync(outFile) ? readFileSync(outFile, "utf8") : "";
|
|
174
|
+
if (current !== css) fail(`${outShown} is out of date with ${shown}. Run: npx ${PKG} brand build ${shown} --out ${outShown}${args.scope ? ` --scope "${args.scope}"` : ""}`);
|
|
175
|
+
process.stdout.write(`✓ ${outShown} matches ${shown}.\n`);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
mkdirSync(dirname(outFile), { recursive: true });
|
|
179
|
+
writeFileSync(outFile, css);
|
|
180
|
+
process.stdout.write(`✓ wrote ${outShown} from ${shown}. Import it after "${PKG}/dist/index.css".\n`);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
fail(`unknown brand command "${sub || ""}". Use: brand init | brand validate | brand build.`);
|
|
185
|
+
}
|
|
186
|
+
|
|
120
187
|
// Boot the bundled MCP server over stdio. The SDK + server are lazy-imported
|
|
121
188
|
// here so plain `init` carries no dependency cost. stdout is the MCP protocol
|
|
122
189
|
// channel, so this path must only ever log to stderr. The shipped server reads
|
|
@@ -140,6 +207,7 @@ async function main() {
|
|
|
140
207
|
const cmd = args._[0];
|
|
141
208
|
if (cmd === "init") return runInit(args);
|
|
142
209
|
if (cmd === "mcp") return runMcp();
|
|
210
|
+
if (cmd === "brand") return runBrand(args);
|
|
143
211
|
|
|
144
212
|
fail(`unknown command "${cmd}". Run \`npx ${PKG} --help\`.`);
|
|
145
213
|
}
|
package/dist/ai-schema.json
CHANGED
package/dist/charts/index.js
CHANGED
|
@@ -200,9 +200,11 @@ function readVar(name) {
|
|
|
200
200
|
}
|
|
201
201
|
// SVG presentation attributes do not resolve var() in every engine, so a token is
|
|
202
202
|
// turned into a concrete rgb() string when the browser can tell us its value. The
|
|
203
|
-
// var() form is the SSR / jsdom fallback
|
|
203
|
+
// var() form is the SSR / jsdom fallback, and what the first (hydrating) client
|
|
204
|
+
// render uses so it matches the server's HTML (`live` = false).
|
|
204
205
|
function resolveVar(name) {
|
|
205
|
-
var
|
|
206
|
+
var live = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
|
|
207
|
+
var value = live ? readVar(name) : "";
|
|
206
208
|
return value ? "rgb(".concat(value.split(/[\s,]+/).join(" "), ")") : "rgb(var(".concat(name, "))");
|
|
207
209
|
}
|
|
208
210
|
/**
|
|
@@ -211,77 +213,92 @@ function resolveVar(name) {
|
|
|
211
213
|
* by the consumer (e.g. a colour stored with the data).
|
|
212
214
|
*/
|
|
213
215
|
function resolveColor(color) {
|
|
216
|
+
var live = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
|
|
214
217
|
var name = tokenVar(color);
|
|
215
|
-
return name ? resolveVar(name) : color;
|
|
218
|
+
return name ? resolveVar(name, live) : color;
|
|
216
219
|
}
|
|
217
220
|
function seriesColors(categories, colors) {
|
|
221
|
+
var live = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
|
218
222
|
var palette = colors && colors.length ? colors : DEFAULT_CHART_COLORS;
|
|
219
223
|
return categories.map(function (_, i) {
|
|
220
|
-
return resolveColor(palette[i % palette.length]);
|
|
224
|
+
return resolveColor(palette[i % palette.length], live);
|
|
221
225
|
});
|
|
222
226
|
}
|
|
223
|
-
function readChrome() {
|
|
227
|
+
function readChrome(live) {
|
|
224
228
|
return Object.fromEntries(Object.entries(CHROME_VARS).map(function (_ref) {
|
|
225
229
|
var _ref2 = cn._slicedToArray(_ref, 2),
|
|
226
230
|
k = _ref2[0],
|
|
227
231
|
v = _ref2[1];
|
|
228
|
-
return [k, resolveVar(v)];
|
|
232
|
+
return [k, resolveVar(v, live)];
|
|
229
233
|
}));
|
|
230
234
|
}
|
|
235
|
+
// The theme is an external store: the attributes on <html> that flip it. The
|
|
236
|
+
// server snapshot is null, so a hydrating render keeps the var() fallback the
|
|
237
|
+
// server rendered and React re-renders with live colours right after (#130).
|
|
238
|
+
function subscribeTheme(onChange) {
|
|
239
|
+
if (typeof document === "undefined" || typeof MutationObserver !== "function") return function () {};
|
|
240
|
+
var observer = new MutationObserver(onChange);
|
|
241
|
+
observer.observe(document.documentElement, {
|
|
242
|
+
attributes: true,
|
|
243
|
+
attributeFilter: ["class", "data-theme", "style"]
|
|
244
|
+
});
|
|
245
|
+
return function () {
|
|
246
|
+
return observer.disconnect();
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
function themeSnapshot() {
|
|
250
|
+
if (typeof document === "undefined") return null;
|
|
251
|
+
var el = document.documentElement;
|
|
252
|
+
return "".concat(el.className, "|").concat(el.getAttribute("data-theme") || "", "|").concat(el.getAttribute("style") || "");
|
|
253
|
+
}
|
|
254
|
+
var serverThemeSnapshot = function serverThemeSnapshot() {
|
|
255
|
+
return null;
|
|
256
|
+
};
|
|
231
257
|
/**
|
|
232
258
|
* Chart chrome + series colours, re-read whenever the theme flips (the `dark`
|
|
233
259
|
* class or `data-theme` on <html>) so axes and series follow dark mode without
|
|
234
260
|
* a remount.
|
|
235
261
|
*/
|
|
236
262
|
function useChartTheme(categories, colors) {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
_useState2[0];
|
|
240
|
-
var setVersion = _useState2[1];
|
|
241
|
-
React.useEffect(function () {
|
|
242
|
-
if (typeof MutationObserver !== "function") return undefined;
|
|
243
|
-
var observer = new MutationObserver(function () {
|
|
244
|
-
return setVersion(function (v) {
|
|
245
|
-
return v + 1;
|
|
246
|
-
});
|
|
247
|
-
});
|
|
248
|
-
observer.observe(document.documentElement, {
|
|
249
|
-
attributes: true,
|
|
250
|
-
attributeFilter: ["class", "data-theme", "style"]
|
|
251
|
-
});
|
|
252
|
-
return function () {
|
|
253
|
-
return observer.disconnect();
|
|
254
|
-
};
|
|
255
|
-
}, []);
|
|
263
|
+
// The snapshot only signals a change; the values come from the live document.
|
|
264
|
+
var live = React.useSyncExternalStore(subscribeTheme, themeSnapshot, serverThemeSnapshot) !== null;
|
|
256
265
|
return {
|
|
257
|
-
chrome: readChrome(),
|
|
258
|
-
series: seriesColors(categories, colors)
|
|
266
|
+
chrome: readChrome(live),
|
|
267
|
+
series: seriesColors(categories, colors, live)
|
|
259
268
|
};
|
|
260
269
|
}
|
|
261
|
-
|
|
270
|
+
function subscribeReducedMotion(onChange) {
|
|
271
|
+
var _query$addEventListen;
|
|
272
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return function () {};
|
|
273
|
+
var query = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
274
|
+
(_query$addEventListen = query.addEventListener) === null || _query$addEventListen === void 0 || _query$addEventListen.call(query, "change", onChange);
|
|
275
|
+
return function () {
|
|
276
|
+
var _query$removeEventLis;
|
|
277
|
+
return (_query$removeEventLis = query.removeEventListener) === null || _query$removeEventLis === void 0 ? void 0 : _query$removeEventLis.call(query, "change", onChange);
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
var serverReducedMotion = function serverReducedMotion() {
|
|
281
|
+
return false;
|
|
282
|
+
};
|
|
283
|
+
/**
|
|
284
|
+
* `true` while the user asks the OS for reduced motion; follows changes live.
|
|
285
|
+
* `false` on the server and while hydrating, so the first render matches.
|
|
286
|
+
*/
|
|
262
287
|
function useReducedMotion() {
|
|
263
|
-
|
|
264
|
-
_useState4 = cn._slicedToArray(_useState3, 2),
|
|
265
|
-
reduced = _useState4[0],
|
|
266
|
-
setReduced = _useState4[1];
|
|
267
|
-
React.useEffect(function () {
|
|
268
|
-
var _query$addEventListen;
|
|
269
|
-
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return undefined;
|
|
270
|
-
var query = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
271
|
-
var update = function update() {
|
|
272
|
-
return setReduced(query.matches);
|
|
273
|
-
};
|
|
274
|
-
(_query$addEventListen = query.addEventListener) === null || _query$addEventListen === void 0 || _query$addEventListen.call(query, "change", update);
|
|
275
|
-
return function () {
|
|
276
|
-
var _query$removeEventLis;
|
|
277
|
-
return (_query$removeEventLis = query.removeEventListener) === null || _query$removeEventLis === void 0 ? void 0 : _query$removeEventLis.call(query, "change", update);
|
|
278
|
-
};
|
|
279
|
-
}, []);
|
|
280
|
-
return reduced;
|
|
288
|
+
return React.useSyncExternalStore(subscribeReducedMotion, prefersReducedMotion, serverReducedMotion);
|
|
281
289
|
}
|
|
282
290
|
var defaultValueFormatter = function defaultValueFormatter(value) {
|
|
283
291
|
return typeof value === "number" ? value.toLocaleString() : value == null ? "" : String(value);
|
|
284
292
|
};
|
|
293
|
+
/**
|
|
294
|
+
* A per-instance id for the SVG defs recharts draws (clip paths). recharts 2
|
|
295
|
+
* falls back to a module-level counter, which differs between the server and the
|
|
296
|
+
* client; an id from React.useId() is the same on both. Only [A-Za-z0-9_-] so it
|
|
297
|
+
* is safe inside `url(#…)`.
|
|
298
|
+
*/
|
|
299
|
+
function useChartId() {
|
|
300
|
+
return "dt-chart-".concat(React.useId().replace(/[^A-Za-z0-9_-]/g, ""));
|
|
301
|
+
}
|
|
285
302
|
|
|
286
303
|
var _excluded$2 = ["kind", "data", "index", "categories", "colors", "valueFormatter", "xAxisFormatter", "height", "showLegend", "showTooltip", "showXAxis", "showYAxis", "showGrid", "yAxisWidth", "curveType", "stacked", "horizontal", "showDots", "connectNulls", "animate", "title", "description", "emptyState", "accessibleTable", "className"];
|
|
287
304
|
var ROOTS = {
|
|
@@ -301,7 +318,8 @@ var CURVES = {
|
|
|
301
318
|
natural: "natural"
|
|
302
319
|
};
|
|
303
320
|
function renderSeries(kind, _ref) {
|
|
304
|
-
var
|
|
321
|
+
var id = _ref.id,
|
|
322
|
+
category = _ref.category,
|
|
305
323
|
color = _ref.color,
|
|
306
324
|
curve = _ref.curve,
|
|
307
325
|
stacked = _ref.stacked,
|
|
@@ -311,6 +329,7 @@ function renderSeries(kind, _ref) {
|
|
|
311
329
|
horizontal = _ref.horizontal,
|
|
312
330
|
barRadius = _ref.barRadius;
|
|
313
331
|
var common = {
|
|
332
|
+
id: id,
|
|
314
333
|
dataKey: category,
|
|
315
334
|
name: category,
|
|
316
335
|
isAnimationActive: animate
|
|
@@ -410,6 +429,7 @@ var CartesianChart = /*#__PURE__*/React__default.default.forwardRef(function Car
|
|
|
410
429
|
chrome = _useChartTheme.chrome,
|
|
411
430
|
series = _useChartTheme.series;
|
|
412
431
|
var reducedMotion = useReducedMotion();
|
|
432
|
+
var chartId = useChartId();
|
|
413
433
|
var Root = ROOTS[kind];
|
|
414
434
|
var isHorizontalBars = kind === "bar" && horizontal;
|
|
415
435
|
var curve = CURVES[curveType] || "monotone";
|
|
@@ -470,6 +490,7 @@ var CartesianChart = /*#__PURE__*/React__default.default.forwardRef(function Car
|
|
|
470
490
|
height: "100%",
|
|
471
491
|
minWidth: 0,
|
|
472
492
|
children: jsxRuntime.jsxs(Root, {
|
|
493
|
+
id: chartId,
|
|
473
494
|
data: data,
|
|
474
495
|
layout: isHorizontalBars ? "vertical" : "horizontal",
|
|
475
496
|
margin: {
|
|
@@ -508,6 +529,7 @@ var CartesianChart = /*#__PURE__*/React__default.default.forwardRef(function Car
|
|
|
508
529
|
})
|
|
509
530
|
}), categories.map(function (category, i) {
|
|
510
531
|
return renderSeries(kind, {
|
|
532
|
+
id: "".concat(chartId, "-").concat(i),
|
|
511
533
|
category: category,
|
|
512
534
|
color: series[i],
|
|
513
535
|
curve: curve,
|
|
@@ -591,6 +613,7 @@ var DonutChart = /*#__PURE__*/React__default.default.forwardRef(function (_ref,
|
|
|
591
613
|
chrome = _useChartTheme.chrome,
|
|
592
614
|
series = _useChartTheme.series;
|
|
593
615
|
var reducedMotion = useReducedMotion();
|
|
616
|
+
var chartId = useChartId();
|
|
594
617
|
var slices = rows.map(function (row, i) {
|
|
595
618
|
return cn._objectSpread2(cn._objectSpread2({}, row), {}, {
|
|
596
619
|
fill: series[i]
|
|
@@ -632,6 +655,7 @@ var DonutChart = /*#__PURE__*/React__default.default.forwardRef(function (_ref,
|
|
|
632
655
|
height: "100%",
|
|
633
656
|
minWidth: 0,
|
|
634
657
|
children: jsxRuntime.jsxs(recharts.PieChart, {
|
|
658
|
+
id: chartId,
|
|
635
659
|
accessibilityLayer: false,
|
|
636
660
|
children: [showTooltip && jsxRuntime.jsx(recharts.Tooltip, {
|
|
637
661
|
isAnimationActive: false,
|
|
@@ -640,6 +664,7 @@ var DonutChart = /*#__PURE__*/React__default.default.forwardRef(function (_ref,
|
|
|
640
664
|
hideLabel: true
|
|
641
665
|
})
|
|
642
666
|
}), jsxRuntime.jsx(recharts.Pie, {
|
|
667
|
+
id: "".concat(chartId, "-0"),
|
|
643
668
|
data: slices,
|
|
644
669
|
dataKey: category,
|
|
645
670
|
nameKey: index,
|
|
@@ -691,9 +716,11 @@ var Sparkline = /*#__PURE__*/React__default.default.forwardRef(function (_ref, r
|
|
|
691
716
|
var _useChartTheme = useChartTheme([category], [color]),
|
|
692
717
|
series = _useChartTheme.series;
|
|
693
718
|
var reducedMotion = useReducedMotion();
|
|
719
|
+
var chartId = useChartId();
|
|
694
720
|
var stroke = series[0];
|
|
695
721
|
var Root = type === "area" ? recharts.AreaChart : recharts.LineChart;
|
|
696
722
|
var common = {
|
|
723
|
+
id: "".concat(chartId, "-0"),
|
|
697
724
|
dataKey: category,
|
|
698
725
|
name: category,
|
|
699
726
|
type: "monotone",
|
|
@@ -734,6 +761,7 @@ var Sparkline = /*#__PURE__*/React__default.default.forwardRef(function (_ref, r
|
|
|
734
761
|
height: "100%",
|
|
735
762
|
minWidth: 0,
|
|
736
763
|
children: jsxRuntime.jsxs(Root, {
|
|
764
|
+
id: chartId,
|
|
737
765
|
data: data,
|
|
738
766
|
margin: {
|
|
739
767
|
top: 2,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CartesianChart.d.ts","sourceRoot":"","sources":["../../../src/components/charts/CartesianChart.jsx"],"names":[],"mappings":";AA0DA,iEAAiE;AACjE,
|
|
1
|
+
{"version":3,"file":"CartesianChart.d.ts","sourceRoot":"","sources":["../../../src/components/charts/CartesianChart.jsx"],"names":[],"mappings":";AA0DA,iEAAiE;AACjE,wFA2HG;kBAtLe,OAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DonutChart.d.ts","sourceRoot":"","sources":["../../../src/components/charts/DonutChart.jsx"],"names":[],"mappings":";AAKA,
|
|
1
|
+
{"version":3,"file":"DonutChart.d.ts","sourceRoot":"","sources":["../../../src/components/charts/DonutChart.jsx"],"names":[],"mappings":";AAKA,oFAgFE;kBArFgB,OAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Sparkline.d.ts","sourceRoot":"","sources":["../../../src/components/charts/Sparkline.jsx"],"names":[],"mappings":";AAKA,qFAAqF;AACrF,
|
|
1
|
+
{"version":3,"file":"Sparkline.d.ts","sourceRoot":"","sources":["../../../src/components/charts/Sparkline.jsx"],"names":[],"mappings":";AAKA,qFAAqF;AACrF,mFAuEE;kBA7EgB,OAAO"}
|
|
@@ -5,8 +5,8 @@ export function tokenVar(color: any): string | null;
|
|
|
5
5
|
* matching `--dt-*` variable; any other string is treated as a CSS colour supplied
|
|
6
6
|
* by the consumer (e.g. a colour stored with the data).
|
|
7
7
|
*/
|
|
8
|
-
export function resolveColor(color: any): any;
|
|
9
|
-
export function seriesColors(categories: any, colors: any): any;
|
|
8
|
+
export function resolveColor(color: any, live?: boolean): any;
|
|
9
|
+
export function seriesColors(categories: any, colors: any, live?: boolean): any;
|
|
10
10
|
/**
|
|
11
11
|
* Chart chrome + series colours, re-read whenever the theme flips (the `dark`
|
|
12
12
|
* class or `data-theme` on <html>) so axes and series follow dark mode without
|
|
@@ -18,8 +18,18 @@ export function useChartTheme(categories: any, colors: any): {
|
|
|
18
18
|
};
|
|
19
19
|
series: any;
|
|
20
20
|
};
|
|
21
|
-
/**
|
|
21
|
+
/**
|
|
22
|
+
* `true` while the user asks the OS for reduced motion; follows changes live.
|
|
23
|
+
* `false` on the server and while hydrating, so the first render matches.
|
|
24
|
+
*/
|
|
22
25
|
export function useReducedMotion(): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* A per-instance id for the SVG defs recharts draws (clip paths). recharts 2
|
|
28
|
+
* falls back to a module-level counter, which differs between the server and the
|
|
29
|
+
* client; an id from React.useId() is the same on both. Only [A-Za-z0-9_-] so it
|
|
30
|
+
* is safe inside `url(#…)`.
|
|
31
|
+
*/
|
|
32
|
+
export function useChartId(): string;
|
|
23
33
|
export const CHART_PALETTES: string[];
|
|
24
34
|
export const DEFAULT_CHART_COLORS: string[];
|
|
25
35
|
export function defaultValueFormatter(value: any): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chartTheme.d.ts","sourceRoot":"","sources":["../../../src/components/charts/chartTheme.js"],"names":[],"mappings":"AAgBA,sGAAsG;AACtG,oDAGC;
|
|
1
|
+
{"version":3,"file":"chartTheme.d.ts","sourceRoot":"","sources":["../../../src/components/charts/chartTheme.js"],"names":[],"mappings":"AAgBA,sGAAsG;AACtG,oDAGC;AAgBD;;;;GAIG;AACH,8DAGC;AAED,gFAGC;AAwBD;;;;GAIG;AACH;;;;;EAIC;AAWD;;;GAGG;AACH,4CAEC;AAKD;;;;;GAKG;AACH,qCAEC;AA7GD,sCAAsG;AAEtG,4CAA4G;AAgGrG,0DACkF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MobileCard.d.ts","sourceRoot":"","sources":["../../../../src/components/core/Table/MobileCard.jsx"],"names":[],"mappings":";AAWA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"MobileCard.d.ts","sourceRoot":"","sources":["../../../../src/components/core/Table/MobileCard.jsx"],"names":[],"mappings":";AAWA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4CAoOC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MobileFilters.d.ts","sourceRoot":"","sources":["../../../../src/components/core/Table/MobileFilters.jsx"],"names":[],"mappings":";AAGA;;GAEG;AACH;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"MobileFilters.d.ts","sourceRoot":"","sources":["../../../../src/components/core/Table/MobileFilters.jsx"],"names":[],"mappings":";AAGA;;GAEG;AACH;;;;;;;;;;;4CAmEC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Table.d.ts","sourceRoot":"","sources":["../../../../src/components/core/Table/Table.jsx"],"names":[],"mappings":";AA8CA,+
|
|
1
|
+
{"version":3,"file":"Table.d.ts","sourceRoot":"","sources":["../../../../src/components/core/Table/Table.jsx"],"names":[],"mappings":";AA8CA,+EAkhDG;kBAvjDI,OAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Stepper.d.ts","sourceRoot":"","sources":["../../../src/components/utility/Stepper.jsx"],"names":[],"mappings":";AAIA,
|
|
1
|
+
{"version":3,"file":"Stepper.d.ts","sourceRoot":"","sources":["../../../src/components/utility/Stepper.jsx"],"names":[],"mappings":";AAIA,iFAoIG;kBAxIe,OAAO"}
|
|
@@ -57,7 +57,7 @@ var StatCard = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
|
57
57
|
}), change && !loading && jsxs("p", {
|
|
58
58
|
className: "mt-1 flex items-center gap-1 text-xs text-muted",
|
|
59
59
|
children: [jsxs("span", {
|
|
60
|
-
className: cn('inline-flex items-center gap-0.5 font-semibold', good ? 'text-success-
|
|
60
|
+
className: cn('inline-flex items-center gap-0.5 font-semibold', good ? 'text-success-700 dark:text-success-400' : 'text-error-700 dark:text-error-400'),
|
|
61
61
|
children: [up ? jsx(ArrowUp, {
|
|
62
62
|
className: "h-3.5 w-3.5",
|
|
63
63
|
"aria-hidden": "true"
|
|
@@ -4,7 +4,7 @@ import { jsx, jsxs } from 'react/jsx-runtime';
|
|
|
4
4
|
import React from 'react';
|
|
5
5
|
import { ResponsiveContainer, AreaChart, BarChart, LineChart, CartesianGrid, XAxis, YAxis, Tooltip, Bar, Area, Line } from 'recharts';
|
|
6
6
|
import { ChartFrame, ChartTooltipContent } from './ChartFrame.js';
|
|
7
|
-
import { useChartTheme, useReducedMotion, defaultValueFormatter } from './chartTheme.js';
|
|
7
|
+
import { useChartTheme, useReducedMotion, useChartId, defaultValueFormatter } from './chartTheme.js';
|
|
8
8
|
|
|
9
9
|
var _excluded = ["kind", "data", "index", "categories", "colors", "valueFormatter", "xAxisFormatter", "height", "showLegend", "showTooltip", "showXAxis", "showYAxis", "showGrid", "yAxisWidth", "curveType", "stacked", "horizontal", "showDots", "connectNulls", "animate", "title", "description", "emptyState", "accessibleTable", "className"];
|
|
10
10
|
var ROOTS = {
|
|
@@ -24,7 +24,8 @@ var CURVES = {
|
|
|
24
24
|
natural: "natural"
|
|
25
25
|
};
|
|
26
26
|
function renderSeries(kind, _ref) {
|
|
27
|
-
var
|
|
27
|
+
var id = _ref.id,
|
|
28
|
+
category = _ref.category,
|
|
28
29
|
color = _ref.color,
|
|
29
30
|
curve = _ref.curve,
|
|
30
31
|
stacked = _ref.stacked,
|
|
@@ -34,6 +35,7 @@ function renderSeries(kind, _ref) {
|
|
|
34
35
|
horizontal = _ref.horizontal,
|
|
35
36
|
barRadius = _ref.barRadius;
|
|
36
37
|
var common = {
|
|
38
|
+
id: id,
|
|
37
39
|
dataKey: category,
|
|
38
40
|
name: category,
|
|
39
41
|
isAnimationActive: animate
|
|
@@ -133,6 +135,7 @@ var CartesianChart = /*#__PURE__*/React.forwardRef(function CartesianChart(_ref2
|
|
|
133
135
|
chrome = _useChartTheme.chrome,
|
|
134
136
|
series = _useChartTheme.series;
|
|
135
137
|
var reducedMotion = useReducedMotion();
|
|
138
|
+
var chartId = useChartId();
|
|
136
139
|
var Root = ROOTS[kind];
|
|
137
140
|
var isHorizontalBars = kind === "bar" && horizontal;
|
|
138
141
|
var curve = CURVES[curveType] || "monotone";
|
|
@@ -193,6 +196,7 @@ var CartesianChart = /*#__PURE__*/React.forwardRef(function CartesianChart(_ref2
|
|
|
193
196
|
height: "100%",
|
|
194
197
|
minWidth: 0,
|
|
195
198
|
children: jsxs(Root, {
|
|
199
|
+
id: chartId,
|
|
196
200
|
data: data,
|
|
197
201
|
layout: isHorizontalBars ? "vertical" : "horizontal",
|
|
198
202
|
margin: {
|
|
@@ -231,6 +235,7 @@ var CartesianChart = /*#__PURE__*/React.forwardRef(function CartesianChart(_ref2
|
|
|
231
235
|
})
|
|
232
236
|
}), categories.map(function (category, i) {
|
|
233
237
|
return renderSeries(kind, {
|
|
238
|
+
id: "".concat(chartId, "-").concat(i),
|
|
234
239
|
category: category,
|
|
235
240
|
color: series[i],
|
|
236
241
|
curve: curve,
|
|
@@ -4,7 +4,7 @@ import { jsx, jsxs } from 'react/jsx-runtime';
|
|
|
4
4
|
import React from 'react';
|
|
5
5
|
import { ResponsiveContainer, PieChart, Tooltip, Pie } from 'recharts';
|
|
6
6
|
import { ChartFrame, ChartTooltipContent } from './ChartFrame.js';
|
|
7
|
-
import { useChartTheme, useReducedMotion, defaultValueFormatter } from './chartTheme.js';
|
|
7
|
+
import { useChartTheme, useReducedMotion, useChartId, defaultValueFormatter } from './chartTheme.js';
|
|
8
8
|
|
|
9
9
|
var _excluded = ["data", "index", "category", "colors", "valueFormatter", "variant", "innerRadius", "outerRadius", "centerLabel", "height", "showLegend", "showTooltip", "animate", "title", "description", "emptyState", "accessibleTable", "className"];
|
|
10
10
|
var DonutChart = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
@@ -46,6 +46,7 @@ var DonutChart = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
|
46
46
|
chrome = _useChartTheme.chrome,
|
|
47
47
|
series = _useChartTheme.series;
|
|
48
48
|
var reducedMotion = useReducedMotion();
|
|
49
|
+
var chartId = useChartId();
|
|
49
50
|
var slices = rows.map(function (row, i) {
|
|
50
51
|
return _objectSpread2(_objectSpread2({}, row), {}, {
|
|
51
52
|
fill: series[i]
|
|
@@ -87,6 +88,7 @@ var DonutChart = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
|
87
88
|
height: "100%",
|
|
88
89
|
minWidth: 0,
|
|
89
90
|
children: jsxs(PieChart, {
|
|
91
|
+
id: chartId,
|
|
90
92
|
accessibilityLayer: false,
|
|
91
93
|
children: [showTooltip && jsx(Tooltip, {
|
|
92
94
|
isAnimationActive: false,
|
|
@@ -95,6 +97,7 @@ var DonutChart = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
|
95
97
|
hideLabel: true
|
|
96
98
|
})
|
|
97
99
|
}), jsx(Pie, {
|
|
100
|
+
id: "".concat(chartId, "-0"),
|
|
98
101
|
data: slices,
|
|
99
102
|
dataKey: category,
|
|
100
103
|
nameKey: index,
|
|
@@ -4,7 +4,7 @@ import { jsx, jsxs } from 'react/jsx-runtime';
|
|
|
4
4
|
import React from 'react';
|
|
5
5
|
import { ResponsiveContainer, AreaChart, LineChart, YAxis, Tooltip, Area, Line } from 'recharts';
|
|
6
6
|
import { ChartFrame, ChartTooltipContent } from './ChartFrame.js';
|
|
7
|
-
import { useChartTheme, useReducedMotion, defaultValueFormatter } from './chartTheme.js';
|
|
7
|
+
import { useChartTheme, useReducedMotion, useChartId, defaultValueFormatter } from './chartTheme.js';
|
|
8
8
|
|
|
9
9
|
var _excluded = ["data", "category", "index", "color", "type", "valueFormatter", "height", "showTooltip", "animate", "title", "description", "emptyState", "accessibleTable", "className"];
|
|
10
10
|
/** A word-sized trend line: no axes, grid or legend — just the shape of the data. */
|
|
@@ -36,9 +36,11 @@ var Sparkline = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
|
36
36
|
var _useChartTheme = useChartTheme([category], [color]),
|
|
37
37
|
series = _useChartTheme.series;
|
|
38
38
|
var reducedMotion = useReducedMotion();
|
|
39
|
+
var chartId = useChartId();
|
|
39
40
|
var stroke = series[0];
|
|
40
41
|
var Root = type === "area" ? AreaChart : LineChart;
|
|
41
42
|
var common = {
|
|
43
|
+
id: "".concat(chartId, "-0"),
|
|
42
44
|
dataKey: category,
|
|
43
45
|
name: category,
|
|
44
46
|
type: "monotone",
|
|
@@ -79,6 +81,7 @@ var Sparkline = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
|
|
|
79
81
|
height: "100%",
|
|
80
82
|
minWidth: 0,
|
|
81
83
|
children: jsxs(Root, {
|
|
84
|
+
id: chartId,
|
|
82
85
|
data: data,
|
|
83
86
|
margin: {
|
|
84
87
|
top: 2,
|