@eifi1/ui-kit 0.11.0 → 0.13.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 +59 -34
- package/dist/chart.d.ts +3 -1
- package/dist/chart.js +2 -0
- package/dist/chart.js.map +1 -1
- package/dist/components/account-settings-labels.d.ts +105 -0
- package/dist/components/account-settings-labels.js +81 -0
- package/dist/components/account-settings-labels.js.map +1 -0
- package/dist/components/account-settings.d.ts +36 -52
- package/dist/components/account-settings.js +44 -8
- package/dist/components/account-settings.js.map +1 -1
- package/dist/components/amount-input.d.ts +40 -4
- package/dist/components/amount-input.js +50 -12
- package/dist/components/amount-input.js.map +1 -1
- package/dist/components/authed-image.d.ts +68 -0
- package/dist/components/authed-image.js +117 -0
- package/dist/components/authed-image.js.map +1 -0
- package/dist/components/breadcrumbs.d.ts +2 -1
- package/dist/components/breadcrumbs.js +5 -2
- package/dist/components/breadcrumbs.js.map +1 -1
- package/dist/components/bulk-action-bar.d.ts +10 -2
- package/dist/components/bulk-action-bar.js.map +1 -1
- package/dist/components/button-group.d.ts +51 -2
- package/dist/components/button-group.js +5 -1
- package/dist/components/button-group.js.map +1 -1
- package/dist/components/calculator.d.ts +15 -4
- package/dist/components/calendar-heatmap.d.ts +41 -3
- package/dist/components/calendar-heatmap.js +48 -7
- package/dist/components/calendar-heatmap.js.map +1 -1
- package/dist/components/chart.js +14 -8
- package/dist/components/chart.js.map +1 -1
- package/dist/components/chip.d.ts +2 -1
- package/dist/components/chip.js +26 -18
- package/dist/components/chip.js.map +1 -1
- package/dist/components/choice-card.d.ts +35 -3
- package/dist/components/choice-card.js +83 -25
- package/dist/components/choice-card.js.map +1 -1
- package/dist/components/combobox-core.d.ts +3 -1
- package/dist/components/combobox-core.js +18 -5
- package/dist/components/combobox-core.js.map +1 -1
- package/dist/components/combobox.d.ts +2 -2
- package/dist/components/combobox.js +31 -9
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/copy-button.d.ts +51 -70
- package/dist/components/copy-button.js +1 -1
- package/dist/components/copy-button.js.map +1 -1
- package/dist/components/data-table-cells.d.ts +63 -0
- package/dist/components/data-table-cells.js +64 -0
- package/dist/components/data-table-cells.js.map +1 -0
- package/dist/components/data-table-filter-popover.d.ts +1 -1
- package/dist/components/data-table-filter-popover.js +8 -1
- package/dist/components/data-table-filter-popover.js.map +1 -1
- package/dist/components/data-table-filters.d.ts +1 -1
- package/dist/components/data-table-filters.js +31 -1
- package/dist/components/data-table-filters.js.map +1 -1
- package/dist/components/data-table-labels.d.ts +13 -0
- package/dist/components/data-table-labels.js +8 -1
- package/dist/components/data-table-labels.js.map +1 -1
- package/dist/components/data-table.d.ts +1 -1
- package/dist/components/data-table.js +125 -27
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/date-picker.d.ts +3 -1
- package/dist/components/date-picker.js +15 -2
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/description-list.d.ts +23 -3
- package/dist/components/description-list.js +23 -3
- package/dist/components/description-list.js.map +1 -1
- package/dist/components/dialog-frame.d.ts +1 -0
- package/dist/components/entity-combobox.d.ts +1 -1
- package/dist/components/entity-combobox.js +40 -20
- package/dist/components/entity-combobox.js.map +1 -1
- package/dist/components/error-boundary.d.ts +281 -0
- package/dist/components/error-boundary.js +302 -0
- package/dist/components/error-boundary.js.map +1 -0
- package/dist/components/field-sync.js +90 -83
- package/dist/components/field-sync.js.map +1 -1
- package/dist/components/field.d.ts +30 -4
- package/dist/components/field.js +40 -17
- package/dist/components/field.js.map +1 -1
- package/dist/components/file-button.d.ts +50 -208
- package/dist/components/file-dropzone.d.ts +49 -2
- package/dist/components/floating-panel.d.ts +13 -4
- package/dist/components/floating-panel.js +7 -3
- package/dist/components/floating-panel.js.map +1 -1
- package/dist/components/form-actions.d.ts +53 -0
- package/dist/components/form-actions.js +98 -0
- package/dist/components/form-actions.js.map +1 -0
- package/dist/components/full-bleed-dialog.js +4 -0
- package/dist/components/full-bleed-dialog.js.map +1 -1
- package/dist/components/hover-menu.js +64 -56
- package/dist/components/hover-menu.js.map +1 -1
- package/dist/components/image-grid.d.ts +67 -0
- package/dist/components/image-grid.js +112 -0
- package/dist/components/image-grid.js.map +1 -0
- package/dist/components/lightbox.d.ts +104 -0
- package/dist/components/lightbox.js +229 -0
- package/dist/components/lightbox.js.map +1 -0
- package/dist/components/line-items.d.ts +114 -0
- package/dist/components/line-items.js +238 -0
- package/dist/components/line-items.js.map +1 -0
- package/dist/components/list.d.ts +37 -4
- package/dist/components/list.js +35 -14
- package/dist/components/list.js.map +1 -1
- package/dist/components/loading-state.d.ts +24 -0
- package/dist/components/loading-state.js +32 -0
- package/dist/components/loading-state.js.map +1 -0
- package/dist/components/menu-item.d.ts +2 -1
- package/dist/components/menu-item.js +5 -1
- package/dist/components/menu-item.js.map +1 -1
- package/dist/components/mini-calendar.d.ts +13 -1
- package/dist/components/mini-calendar.js +46 -2
- package/dist/components/mini-calendar.js.map +1 -1
- package/dist/components/modal.d.ts +20 -1
- package/dist/components/modal.js +26 -2
- package/dist/components/modal.js.map +1 -1
- package/dist/components/month-picker.d.ts +21 -1
- package/dist/components/month-picker.js +139 -26
- package/dist/components/month-picker.js.map +1 -1
- package/dist/components/multi-entity-combobox.d.ts +1 -1
- package/dist/components/multi-entity-combobox.js +42 -20
- package/dist/components/multi-entity-combobox.js.map +1 -1
- package/dist/components/nav-pills.d.ts +2 -1
- package/dist/components/nav-pills.js +5 -1
- package/dist/components/nav-pills.js.map +1 -1
- package/dist/components/number-field.d.ts +24 -5
- package/dist/components/number-field.js +5 -7
- package/dist/components/number-field.js.map +1 -1
- package/dist/components/number-input.d.ts +25 -5
- package/dist/components/number-input.js +7 -1
- package/dist/components/number-input.js.map +1 -1
- package/dist/components/numpad-sheet.d.ts +20 -5
- package/dist/components/numpad-sheet.js +3 -2
- package/dist/components/numpad-sheet.js.map +1 -1
- package/dist/components/page-header.d.ts +35 -6
- package/dist/components/page-header.js +7 -1
- package/dist/components/page-header.js.map +1 -1
- package/dist/components/passkeys-setting.d.ts +67 -0
- package/dist/components/passkeys-setting.js +214 -0
- package/dist/components/passkeys-setting.js.map +1 -0
- package/dist/components/picker-sheet.js +5 -1
- package/dist/components/picker-sheet.js.map +1 -1
- package/dist/components/pie-chart-labels.d.ts +20 -0
- package/dist/components/pie-chart-labels.js +12 -0
- package/dist/components/pie-chart-labels.js.map +1 -0
- package/dist/components/pie-chart.d.ts +101 -0
- package/dist/components/pie-chart.js +283 -0
- package/dist/components/pie-chart.js.map +1 -0
- package/dist/components/popover.js +3 -0
- package/dist/components/popover.js.map +1 -1
- package/dist/components/progress-bar.d.ts +44 -3
- package/dist/components/progress-bar.js +58 -22
- package/dist/components/progress-bar.js.map +1 -1
- package/dist/components/qr-code.d.ts +34 -0
- package/dist/components/qr-code.js +57 -0
- package/dist/components/qr-code.js.map +1 -0
- package/dist/components/search-field.d.ts +15 -3
- package/dist/components/search-field.js +5 -1
- package/dist/components/search-field.js.map +1 -1
- package/dist/components/settings-fields.d.ts +49 -1
- package/dist/components/signed-amount.d.ts +122 -0
- package/dist/components/signed-amount.js +152 -0
- package/dist/components/signed-amount.js.map +1 -0
- package/dist/components/skeleton.d.ts +10 -3
- package/dist/components/skeleton.js +12 -2
- package/dist/components/skeleton.js.map +1 -1
- package/dist/components/stat-tile.d.ts +2 -1
- package/dist/components/stat-tile.js +6 -3
- package/dist/components/stat-tile.js.map +1 -1
- package/dist/components/swipeable-row.js +4 -3
- package/dist/components/swipeable-row.js.map +1 -1
- package/dist/components/table.d.ts +39 -5
- package/dist/components/table.js +45 -11
- package/dist/components/table.js.map +1 -1
- package/dist/components/text-link.d.ts +238 -0
- package/dist/components/text-link.js +144 -0
- package/dist/components/text-link.js.map +1 -0
- package/dist/components/text.d.ts +26 -2
- package/dist/components/text.js +16 -2
- package/dist/components/text.js.map +1 -1
- package/dist/components/time-input.d.ts +49 -1
- package/dist/components/toggle-group.d.ts +35 -0
- package/dist/components/toggle-group.js +43 -14
- package/dist/components/toggle-group.js.map +1 -1
- package/dist/components/toggle-legend.d.ts +53 -3
- package/dist/components/toggle-legend.js +54 -1
- package/dist/components/toggle-legend.js.map +1 -1
- package/dist/components/tooltip.d.ts +51 -1
- package/dist/components/tooltip.js +59 -35
- package/dist/components/tooltip.js.map +1 -1
- package/dist/components/ui.d.ts +51 -779
- package/dist/components/ui.js +364 -34
- package/dist/components/ui.js.map +1 -1
- package/dist/components/use-table-state.d.ts +3 -52
- package/dist/components/use-table-state.js +128 -30
- package/dist/components/use-table-state.js.map +1 -1
- package/dist/{data-table-filters-Dh9uF_S-.d.ts → data-table-Drun8Fk9.d.ts} +305 -61
- package/dist/data-table.d.ts +2 -1
- package/dist/data-table.js +5 -1
- package/dist/data-table.js.map +1 -1
- package/dist/feedback/feedback-attachment.js +4 -6
- package/dist/feedback/feedback-attachment.js.map +1 -1
- package/dist/feedback/feedback-dialog.d.ts +26 -3
- package/dist/feedback/feedback-dialog.js +21 -5
- package/dist/feedback/feedback-dialog.js.map +1 -1
- package/dist/feedback/feedback-inbox.js +86 -75
- package/dist/feedback/feedback-inbox.js.map +1 -1
- package/dist/feedback/feedback-thread.d.ts +173 -0
- package/dist/feedback/feedback-thread.js +264 -0
- package/dist/feedback/feedback-thread.js.map +1 -0
- package/dist/feedback.d.ts +2 -1
- package/dist/feedback.js +1 -0
- package/dist/feedback.js.map +1 -1
- package/dist/hooks/use-authed-src.d.ts +71 -0
- package/dist/hooks/use-authed-src.js +63 -0
- package/dist/hooks/use-authed-src.js.map +1 -0
- package/dist/hooks/use-file-drop.d.ts +49 -2
- package/dist/hooks/use-hotkey.d.ts +59 -0
- package/dist/hooks/use-hotkey.js +105 -0
- package/dist/hooks/use-hotkey.js.map +1 -0
- package/dist/hooks/use-search-param-state.d.ts +83 -0
- package/dist/hooks/use-search-param-state.js +94 -0
- package/dist/hooks/use-search-param-state.js.map +1 -0
- package/dist/i18n/defaults.d.ts +15 -4
- package/dist/i18n/defaults.js +31 -1
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +46 -312
- package/dist/i18n/kit-labels.js +20 -5
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/locales/de-CH-informal.d.ts +15 -4
- package/dist/i18n/locales/de-CH.d.ts +15 -4
- package/dist/i18n/locales/de-informal.d.ts +15 -4
- package/dist/i18n/locales/de.d.ts +15 -4
- package/dist/i18n/locales/de.js +164 -3
- package/dist/i18n/locales/de.js.map +1 -1
- package/dist/i18n/locales/es.d.ts +15 -4
- package/dist/i18n/locales/es.js +161 -3
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.d.ts +15 -4
- package/dist/i18n/locales/fr.js +161 -3
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.d.ts +15 -4
- package/dist/i18n/locales/hu.js +161 -3
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.d.ts +15 -4
- package/dist/i18n/locales/it.js +161 -3
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.d.ts +15 -4
- package/dist/i18n/locales/zh.js +161 -3
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/index.d.ts +39 -19
- package/dist/index.js +40 -1
- package/dist/index.js.map +1 -1
- package/dist/kit-labels-Mz8zZHIF.d.ts +1744 -0
- package/dist/lib/format.d.ts +162 -0
- package/dist/lib/format.js +151 -0
- package/dist/lib/format.js.map +1 -0
- package/dist/lib/qr-encode.d.ts +44 -0
- package/dist/lib/qr-encode.js +338 -0
- package/dist/lib/qr-encode.js.map +1 -0
- package/dist/rhf/fields.d.ts +283 -0
- package/dist/rhf/fields.js +631 -0
- package/dist/rhf/fields.js.map +1 -0
- package/dist/rhf/form.d.ts +49 -1
- package/dist/rhf/line-items.d.ts +31 -0
- package/dist/rhf/line-items.js +59 -0
- package/dist/rhf/line-items.js.map +1 -0
- package/dist/rhf.d.ts +61 -1
- package/dist/rhf.js +2 -0
- package/dist/rhf.js.map +1 -1
- package/dist/search/command-palette.js +20 -14
- package/dist/search/command-palette.js.map +1 -1
- package/dist/shell/app-shell.d.ts +99 -2
- package/dist/shell/app-shell.js +120 -57
- package/dist/shell/app-shell.js.map +1 -1
- package/dist/shell/auth-layout.d.ts +74 -0
- package/dist/shell/auth-layout.js +97 -0
- package/dist/shell/auth-layout.js.map +1 -0
- package/dist/shell/top-bar-brand.d.ts +81 -0
- package/dist/shell/top-bar-brand.js +47 -0
- package/dist/shell/top-bar-brand.js.map +1 -0
- package/dist/shell/topbar-action-menu.d.ts +21 -4
- package/dist/shell/topbar-action-menu.js +18 -2
- package/dist/shell/topbar-action-menu.js.map +1 -1
- package/dist/shell.d.ts +56 -1
- package/dist/shell.js +2 -0
- package/dist/shell.js.map +1 -1
- package/dist/tour/tour.js +10 -4
- package/dist/tour/tour.js.map +1 -1
- package/dist/wizard/stepper-nav.d.ts +48 -1
- package/dist/wizard/use-wizard.js +4 -2
- package/dist/wizard/use-wizard.js.map +1 -1
- package/dist/wizard/wizard-context.d.ts +24 -1
- package/dist/wizard/wizard-context.js +19 -2
- package/dist/wizard/wizard-context.js.map +1 -1
- package/dist/wizard/wizard-step.d.ts +30 -5
- package/dist/wizard/wizard-step.js +34 -3
- package/dist/wizard/wizard-step.js.map +1 -1
- package/dist/wizard.d.ts +50 -3
- package/package.json +6 -6
- package/src/chart.ts +4 -0
- package/src/components/account-settings-labels.ts +190 -0
- package/src/components/account-settings.tsx +110 -63
- package/src/components/amount-input.tsx +109 -10
- package/src/components/authed-image.tsx +190 -0
- package/src/components/breadcrumbs.tsx +8 -2
- package/src/components/bulk-action-bar.tsx +16 -3
- package/src/components/button-group.tsx +7 -2
- package/src/components/calendar-heatmap.tsx +105 -10
- package/src/components/chart.tsx +19 -8
- package/src/components/chip.tsx +14 -4
- package/src/components/choice-card.tsx +136 -25
- package/src/components/combobox-core.tsx +33 -9
- package/src/components/combobox.tsx +33 -9
- package/src/components/copy-button.tsx +3 -2
- package/src/components/data-table-cells.tsx +119 -0
- package/src/components/data-table-filter-popover.tsx +13 -5
- package/src/components/data-table-filters.ts +77 -0
- package/src/components/data-table-labels.ts +23 -0
- package/src/components/data-table.tsx +230 -13
- package/src/components/date-picker.tsx +19 -3
- package/src/components/description-list.tsx +52 -3
- package/src/components/entity-combobox.tsx +25 -7
- package/src/components/error-boundary.tsx +640 -0
- package/src/components/field-sync.tsx +48 -40
- package/src/components/field.tsx +56 -5
- package/src/components/floating-panel.tsx +20 -7
- package/src/components/form-actions.tsx +191 -0
- package/src/components/full-bleed-dialog.tsx +4 -0
- package/src/components/hover-menu.tsx +26 -17
- package/src/components/image-grid.tsx +181 -0
- package/src/components/lightbox.tsx +374 -0
- package/src/components/line-items.tsx +385 -0
- package/src/components/list.tsx +82 -19
- package/src/components/loading-state.tsx +47 -0
- package/src/components/menu-item.tsx +7 -2
- package/src/components/mini-calendar.tsx +72 -3
- package/src/components/modal.tsx +65 -3
- package/src/components/month-picker.tsx +181 -26
- package/src/components/multi-entity-combobox.tsx +27 -7
- package/src/components/nav-pills.tsx +8 -1
- package/src/components/number-field.tsx +15 -10
- package/src/components/number-input.tsx +17 -1
- package/src/components/numpad-sheet.tsx +6 -1
- package/src/components/page-header.tsx +42 -5
- package/src/components/passkeys-setting.tsx +331 -0
- package/src/components/picker-sheet.tsx +10 -1
- package/src/components/pie-chart-labels.ts +32 -0
- package/src/components/pie-chart.tsx +479 -0
- package/src/components/popover.tsx +3 -0
- package/src/components/progress-bar.tsx +129 -19
- package/src/components/qr-code.tsx +83 -0
- package/src/components/search-field.tsx +20 -4
- package/src/components/signed-amount.tsx +295 -0
- package/src/components/skeleton.tsx +21 -3
- package/src/components/stat-tile.tsx +11 -3
- package/src/components/swipeable-row.tsx +7 -7
- package/src/components/table.tsx +102 -13
- package/src/components/text-link.tsx +356 -0
- package/src/components/text.tsx +46 -2
- package/src/components/toggle-group.tsx +93 -20
- package/src/components/toggle-legend.tsx +108 -2
- package/src/components/tooltip.tsx +79 -8
- package/src/components/ui.tsx +707 -49
- package/src/components/use-table-state.ts +265 -33
- package/src/data-table.ts +10 -0
- package/src/feedback/feedback-attachment.tsx +10 -7
- package/src/feedback/feedback-dialog.tsx +49 -7
- package/src/feedback/feedback-inbox.tsx +7 -0
- package/src/feedback/feedback-thread.tsx +510 -0
- package/src/feedback.ts +1 -0
- package/src/hooks/use-authed-src.ts +161 -0
- package/src/hooks/use-hotkey.ts +172 -0
- package/src/hooks/use-search-param-state.ts +187 -0
- package/src/i18n/defaults.ts +30 -0
- package/src/i18n/kit-labels.tsx +118 -8
- package/src/i18n/locales/de.ts +161 -0
- package/src/i18n/locales/es.ts +158 -0
- package/src/i18n/locales/fr.ts +161 -0
- package/src/i18n/locales/hu.ts +159 -0
- package/src/i18n/locales/it.ts +159 -0
- package/src/i18n/locales/zh.ts +158 -0
- package/src/index.ts +59 -0
- package/src/lib/format.ts +348 -0
- package/src/lib/qr-encode.ts +420 -0
- package/src/rhf/fields.tsx +1135 -0
- package/src/rhf/line-items.tsx +130 -0
- package/src/rhf.ts +6 -0
- package/src/search/command-palette.tsx +29 -19
- package/src/shell/app-shell.tsx +153 -3
- package/src/shell/auth-layout.tsx +190 -0
- package/src/shell/top-bar-brand.tsx +76 -0
- package/src/shell/topbar-action-menu.tsx +32 -4
- package/src/shell.ts +2 -0
- package/src/tour/tour.tsx +16 -5
- package/src/wizard/use-wizard.ts +8 -4
- package/src/wizard/wizard-context.tsx +41 -1
- package/src/wizard/wizard-step.tsx +75 -6
- package/tokens.css +12 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import { Link as RouterLink } from "react-router";
|
|
3
|
+
import { cn } from "../lib/cn";
|
|
4
|
+
import { useKitLink } from "../i18n/kit-labels";
|
|
5
|
+
import { pickLinkRenderer } from "../components/text-link";
|
|
6
|
+
import type { KitLinkComponent, KitLinkProps } from "../i18n/kit-labels";
|
|
7
|
+
|
|
8
|
+
const routerLink: KitLinkComponent = ({ href, ...p }) => <RouterLink to={href} {...p} />;
|
|
9
|
+
const plainLink: KitLinkComponent = ({ children, ...p }) => <a {...p}>{children}</a>;
|
|
10
|
+
|
|
11
|
+
/** Below which width only the logo shows. The name stays in the link's accessible
|
|
12
|
+
* name at every width. */
|
|
13
|
+
const COLLAPSE = {
|
|
14
|
+
sm: "sr-only sm:not-sr-only sm:truncate",
|
|
15
|
+
md: "sr-only md:not-sr-only md:truncate",
|
|
16
|
+
} as const;
|
|
17
|
+
|
|
18
|
+
export interface TopBarBrandProps extends Omit<KitLinkProps, "href" | "children"> {
|
|
19
|
+
/** The brand mark — an SVG, sized by the caller or `h-6 w-auto` by default. */
|
|
20
|
+
logo: ReactNode;
|
|
21
|
+
/** The product name beside the logo, and the link's accessible name. */
|
|
22
|
+
name: ReactNode;
|
|
23
|
+
/** Where the brand links to. Default `/`. */
|
|
24
|
+
to?: string;
|
|
25
|
+
/** Hide the name below `sm` (default) or `md`; `false` always shows it. It is
|
|
26
|
+
* visually hidden, not removed, so the link keeps its name on a phone. */
|
|
27
|
+
collapseBelow?: "sm" | "md" | false;
|
|
28
|
+
/** The app's router link for this one link. Default: the provider's
|
|
29
|
+
* `linkComponent`, else react-router's `Link`. */
|
|
30
|
+
renderLink?: KitLinkComponent;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The top bar's home link: logo + product name, collapsing to the logo on a phone.
|
|
35
|
+
* Pass it as {@link TopBar}'s `brand`.
|
|
36
|
+
*
|
|
37
|
+
* kastlan's (top-bar.tsx:66) hid nothing and truncated the name instead — on a phone
|
|
38
|
+
* with five actions that left "Ka…" beside the logo — and needed an `aria-label`
|
|
39
|
+
* because the name could be cut. Here the name is `sr-only` below the breakpoint, so
|
|
40
|
+
* the logo is the whole visible link there and the name is still what it is called.
|
|
41
|
+
*/
|
|
42
|
+
export function TopBarBrand({
|
|
43
|
+
logo,
|
|
44
|
+
name,
|
|
45
|
+
to = "/",
|
|
46
|
+
collapseBelow = "sm",
|
|
47
|
+
renderLink,
|
|
48
|
+
className,
|
|
49
|
+
...rest
|
|
50
|
+
}: TopBarBrandProps) {
|
|
51
|
+
const kitLink = useKitLink();
|
|
52
|
+
return (
|
|
53
|
+
<RenderedLink
|
|
54
|
+
// The kit's one link rule (`pickLinkRenderer`): an external `to` or an in-page
|
|
55
|
+
// `#anchor` is a plain `<a>`, never the router's link.
|
|
56
|
+
render={pickLinkRenderer(renderLink, kitLink ?? routerLink, to) ?? plainLink}
|
|
57
|
+
{...rest}
|
|
58
|
+
href={to}
|
|
59
|
+
className={cn(
|
|
60
|
+
// `relative` contains the sr-only name.
|
|
61
|
+
"relative flex min-w-0 items-center gap-2 rounded-md font-semibold text-[var(--text-primary)] hover:opacity-80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--brand)]",
|
|
62
|
+
className,
|
|
63
|
+
)}
|
|
64
|
+
>
|
|
65
|
+
<span aria-hidden className="flex shrink-0 items-center [&_svg]:h-6 [&_svg]:w-auto">
|
|
66
|
+
{logo}
|
|
67
|
+
</span>
|
|
68
|
+
<span className={collapseBelow ? COLLAPSE[collapseBelow] : "truncate"}>{name}</span>
|
|
69
|
+
</RenderedLink>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Calls the link renderer as a component, so a router link's hooks are its own. */
|
|
74
|
+
function RenderedLink({ render, ...props }: KitLinkProps & { render: KitLinkComponent }) {
|
|
75
|
+
return render(props);
|
|
76
|
+
}
|
|
@@ -5,6 +5,8 @@ import { cn } from "../lib/cn";
|
|
|
5
5
|
import { HoverMenu } from "../components/hover-menu";
|
|
6
6
|
import { MenuItem } from "../components/menu-item";
|
|
7
7
|
import type { MenuItemTone } from "../components/menu-item";
|
|
8
|
+
import { StatusDot } from "../components/status-dot";
|
|
9
|
+
import type { UserAvatarBadge } from "../components/user-avatar";
|
|
8
10
|
import { TOPBAR_TRIGGER_CLASS } from "./topbar-controls";
|
|
9
11
|
|
|
10
12
|
/**
|
|
@@ -56,9 +58,15 @@ export interface TopBarMenuHeader {
|
|
|
56
58
|
title: ReactNode;
|
|
57
59
|
/** The muted second line — an email, a role. */
|
|
58
60
|
subtitle?: ReactNode;
|
|
59
|
-
/**
|
|
60
|
-
*
|
|
61
|
-
|
|
61
|
+
/**
|
|
62
|
+
* Anything below — a role chip. A link or button here stays out of the arrow keys
|
|
63
|
+
* and in the Tab order, like the footer's.
|
|
64
|
+
*
|
|
65
|
+
* Pass a function to get `close`, as `footer` does — keksdose F7: its admin role
|
|
66
|
+
* chip links to the admin area, and a router link does not unmount the menu, so
|
|
67
|
+
* without `close` the panel stayed open over the page it had just navigated to.
|
|
68
|
+
*/
|
|
69
|
+
extra?: ReactNode | ((close: () => void) => ReactNode);
|
|
62
70
|
}
|
|
63
71
|
|
|
64
72
|
/** What a control is, as far as `HoverMenu` is concerned, when it lives in the header
|
|
@@ -125,6 +133,7 @@ function keepTabInsidePanel(e: ReactKeyboardEvent<HTMLUListElement>) {
|
|
|
125
133
|
*/
|
|
126
134
|
export function TopBarActionMenu({
|
|
127
135
|
icon,
|
|
136
|
+
iconBadge,
|
|
128
137
|
trigger,
|
|
129
138
|
triggerClassName,
|
|
130
139
|
ariaLabel,
|
|
@@ -139,6 +148,13 @@ export function TopBarActionMenu({
|
|
|
139
148
|
}: {
|
|
140
149
|
/** The trigger's face for the usual icon button. Ignored when `trigger` is given. */
|
|
141
150
|
icon?: ReactNode;
|
|
151
|
+
/**
|
|
152
|
+
* A status dot in the top-end corner of `icon` — keksdose's unread-support dot on the
|
|
153
|
+
* feedback trigger. Like `UserAvatar`'s `badge`, its `label` joins the trigger's name
|
|
154
|
+
* ("Send feedback 2 unread"), so the dot is not something only the eye is told about.
|
|
155
|
+
* Ignored with `trigger`: give the face its own badge there.
|
|
156
|
+
*/
|
|
157
|
+
iconBadge?: UserAvatarBadge | null;
|
|
142
158
|
/**
|
|
143
159
|
* A face of your own for the trigger — the account menu's `UserAvatar`. It is drawn
|
|
144
160
|
* INSIDE the kit's button, which keeps the wiring: `aria-haspopup`, `aria-expanded`,
|
|
@@ -190,6 +206,17 @@ export function TopBarActionMenu({
|
|
|
190
206
|
{" "}
|
|
191
207
|
{trigger({ open })}
|
|
192
208
|
</button>
|
|
209
|
+
) : iconBadge ? (
|
|
210
|
+
// Named by its content, like the custom-trigger branch, so the badge label is
|
|
211
|
+
// part of the name; an `aria-label` would have hidden it.
|
|
212
|
+
<button type="button" onClick={toggle} className={cn(TOPBAR_TRIGGER_CLASS, "relative", triggerClassName)}>
|
|
213
|
+
<span className="sr-only">{ariaLabel}</span>{" "}
|
|
214
|
+
<span aria-hidden className="relative inline-flex">
|
|
215
|
+
{icon}
|
|
216
|
+
<StatusDot ring tone={iconBadge.tone ?? "danger"} className="absolute -end-0.5 -top-0.5" />
|
|
217
|
+
</span>{" "}
|
|
218
|
+
<span className="sr-only">{iconBadge.label}</span>
|
|
219
|
+
</button>
|
|
193
220
|
) : (
|
|
194
221
|
<button
|
|
195
222
|
type="button"
|
|
@@ -204,6 +231,7 @@ export function TopBarActionMenu({
|
|
|
204
231
|
>
|
|
205
232
|
{(close) => {
|
|
206
233
|
const footerBody = typeof footer === "function" ? footer(close) : footer;
|
|
234
|
+
const headerExtra = typeof header?.extra === "function" ? header.extra(close) : header?.extra;
|
|
207
235
|
const footerClass =
|
|
208
236
|
"flex flex-wrap gap-x-3 gap-y-1 text-xs text-[var(--text-muted)] [&_a:hover]:text-[var(--text-primary)] [&_a]:rounded-sm [&_a:focus-visible]:outline-none [&_a:focus-visible]:ring-2 [&_a:focus-visible]:ring-[var(--brand)]";
|
|
209
237
|
return (
|
|
@@ -215,7 +243,7 @@ export function TopBarActionMenu({
|
|
|
215
243
|
{header.subtitle != null && (
|
|
216
244
|
<div className="truncate text-xs text-[var(--text-muted)]">{header.subtitle}</div>
|
|
217
245
|
)}
|
|
218
|
-
{
|
|
246
|
+
{headerExtra != null && headerExtra !== false && <div className="mt-1">{headerExtra}</div>}
|
|
219
247
|
</MenuSection>
|
|
220
248
|
)}
|
|
221
249
|
{heading && (
|
package/src/shell.ts
CHANGED
package/src/tour/tour.tsx
CHANGED
|
@@ -157,11 +157,15 @@ export function TourProvider({
|
|
|
157
157
|
const [activeId, setActiveId] = useState<string | null>(null);
|
|
158
158
|
const optsRef = useRef<StartOptions>({});
|
|
159
159
|
// Live mirrors so the step-control callbacks can stay stable (identity-safe for
|
|
160
|
-
// consumers) while still reading the current steps/index.
|
|
160
|
+
// consumers) while still reading the current steps/index. Synced in a layout
|
|
161
|
+
// effect — after the commit, before paint and before any passive effect or event
|
|
162
|
+
// can call them — rather than written during render.
|
|
161
163
|
const stepsRef = useRef<TourStep[] | null>(null);
|
|
162
|
-
stepsRef.current = steps;
|
|
163
164
|
const indexRef = useRef(0);
|
|
164
|
-
|
|
165
|
+
useLayoutEffect(() => {
|
|
166
|
+
stepsRef.current = steps;
|
|
167
|
+
indexRef.current = index;
|
|
168
|
+
}, [steps, index]);
|
|
165
169
|
const active = !!steps && steps.length > 0;
|
|
166
170
|
const total = steps?.length ?? 0;
|
|
167
171
|
|
|
@@ -277,6 +281,15 @@ function TourOverlay({
|
|
|
277
281
|
const isLast = index === steps.length - 1;
|
|
278
282
|
const [rect, setRect] = useState<Rect | null>(null);
|
|
279
283
|
const [ready, setReady] = useState(false);
|
|
284
|
+
// A new step starts unlocated: reset during render when the step changes, so the
|
|
285
|
+
// previous step's spotlight never paints over the new one. The effect below then
|
|
286
|
+
// locates it.
|
|
287
|
+
const [locating, setLocating] = useState({ index, step });
|
|
288
|
+
if (locating.index !== index || locating.step !== step) {
|
|
289
|
+
setLocating({ index, step });
|
|
290
|
+
setReady(false);
|
|
291
|
+
setRect(null);
|
|
292
|
+
}
|
|
280
293
|
// The overlay is portalled to <body>, out of whatever `dir` subtree the app set, so it
|
|
281
294
|
// takes the direction of the element it spotlights (the document's for a centered
|
|
282
295
|
// step). Arrow keys and start/end placement read it.
|
|
@@ -287,8 +300,6 @@ function TourOverlay({
|
|
|
287
300
|
useEffect(() => {
|
|
288
301
|
let cancelled = false;
|
|
289
302
|
let raf = 0;
|
|
290
|
-
setReady(false);
|
|
291
|
-
setRect(null);
|
|
292
303
|
void (async () => {
|
|
293
304
|
await step.beforeStep?.();
|
|
294
305
|
if (cancelled) return;
|
package/src/wizard/use-wizard.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* The committing step is the last one unless a step says `commits: true`; the
|
|
15
15
|
* steps after that one are post-commit steps (see `WizardStepConfig.commits`).
|
|
16
16
|
*/
|
|
17
|
-
import { useCallback, useEffect, useReducer, useRef, useState } from "react";
|
|
17
|
+
import { useCallback, useEffect, useLayoutEffect, useReducer, useRef, useState } from "react";
|
|
18
18
|
import { useSearchParams } from "react-router";
|
|
19
19
|
import { useKitLabels } from "../i18n/kit-labels";
|
|
20
20
|
import { DEFAULT_WIZARD_LABELS } from "./types";
|
|
@@ -163,8 +163,12 @@ export function useWizard<TData extends Record<string, unknown>>(
|
|
|
163
163
|
missingRequiredMessage,
|
|
164
164
|
onValidationFailed,
|
|
165
165
|
} = options;
|
|
166
|
+
// The latest `steps`, for the stable callbacks below. Synced after commit (before
|
|
167
|
+
// paint, and before any handler can run) rather than written during render.
|
|
166
168
|
const stepsRef = useRef<WizardStepConfig[]>(steps);
|
|
167
|
-
|
|
169
|
+
useLayoutEffect(() => {
|
|
170
|
+
stepsRef.current = steps;
|
|
171
|
+
}, [steps]);
|
|
168
172
|
// A hook, not a component, but it produces two sentences of its own — the
|
|
169
173
|
// "fill in the required fields" toast and the fallback submit error — and both
|
|
170
174
|
// reach the user. So it reads the provider like any component does; only the two
|
|
@@ -239,8 +243,8 @@ export function useWizard<TData extends Record<string, unknown>>(
|
|
|
239
243
|
// it back.
|
|
240
244
|
const clearStepUrl = useStepUrl(urlParam, state.currentStepIndex);
|
|
241
245
|
|
|
242
|
-
// `steps`, not `stepsRef.current`:
|
|
243
|
-
//
|
|
246
|
+
// `steps`, not `stepsRef.current`: reading a ref in render is what the hooks
|
|
247
|
+
// linter (rightly) objects to, and the ref only catches up after the commit.
|
|
244
248
|
const currentStep = steps[state.currentStepIndex];
|
|
245
249
|
const isFirstStep = state.currentStepIndex === 0;
|
|
246
250
|
const isLastStep = state.currentStepIndex === steps.length - 1;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createContext, useContext } from "react";
|
|
1
|
+
import { createContext, useContext, useEffect, useRef } from "react";
|
|
2
2
|
import type { ValidateResult } from "./types";
|
|
3
3
|
|
|
4
4
|
export interface WizardContextValue {
|
|
@@ -36,3 +36,43 @@ export function useWizardContext(): WizardContextValue {
|
|
|
36
36
|
export function useOptionalWizardContext(): WizardContextValue | null {
|
|
37
37
|
return useContext(WizardContext);
|
|
38
38
|
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Registers a plain validator for the mounted step — the counterpart to
|
|
42
|
+
* `useRhfWizardStep` (in `@eifi1/ui-kit/rhf`) for a step that gates on its own state
|
|
43
|
+
* (a hand-managed list of lines, a sum that has to balance) rather than a form.
|
|
44
|
+
*
|
|
45
|
+
* ```tsx
|
|
46
|
+
* useWizardStepValidate(() => ({ ok: lines.length >= 2, errors: { lines: t("…") } }));
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* Next (and Finish) run it with the step's other validators; a `false` or a result
|
|
50
|
+
* with `ok: false` keeps the wizard where it is. `validate` is read through a ref, so
|
|
51
|
+
* an inline closure over the latest state registers exactly once. Throws outside a
|
|
52
|
+
* `<StepperNav>`, like {@link useWizardContext}: a validator with nothing to run it is
|
|
53
|
+
* a bug to hear about.
|
|
54
|
+
*/
|
|
55
|
+
export function useWizardStepValidate(
|
|
56
|
+
validate: () => ValidateResult | Promise<ValidateResult>,
|
|
57
|
+
): void {
|
|
58
|
+
const { registerStepValidate } = useWizardContext();
|
|
59
|
+
const ref = useRef(validate);
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
ref.current = validate;
|
|
62
|
+
});
|
|
63
|
+
useEffect(() => registerStepValidate(() => ref.current()), [registerStepValidate]);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Disables the wizard's Next and Skip while `blocked` holds (tenant shares that do not
|
|
68
|
+
* add up to 100 %). Unlike {@link useWizardStepValidate}, which answers a click, this
|
|
69
|
+
* greys the button out before one. The gate is lifted again when the step unmounts, so
|
|
70
|
+
* the next step starts unblocked.
|
|
71
|
+
*/
|
|
72
|
+
export function useWizardNextGate(blocked: boolean): void {
|
|
73
|
+
const { setNextBlocked } = useWizardContext();
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
setNextBlocked(blocked);
|
|
76
|
+
return () => setNextBlocked(false);
|
|
77
|
+
}, [blocked, setNextBlocked]);
|
|
78
|
+
}
|
|
@@ -1,14 +1,83 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
import { cn } from "../lib/cn";
|
|
3
3
|
|
|
4
|
+
export interface WizardStepProps {
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
className?: string;
|
|
7
|
+
/**
|
|
8
|
+
* The step's heading ("Choose a unit"), drawn in the one style every step shares.
|
|
9
|
+
* kastlan's steps each hand-wrote `<h3 className="text-lg font-semibold">` (about
|
|
10
|
+
* sixteen of them: lease-picker-step, lease-unit-step, …), and a hand-written
|
|
11
|
+
* heading is one that drifts — a size here, a colour there. Omitted: no heading.
|
|
12
|
+
*/
|
|
13
|
+
title?: ReactNode;
|
|
14
|
+
/** The line under the title: what the step asks for, or why. Rendered only with a
|
|
15
|
+
* `title` or on its own when there is none. */
|
|
16
|
+
description?: ReactNode;
|
|
17
|
+
/**
|
|
18
|
+
* Controls for the step as a whole, at the end of the header row beside the title —
|
|
19
|
+
* kastlan 43: the buildings step's "Add building" had nowhere to go but UNDER the
|
|
20
|
+
* list it adds to, where it falls below the fold once there are three buildings.
|
|
21
|
+
* A header action is where every other kit surface (`PageHeader`, `Card`) puts it.
|
|
22
|
+
*
|
|
23
|
+
* Wraps under the title on a narrow screen rather than squeezing it. Renders the
|
|
24
|
+
* header on its own if there is no `title` either.
|
|
25
|
+
*/
|
|
26
|
+
actions?: ReactNode;
|
|
27
|
+
/** The heading's level. Default 3: the page has its `h1` and the wizard's own
|
|
28
|
+
* chrome sits at `h2` (the review step, the cancel dialog), so a step is under it. */
|
|
29
|
+
headingLevel?: 2 | 3 | 4;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const HEADING = { 2: "h2", 3: "h3", 4: "h4" } as const;
|
|
33
|
+
|
|
4
34
|
/** The vertical rhythm one wizard step's content sits on. A component rather
|
|
5
|
-
* than a class string so every step in every app spaces its fields the same
|
|
35
|
+
* than a class string so every step in every app spaces its fields the same —
|
|
36
|
+
* and, with `title` / `description`, heads them the same. */
|
|
6
37
|
export function WizardStep({
|
|
7
38
|
children,
|
|
8
39
|
className,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
40
|
+
title,
|
|
41
|
+
description,
|
|
42
|
+
headingLevel = 3,
|
|
43
|
+
actions,
|
|
44
|
+
}: WizardStepProps) {
|
|
45
|
+
const hasTitle = title !== undefined && title !== null && title !== false && title !== "";
|
|
46
|
+
const hasDescription =
|
|
47
|
+
description !== undefined && description !== null && description !== false && description !== "";
|
|
48
|
+
const hasActions = actions !== undefined && actions !== null && actions !== false && actions !== "";
|
|
49
|
+
const Heading = HEADING[headingLevel];
|
|
50
|
+
const heading = (
|
|
51
|
+
<>
|
|
52
|
+
{hasTitle && <Heading className="text-lg font-semibold text-[var(--text-primary)]">{title}</Heading>}
|
|
53
|
+
{hasDescription && <p className="text-sm text-[var(--text-muted)]">{description}</p>}
|
|
54
|
+
</>
|
|
55
|
+
);
|
|
56
|
+
return (
|
|
57
|
+
<div className={cn("space-y-6", className)}>
|
|
58
|
+
{hasActions ? (
|
|
59
|
+
// One row: the text takes the room, the actions keep their width at the end
|
|
60
|
+
// and wrap below it when there is not enough — `basis-64` is the width the
|
|
61
|
+
// title asks for before that happens (a zero basis would never wrap and
|
|
62
|
+
// squeeze the title to a word a line instead). `items-start` so a two-line
|
|
63
|
+
// description does not pull the button down to its middle; `ms-auto` keeps
|
|
64
|
+
// the actions at the end with no title, and when they wrap.
|
|
65
|
+
<div data-slot="wizard-step-header" className="flex flex-wrap items-start justify-between gap-x-4 gap-y-2">
|
|
66
|
+
{(hasTitle || hasDescription) && <div className="min-w-0 grow basis-64 space-y-1">{heading}</div>}
|
|
67
|
+
<div data-slot="wizard-step-actions" className="ms-auto flex shrink-0 flex-wrap items-center gap-2">
|
|
68
|
+
{actions}
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
) : (
|
|
72
|
+
// Without actions the header is exactly what it was, so a step that passes
|
|
73
|
+
// none renders as before.
|
|
74
|
+
(hasTitle || hasDescription) && (
|
|
75
|
+
<div data-slot="wizard-step-header" className="space-y-1">
|
|
76
|
+
{heading}
|
|
77
|
+
</div>
|
|
78
|
+
)
|
|
79
|
+
)}
|
|
80
|
+
{children}
|
|
81
|
+
</div>
|
|
82
|
+
);
|
|
14
83
|
}
|
package/tokens.css
CHANGED
|
@@ -233,6 +233,18 @@
|
|
|
233
233
|
--success-bg: rgba(6, 78, 59, 0.25);
|
|
234
234
|
}
|
|
235
235
|
|
|
236
|
+
/* ── Media ─────────────────────────────────────────────────────────────────
|
|
237
|
+
Controls drawn ON a photo or a live camera picture (the camera shutter), whose
|
|
238
|
+
background is the picture, not the page — so they must NOT follow the theme: a
|
|
239
|
+
dark-mode inverse pair would put a dark ring on a dark viewfinder. The same in both
|
|
240
|
+
themes, on purpose. */
|
|
241
|
+
:root,
|
|
242
|
+
.dark {
|
|
243
|
+
--media-ink: #ffffff;
|
|
244
|
+
--media-scrim: rgb(0 0 0 / 0.35);
|
|
245
|
+
--media-scrim-hover: rgb(0 0 0 / 0.5);
|
|
246
|
+
}
|
|
247
|
+
|
|
236
248
|
/* ── Toasts ─────────────────────────────────────────────────────────────────
|
|
237
249
|
The kit `<Toaster>` (components/toast.tsx) paints sonner with the AlertBanner
|
|
238
250
|
tones. These are ALIASES, not new colours, and they exist for one reason: sonner
|