@godxjp/ui 32.14.0 → 32.15.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 +4 -4
- package/agent/START-HERE.md +7 -7
- package/agent/components/HeatmapChart.json +97 -0
- package/agent/components-index.json +5 -0
- package/agent/components.json +97 -0
- package/agent/index.json +7 -7
- package/agent/llms.txt +6 -6
- package/agent/tokens.json +114 -0
- package/dist/components/charts/chart-summary.d.ts +32 -1
- package/dist/components/charts/chart-summary.js +49 -0
- package/dist/components/charts/heatmap-chart.d.ts +19 -0
- package/dist/components/charts/heatmap-chart.js +293 -0
- package/dist/components/charts/index.d.ts +3 -0
- package/dist/components/charts/index.js +2 -0
- package/dist/components/feedback/tooltip.d.ts +9 -0
- package/dist/components/feedback/tooltip.js +4 -1
- package/dist/contracts/measurement.json +1 -1
- package/dist/i18n/messages/en.json +8 -1
- package/dist/i18n/messages/ja.json +8 -1
- package/dist/i18n/messages/vi.json +8 -1
- package/dist/props/components/charts.prop.d.ts +58 -0
- package/dist/props/registry.d.ts +37 -0
- package/dist/props/registry.js +36 -0
- package/dist/styles/chart-layout.css +161 -0
- package/dist/styles/layers.json +8 -1
- package/dist/styles.css +1 -1
- package/dist/tokens/components/chart.css +27 -0
- package/dist/tokens/foundation.css +12 -0
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ npm i @godxjp/ui
|
|
|
18
18
|
|
|
19
19
|
<!-- agent-catalog-counts:start -->
|
|
20
20
|
|
|
21
|
-
The catalog —
|
|
21
|
+
The catalog — 163 components, 2229 tokens, 43 cardinal rules — is published in two forms from one
|
|
22
22
|
source. **Entry point for either: [`AGENTS.md`](AGENTS.md).**
|
|
23
23
|
<!-- agent-catalog-counts:end -->
|
|
24
24
|
|
|
@@ -53,10 +53,10 @@ static files straight from this public repo — no hosting, no deploy step:
|
|
|
53
53
|
| [`agent/llms.txt`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/llms.txt) | 3 KB | the [llms.txt](https://llmstxt.org/) entry point |
|
|
54
54
|
| [`agent/DESIGN.md`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/DESIGN.md) | 17 KB | the visual spec: tokens, colour scarcity, admin screen anatomy, do/don't |
|
|
55
55
|
| [`agent/index.json`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/index.json) | 3 KB | manifest: version, counts, every file's URL |
|
|
56
|
-
| [`agent/components-index.json`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components-index.json) | 48 KB | all
|
|
56
|
+
| [`agent/components-index.json`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components-index.json) | 48 KB | all 163 as name + group + tagline — **fetch this first** |
|
|
57
57
|
| [`agent/components/<Name>.json`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components/Select.json) | 1 KB–37 KB | one file per component, each with its `importPath` — **this is the route to take** |
|
|
58
|
-
| [`agent/components.json`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components.json) | 1.2 MB | all
|
|
59
|
-
| [`agent/tokens.json`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/tokens.json) |
|
|
58
|
+
| [`agent/components.json`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components.json) | 1.2 MB | all 163 entries in one file — most URL fetchers truncate this silently; prefer the per-component files |
|
|
59
|
+
| [`agent/tokens.json`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/tokens.json) | 857 KB | all 2229 design tokens, their values and why they exist |
|
|
60
60
|
| [`agent/vocabulary.json`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/vocabulary.json) | 7 KB | the controlled prop vocabulary |
|
|
61
61
|
| [`agent/rules.json`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/rules.json) | 21 KB | the 43 cardinal rules |
|
|
62
62
|
<!-- prettier-ignore-end -->
|
package/agent/START-HERE.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
You are about to write code against a design system you did not author. This file is the whole
|
|
4
4
|
contract. Read it before you write JSX.
|
|
5
5
|
|
|
6
|
-
**This catalog describes `@godxjp/ui` 32.
|
|
6
|
+
**This catalog describes `@godxjp/ui` 32.15.0.** If the project you are editing has a different
|
|
7
7
|
version in its `package.json`, read the pinned catalog for THAT version instead
|
|
8
8
|
(`…/v<their-version>/agent/…`). A catalog newer than the installed package describes props that do
|
|
9
9
|
not exist yet; older, and it hides props that do. Neither failure announces itself.
|
|
@@ -52,7 +52,7 @@ screen anatomy, the visual target the rules below do not give you. Then fetch in
|
|
|
52
52
|
task is a task** — "build a settings page", "confirm a destructive delete", "a list page with
|
|
53
53
|
filters" — start HERE, not at the components. Then fetch `patterns/<name>.json` for complete,
|
|
54
54
|
copy-paste-ready code. A component index answers "does X exist"; it cannot answer "build Y".
|
|
55
|
-
1. `components-index.json` — 48 KB, all
|
|
55
|
+
1. `components-index.json` — 48 KB, all 163 components as name + group +
|
|
56
56
|
tagline. Read this when you already know the SHAPE you need. Each entry may carry `absorbed`:
|
|
57
57
|
names that **do not exist** and map to it — `Combobox`, `Autocomplete`, `CountrySelect` and
|
|
58
58
|
`SearchSelect` are all `Select`. If you are about to hand-roll something, search this field
|
|
@@ -61,10 +61,10 @@ screen anatomy, the visual target the rules below do not give you. Then fetch in
|
|
|
61
61
|
its `importPath`, and its examples. Fetch only the handful you picked in step 1.
|
|
62
62
|
3. `rules.json` — 43 cardinal rules. The ones about raw HTML and hardcoded colour are not
|
|
63
63
|
style advice.
|
|
64
|
-
4. `tokens.json` —
|
|
65
|
-
brand, read the
|
|
64
|
+
4. `tokens.json` — 2229 design tokens, each tagged with its `tier`. **If you were handed a
|
|
65
|
+
brand, read the 216 `foundation` entries first** — `--primary`, `--background`,
|
|
66
66
|
`--radius`, `--font-size-base` are the handful everything else derives from. The
|
|
67
|
-
|
|
67
|
+
1900 `component` entries are per-part knobs; reach for one only when a role is
|
|
68
68
|
right everywhere except one component.
|
|
69
69
|
5. `anti-ai-tells.json` — 35 shapes that make generated UI look generated, each with the
|
|
70
70
|
fix. Read before you reach for a gradient hero or a wall of coloured chips.
|
|
@@ -148,9 +148,9 @@ has stopped following the brand.
|
|
|
148
148
|
|
|
149
149
|
| `tier` | count | what it is | set it? |
|
|
150
150
|
|---|---|---|---|
|
|
151
|
-
| `foundation` |
|
|
151
|
+
| `foundation` | 216 | the seeds — `--primary`, `--background`, `--foreground`, `--radius`, `--font-size-base`, `--shadow-color`. Everything below is derived from these | **yes — this is the main road.** The default `--primary` is a neutral placeholder: set it (`:root { --primary: <H> <S>% <L>%; }`, HSL components, no `hsl()` wrapper) or import a theme preset such as `@godxjp/ui/themes/godx.css` |
|
|
152
152
|
| `semantic` | 113 | named roles that follow the seeds — `--ring`, `--text-link`, `--primary-hover`, `--overlay-background` | only when the seed is right and ONE role must differ. That role then stops following a later brand change |
|
|
153
|
-
| `component` |
|
|
153
|
+
| `component` | 1900 | per-part knobs, `--{component}-{part}-{property}` | rarely. Most are declared `initial` with the real default at the call site — deliberate, so a scoped override re-resolves instead of freezing at `:root` |
|
|
154
154
|
|
|
155
155
|
A token whose `value` is `initial` is not empty and not broken: `initial` is the guaranteed-invalid
|
|
156
156
|
value, so the real default is computed where the element paints it. Set it and yours wins.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
{
|
|
2
|
+
"example": "import { HeatmapChart } from \"@godxjp/ui/charts/heatmap-chart\";\nimport { useTranslation } from \"@godxjp/ui/i18n\";\n\nconst { t, locale } = useTranslation();\nconst weekday = new Intl.DateTimeFormat(locale, { weekday: \"short\", timeZone: \"UTC\" });\nconst rows = [\"mon\", \"tue\", \"wed\", \"thu\", \"fri\", \"sat\", \"sun\"].map((key, day) => ({\n key,\n label: weekday.format(new Date(Date.UTC(2024, 0, 1 + day))), // 2024-01-01 is a Monday\n}));\nconst columns = Array.from({ length: 24 }, (_, hour) => ({ key: hour, label: new Intl.NumberFormat(locale).format(hour) }));\n\n<HeatmapChart\n label={t(\"dashboard.revenueByHour\")}\n rows={rows}\n columns={columns}\n data={slots /* [{ row: \"fri\", column: 19, value: 48000 }, …] — omit closed hours */}\n numberFormat={{ style: \"currency\", currency: \"JPY\" }}\n topN={3}\n/>",
|
|
3
|
+
"group": "data-display",
|
|
4
|
+
"importPath": "@godxjp/ui/charts/heatmap-chart",
|
|
5
|
+
"name": "HeatmapChart",
|
|
6
|
+
"props": [
|
|
7
|
+
{
|
|
8
|
+
"description": "Row categories, top to bottom (the y axis — weekdays). `label` is already translated.",
|
|
9
|
+
"name": "rows",
|
|
10
|
+
"required": true,
|
|
11
|
+
"type": "{ key: string | number; label: string }[]"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"description": "Column categories, start to end (the x axis — hours). `label` is already translated.",
|
|
15
|
+
"name": "columns",
|
|
16
|
+
"required": true,
|
|
17
|
+
"type": "{ key: string | number; label: string }[]"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"description": "Cell values keyed by row + column key. A cell that is absent, null, undefined or NaN is EMPTY ('no data') — never painted as a zero.",
|
|
21
|
+
"name": "data",
|
|
22
|
+
"required": true,
|
|
23
|
+
"type": "{ row: string | number; column: string | number; value: number | null | undefined }[]"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"description": "Accessible name of the figure and its grid + visible caption.",
|
|
27
|
+
"name": "label",
|
|
28
|
+
"required": true,
|
|
29
|
+
"type": "string"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"defaultValue": "true",
|
|
33
|
+
"description": "Paint `label` as a visible caption. Set false under a CardTitle that already says it — the caption stays sr-only so the grid keeps its name.",
|
|
34
|
+
"name": "showCaption",
|
|
35
|
+
"type": "boolean"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"description": "Extra context prepended to the screen-reader summary.",
|
|
39
|
+
"name": "description",
|
|
40
|
+
"type": "string"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"defaultValue": "\"md\"",
|
|
44
|
+
"description": "CELL size tier (--chart-heatmap-cell-size-*: 24/28/32/40px) — not a canvas height. A cell never shrinks below it; when the columns do not fit, the matrix scrolls inside its own box with the row header pinned.",
|
|
45
|
+
"name": "size",
|
|
46
|
+
"type": "\"xs\" | \"sm\" | \"md\" | \"lg\""
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"description": "Locale-aware formatting for cell values, the tooltip, the legend ranges and the summary (e.g. `{ style: 'currency', currency: 'JPY' }`).",
|
|
50
|
+
"name": "numberFormat",
|
|
51
|
+
"type": "Intl.NumberFormatOptions"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"description": "Emphasize the N highest cells with an outline ring plus a 'Top k' note in the tooltip, the cell text and the legend — never colour alone. Ties keep `data` order.",
|
|
55
|
+
"name": "topN",
|
|
56
|
+
"type": "number"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"defaultValue": "true",
|
|
60
|
+
"description": "Colour-scale legend (min … max, one readable range per swatch) plus the 'no data' and 'top N' keys when they apply.",
|
|
61
|
+
"name": "showLegend",
|
|
62
|
+
"type": "boolean"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"description": "Shown when there are no rows, no columns or no cells with a value.",
|
|
66
|
+
"name": "emptyMessage",
|
|
67
|
+
"type": "string"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"description": "Forwarded to the <figure> element.",
|
|
71
|
+
"name": "ref",
|
|
72
|
+
"type": "React.Ref<HTMLElement>"
|
|
73
|
+
}
|
|
74
|
+
],
|
|
75
|
+
"related": [
|
|
76
|
+
"CompactBarTrend — one row of values; the other dependency-free chart.",
|
|
77
|
+
"BarChart — exact comparison across a single category axis (recharts peer).",
|
|
78
|
+
"DataTable — when the reader needs to sort, filter or read exact numbers first."
|
|
79
|
+
],
|
|
80
|
+
"rules": [],
|
|
81
|
+
"storyPath": "charts/heatmap-chart.tsx",
|
|
82
|
+
"tagline": "DEPENDENCY-FREE rows × columns heatmap — weekday × hour revenue / order counts, cell intensity from the sequential CVD-safe --chart-heat-1..5 ramp. Empty ≠ zero (dashed outline + 'no data' text), optional top-N ring, per-cell tooltip, APG grid keyboard, the table itself is the text alternative. Needs NO recharts. Matrix / punch card / activity heatmap / busy-hours chart.",
|
|
83
|
+
"usage": [
|
|
84
|
+
"DO import from the isolated entry: `import { HeatmapChart } from \"@godxjp/ui/charts/heatmap-chart\";` — it never links the optional `recharts` peer.",
|
|
85
|
+
"DO derive axis labels with Intl in the active locale — weekdays via `Intl.DateTimeFormat(locale, { weekday: 'short' })`, hours via `Intl.NumberFormat(locale)` — and pass money through `numberFormat`, never a hand-built '¥' string.",
|
|
86
|
+
"DO leave a slot OUT of `data` (or pass `value: null`) when there is no measurement — a closed hour, a day before the store opened. Pass `0` only for a real zero. The two render differently (dashed outline vs filled) and read differently ('No data' vs '¥0').",
|
|
87
|
+
"DO use `topN` to call out the peak slots; the ring is a shape and the rank is text, so the emphasis survives greyscale and colour-vision deficiency.",
|
|
88
|
+
"DO retheme through the tokens: the ramp is the foundation `--chart-heat-1..5` (light + dark), geometry and cues are `--chart-heatmap-*`. NEVER tint cells from the app, add page CSS, or fake the matrix with a styled Table.",
|
|
89
|
+
"DON'T add a separate sr-only table: the matrix IS a native data table with `role=\"grid\"` and header cells, so the visible chart and its text alternative cannot drift apart.",
|
|
90
|
+
"DON'T use it for a continuous series over time (LineChart / AreaChart) or one row of values (CompactBarTrend)."
|
|
91
|
+
],
|
|
92
|
+
"useCases": [
|
|
93
|
+
"Restaurant / retail HQ: revenue or order count by weekday × hour across the chain (POS busy-hours).",
|
|
94
|
+
"Support desk: ticket volume by weekday × hour, to plan staffing.",
|
|
95
|
+
"Any categorical matrix where intensity matters more than the exact figure: store × week, region × product."
|
|
96
|
+
]
|
|
97
|
+
}
|
|
@@ -712,6 +712,11 @@
|
|
|
712
712
|
"name": "CompactBarTrend",
|
|
713
713
|
"tagline": "DEPENDENCY-FREE compact vertical bar trend for dashboard summary cards — N category/value pairs, muted marks plus ONE emphasized 'current' bar, all geometry from --chart-trend-* tokens. Needs NO recharts. Sparkline / micro-chart / activity pulse / KPI trend strip."
|
|
714
714
|
},
|
|
715
|
+
{
|
|
716
|
+
"group": "data-display",
|
|
717
|
+
"name": "HeatmapChart",
|
|
718
|
+
"tagline": "DEPENDENCY-FREE rows × columns heatmap — weekday × hour revenue / order counts, cell intensity from the sequential CVD-safe --chart-heat-1..5 ramp. Empty ≠ zero (dashed outline + 'no data' text), optional top-N ring, per-cell tooltip, APG grid keyboard, the table itself is the text alternative. Needs NO recharts. Matrix / punch card / activity heatmap / busy-hours chart."
|
|
719
|
+
},
|
|
715
720
|
{
|
|
716
721
|
"group": "data-display",
|
|
717
722
|
"name": "AreaChart",
|
package/agent/components.json
CHANGED
|
@@ -13247,6 +13247,103 @@
|
|
|
13247
13247
|
"A dependency-constrained app (no recharts) that still needs a token-driven chart."
|
|
13248
13248
|
]
|
|
13249
13249
|
},
|
|
13250
|
+
{
|
|
13251
|
+
"example": "import { HeatmapChart } from \"@godxjp/ui/charts/heatmap-chart\";\nimport { useTranslation } from \"@godxjp/ui/i18n\";\n\nconst { t, locale } = useTranslation();\nconst weekday = new Intl.DateTimeFormat(locale, { weekday: \"short\", timeZone: \"UTC\" });\nconst rows = [\"mon\", \"tue\", \"wed\", \"thu\", \"fri\", \"sat\", \"sun\"].map((key, day) => ({\n key,\n label: weekday.format(new Date(Date.UTC(2024, 0, 1 + day))), // 2024-01-01 is a Monday\n}));\nconst columns = Array.from({ length: 24 }, (_, hour) => ({ key: hour, label: new Intl.NumberFormat(locale).format(hour) }));\n\n<HeatmapChart\n label={t(\"dashboard.revenueByHour\")}\n rows={rows}\n columns={columns}\n data={slots /* [{ row: \"fri\", column: 19, value: 48000 }, …] — omit closed hours */}\n numberFormat={{ style: \"currency\", currency: \"JPY\" }}\n topN={3}\n/>",
|
|
13252
|
+
"group": "data-display",
|
|
13253
|
+
"importPath": "@godxjp/ui/charts/heatmap-chart",
|
|
13254
|
+
"name": "HeatmapChart",
|
|
13255
|
+
"props": [
|
|
13256
|
+
{
|
|
13257
|
+
"description": "Row categories, top to bottom (the y axis — weekdays). `label` is already translated.",
|
|
13258
|
+
"name": "rows",
|
|
13259
|
+
"required": true,
|
|
13260
|
+
"type": "{ key: string | number; label: string }[]"
|
|
13261
|
+
},
|
|
13262
|
+
{
|
|
13263
|
+
"description": "Column categories, start to end (the x axis — hours). `label` is already translated.",
|
|
13264
|
+
"name": "columns",
|
|
13265
|
+
"required": true,
|
|
13266
|
+
"type": "{ key: string | number; label: string }[]"
|
|
13267
|
+
},
|
|
13268
|
+
{
|
|
13269
|
+
"description": "Cell values keyed by row + column key. A cell that is absent, null, undefined or NaN is EMPTY ('no data') — never painted as a zero.",
|
|
13270
|
+
"name": "data",
|
|
13271
|
+
"required": true,
|
|
13272
|
+
"type": "{ row: string | number; column: string | number; value: number | null | undefined }[]"
|
|
13273
|
+
},
|
|
13274
|
+
{
|
|
13275
|
+
"description": "Accessible name of the figure and its grid + visible caption.",
|
|
13276
|
+
"name": "label",
|
|
13277
|
+
"required": true,
|
|
13278
|
+
"type": "string"
|
|
13279
|
+
},
|
|
13280
|
+
{
|
|
13281
|
+
"defaultValue": "true",
|
|
13282
|
+
"description": "Paint `label` as a visible caption. Set false under a CardTitle that already says it — the caption stays sr-only so the grid keeps its name.",
|
|
13283
|
+
"name": "showCaption",
|
|
13284
|
+
"type": "boolean"
|
|
13285
|
+
},
|
|
13286
|
+
{
|
|
13287
|
+
"description": "Extra context prepended to the screen-reader summary.",
|
|
13288
|
+
"name": "description",
|
|
13289
|
+
"type": "string"
|
|
13290
|
+
},
|
|
13291
|
+
{
|
|
13292
|
+
"defaultValue": "\"md\"",
|
|
13293
|
+
"description": "CELL size tier (--chart-heatmap-cell-size-*: 24/28/32/40px) — not a canvas height. A cell never shrinks below it; when the columns do not fit, the matrix scrolls inside its own box with the row header pinned.",
|
|
13294
|
+
"name": "size",
|
|
13295
|
+
"type": "\"xs\" | \"sm\" | \"md\" | \"lg\""
|
|
13296
|
+
},
|
|
13297
|
+
{
|
|
13298
|
+
"description": "Locale-aware formatting for cell values, the tooltip, the legend ranges and the summary (e.g. `{ style: 'currency', currency: 'JPY' }`).",
|
|
13299
|
+
"name": "numberFormat",
|
|
13300
|
+
"type": "Intl.NumberFormatOptions"
|
|
13301
|
+
},
|
|
13302
|
+
{
|
|
13303
|
+
"description": "Emphasize the N highest cells with an outline ring plus a 'Top k' note in the tooltip, the cell text and the legend — never colour alone. Ties keep `data` order.",
|
|
13304
|
+
"name": "topN",
|
|
13305
|
+
"type": "number"
|
|
13306
|
+
},
|
|
13307
|
+
{
|
|
13308
|
+
"defaultValue": "true",
|
|
13309
|
+
"description": "Colour-scale legend (min … max, one readable range per swatch) plus the 'no data' and 'top N' keys when they apply.",
|
|
13310
|
+
"name": "showLegend",
|
|
13311
|
+
"type": "boolean"
|
|
13312
|
+
},
|
|
13313
|
+
{
|
|
13314
|
+
"description": "Shown when there are no rows, no columns or no cells with a value.",
|
|
13315
|
+
"name": "emptyMessage",
|
|
13316
|
+
"type": "string"
|
|
13317
|
+
},
|
|
13318
|
+
{
|
|
13319
|
+
"description": "Forwarded to the <figure> element.",
|
|
13320
|
+
"name": "ref",
|
|
13321
|
+
"type": "React.Ref<HTMLElement>"
|
|
13322
|
+
}
|
|
13323
|
+
],
|
|
13324
|
+
"related": [
|
|
13325
|
+
"CompactBarTrend — one row of values; the other dependency-free chart.",
|
|
13326
|
+
"BarChart — exact comparison across a single category axis (recharts peer).",
|
|
13327
|
+
"DataTable — when the reader needs to sort, filter or read exact numbers first."
|
|
13328
|
+
],
|
|
13329
|
+
"rules": [],
|
|
13330
|
+
"storyPath": "charts/heatmap-chart.tsx",
|
|
13331
|
+
"tagline": "DEPENDENCY-FREE rows × columns heatmap — weekday × hour revenue / order counts, cell intensity from the sequential CVD-safe --chart-heat-1..5 ramp. Empty ≠ zero (dashed outline + 'no data' text), optional top-N ring, per-cell tooltip, APG grid keyboard, the table itself is the text alternative. Needs NO recharts. Matrix / punch card / activity heatmap / busy-hours chart.",
|
|
13332
|
+
"usage": [
|
|
13333
|
+
"DO import from the isolated entry: `import { HeatmapChart } from \"@godxjp/ui/charts/heatmap-chart\";` — it never links the optional `recharts` peer.",
|
|
13334
|
+
"DO derive axis labels with Intl in the active locale — weekdays via `Intl.DateTimeFormat(locale, { weekday: 'short' })`, hours via `Intl.NumberFormat(locale)` — and pass money through `numberFormat`, never a hand-built '¥' string.",
|
|
13335
|
+
"DO leave a slot OUT of `data` (or pass `value: null`) when there is no measurement — a closed hour, a day before the store opened. Pass `0` only for a real zero. The two render differently (dashed outline vs filled) and read differently ('No data' vs '¥0').",
|
|
13336
|
+
"DO use `topN` to call out the peak slots; the ring is a shape and the rank is text, so the emphasis survives greyscale and colour-vision deficiency.",
|
|
13337
|
+
"DO retheme through the tokens: the ramp is the foundation `--chart-heat-1..5` (light + dark), geometry and cues are `--chart-heatmap-*`. NEVER tint cells from the app, add page CSS, or fake the matrix with a styled Table.",
|
|
13338
|
+
"DON'T add a separate sr-only table: the matrix IS a native data table with `role=\"grid\"` and header cells, so the visible chart and its text alternative cannot drift apart.",
|
|
13339
|
+
"DON'T use it for a continuous series over time (LineChart / AreaChart) or one row of values (CompactBarTrend)."
|
|
13340
|
+
],
|
|
13341
|
+
"useCases": [
|
|
13342
|
+
"Restaurant / retail HQ: revenue or order count by weekday × hour across the chain (POS busy-hours).",
|
|
13343
|
+
"Support desk: ticket volume by weekday × hour, to plan staffing.",
|
|
13344
|
+
"Any categorical matrix where intensity matters more than the exact figure: store × week, region × product."
|
|
13345
|
+
]
|
|
13346
|
+
},
|
|
13250
13347
|
{
|
|
13251
13348
|
"example": "import { AreaChart } from \"@godxjp/ui/charts\";\n\n<AreaChart\n label={t(\"dashboard.trafficByChannel\")}\n data={data}\n categoryKey=\"day\"\n series={[\n { dataKey: \"organic\", label: t(\"channel.organic\") },\n { dataKey: \"paid\", label: t(\"channel.paid\") },\n ]}\n stacked\n/>",
|
|
13252
13349
|
"group": "data-display",
|
package/agent/index.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"counts": {
|
|
3
3
|
"anti-ai-tells": 35,
|
|
4
|
-
"components":
|
|
4
|
+
"components": 163,
|
|
5
5
|
"patterns": 24,
|
|
6
6
|
"rules": 43,
|
|
7
|
-
"tokens":
|
|
7
|
+
"tokens": 2229,
|
|
8
8
|
"vocabulary": 14
|
|
9
9
|
},
|
|
10
10
|
"design": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/DESIGN.md",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
},
|
|
17
17
|
{
|
|
18
18
|
"file": "components-index.json",
|
|
19
|
-
"note": "48 KB — name + group + tagline for all
|
|
19
|
+
"note": "48 KB — name + group + tagline for all 163. FETCH THIS FIRST, then fetch only the components you chose.",
|
|
20
20
|
"url": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components-index.json"
|
|
21
21
|
},
|
|
22
22
|
{
|
|
@@ -54,19 +54,19 @@
|
|
|
54
54
|
"note": "Pin to the tag that matches the @godxjp/ui version you installed. A catalog newer than your package describes props you do not have; older, and it hides props you do.",
|
|
55
55
|
"read": {
|
|
56
56
|
"live": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/index.json",
|
|
57
|
-
"pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v32.
|
|
57
|
+
"pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v32.15.0/agent/index.json"
|
|
58
58
|
},
|
|
59
59
|
"source": "mcp/src/data — the same data @godxjp/ui-mcp serves — plus the foundation and semantic token tiers, read from src/tokens/*.css",
|
|
60
60
|
"start": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/START-HERE.md",
|
|
61
61
|
"tokenTiers": {
|
|
62
62
|
"component": "per-part knobs, --{component}-{part}-{property}; usually leave these alone",
|
|
63
63
|
"counts": {
|
|
64
|
-
"component":
|
|
65
|
-
"foundation":
|
|
64
|
+
"component": 1900,
|
|
65
|
+
"foundation": 216,
|
|
66
66
|
"semantic": 113
|
|
67
67
|
},
|
|
68
68
|
"foundation": "the seeds a consumer is invited to set — --primary, --background, --radius",
|
|
69
69
|
"semantic": "named roles that follow the seeds — --ring, --text-link, --overlay-background"
|
|
70
70
|
},
|
|
71
|
-
"version": "32.
|
|
71
|
+
"version": "32.15.0"
|
|
72
72
|
}
|
package/agent/llms.txt
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# @godxjp/ui
|
|
2
2
|
|
|
3
|
-
> A Japanese-enterprise React design system:
|
|
4
|
-
> 43 cardinal rules. This file is the entry point for AI agents. Catalog version 32.
|
|
3
|
+
> A Japanese-enterprise React design system: 163 components, 2229 design tokens,
|
|
4
|
+
> 43 cardinal rules. This file is the entry point for AI agents. Catalog version 32.15.0.
|
|
5
5
|
|
|
6
6
|
If your client can run a process, do not read these files — run the MCP server instead
|
|
7
|
-
(`npx @godxjp/ui-mcp@32.
|
|
7
|
+
(`npx @godxjp/ui-mcp@32.15.0`). It is searchable and version-locked. These files exist for agents
|
|
8
8
|
that can only fetch URLs.
|
|
9
9
|
|
|
10
10
|
## Start
|
|
@@ -16,10 +16,10 @@ that can only fetch URLs.
|
|
|
16
16
|
## Catalog
|
|
17
17
|
|
|
18
18
|
- [patterns-index.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/patterns-index.json): 24 whole-task patterns (name, tagline, tags). Start here when the task is a TASK — "build a settings page" — then fetch `patterns/<name>.json` for complete code.
|
|
19
|
-
- [components-index.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components-index.json): 48 KB — all
|
|
19
|
+
- [components-index.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components-index.json): 48 KB — all 163 components as name, group, tagline, plus `absorbed`: the names that do NOT exist and map to it (`Combobox` → `Select`).
|
|
20
20
|
- [components/<Name>.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components/Select.json): one file per component (1 KB–37 KB, median 6 KB). Read the index, then fetch only the ones you chose — this is the selective route, and the reason you do not need the blob.
|
|
21
21
|
- [components.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components.json): 1.2 MB — every entry in one file. Most URL fetchers truncate a response this size without saying so; prefer the per-component files.
|
|
22
|
-
- [tokens.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/tokens.json): every design token with its value, the reason it exists, and its `tier` —
|
|
22
|
+
- [tokens.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/tokens.json): every design token with its value, the reason it exists, and its `tier` — 216 `foundation` seeds (`--primary`, `--background`, `--radius`: set these when you are handed a brand), 113 `semantic` roles, 1900 `component` knobs.
|
|
23
23
|
- [vocabulary.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/vocabulary.json): the controlled prop vocabulary — which prop name means what, across every component.
|
|
24
24
|
- [rules.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/rules.json): 43 cardinal rules.
|
|
25
25
|
- [anti-ai-tells.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/anti-ai-tells.json): 35 shapes that make generated UI look generated, each with its fix.
|
|
@@ -27,7 +27,7 @@ that can only fetch URLs.
|
|
|
27
27
|
## Pinning
|
|
28
28
|
|
|
29
29
|
Every URL above tracks `main`. To pin to the release a project actually installed, swap `main` for
|
|
30
|
-
the tag: `.../godx-jp/godxjp-ui/v32.
|
|
30
|
+
the tag: `.../godx-jp/godxjp-ui/v32.15.0/agent/...`. A catalog that does not match the installed
|
|
31
31
|
package describes props that are absent, or hides props that are present, and says nothing either way.
|
|
32
32
|
|
|
33
33
|
Pinned catalogs only exist for releases whose tag actually contains `agent/`. If `…/v<version>/agent/index.json` returns 404, that release predates this catalog: read `…/main/…` instead and compare `index.json` → `version` against the package you have, so you at least know which way it drifted.
|
package/agent/tokens.json
CHANGED
|
@@ -443,6 +443,36 @@
|
|
|
443
443
|
"tier": "foundation",
|
|
444
444
|
"value": "#eb6101"
|
|
445
445
|
},
|
|
446
|
+
{
|
|
447
|
+
"description": "Sequential heat ramp — HeatmapChart (gh#1330). ONE hue (the --chart-1 blue, 204°) stepped by lightness alone, so the order of the steps survives every colour-vision deficiency: CVD shifts hue, and a single-hue ramp carries its meaning in luminance, which protan/deutan/tritan vision all keep. Relative luminance falls monotonically 0.805 → 0.541 → 0.330 → 0.173 → 0.064; against the light --card that is 1.21 / 1.74 / 2.72 / 4.62 / 9.03:1, each step ≥1.45:1 from the last. Step 1 is deliberately quiet (it is \"low\", not \"absent\"): an EMPTY cell is told apart by its dashed outline and its text, never by this fill. A service retunes the whole ramp here.",
|
|
448
|
+
"name": "--chart-heat-1",
|
|
449
|
+
"tier": "foundation",
|
|
450
|
+
"value": "#d6ebf8"
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
"description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
|
|
454
|
+
"name": "--chart-heat-2",
|
|
455
|
+
"tier": "foundation",
|
|
456
|
+
"value": "#94c9ec"
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
"description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
|
|
460
|
+
"name": "--chart-heat-3",
|
|
461
|
+
"tier": "foundation",
|
|
462
|
+
"value": "#4ea3dc"
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
"description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
|
|
466
|
+
"name": "--chart-heat-4",
|
|
467
|
+
"tier": "foundation",
|
|
468
|
+
"value": "#0077c7"
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
"description": "Foundation tokens: color, typography, raw spacing, ratio, radius, shadow.",
|
|
472
|
+
"name": "--chart-heat-5",
|
|
473
|
+
"tier": "foundation",
|
|
474
|
+
"value": "#004a7f"
|
|
475
|
+
},
|
|
446
476
|
{
|
|
447
477
|
"description": "Disabled affordance opacity — single knob (was referenced but undefined → silent failure).",
|
|
448
478
|
"name": "--disabled-opacity",
|
|
@@ -2855,6 +2885,90 @@
|
|
|
2855
2885
|
"tier": "component",
|
|
2856
2886
|
"value": "3 3"
|
|
2857
2887
|
},
|
|
2888
|
+
{
|
|
2889
|
+
"description": "Minimum cell edge per tier. `xs` is still 24px — a cell is a hover/focus target (WCAG 2.5.8).",
|
|
2890
|
+
"name": "--chart-heatmap-cell-size-xs",
|
|
2891
|
+
"tier": "component",
|
|
2892
|
+
"value": "1.5rem"
|
|
2893
|
+
},
|
|
2894
|
+
{
|
|
2895
|
+
"description": "Chart component tokens — the dependency-free `CompactBarTrend` primitive (`@godxjp/ui/charts`). Every piece of its geometry and every fill is a public knob so a service theme can match its own design grid WITHOUT page-local CSS or inline heights (cardinal rules #44/#45). The recharts-backed charts draw their own SVG from the foundation `--chart-1..6` palette, plus the cartesian series knobs at the bottom of this file.",
|
|
2896
|
+
"name": "--chart-heatmap-cell-size-sm",
|
|
2897
|
+
"tier": "component",
|
|
2898
|
+
"value": "1.75rem"
|
|
2899
|
+
},
|
|
2900
|
+
{
|
|
2901
|
+
"description": "Chart component tokens — the dependency-free `CompactBarTrend` primitive (`@godxjp/ui/charts`). Every piece of its geometry and every fill is a public knob so a service theme can match its own design grid WITHOUT page-local CSS or inline heights (cardinal rules #44/#45). The recharts-backed charts draw their own SVG from the foundation `--chart-1..6` palette, plus the cartesian series knobs at the bottom of this file.",
|
|
2902
|
+
"name": "--chart-heatmap-cell-size-md",
|
|
2903
|
+
"tier": "component",
|
|
2904
|
+
"value": "2rem"
|
|
2905
|
+
},
|
|
2906
|
+
{
|
|
2907
|
+
"description": "Chart component tokens — the dependency-free `CompactBarTrend` primitive (`@godxjp/ui/charts`). Every piece of its geometry and every fill is a public knob so a service theme can match its own design grid WITHOUT page-local CSS or inline heights (cardinal rules #44/#45). The recharts-backed charts draw their own SVG from the foundation `--chart-1..6` palette, plus the cartesian series knobs at the bottom of this file.",
|
|
2908
|
+
"name": "--chart-heatmap-cell-size-lg",
|
|
2909
|
+
"tier": "component",
|
|
2910
|
+
"value": "2.5rem"
|
|
2911
|
+
},
|
|
2912
|
+
{
|
|
2913
|
+
"description": "Active tier — chart-layout.css re-points this per `data-size`.",
|
|
2914
|
+
"name": "--chart-heatmap-cell-size",
|
|
2915
|
+
"tier": "component",
|
|
2916
|
+
"value": "var(--chart-heatmap-cell-size-md)"
|
|
2917
|
+
},
|
|
2918
|
+
{
|
|
2919
|
+
"description": "Surface gap between neighbouring cells (the table's border-spacing).",
|
|
2920
|
+
"name": "--chart-heatmap-cell-gap",
|
|
2921
|
+
"tier": "component",
|
|
2922
|
+
"value": "var(--stroke-md)"
|
|
2923
|
+
},
|
|
2924
|
+
{
|
|
2925
|
+
"description": "default = calc(var(--radius) / var(--radius-ratio) / var(--radius-ratio)), resolved at the call site",
|
|
2926
|
+
"name": "--chart-heatmap-cell-radius",
|
|
2927
|
+
"tier": "component",
|
|
2928
|
+
"value": "initial"
|
|
2929
|
+
},
|
|
2930
|
+
{
|
|
2931
|
+
"description": "EMPTY cell outline — the non-colour cue that tells \"no data\" from a zero (WCAG 1.4.1). Role-mirror knob, `initial` at :root; default at the call site = `var(--stroke-hairline) dashed hsl(var(--muted-foreground))`.",
|
|
2932
|
+
"name": "--chart-heatmap-empty-border",
|
|
2933
|
+
"tier": "component",
|
|
2934
|
+
"value": "initial"
|
|
2935
|
+
},
|
|
2936
|
+
{
|
|
2937
|
+
"description": "Top-N emphasis ring — a SHAPE cue, never colour alone. Colour is a role-mirror knob (default `hsl(var(--foreground))` at the call site); width is a plain constant.",
|
|
2938
|
+
"name": "--chart-heatmap-emphasis-border",
|
|
2939
|
+
"tier": "component",
|
|
2940
|
+
"value": "initial"
|
|
2941
|
+
},
|
|
2942
|
+
{
|
|
2943
|
+
"description": "Chart component tokens — the dependency-free `CompactBarTrend` primitive (`@godxjp/ui/charts`). Every piece of its geometry and every fill is a public knob so a service theme can match its own design grid WITHOUT page-local CSS or inline heights (cardinal rules #44/#45). The recharts-backed charts draw their own SVG from the foundation `--chart-1..6` palette, plus the cartesian series knobs at the bottom of this file.",
|
|
2944
|
+
"name": "--chart-heatmap-emphasis-width",
|
|
2945
|
+
"tier": "component",
|
|
2946
|
+
"value": "var(--stroke-md)"
|
|
2947
|
+
},
|
|
2948
|
+
{
|
|
2949
|
+
"description": "The pinned row-header column paints over cells scrolled beneath it, so it needs a ground. Role-mirror knob; default = `hsl(var(--card))` at the call site.",
|
|
2950
|
+
"name": "--chart-heatmap-row-header-background",
|
|
2951
|
+
"tier": "component",
|
|
2952
|
+
"value": "initial"
|
|
2953
|
+
},
|
|
2954
|
+
{
|
|
2955
|
+
"description": "Chart component tokens — the dependency-free `CompactBarTrend` primitive (`@godxjp/ui/charts`). Every piece of its geometry and every fill is a public knob so a service theme can match its own design grid WITHOUT page-local CSS or inline heights (cardinal rules #44/#45). The recharts-backed charts draw their own SVG from the foundation `--chart-1..6` palette, plus the cartesian series knobs at the bottom of this file.",
|
|
2956
|
+
"name": "--chart-heatmap-tick-font-size",
|
|
2957
|
+
"tier": "component",
|
|
2958
|
+
"value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
|
|
2959
|
+
},
|
|
2960
|
+
{
|
|
2961
|
+
"description": "Legend rhythm: the swatch edge and the gap between legend items / plot ↔ legend.",
|
|
2962
|
+
"name": "--chart-heatmap-legend-swatch-size",
|
|
2963
|
+
"tier": "component",
|
|
2964
|
+
"value": "var(--space-3)"
|
|
2965
|
+
},
|
|
2966
|
+
{
|
|
2967
|
+
"description": "Chart component tokens — the dependency-free `CompactBarTrend` primitive (`@godxjp/ui/charts`). Every piece of its geometry and every fill is a public knob so a service theme can match its own design grid WITHOUT page-local CSS or inline heights (cardinal rules #44/#45). The recharts-backed charts draw their own SVG from the foundation `--chart-1..6` palette, plus the cartesian series knobs at the bottom of this file.",
|
|
2968
|
+
"name": "--chart-heatmap-legend-gap",
|
|
2969
|
+
"tier": "component",
|
|
2970
|
+
"value": "var(--space-2)"
|
|
2971
|
+
},
|
|
2858
2972
|
{
|
|
2859
2973
|
"description": "Bubble fill. `initial` so the --muted default re-resolves at the CALL SITE under a scoped theme; a :root binding to a role var freezes at :root (docs/TOKENS.md — the :root freeze rule). Documented default = hsl(var(--muted)).",
|
|
2860
2974
|
"name": "--chat-bubble-background",
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* alternative (WCAG 1.1.1). No JSX — filename pascal is intentionally NOT
|
|
4
4
|
* exported, so this is not a catalog primitive.
|
|
5
5
|
*/
|
|
6
|
-
import type { ChartDatum, ChartSeriesProp } from "../../props/components/charts.prop.js";
|
|
6
|
+
import type { ChartDatum, ChartSeriesProp, HeatmapCategory, HeatmapDatum } from "../../props/components/charts.prop.js";
|
|
7
7
|
type Formatter = Intl.NumberFormat;
|
|
8
8
|
export type ChartSummary = {
|
|
9
9
|
rows: string[];
|
|
@@ -39,4 +39,35 @@ export declare function trendRatios(data: ChartDatum[], valueKey: string): numbe
|
|
|
39
39
|
* datum).
|
|
40
40
|
*/
|
|
41
41
|
export declare function resolveEmphasizedIndex(index: number | undefined, length: number): number;
|
|
42
|
+
/** Number of steps in the `--chart-heat-1..N` ramp. */
|
|
43
|
+
export declare const HEAT_STEPS = 5;
|
|
44
|
+
/** The lookup key of one heatmap cell. */
|
|
45
|
+
export declare function heatmapCellKey(row: string | number, column: string | number): string;
|
|
46
|
+
export type HeatmapModel = {
|
|
47
|
+
/** Finite values by cell key. A key that is absent is an EMPTY cell, never a zero. */
|
|
48
|
+
values: Map<string, number>;
|
|
49
|
+
/** Ramp step 1..HEAT_STEPS by cell key. */
|
|
50
|
+
steps: Map<string, number>;
|
|
51
|
+
/** 1-based rank of the top-N cells by cell key. */
|
|
52
|
+
ranks: Map<string, number>;
|
|
53
|
+
/** Scale domain: `min(0, smallest)` .. largest. */
|
|
54
|
+
min: number;
|
|
55
|
+
max: number;
|
|
56
|
+
/** Count of cells with a value inside the rows × columns matrix. */
|
|
57
|
+
present: number;
|
|
58
|
+
/** Count of matrix cells with no value. */
|
|
59
|
+
empty: number;
|
|
60
|
+
/** The highest cell, for the one-line summary. */
|
|
61
|
+
highest: {
|
|
62
|
+
row: HeatmapCategory;
|
|
63
|
+
column: HeatmapCategory;
|
|
64
|
+
value: number;
|
|
65
|
+
} | null;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Bin a heatmap's cells onto the sequential ramp. The domain starts at zero (or the smallest value,
|
|
69
|
+
* when that is negative) so the fill encodes MAGNITUDE — a heatmap of 900..1000 whose 900 painted
|
|
70
|
+
* as "empty-light" would read as a quiet hour. Cells outside `rows` × `columns` are ignored.
|
|
71
|
+
*/
|
|
72
|
+
export declare function buildHeatmapModel(rows: HeatmapCategory[], columns: HeatmapCategory[], data: HeatmapDatum[], topN?: number): HeatmapModel;
|
|
42
73
|
export {};
|
|
@@ -40,11 +40,60 @@ function resolveEmphasizedIndex(index, length) {
|
|
|
40
40
|
const resolved = index < 0 ? length + index : index;
|
|
41
41
|
return resolved >= 0 && resolved < length ? resolved : -1;
|
|
42
42
|
}
|
|
43
|
+
const HEAT_STEPS = 5;
|
|
44
|
+
function heatmapCellKey(row, column) {
|
|
45
|
+
return `${String(row)}\0${String(column)}`;
|
|
46
|
+
}
|
|
47
|
+
function buildHeatmapModel(rows, columns, data, topN) {
|
|
48
|
+
const rowByKey = new Map(rows.map((row) => [String(row.key), row]));
|
|
49
|
+
const columnByKey = new Map(columns.map((column) => [String(column.key), column]));
|
|
50
|
+
const values = /* @__PURE__ */ new Map();
|
|
51
|
+
const order = [];
|
|
52
|
+
for (const datum of data) {
|
|
53
|
+
const row = rowByKey.get(String(datum.row));
|
|
54
|
+
const column = columnByKey.get(String(datum.column));
|
|
55
|
+
if (!row || !column) continue;
|
|
56
|
+
if (typeof datum.value !== "number" || !Number.isFinite(datum.value)) continue;
|
|
57
|
+
const key = heatmapCellKey(row.key, column.key);
|
|
58
|
+
if (values.has(key)) continue;
|
|
59
|
+
values.set(key, datum.value);
|
|
60
|
+
order.push({ key, value: datum.value, row, column });
|
|
61
|
+
}
|
|
62
|
+
let min = 0;
|
|
63
|
+
let max = 0;
|
|
64
|
+
for (const { value } of order) {
|
|
65
|
+
if (value < min) min = value;
|
|
66
|
+
if (value > max) max = value;
|
|
67
|
+
}
|
|
68
|
+
const steps = /* @__PURE__ */ new Map();
|
|
69
|
+
for (const { key, value } of order) {
|
|
70
|
+
const ratio = max > min ? (value - min) / (max - min) : max > 0 ? 1 : 0;
|
|
71
|
+
steps.set(key, Math.min(HEAT_STEPS, Math.floor(ratio * HEAT_STEPS) + 1));
|
|
72
|
+
}
|
|
73
|
+
const ranked = [...order].sort((a, b) => b.value - a.value);
|
|
74
|
+
const ranks = /* @__PURE__ */ new Map();
|
|
75
|
+
const n = topN !== void 0 && Number.isInteger(topN) && topN > 0 ? topN : 0;
|
|
76
|
+
ranked.slice(0, n).forEach((cell, index) => ranks.set(cell.key, index + 1));
|
|
77
|
+
const top = ranked[0];
|
|
78
|
+
return {
|
|
79
|
+
values,
|
|
80
|
+
steps,
|
|
81
|
+
ranks,
|
|
82
|
+
min,
|
|
83
|
+
max,
|
|
84
|
+
present: order.length,
|
|
85
|
+
empty: rows.length * columns.length - order.length,
|
|
86
|
+
highest: top ? { row: top.row, column: top.column, value: top.value } : null
|
|
87
|
+
};
|
|
88
|
+
}
|
|
43
89
|
export {
|
|
90
|
+
HEAT_STEPS,
|
|
44
91
|
buildCartesianSummary,
|
|
92
|
+
buildHeatmapModel,
|
|
45
93
|
buildPieSummary,
|
|
46
94
|
buildSeriesRows,
|
|
47
95
|
buildTrendSummary,
|
|
96
|
+
heatmapCellKey,
|
|
48
97
|
resolveEmphasizedIndex,
|
|
49
98
|
trendRatios
|
|
50
99
|
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { HeatmapChartProp } from "../../props/components/charts.prop.js";
|
|
3
|
+
export type { HeatmapChartProp, HeatmapChartProp as HeatmapChartProps, HeatmapCategory, HeatmapDatum, } from "../../props/components/charts.prop.js";
|
|
4
|
+
/**
|
|
5
|
+
* HeatmapChart — a **dependency-free** rows × columns matrix (weekday × hour revenue, order counts
|
|
6
|
+
* per slot). Cell fill steps through the sequential `--chart-heat-1..5` ramp.
|
|
7
|
+
*
|
|
8
|
+
* - **One structure for sight and for AT.** The matrix IS a native data table (`<th scope>` headers,
|
|
9
|
+
* one cell per slot) with `role="grid"`, so the screen-reader text alternative is the same element
|
|
10
|
+
* the eye reads — no second, drifting copy. Each cell carries its formatted value as text.
|
|
11
|
+
* - **Keyboard** — WAI-ARIA APG data grid: one tab stop (roving tabindex), arrows move between
|
|
12
|
+
* cells (mirrored under RTL), Home/End go to the row's ends, Ctrl+Home/End to the first/last
|
|
13
|
+
* cell. A focused or hovered cell shows ONE shared tooltip; Escape dismisses it.
|
|
14
|
+
* - **Never colour alone** — an empty cell is outlined (dashed) and reads "no data"; a zero is a
|
|
15
|
+
* filled step-1 cell that reads "0"; a top-N cell wears a ring and reads "top N".
|
|
16
|
+
* - **Narrow screens** — the matrix never shrinks a cell below its `size` tier; it scrolls inside
|
|
17
|
+
* its own box with the row header pinned, so the page never scrolls sideways.
|
|
18
|
+
*/
|
|
19
|
+
export declare function HeatmapChart({ rows, columns, data, label, showCaption, description, size, numberFormat, topN, showLegend, emptyMessage, className, id, ref, }: HeatmapChartProp): React.JSX.Element;
|