@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
|
@@ -1,10 +1,58 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { SelectProps } from '
|
|
3
|
+
import { aJ as SelectProps } from '../kit-labels-Mz8zZHIF.js';
|
|
4
4
|
import { ThemePreference } from '../theme/theme-store.js';
|
|
5
|
+
import './data-table-labels.js';
|
|
6
|
+
import './mini-calendar.js';
|
|
7
|
+
import './calendar-heatmap.js';
|
|
8
|
+
import './popover.js';
|
|
9
|
+
import './chip.js';
|
|
10
|
+
import 'lucide-react';
|
|
11
|
+
import './field-sync.js';
|
|
5
12
|
import './tooltip.js';
|
|
6
13
|
import '../hooks/use-anchored-rect.js';
|
|
7
14
|
import '../lib/clipping.js';
|
|
15
|
+
import '../wizard/types.js';
|
|
16
|
+
import '../tour/tour.js';
|
|
17
|
+
import '../search/command-palette.js';
|
|
18
|
+
import '../search/global-search.js';
|
|
19
|
+
import '../search/search-index.js';
|
|
20
|
+
import './month-picker.js';
|
|
21
|
+
import './page-contents.js';
|
|
22
|
+
import './series-chart-labels.js';
|
|
23
|
+
import './pie-chart-labels.js';
|
|
24
|
+
import './sparkline.js';
|
|
25
|
+
import './stat-tile.js';
|
|
26
|
+
import './signature-pad.js';
|
|
27
|
+
import './password-strength.js';
|
|
28
|
+
import './danger-confirm.js';
|
|
29
|
+
import './swatch-picker.js';
|
|
30
|
+
import './tile-radio.js';
|
|
31
|
+
import './icon-picker.js';
|
|
32
|
+
import './dialog-frame.js';
|
|
33
|
+
import './modal.js';
|
|
34
|
+
import '../hooks/use-search-param-state.js';
|
|
35
|
+
import './measured-grid.js';
|
|
36
|
+
import '../feedback/feedback-attachment.js';
|
|
37
|
+
import '../feedback/feedback-dialog.js';
|
|
38
|
+
import '../feedback/feedback-thread.js';
|
|
39
|
+
import '../feedback/feedback-inbox.js';
|
|
40
|
+
import './account-settings-labels.js';
|
|
41
|
+
import './confirm-dialog.js';
|
|
42
|
+
import './floating-panel.js';
|
|
43
|
+
import './bulk-action-bar.js';
|
|
44
|
+
import './list.js';
|
|
45
|
+
import './breadcrumbs.js';
|
|
46
|
+
import './toast.js';
|
|
47
|
+
import './description-list.js';
|
|
48
|
+
import './line-items.js';
|
|
49
|
+
import './progress-bar.js';
|
|
50
|
+
import './signed-amount.js';
|
|
51
|
+
import './error-boundary.js';
|
|
52
|
+
import './authed-image.js';
|
|
53
|
+
import '../hooks/use-authed-src.js';
|
|
54
|
+
import './image-grid.js';
|
|
55
|
+
import './lightbox.js';
|
|
8
56
|
import 'zustand/middleware';
|
|
9
57
|
import 'zustand';
|
|
10
58
|
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ComponentPropsWithoutRef, ReactNode } from 'react';
|
|
3
|
+
import { StatTileLabels } from './stat-tile.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The text colours a figure can carry, token-backed — `StatTile`'s tones, as a class
|
|
7
|
+
* any span can take.
|
|
8
|
+
*
|
|
9
|
+
* - `default` — the primary text colour. `muted` — the secondary, quiet one.
|
|
10
|
+
* - `income` / `expense` / `net` — the money trio (CVD-safe teal / amber / violet).
|
|
11
|
+
* - `success` / `warning` / `danger` / `info` — a verdict: a rent rise is the tenant's
|
|
12
|
+
* bad news (kastlan lease-columns), a vote "for" is green (meeting-agenda-tab).
|
|
13
|
+
* - `brand` — the app's accent.
|
|
14
|
+
*
|
|
15
|
+
* Colour is never the only carrier: pair a verdict with an arrow, a word, or a sign.
|
|
16
|
+
*/
|
|
17
|
+
type TextTone = "default" | "muted" | "brand" | "income" | "expense" | "net" | "success" | "warning" | "danger" | "info";
|
|
18
|
+
/**
|
|
19
|
+
* The class that colours text in `tone` — for the spans kastlan colours by hand with
|
|
20
|
+
* `text-[var(--danger)]` / `text-emerald-600` (settlement-table, changelog-page,
|
|
21
|
+
* meeting-agenda-tab), so the palette they draw from is the kit's tokens.
|
|
22
|
+
*/
|
|
23
|
+
declare function toneTextClass(tone: TextTone): string;
|
|
24
|
+
interface ToneProps extends ComponentPropsWithoutRef<"span"> {
|
|
25
|
+
tone: TextTone;
|
|
26
|
+
}
|
|
27
|
+
/** A `<span>` in a {@link TextTone} — `<Tone tone="success">{votesFor}</Tone>`. */
|
|
28
|
+
declare function Tone({ tone, className, ...rest }: ToneProps): react.JSX.Element;
|
|
29
|
+
/** Which way is +1: `up` for a figure where more is good news (income, savings),
|
|
30
|
+
* `down` where less is (a rent the tenant pays, a cost). */
|
|
31
|
+
type GoodDirection = "up" | "down";
|
|
32
|
+
/**
|
|
33
|
+
* How a signed figure is coloured:
|
|
34
|
+
* - `signed` (default) — money read by its own sign: above zero `income`, below zero
|
|
35
|
+
* `expense`, zero muted. A balance, a net.
|
|
36
|
+
* - `income` / `expense` / `neutral` — one colour whatever the sign (`neutral` is the
|
|
37
|
+
* text's own colour).
|
|
38
|
+
* - `verdict` — the change judged by {@link SignedAmountProps.goodDirection}: good
|
|
39
|
+
* news `success`, bad news `danger`, zero muted. Setting `goodDirection` implies it.
|
|
40
|
+
*/
|
|
41
|
+
type SignedAmountTone = "signed" | "income" | "expense" | "neutral" | "verdict";
|
|
42
|
+
/** What a signed figure says to a screen reader, whose readers disagree about a
|
|
43
|
+
* leading "+" (most skip it) and a "−" (some read "dash", some nothing). */
|
|
44
|
+
interface SignedAmountLabels {
|
|
45
|
+
/** A figure above zero. `amount` is formatted and unsigned. */
|
|
46
|
+
positive: (amount: string) => string;
|
|
47
|
+
/** A figure below zero. `amount` is formatted and unsigned. */
|
|
48
|
+
negative: (amount: string) => string;
|
|
49
|
+
}
|
|
50
|
+
declare const DEFAULT_SIGNED_AMOUNT_LABELS: SignedAmountLabels;
|
|
51
|
+
interface SignedFormatProps {
|
|
52
|
+
/** ISO 4217 code: format as money. */
|
|
53
|
+
currency?: string;
|
|
54
|
+
/** `"percent"` reads `value` as a RATIO (`0.12` → 12 %), as `StatTile`'s delta does. */
|
|
55
|
+
unit?: "value" | "percent";
|
|
56
|
+
/** Compact notation: 12 400 → "12K". */
|
|
57
|
+
compact?: boolean;
|
|
58
|
+
/** Fraction digits, as `formatNumber`'s `digits`. */
|
|
59
|
+
digits?: number | {
|
|
60
|
+
min?: number;
|
|
61
|
+
max?: number;
|
|
62
|
+
};
|
|
63
|
+
/** Formats the UNSIGNED magnitude, replacing the `Intl` default outright. The sign
|
|
64
|
+
* is the component's. */
|
|
65
|
+
format?: (magnitude: number) => string;
|
|
66
|
+
locale?: string;
|
|
67
|
+
}
|
|
68
|
+
interface SignedAmountProps extends SignedFormatProps, Omit<ComponentPropsWithoutRef<"span">, "children"> {
|
|
69
|
+
value: number;
|
|
70
|
+
/** See {@link SignedAmountTone}. Default `signed`, or `verdict` with `goodDirection`. */
|
|
71
|
+
tone?: SignedAmountTone;
|
|
72
|
+
/** Which way is good news — colours by verdict (`success` / `danger`). */
|
|
73
|
+
goodDirection?: GoodDirection;
|
|
74
|
+
/** Print "+" before a positive figure (default `true`). A negative always shows its
|
|
75
|
+
* minus; zero shows neither. */
|
|
76
|
+
showPlus?: boolean;
|
|
77
|
+
/** An arrow before the figure (up / down / a dash at zero) — so the direction does not
|
|
78
|
+
* ride on colour alone. Decorative; the words say the same. */
|
|
79
|
+
arrow?: boolean;
|
|
80
|
+
/** Tag the figure `data-private`, for the host's demo-mode blur. */
|
|
81
|
+
sensitive?: boolean;
|
|
82
|
+
labels?: Partial<SignedAmountLabels>;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* A figure with a sign that matters: a balance, a rent change, a net.
|
|
86
|
+
*
|
|
87
|
+
* kastlan writes it by hand in five places — `{change > 0 ? "+" : ""}{formatCurrency(
|
|
88
|
+
* change)}` in a span coloured by a ternary (lease-columns:190, settlement-table:58,
|
|
89
|
+
* the tenancy `formatPct`) — and each picks its own colours for the same verdict.
|
|
90
|
+
*
|
|
91
|
+
* The visible figure (sign, digits, arrow) is hidden from assistive tech and spoken as
|
|
92
|
+
* words instead ("plus CHF 50.00" / "minus CHF 50.00", `signedAmount.*`): a "+" is
|
|
93
|
+
* skipped by most screen readers, and `Intl`'s "−" is read as "dash" or not at all.
|
|
94
|
+
*/
|
|
95
|
+
declare function SignedAmount({ value, currency, unit, compact, digits, format, locale, tone, goodDirection, showPlus, arrow, sensitive, labels, className, ...rest }: SignedAmountProps): react.JSX.Element;
|
|
96
|
+
interface DeltaProps extends SignedFormatProps, Omit<ComponentPropsWithoutRef<"span">, "children"> {
|
|
97
|
+
/** The change. Above zero is "up". */
|
|
98
|
+
value: number;
|
|
99
|
+
/** Which way is good news. Unset, the change is stated and not judged (muted); set,
|
|
100
|
+
* it is coloured `success` / `danger` and its sentence says "(better)" / "(worse)". */
|
|
101
|
+
goodDirection?: GoodDirection;
|
|
102
|
+
/** What it is measured against, after it: "vs last month". */
|
|
103
|
+
label?: ReactNode;
|
|
104
|
+
/** Hide the arrow (shown by default, as on a StatTile). At zero the arrow is a flat
|
|
105
|
+
* dash BESIDE the figure ("– 0.00 %"), never in place of it. */
|
|
106
|
+
arrow?: boolean;
|
|
107
|
+
sensitive?: boolean;
|
|
108
|
+
/** The `statTile` namespace's direction words — a delta says the same as a tile's. */
|
|
109
|
+
labels?: Partial<Pick<StatTileLabels, "increase" | "decrease" | "unchanged" | "better" | "worse">>;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* `StatTile`'s delta on its own: an arrow, the unsigned magnitude, and a sentence for
|
|
113
|
+
* screen readers ("Up 12% (worse)"), coloured only when `goodDirection` judges it —
|
|
114
|
+
* users up and cost up are the same arrow until someone says which is good.
|
|
115
|
+
*
|
|
116
|
+
* For a change shown outside a tile: kastlan's rent-change column
|
|
117
|
+
* (lease-columns:219, a "+1.25%" chip), the breakdown rows of the rent calculator
|
|
118
|
+
* (breakdown-row:5, a trend icon coloured by hand).
|
|
119
|
+
*/
|
|
120
|
+
declare function Delta({ value, currency, unit, compact, digits, format, locale, goodDirection, label, arrow, sensitive, labels, className, ...rest }: DeltaProps): react.JSX.Element | null;
|
|
121
|
+
|
|
122
|
+
export { DEFAULT_SIGNED_AMOUNT_LABELS, Delta, type DeltaProps, type GoodDirection, SignedAmount, type SignedAmountLabels, type SignedAmountProps, type SignedAmountTone, type TextTone, Tone, type ToneProps, toneTextClass };
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { ArrowDown, ArrowUp, Minus } from "lucide-react";
|
|
4
|
+
import { cn } from "../lib/cn.js";
|
|
5
|
+
import { formatMoney, formatNumber, formatPercent } from "../lib/format.js";
|
|
6
|
+
import { useKitLabels, useKitLocale } from "../i18n/kit-labels.js";
|
|
7
|
+
import { DEFAULT_STAT_TILE_LABELS } from "./stat-tile.js";
|
|
8
|
+
const TEXT_TONE = {
|
|
9
|
+
default: "text-[var(--text-primary)]",
|
|
10
|
+
muted: "text-[var(--text-muted)]",
|
|
11
|
+
brand: "text-[var(--brand)]",
|
|
12
|
+
income: "text-[var(--money-income)]",
|
|
13
|
+
expense: "text-[var(--money-expense)]",
|
|
14
|
+
net: "text-[var(--money-net)]",
|
|
15
|
+
success: "text-[var(--success)]",
|
|
16
|
+
warning: "text-[var(--warning)]",
|
|
17
|
+
danger: "text-[var(--danger)]",
|
|
18
|
+
info: "text-[var(--info)]"
|
|
19
|
+
};
|
|
20
|
+
function toneTextClass(tone) {
|
|
21
|
+
return TEXT_TONE[tone];
|
|
22
|
+
}
|
|
23
|
+
function Tone({ tone, className, ...rest }) {
|
|
24
|
+
return /* @__PURE__ */ jsx("span", { ...rest, className: cn(TEXT_TONE[tone], className) });
|
|
25
|
+
}
|
|
26
|
+
const DEFAULT_SIGNED_AMOUNT_LABELS = {
|
|
27
|
+
positive: (amount) => `plus ${amount}`,
|
|
28
|
+
negative: (amount) => `minus ${amount}`
|
|
29
|
+
};
|
|
30
|
+
function useMagnitudeFormatter({ currency, unit, compact, digits, format, locale }) {
|
|
31
|
+
const kitLocale = useKitLocale(locale);
|
|
32
|
+
return (magnitude) => {
|
|
33
|
+
if (format) return format(magnitude);
|
|
34
|
+
if (unit === "percent") return formatPercent(magnitude, { locale: kitLocale, compact, digits });
|
|
35
|
+
if (currency) return formatMoney(magnitude, currency, { locale: kitLocale, compact, digits });
|
|
36
|
+
return formatNumber(magnitude, { locale: kitLocale, compact, digits });
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function directionOf(value) {
|
|
40
|
+
return value > 0 ? "up" : value < 0 ? "down" : "flat";
|
|
41
|
+
}
|
|
42
|
+
function signedToneClass(tone, dir, goodDirection) {
|
|
43
|
+
if (tone === "verdict" || goodDirection && tone === "signed") {
|
|
44
|
+
if (dir === "flat" || !goodDirection) return TEXT_TONE.muted;
|
|
45
|
+
return dir === goodDirection ? TEXT_TONE.success : TEXT_TONE.danger;
|
|
46
|
+
}
|
|
47
|
+
if (tone === "signed") return dir === "flat" ? TEXT_TONE.muted : dir === "up" ? TEXT_TONE.income : TEXT_TONE.expense;
|
|
48
|
+
if (tone === "neutral") return "";
|
|
49
|
+
return TEXT_TONE[tone];
|
|
50
|
+
}
|
|
51
|
+
const ARROW = { up: ArrowUp, down: ArrowDown, flat: Minus };
|
|
52
|
+
function SignedAmount({
|
|
53
|
+
value,
|
|
54
|
+
currency,
|
|
55
|
+
unit,
|
|
56
|
+
compact,
|
|
57
|
+
digits,
|
|
58
|
+
format,
|
|
59
|
+
locale,
|
|
60
|
+
tone = "signed",
|
|
61
|
+
goodDirection,
|
|
62
|
+
showPlus = true,
|
|
63
|
+
arrow = false,
|
|
64
|
+
sensitive = false,
|
|
65
|
+
labels,
|
|
66
|
+
className,
|
|
67
|
+
...rest
|
|
68
|
+
}) {
|
|
69
|
+
const text = useKitLabels("signedAmount", DEFAULT_SIGNED_AMOUNT_LABELS, labels);
|
|
70
|
+
const fmt = useMagnitudeFormatter({ currency, unit, compact, digits, format, locale });
|
|
71
|
+
const finite = Number.isFinite(value);
|
|
72
|
+
const dir = finite ? directionOf(value) : "flat";
|
|
73
|
+
const amount = finite ? fmt(Math.abs(value)) : "\u2014";
|
|
74
|
+
const sign = dir === "up" ? showPlus ? "+" : "" : dir === "down" ? "\u2212" : "";
|
|
75
|
+
const spoken = dir === "up" ? text.positive(amount) : dir === "down" ? text.negative(amount) : amount;
|
|
76
|
+
const Icon = ARROW[dir];
|
|
77
|
+
return /* @__PURE__ */ jsxs(
|
|
78
|
+
"span",
|
|
79
|
+
{
|
|
80
|
+
...rest,
|
|
81
|
+
"data-private": sensitive ? "" : void 0,
|
|
82
|
+
"data-direction": dir,
|
|
83
|
+
className: cn(
|
|
84
|
+
"relative inline-flex items-center gap-0.5 whitespace-nowrap tabular-nums",
|
|
85
|
+
signedToneClass(tone, dir, goodDirection),
|
|
86
|
+
className
|
|
87
|
+
),
|
|
88
|
+
children: [
|
|
89
|
+
arrow && /* @__PURE__ */ jsx(Icon, { "aria-hidden": true, className: "size-[1em] shrink-0" }),
|
|
90
|
+
/* @__PURE__ */ jsxs("span", { "aria-hidden": true, children: [
|
|
91
|
+
sign,
|
|
92
|
+
amount
|
|
93
|
+
] }),
|
|
94
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: spoken })
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
function Delta({
|
|
100
|
+
value,
|
|
101
|
+
currency,
|
|
102
|
+
unit,
|
|
103
|
+
compact,
|
|
104
|
+
digits,
|
|
105
|
+
format,
|
|
106
|
+
locale,
|
|
107
|
+
goodDirection,
|
|
108
|
+
label,
|
|
109
|
+
arrow = true,
|
|
110
|
+
sensitive = false,
|
|
111
|
+
labels,
|
|
112
|
+
className,
|
|
113
|
+
...rest
|
|
114
|
+
}) {
|
|
115
|
+
const text = useKitLabels("statTile", DEFAULT_STAT_TILE_LABELS, labels);
|
|
116
|
+
const fmt = useMagnitudeFormatter({ currency, unit, compact, digits, format, locale });
|
|
117
|
+
if (!Number.isFinite(value)) return null;
|
|
118
|
+
const amount = fmt(Math.abs(value));
|
|
119
|
+
const dir = directionOf(value);
|
|
120
|
+
const Icon = ARROW[dir];
|
|
121
|
+
let spoken = dir === "up" ? text.increase(amount) : dir === "down" ? text.decrease(amount) : text.unchanged;
|
|
122
|
+
let tone = TEXT_TONE.muted;
|
|
123
|
+
if (goodDirection && dir !== "flat") {
|
|
124
|
+
const good = dir === goodDirection;
|
|
125
|
+
spoken = good ? text.better(spoken) : text.worse(spoken);
|
|
126
|
+
tone = good ? TEXT_TONE.success : TEXT_TONE.danger;
|
|
127
|
+
}
|
|
128
|
+
return /* @__PURE__ */ jsxs(
|
|
129
|
+
"span",
|
|
130
|
+
{
|
|
131
|
+
...rest,
|
|
132
|
+
"data-direction": dir,
|
|
133
|
+
className: cn("relative inline-flex flex-wrap items-center gap-x-1.5 tabular-nums", className),
|
|
134
|
+
children: [
|
|
135
|
+
/* @__PURE__ */ jsxs("span", { "data-private": sensitive ? "" : void 0, className: cn("inline-flex items-center gap-0.5 font-medium", tone), children: [
|
|
136
|
+
arrow && /* @__PURE__ */ jsx(Icon, { className: "size-[1em] shrink-0", "aria-hidden": true }),
|
|
137
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": true, children: amount }),
|
|
138
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: spoken })
|
|
139
|
+
] }),
|
|
140
|
+
label != null && /* @__PURE__ */ jsx("span", { className: "text-[var(--text-muted)]", children: label })
|
|
141
|
+
]
|
|
142
|
+
}
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
export {
|
|
146
|
+
DEFAULT_SIGNED_AMOUNT_LABELS,
|
|
147
|
+
Delta,
|
|
148
|
+
SignedAmount,
|
|
149
|
+
Tone,
|
|
150
|
+
toneTextClass
|
|
151
|
+
};
|
|
152
|
+
//# sourceMappingURL=signed-amount.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/signed-amount.tsx"],"sourcesContent":["import type { ComponentPropsWithoutRef, ReactNode } from \"react\";\nimport { ArrowDown, ArrowUp, Minus } from \"lucide-react\";\nimport { cn } from \"../lib/cn\";\nimport { formatMoney, formatNumber, formatPercent } from \"../lib/format\";\nimport { useKitLabels, useKitLocale } from \"../i18n/kit-labels\";\nimport { DEFAULT_STAT_TILE_LABELS } from \"./stat-tile\";\nimport type { StatTileLabels } from \"./stat-tile\";\n\n/**\n * The text colours a figure can carry, token-backed — `StatTile`'s tones, as a class\n * any span can take.\n *\n * - `default` — the primary text colour. `muted` — the secondary, quiet one.\n * - `income` / `expense` / `net` — the money trio (CVD-safe teal / amber / violet).\n * - `success` / `warning` / `danger` / `info` — a verdict: a rent rise is the tenant's\n * bad news (kastlan lease-columns), a vote \"for\" is green (meeting-agenda-tab).\n * - `brand` — the app's accent.\n *\n * Colour is never the only carrier: pair a verdict with an arrow, a word, or a sign.\n */\nexport type TextTone =\n | \"default\"\n | \"muted\"\n | \"brand\"\n | \"income\"\n | \"expense\"\n | \"net\"\n | \"success\"\n | \"warning\"\n | \"danger\"\n | \"info\";\n\nconst TEXT_TONE: Record<TextTone, string> = {\n default: \"text-[var(--text-primary)]\",\n muted: \"text-[var(--text-muted)]\",\n brand: \"text-[var(--brand)]\",\n income: \"text-[var(--money-income)]\",\n expense: \"text-[var(--money-expense)]\",\n net: \"text-[var(--money-net)]\",\n success: \"text-[var(--success)]\",\n warning: \"text-[var(--warning)]\",\n danger: \"text-[var(--danger)]\",\n info: \"text-[var(--info)]\",\n};\n\n/**\n * The class that colours text in `tone` — for the spans kastlan colours by hand with\n * `text-[var(--danger)]` / `text-emerald-600` (settlement-table, changelog-page,\n * meeting-agenda-tab), so the palette they draw from is the kit's tokens.\n */\nexport function toneTextClass(tone: TextTone): string {\n return TEXT_TONE[tone];\n}\n\nexport interface ToneProps extends ComponentPropsWithoutRef<\"span\"> {\n tone: TextTone;\n}\n\n/** A `<span>` in a {@link TextTone} — `<Tone tone=\"success\">{votesFor}</Tone>`. */\nexport function Tone({ tone, className, ...rest }: ToneProps) {\n return <span {...rest} className={cn(TEXT_TONE[tone], className)} />;\n}\n\n/* ── Signed amounts ──────────────────────────────────────────────────────── */\n\n/** Which way is +1: `up` for a figure where more is good news (income, savings),\n * `down` where less is (a rent the tenant pays, a cost). */\nexport type GoodDirection = \"up\" | \"down\";\n\n/**\n * How a signed figure is coloured:\n * - `signed` (default) — money read by its own sign: above zero `income`, below zero\n * `expense`, zero muted. A balance, a net.\n * - `income` / `expense` / `neutral` — one colour whatever the sign (`neutral` is the\n * text's own colour).\n * - `verdict` — the change judged by {@link SignedAmountProps.goodDirection}: good\n * news `success`, bad news `danger`, zero muted. Setting `goodDirection` implies it.\n */\nexport type SignedAmountTone = \"signed\" | \"income\" | \"expense\" | \"neutral\" | \"verdict\";\n\n/** What a signed figure says to a screen reader, whose readers disagree about a\n * leading \"+\" (most skip it) and a \"−\" (some read \"dash\", some nothing). */\nexport interface SignedAmountLabels {\n /** A figure above zero. `amount` is formatted and unsigned. */\n positive: (amount: string) => string;\n /** A figure below zero. `amount` is formatted and unsigned. */\n negative: (amount: string) => string;\n}\n\nexport const DEFAULT_SIGNED_AMOUNT_LABELS: SignedAmountLabels = {\n positive: (amount) => `plus ${amount}`,\n negative: (amount) => `minus ${amount}`,\n};\n\ninterface SignedFormatProps {\n /** ISO 4217 code: format as money. */\n currency?: string;\n /** `\"percent\"` reads `value` as a RATIO (`0.12` → 12 %), as `StatTile`'s delta does. */\n unit?: \"value\" | \"percent\";\n /** Compact notation: 12 400 → \"12K\". */\n compact?: boolean;\n /** Fraction digits, as `formatNumber`'s `digits`. */\n digits?: number | { min?: number; max?: number };\n /** Formats the UNSIGNED magnitude, replacing the `Intl` default outright. The sign\n * is the component's. */\n format?: (magnitude: number) => string;\n locale?: string;\n}\n\nfunction useMagnitudeFormatter({ currency, unit, compact, digits, format, locale }: SignedFormatProps) {\n const kitLocale = useKitLocale(locale);\n return (magnitude: number): string => {\n if (format) return format(magnitude);\n if (unit === \"percent\") return formatPercent(magnitude, { locale: kitLocale, compact, digits });\n if (currency) return formatMoney(magnitude, currency, { locale: kitLocale, compact, digits });\n return formatNumber(magnitude, { locale: kitLocale, compact, digits });\n };\n}\n\nfunction directionOf(value: number): \"up\" | \"down\" | \"flat\" {\n return value > 0 ? \"up\" : value < 0 ? \"down\" : \"flat\";\n}\n\nfunction signedToneClass(\n tone: SignedAmountTone,\n dir: \"up\" | \"down\" | \"flat\",\n goodDirection: GoodDirection | undefined,\n): string {\n if (tone === \"verdict\" || (goodDirection && tone === \"signed\")) {\n if (dir === \"flat\" || !goodDirection) return TEXT_TONE.muted;\n return dir === goodDirection ? TEXT_TONE.success : TEXT_TONE.danger;\n }\n if (tone === \"signed\") return dir === \"flat\" ? TEXT_TONE.muted : dir === \"up\" ? TEXT_TONE.income : TEXT_TONE.expense;\n if (tone === \"neutral\") return \"\";\n return TEXT_TONE[tone];\n}\n\nconst ARROW = { up: ArrowUp, down: ArrowDown, flat: Minus } as const;\n\nexport interface SignedAmountProps\n extends SignedFormatProps,\n Omit<ComponentPropsWithoutRef<\"span\">, \"children\"> {\n value: number;\n /** See {@link SignedAmountTone}. Default `signed`, or `verdict` with `goodDirection`. */\n tone?: SignedAmountTone;\n /** Which way is good news — colours by verdict (`success` / `danger`). */\n goodDirection?: GoodDirection;\n /** Print \"+\" before a positive figure (default `true`). A negative always shows its\n * minus; zero shows neither. */\n showPlus?: boolean;\n /** An arrow before the figure (up / down / a dash at zero) — so the direction does not\n * ride on colour alone. Decorative; the words say the same. */\n arrow?: boolean;\n /** Tag the figure `data-private`, for the host's demo-mode blur. */\n sensitive?: boolean;\n labels?: Partial<SignedAmountLabels>;\n}\n\n/**\n * A figure with a sign that matters: a balance, a rent change, a net.\n *\n * kastlan writes it by hand in five places — `{change > 0 ? \"+\" : \"\"}{formatCurrency(\n * change)}` in a span coloured by a ternary (lease-columns:190, settlement-table:58,\n * the tenancy `formatPct`) — and each picks its own colours for the same verdict.\n *\n * The visible figure (sign, digits, arrow) is hidden from assistive tech and spoken as\n * words instead (\"plus CHF 50.00\" / \"minus CHF 50.00\", `signedAmount.*`): a \"+\" is\n * skipped by most screen readers, and `Intl`'s \"−\" is read as \"dash\" or not at all.\n */\nexport function SignedAmount({\n value,\n currency,\n unit,\n compact,\n digits,\n format,\n locale,\n tone = \"signed\",\n goodDirection,\n showPlus = true,\n arrow = false,\n sensitive = false,\n labels,\n className,\n ...rest\n}: SignedAmountProps) {\n const text = useKitLabels(\"signedAmount\", DEFAULT_SIGNED_AMOUNT_LABELS, labels);\n const fmt = useMagnitudeFormatter({ currency, unit, compact, digits, format, locale });\n const finite = Number.isFinite(value);\n const dir = finite ? directionOf(value) : \"flat\";\n const amount = finite ? fmt(Math.abs(value)) : \"—\";\n // U+2212, the typographic minus: the same width as \"+\", so a column of signed figures\n // lines up under `tabular-nums`.\n const sign = dir === \"up\" ? (showPlus ? \"+\" : \"\") : dir === \"down\" ? \"−\" : \"\";\n const spoken = dir === \"up\" ? text.positive(amount) : dir === \"down\" ? text.negative(amount) : amount;\n const Icon = ARROW[dir];\n return (\n <span\n {...rest}\n data-private={sensitive ? \"\" : undefined}\n data-direction={dir}\n className={cn(\n \"relative inline-flex items-center gap-0.5 whitespace-nowrap tabular-nums\",\n signedToneClass(tone, dir, goodDirection),\n className,\n )}\n >\n {arrow && <Icon aria-hidden className=\"size-[1em] shrink-0\" />}\n <span aria-hidden>\n {sign}\n {amount}\n </span>\n <span className=\"sr-only\">{spoken}</span>\n </span>\n );\n}\n\nexport interface DeltaProps extends SignedFormatProps, Omit<ComponentPropsWithoutRef<\"span\">, \"children\"> {\n /** The change. Above zero is \"up\". */\n value: number;\n /** Which way is good news. Unset, the change is stated and not judged (muted); set,\n * it is coloured `success` / `danger` and its sentence says \"(better)\" / \"(worse)\". */\n goodDirection?: GoodDirection;\n /** What it is measured against, after it: \"vs last month\". */\n label?: ReactNode;\n /** Hide the arrow (shown by default, as on a StatTile). At zero the arrow is a flat\n * dash BESIDE the figure (\"– 0.00 %\"), never in place of it. */\n arrow?: boolean;\n sensitive?: boolean;\n /** The `statTile` namespace's direction words — a delta says the same as a tile's. */\n labels?: Partial<Pick<StatTileLabels, \"increase\" | \"decrease\" | \"unchanged\" | \"better\" | \"worse\">>;\n}\n\n/**\n * `StatTile`'s delta on its own: an arrow, the unsigned magnitude, and a sentence for\n * screen readers (\"Up 12% (worse)\"), coloured only when `goodDirection` judges it —\n * users up and cost up are the same arrow until someone says which is good.\n *\n * For a change shown outside a tile: kastlan's rent-change column\n * (lease-columns:219, a \"+1.25%\" chip), the breakdown rows of the rent calculator\n * (breakdown-row:5, a trend icon coloured by hand).\n */\nexport function Delta({\n value,\n currency,\n unit,\n compact,\n digits,\n format,\n locale,\n goodDirection,\n label,\n arrow = true,\n sensitive = false,\n labels,\n className,\n ...rest\n}: DeltaProps) {\n const text = useKitLabels(\"statTile\", DEFAULT_STAT_TILE_LABELS, labels);\n const fmt = useMagnitudeFormatter({ currency, unit, compact, digits, format, locale });\n if (!Number.isFinite(value)) return null;\n const amount = fmt(Math.abs(value));\n const dir = directionOf(value);\n const Icon = ARROW[dir];\n let spoken = dir === \"up\" ? text.increase(amount) : dir === \"down\" ? text.decrease(amount) : text.unchanged;\n let tone = TEXT_TONE.muted;\n if (goodDirection && dir !== \"flat\") {\n const good = dir === goodDirection;\n spoken = good ? text.better(spoken) : text.worse(spoken);\n tone = good ? TEXT_TONE.success : TEXT_TONE.danger;\n }\n return (\n <span\n {...rest}\n data-direction={dir}\n className={cn(\"relative inline-flex flex-wrap items-center gap-x-1.5 tabular-nums\", className)}\n >\n <span data-private={sensitive ? \"\" : undefined} className={cn(\"inline-flex items-center gap-0.5 font-medium\", tone)}>\n {arrow && <Icon className=\"size-[1em] shrink-0\" aria-hidden />}\n {/* The figure at zero too, beside the flat dash (kastlan feedback #48). Before\n this a flat delta with an arrow drew the dash ALONE, as a StatTile does — so\n a rent-change column that printed \"0.00 %\" for an unchanged lease showed a\n bare \"–\" in its place, and a bare dash is what a table prints for a MISSING\n value: \"unchanged\" and \"not known\" looked the same. The Minus icon is the\n neutral indicator, the muted tone the neutral colour, and the figure says\n how much (none) in the column's own digits. A value that is missing never\n reaches here — a non-finite one renders nothing, above. Visible change for\n every `<Delta value={0}>` with the default arrow: \"–\" became \"– 0 %\". */}\n <span aria-hidden>{amount}</span>\n <span className=\"sr-only\">{spoken}</span>\n </span>\n {label != null && <span className=\"text-[var(--text-muted)]\">{label}</span>}\n </span>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -19,6 +19,13 @@ interface SkeletonProps extends Omit<ComponentPropsWithoutRef<"div">, "children"
|
|
|
19
19
|
shape?: SkeletonShape;
|
|
20
20
|
/** For `line`: this many lines, the last one shorter — a paragraph's outline. */
|
|
21
21
|
lines?: number;
|
|
22
|
+
/**
|
|
23
|
+
* Say what is loading, once: wraps the placeholder in a `role="status"` region with
|
|
24
|
+
* this as its (visually hidden) text — kastlan's activity feed (activity-feed:52)
|
|
25
|
+
* built exactly that by hand around `<Skeleton lines={5} />`. The placeholder itself
|
|
26
|
+
* stays hidden. Left out, nothing is announced, as before.
|
|
27
|
+
*/
|
|
28
|
+
label?: string;
|
|
22
29
|
}
|
|
23
30
|
/**
|
|
24
31
|
* A grey stand-in for content that is on its way.
|
|
@@ -28,9 +35,9 @@ interface SkeletonProps extends Omit<ComponentPropsWithoutRef<"div">, "children"
|
|
|
28
35
|
*
|
|
29
36
|
* ALWAYS `aria-hidden`. A placeholder is not content, and a reader that met twelve
|
|
30
37
|
* unnamed grey boxes would have learned nothing. Say "loading" once, where it
|
|
31
|
-
* belongs: `aria-busy` on the region being filled,
|
|
32
|
-
* beside the skeletons
|
|
38
|
+
* belongs: `aria-busy` on the region being filled, a `Spinner` / sr-only line
|
|
39
|
+
* beside the skeletons, or this component's own `label`.
|
|
33
40
|
*/
|
|
34
|
-
declare function Skeleton({
|
|
41
|
+
declare function Skeleton({ label, ...props }: SkeletonProps): react.JSX.Element;
|
|
35
42
|
|
|
36
43
|
export { SKELETON_CLASS, Skeleton, type SkeletonProps, type SkeletonShape };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { cn } from "../lib/cn.js";
|
|
4
4
|
const SKELETON_CLASS = "animate-pulse rounded bg-[var(--bg-active)] motion-reduce:animate-none";
|
|
5
5
|
const SHAPE = {
|
|
@@ -7,7 +7,17 @@ const SHAPE = {
|
|
|
7
7
|
block: "h-24 w-full rounded-md",
|
|
8
8
|
circle: "size-10 rounded-full"
|
|
9
9
|
};
|
|
10
|
-
function Skeleton({
|
|
10
|
+
function Skeleton({ label, ...props }) {
|
|
11
|
+
if (!label) return /* @__PURE__ */ jsx(SkeletonFill, { ...props });
|
|
12
|
+
return (
|
|
13
|
+
// `relative`: the containing block for the sr-only text (sr-only-containment.test).
|
|
14
|
+
/* @__PURE__ */ jsxs("div", { role: "status", className: "relative", "data-skeleton-status": "", children: [
|
|
15
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: label }),
|
|
16
|
+
/* @__PURE__ */ jsx(SkeletonFill, { ...props })
|
|
17
|
+
] })
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
function SkeletonFill({ shape = "line", lines, className, ...rest }) {
|
|
11
21
|
if (shape === "line" && lines !== void 0 && lines > 1) {
|
|
12
22
|
return /* @__PURE__ */ jsx("div", { ...rest, "aria-hidden": true, className: cn("flex flex-col gap-2", className), "data-skeleton": "lines", children: Array.from({ length: lines }, (_, i) => /* @__PURE__ */ jsx(
|
|
13
23
|
"div",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/skeleton.tsx"],"sourcesContent":["import type { ComponentPropsWithoutRef } from \"react\";\nimport { cn } from \"../lib/cn\";\n\n/**\n * The look of a placeholder, as one class string — the same fill and pulse\n * `StatTile`'s `loading` headline draws (it imports this), so a tile and the list\n * beside it shimmer as one surface.\n *\n * `motion-reduce:animate-none`: a pulse is motion with no information in it, which\n * is exactly what `prefers-reduced-motion` asks to be dropped. The fill stays, so the\n * shape of what is coming is still there.\n */\nexport const SKELETON_CLASS = \"animate-pulse rounded bg-[var(--bg-active)] motion-reduce:animate-none\";\n\nexport type SkeletonShape = \"line\" | \"block\" | \"circle\";\n\nexport interface SkeletonProps extends Omit<ComponentPropsWithoutRef<\"div\">, \"children\"> {\n /** `line` (default): a bar the height of a line of small text. `block`: an area\n * (an image, a chart, a card body). `circle`: an avatar. Size any of them with\n * `className` (`w-32`, `h-40`, `size-8`). */\n shape?: SkeletonShape;\n /** For `line`: this many lines, the last one shorter — a paragraph's outline. */\n lines?: number;\n}\n\nconst SHAPE: Record<SkeletonShape, string> = {\n line: \"h-3 w-full\",\n block: \"h-24 w-full rounded-md\",\n circle: \"size-10 rounded-full\",\n};\n\n/**\n * A grey stand-in for content that is on its way.\n *\n * keksdose and kastlan both drew these by hand — `animate-pulse bg-slate-200` in one\n * place, a token in the next, a pulse that ran under reduced motion everywhere.\n *\n * ALWAYS `aria-hidden`. A placeholder is not content, and a reader that met twelve\n * unnamed grey boxes would have learned nothing. Say \"loading\" once, where it\n * belongs: `aria-busy` on the region being filled,
|
|
1
|
+
{"version":3,"sources":["../../src/components/skeleton.tsx"],"sourcesContent":["import type { ComponentPropsWithoutRef } from \"react\";\nimport { cn } from \"../lib/cn\";\n\n/**\n * The look of a placeholder, as one class string — the same fill and pulse\n * `StatTile`'s `loading` headline draws (it imports this), so a tile and the list\n * beside it shimmer as one surface.\n *\n * `motion-reduce:animate-none`: a pulse is motion with no information in it, which\n * is exactly what `prefers-reduced-motion` asks to be dropped. The fill stays, so the\n * shape of what is coming is still there.\n */\nexport const SKELETON_CLASS = \"animate-pulse rounded bg-[var(--bg-active)] motion-reduce:animate-none\";\n\nexport type SkeletonShape = \"line\" | \"block\" | \"circle\";\n\nexport interface SkeletonProps extends Omit<ComponentPropsWithoutRef<\"div\">, \"children\"> {\n /** `line` (default): a bar the height of a line of small text. `block`: an area\n * (an image, a chart, a card body). `circle`: an avatar. Size any of them with\n * `className` (`w-32`, `h-40`, `size-8`). */\n shape?: SkeletonShape;\n /** For `line`: this many lines, the last one shorter — a paragraph's outline. */\n lines?: number;\n /**\n * Say what is loading, once: wraps the placeholder in a `role=\"status\"` region with\n * this as its (visually hidden) text — kastlan's activity feed (activity-feed:52)\n * built exactly that by hand around `<Skeleton lines={5} />`. The placeholder itself\n * stays hidden. Left out, nothing is announced, as before.\n */\n label?: string;\n}\n\nconst SHAPE: Record<SkeletonShape, string> = {\n line: \"h-3 w-full\",\n block: \"h-24 w-full rounded-md\",\n circle: \"size-10 rounded-full\",\n};\n\n/**\n * A grey stand-in for content that is on its way.\n *\n * keksdose and kastlan both drew these by hand — `animate-pulse bg-slate-200` in one\n * place, a token in the next, a pulse that ran under reduced motion everywhere.\n *\n * ALWAYS `aria-hidden`. A placeholder is not content, and a reader that met twelve\n * unnamed grey boxes would have learned nothing. Say \"loading\" once, where it\n * belongs: `aria-busy` on the region being filled, a `Spinner` / sr-only line\n * beside the skeletons, or this component's own `label`.\n */\nexport function Skeleton({ label, ...props }: SkeletonProps) {\n if (!label) return <SkeletonFill {...props} />;\n return (\n // `relative`: the containing block for the sr-only text (sr-only-containment.test).\n <div role=\"status\" className=\"relative\" data-skeleton-status=\"\">\n <span className=\"sr-only\">{label}</span>\n <SkeletonFill {...props} />\n </div>\n );\n}\n\nfunction SkeletonFill({ shape = \"line\", lines, className, ...rest }: Omit<SkeletonProps, \"label\">) {\n if (shape === \"line\" && lines !== undefined && lines > 1) {\n return (\n <div {...rest} aria-hidden className={cn(\"flex flex-col gap-2\", className)} data-skeleton=\"lines\">\n {Array.from({ length: lines }, (_, i) => (\n <div\n key={i}\n className={cn(SKELETON_CLASS, SHAPE.line, i === lines - 1 && \"w-2/3\")}\n data-skeleton=\"line\"\n />\n ))}\n </div>\n );\n }\n return (\n <div\n {...rest}\n aria-hidden\n data-skeleton={shape}\n className={cn(SKELETON_CLASS, SHAPE[shape], className)}\n />\n );\n}\n"],"mappings":";AAkDqB,cAGjB,YAHiB;AAjDrB,SAAS,UAAU;AAWZ,MAAM,iBAAiB;AAoB9B,MAAM,QAAuC;AAAA,EAC3C,MAAM;AAAA,EACN,OAAO;AAAA,EACP,QAAQ;AACV;AAaO,SAAS,SAAS,EAAE,OAAO,GAAG,MAAM,GAAkB;AAC3D,MAAI,CAAC,MAAO,QAAO,oBAAC,gBAAc,GAAG,OAAO;AAC5C;AAAA;AAAA,IAEE,qBAAC,SAAI,MAAK,UAAS,WAAU,YAAW,wBAAqB,IAC3D;AAAA,0BAAC,UAAK,WAAU,WAAW,iBAAM;AAAA,MACjC,oBAAC,gBAAc,GAAG,OAAO;AAAA,OAC3B;AAAA;AAEJ;AAEA,SAAS,aAAa,EAAE,QAAQ,QAAQ,OAAO,WAAW,GAAG,KAAK,GAAiC;AACjG,MAAI,UAAU,UAAU,UAAU,UAAa,QAAQ,GAAG;AACxD,WACE,oBAAC,SAAK,GAAG,MAAM,eAAW,MAAC,WAAW,GAAG,uBAAuB,SAAS,GAAG,iBAAc,SACvF,gBAAM,KAAK,EAAE,QAAQ,MAAM,GAAG,CAAC,GAAG,MACjC;AAAA,MAAC;AAAA;AAAA,QAEC,WAAW,GAAG,gBAAgB,MAAM,MAAM,MAAM,QAAQ,KAAK,OAAO;AAAA,QACpE,iBAAc;AAAA;AAAA,MAFT;AAAA,IAGP,CACD,GACH;AAAA,EAEJ;AACA,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ,eAAW;AAAA,MACX,iBAAe;AAAA,MACf,WAAW,GAAG,gBAAgB,MAAM,KAAK,GAAG,SAAS;AAAA;AAAA,EACvD;AAEJ;","names":[]}
|
|
@@ -166,7 +166,8 @@ interface StatTileProps extends Omit<ComponentPropsWithoutRef<"div">, "children"
|
|
|
166
166
|
/** Makes the tile a link. See {@link renderLink} for a router. */
|
|
167
167
|
href?: string;
|
|
168
168
|
/** Renders the link for `href` — pass your router's `<Link>` here, since a plain
|
|
169
|
-
* `<a>` reloads a single-page app. Default: `<
|
|
169
|
+
* `<a>` reloads a single-page app. Default: the `<UiKitProvider linkComponent>`
|
|
170
|
+
* (for an in-app `href`), then `<a>`. */
|
|
170
171
|
renderLink?: (props: StatTileLinkProps) => ReactElement;
|
|
171
172
|
/** Makes the tile a button (ignored when `href` is given). */
|
|
172
173
|
onClick?: () => void;
|
|
@@ -3,7 +3,8 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { isValidElement, useId, useLayoutEffect, useState } from "react";
|
|
4
4
|
import { ArrowDown, ArrowUp, Minus } from "lucide-react";
|
|
5
5
|
import { cn } from "../lib/cn.js";
|
|
6
|
-
import { useKitLabels, useKitLocale } from "../i18n/kit-labels.js";
|
|
6
|
+
import { useKitLabels, useKitLink, useKitLocale } from "../i18n/kit-labels.js";
|
|
7
|
+
import { pickLinkRenderer, RenderedKitLink } from "./text-link.js";
|
|
7
8
|
import { Card, FieldHint } from "./ui.js";
|
|
8
9
|
import { Sparkline } from "./sparkline.js";
|
|
9
10
|
import { Tooltip } from "./tooltip.js";
|
|
@@ -82,6 +83,7 @@ function StatTile({
|
|
|
82
83
|
...rest
|
|
83
84
|
}) {
|
|
84
85
|
const text = useKitLabels("statTile", DEFAULT_STAT_TILE_LABELS, labels);
|
|
86
|
+
const kitLink = useKitLink();
|
|
85
87
|
const [labelEl, setLabelEl] = useState(null);
|
|
86
88
|
const labelCut = useIsTruncated(truncateLabel ? labelEl : null);
|
|
87
89
|
const kitLocale = useKitLocale(locale);
|
|
@@ -112,7 +114,8 @@ function StatTile({
|
|
|
112
114
|
"aria-describedby": describedBy,
|
|
113
115
|
children: label
|
|
114
116
|
};
|
|
115
|
-
|
|
117
|
+
const kit = pickLinkRenderer(void 0, kitLink, href);
|
|
118
|
+
labelNode = renderLink ? renderLink(linkProps) : kit ? /* @__PURE__ */ jsx(RenderedKitLink, { render: kit, props: linkProps }) : /* @__PURE__ */ jsx("a", { href, className: stretched, "aria-describedby": describedBy, children: label });
|
|
116
119
|
} else if (onClick) {
|
|
117
120
|
labelNode = /* @__PURE__ */ jsx("button", { type: "button", onClick, "aria-describedby": describedBy, className: stretched, children: label });
|
|
118
121
|
}
|
|
@@ -135,7 +138,7 @@ function StatTile({
|
|
|
135
138
|
/* @__PURE__ */ jsxs("div", { className: "relative mt-1 flex flex-wrap items-center gap-x-1.5 text-xs tabular-nums", children: [
|
|
136
139
|
/* @__PURE__ */ jsxs("span", { id: deltaId, "data-private": priv, className: cn("inline-flex items-center gap-0.5 font-medium", deltaTone), children: [
|
|
137
140
|
/* @__PURE__ */ jsx(Icon, { className: "size-3 shrink-0", "aria-hidden": true }),
|
|
138
|
-
/* @__PURE__ */ jsx("span", { "aria-hidden": true, children:
|
|
141
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": true, children: amount }),
|
|
139
142
|
/* @__PURE__ */ jsx("span", { className: "sr-only", children: spoken })
|
|
140
143
|
] }),
|
|
141
144
|
d.label != null && /* @__PURE__ */ jsx("span", { className: "text-[var(--text-muted)]", children: d.label })
|