@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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isValidElement } from "react";
|
|
1
|
+
import { isValidElement, useContext } from "react";
|
|
2
2
|
import type { KeyboardEvent, MouseEvent, ReactElement, ReactNode } from "react";
|
|
3
3
|
import { MoreHorizontal } from "lucide-react";
|
|
4
4
|
import type { LucideIcon } from "lucide-react";
|
|
@@ -15,6 +15,8 @@ import type { TooltipSide } from "./tooltip";
|
|
|
15
15
|
import type { DataTableColumn } from "./data-table";
|
|
16
16
|
import { TableHeaderCell, type TableHeaderCellProps } from "./table";
|
|
17
17
|
import { DEFAULT_ROW_ACTIONS_LABELS } from "./row-actions-labels";
|
|
18
|
+
import { ConfirmContext } from "./confirm-context";
|
|
19
|
+
import { ConfirmProvider } from "./confirm-dialog";
|
|
18
20
|
|
|
19
21
|
/**
|
|
20
22
|
* A row's actions — inline icons at Normal, one "⋯" menu at Large and above
|
|
@@ -30,6 +32,11 @@ import { DEFAULT_ROW_ACTIONS_LABELS } from "./row-actions-labels";
|
|
|
30
32
|
* The data is the roster's `UserRowActionList`, generalised: entries, and `false` /
|
|
31
33
|
* `null` for the ones a condition left out (`row.locked || {…}`).
|
|
32
34
|
*
|
|
35
|
+
* Destructive actions belong in the menu (0.49 KIT-12): a `tone: "danger"` action goes
|
|
36
|
+
* into the "⋯" menu while the others stay inline (`dangerPlacement`), and choosing it
|
|
37
|
+
* opens a `ConfirmDialog` before `onSelect` runs (`confirm`; `false` to opt out). A
|
|
38
|
+
* delete is then never a bin icon in every row, one stray tap from gone.
|
|
39
|
+
*
|
|
33
40
|
* 0.33 (§10.16): an action carries its state at both sizes — a toggle (`pressed`), a
|
|
34
41
|
* disclosure (`expanded`, `controls`), a tone, a tour anchor (`dataTour`) — so a row
|
|
35
42
|
* with an "on" share button or a tour step no longer keeps hand-rolled IconButtons at
|
|
@@ -47,11 +54,21 @@ export interface RowAction {
|
|
|
47
54
|
/** The action's name: the inline icon's name and tooltip, the menu entry's words. */
|
|
48
55
|
label: string;
|
|
49
56
|
/**
|
|
50
|
-
* Runs it. The kit sends nothing —
|
|
51
|
-
* Optional only beside `href`; an action has one or
|
|
52
|
-
* then runs as the link is followed).
|
|
57
|
+
* Runs it. The kit sends nothing — it calls this, after a `tone: "danger"` action's
|
|
58
|
+
* confirmation (see {@link confirm}). Optional only beside `href`; an action has one or
|
|
59
|
+
* the other (or both: `onSelect` then runs as the link is followed).
|
|
53
60
|
*/
|
|
54
61
|
onSelect?: () => void;
|
|
62
|
+
/**
|
|
63
|
+
* 0.49 KIT-12: ask before `onSelect`. A `tone: "danger"` action asks by default — a
|
|
64
|
+
* `ConfirmDialog` (the provider's `useConfirm`, else one of its own) titled with the
|
|
65
|
+
* action and the row's name, "Delete “Ada Example”?", the consequence under it
|
|
66
|
+
* (`rowActions.confirmBody`), the action's label on the danger button and focus on
|
|
67
|
+
* Cancel. Pass the words to say more, or `false` when the app confirms in `onSelect`
|
|
68
|
+
* itself or offers an undo instead. Any other tone asks only when given one. Not for
|
|
69
|
+
* an `href` action: a link only navigates.
|
|
70
|
+
*/
|
|
71
|
+
confirm?: boolean | RowActionConfirm;
|
|
55
72
|
/**
|
|
56
73
|
* The action NAVIGATES — an edit page, a mail to compose (0.32.1, kastlan's 0.32
|
|
57
74
|
* report): a real link inline and in the menu, so open in a new tab, a middle click
|
|
@@ -133,6 +150,13 @@ export interface RowAction {
|
|
|
133
150
|
dataTour?: string;
|
|
134
151
|
}
|
|
135
152
|
|
|
153
|
+
/** The words of a {@link RowAction.confirm}; each defaults as described there. */
|
|
154
|
+
export interface RowActionConfirm {
|
|
155
|
+
title?: ReactNode;
|
|
156
|
+
body?: ReactNode;
|
|
157
|
+
confirmLabel?: ReactNode;
|
|
158
|
+
}
|
|
159
|
+
|
|
136
160
|
/** What a row's actions may be: entries, and `false` / `null` / `undefined` for the ones
|
|
137
161
|
* a condition left out. */
|
|
138
162
|
export type RowActionList = readonly (RowAction | false | null | undefined)[];
|
|
@@ -143,6 +167,11 @@ export interface RowActionsLabels {
|
|
|
143
167
|
actions: string;
|
|
144
168
|
/** The menu button's name, given the row's: "Actions for Ada Example". */
|
|
145
169
|
actionsFor: (name: string) => string;
|
|
170
|
+
/** 0.49 KIT-12: a danger action's confirmation title, given the action's label and the
|
|
171
|
+
* row's name when it has one: "Delete “Ada Example”?", "Delete?". */
|
|
172
|
+
confirmTitle: (action: string, name?: string) => string;
|
|
173
|
+
/** 0.49 KIT-12: the line under it — "This cannot be undone." */
|
|
174
|
+
confirmBody: string;
|
|
146
175
|
}
|
|
147
176
|
|
|
148
177
|
// Defined in ./row-actions-labels, which holds no component code (0.34, KS U8).
|
|
@@ -166,6 +195,13 @@ export type RowActionsSize = Extract<IconButtonSize, "md" | "sm" | "xs" | "2xs">
|
|
|
166
195
|
|
|
167
196
|
export interface RowActionsProps {
|
|
168
197
|
actions: RowActionList;
|
|
198
|
+
/**
|
|
199
|
+
* 0.49 KIT-12: where `tone: "danger"` actions go while the others are inline. `"menu"`
|
|
200
|
+
* (default): into the row's "⋯" menu, so a delete is never one stray tap in every
|
|
201
|
+
* row — the other actions stay icons beside it. `"inline"`: an icon like the rest.
|
|
202
|
+
* `collapse="inline"` keeps every action inline, `collapse="menu"` every one in the menu.
|
|
203
|
+
*/
|
|
204
|
+
dangerPlacement?: "menu" | "inline";
|
|
169
205
|
/** The row's name, for the menu button's name — "Actions for Ada Example". Without it
|
|
170
206
|
* (or `null`, as API fields often are) the button is "Actions". */
|
|
171
207
|
name?: string | null;
|
|
@@ -226,7 +262,7 @@ function toneAttr(tone: RowActionTone | undefined) {
|
|
|
226
262
|
* A row's actions, inline or as a "⋯" menu — see {@link RowActionsCollapse}. Every
|
|
227
263
|
* control stops its click (and the Enter/Space it stands for) from reaching the row, so
|
|
228
264
|
* a clickable row or a DataTable `rowLink` does not open as well; in a DataTable column
|
|
229
|
-
* also set `noRowLink: true`, as {@link rowActionsColumn} does.
|
|
265
|
+
* also set `noRowLink: true` and `role: "actions"`, as {@link rowActionsColumn} does.
|
|
230
266
|
*
|
|
231
267
|
* Inline, the icons sit in a {@link CompactControls} region at Normal: their labels
|
|
232
268
|
* stay the names and the tooltips, and a locked one keeps its reason in the tooltip — a
|
|
@@ -238,10 +274,54 @@ function toneAttr(tone: RowActionTone | undefined) {
|
|
|
238
274
|
* press close it, and focus goes back to the "⋯" button, which is where a confirmation
|
|
239
275
|
* dialog then returns it.
|
|
240
276
|
*/
|
|
241
|
-
export function RowActions({
|
|
277
|
+
export function RowActions(props: RowActionsProps) {
|
|
278
|
+
const outer = useContext(ConfirmContext);
|
|
279
|
+
// A danger action asks first (0.49 KIT-12). Under the app's ConfirmProvider through
|
|
280
|
+
// it; without one, through a provider of this row's own — only when there is
|
|
281
|
+
// something to ask, so a plain row adds nothing.
|
|
282
|
+
if (outer === null && visibleActions(props.actions).some(asksFirst)) {
|
|
283
|
+
return (
|
|
284
|
+
<ConfirmProvider>
|
|
285
|
+
<RowActionsBody {...props} />
|
|
286
|
+
</ConfirmProvider>
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
return <RowActionsBody {...props} />;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/** Whether choosing `action` opens a confirmation first: a danger action unless it says
|
|
293
|
+
* `confirm: false`, any other when it passes one; never a link. */
|
|
294
|
+
function asksFirst(action: RowAction): boolean {
|
|
295
|
+
if (action.href !== undefined || action.confirm === false) return false;
|
|
296
|
+
return action.confirm !== undefined || action.tone === "danger";
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/** `action.onSelect`, after its confirmation when it {@link asksFirst}. */
|
|
300
|
+
function useRunAction(name: string | null | undefined, labels: RowActionsLabels) {
|
|
301
|
+
const confirm = useContext(ConfirmContext);
|
|
302
|
+
return (action: RowAction) => {
|
|
303
|
+
if (!asksFirst(action) || confirm === null) {
|
|
304
|
+
action.onSelect?.();
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
const words = typeof action.confirm === "object" ? action.confirm : {};
|
|
308
|
+
void confirm({
|
|
309
|
+
title: words.title ?? labels.confirmTitle(action.label, name ?? undefined),
|
|
310
|
+
body: words.body ?? labels.confirmBody,
|
|
311
|
+
confirmLabel: words.confirmLabel ?? action.label,
|
|
312
|
+
tone: "danger",
|
|
313
|
+
commit: action.commit,
|
|
314
|
+
}).then((ok) => {
|
|
315
|
+
if (ok) action.onSelect?.();
|
|
316
|
+
});
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function RowActionsBody({
|
|
242
321
|
actions,
|
|
243
322
|
name,
|
|
244
323
|
collapse = "auto",
|
|
324
|
+
dangerPlacement = "menu",
|
|
245
325
|
size = "xs",
|
|
246
326
|
menuWidth = "15rem",
|
|
247
327
|
className,
|
|
@@ -251,28 +331,64 @@ export function RowActions({
|
|
|
251
331
|
}: RowActionsProps) {
|
|
252
332
|
const labels = useKitLabels("rowActions", DEFAULT_ROW_ACTIONS_LABELS, labelsProp);
|
|
253
333
|
const large = useLargeText();
|
|
334
|
+
const run = useRunAction(name, labels);
|
|
254
335
|
const entries = visibleActions(actions);
|
|
255
336
|
if (entries.length === 0) return null;
|
|
256
337
|
const asMenu = collapse === "menu" || (collapse === "auto" && large && entries.length > 1);
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
action={action}
|
|
264
|
-
size={size}
|
|
265
|
-
glyphSize={glyphSize}
|
|
266
|
-
tooltipSide={tooltipSide}
|
|
267
|
-
/>
|
|
268
|
-
))}
|
|
269
|
-
</div>
|
|
270
|
-
);
|
|
271
|
-
// Compact at Normal (no room for a reason line in a row); at Large an inline action
|
|
272
|
-
// is the app's choice ("inline") or the row's only one, and shows its words.
|
|
273
|
-
return large ? strip : <CompactControls>{strip}</CompactControls>;
|
|
274
|
-
}
|
|
338
|
+
// Inline, a danger action still goes into the "⋯" menu (KIT-12) unless the app keeps it
|
|
339
|
+
// inline: the other actions stay icons, the menu holds the destructive ones.
|
|
340
|
+
const toMenu = (action: RowAction) =>
|
|
341
|
+
asMenu || (collapse === "auto" && dangerPlacement === "menu" && action.tone === "danger");
|
|
342
|
+
const inline = entries.filter((action) => !toMenu(action));
|
|
343
|
+
const menu = entries.filter(toMenu);
|
|
275
344
|
const title = name ? labels.actionsFor(name) : labels.actions;
|
|
345
|
+
const menuButton = menu.length > 0 && (
|
|
346
|
+
<RowActionsMenu
|
|
347
|
+
entries={menu}
|
|
348
|
+
title={title}
|
|
349
|
+
size={size}
|
|
350
|
+
menuWidth={menuWidth}
|
|
351
|
+
run={run}
|
|
352
|
+
className={inline.length === 0 ? className : undefined}
|
|
353
|
+
/>
|
|
354
|
+
);
|
|
355
|
+
if (inline.length === 0) return menuButton || null;
|
|
356
|
+
const strip = (
|
|
357
|
+
<div data-slot="row-actions" className={cn("inline-flex items-center gap-0.5", className)}>
|
|
358
|
+
{inline.map((action) => (
|
|
359
|
+
<InlineAction
|
|
360
|
+
key={action.key ?? action.label}
|
|
361
|
+
action={action}
|
|
362
|
+
size={size}
|
|
363
|
+
glyphSize={glyphSize}
|
|
364
|
+
tooltipSide={tooltipSide}
|
|
365
|
+
run={run}
|
|
366
|
+
/>
|
|
367
|
+
))}
|
|
368
|
+
{menuButton}
|
|
369
|
+
</div>
|
|
370
|
+
);
|
|
371
|
+
// Compact at Normal (no room for a reason line in a row); at Large an inline action
|
|
372
|
+
// is the app's choice ("inline") or the row's only one, and shows its words.
|
|
373
|
+
return large ? strip : <CompactControls>{strip}</CompactControls>;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/** The "⋯" button and its menu of `entries`. */
|
|
377
|
+
function RowActionsMenu({
|
|
378
|
+
entries,
|
|
379
|
+
title,
|
|
380
|
+
size,
|
|
381
|
+
menuWidth,
|
|
382
|
+
run,
|
|
383
|
+
className,
|
|
384
|
+
}: {
|
|
385
|
+
entries: RowAction[];
|
|
386
|
+
title: string;
|
|
387
|
+
size: RowActionsSize;
|
|
388
|
+
menuWidth: `${number}rem`;
|
|
389
|
+
run: (action: RowAction) => void;
|
|
390
|
+
className?: string;
|
|
391
|
+
}) {
|
|
276
392
|
// The menu closed when the action was chosen, so what is in flight shows on "⋯".
|
|
277
393
|
const busy = entries.some((action) => action.pending);
|
|
278
394
|
const anchored = entries.filter((action) => action.dataTour);
|
|
@@ -315,7 +431,7 @@ export function RowActions({
|
|
|
315
431
|
<ul data-slot="row-actions-menu" className="space-y-0.5">
|
|
316
432
|
{entries.map((action) => (
|
|
317
433
|
<li key={action.key ?? action.label}>
|
|
318
|
-
<MenuAction action={action} close={close} />
|
|
434
|
+
<MenuAction action={action} close={close} run={run} />
|
|
319
435
|
</li>
|
|
320
436
|
))}
|
|
321
437
|
</ul>
|
|
@@ -355,7 +471,7 @@ function useActionHref(action: RowAction): string | undefined {
|
|
|
355
471
|
}
|
|
356
472
|
|
|
357
473
|
/** One entry of the "⋯" menu: the words, as a link for an `href`, else a button. */
|
|
358
|
-
function MenuAction({ action, close }: { action: RowAction; close: () => void }) {
|
|
474
|
+
function MenuAction({ action, close, run }: { action: RowAction; close: () => void; run: (action: RowAction) => void }) {
|
|
359
475
|
const href = useActionHref(action);
|
|
360
476
|
const glyph = glyphOf(action.icon);
|
|
361
477
|
const glyphTone = action.tone === undefined ? undefined : MENU_GLYPH_TONE[action.tone];
|
|
@@ -376,7 +492,7 @@ function MenuAction({ action, close }: { action: RowAction; close: () => void })
|
|
|
376
492
|
const tone = action.tone === "danger" ? "danger" : undefined;
|
|
377
493
|
const select = () => {
|
|
378
494
|
close();
|
|
379
|
-
action
|
|
495
|
+
run(action);
|
|
380
496
|
};
|
|
381
497
|
if (href !== undefined) {
|
|
382
498
|
return (
|
|
@@ -424,11 +540,13 @@ function InlineAction({
|
|
|
424
540
|
size,
|
|
425
541
|
glyphSize,
|
|
426
542
|
tooltipSide,
|
|
543
|
+
run,
|
|
427
544
|
}: {
|
|
428
545
|
action: RowAction;
|
|
429
546
|
size: RowActionsSize;
|
|
430
547
|
glyphSize?: IconButtonGlyphSize;
|
|
431
548
|
tooltipSide?: TooltipSide;
|
|
549
|
+
run: (action: RowAction) => void;
|
|
432
550
|
}) {
|
|
433
551
|
const href = useActionHref(action);
|
|
434
552
|
const glyph = glyphOf(action.icon);
|
|
@@ -471,7 +589,7 @@ function InlineAction({
|
|
|
471
589
|
pending={action.pending}
|
|
472
590
|
disabled={action.disabled}
|
|
473
591
|
stopPropagation
|
|
474
|
-
onClick={() => action
|
|
592
|
+
onClick={() => run(action)}
|
|
475
593
|
>
|
|
476
594
|
{glyph}
|
|
477
595
|
</IconButton>
|
|
@@ -481,7 +599,7 @@ function InlineAction({
|
|
|
481
599
|
const stop = {
|
|
482
600
|
onClick: (e: MouseEvent) => {
|
|
483
601
|
e.stopPropagation();
|
|
484
|
-
action
|
|
602
|
+
run(action);
|
|
485
603
|
},
|
|
486
604
|
onKeyDown: (e: KeyboardEvent) => {
|
|
487
605
|
if (e.key === "Enter" || e.key === " ") e.stopPropagation();
|
|
@@ -606,7 +724,7 @@ export interface RowActionsColumnOptions<T> {
|
|
|
606
724
|
*/
|
|
607
725
|
header?: ReactNode | false;
|
|
608
726
|
labels?: LabelOverride<RowActionsLabels>;
|
|
609
|
-
/** Anything else for the column (`mobileHidden`, `cellProps`…), merged last. */
|
|
727
|
+
/** Anything else for the column (`mobileHidden`, `cellProps`, another `role`…), merged last. */
|
|
610
728
|
column?: Partial<DataTableColumn<T>>;
|
|
611
729
|
}
|
|
612
730
|
|
|
@@ -618,9 +736,10 @@ export interface RowActionsColumnOptions<T> {
|
|
|
618
736
|
*
|
|
619
737
|
* The heading says "Actions" on screen (0.46.1; `header` changes or hides it), the
|
|
620
738
|
* column hugs its content at the row's end, and `noRowLink` keeps a `rowHref` anchor off it, so the
|
|
621
|
-
* buttons keep their own clicks.
|
|
622
|
-
*
|
|
623
|
-
*
|
|
739
|
+
* buttons keep their own clicks. It is `role: "actions"` (0.49 KIT-7): DataTable's default
|
|
740
|
+
* phone card draws it after its three fields, at the card's end, and never counts it as
|
|
741
|
+
* one of them. Set `column: { mobileHidden: true }` to drop it there (with
|
|
742
|
+
* `mobileDetailsInRow` it then shows in the opened row instead).
|
|
624
743
|
*/
|
|
625
744
|
export function rowActionsColumn<T>({
|
|
626
745
|
key = "actions",
|
|
@@ -660,6 +779,8 @@ export function rowActionsColumn<T>({
|
|
|
660
779
|
// `RowActionsHead` (0.47).
|
|
661
780
|
headClassName: ROW_ACTIONS_HEAD_CLASS,
|
|
662
781
|
noRowLink: true,
|
|
782
|
+
// After the phone card's fields, never one of them (0.49 KIT-7).
|
|
783
|
+
role: "actions",
|
|
663
784
|
...column,
|
|
664
785
|
};
|
|
665
786
|
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { cn } from "../lib/cn";
|
|
2
|
+
import { NavPills } from "./nav-pills";
|
|
3
|
+
import type { NavPillItem, NavPillLinkProps } from "./nav-pills";
|
|
4
|
+
import type { ReactElement, Ref } from "react";
|
|
5
|
+
|
|
6
|
+
export interface SectionNavProps<T extends string> {
|
|
7
|
+
/** The section's pages, each with its `href` (a pill without one is a button that
|
|
8
|
+
* calls `onSelect`). Labels short: the row is one line. */
|
|
9
|
+
items: NavPillItem<T>[];
|
|
10
|
+
/** The page that is open. `null`: none of them. */
|
|
11
|
+
current: T | null;
|
|
12
|
+
/** The section's name — the landmark's accessible name ("Accounting"). */
|
|
13
|
+
label: string;
|
|
14
|
+
/** Called with a pill's value on a click, before the router follows its link. */
|
|
15
|
+
onSelect?: (value: T) => void;
|
|
16
|
+
/** Your router's link. Default: the `<UiKitProvider linkComponent>`, then `<a>`. */
|
|
17
|
+
renderLink?: (props: NavPillLinkProps) => ReactElement;
|
|
18
|
+
/** Default `true`: only below `md`, where the sidebar that lists the same pages is
|
|
19
|
+
* gone. `false` shows it at every width. */
|
|
20
|
+
phoneOnly?: boolean;
|
|
21
|
+
className?: string;
|
|
22
|
+
ref?: Ref<HTMLElement>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The pages of a section on a phone, as one row of pills under the page title (0.49
|
|
27
|
+
* KIT-6) — kastlan's section pills, which each section page drew by hand.
|
|
28
|
+
*
|
|
29
|
+
* On a desktop the sidebar lists a group's pages; on a phone the AppShell's bar holds
|
|
30
|
+
* the groups, and a group's pages are a sheet away. This row puts them on the page
|
|
31
|
+
* itself: {@link NavPills} with `layout="scroll"` — one line that scrolls sideways, faded
|
|
32
|
+
* where it is cut, the open page scrolled into view (the row only, never the page). At
|
|
33
|
+
* most 48 px high: 44 px pills, the touch target a finger needs, and 2 px above and
|
|
34
|
+
* below. Each pill is a link (`aria-current="page"` on the open one) and its own tab
|
|
35
|
+
* stop; the row is a `<nav>` named by `label`.
|
|
36
|
+
*
|
|
37
|
+
* Place it right under the page's title (`PageHeader`); the AppShell's own row of a
|
|
38
|
+
* group's pages above the bar (`mobileSubNav`) is the shell-wide alternative — use one,
|
|
39
|
+
* not both, for the same pages.
|
|
40
|
+
*/
|
|
41
|
+
export function SectionNav<T extends string>({
|
|
42
|
+
items,
|
|
43
|
+
current,
|
|
44
|
+
label,
|
|
45
|
+
onSelect,
|
|
46
|
+
renderLink,
|
|
47
|
+
phoneOnly = true,
|
|
48
|
+
className,
|
|
49
|
+
ref,
|
|
50
|
+
}: SectionNavProps<T>) {
|
|
51
|
+
return (
|
|
52
|
+
<NavPills
|
|
53
|
+
ref={ref}
|
|
54
|
+
aria-label={label}
|
|
55
|
+
items={items}
|
|
56
|
+
current={current}
|
|
57
|
+
onSelect={onSelect}
|
|
58
|
+
renderLink={renderLink}
|
|
59
|
+
layout="scroll"
|
|
60
|
+
// The ring inside the pill: the row scrolls, so it clips what leaves its box.
|
|
61
|
+
itemClassName="min-h-11 focus-visible:ring-inset"
|
|
62
|
+
className={cn("py-0.5 large:py-0", phoneOnly && "md:hidden", className)}
|
|
63
|
+
/>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
@@ -116,7 +116,9 @@ import {
|
|
|
116
116
|
import { useBreakpoint } from "../hooks/use-breakpoint";
|
|
117
117
|
import { useTextSize } from "../theme/text-size";
|
|
118
118
|
import { chartHeightProps, type ChartHeight } from "./chart-height";
|
|
119
|
+
import { useChartEdge } from "./chart-edge";
|
|
119
120
|
import { cn } from "../lib/cn";
|
|
121
|
+
import { formatWithMinus } from "../lib/minus";
|
|
120
122
|
|
|
121
123
|
export interface SeriesChartSeries {
|
|
122
124
|
/** The row key this line reads — and the `--color-<key>` it is painted with, so it
|
|
@@ -764,7 +766,8 @@ function useDefaultFormat(localeProp: string | undefined): (value: number) => st
|
|
|
764
766
|
const locale = useKitLocale(localeProp);
|
|
765
767
|
return useMemo(() => {
|
|
766
768
|
const format = new Intl.NumberFormat(locale, { maximumFractionDigits: 2 });
|
|
767
|
-
|
|
769
|
+
// U+2212 on a negative tick and in the tooltip (0.49, KIT-1).
|
|
770
|
+
return (value: number) => formatWithMinus(format, value);
|
|
768
771
|
}, [locale]);
|
|
769
772
|
}
|
|
770
773
|
|
|
@@ -1019,6 +1022,7 @@ function SeriesPlot({
|
|
|
1019
1022
|
// grows by itself — and the axes aim at three ticks instead of five from Large up.
|
|
1020
1023
|
// Strokes, dashes and the grid stay px.
|
|
1021
1024
|
const { scale } = useTextSize();
|
|
1025
|
+
const edgeFor = useChartEdge();
|
|
1022
1026
|
const ticksAim = tickTarget(scale);
|
|
1023
1027
|
const grow = (px: number) => (scale === 1 ? px : Math.round(px * scale));
|
|
1024
1028
|
// The keyboard stops' roving tab stop, and the one that has focus (see `PointKeys`).
|
|
@@ -1552,6 +1556,9 @@ function SeriesPlot({
|
|
|
1552
1556
|
const type = entry.type ?? "line";
|
|
1553
1557
|
const yAxisId = entry.axis ?? DEFAULT_Y_AXIS;
|
|
1554
1558
|
const color = `var(--color-${entry.key})`;
|
|
1559
|
+
// A filled mark in a hue under 3:1 against the ground gets a 1px ink edge
|
|
1560
|
+
// (WCAG 1.4.11, anyplot's rule) — measured on the colour the config paints.
|
|
1561
|
+
const edge = edgeFor(config[entry.key]?.color);
|
|
1555
1562
|
const own = entry.dash ?? (entry.dashed ? 1 : 0);
|
|
1556
1563
|
const dash = entry.step ? strokeDash(STEP_DASH) : typeof own === "string" ? own : strokeDash(own);
|
|
1557
1564
|
const curve = entry.step ? "stepAfter" : (entry.curve ?? "monotone");
|
|
@@ -1566,6 +1573,7 @@ function SeriesPlot({
|
|
|
1566
1573
|
stackId={entry.stack}
|
|
1567
1574
|
fill={color}
|
|
1568
1575
|
fillOpacity={entry.fillOpacity}
|
|
1576
|
+
{...(edge ? { stroke: edge, strokeWidth: 1 } : {})}
|
|
1569
1577
|
radius={entry.stack === undefined ? BAR_RADIUS : 0}
|
|
1570
1578
|
// Read off the row rather than recharts' `value`: in a stack that is the
|
|
1571
1579
|
// layer's running top, which a hole has too — and a hole gets no stub.
|
|
@@ -1596,8 +1604,9 @@ function SeriesPlot({
|
|
|
1596
1604
|
type={curve}
|
|
1597
1605
|
dataKey={entry.key}
|
|
1598
1606
|
stackId={entry.stack}
|
|
1599
|
-
|
|
1600
|
-
|
|
1607
|
+
// The edge replaces the hue on the area's outline only; the fill keeps it.
|
|
1608
|
+
stroke={edge ?? color}
|
|
1609
|
+
strokeWidth={edge ? 1 : width}
|
|
1601
1610
|
strokeDasharray={dash}
|
|
1602
1611
|
fill={color}
|
|
1603
1612
|
fillOpacity={entry.fillOpacity ?? (entry.stack !== undefined ? 0.55 : 0.2)}
|
|
@@ -448,7 +448,7 @@ export function SharePanel({
|
|
|
448
448
|
{captionNode && <Caption as="div">{captionNode}</Caption>}
|
|
449
449
|
</div>
|
|
450
450
|
<Button
|
|
451
|
-
variant="
|
|
451
|
+
variant="accent"
|
|
452
452
|
commit
|
|
453
453
|
pending={busy === "add"}
|
|
454
454
|
disabled={busy !== null || (empty && !addWithoutEmail)}
|
|
@@ -616,7 +616,7 @@ export function SignaturePad({
|
|
|
616
616
|
</Button>
|
|
617
617
|
)}
|
|
618
618
|
{onSave && (
|
|
619
|
-
<Button type="button" variant="
|
|
619
|
+
<Button type="button" variant="accent" onClick={save} disabled={disabled || isEmpty} className="ms-auto">
|
|
620
620
|
{labels.save}
|
|
621
621
|
</Button>
|
|
622
622
|
)}
|
|
@@ -3,6 +3,7 @@ import { cn } from "../lib/cn";
|
|
|
3
3
|
import { useKitLabels, useKitLocale, type LabelOverride } from "../i18n/kit-labels";
|
|
4
4
|
import { useTextSize } from "../theme/text-size";
|
|
5
5
|
import { DEFAULT_SPARKLINE_LABELS } from "./sparkline-labels";
|
|
6
|
+
import { formatWithMinus } from "../lib/minus";
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* The words a sparkline speaks. It has no axes, no tooltip and no legend, so its
|
|
@@ -118,7 +119,7 @@ function defaultFormat(locale: string | undefined): (v: number) => string {
|
|
|
118
119
|
f = new Intl.NumberFormat(locale, { maximumFractionDigits: 2 });
|
|
119
120
|
formatters.set(key, f);
|
|
120
121
|
}
|
|
121
|
-
return (v) => f
|
|
122
|
+
return (v) => formatWithMinus(f, v);
|
|
122
123
|
}
|
|
123
124
|
|
|
124
125
|
const isValue = (v: number | null | undefined): v is number => typeof v === "number" && Number.isFinite(v);
|
|
@@ -16,6 +16,7 @@ import { Tooltip } from "./tooltip";
|
|
|
16
16
|
// tile's private copy of the string did not.
|
|
17
17
|
import { SKELETON_CLASS } from "./skeleton";
|
|
18
18
|
import { DEFAULT_STAT_TILE_LABELS } from "./stat-tile-labels";
|
|
19
|
+
import { formatWithMinus } from "../lib/minus";
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* The words a stat tile speaks. The delta's arrow is an icon, and an icon is not a
|
|
@@ -352,11 +353,15 @@ export function StatTile({
|
|
|
352
353
|
const fmt =
|
|
353
354
|
format ??
|
|
354
355
|
((n: number) =>
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
356
|
+
// U+2212 for a negative headline (0.49, KIT-1).
|
|
357
|
+
formatWithMinus(
|
|
358
|
+
numberFormatter(kitLocale, {
|
|
359
|
+
...(currency ? { style: "currency", currency } : null),
|
|
360
|
+
...(compact ? { notation: "compact" } : null),
|
|
361
|
+
...numberFormat,
|
|
362
|
+
}),
|
|
363
|
+
n,
|
|
364
|
+
));
|
|
360
365
|
const show = (v: ReactNode) => (typeof v === "number" ? fmt(v) : v);
|
|
361
366
|
|
|
362
367
|
const d = typeof delta === "number" ? { value: delta } : delta;
|
|
@@ -592,14 +597,21 @@ function FigureRow({
|
|
|
592
597
|
// next row stayed on one — two layouts in one list, and a figure no longer beside
|
|
593
598
|
// the period it belongs to. Now the label breaks within itself and the amount stays
|
|
594
599
|
// on the label's first line, end-aligned like every other row.
|
|
600
|
+
//
|
|
601
|
+
// 0.49: between WORDS only. `overflow-wrap:anywhere` (with `min-w-0`) cut a single
|
|
602
|
+
// word at any letter — "PROJECT|ED" in a 160px KPI tile at 360px. The label now keeps
|
|
603
|
+
// a flex item's own floor, its longest word; only a word that cannot share the line
|
|
604
|
+
// with the figure sends the figure to the next line, still end-aligned. `break-word`
|
|
605
|
+
// is the last resort for a word wider than the whole tile, and does not lower that
|
|
606
|
+
// floor the way `anywhere` did.
|
|
595
607
|
return (
|
|
596
608
|
<div
|
|
597
609
|
className={cn(
|
|
598
610
|
"flex text-xs tabular-nums text-muted",
|
|
599
|
-
stacked ? "flex-col items-start" : "items-baseline gap-x-2",
|
|
611
|
+
stacked ? "flex-col items-start" : "flex-wrap items-baseline gap-x-2",
|
|
600
612
|
)}
|
|
601
613
|
>
|
|
602
|
-
<dt className="
|
|
614
|
+
<dt className="max-w-full uppercase tracking-wide [overflow-wrap:break-word]">{figure.label}</dt>
|
|
603
615
|
<dd
|
|
604
616
|
data-private={priv}
|
|
605
617
|
className={cn(
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ComponentPropsWithRef, ReactNode } from "react";
|
|
2
2
|
import { cn } from "../lib/cn";
|
|
3
|
+
import { statusTone, type StatusKind } from "../lib/status-tone";
|
|
3
4
|
import type { ProgressBarTone } from "./progress-bar";
|
|
4
5
|
import type { ChipHue } from "./chip";
|
|
5
6
|
|
|
@@ -90,6 +91,9 @@ const DOT_ON_FIRST_LINE: Record<StatusDotSize, string> = {
|
|
|
90
91
|
|
|
91
92
|
export interface StatusDotProps extends Omit<ComponentPropsWithRef<"span">, "children"> {
|
|
92
93
|
tone?: StatusDotTone;
|
|
94
|
+
/** What the dot means as a status (0.49 KIT-8), instead of a `tone` — see Chip's
|
|
95
|
+
* `status` and {@link statusTone}. An explicit `tone` wins. */
|
|
96
|
+
status?: StatusKind;
|
|
93
97
|
size?: StatusDotSize;
|
|
94
98
|
/**
|
|
95
99
|
* Visible text beside the dot — a legend entry ("Rented") or a status ("Online"). It
|
|
@@ -122,7 +126,8 @@ export interface StatusDotProps extends Omit<ComponentPropsWithRef<"span">, "chi
|
|
|
122
126
|
* this.
|
|
123
127
|
*/
|
|
124
128
|
export function StatusDot({
|
|
125
|
-
tone
|
|
129
|
+
tone: toneProp,
|
|
130
|
+
status,
|
|
126
131
|
size = "sm",
|
|
127
132
|
label,
|
|
128
133
|
ring = false,
|
|
@@ -131,6 +136,7 @@ export function StatusDot({
|
|
|
131
136
|
"aria-label": ariaLabel,
|
|
132
137
|
...rest
|
|
133
138
|
}: StatusDotProps) {
|
|
139
|
+
const tone: StatusDotTone = toneProp ?? (status ? statusTone(status) : "neutral");
|
|
134
140
|
const dot = (
|
|
135
141
|
<span
|
|
136
142
|
// The tone as data (0.34, refactor audit 2026-10, TST-9): a stable hook for a test or
|
|
@@ -580,7 +580,9 @@ function useTooltipTrigger(
|
|
|
580
580
|
// A layer on the Escape stack while up (Wave 2, DUP-1): over a dialog, the first
|
|
581
581
|
// Escape dismisses the bubble — WCAG 1.4.13, without moving focus — and the next one
|
|
582
582
|
// the dialog. Inside a Modal the bubble used to be beyond reach of the key.
|
|
583
|
-
|
|
583
|
+
// Not an overlay: a tooltip annotates what it is on, so a floating launcher with one
|
|
584
|
+
// does not step aside for its own bubble (`hideWhenOverlay`, 0.49 KIT-11).
|
|
585
|
+
useDismissLayer(open, () => setDismissed(true), { overlay: false });
|
|
584
586
|
// A press anywhere else closes it — the case a blur does not cover: Safari moves no
|
|
585
587
|
// focus on a tap, and a tap on plain text moves it nowhere.
|
|
586
588
|
useOutsideClick(triggerRef, close, open);
|
|
@@ -241,7 +241,7 @@ export function TranslationReviewEditor({
|
|
|
241
241
|
<div className="flex flex-wrap gap-2">
|
|
242
242
|
{!missing && (
|
|
243
243
|
<Button
|
|
244
|
-
variant="
|
|
244
|
+
variant="default"
|
|
245
245
|
commit={COMMIT_EXCEPT_BILLING}
|
|
246
246
|
pending={busy === "approve"}
|
|
247
247
|
disabled={busy !== null}
|
|
@@ -251,7 +251,7 @@ export function TranslationReviewEditor({
|
|
|
251
251
|
</Button>
|
|
252
252
|
)}
|
|
253
253
|
<Button
|
|
254
|
-
variant={missing ? "
|
|
254
|
+
variant={missing ? "default" : "danger"}
|
|
255
255
|
commit={COMMIT_EXCEPT_BILLING}
|
|
256
256
|
pending={busy === "flag"}
|
|
257
257
|
disabled={busy !== null || !canFlag}
|
|
@@ -1088,7 +1088,7 @@ export function TranslationReviewPanel({
|
|
|
1088
1088
|
el.focus();
|
|
1089
1089
|
}
|
|
1090
1090
|
}}
|
|
1091
|
-
variant="
|
|
1091
|
+
variant="default"
|
|
1092
1092
|
size="sm"
|
|
1093
1093
|
commit={COMMIT_EXCEPT_BILLING}
|
|
1094
1094
|
aria-describedby={questionId}
|
|
@@ -1204,7 +1204,7 @@ export function TranslationReviewPanel({
|
|
|
1204
1204
|
{editable && (
|
|
1205
1205
|
<BulkActionBar count={selectedRows.length} onClear={() => setSelected(new Set())}>
|
|
1206
1206
|
<Button
|
|
1207
|
-
variant="
|
|
1207
|
+
variant="default"
|
|
1208
1208
|
size="sm"
|
|
1209
1209
|
commit={COMMIT_EXCEPT_BILLING}
|
|
1210
1210
|
pending={isQueued("bulk-approve")}
|