@godxjp/ui 19.6.0 → 20.1.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 +8 -2
- package/dist/app/theme-axes.d.ts +2 -0
- package/dist/app/theme-axes.js +45 -0
- package/dist/components/charts/chart-cartesian.d.ts +2 -1
- package/dist/components/charts/chart-cartesian.js +52 -3
- package/dist/components/charts/chart-category-axis.d.ts +55 -0
- package/dist/components/charts/chart-category-axis.js +93 -0
- package/dist/components/charts/chart-frame.d.ts +10 -1
- package/dist/components/charts/chart-frame.js +19 -3
- package/dist/components/charts/compact-bar-trend.d.ts +1 -1
- package/dist/components/charts/compact-bar-trend.js +2 -0
- package/dist/components/charts/pie-chart.d.ts +1 -1
- package/dist/components/charts/pie-chart.js +12 -1
- package/dist/components/charts/recharts-peer.d.ts +49 -0
- package/dist/components/charts/recharts-peer.js +45 -0
- package/dist/components/data-display/card.d.ts +14 -3
- package/dist/components/data-display/card.js +22 -4
- package/dist/components/data-display/code-block.js +6 -2
- package/dist/components/data-display/collapsible.d.ts +23 -4
- package/dist/components/data-display/collapsible.js +119 -4
- package/dist/components/data-display/data-table.d.ts +39 -4
- package/dist/components/data-display/data-table.js +802 -270
- package/dist/components/data-display/descriptions.d.ts +27 -6
- package/dist/components/data-display/descriptions.js +58 -17
- package/dist/components/data-display/index.d.ts +5 -1
- package/dist/components/data-display/index.js +4 -0
- package/dist/components/data-display/legend.d.ts +15 -0
- package/dist/components/data-display/legend.js +11 -0
- package/dist/components/data-display/list-row.d.ts +10 -1
- package/dist/components/data-display/list-row.js +8 -2
- package/dist/components/data-display/popover.d.ts +60 -7
- package/dist/components/data-display/popover.js +268 -39
- package/dist/components/data-display/progress.d.ts +50 -2
- package/dist/components/data-display/progress.js +57 -9
- package/dist/components/data-display/range-timeline.d.ts +38 -0
- package/dist/components/data-display/range-timeline.js +161 -0
- package/dist/components/data-display/scroll-area.js +13 -2
- package/dist/components/data-display/service-launcher-card.js +10 -10
- package/dist/components/data-display/table.d.ts +11 -3
- package/dist/components/data-display/table.js +48 -18
- package/dist/components/data-display/tree-list.js +4 -9
- package/dist/components/data-entry/calendar.d.ts +2 -2
- package/dist/components/data-entry/calendar.js +79 -33
- package/dist/components/data-entry/cascader.d.ts +1 -1
- package/dist/components/data-entry/cascader.js +188 -24
- package/dist/components/data-entry/checkbox.d.ts +19 -6
- package/dist/components/data-entry/checkbox.js +55 -16
- package/dist/components/data-entry/choice-option.d.ts +1 -1
- package/dist/components/data-entry/color-picker.d.ts +1 -1
- package/dist/components/data-entry/color-picker.js +17 -5
- package/dist/components/data-entry/control-appearance.d.ts +64 -0
- package/dist/components/data-entry/control-appearance.js +39 -0
- package/dist/components/data-entry/control-surface.d.ts +61 -0
- package/dist/components/data-entry/control-surface.js +39 -0
- package/dist/components/data-entry/date-picker.d.ts +1 -1
- package/dist/components/data-entry/date-picker.js +344 -113
- package/dist/components/data-entry/date-range-picker.d.ts +2 -2
- package/dist/components/data-entry/date-range-picker.js +278 -140
- package/dist/components/data-entry/field.js +0 -1
- package/dist/components/data-entry/form-field.d.ts +1 -1
- package/dist/components/data-entry/form-field.js +39 -4
- package/dist/components/data-entry/form.d.ts +4 -0
- package/dist/components/data-entry/form.js +5 -3
- package/dist/components/data-entry/index.d.ts +7 -3
- package/dist/components/data-entry/index.js +10 -1
- package/dist/components/data-entry/input-otp.d.ts +1 -1
- package/dist/components/data-entry/input.d.ts +12 -34
- package/dist/components/data-entry/input.js +92 -24
- package/dist/components/data-entry/label.d.ts +3 -2
- package/dist/components/data-entry/label.js +23 -10
- package/dist/components/data-entry/month-picker.d.ts +2 -2
- package/dist/components/data-entry/month-picker.js +47 -10
- package/dist/components/data-entry/month-range-picker.d.ts +2 -2
- package/dist/components/data-entry/month-range-picker.js +51 -11
- package/dist/components/data-entry/number-input.d.ts +7 -0
- package/dist/components/data-entry/number-input.js +147 -98
- package/dist/components/data-entry/password-input.d.ts +1 -1
- package/dist/components/data-entry/radio.d.ts +1 -1
- package/dist/components/data-entry/radio.js +61 -13
- package/dist/components/data-entry/search-input.d.ts +1 -1
- package/dist/components/data-entry/search-input.js +16 -2
- package/dist/components/data-entry/search-select.d.ts +2 -2
- package/dist/components/data-entry/search-select.js +209 -78
- package/dist/components/data-entry/select.d.ts +22 -4
- package/dist/components/data-entry/select.js +215 -163
- package/dist/components/data-entry/slider.d.ts +9 -1
- package/dist/components/data-entry/slider.js +87 -9
- package/dist/components/data-entry/switch.d.ts +3 -0
- package/dist/components/data-entry/switch.js +29 -3
- package/dist/components/data-entry/textarea.d.ts +14 -56
- package/dist/components/data-entry/textarea.js +80 -33
- package/dist/components/data-entry/time-picker.d.ts +2 -2
- package/dist/components/data-entry/time-picker.js +333 -109
- package/dist/components/data-entry/time-range-picker.d.ts +5 -0
- package/dist/components/data-entry/time-range-picker.js +89 -0
- package/dist/components/data-entry/transfer.d.ts +1 -1
- package/dist/components/data-entry/transfer.js +99 -31
- package/dist/components/data-entry/tree-select-strategy.d.ts +1 -1
- package/dist/components/data-entry/tree-select.d.ts +1 -1
- package/dist/components/data-entry/tree-select.js +197 -92
- package/dist/components/data-entry/tree-utils.d.ts +1 -1
- package/dist/components/data-entry/tree-utils.js +7 -14
- package/dist/components/data-entry/upload-files.d.ts +2 -0
- package/dist/components/data-entry/upload-files.js +31 -0
- package/dist/components/data-entry/upload-request.d.ts +4 -0
- package/dist/components/data-entry/upload-request.js +53 -0
- package/dist/components/data-entry/upload-types.d.ts +28 -0
- package/dist/components/data-entry/upload-types.js +2 -0
- package/dist/components/data-entry/upload.d.ts +2 -2
- package/dist/components/data-entry/upload.js +482 -117
- package/dist/components/feedback/dialog.d.ts +105 -38
- package/dist/components/feedback/dialog.js +268 -193
- package/dist/components/feedback/overlay-close-focus.d.ts +31 -0
- package/dist/components/feedback/overlay-close-focus.js +31 -0
- package/dist/components/feedback/overlay-header-tone.d.ts +1 -1
- package/dist/components/feedback/sheet.d.ts +53 -11
- package/dist/components/feedback/sheet.js +150 -81
- package/dist/components/feedback/tooltip.d.ts +51 -7
- package/dist/components/feedback/tooltip.js +107 -25
- package/dist/components/general/button.d.ts +1 -1
- package/dist/components/general/button.js +7 -3
- package/dist/components/general/index.d.ts +1 -0
- package/dist/components/general/index.js +2 -0
- package/dist/components/general/logo.d.ts +17 -0
- package/dist/components/general/logo.js +22 -16
- package/dist/components/general/typography.d.ts +3 -0
- package/dist/components/general/typography.js +15 -1
- package/dist/components/general/visually-hidden.d.ts +3 -0
- package/dist/components/general/visually-hidden.js +9 -0
- package/dist/components/layout/app-launcher.d.ts +34 -0
- package/dist/components/layout/app-launcher.js +228 -0
- package/dist/components/layout/app-shell.d.ts +3 -1
- package/dist/components/layout/app-shell.js +69 -12
- package/dist/components/layout/aspect-ratio.js +0 -1
- package/dist/components/layout/auth-divider.js +0 -1
- package/dist/components/layout/breadcrumb.d.ts +14 -2
- package/dist/components/layout/breadcrumb.js +46 -4
- package/dist/components/layout/flex.d.ts +1 -1
- package/dist/components/layout/flex.js +41 -3
- package/dist/components/layout/index.d.ts +3 -0
- package/dist/components/layout/index.js +5 -1
- package/dist/components/layout/nav-surface.d.ts +26 -0
- package/dist/components/layout/nav-surface.js +17 -0
- package/dist/components/layout/org-switcher.d.ts +5 -1
- package/dist/components/layout/org-switcher.js +25 -4
- package/dist/components/layout/page-container.d.ts +1 -1
- package/dist/components/layout/page-container.js +5 -3
- package/dist/components/layout/responsive-grid.d.ts +16 -2
- package/dist/components/layout/responsive-grid.js +29 -2
- package/dist/components/layout/separator.js +0 -1
- package/dist/components/layout/sidebar.js +4 -1
- package/dist/components/layout/split-pane.d.ts +14 -1
- package/dist/components/layout/split-pane.js +26 -13
- package/dist/components/layout/topbar-item.d.ts +3 -0
- package/dist/components/layout/topbar-item.js +19 -5
- package/dist/components/layout/topbar.d.ts +1 -1
- package/dist/components/layout/topbar.js +27 -6
- package/dist/components/navigation/app-setting-picker.js +21 -2
- package/dist/components/navigation/app-setting-toggle.d.ts +16 -0
- package/dist/components/navigation/app-setting-toggle.js +96 -0
- package/dist/components/navigation/dropdown-menu.d.ts +227 -18
- package/dist/components/navigation/dropdown-menu.js +402 -118
- package/dist/components/navigation/index.d.ts +2 -0
- package/dist/components/navigation/index.js +2 -0
- package/dist/components/navigation/pagination-utils.d.ts +2 -1
- package/dist/components/navigation/pagination.d.ts +2 -2
- package/dist/components/navigation/pagination.js +155 -83
- package/dist/components/navigation/steps.d.ts +2 -2
- package/dist/components/navigation/steps.js +29 -4
- package/dist/components/navigation/tabs.d.ts +29 -16
- package/dist/components/navigation/tabs.js +374 -144
- package/dist/components/ui/accordion.d.ts +50 -5
- package/dist/components/ui/accordion.js +239 -33
- package/dist/components/ui/aspect-ratio.d.ts +23 -2
- package/dist/components/ui/aspect-ratio.js +15 -13
- package/dist/components/ui/avatar.d.ts +29 -4
- package/dist/components/ui/avatar.js +111 -25
- package/dist/components/ui/hover-card.d.ts +42 -4
- package/dist/components/ui/hover-card.js +183 -27
- package/dist/components/ui/input-otp.d.ts +26 -28
- package/dist/components/ui/input-otp.js +50 -7
- package/dist/components/ui/label.js +0 -1
- package/dist/components/ui/password-input.d.ts +36 -2
- package/dist/components/ui/password-input.js +27 -7
- package/dist/components/ui/rating.d.ts +25 -0
- package/dist/components/ui/rating.js +67 -27
- package/dist/components/ui/segmented.d.ts +12 -3
- package/dist/components/ui/segmented.js +17 -2
- package/dist/components/ui/separator.d.ts +12 -2
- package/dist/components/ui/separator.js +30 -9
- package/dist/components/ui/tag-input.d.ts +45 -0
- package/dist/components/ui/tag-input.js +109 -27
- package/dist/components/ui/toggle-group.d.ts +50 -5
- package/dist/components/ui/toggle-group.js +79 -20
- package/dist/components/ui/toggle.d.ts +31 -5
- package/dist/components/ui/toggle.js +42 -3
- package/dist/form/form-context.d.ts +29 -0
- package/dist/form/form-context.js +44 -4
- package/dist/form/form-field-array.d.ts +22 -0
- package/dist/form/form-field-array.js +50 -0
- package/dist/form/form-field-control.d.ts +2 -1
- package/dist/form/form-field-control.js +116 -40
- package/dist/form/form-root.d.ts +2 -1
- package/dist/form/form-root.js +142 -23
- package/dist/form/index.d.ts +3 -1
- package/dist/form/index.js +12 -1
- package/dist/i18n/messages/en.json +64 -5
- package/dist/i18n/messages/ja.json +64 -5
- package/dist/i18n/messages/vi.json +64 -5
- package/dist/inertia/index.d.ts +20 -0
- package/dist/inertia/index.js +60 -1
- package/dist/lib/control-styles.d.ts +25 -3
- package/dist/lib/control-styles.js +9 -3
- package/dist/lib/datetime/picker-format.d.ts +8 -0
- package/dist/lib/datetime/picker-format.js +54 -0
- package/dist/lib/slot.d.ts +32 -0
- package/dist/lib/slot.js +22 -0
- package/dist/lib/variants.d.ts +22 -3
- package/dist/lib/variants.js +56 -1
- package/dist/props/components/app.prop.d.ts +25 -1
- package/dist/props/components/charts.prop.d.ts +21 -0
- package/dist/props/components/data-display.prop.d.ts +72 -4
- package/dist/props/components/data-entry.prop.d.ts +718 -46
- package/dist/props/components/form.prop.d.ts +142 -4
- package/dist/props/components/general.prop.d.ts +17 -1
- package/dist/props/components/index.d.ts +3 -3
- package/dist/props/components/layout.prop.d.ts +281 -11
- package/dist/props/components/navigation.prop.d.ts +114 -4
- package/dist/props/registry.d.ts +397 -11
- package/dist/props/registry.js +526 -11
- package/dist/props/vocabulary/content.prop.d.ts +1 -1
- package/dist/props/vocabulary/data.prop.d.ts +179 -1
- package/dist/props/vocabulary/index.d.ts +5 -5
- package/dist/props/vocabulary/interaction.prop.d.ts +68 -3
- package/dist/props/vocabulary/layout.prop.d.ts +57 -1
- package/dist/props/vocabulary/navigation.prop.d.ts +40 -0
- package/dist/props/vocabulary/shared.prop.d.ts +33 -0
- package/dist/styles/badge-layout.css +2 -1
- package/dist/styles/card-layout.css +26 -4
- package/dist/styles/chart-layout.css +15 -0
- package/dist/styles/control.css +657 -15
- package/dist/styles/core.css +5 -2
- package/dist/styles/data-display-layout.css +313 -6
- package/dist/styles/data-entry-layout.css +13 -0
- package/dist/styles/focus-ring.css +4 -0
- package/dist/styles/index.css +5 -2
- package/dist/styles/layout.css +327 -4
- package/dist/styles/navigation-layout.css +227 -0
- package/dist/styles/shell-layout.css +369 -13
- package/dist/styles/table-layout.css +95 -6
- package/dist/styles/text-layout.css +10 -4
- package/dist/tokens/base.css +2 -1
- package/dist/tokens/components/badge.css +1 -0
- package/dist/tokens/components/chart.css +6 -0
- package/dist/tokens/components/control.css +79 -2
- package/dist/tokens/components/data-display.css +20 -0
- package/dist/tokens/components/descriptions.css +11 -0
- package/dist/tokens/components/flex.css +8 -0
- package/dist/tokens/components/navigation.css +55 -0
- package/dist/tokens/components/shell.css +53 -3
- package/dist/tokens/components/table.css +14 -0
- package/dist/tokens/foundation.css +2 -0
- package/dist/tokens/semantic/layout.css +9 -0
- package/docs/COMPONENTS.md +9 -3
- package/docs/CONSUMER-RULES.md +13 -0
- package/docs/DESIGN-AUTHORITY.md +145 -83
- package/docs/DEVELOPMENT.md +4 -3
- package/docs/FORMS.md +151 -6
- package/docs/FRAME-COVERAGE-REPORT.md +32 -17
- package/docs/README.md +15 -15
- package/docs/STANDARDS-vocabulary-tokens.md +1 -1
- package/docs/TESTING.md +15 -6
- package/docs/WHAT-BELONGS-HERE.md +179 -0
- package/docs/charts/cjk-category-axis.tsx +81 -0
- package/docs/data-display/card/index.tsx +22 -0
- package/docs/data-display/data-table/examples/antd-parity.tsx +257 -0
- package/docs/data-display/data-table/index.tsx +23 -0
- package/docs/data-display/descriptions.tsx +41 -0
- package/docs/data-display/legend.tsx +145 -0
- package/docs/data-display/progress.tsx +32 -0
- package/docs/data-display/scroll-area.tsx +31 -25
- package/docs/data-display/table.tsx +104 -45
- package/docs/data-display/timeline.tsx +41 -0
- package/docs/data-entry/date-picker.tsx +85 -0
- package/docs/data-entry/date-range-picker.tsx +26 -0
- package/docs/data-entry/form-dynamic-fields.tsx +199 -0
- package/docs/data-entry/form.tsx +74 -4
- package/docs/data-entry/input-otp.tsx +24 -0
- package/docs/data-entry/input.tsx +46 -1
- package/docs/data-entry/month-range-picker.tsx +1 -1
- package/docs/data-entry/segmented.tsx +1 -1
- package/docs/data-entry/select.tsx +29 -2
- package/docs/data-entry/switch.tsx +41 -0
- package/docs/data-entry/textarea.tsx +38 -0
- package/docs/data-entry/time-picker.tsx +85 -1
- package/docs/data-entry/time-range-picker.tsx +55 -0
- package/docs/data-entry/transfer.tsx +17 -0
- package/docs/data-entry/upload.tsx +56 -12
- package/docs/feedback/sheet.tsx +1 -1
- package/docs/feedback/tooltip.tsx +1 -1
- package/docs/general/activity.tsx +2 -2
- package/docs/general/button/index.tsx +14 -1
- package/docs/general/typography.tsx +14 -1
- package/docs/layout/app-launcher.tsx +151 -0
- package/docs/layout/app-shell-arrangements.tsx +225 -0
- package/docs/layout/app-shell.tsx +11 -0
- package/docs/layout/aspect-ratio.tsx +1 -1
- package/docs/layout/flex.tsx +50 -0
- package/docs/layout/responsive-grid.tsx +21 -1
- package/docs/layout/topbar.tsx +5 -9
- package/docs/navigation/app-setting-picker.tsx +37 -1
- package/docs/navigation/app-setting-toggle.tsx +111 -0
- package/docs/navigation/breadcrumb.tsx +48 -0
- package/docs/navigation/dropdown-menu.tsx +21 -0
- package/docs/navigation/pagination.tsx +52 -0
- package/docs/navigation/steps.tsx +37 -0
- package/docs/navigation/tabs.tsx +97 -1
- package/docs/query/button-refetch.tsx +1 -0
- package/package.json +28 -8
- package/scripts/_agent-setup.mjs +182 -3
- package/scripts/consumer-rule.md +98 -0
- package/scripts/guinea-pig-skill.md +322 -0
- package/scripts/init-guinea-pig.mjs +84 -0
- package/scripts/postinstall.mjs +13 -2
- package/scripts/ui-audit.mjs +351 -37
- /package/dist/tokens/{antd.generated.css → derived.css} +0 -0
package/README.md
CHANGED
|
@@ -133,8 +133,15 @@ One token `--phi-unit` drives page/section/card spacing; micro control gaps use
|
|
|
133
133
|
|
|
134
134
|
```bash
|
|
135
135
|
pnpm preview # preview app → http://localhost:6008 (fixed port, kills stale)
|
|
136
|
+
pnpm typecheck && pnpm lint && pnpm run audit # the cheap gates — run these freely
|
|
137
|
+
pnpm vitest run src/components/<group>/__tests__ --maxWorkers=2 # ONLY what you touched
|
|
138
|
+
|
|
139
|
+
# Heavy — CI's job. Run locally AT MOST ONCE, right before opening a PR, and never
|
|
140
|
+
# with other agents working on the same machine: `verify` builds the library AND the
|
|
141
|
+
# preview site AND runs all 506 test files. Measured with agents in parallel: 70 vitest
|
|
142
|
+
# workers, load average 90, an overheating laptop.
|
|
136
143
|
pnpm preview:build # static build — also what deploys to GitHub Pages
|
|
137
|
-
pnpm verify # typecheck · lint · format · the 5 guards ·
|
|
144
|
+
pnpm verify # typecheck · lint · format · the 5 guards · FULL suite
|
|
138
145
|
pnpm release --ui <patch|minor|major> --mcp <…|skip> # publish lib + MCP in lockstep
|
|
139
146
|
```
|
|
140
147
|
|
|
@@ -174,5 +181,4 @@ This repo ships two packages — `@godxjp/ui` (this dir) and `@godxjp/ui-mcp` (`
|
|
|
174
181
|
- [docs/COMPONENTS.md](./docs/COMPONENTS.md) · [docs/TOKENS.md](./docs/TOKENS.md) · [docs/SPACING.md](./docs/SPACING.md)
|
|
175
182
|
- [docs/PROPS-VOCABULARY.md](./docs/PROPS-VOCABULARY.md) · [docs/PROPS-REGISTRY.md](./docs/PROPS-REGISTRY.md)
|
|
176
183
|
- [docs/DATETIME.md](./docs/DATETIME.md) · [docs/FORMS.md](./docs/FORMS.md) · [docs/TESTING.md](./docs/TESTING.md)
|
|
177
|
-
- **Architecture decisions** under `debate/*/04-Decision.md` (ADRs from the design debates)
|
|
178
184
|
- MCP: **godxjp-ui-mcp** (`.mcp.json`) — live catalog for agents
|
package/dist/app/theme-axes.d.ts
CHANGED
|
@@ -43,3 +43,5 @@ export declare const isAppFontSize: (v: unknown) => v is AppFontSize;
|
|
|
43
43
|
* `data-brand` so the app's own `--primary` token applies.
|
|
44
44
|
*/
|
|
45
45
|
export declare function applyThemeAxes(el: HTMLElement, axes: Partial<AppThemeAxes>): void;
|
|
46
|
+
/** Apply an entity's action palette, including portals. Call the returned cleanup on scope exit. */
|
|
47
|
+
export declare function applyPrimaryColor(root: HTMLElement, color: string, foreground?: string | null): () => void;
|
package/dist/app/theme-axes.js
CHANGED
|
@@ -39,12 +39,57 @@ function applyThemeAxes(el, axes) {
|
|
|
39
39
|
else el.style.setProperty("--scaling", String(axes.scaling));
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
|
+
function applyPrimaryColor(root, color, foreground) {
|
|
43
|
+
const parse = (value) => {
|
|
44
|
+
if (!/^#[\da-f]{6}$/i.test(value)) return null;
|
|
45
|
+
return [1, 3, 5].map((offset) => parseInt(value.slice(offset, offset + 2), 16) / 255);
|
|
46
|
+
};
|
|
47
|
+
const rgb = parse(color);
|
|
48
|
+
if (!rgb) return () => {
|
|
49
|
+
};
|
|
50
|
+
const luminance = (channels) => channels.reduce(
|
|
51
|
+
(sum, value, index) => sum + (value <= 0.04045 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4) * [0.2126, 0.7152, 0.0722][index],
|
|
52
|
+
0
|
|
53
|
+
);
|
|
54
|
+
const text = foreground && parse(foreground) || (luminance(rgb) > 0.179 ? [0, 0, 0] : [1, 1, 1]);
|
|
55
|
+
const hsl = (channels) => {
|
|
56
|
+
const [r, g, b] = channels;
|
|
57
|
+
const max = Math.max(r, g, b), min = Math.min(r, g, b);
|
|
58
|
+
const delta = max - min, lightness = (max + min) / 2;
|
|
59
|
+
const saturation = delta === 0 ? 0 : delta / (1 - Math.abs(2 * lightness - 1));
|
|
60
|
+
const hue = delta === 0 ? 0 : 60 * (max === r ? ((g - b) / delta + 6) % 6 : max === g ? (b - r) / delta + 2 : (r - g) / delta + 4);
|
|
61
|
+
return `${hue} ${saturation * 100}% ${lightness * 100}%`;
|
|
62
|
+
};
|
|
63
|
+
const away = luminance(text) > 0.5 ? 0 : 1;
|
|
64
|
+
const shade = (amount) => hsl(rgb.map((channel) => channel * (1 - amount) + away * amount));
|
|
65
|
+
const palette = {
|
|
66
|
+
"--primary": hsl(rgb),
|
|
67
|
+
"--primary-foreground": hsl(text),
|
|
68
|
+
"--primary-hover": shade(0.12),
|
|
69
|
+
"--primary-active": shade(0.24),
|
|
70
|
+
"--primary-border": hsl(rgb),
|
|
71
|
+
"--ring": hsl(rgb)
|
|
72
|
+
};
|
|
73
|
+
const previous = Object.keys(palette).map((key) => [
|
|
74
|
+
key,
|
|
75
|
+
root.style.getPropertyValue(key),
|
|
76
|
+
root.style.getPropertyPriority(key)
|
|
77
|
+
]);
|
|
78
|
+
for (const [key, value] of Object.entries(palette)) root.style.setProperty(key, value);
|
|
79
|
+
return () => {
|
|
80
|
+
for (const [key, value, priority] of previous) {
|
|
81
|
+
if (value) root.style.setProperty(key, value, priority);
|
|
82
|
+
else root.style.removeProperty(key);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
42
86
|
export {
|
|
43
87
|
APP_BRANDS,
|
|
44
88
|
APP_DENSITIES,
|
|
45
89
|
APP_FONT_SIZES,
|
|
46
90
|
APP_THEMES,
|
|
47
91
|
PREFERS_DARK_SCHEME_QUERY,
|
|
92
|
+
applyPrimaryColor,
|
|
48
93
|
applyThemeAxes,
|
|
49
94
|
isAppBrand,
|
|
50
95
|
isAppDensity,
|
|
@@ -11,6 +11,7 @@ type CartesianChartProps = {
|
|
|
11
11
|
series: ChartSeriesProp[];
|
|
12
12
|
categoryKey: string;
|
|
13
13
|
label: React.ReactNode;
|
|
14
|
+
showCaption?: boolean;
|
|
14
15
|
description?: React.ReactNode;
|
|
15
16
|
size?: "xs" | "sm" | "md" | "lg";
|
|
16
17
|
height?: number;
|
|
@@ -27,5 +28,5 @@ type CartesianChartProps = {
|
|
|
27
28
|
/** bar */
|
|
28
29
|
horizontal?: boolean;
|
|
29
30
|
};
|
|
30
|
-
export declare function CartesianChart({ kind, data, series, categoryKey, label, description, size, height, showLegend, showGrid, numberFormat, emptyMessage, className, id, curved, stacked, horizontal, }: CartesianChartProps): React.JSX.Element;
|
|
31
|
+
export declare function CartesianChart({ kind, data, series, categoryKey, label, showCaption, description, size, height, showLegend, showGrid, numberFormat, emptyMessage, className, id, curved, stacked, horizontal, }: CartesianChartProps): React.JSX.Element;
|
|
31
32
|
export {};
|
|
@@ -13,18 +13,22 @@ import {
|
|
|
13
13
|
ResponsiveContainer,
|
|
14
14
|
Tooltip,
|
|
15
15
|
XAxis,
|
|
16
|
-
YAxis
|
|
17
|
-
|
|
16
|
+
YAxis,
|
|
17
|
+
assertRechartsPeer
|
|
18
|
+
} from "./recharts-peer.js";
|
|
19
|
+
import { cn } from "../../lib/utils.js";
|
|
18
20
|
import { EmptyState } from "../data-display/empty-state.js";
|
|
19
21
|
import { useTranslation } from "../../i18n/use-translation.js";
|
|
20
22
|
import { ChartFrame, chartColor, chartHeight, useChartNumberFormat } from "./chart-frame.js";
|
|
21
23
|
import { buildCartesianSummary } from "./chart-summary.js";
|
|
24
|
+
import { useCategoryAxisMetrics } from "./chart-category-axis.js";
|
|
22
25
|
function CartesianChart({
|
|
23
26
|
kind,
|
|
24
27
|
data,
|
|
25
28
|
series,
|
|
26
29
|
categoryKey,
|
|
27
30
|
label,
|
|
31
|
+
showCaption = true,
|
|
28
32
|
description,
|
|
29
33
|
size = "md",
|
|
30
34
|
height,
|
|
@@ -38,6 +42,7 @@ function CartesianChart({
|
|
|
38
42
|
stacked = false,
|
|
39
43
|
horizontal = false
|
|
40
44
|
}) {
|
|
45
|
+
assertRechartsPeer();
|
|
41
46
|
const { t, locale } = useTranslation();
|
|
42
47
|
const fmt = useChartNumberFormat(numberFormat);
|
|
43
48
|
const list = React.useMemo(
|
|
@@ -56,6 +61,41 @@ function CartesianChart({
|
|
|
56
61
|
const resolvedHeight = chartHeight(size, height);
|
|
57
62
|
const tickFormatter = (value) => fmt.format(value);
|
|
58
63
|
const curve = curved ? "monotone" : "linear";
|
|
64
|
+
const measuresCategoryAxis = kind === "bar" && horizontal;
|
|
65
|
+
const canvasRef = React.useRef(null);
|
|
66
|
+
const probeRef = React.useRef(null);
|
|
67
|
+
const categoryLabels = React.useMemo(
|
|
68
|
+
() => measuresCategoryAxis ? data.map((datum) => String(datum[categoryKey] ?? "")) : [],
|
|
69
|
+
[measuresCategoryAxis, data, categoryKey]
|
|
70
|
+
);
|
|
71
|
+
const categoryAxis = useCategoryAxisMetrics(
|
|
72
|
+
canvasRef,
|
|
73
|
+
probeRef,
|
|
74
|
+
categoryLabels,
|
|
75
|
+
measuresCategoryAxis && hasData
|
|
76
|
+
);
|
|
77
|
+
const categoryTick = (tickProps) => {
|
|
78
|
+
const full = String(tickProps.payload?.value ?? "");
|
|
79
|
+
const shown = categoryAxis.display(full);
|
|
80
|
+
return (
|
|
81
|
+
// `recharts-text` is what chart-layout.css styles the tick typography through; the rest of
|
|
82
|
+
// the class list is recharts' own (it hands `recharts-cartesian-axis-tick-value` in).
|
|
83
|
+
/* @__PURE__ */ jsxs(
|
|
84
|
+
"text",
|
|
85
|
+
{
|
|
86
|
+
className: cn("recharts-text", tickProps.className),
|
|
87
|
+
x: tickProps.x,
|
|
88
|
+
y: tickProps.y,
|
|
89
|
+
textAnchor: tickProps.textAnchor,
|
|
90
|
+
dominantBaseline: "central",
|
|
91
|
+
children: [
|
|
92
|
+
shown === full ? null : /* @__PURE__ */ jsx("title", { children: full }),
|
|
93
|
+
shown
|
|
94
|
+
]
|
|
95
|
+
}
|
|
96
|
+
)
|
|
97
|
+
);
|
|
98
|
+
};
|
|
59
99
|
const axes = (numberAxisVertical) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
60
100
|
showGrid ? /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", stroke: "hsl(var(--border))" }) : null,
|
|
61
101
|
numberAxisVertical ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -95,7 +135,9 @@ function CartesianChart({
|
|
|
95
135
|
dataKey: categoryKey,
|
|
96
136
|
tickLine: false,
|
|
97
137
|
stroke: "hsl(var(--muted-foreground))",
|
|
98
|
-
fontSize: 12
|
|
138
|
+
fontSize: 12,
|
|
139
|
+
width: categoryAxis.width,
|
|
140
|
+
tick: categoryTick
|
|
99
141
|
}
|
|
100
142
|
)
|
|
101
143
|
] }),
|
|
@@ -158,6 +200,7 @@ function CartesianChart({
|
|
|
158
200
|
ChartFrame,
|
|
159
201
|
{
|
|
160
202
|
label,
|
|
203
|
+
showCaption,
|
|
161
204
|
description,
|
|
162
205
|
summaryRows: summary.rows,
|
|
163
206
|
imgSummary: summary.img,
|
|
@@ -165,6 +208,12 @@ function CartesianChart({
|
|
|
165
208
|
height: resolvedHeight,
|
|
166
209
|
className,
|
|
167
210
|
id,
|
|
211
|
+
canvasRef,
|
|
212
|
+
canvasExtra: measuresCategoryAxis ? (
|
|
213
|
+
// Out-of-flow, hidden, and inside `.ui-chart` — so it inherits exactly the typography
|
|
214
|
+
// the axis ticks are painted in, including the `[lang="ja"]` face.
|
|
215
|
+
/* @__PURE__ */ jsx("span", { ref: probeRef, className: "ui-chart-axis-probe", "aria-hidden": "true" })
|
|
216
|
+
) : null,
|
|
168
217
|
children: hasData ? /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", minWidth: 0, children: chart() }) : /* @__PURE__ */ jsx(EmptyState, { title: emptyMessage ?? t("chart.empty") })
|
|
169
218
|
}
|
|
170
219
|
);
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Category-axis sizing for the HORIZONTAL bar chart (gh#409 · 1).
|
|
4
|
+
*
|
|
5
|
+
* recharts reserves a fixed 60px for the category axis whatever the ticks say, so a Japanese
|
|
6
|
+
* company name — 8–10 full-width glyphs, 100–125px — was painted OUTSIDE the chart box and the
|
|
7
|
+
* SVG clip cut it from the START, removing exactly the identifying `株式会社` prefix. Latin text
|
|
8
|
+
* degrades gracefully there; 全角 does not, and `docs/DESIGN-AUTHORITY.md` gives anything the user
|
|
9
|
+
* READS to the Japanese standard.
|
|
10
|
+
*
|
|
11
|
+
* The mechanism: measure every tick in the real rendered typography, size the axis from the
|
|
12
|
+
* WIDEST one, cap that at a token-owned fraction of the canvas so one long name can never eat
|
|
13
|
+
* the bars, and truncate anything past the cap at its END — the start, which identifies the row,
|
|
14
|
+
* always survives, and the full string stays reachable through the tick's `<title>` and the
|
|
15
|
+
* figure's screen-reader list.
|
|
16
|
+
*
|
|
17
|
+
* The two knobs are component tokens (`src/tokens/components/chart.css`). They are read back in
|
|
18
|
+
* px from real CSS properties on the probe element, because a custom property's computed value
|
|
19
|
+
* keeps whatever unit its author wrote.
|
|
20
|
+
*/
|
|
21
|
+
/** Axis knobs resolved from the probe's computed style. `gap` is px, `maxFraction` unitless. */
|
|
22
|
+
export type CategoryAxisKnobs = {
|
|
23
|
+
/** Space between the tick text and the plot area. */
|
|
24
|
+
gap: number;
|
|
25
|
+
/** Share of the canvas the category axis may take, 0..1. */
|
|
26
|
+
maxFraction: number;
|
|
27
|
+
};
|
|
28
|
+
/** What the chart needs to draw the axis: its reserved width and the text of each tick. */
|
|
29
|
+
export type CategoryAxisMetrics = {
|
|
30
|
+
/** `width` for recharts' `YAxis`, or `undefined` while nothing has been measured yet. */
|
|
31
|
+
width: number | undefined;
|
|
32
|
+
/** Tick text to paint — the original label, or one truncated at its END. */
|
|
33
|
+
display: (label: string) => string;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Axis width from the measured tick widths: the widest tick, capped, plus the gap.
|
|
37
|
+
* Pure — the browser measurement is injected, so the rule is testable without a layout engine.
|
|
38
|
+
*/
|
|
39
|
+
export declare function resolveCategoryAxisWidth(textWidths: readonly number[], available: number, { gap, maxFraction }: CategoryAxisKnobs): {
|
|
40
|
+
width: number;
|
|
41
|
+
textCap: number;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Cut `label` at its END until it fits `maxWidth`, appending an ellipsis. The first glyph is
|
|
45
|
+
* always kept: a tick that reads `…` identifies nothing, and a tick cut from the front is the
|
|
46
|
+
* bug this exists to fix.
|
|
47
|
+
*/
|
|
48
|
+
export declare function truncateToWidth(label: string, maxWidth: number, measure: (text: string) => number): string;
|
|
49
|
+
/**
|
|
50
|
+
* Measure the category ticks in the live document and keep the axis sized to them.
|
|
51
|
+
*
|
|
52
|
+
* Re-runs when the canvas resizes and once `document.fonts` settles, because a CJK web face
|
|
53
|
+
* arriving after first paint changes every one of these widths.
|
|
54
|
+
*/
|
|
55
|
+
export declare function useCategoryAxisMetrics(canvasRef: React.RefObject<HTMLDivElement | null>, probeRef: React.RefObject<HTMLSpanElement | null>, labels: readonly string[], enabled: boolean): CategoryAxisMetrics;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
const ELLIPSIS = "\u2026";
|
|
4
|
+
function resolveCategoryAxisWidth(textWidths, available, { gap, maxFraction }) {
|
|
5
|
+
const textCap = Math.max(0, available * maxFraction - gap);
|
|
6
|
+
const widest = textWidths.length > 0 ? Math.max(...textWidths) : 0;
|
|
7
|
+
return { width: Math.ceil(Math.min(widest, textCap) + gap), textCap };
|
|
8
|
+
}
|
|
9
|
+
function truncateToWidth(label, maxWidth, measure) {
|
|
10
|
+
if (measure(label) <= maxWidth) return label;
|
|
11
|
+
const glyphs = [...label];
|
|
12
|
+
for (let keep = glyphs.length - 1; keep > 1; keep -= 1) {
|
|
13
|
+
const candidate = glyphs.slice(0, keep).join("") + ELLIPSIS;
|
|
14
|
+
if (measure(candidate) <= maxWidth) return candidate;
|
|
15
|
+
}
|
|
16
|
+
return `${glyphs[0] ?? ""}${ELLIPSIS}`;
|
|
17
|
+
}
|
|
18
|
+
function readKnobs(probe) {
|
|
19
|
+
const style = getComputedStyle(probe);
|
|
20
|
+
const gap = Number.parseFloat(style.marginInlineEnd);
|
|
21
|
+
const maxFraction = Number.parseFloat(
|
|
22
|
+
style.getPropertyValue("--chart-category-axis-max-fraction")
|
|
23
|
+
);
|
|
24
|
+
return {
|
|
25
|
+
gap: Number.isFinite(gap) ? gap : 0,
|
|
26
|
+
maxFraction: Number.isFinite(maxFraction) ? maxFraction : 1
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function sameTruncations(a, b) {
|
|
30
|
+
if (a.size !== b.size) return false;
|
|
31
|
+
for (const [key, value] of a) {
|
|
32
|
+
if (b.get(key) !== value) return false;
|
|
33
|
+
}
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
function useCategoryAxisMetrics(canvasRef, probeRef, labels, enabled) {
|
|
37
|
+
const [measured, setMeasured] = React.useState(void 0);
|
|
38
|
+
const labelsRef = React.useRef(labels);
|
|
39
|
+
labelsRef.current = labels;
|
|
40
|
+
const key = labels.join("\0");
|
|
41
|
+
React.useEffect(() => {
|
|
42
|
+
const canvas = canvasRef.current;
|
|
43
|
+
const probe = probeRef.current;
|
|
44
|
+
if (!enabled || !canvas || !probe) {
|
|
45
|
+
setMeasured(void 0);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const ticks = labelsRef.current;
|
|
49
|
+
const measure = (text) => {
|
|
50
|
+
probe.textContent = text;
|
|
51
|
+
return probe.getBoundingClientRect().width;
|
|
52
|
+
};
|
|
53
|
+
const run = () => {
|
|
54
|
+
const available = canvas.clientWidth;
|
|
55
|
+
if (available <= 0) return;
|
|
56
|
+
const knobs = readKnobs(probe);
|
|
57
|
+
const widths = ticks.map(measure);
|
|
58
|
+
const { width, textCap } = resolveCategoryAxisWidth(widths, available, knobs);
|
|
59
|
+
const truncations2 = /* @__PURE__ */ new Map();
|
|
60
|
+
ticks.forEach((label, index) => {
|
|
61
|
+
if ((widths[index] ?? 0) > textCap) {
|
|
62
|
+
truncations2.set(label, truncateToWidth(label, textCap, measure));
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
probe.textContent = "";
|
|
66
|
+
setMeasured(
|
|
67
|
+
(previous) => previous && previous.width === width && sameTruncations(previous.truncations, truncations2) ? previous : { width, truncations: truncations2 }
|
|
68
|
+
);
|
|
69
|
+
};
|
|
70
|
+
run();
|
|
71
|
+
const observer = new ResizeObserver(run);
|
|
72
|
+
observer.observe(canvas);
|
|
73
|
+
let live = true;
|
|
74
|
+
void document.fonts?.ready.then(() => {
|
|
75
|
+
if (live) run();
|
|
76
|
+
});
|
|
77
|
+
return () => {
|
|
78
|
+
live = false;
|
|
79
|
+
observer.disconnect();
|
|
80
|
+
};
|
|
81
|
+
}, [canvasRef, probeRef, enabled, key]);
|
|
82
|
+
const truncations = measured?.truncations;
|
|
83
|
+
const display = React.useCallback(
|
|
84
|
+
(label) => truncations?.get(label) ?? label,
|
|
85
|
+
[truncations]
|
|
86
|
+
);
|
|
87
|
+
return { width: measured?.width, display };
|
|
88
|
+
}
|
|
89
|
+
export {
|
|
90
|
+
resolveCategoryAxisWidth,
|
|
91
|
+
truncateToWidth,
|
|
92
|
+
useCategoryAxisMetrics
|
|
93
|
+
};
|
|
@@ -18,6 +18,11 @@ export declare function useChartNumberFormat(options?: Intl.NumberFormatOptions)
|
|
|
18
18
|
type ChartFrameProps = {
|
|
19
19
|
/** Visible caption; also the accessible name via `aria-labelledby` → `<figcaption>`. */
|
|
20
20
|
label: React.ReactNode;
|
|
21
|
+
/**
|
|
22
|
+
* Paint the caption. `false` keeps the `<figcaption>` in the DOM as `sr-only`, so
|
|
23
|
+
* `aria-labelledby` still names the figure — only the duplicate visible title goes away.
|
|
24
|
+
*/
|
|
25
|
+
showCaption?: boolean;
|
|
21
26
|
/** Extra context appended to the screen-reader description. */
|
|
22
27
|
description?: React.ReactNode;
|
|
23
28
|
/** Pre-formatted "category: value" rows for the screen-reader text alternative. */
|
|
@@ -39,11 +44,15 @@ type ChartFrameProps = {
|
|
|
39
44
|
id?: string;
|
|
40
45
|
children: React.ReactNode;
|
|
41
46
|
ref?: React.Ref<HTMLElement>;
|
|
47
|
+
/** The plot box itself — charts that measure their own axis need to read its width. */
|
|
48
|
+
canvasRef?: React.Ref<HTMLDivElement>;
|
|
49
|
+
/** Rendered inside the canvas, after `children` (the axis measuring probe). */
|
|
50
|
+
canvasExtra?: React.ReactNode;
|
|
42
51
|
};
|
|
43
52
|
/**
|
|
44
53
|
* The accessible figure wrapper. The chart body passed as `children` is wrapped
|
|
45
54
|
* in a `role="img"` element with a short `aria-label`; the full data is exposed as
|
|
46
55
|
* a sibling visually-hidden list referenced by the figure's `aria-describedby`.
|
|
47
56
|
*/
|
|
48
|
-
export declare function ChartFrame({ label, description, summaryRows, imgSummary, hasData, height, size, footer, className, id, children, ref, }: ChartFrameProps): React.JSX.Element;
|
|
57
|
+
export declare function ChartFrame({ label, showCaption, description, summaryRows, imgSummary, hasData, height, size, footer, className, id, children, ref, canvasRef, canvasExtra, }: ChartFrameProps): React.JSX.Element;
|
|
49
58
|
export {};
|
|
@@ -29,6 +29,7 @@ function useChartNumberFormat(options) {
|
|
|
29
29
|
}
|
|
30
30
|
function ChartFrame({
|
|
31
31
|
label,
|
|
32
|
+
showCaption = true,
|
|
32
33
|
description,
|
|
33
34
|
summaryRows,
|
|
34
35
|
imgSummary,
|
|
@@ -39,7 +40,9 @@ function ChartFrame({
|
|
|
39
40
|
className,
|
|
40
41
|
id,
|
|
41
42
|
children,
|
|
42
|
-
ref
|
|
43
|
+
ref,
|
|
44
|
+
canvasRef,
|
|
45
|
+
canvasExtra
|
|
43
46
|
}) {
|
|
44
47
|
const reactId = React.useId();
|
|
45
48
|
const titleId = `${id ?? reactId}-title`;
|
|
@@ -55,8 +58,21 @@ function ChartFrame({
|
|
|
55
58
|
"aria-labelledby": titleId,
|
|
56
59
|
"aria-describedby": descId,
|
|
57
60
|
children: [
|
|
58
|
-
/* @__PURE__ */ jsx("figcaption", { id: titleId, className: "ui-chart-title", children: label }),
|
|
59
|
-
/* @__PURE__ */
|
|
61
|
+
/* @__PURE__ */ jsx("figcaption", { id: titleId, className: showCaption ? "ui-chart-title" : "sr-only", children: label }),
|
|
62
|
+
/* @__PURE__ */ jsxs(
|
|
63
|
+
"div",
|
|
64
|
+
{
|
|
65
|
+
ref: canvasRef,
|
|
66
|
+
className: "ui-chart-canvas",
|
|
67
|
+
style: { height },
|
|
68
|
+
role: "img",
|
|
69
|
+
"aria-label": imgSummary,
|
|
70
|
+
children: [
|
|
71
|
+
children,
|
|
72
|
+
canvasExtra
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
),
|
|
60
76
|
footer ? /* @__PURE__ */ jsx("div", { className: "ui-chart-footer", children: footer }) : null,
|
|
61
77
|
/* @__PURE__ */ jsxs("p", { id: descId, className: "sr-only", children: [
|
|
62
78
|
description ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -12,4 +12,4 @@ export type { CompactBarTrendProp, CompactBarTrendProp as CompactBarTrendProps,
|
|
|
12
12
|
* localized one-line summary, and a visually-hidden per-category value list referenced through
|
|
13
13
|
* `aria-describedby` (WCAG 1.1.1).
|
|
14
14
|
*/
|
|
15
|
-
export declare function CompactBarTrend({ data, categoryKey, valueKey, label, description, size, emphasizedIndex, showCategoryLabels, numberFormat, footer, emptyMessage, className, id, ref, }: CompactBarTrendProp): React.JSX.Element;
|
|
15
|
+
export declare function CompactBarTrend({ data, categoryKey, valueKey, label, showCaption, description, size, emphasizedIndex, showCategoryLabels, numberFormat, footer, emptyMessage, className, id, ref, }: CompactBarTrendProp): React.JSX.Element;
|
|
@@ -11,6 +11,7 @@ function CompactBarTrend({
|
|
|
11
11
|
categoryKey,
|
|
12
12
|
valueKey,
|
|
13
13
|
label,
|
|
14
|
+
showCaption = true,
|
|
14
15
|
description,
|
|
15
16
|
size = "xs",
|
|
16
17
|
emphasizedIndex,
|
|
@@ -40,6 +41,7 @@ function CompactBarTrend({
|
|
|
40
41
|
{
|
|
41
42
|
ref,
|
|
42
43
|
label,
|
|
44
|
+
showCaption,
|
|
43
45
|
description,
|
|
44
46
|
summaryRows: summary.rows,
|
|
45
47
|
imgSummary: summary.img,
|
|
@@ -5,4 +5,4 @@ export type { PieChartProp, PieChartProp as PieChartProps, } from "../../props/c
|
|
|
5
5
|
* Import from the tree-shaken `@godxjp/ui/charts` entry; requires the `recharts`
|
|
6
6
|
* optional peer dependency.
|
|
7
7
|
*/
|
|
8
|
-
export declare function PieChart({ data, dataKey, nameKey, colors, label, description, size, height, showLegend, numberFormat, donut, emptyMessage, className, id, }: PieChartProp): import("react").JSX.Element;
|
|
8
|
+
export declare function PieChart({ data, dataKey, nameKey, colors, label, showCaption, description, size, height, showLegend, numberFormat, donut, emptyMessage, className, id, }: PieChartProp): import("react").JSX.Element;
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
Cell,
|
|
5
|
+
Legend,
|
|
6
|
+
Pie,
|
|
7
|
+
PieChart as RPieChart,
|
|
8
|
+
ResponsiveContainer,
|
|
9
|
+
Tooltip,
|
|
10
|
+
assertRechartsPeer
|
|
11
|
+
} from "./recharts-peer.js";
|
|
4
12
|
import { EmptyState } from "../data-display/empty-state.js";
|
|
5
13
|
import { useTranslation } from "../../i18n/use-translation.js";
|
|
6
14
|
import { ChartFrame, chartColor, chartHeight, useChartNumberFormat } from "./chart-frame.js";
|
|
@@ -11,6 +19,7 @@ function PieChart({
|
|
|
11
19
|
nameKey,
|
|
12
20
|
colors,
|
|
13
21
|
label,
|
|
22
|
+
showCaption = true,
|
|
14
23
|
description,
|
|
15
24
|
size = "md",
|
|
16
25
|
height,
|
|
@@ -21,6 +30,7 @@ function PieChart({
|
|
|
21
30
|
className,
|
|
22
31
|
id
|
|
23
32
|
}) {
|
|
33
|
+
assertRechartsPeer();
|
|
24
34
|
const { t } = useTranslation();
|
|
25
35
|
const fmt = useChartNumberFormat(numberFormat);
|
|
26
36
|
const hasData = data.length > 0;
|
|
@@ -36,6 +46,7 @@ function PieChart({
|
|
|
36
46
|
ChartFrame,
|
|
37
47
|
{
|
|
38
48
|
label,
|
|
49
|
+
showCaption,
|
|
39
50
|
description,
|
|
40
51
|
summaryRows: summary.rows,
|
|
41
52
|
imgSummary: summary.img,
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ONE module in `@godxjp/ui` that touches the optional `recharts` peer.
|
|
3
|
+
*
|
|
4
|
+
* WHY IT EXISTS (gh#409 · 6). `recharts` is declared optional in `peerDependenciesMeta`, so a
|
|
5
|
+
* bundler that cannot resolve it substitutes an empty stub, and EVERY named import of that stub
|
|
6
|
+
* becomes its own `[MISSING_EXPORT]` diagnostic. A consumer who had not installed recharts got 18
|
|
7
|
+
* of them, spread across `dist/components/charts/**`, none of which said what to install.
|
|
8
|
+
*
|
|
9
|
+
* Reading the peer through a NAMESPACE import removes those bindings — there is no named export
|
|
10
|
+
* left to be missing. ONE named import is kept on purpose: it is what still fails the BUILD (a
|
|
11
|
+
* silent build followed by a blank page at load is worse than a red build), and because the
|
|
12
|
+
* bundler prints the offending SOURCE LINE, its local alias is written as the remedy — so the
|
|
13
|
+
* single remaining diagnostic reads
|
|
14
|
+
*
|
|
15
|
+
* [MISSING_EXPORT] "ResponsiveContainer" is not exported by
|
|
16
|
+
* "__vite-optional-peer-dep:recharts:@godxjp/ui".
|
|
17
|
+
* ╭─[ …/dist/components/charts/recharts-peer.js:3:10 ]
|
|
18
|
+
* 3 │ import { ResponsiveContainer as install_recharts_or_use_charts_compact_bar_trend } from "recharts";
|
|
19
|
+
*
|
|
20
|
+
* which names the package, the fix, and the alternative that needs no peer at all.
|
|
21
|
+
*
|
|
22
|
+
* `assertRechartsPeer` covers the bundlers that resolve a missing optional peer to a silent empty
|
|
23
|
+
* object instead of a throwing stub: there the first chart to render says what is missing.
|
|
24
|
+
*
|
|
25
|
+
* Do NOT `import … from "recharts"` anywhere else in the library.
|
|
26
|
+
*/
|
|
27
|
+
import * as peer from "recharts";
|
|
28
|
+
/** What a consumer has to do. Kept as one string so the message cannot drift between call sites. */
|
|
29
|
+
export declare const RECHARTS_PEER_MESSAGE: string;
|
|
30
|
+
/**
|
|
31
|
+
* Throw the remedy instead of an `undefined is not a component` render error. Called by each
|
|
32
|
+
* recharts-backed chart before it renders anything.
|
|
33
|
+
*/
|
|
34
|
+
export declare function assertRechartsPeer(): void;
|
|
35
|
+
export declare const Area: <DataPointType = any, ValueAxisType = any>(props: peer.AreaProps<DataPointType, ValueAxisType>) => import("react").ReactElement, AreaChart: <DataPointType = any>(props: import("recharts/types/util/types").CartesianChartProps<DataPointType> & {
|
|
36
|
+
ref?: React.Ref<SVGSVGElement>;
|
|
37
|
+
}) => React.ReactElement, Bar: <DataPointType = any, ValueAxisType = any>(props: peer.BarProps<DataPointType, ValueAxisType>) => import("react").ReactElement, BarChart: <DataPointType = any>(props: import("recharts/types/util/types").CartesianChartProps<DataPointType> & {
|
|
38
|
+
ref?: React.Ref<SVGSVGElement>;
|
|
39
|
+
}) => React.ReactElement, CartesianGrid: typeof peer.CartesianGrid, Cell: import("react").FunctionComponent<peer.CellProps>, Legend: import("react").MemoExoticComponent<(outsideProps: peer.LegendProps) => React.ReactPortal | null>, Line: {
|
|
40
|
+
<DataPointType = any, ValueAxisType = any>(props: peer.LineProps<DataPointType, ValueAxisType>): import("react").ReactElement;
|
|
41
|
+
(props: peer.LineProps<any, any>): import("react").ReactElement;
|
|
42
|
+
}, LineChart: <DataPointType = any>(props: import("recharts/types/util/types").CartesianChartProps<DataPointType> & {
|
|
43
|
+
ref?: React.Ref<SVGSVGElement>;
|
|
44
|
+
}) => React.ReactElement, Pie: {
|
|
45
|
+
<DataPointType = any, DataValueType = any>(outsideProps: peer.PieProps<DataPointType, DataValueType>): import("react").ReactElement;
|
|
46
|
+
(outsideProps: peer.PieProps<any, any>): import("react").ReactElement;
|
|
47
|
+
}, PieChart: <DataPointType = any>(props: import("recharts/types/util/types").PolarChartProps<DataPointType> & {
|
|
48
|
+
ref?: React.Ref<SVGSVGElement>;
|
|
49
|
+
}) => React.ReactElement, ResponsiveContainer: import("react").ForwardRefExoticComponent<peer.ResponsiveContainerProps & import("react").RefAttributes<HTMLDivElement>>, Tooltip: typeof peer.Tooltip, XAxis: <DataPointType = any, DataValueType = any>(props: peer.XAxisProps<DataPointType, DataValueType>) => import("react").ReactElement, YAxis: <DataPointType = any, DataValueType = any>(props: peer.YAxisProps<DataPointType, DataValueType>) => import("react").ReactElement;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import * as peer from "recharts";
|
|
3
|
+
import { ResponsiveContainer as install_recharts_or_use_charts_compact_bar_trend } from "recharts";
|
|
4
|
+
const RECHARTS_PEER_MESSAGE = '@godxjp/ui charts need the optional peer dependency "recharts" (^2.13.0 || ^3.0.0), which is not installed. Install it \u2014 `pnpm add recharts` / `npm i recharts` \u2014 or, for a dependency-free trend mark, import { CompactBarTrend } from "@godxjp/ui/charts/compact-bar-trend".';
|
|
5
|
+
function assertRechartsPeer() {
|
|
6
|
+
if (typeof install_recharts_or_use_charts_compact_bar_trend === "undefined") {
|
|
7
|
+
throw new Error(RECHARTS_PEER_MESSAGE);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
const {
|
|
11
|
+
Area,
|
|
12
|
+
AreaChart,
|
|
13
|
+
Bar,
|
|
14
|
+
BarChart,
|
|
15
|
+
CartesianGrid,
|
|
16
|
+
Cell,
|
|
17
|
+
Legend,
|
|
18
|
+
Line,
|
|
19
|
+
LineChart,
|
|
20
|
+
Pie,
|
|
21
|
+
PieChart,
|
|
22
|
+
ResponsiveContainer,
|
|
23
|
+
Tooltip,
|
|
24
|
+
XAxis,
|
|
25
|
+
YAxis
|
|
26
|
+
} = peer;
|
|
27
|
+
export {
|
|
28
|
+
Area,
|
|
29
|
+
AreaChart,
|
|
30
|
+
Bar,
|
|
31
|
+
BarChart,
|
|
32
|
+
CartesianGrid,
|
|
33
|
+
Cell,
|
|
34
|
+
Legend,
|
|
35
|
+
Line,
|
|
36
|
+
LineChart,
|
|
37
|
+
Pie,
|
|
38
|
+
PieChart,
|
|
39
|
+
RECHARTS_PEER_MESSAGE,
|
|
40
|
+
ResponsiveContainer,
|
|
41
|
+
Tooltip,
|
|
42
|
+
XAxis,
|
|
43
|
+
YAxis,
|
|
44
|
+
assertRechartsPeer
|
|
45
|
+
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { GapProp, PadProp, PadRawProp } from "../../props/vocabulary/index.js";
|
|
1
2
|
import * as React from "react";
|
|
2
3
|
import type { LucideIcon } from "lucide-react";
|
|
3
4
|
import type { HeadingLevelProp } from "../../props/vocabulary/index.js";
|
|
@@ -87,16 +88,21 @@ export declare const CardContent: React.ForwardRefExoticComponent<React.HTMLAttr
|
|
|
87
88
|
export type CardFooterProps = React.HTMLAttributes<HTMLDivElement> & {
|
|
88
89
|
/** Top border + symmetric action band — form Save/Cancel, table summary. */
|
|
89
90
|
separated?: boolean;
|
|
90
|
-
/** Full-bleed footer (
|
|
91
|
+
/** Full-bleed footer (the conventional `actions` bar). */
|
|
91
92
|
flush?: boolean;
|
|
92
93
|
};
|
|
93
94
|
export declare const CardFooter: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & {
|
|
94
95
|
/** Top border + symmetric action band — form Save/Cancel, table summary. */
|
|
95
96
|
separated?: boolean;
|
|
96
|
-
/** Full-bleed footer (
|
|
97
|
+
/** Full-bleed footer (the conventional `actions` bar). */
|
|
97
98
|
flush?: boolean;
|
|
98
99
|
} & React.RefAttributes<HTMLDivElement>>;
|
|
99
100
|
export type CardBarProps = React.HTMLAttributes<HTMLDivElement> & {
|
|
101
|
+
pad?: PadProp;
|
|
102
|
+
padRaw?: PadRawProp;
|
|
103
|
+
gap?: GapProp;
|
|
104
|
+
surface?: "muted";
|
|
105
|
+
border?: "none" | "block-start" | "block-end" | "both";
|
|
100
106
|
/** Right-aligned actions slot (settings/save), Ant `tabBarExtraContent`-style. */
|
|
101
107
|
extra?: React.ReactNode;
|
|
102
108
|
};
|
|
@@ -107,6 +113,11 @@ export type CardBarProps = React.HTMLAttributes<HTMLDivElement> & {
|
|
|
107
113
|
* border is enough).
|
|
108
114
|
*/
|
|
109
115
|
export declare const CardBar: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & {
|
|
116
|
+
pad?: PadProp;
|
|
117
|
+
padRaw?: PadRawProp;
|
|
118
|
+
gap?: GapProp;
|
|
119
|
+
surface?: "muted";
|
|
120
|
+
border?: "none" | "block-start" | "block-end" | "both";
|
|
110
121
|
/** Right-aligned actions slot (settings/save), Ant `tabBarExtraContent`-style. */
|
|
111
122
|
extra?: React.ReactNode;
|
|
112
123
|
} & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -134,6 +145,6 @@ export type StatCardProps = React.HTMLAttributes<HTMLDivElement> & {
|
|
|
134
145
|
};
|
|
135
146
|
/** KPI / stat tile — token-driven layout aligned to dashboard KPI cards. */
|
|
136
147
|
export declare function StatCard({ label, value, hint, icon: Icon, delta, layout, align, inverse, accent, accentPlacement, className, ...props }: StatCardProps): React.JSX.Element;
|
|
137
|
-
/** Header actions slot —
|
|
148
|
+
/** Header actions slot — compose beside CardTitle inside CardHeader; the header owns positioning. */
|
|
138
149
|
export declare const CardAction: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
|
|
139
150
|
export {};
|