@eifi1/ui-kit 0.48.2 → 0.50.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 +34 -16
- package/dist/admin/admin-action-confirm.js +1 -1
- package/dist/admin/admin-action-confirm.js.map +1 -1
- package/dist/admin/invitations-panel.js +5 -1
- package/dist/admin/invitations-panel.js.map +1 -1
- package/dist/admin/user-roster.d.ts +24 -12
- package/dist/admin/user-roster.js +21 -6
- package/dist/admin/user-roster.js.map +1 -1
- package/dist/auth/accept-invitation.js +2 -2
- package/dist/auth/accept-invitation.js.map +1 -1
- package/dist/auth/not-found-page.js +1 -1
- package/dist/auth/not-found-page.js.map +1 -1
- package/dist/auth/reset-password-form.js +2 -2
- package/dist/auth/reset-password-form.js.map +1 -1
- package/dist/auth/verify-email.d.ts +9 -1
- package/dist/auth/verify-email.js +5 -3
- package/dist/auth/verify-email.js.map +1 -1
- package/dist/billing/plan-card.js +2 -2
- package/dist/billing/plan-card.js.map +1 -1
- package/dist/components/amount-input.d.ts +2 -1
- package/dist/components/amount-input.js +3 -2
- package/dist/components/amount-input.js.map +1 -1
- package/dist/components/autocomplete.js +1 -0
- package/dist/components/autocomplete.js.map +1 -1
- package/dist/components/breadcrumbs.d.ts +19 -1
- package/dist/components/breadcrumbs.js +11 -4
- package/dist/components/breadcrumbs.js.map +1 -1
- package/dist/components/button-look.d.ts +37 -7
- package/dist/components/button-look.js +33 -6
- package/dist/components/button-look.js.map +1 -1
- package/dist/components/button.d.ts +4 -1
- package/dist/components/button.js +2 -2
- package/dist/components/button.js.map +1 -1
- package/dist/components/calendar-heatmap.js +2 -1
- package/dist/components/calendar-heatmap.js.map +1 -1
- package/dist/components/chart-edge.d.ts +10 -0
- package/dist/components/chart-edge.js +57 -0
- package/dist/components/chart-edge.js.map +1 -0
- package/dist/components/chart.js +2 -1
- package/dist/components/chart.js.map +1 -1
- package/dist/components/chip.d.ts +8 -1
- package/dist/components/chip.js +4 -1
- package/dist/components/chip.js.map +1 -1
- package/dist/components/combobox-core.js +1 -0
- package/dist/components/combobox-core.js.map +1 -1
- package/dist/components/combobox-suggestions.js +1 -0
- package/dist/components/combobox-suggestions.js.map +1 -1
- package/dist/components/confirm-context.d.ts +5 -0
- package/dist/components/confirm-context.js +7 -0
- package/dist/components/confirm-context.js.map +1 -0
- package/dist/components/confirm-dialog.js +3 -3
- package/dist/components/confirm-dialog.js.map +1 -1
- package/dist/components/currency-select.d.ts +28 -2
- package/dist/components/currency-select.js +56 -10
- package/dist/components/currency-select.js.map +1 -1
- package/dist/components/danger-confirm.d.ts +2 -2
- package/dist/components/danger-confirm.js +1 -1
- package/dist/components/danger-confirm.js.map +1 -1
- package/dist/components/data-table-fit.js +21 -3
- package/dist/components/data-table-fit.js.map +1 -1
- package/dist/components/data-table-mobile.d.ts +58 -3
- package/dist/components/data-table-mobile.js +147 -16
- package/dist/components/data-table-mobile.js.map +1 -1
- package/dist/components/data-table-row-actions.d.ts +2 -1
- package/dist/components/data-table-row-actions.js +7 -0
- package/dist/components/data-table-row-actions.js.map +1 -1
- package/dist/components/data-table-row.d.ts +1 -1
- package/dist/components/data-table-row.js.map +1 -1
- package/dist/components/data-table.d.ts +34 -1
- package/dist/components/data-table.js +37 -10
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/dropdown.js +1 -0
- package/dist/components/dropdown.js.map +1 -1
- package/dist/components/error-boundary.js +2 -2
- package/dist/components/error-boundary.js.map +1 -1
- package/dist/components/floating-panel.d.ts +36 -13
- package/dist/components/floating-panel.js +27 -7
- package/dist/components/floating-panel.js.map +1 -1
- package/dist/components/form-actions.d.ts +1 -1
- package/dist/components/form-actions.js +1 -1
- package/dist/components/form-actions.js.map +1 -1
- package/dist/components/full-bleed-dialog.js +1 -0
- package/dist/components/full-bleed-dialog.js.map +1 -1
- package/dist/components/icon-button.d.ts +11 -0
- package/dist/components/icon-button.js +7 -5
- package/dist/components/icon-button.js.map +1 -1
- package/dist/components/modal.js +1 -0
- package/dist/components/modal.js.map +1 -1
- package/dist/components/nav-pills.d.ts +8 -1
- package/dist/components/nav-pills.js +61 -38
- package/dist/components/nav-pills.js.map +1 -1
- package/dist/components/number-input.d.ts +2 -1
- package/dist/components/number-input.js +6 -2
- package/dist/components/number-input.js.map +1 -1
- package/dist/components/numpad-sheet.js +2 -0
- package/dist/components/numpad-sheet.js.map +1 -1
- package/dist/components/page-header-context.d.ts +8 -0
- package/dist/components/page-header-context.js +7 -0
- package/dist/components/page-header-context.js.map +1 -0
- package/dist/components/page-header.d.ts +14 -2
- package/dist/components/page-header.js +10 -1
- package/dist/components/page-header.js.map +1 -1
- package/dist/components/picker-sheet.js +2 -0
- package/dist/components/picker-sheet.js.map +1 -1
- package/dist/components/pie-chart.js +2 -1
- package/dist/components/pie-chart.js.map +1 -1
- package/dist/components/popover.js +1 -0
- package/dist/components/popover.js.map +1 -1
- package/dist/components/progress-bar.js +5 -4
- package/dist/components/progress-bar.js.map +1 -1
- package/dist/components/reauth-dialog.js +1 -1
- package/dist/components/reauth-dialog.js.map +1 -1
- package/dist/components/row-actions-labels.js +3 -1
- package/dist/components/row-actions-labels.js.map +1 -1
- package/dist/components/row-actions.d.ts +43 -9
- package/dist/components/row-actions.js +78 -15
- package/dist/components/row-actions.js.map +1 -1
- package/dist/components/section-nav.d.ts +37 -0
- package/dist/components/section-nav.js +33 -0
- package/dist/components/section-nav.js.map +1 -0
- package/dist/components/series-chart.js +8 -3
- package/dist/components/series-chart.js.map +1 -1
- package/dist/components/share-card.js +1 -1
- package/dist/components/share-card.js.map +1 -1
- package/dist/components/signature-pad.js +1 -1
- package/dist/components/signature-pad.js.map +1 -1
- package/dist/components/sparkline.js +2 -1
- package/dist/components/sparkline.js.map +1 -1
- package/dist/components/stat-tile.js +14 -7
- package/dist/components/stat-tile.js.map +1 -1
- package/dist/components/status-dot.d.ts +5 -1
- package/dist/components/status-dot.js +4 -1
- package/dist/components/status-dot.js.map +1 -1
- package/dist/components/tooltip.js +1 -1
- package/dist/components/tooltip.js.map +1 -1
- package/dist/components/translation-review-editor.js +2 -2
- package/dist/components/translation-review-editor.js.map +1 -1
- package/dist/components/translation-review.js +2 -2
- package/dist/components/translation-review.js.map +1 -1
- package/dist/components/treemap.d.ts +5 -2
- package/dist/components/treemap.js +26 -6
- package/dist/components/treemap.js.map +1 -1
- package/dist/components/use-table-state.js +37 -6
- package/dist/components/use-table-state.js.map +1 -1
- package/dist/data-table.js.map +1 -1
- package/dist/demo/demo-banner.js +1 -1
- package/dist/demo/demo-banner.js.map +1 -1
- package/dist/demo/demo-ended.js +1 -1
- package/dist/demo/demo-ended.js.map +1 -1
- package/dist/demo/demo-start.js +1 -1
- package/dist/demo/demo-start.js.map +1 -1
- package/dist/eslint/index.js +1 -1
- package/dist/feedback/feedback-inbox.js +1 -1
- package/dist/feedback/feedback-inbox.js.map +1 -1
- package/dist/hooks/use-dismiss.d.ts +9 -1
- package/dist/hooks/use-dismiss.js +25 -5
- package/dist/hooks/use-dismiss.js.map +1 -1
- package/dist/hooks/use-document-title.d.ts +14 -0
- package/dist/hooks/use-document-title.js +22 -0
- package/dist/hooks/use-document-title.js.map +1 -0
- package/dist/i18n/defaults.js +2 -0
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/german.js +20 -3
- package/dist/i18n/german.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +34 -1
- package/dist/i18n/kit-labels.js +43 -2
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/locales/en.js +22 -3
- package/dist/i18n/locales/en.js.map +3 -3
- package/dist/i18n/locales/es.js +20 -3
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.js +20 -3
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.js +20 -3
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.js +20 -3
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.js +20 -3
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/i18n/review.js +3 -0
- package/dist/i18n/review.js.map +1 -1
- package/dist/i18n/shared-labels.js +1 -0
- package/dist/i18n/shared-labels.js.map +1 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/dist/landing/landing-actions.js +2 -2
- package/dist/landing/landing-actions.js.map +1 -1
- package/dist/landing/public-header.js +2 -2
- package/dist/landing/public-header.js.map +1 -1
- package/dist/lib/clipboard-minus.d.ts +27 -0
- package/dist/lib/clipboard-minus.js +63 -0
- package/dist/lib/clipboard-minus.js.map +1 -0
- package/dist/lib/data-attributes.d.ts +11 -0
- package/dist/lib/data-attributes.js +10 -0
- package/dist/lib/data-attributes.js.map +1 -0
- package/dist/lib/document-title.d.ts +17 -0
- package/dist/lib/document-title.js +29 -0
- package/dist/lib/document-title.js.map +1 -0
- package/dist/lib/float-clearance.js +8 -2
- package/dist/lib/float-clearance.js.map +1 -1
- package/dist/lib/format.d.ts +36 -10
- package/dist/lib/format.js +57 -11
- package/dist/lib/format.js.map +1 -1
- package/dist/lib/minus.d.ts +32 -0
- package/dist/lib/minus.js +14 -0
- package/dist/lib/minus.js.map +1 -0
- package/dist/lib/status-tone.d.ts +30 -0
- package/dist/lib/status-tone.js +17 -0
- package/dist/lib/status-tone.js.map +1 -0
- package/dist/settings/settings-layout.js +3 -2
- package/dist/settings/settings-layout.js.map +1 -1
- package/dist/shell/account-menu-language.d.ts +1 -1
- package/dist/shell/account-menu-language.js +9 -1
- package/dist/shell/account-menu-language.js.map +1 -1
- package/dist/shell/app-shell-labels.js +2 -1
- package/dist/shell/app-shell-labels.js.map +1 -1
- package/dist/shell/app-shell.d.ts +58 -16
- package/dist/shell/app-shell.js +151 -43
- package/dist/shell/app-shell.js.map +1 -1
- package/dist/shell/language-code.d.ts +3 -0
- package/dist/shell/language-code.js +8 -0
- package/dist/shell/language-code.js.map +1 -0
- package/dist/shell/topbar-controls.d.ts +14 -6
- package/dist/shell/topbar-controls.js +14 -17
- package/dist/shell/topbar-controls.js.map +1 -1
- package/dist/testing/css-variables.generated.d.ts +1 -1
- package/dist/testing/css-variables.generated.js +1 -1
- package/dist/testing/css-variables.generated.js.map +1 -1
- package/dist/testing/react.d.ts +25 -0
- package/dist/testing/react.js +19 -0
- package/dist/testing/react.js.map +1 -0
- package/dist/theme/chart-palette.d.ts +82 -15
- package/dist/theme/chart-palette.js +51 -24
- package/dist/theme/chart-palette.js.map +1 -1
- package/dist/theme/palette-presets.d.ts +9 -0
- package/dist/theme/palette-presets.js +77 -62
- package/dist/theme/palette-presets.js.map +1 -1
- package/dist/tour/tour-dock.d.ts +42 -0
- package/dist/tour/tour-dock.js +80 -0
- package/dist/tour/tour-dock.js.map +1 -0
- package/dist/tour/tour-gates.d.ts +71 -0
- package/dist/tour/tour-gates.js +114 -0
- package/dist/tour/tour-gates.js.map +1 -0
- package/dist/tour/tour-guide-button.d.ts +27 -0
- package/dist/tour/tour-guide-button.js +45 -0
- package/dist/tour/tour-guide-button.js.map +1 -0
- package/dist/tour/tour-guide-labels.d.ts +8 -0
- package/dist/tour/tour-guide-labels.js +9 -0
- package/dist/tour/tour-guide-labels.js.map +1 -0
- package/dist/tour/tour-labels.js +9 -1
- package/dist/tour/tour-labels.js.map +1 -1
- package/dist/tour/tour.d.ts +133 -9
- package/dist/tour/tour.js +594 -70
- package/dist/tour/tour.js.map +1 -1
- package/dist/tour/use-tour-url-sync.d.ts +5 -2
- package/dist/tour/use-tour-url-sync.js +7 -1
- package/dist/tour/use-tour-url-sync.js.map +1 -1
- package/dist/tour.d.ts +2 -0
- package/dist/tour.js +3 -0
- package/dist/tour.js.map +1 -1
- package/dist/wizard/stepper-nav.d.ts +1 -1
- package/dist/wizard/stepper-nav.js +18 -5
- package/dist/wizard/stepper-nav.js.map +1 -1
- package/dist/wizard/types.d.ts +11 -0
- package/dist/wizard/types.js.map +1 -1
- package/dist/wizard/use-wizard.js +11 -5
- package/dist/wizard/use-wizard.js.map +1 -1
- package/package.json +9 -1
- package/src/admin/admin-action-confirm.tsx +1 -1
- package/src/admin/invitations-panel.tsx +7 -3
- package/src/admin/user-roster.tsx +41 -14
- package/src/auth/accept-invitation.tsx +3 -3
- package/src/auth/not-found-page.tsx +1 -1
- package/src/auth/reset-password-form.tsx +3 -3
- package/src/auth/verify-email.tsx +13 -3
- package/src/billing/plan-card.tsx +2 -2
- package/src/components/amount-input.tsx +5 -4
- package/src/components/autocomplete.tsx +2 -0
- package/src/components/breadcrumbs.tsx +32 -4
- package/src/components/button-look.ts +86 -15
- package/src/components/button.tsx +6 -3
- package/src/components/calendar-heatmap.tsx +2 -1
- package/src/components/chart-edge.ts +73 -0
- package/src/components/chart.tsx +3 -1
- package/src/components/chip.tsx +10 -1
- package/src/components/combobox-core.tsx +2 -0
- package/src/components/combobox-suggestions.tsx +2 -0
- package/src/components/confirm-context.ts +7 -0
- package/src/components/confirm-dialog.tsx +3 -3
- package/src/components/currency-select.tsx +95 -6
- package/src/components/danger-confirm.tsx +3 -3
- package/src/components/data-table-fit.ts +41 -6
- package/src/components/data-table-mobile.tsx +259 -17
- package/src/components/data-table-row-actions.tsx +9 -1
- package/src/components/data-table-row.tsx +3 -0
- package/src/components/data-table.tsx +91 -19
- package/src/components/dropdown.tsx +2 -0
- package/src/components/error-boundary.tsx +2 -2
- package/src/components/floating-panel.tsx +67 -16
- package/src/components/form-actions.tsx +2 -2
- package/src/components/full-bleed-dialog.tsx +3 -0
- package/src/components/icon-button.tsx +21 -8
- package/src/components/modal.tsx +3 -0
- package/src/components/nav-pills.tsx +29 -2
- package/src/components/number-input.tsx +8 -3
- package/src/components/numpad-sheet.tsx +4 -0
- package/src/components/page-header-context.ts +8 -0
- package/src/components/page-header.tsx +34 -2
- package/src/components/picker-sheet.tsx +4 -0
- package/src/components/pie-chart.tsx +2 -1
- package/src/components/popover.tsx +2 -0
- package/src/components/progress-bar.tsx +6 -3
- package/src/components/reauth-dialog.tsx +1 -1
- package/src/components/row-actions-labels.ts +2 -0
- package/src/components/row-actions.tsx +154 -33
- package/src/components/section-nav.tsx +65 -0
- package/src/components/series-chart.tsx +12 -3
- package/src/components/share-card.tsx +1 -1
- package/src/components/signature-pad.tsx +1 -1
- package/src/components/sparkline.tsx +2 -1
- package/src/components/stat-tile.tsx +19 -7
- package/src/components/status-dot.tsx +7 -1
- package/src/components/tooltip.tsx +3 -1
- package/src/components/translation-review-editor.tsx +2 -2
- package/src/components/translation-review.tsx +2 -2
- package/src/components/treemap.tsx +34 -8
- package/src/components/use-table-state.ts +63 -8
- package/src/data-table.ts +3 -3
- package/src/demo/demo-banner.tsx +1 -1
- package/src/demo/demo-ended.tsx +1 -1
- package/src/demo/demo-start.tsx +1 -1
- package/src/feedback/feedback-inbox.tsx +1 -1
- package/src/hooks/use-dismiss.ts +43 -4
- package/src/hooks/use-document-title.ts +31 -0
- package/src/i18n/defaults.ts +2 -0
- package/src/i18n/german.ts +17 -0
- package/src/i18n/kit-labels.tsx +79 -1
- package/src/i18n/locales/es.ts +17 -0
- package/src/i18n/locales/fr.ts +17 -0
- package/src/i18n/locales/hu.ts +17 -0
- package/src/i18n/locales/it.ts +17 -0
- package/src/i18n/locales/zh.ts +17 -0
- package/src/i18n/review.ts +3 -0
- package/src/i18n/shared-labels.ts +1 -0
- package/src/index.ts +13 -0
- package/src/landing/landing-actions.tsx +2 -2
- package/src/landing/public-header.tsx +2 -2
- package/src/lib/clipboard-minus.ts +94 -0
- package/src/lib/data-attributes.ts +14 -0
- package/src/lib/document-title.ts +41 -0
- package/src/lib/float-clearance.ts +19 -3
- package/src/lib/format.ts +117 -30
- package/src/lib/minus.ts +50 -0
- package/src/lib/status-tone.ts +43 -0
- package/src/settings/settings-layout.tsx +3 -2
- package/src/shell/account-menu-language.tsx +14 -2
- package/src/shell/app-shell-labels.ts +1 -0
- package/src/shell/app-shell.tsx +291 -68
- package/src/shell/language-code.ts +5 -0
- package/src/shell/topbar-controls.tsx +35 -15
- package/src/testing/css-variables.generated.ts +6 -6
- package/src/testing/react.ts +59 -0
- package/src/theme/chart-palette.ts +102 -20
- package/src/theme/palette-presets.ts +121 -84
- package/src/tour/tour-dock.ts +132 -0
- package/src/tour/tour-gates.ts +195 -0
- package/src/tour/tour-guide-button.tsx +64 -0
- package/src/tour/tour-guide-labels.ts +15 -0
- package/src/tour/tour-labels.ts +8 -0
- package/src/tour/tour.tsx +949 -86
- package/src/tour/use-tour-url-sync.ts +14 -4
- package/src/tour.ts +3 -0
- package/src/wizard/stepper-nav.tsx +27 -7
- package/src/wizard/types.ts +12 -0
- package/src/wizard/use-wizard.ts +16 -9
- package/tokens.css +28 -18
|
@@ -12,12 +12,14 @@ import { useLayoutEffect, useRef, useState, useSyncExternalStore } from "react";
|
|
|
12
12
|
import type { ComponentProps, ComponentPropsWithoutRef, KeyboardEvent, ReactNode } from "react";
|
|
13
13
|
import { Treemap as RechartsTreemap } from "recharts";
|
|
14
14
|
import { ChartContainer, ChartTooltip, ChartTooltipContent, type ChartConfig } from "./chart";
|
|
15
|
-
import { PALETTE_HEX, textOn } from "../theme/chart-palette";
|
|
15
|
+
import { PALETTE_HEX, PALETTE_SIZE, textOn } from "../theme/chart-palette";
|
|
16
|
+
import { resolveChartColor, useChartEdge } from "./chart-edge";
|
|
16
17
|
import { parseHex } from "../theme/color";
|
|
17
18
|
import { dirOf, type Direction } from "../lib/direction";
|
|
18
19
|
import { cn } from "../lib/cn";
|
|
19
20
|
import { useTextSize } from "../theme/text-size";
|
|
20
21
|
import { chartHeightProps, type ChartHeight } from "./chart-height";
|
|
22
|
+
import { formatWithMinus } from "../lib/minus";
|
|
21
23
|
|
|
22
24
|
/**
|
|
23
25
|
* One tile.
|
|
@@ -39,7 +41,9 @@ export interface TreemapNode {
|
|
|
39
41
|
value: number;
|
|
40
42
|
/** Overrides the by-index palette colour for this tile — e.g. to paint every child
|
|
41
43
|
* in its parent group's colour, so the groups stay legible in one picture. A
|
|
42
|
-
* concrete `#rrggbb` or a bare `var(--chart-N)` keeps the label ink measured
|
|
44
|
+
* concrete `#rrggbb` or a bare `var(--chart-N)` keeps the label ink measured — so
|
|
45
|
+
* does `CHART_ROLES.other` (`var(--chart-muted)`), the colour for a "rest" bucket,
|
|
46
|
+
* which should not wrap round to a hue the reader matches to a real node;
|
|
43
47
|
* anything else (another var, a `color-mix()`) gets `currentColor` ink, because
|
|
44
48
|
* there is nothing to measure — set `labelColor` then. */
|
|
45
49
|
fill?: string;
|
|
@@ -101,7 +105,8 @@ export interface TreemapProps extends Omit<ComponentPropsWithoutRef<"div">, "chi
|
|
|
101
105
|
maxTiles?: number;
|
|
102
106
|
/**
|
|
103
107
|
* The categorical ramp tiles take by index, as concrete hex. Default: the page's
|
|
104
|
-
* live `--chart-1…
|
|
108
|
+
* live `--chart-1…8` tokens (see `useChartTokenHex`), cycled after eight like
|
|
109
|
+
* `paletteFor` (0.49). Pass one when the host
|
|
105
110
|
* already holds the active palette — e.g. `createPaletteStore`'s `useChartHex()` —
|
|
106
111
|
* so a caller colouring a legend beside the map is guaranteed the same list.
|
|
107
112
|
*/
|
|
@@ -119,7 +124,7 @@ export interface TreemapProps extends Omit<ComponentPropsWithoutRef<"div">, "chi
|
|
|
119
124
|
// re-read whenever <html>'s class or style changes — which is exactly when a theme
|
|
120
125
|
// toggle or a palette switch lands.
|
|
121
126
|
|
|
122
|
-
const CHART_TOKENS =
|
|
127
|
+
const CHART_TOKENS = PALETTE_SIZE;
|
|
123
128
|
|
|
124
129
|
/** The resolved ramp, joined into ONE string so `useSyncExternalStore` compares a
|
|
125
130
|
* primitive: a fresh array per read would never be `Object.is`-equal to the last and
|
|
@@ -163,9 +168,12 @@ const CHART_TOKEN_REF = /^var\(\s*--chart-(\d+)\s*\)$/;
|
|
|
163
168
|
function measurableFill(fill: string, tokens: readonly string[]): string | null {
|
|
164
169
|
if (parseHex(fill)) return fill;
|
|
165
170
|
const m = CHART_TOKEN_REF.exec(fill.trim());
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
171
|
+
const hex = m ? tokens[Number(m[1]) - 1] : undefined;
|
|
172
|
+
if (hex && parseHex(hex)) return hex;
|
|
173
|
+
// Any other bare token the page declares — `var(--chart-muted)` for a rest bucket,
|
|
174
|
+
// `var(--chart-9)`, a money colour — read off <html> as it resolves.
|
|
175
|
+
if (typeof document === "undefined") return null;
|
|
176
|
+
return resolveChartColor(fill, getComputedStyle(document.documentElement));
|
|
169
177
|
}
|
|
170
178
|
|
|
171
179
|
// ── Tile ──────────────────────────────────────────────────────────────────
|
|
@@ -241,6 +249,7 @@ export function TreemapCell({
|
|
|
241
249
|
// Before the early return: a hook has to run on every render of the cell.
|
|
242
250
|
const tokenHex = useChartTokenHex();
|
|
243
251
|
const { scale } = useTextSize();
|
|
252
|
+
const edgeFor = useChartEdge();
|
|
244
253
|
// Depth 0 is recharts' synthetic root, which spans the whole chart.
|
|
245
254
|
if (!depth) return null;
|
|
246
255
|
// Whole pixels: a rect on a half pixel renders its edge across two half-lit
|
|
@@ -252,6 +261,9 @@ export function TreemapCell({
|
|
|
252
261
|
const tileFill = fill ?? "var(--chart-1)";
|
|
253
262
|
const measured = measurableFill(tileFill, tokenHex);
|
|
254
263
|
const ink = labelColor ?? (measured ? textOn(measured) : "currentColor");
|
|
264
|
+
// A tile in a hue under 3:1 against the card gets a 1px ink edge inside the gutter
|
|
265
|
+
// (WCAG 1.4.11, anyplot's rule); a hue that clears it stays bare.
|
|
266
|
+
const edge = measured ? edgeFor(measured) : undefined;
|
|
255
267
|
// The halo only on an OPAQUE fill we could measure. A translucent fill (a
|
|
256
268
|
// `color-mix(… transparent)`) composited twice — once as the tile, once as the halo
|
|
257
269
|
// over it — draws a darker ring round every glyph, which read as doubled text on the
|
|
@@ -310,6 +322,20 @@ export function TreemapCell({
|
|
|
310
322
|
strokeWidth={2}
|
|
311
323
|
rx={3}
|
|
312
324
|
/>
|
|
325
|
+
{edge && pw > 3 && ph > 3 && (
|
|
326
|
+
<rect
|
|
327
|
+
data-edge=""
|
|
328
|
+
x={px + 1.5}
|
|
329
|
+
y={py + 1.5}
|
|
330
|
+
width={pw - 3}
|
|
331
|
+
height={ph - 3}
|
|
332
|
+
fill="none"
|
|
333
|
+
stroke={edge}
|
|
334
|
+
strokeWidth={1}
|
|
335
|
+
rx={2}
|
|
336
|
+
style={{ pointerEvents: "none" }}
|
|
337
|
+
/>
|
|
338
|
+
)}
|
|
313
339
|
{label != null && (
|
|
314
340
|
<text
|
|
315
341
|
// A plain attribute, so the host's `[data-private]` rule reaches an SVG
|
|
@@ -437,7 +463,7 @@ export function Treemap({
|
|
|
437
463
|
const total = nodes.reduce((acc, n) => acc + n.size, 0);
|
|
438
464
|
const format = (v: number): ReactNode => {
|
|
439
465
|
const share = total > 0 ? v / total : undefined;
|
|
440
|
-
return valueFormatter ? valueFormatter(v, share) : DEFAULT_NUMBER
|
|
466
|
+
return valueFormatter ? valueFormatter(v, share) : formatWithMinus(DEFAULT_NUMBER, v);
|
|
441
467
|
};
|
|
442
468
|
const Content = redactNames ? RedactedTooltipContent : ChartTooltipContent;
|
|
443
469
|
return (
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
2
|
import type { SetStateAction } from "react";
|
|
3
|
+
import * as ReactRouter from "react-router";
|
|
3
4
|
import { useLocation, useSearchParams } from "react-router";
|
|
4
5
|
import { useKitTableStorageKeyPrefix } from "../i18n/kit-labels";
|
|
5
6
|
import { readStored, writeStored } from "../lib/safe-storage";
|
|
@@ -103,6 +104,62 @@ function urlKeys(prefix = ""): UrlKeys {
|
|
|
103
104
|
};
|
|
104
105
|
}
|
|
105
106
|
|
|
107
|
+
/** What a table reads and writes the URL through: react-router's, or none. */
|
|
108
|
+
interface TableSearch {
|
|
109
|
+
searchParams: URLSearchParams;
|
|
110
|
+
setSearchParams: ReturnType<typeof useSearchParams>[1];
|
|
111
|
+
locationState: unknown;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function useRouterSearch(): TableSearch {
|
|
115
|
+
const [searchParams, setSearchParams] = useSearchParams();
|
|
116
|
+
const location = useLocation();
|
|
117
|
+
return { searchParams, setSearchParams, locationState: location.state };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const NO_ROUTER_SEARCH: TableSearch = {
|
|
121
|
+
searchParams: new URLSearchParams(),
|
|
122
|
+
setSearchParams: () => {},
|
|
123
|
+
locationState: null,
|
|
124
|
+
};
|
|
125
|
+
function useNoRouterSearch(): TableSearch {
|
|
126
|
+
return NO_ROUTER_SEARCH;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* `useInRouterContext`, read off the namespace inside a `try` like
|
|
131
|
+
* use-search-param-state's probe: a test's `vi.mock("react-router", () => ({ … }))`
|
|
132
|
+
* without it throws on the read. Missing, a table assumes a Router, as before 0.49.
|
|
133
|
+
*/
|
|
134
|
+
function readInRouterContext(): () => boolean {
|
|
135
|
+
try {
|
|
136
|
+
return (ReactRouter as unknown as { useInRouterContext?: () => boolean }).useInRouterContext ?? (() => true);
|
|
137
|
+
} catch {
|
|
138
|
+
return () => true;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const useInRouterContext = readInRouterContext();
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* The URL access a table needs (0.49, KIT-3). Without `urlSync` a table needs no Router:
|
|
145
|
+
* before 0.49 it called `useSearchParams()` unconditionally and threw outside one even
|
|
146
|
+
* with URL sync off. With `urlSync` and no Router, a development build throws a message
|
|
147
|
+
* that names the fix; a production build keeps the view in local state rather than
|
|
148
|
+
* crash the page. Whether a Router is around does not change during a table's life, so
|
|
149
|
+
* which hook runs is stable from render to render.
|
|
150
|
+
*/
|
|
151
|
+
function useTableSearch(urlSync: boolean, owner: string): TableSearch {
|
|
152
|
+
const inRouter = useInRouterContext();
|
|
153
|
+
if (!inRouter && urlSync && import.meta.env?.DEV) {
|
|
154
|
+
throw new Error(
|
|
155
|
+
`${owner} urlSync requires a Router: render it inside a react-router Router ` +
|
|
156
|
+
"(BrowserRouter, a data router or a MemoryRouter), or leave urlSync off.",
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
const useSearch = inRouter ? useRouterSearch : useNoRouterSearch;
|
|
160
|
+
return useSearch();
|
|
161
|
+
}
|
|
162
|
+
|
|
106
163
|
/** `urlSync` split into "is it on" and "under which prefix". */
|
|
107
164
|
function resolveTableUrlSync(urlSync: TableUrlSync | undefined): { enabled: boolean; prefix: string } {
|
|
108
165
|
if (!urlSync) return { enabled: false, prefix: "" };
|
|
@@ -295,10 +352,9 @@ export function useTableState<T>({
|
|
|
295
352
|
}) {
|
|
296
353
|
const { enabled: urlSync, prefix: urlPrefix } = resolveTableUrlSync(urlSyncOption);
|
|
297
354
|
const keys = useMemo(() => urlKeys(urlPrefix), [urlPrefix]);
|
|
298
|
-
//
|
|
299
|
-
//
|
|
300
|
-
const
|
|
301
|
-
const location = useLocation();
|
|
355
|
+
// The SAME pair is used to read and to write; see `readTableUrlState`. No Router is
|
|
356
|
+
// needed without `urlSync` (0.49, KIT-3; see `useTableSearch`).
|
|
357
|
+
const { searchParams, setSearchParams, locationState } = useTableSearch(urlSync, "DataTable");
|
|
302
358
|
// Read URL once on mount so URL-encoded views (e.g. shared links, deep links from
|
|
303
359
|
// other pages) populate initial state. After mount, state is local.
|
|
304
360
|
const [urlInitial] = useState<TableUrlState>(() =>
|
|
@@ -436,7 +492,7 @@ export function useTableState<T>({
|
|
|
436
492
|
// `columns` is deliberately not a dependency and does not need to be: the
|
|
437
493
|
// signature above is computed from it, so a column set that would produce a
|
|
438
494
|
// different address produces a different signature first.
|
|
439
|
-
writeUrlState(setSearchParams, columns, sorts, filters, pageSize, page, defaultPageSize, undefined,
|
|
495
|
+
writeUrlState(setSearchParams, columns, sorts, filters, pageSize, page, defaultPageSize, undefined, locationState, keys);
|
|
440
496
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
441
497
|
}, [urlSync, urlSig]);
|
|
442
498
|
|
|
@@ -620,8 +676,7 @@ export function useTableUrlState<T>({
|
|
|
620
676
|
const urlSync = resolved.enabled;
|
|
621
677
|
const urlPrefix = urlPrefixOption ?? resolved.prefix;
|
|
622
678
|
const keys = useMemo(() => urlKeys(urlPrefix), [urlPrefix]);
|
|
623
|
-
const
|
|
624
|
-
const location = useLocation();
|
|
679
|
+
const { searchParams, setSearchParams, locationState } = useTableSearch(urlSync, "useTableUrlState");
|
|
625
680
|
const [state, setState] = useState<OwnedState>(() => {
|
|
626
681
|
const url = urlSync ? readTableUrlState(searchParams, columns, urlPrefix) : {};
|
|
627
682
|
return {
|
|
@@ -653,7 +708,7 @@ export function useTableUrlState<T>({
|
|
|
653
708
|
state.page,
|
|
654
709
|
defaultPageSize,
|
|
655
710
|
manageSearch ? state.search : undefined,
|
|
656
|
-
|
|
711
|
+
locationState,
|
|
657
712
|
keys,
|
|
658
713
|
);
|
|
659
714
|
// Keyed on the signature, which is computed from everything the write reads — see
|
package/src/data-table.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// `@eifi1/ui-kit/data-table` — the table suite.
|
|
2
2
|
//
|
|
3
|
-
// A re-slicing of the main barrel, not a new API. This entry point
|
|
4
|
-
// `react-router
|
|
5
|
-
//
|
|
3
|
+
// A re-slicing of the main barrel, not a new API. This entry point imports
|
|
4
|
+
// `react-router` (a peer dependency), but since 0.49 (KIT-3) a Router is needed only for
|
|
5
|
+
// a table with `urlSync`: without it DataTable keeps its view in local state alone.
|
|
6
6
|
export * from "./components/data-table-labels";
|
|
7
7
|
export * from "./components/data-table-sort";
|
|
8
8
|
export * from "./components/data-table-filters";
|
package/src/demo/demo-banner.tsx
CHANGED
|
@@ -116,7 +116,7 @@ export function DemoBanner({
|
|
|
116
116
|
<>
|
|
117
117
|
{!collapsed && (
|
|
118
118
|
<>
|
|
119
|
-
<Button href={accessLink.href} variant="
|
|
119
|
+
<Button href={accessLink.href} variant="accent" size="sm">
|
|
120
120
|
{accessLink.label}
|
|
121
121
|
</Button>
|
|
122
122
|
<Button href={signInHref} variant="secondary" size="sm">
|
package/src/demo/demo-ended.tsx
CHANGED
|
@@ -75,7 +75,7 @@ export function DemoEnded({
|
|
|
75
75
|
</p>
|
|
76
76
|
{children}
|
|
77
77
|
<div className="mt-4 flex w-full flex-col gap-2 sm:w-auto sm:flex-row sm:flex-wrap sm:justify-center">
|
|
78
|
-
<Button href={restartHref} variant="
|
|
78
|
+
<Button href={restartHref} variant="accent">
|
|
79
79
|
{labels.restart}
|
|
80
80
|
</Button>
|
|
81
81
|
<Button href={accessLink.href} variant="secondary">
|
package/src/demo/demo-start.tsx
CHANGED
|
@@ -139,7 +139,7 @@ export function DemoStart<T>({
|
|
|
139
139
|
</div>
|
|
140
140
|
{refusal !== null && (
|
|
141
141
|
<div className="flex flex-wrap justify-center gap-3">
|
|
142
|
-
<Button href={accessLink.href} variant="
|
|
142
|
+
<Button href={accessLink.href} variant="accent">
|
|
143
143
|
{accessLink.label}
|
|
144
144
|
</Button>
|
|
145
145
|
<Button href={backHref} variant="secondary">
|
|
@@ -469,7 +469,7 @@ export function FeedbackNoteEditor({
|
|
|
469
469
|
<Button variant="ghost" onClick={onCancel}>
|
|
470
470
|
{cancelLabel}
|
|
471
471
|
</Button>
|
|
472
|
-
<Button variant="
|
|
472
|
+
<Button variant="accent" disabled={pending || blank} commit={commit} onClick={submit}>
|
|
473
473
|
{saveLabel}
|
|
474
474
|
</Button>
|
|
475
475
|
</div>
|
package/src/hooks/use-dismiss.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useCallback, useEffect, useRef } from "react";
|
|
1
|
+
import { useCallback, useEffect, useRef, useSyncExternalStore } from "react";
|
|
2
2
|
import type { KeyboardEvent as ReactKeyboardEvent, RefObject } from "react";
|
|
3
3
|
import { isComposing } from "../lib/ime";
|
|
4
4
|
|
|
@@ -60,6 +60,9 @@ import { isComposing } from "../lib/ime";
|
|
|
60
60
|
/** A layer's handler, read through a ref so the stack holds one stable entry per open. */
|
|
61
61
|
interface Layer {
|
|
62
62
|
escape: (e: KeyboardEvent) => void;
|
|
63
|
+
/** Whether it covers the page — a dialog, a sheet, a popover, a list — rather than
|
|
64
|
+
* annotating it (a tooltip). Counted by {@link useOverlayOpen}. */
|
|
65
|
+
overlay: boolean;
|
|
63
66
|
}
|
|
64
67
|
|
|
65
68
|
/** What {@link useDismissLayer} hands back: its layer while open, for
|
|
@@ -114,11 +117,13 @@ function push(layer: Layer): void {
|
|
|
114
117
|
document.addEventListener("keydown", onBubble);
|
|
115
118
|
}
|
|
116
119
|
layers.push(layer);
|
|
120
|
+
if (layer.overlay) notifyOverlays();
|
|
117
121
|
}
|
|
118
122
|
|
|
119
123
|
function pop(layer: Layer): void {
|
|
120
124
|
const at = layers.indexOf(layer);
|
|
121
125
|
if (at >= 0) layers.splice(at, 1);
|
|
126
|
+
if (at >= 0 && layer.overlay) notifyOverlays();
|
|
122
127
|
if (layers.length > 0) return;
|
|
123
128
|
document.removeEventListener("keydown", onCapture, true);
|
|
124
129
|
document.removeEventListener("keydown", onBubble);
|
|
@@ -135,7 +140,11 @@ function pop(layer: Layer): void {
|
|
|
135
140
|
* read live, so it need not be memoised; the layer is pushed and popped only when
|
|
136
141
|
* `open` flips. The layer it returns is for the owner's {@link runOwnKeyDown}.
|
|
137
142
|
*/
|
|
138
|
-
export function useDismissLayer(
|
|
143
|
+
export function useDismissLayer(
|
|
144
|
+
open: boolean,
|
|
145
|
+
onEscape: (e: KeyboardEvent) => void,
|
|
146
|
+
{ overlay = true }: { overlay?: boolean } = {},
|
|
147
|
+
): DismissLayer {
|
|
139
148
|
const handlerRef = useRef(onEscape);
|
|
140
149
|
const layerRef = useRef<Layer | null>(null);
|
|
141
150
|
// Written in an effect, not during render, so it satisfies react-hooks/refs: a
|
|
@@ -148,17 +157,47 @@ export function useDismissLayer(open: boolean, onEscape: (e: KeyboardEvent) => v
|
|
|
148
157
|
});
|
|
149
158
|
useEffect(() => {
|
|
150
159
|
if (!open || typeof document === "undefined") return;
|
|
151
|
-
const layer: Layer = { escape: (e) => handlerRef.current(e) };
|
|
160
|
+
const layer: Layer = { escape: (e) => handlerRef.current(e), overlay };
|
|
152
161
|
layerRef.current = layer;
|
|
153
162
|
push(layer);
|
|
154
163
|
return () => {
|
|
155
164
|
pop(layer);
|
|
156
165
|
layerRef.current = null;
|
|
157
166
|
};
|
|
158
|
-
}, [open]);
|
|
167
|
+
}, [open, overlay]);
|
|
159
168
|
return layerRef;
|
|
160
169
|
}
|
|
161
170
|
|
|
171
|
+
/*
|
|
172
|
+
* Whether an overlay is open (0.49 KIT-11): every layer on the stack but a tooltip's is a
|
|
173
|
+
* dialog, a sheet, a popover, a hover menu or a list covering part of the page, so the
|
|
174
|
+
* stack is also the one place that knows. The floating launchers (`hideWhenOverlay`) step
|
|
175
|
+
* aside while one is open instead of floating over it or beside it.
|
|
176
|
+
*/
|
|
177
|
+
const overlayListeners = new Set<() => void>();
|
|
178
|
+
|
|
179
|
+
function notifyOverlays(): void {
|
|
180
|
+
for (const listener of overlayListeners) listener();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function subscribeOverlays(listener: () => void): () => void {
|
|
184
|
+
overlayListeners.add(listener);
|
|
185
|
+
return () => {
|
|
186
|
+
overlayListeners.delete(listener);
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function anyOverlayOpen(): boolean {
|
|
191
|
+
return layers.some((layer) => layer.overlay);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/** True while a kit dialog, sheet, popover, hover menu or list is open (any layer of the
|
|
195
|
+
* Escape stack but a tooltip's). Internal. */
|
|
196
|
+
export function useOverlayOpen(enabled = true): boolean {
|
|
197
|
+
const open = useSyncExternalStore(subscribeOverlays, anyOverlayOpen, () => false);
|
|
198
|
+
return enabled && open;
|
|
199
|
+
}
|
|
200
|
+
|
|
162
201
|
/**
|
|
163
202
|
* For a layer's own element, in its `onKeyDown`: hands an Escape on its way up to the
|
|
164
203
|
* topmost layer — this one, unless something opened over it without taking focus (a
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useEffect } from "react";
|
|
2
|
+
import { useKitDocumentTitle } from "../i18n/kit-labels";
|
|
3
|
+
import { DEFAULT_DOCUMENT_TITLE_FORMAT, formatDocumentTitle } from "../lib/document-title";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Writes the window's title (`document.title`) while the calling component is mounted,
|
|
7
|
+
* and puts back the title it found when it unmounts (0.49 KIT-9).
|
|
8
|
+
*
|
|
9
|
+
* `parts` are positional: `[page, section, app]`. The app falls back to the provider's
|
|
10
|
+
* `appName`, the format to the provider's `documentTitleFormat` (default
|
|
11
|
+
* "{page} · {section} · {app}"); a missing part drops with its separator
|
|
12
|
+
* ({@link formatDocumentTitle}). Parts that are ALL empty write nothing — the provider's
|
|
13
|
+
* app alone is not a page's title.
|
|
14
|
+
*
|
|
15
|
+
* `PageHeader` calls it for its `h1` (`documentTitle`); call it yourself for a page
|
|
16
|
+
* without one.
|
|
17
|
+
*/
|
|
18
|
+
export function useDocumentTitle(parts: ReadonlyArray<string | null | undefined | false>): void {
|
|
19
|
+
const { format, appName } = useKitDocumentTitle();
|
|
20
|
+
const [page, section, app] = parts.map((p) => (typeof p === "string" && p.trim() !== "" ? p : undefined));
|
|
21
|
+
const any = parts.some((p) => typeof p === "string" && p.trim() !== "");
|
|
22
|
+
const title = any ? formatDocumentTitle(format ?? DEFAULT_DOCUMENT_TITLE_FORMAT, { page, section, app: app ?? appName }) : null;
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
if (title === null || title === "") return;
|
|
25
|
+
const before = document.title;
|
|
26
|
+
document.title = title;
|
|
27
|
+
return () => {
|
|
28
|
+
document.title = before;
|
|
29
|
+
};
|
|
30
|
+
}, [title]);
|
|
31
|
+
}
|
package/src/i18n/defaults.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
import { DEFAULT_WIZARD_LABELS } from "../wizard/wizard-labels";
|
|
15
15
|
import { DEFAULT_TOUR_LABELS } from "../tour/tour-labels";
|
|
16
16
|
import { DEFAULT_TOUR_CATALOGUE_LABELS } from "../tour/tour-catalogue-labels";
|
|
17
|
+
import { DEFAULT_TOUR_GUIDE_LABELS } from "../tour/tour-guide-labels";
|
|
17
18
|
import { DEFAULT_COMMAND_PALETTE_LABELS } from "../search/command-palette-labels";
|
|
18
19
|
import { DEFAULT_GLOBAL_SEARCH_LABELS } from "../search/global-search-labels";
|
|
19
20
|
import { DEFAULT_SERIES_CHART_LABELS } from "../components/series-chart-labels";
|
|
@@ -173,6 +174,7 @@ export const DEFAULT_UI_KIT_LABELS: UiKitLabels = {
|
|
|
173
174
|
wizard: DEFAULT_WIZARD_LABELS,
|
|
174
175
|
tour: DEFAULT_TOUR_LABELS,
|
|
175
176
|
tourCatalogue: DEFAULT_TOUR_CATALOGUE_LABELS,
|
|
177
|
+
tourGuide: DEFAULT_TOUR_GUIDE_LABELS,
|
|
176
178
|
commandPalette: DEFAULT_COMMAND_PALETTE_LABELS,
|
|
177
179
|
globalSearch: DEFAULT_GLOBAL_SEARCH_LABELS,
|
|
178
180
|
seriesChart: DEFAULT_SERIES_CHART_LABELS,
|
package/src/i18n/german.ts
CHANGED
|
@@ -556,6 +556,7 @@ export function germanLabels(numberLocale: string): UiKitLabels {
|
|
|
556
556
|
theme: "Theme wechseln",
|
|
557
557
|
palette: "Darstellungsvorlage",
|
|
558
558
|
language: "Sprache",
|
|
559
|
+
languageCurrent: (name) => `Sprache wählen, aktuell: ${name}`,
|
|
559
560
|
switchRole: "Rolle wechseln",
|
|
560
561
|
role: (value) => `Rolle: ${value}`,
|
|
561
562
|
},
|
|
@@ -633,6 +634,19 @@ export function germanLabels(numberLocale: string): UiKitLabels {
|
|
|
633
634
|
awaitClickHint: "Klicken Sie auf das hervorgehobene Element, um fortzufahren",
|
|
634
635
|
awaitInputHint: "Geben Sie im hervorgehobenen Feld einen Wert ein, um fortzufahren", // 0.46: TourStep.awaitInput (keksdose live #436).
|
|
635
636
|
step: (current, total) => `${n(current)} / ${n(total)}`,
|
|
637
|
+
// 0.50: guided form tours (docs/tours-harmonization.md §11).
|
|
638
|
+
leaveEmpty: "Leer lassen",
|
|
639
|
+
optional: "Optional",
|
|
640
|
+
gateHint: "Füllen Sie das hervorgehobene Feld aus, um fortzufahren",
|
|
641
|
+
gateReady: "Bereit. Drücken Sie Weiter oder die Eingabetaste, um fortzufahren.",
|
|
642
|
+
awaitGateHint: "Speichern Sie, um fortzufahren",
|
|
643
|
+
awaitGateRefused: "Das ist noch nicht gespeichert. Prüfen Sie das Formular und versuchen Sie es erneut.",
|
|
644
|
+
backToStep: (title) => `Zurück zu „${title}“`,
|
|
645
|
+
},
|
|
646
|
+
// 0.50: the form's "Guide me" (TourGuideButton, docs/tours-harmonization.md §11).
|
|
647
|
+
tourGuide: {
|
|
648
|
+
label: "Schritt für Schritt",
|
|
649
|
+
description: "Führt Sie Feld für Feld durch dieses Formular",
|
|
636
650
|
},
|
|
637
651
|
// 0.43.0 — docs/tours-harmonization.md §3, §8: the tours page. keksdose's reviewed words.
|
|
638
652
|
tourCatalogue: {
|
|
@@ -1929,10 +1943,13 @@ export function germanLabels(numberLocale: string): UiKitLabels {
|
|
|
1929
1943
|
rowActions: {
|
|
1930
1944
|
actions: "Aktionen",
|
|
1931
1945
|
actionsFor: (name) => `Aktionen für ${name}`,
|
|
1946
|
+
confirmTitle: (action, name) => (name ? `${action}: «${name}»?` : `${action}?`),
|
|
1947
|
+
confirmBody: "Das lässt sich nicht rückgängig machen.",
|
|
1932
1948
|
},
|
|
1933
1949
|
appShellMore: {
|
|
1934
1950
|
more: "Mehr",
|
|
1935
1951
|
moreTitle: "Weitere Seiten",
|
|
1952
|
+
overview: "Übersicht",
|
|
1936
1953
|
},
|
|
1937
1954
|
// 0.42.0 — docs/admin-harmonization.md §3.1: the admin area's shared words. "Verwaltung"
|
|
1938
1955
|
// as settings §5 names the page; "mit Administratorrechten" rather than "für
|
package/src/i18n/kit-labels.tsx
CHANGED
|
@@ -26,6 +26,7 @@ import type { TabsLabels } from "../components/tabs";
|
|
|
26
26
|
import type { WizardLabels } from "../wizard/types";
|
|
27
27
|
import type { TourLabels } from "../tour/tour";
|
|
28
28
|
import type { TourCatalogueLabels } from "../tour/tour-catalogue-labels";
|
|
29
|
+
import type { TourGuideLabels } from "../tour/tour-guide-labels";
|
|
29
30
|
import type { CommandPaletteLabels } from "../search/command-palette";
|
|
30
31
|
import type { GlobalSearchLabels } from "../search/global-search";
|
|
31
32
|
import type { MonthPickerLabels } from "../components/month-picker";
|
|
@@ -283,6 +284,9 @@ export interface TopBarLabels {
|
|
|
283
284
|
theme: string;
|
|
284
285
|
palette: string;
|
|
285
286
|
language: string;
|
|
287
|
+
/** 0.49 KIT-10: the language menu's trigger, given the current language's name —
|
|
288
|
+
* "Choose language, current: Deutsch". */
|
|
289
|
+
languageCurrent: (name: string) => string;
|
|
286
290
|
switchRole: string;
|
|
287
291
|
/** The role switcher's tooltip, given the active role's name. */
|
|
288
292
|
role: (value: string) => string;
|
|
@@ -332,6 +336,8 @@ export interface UiKitLabels {
|
|
|
332
336
|
tour: TourLabels;
|
|
333
337
|
/** 0.43.0: the tours page — `TourCatalogue` and its card (docs/tours-harmonization.md §3). */
|
|
334
338
|
tourCatalogue: TourCatalogueLabels;
|
|
339
|
+
/** 0.50: the form's "Guide me" — `TourGuideButton` (docs/tours-harmonization.md §11). */
|
|
340
|
+
tourGuide: TourGuideLabels;
|
|
335
341
|
commandPalette: CommandPaletteLabels;
|
|
336
342
|
globalSearch: GlobalSearchLabels;
|
|
337
343
|
seriesChart: SeriesChartLabels;
|
|
@@ -557,6 +563,8 @@ interface KitI18n {
|
|
|
557
563
|
formatDate?: KitDateFormatter;
|
|
558
564
|
tableStorageKeyPrefix?: string;
|
|
559
565
|
timeZone?: string;
|
|
566
|
+
documentTitleFormat?: string;
|
|
567
|
+
appName?: string;
|
|
560
568
|
}
|
|
561
569
|
|
|
562
570
|
/** What a {@link KitDateFormatter} is told about the date it is formatting. */
|
|
@@ -699,6 +707,25 @@ export interface UiKitProviderProps {
|
|
|
699
707
|
* it names in every zone). Left out, timestamps follow the device, as before.
|
|
700
708
|
*/
|
|
701
709
|
timeZone?: string;
|
|
710
|
+
/**
|
|
711
|
+
* 0.49 KIT-9: how `useDocumentTitle` and every `PageHeader`'s `h1` write the window's
|
|
712
|
+
* title, from `{page}`, `{section}` and `{app}`. Default
|
|
713
|
+
* `"{page} · {section} · {app}"` (`DEFAULT_DOCUMENT_TITLE_FORMAT`); a missing part
|
|
714
|
+
* drops with its separator.
|
|
715
|
+
*/
|
|
716
|
+
documentTitleFormat?: string;
|
|
717
|
+
/** 0.49 KIT-9: the app's name, the `{app}` of the window's title ("Kastlan"). Left
|
|
718
|
+
* out, titles end at the page or section. */
|
|
719
|
+
appName?: string;
|
|
720
|
+
/**
|
|
721
|
+
* 0.49 KIT-1b: while a person copies a selection in the page, a U+2212 minus standing
|
|
722
|
+
* before a number ("−CHF 1,250.50") goes to the clipboard as "-", in `text/plain` and
|
|
723
|
+
* `text/html` (what Excel pastes), so a spreadsheet reads a number; the page keeps "−".
|
|
724
|
+
* A copy out of an input, a textarea or an editable element is left alone. Installed
|
|
725
|
+
* once per document, by the first provider that has it on. Default `true`; `false` on
|
|
726
|
+
* the outermost provider leaves the clipboard to the browser.
|
|
727
|
+
*/
|
|
728
|
+
copyAsciiMinus?: boolean;
|
|
702
729
|
children: ReactNode;
|
|
703
730
|
}
|
|
704
731
|
|
|
@@ -719,6 +746,9 @@ export function UiKitProvider({
|
|
|
719
746
|
formatDate,
|
|
720
747
|
tableStorageKeyPrefix,
|
|
721
748
|
timeZone,
|
|
749
|
+
documentTitleFormat,
|
|
750
|
+
appName,
|
|
751
|
+
copyAsciiMinus = true,
|
|
722
752
|
children,
|
|
723
753
|
}: UiKitProviderProps) {
|
|
724
754
|
const outer = useContext(KitI18nContext);
|
|
@@ -732,10 +762,25 @@ export function UiKitProvider({
|
|
|
732
762
|
formatDate: formatDate ?? outer.formatDate,
|
|
733
763
|
tableStorageKeyPrefix: tableStorageKeyPrefix ?? outer.tableStorageKeyPrefix,
|
|
734
764
|
timeZone: timeZone ?? outer.timeZone,
|
|
765
|
+
documentTitleFormat: documentTitleFormat ?? outer.documentTitleFormat,
|
|
766
|
+
appName: appName ?? outer.appName,
|
|
735
767
|
}),
|
|
736
|
-
[
|
|
768
|
+
[
|
|
769
|
+
outer,
|
|
770
|
+
labels,
|
|
771
|
+
locale,
|
|
772
|
+
weekStartsOn,
|
|
773
|
+
linkComponent,
|
|
774
|
+
chartTooltipPlacement,
|
|
775
|
+
formatDate,
|
|
776
|
+
tableStorageKeyPrefix,
|
|
777
|
+
timeZone,
|
|
778
|
+
documentTitleFormat,
|
|
779
|
+
appName,
|
|
780
|
+
],
|
|
737
781
|
);
|
|
738
782
|
useTableViewsJoin(value.tableStorageKeyPrefix ?? DEFAULT_TABLE_STORAGE_KEY_PREFIX);
|
|
783
|
+
useClipboardMinus(copyAsciiMinus);
|
|
739
784
|
return <KitI18nContext.Provider value={value}>{children}</KitI18nContext.Provider>;
|
|
740
785
|
}
|
|
741
786
|
|
|
@@ -773,6 +818,30 @@ function useTableViewsJoin(prefix: string): void {
|
|
|
773
818
|
}, [prefix]);
|
|
774
819
|
}
|
|
775
820
|
|
|
821
|
+
/**
|
|
822
|
+
* The copy handler (lib/clipboard-minus, 0.49 KIT-1b), through a literal `import()` for
|
|
823
|
+
* the reason {@link useTableViewsJoin} gives: a catalogue may reach nothing outside i18n/.
|
|
824
|
+
* It is in place a microtask after the mount — long before a person selects and copies.
|
|
825
|
+
*/
|
|
826
|
+
function useClipboardMinus(on: boolean): void {
|
|
827
|
+
useEffect(() => {
|
|
828
|
+
if (!on || typeof document === "undefined") return;
|
|
829
|
+
let uninstall: (() => void) | undefined;
|
|
830
|
+
let gone = false;
|
|
831
|
+
import("../lib/clipboard-minus").then(
|
|
832
|
+
({ installClipboardMinus }) => {
|
|
833
|
+
if (!gone) uninstall = installClipboardMinus(document);
|
|
834
|
+
},
|
|
835
|
+
// Not loaded: copying works as the browser does it.
|
|
836
|
+
() => undefined,
|
|
837
|
+
);
|
|
838
|
+
return () => {
|
|
839
|
+
gone = true;
|
|
840
|
+
uninstall?.();
|
|
841
|
+
};
|
|
842
|
+
}, [on]);
|
|
843
|
+
}
|
|
844
|
+
|
|
776
845
|
function isRecord(v: unknown): v is Record<string, unknown> {
|
|
777
846
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
778
847
|
}
|
|
@@ -892,6 +961,15 @@ export function useKitTimeZone(): string | undefined {
|
|
|
892
961
|
return useContext(KitI18nContext).timeZone;
|
|
893
962
|
}
|
|
894
963
|
|
|
964
|
+
/** The nearest provider's `documentTitleFormat` and `appName`, or `undefined` each —
|
|
965
|
+
* what `useDocumentTitle` writes with (the format's default is
|
|
966
|
+
* `DEFAULT_DOCUMENT_TITLE_FORMAT`, applied there: this module reaches nothing outside
|
|
967
|
+
* i18n/). */
|
|
968
|
+
export function useKitDocumentTitle(): { format: string | undefined; appName: string | undefined } {
|
|
969
|
+
const { documentTitleFormat, appName } = useContext(KitI18nContext);
|
|
970
|
+
return { format: documentTitleFormat, appName };
|
|
971
|
+
}
|
|
972
|
+
|
|
895
973
|
/** {@link DEFAULT_FILE_LABELS}, but formatting in the provider's locale. */
|
|
896
974
|
export function useKitFileLabels(prop?: Partial<FileLabels>): FileLabels {
|
|
897
975
|
const locale = useKitLocale();
|
package/src/i18n/locales/es.ts
CHANGED
|
@@ -543,6 +543,7 @@ export function uiKitLabelsEs(numberLocale = "es-ES"): UiKitLabels {
|
|
|
543
543
|
theme: "Cambiar de tema",
|
|
544
544
|
palette: "Ajuste de apariencia",
|
|
545
545
|
language: "Idioma",
|
|
546
|
+
languageCurrent: (name) => `Elegir idioma, actual: ${name}`,
|
|
546
547
|
switchRole: "Cambiar de rol",
|
|
547
548
|
role: (value) => `Rol: ${value}`,
|
|
548
549
|
},
|
|
@@ -616,6 +617,19 @@ export function uiKitLabelsEs(numberLocale = "es-ES"): UiKitLabels {
|
|
|
616
617
|
awaitClickHint: "Haga clic en el elemento resaltado para continuar",
|
|
617
618
|
awaitInputHint: "Introduzca un valor en el campo resaltado para continuar", // 0.46: TourStep.awaitInput (keksdose live #436).
|
|
618
619
|
step: (current, total) => `${n(current)} / ${n(total)}`,
|
|
620
|
+
// 0.50: guided form tours (docs/tours-harmonization.md §11).
|
|
621
|
+
leaveEmpty: "Dejar vacío",
|
|
622
|
+
optional: "Opcional",
|
|
623
|
+
gateHint: "Rellene el campo resaltado para continuar",
|
|
624
|
+
gateReady: "Listo. Pulse Siguiente o Intro para continuar.",
|
|
625
|
+
awaitGateHint: "Guarde para continuar",
|
|
626
|
+
awaitGateRefused: "Todavía no se ha guardado. Revise el formulario e inténtelo de nuevo.",
|
|
627
|
+
backToStep: (title) => `Volver a «${title}»`,
|
|
628
|
+
},
|
|
629
|
+
// 0.50: the form's "Guide me" (TourGuideButton, docs/tours-harmonization.md §11).
|
|
630
|
+
tourGuide: {
|
|
631
|
+
label: "Guíeme",
|
|
632
|
+
description: "Le guía por este formulario, campo a campo",
|
|
619
633
|
},
|
|
620
634
|
// 0.43.0 — docs/tours-harmonization.md §3, §8: the tours page.
|
|
621
635
|
tourCatalogue: {
|
|
@@ -1869,10 +1883,13 @@ export function uiKitLabelsEs(numberLocale = "es-ES"): UiKitLabels {
|
|
|
1869
1883
|
rowActions: {
|
|
1870
1884
|
actions: "Acciones",
|
|
1871
1885
|
actionsFor: (name) => `Acciones de ${name}`,
|
|
1886
|
+
confirmTitle: (action, name) => (name ? `¿${action} «${name}»?` : `¿${action}?`),
|
|
1887
|
+
confirmBody: "Esta acción no se puede deshacer.",
|
|
1872
1888
|
},
|
|
1873
1889
|
appShellMore: {
|
|
1874
1890
|
more: "Más",
|
|
1875
1891
|
moreTitle: "Más páginas",
|
|
1892
|
+
overview: "Resumen",
|
|
1876
1893
|
},
|
|
1877
1894
|
// 0.42.0 — docs/admin-harmonization.md §3.1: the admin area's shared words. "Usted",
|
|
1878
1895
|
// as the rest of the catalogue.
|