@eifi1/ui-kit 0.4.1 → 0.5.1
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/LICENSE +32 -0
- package/README.md +498 -57
- package/dist/chart.d.ts +10 -0
- package/dist/chart.js +10 -0
- package/dist/chart.js.map +1 -0
- package/dist/components/account-settings.d.ts +11 -0
- package/dist/components/account-settings.js +19 -12
- package/dist/components/account-settings.js.map +1 -1
- package/dist/components/alert-banner.d.ts +10 -6
- package/dist/components/alert-banner.js +20 -16
- package/dist/components/alert-banner.js.map +1 -1
- package/dist/components/amount-input.d.ts +30 -4
- package/dist/components/amount-input.js +36 -14
- package/dist/components/amount-input.js.map +1 -1
- package/dist/components/calculator.d.ts +24 -7
- package/dist/components/calculator.js +37 -20
- package/dist/components/calculator.js.map +1 -1
- package/dist/components/chart-zoom.d.ts +156 -0
- package/dist/components/chart-zoom.js +262 -0
- package/dist/components/chart-zoom.js.map +1 -0
- package/dist/components/chart.d.ts +28 -3
- package/dist/components/chart.js +71 -32
- package/dist/components/chart.js.map +1 -1
- package/dist/components/checkbox.d.ts +51 -0
- package/dist/components/checkbox.js +123 -0
- package/dist/components/checkbox.js.map +1 -0
- package/dist/components/chip.d.ts +142 -0
- package/dist/components/chip.js +357 -0
- package/dist/components/chip.js.map +1 -0
- package/dist/components/choice-parts.d.ts +24 -0
- package/dist/components/choice-parts.js +18 -0
- package/dist/components/choice-parts.js.map +1 -0
- package/dist/components/combobox-core.d.ts +52 -9
- package/dist/components/combobox-core.js +89 -19
- package/dist/components/combobox-core.js.map +1 -1
- package/dist/components/combobox.d.ts +43 -33
- package/dist/components/combobox.js +409 -340
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/currency-select.d.ts +48 -8
- package/dist/components/currency-select.js +115 -65
- package/dist/components/currency-select.js.map +1 -1
- package/dist/components/data-table-filter-popover.d.ts +15 -3
- package/dist/components/data-table-filter-popover.js +23 -17
- 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 +3 -2
- package/dist/components/data-table-filters.js.map +1 -1
- package/dist/components/data-table-labels.d.ts +53 -2
- package/dist/components/data-table-labels.js +31 -2
- package/dist/components/data-table-labels.js.map +1 -1
- package/dist/components/data-table-pagination.d.ts +3 -1
- package/dist/components/data-table-pagination.js +16 -10
- package/dist/components/data-table-pagination.js.map +1 -1
- package/dist/components/data-table-sort.js +1 -0
- package/dist/components/data-table-sort.js.map +1 -1
- package/dist/components/data-table.d.ts +1 -1
- package/dist/components/data-table.js +201 -85
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/date-picker.d.ts +25 -9
- package/dist/components/date-picker.js +244 -94
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/dropdown.d.ts +74 -19
- package/dist/components/dropdown.js +72 -22
- package/dist/components/dropdown.js.map +1 -1
- package/dist/components/entity-combobox.d.ts +5 -4
- package/dist/components/entity-combobox.js +107 -76
- package/dist/components/entity-combobox.js.map +1 -1
- package/dist/components/facing-pair.d.ts +36 -0
- package/dist/components/facing-pair.js +40 -0
- package/dist/components/facing-pair.js.map +1 -0
- package/dist/components/field-sync.d.ts +164 -0
- package/dist/components/field-sync.js +264 -0
- package/dist/components/field-sync.js.map +1 -0
- package/dist/components/file-dropzone.d.ts +21 -7
- package/dist/components/file-dropzone.js +28 -7
- package/dist/components/file-dropzone.js.map +1 -1
- package/dist/components/full-bleed-dialog.d.ts +37 -26
- package/dist/components/full-bleed-dialog.js +20 -5
- package/dist/components/full-bleed-dialog.js.map +1 -1
- package/dist/components/grouped-picker.d.ts +21 -10
- package/dist/components/grouped-picker.js +66 -52
- package/dist/components/grouped-picker.js.map +1 -1
- package/dist/components/hover-menu.d.ts +20 -4
- package/dist/components/hover-menu.js +15 -4
- package/dist/components/hover-menu.js.map +1 -1
- package/dist/components/mini-calendar.d.ts +102 -14
- package/dist/components/mini-calendar.js +256 -70
- package/dist/components/mini-calendar.js.map +1 -1
- package/dist/components/modal.d.ts +9 -3
- package/dist/components/modal.js +34 -45
- package/dist/components/modal.js.map +1 -1
- package/dist/components/month-picker.d.ts +79 -0
- package/dist/components/month-picker.js +353 -0
- package/dist/components/month-picker.js.map +1 -0
- package/dist/components/multi-entity-combobox.d.ts +7 -6
- package/dist/components/multi-entity-combobox.js +112 -72
- package/dist/components/multi-entity-combobox.js.map +1 -1
- package/dist/components/multi-select.d.ts +13 -11
- package/dist/components/multi-select.js +161 -84
- package/dist/components/multi-select.js.map +1 -1
- package/dist/components/number-field.d.ts +92 -0
- package/dist/components/number-field.js +111 -0
- package/dist/components/number-field.js.map +1 -0
- package/dist/components/number-input.d.ts +21 -2
- package/dist/components/number-input.js +2 -1
- package/dist/components/number-input.js.map +1 -1
- package/dist/components/numpad-sheet.d.ts +25 -4
- package/dist/components/numpad-sheet.js +30 -13
- package/dist/components/numpad-sheet.js.map +1 -1
- package/dist/components/page-contents.d.ts +90 -0
- package/dist/components/page-contents.js +170 -0
- package/dist/components/page-contents.js.map +1 -0
- package/dist/components/password-strength.d.ts +106 -0
- package/dist/components/password-strength.js +132 -0
- package/dist/components/password-strength.js.map +1 -0
- package/dist/components/picker-sheet.d.ts +23 -15
- package/dist/components/picker-sheet.js +34 -14
- package/dist/components/picker-sheet.js.map +1 -1
- package/dist/components/popover.d.ts +62 -4
- package/dist/components/popover.js +55 -2
- package/dist/components/popover.js.map +1 -1
- package/dist/components/search-field.d.ts +25 -7
- package/dist/components/search-field.js +7 -5
- package/dist/components/search-field.js.map +1 -1
- package/dist/components/series-chart-labels.d.ts +14 -0
- package/dist/components/series-chart-labels.js +11 -0
- package/dist/components/series-chart-labels.js.map +1 -0
- package/dist/components/series-chart.d.ts +207 -0
- package/dist/components/series-chart.js +223 -0
- package/dist/components/series-chart.js.map +1 -0
- package/dist/components/settings-fields.d.ts +14 -4
- package/dist/components/settings-fields.js +19 -8
- package/dist/components/settings-fields.js.map +1 -1
- package/dist/components/signature-pad.d.ts +119 -0
- package/dist/components/signature-pad.js +405 -0
- package/dist/components/signature-pad.js.map +1 -0
- package/dist/components/slider.d.ts +80 -0
- package/dist/components/slider.js +155 -0
- package/dist/components/slider.js.map +1 -0
- package/dist/components/sparkline.d.ts +93 -0
- package/dist/components/sparkline.js +205 -0
- package/dist/components/sparkline.js.map +1 -0
- package/dist/components/stat-tile.d.ts +151 -0
- package/dist/components/stat-tile.js +236 -0
- package/dist/components/stat-tile.js.map +1 -0
- package/dist/components/swipeable-row.d.ts +25 -2
- package/dist/components/swipeable-row.js +31 -0
- package/dist/components/swipeable-row.js.map +1 -1
- package/dist/components/switch.d.ts +60 -0
- package/dist/components/switch.js +81 -0
- package/dist/components/switch.js.map +1 -0
- package/dist/components/time-input.d.ts +58 -0
- package/dist/components/time-input.js +50 -0
- package/dist/components/time-input.js.map +1 -0
- package/dist/components/toggle-group.d.ts +18 -3
- package/dist/components/toggle-group.js +10 -6
- package/dist/components/toggle-group.js.map +1 -1
- package/dist/components/toggle-legend.d.ts +115 -0
- package/dist/components/toggle-legend.js +114 -0
- package/dist/components/toggle-legend.js.map +1 -0
- package/dist/components/tooltip.d.ts +40 -11
- package/dist/components/tooltip.js +77 -20
- package/dist/components/tooltip.js.map +1 -1
- package/dist/components/treemap.d.ts +132 -0
- package/dist/components/treemap.js +179 -0
- package/dist/components/treemap.js.map +1 -0
- package/dist/components/trigger-aria.d.ts +18 -0
- package/dist/components/trigger-aria.js +25 -0
- package/dist/components/trigger-aria.js.map +1 -0
- package/dist/components/ui.d.ts +167 -46
- package/dist/components/ui.js +225 -121
- package/dist/components/ui.js.map +1 -1
- package/dist/components/use-mobile-reveal.js +1 -0
- package/dist/components/use-mobile-reveal.js.map +1 -1
- package/dist/components/use-table-state.d.ts +1 -1
- package/dist/components/use-table-state.js +38 -17
- package/dist/components/use-table-state.js.map +1 -1
- package/dist/components/user-avatar.d.ts +5 -3
- package/dist/components/user-avatar.js +4 -2
- package/dist/components/user-avatar.js.map +1 -1
- package/dist/components/wizard-stepper.js +3 -2
- package/dist/components/wizard-stepper.js.map +1 -1
- package/dist/{data-table-filters-aXyf0Xub.d.ts → data-table-filters-DM1auUfH.d.ts} +27 -5
- package/dist/data-table.d.ts +7 -0
- package/dist/data-table.js +12 -0
- package/dist/data-table.js.map +1 -0
- package/dist/feedback/feedback-attachment.js +12 -11
- package/dist/feedback/feedback-attachment.js.map +1 -1
- package/dist/feedback/feedback-dialog.js +2 -1
- package/dist/feedback/feedback-dialog.js.map +1 -1
- package/dist/feedback/feedback-inbox.d.ts +33 -7
- package/dist/feedback/feedback-inbox.js +49 -37
- package/dist/feedback/feedback-inbox.js.map +1 -1
- package/dist/feedback.d.ts +5 -0
- package/dist/feedback.js +5 -0
- package/dist/feedback.js.map +1 -0
- package/dist/hooks/use-anchored-panel.js +1 -0
- package/dist/hooks/use-anchored-panel.js.map +1 -1
- package/dist/hooks/use-anchored-rect.js +1 -0
- package/dist/hooks/use-anchored-rect.js.map +1 -1
- package/dist/hooks/use-announce.d.ts +46 -0
- package/dist/hooks/use-announce.js +37 -0
- package/dist/hooks/use-announce.js.map +1 -0
- package/dist/hooks/use-body-scroll-lock.js +1 -0
- package/dist/hooks/use-body-scroll-lock.js.map +1 -1
- package/dist/hooks/use-close-transition.js +1 -0
- package/dist/hooks/use-close-transition.js.map +1 -1
- package/dist/hooks/use-dismiss.js +1 -0
- package/dist/hooks/use-dismiss.js.map +1 -1
- package/dist/hooks/use-focus-trap.d.ts +16 -0
- package/dist/hooks/use-focus-trap.js +67 -0
- package/dist/hooks/use-focus-trap.js.map +1 -0
- package/dist/hooks/use-media-query.js +1 -0
- package/dist/hooks/use-media-query.js.map +1 -1
- package/dist/hooks/use-overlay-history.js +27 -1
- package/dist/hooks/use-overlay-history.js.map +1 -1
- package/dist/hooks/use-row-swipe.js +1 -0
- package/dist/hooks/use-row-swipe.js.map +1 -1
- package/dist/i18n/defaults.d.ts +31 -0
- package/dist/i18n/defaults.js +63 -0
- package/dist/i18n/defaults.js.map +1 -0
- package/dist/i18n/kit-labels.d.ts +250 -0
- package/dist/i18n/kit-labels.js +184 -0
- package/dist/i18n/kit-labels.js.map +1 -0
- package/dist/index.d.ts +47 -22
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/calc.js +1 -0
- package/dist/lib/calc.js.map +1 -1
- package/dist/lib/cn.js +1 -0
- package/dist/lib/cn.js.map +1 -1
- package/dist/lib/dates.js +1 -0
- package/dist/lib/dates.js.map +1 -1
- package/dist/lib/logger.js +1 -0
- package/dist/lib/logger.js.map +1 -1
- package/dist/lib/safe-storage.js +1 -0
- package/dist/lib/safe-storage.js.map +1 -1
- package/dist/search/command-palette.d.ts +11 -1
- package/dist/search/command-palette.js +21 -15
- package/dist/search/command-palette.js.map +1 -1
- package/dist/search.d.ts +2 -0
- package/dist/search.js +3 -0
- package/dist/search.js.map +1 -0
- package/dist/shell/app-shell.d.ts +33 -4
- package/dist/shell/app-shell.js +275 -78
- package/dist/shell/app-shell.js.map +1 -1
- package/dist/shell/option-switcher-menu.js +3 -2
- package/dist/shell/option-switcher-menu.js.map +1 -1
- package/dist/shell/role-switcher.d.ts +6 -0
- package/dist/shell/role-switcher.js +7 -4
- package/dist/shell/role-switcher.js.map +1 -1
- package/dist/shell/top-bar.d.ts +15 -7
- package/dist/shell/top-bar.js +3 -5
- package/dist/shell/top-bar.js.map +1 -1
- package/dist/shell/topbar-action-menu.js +3 -2
- package/dist/shell/topbar-action-menu.js.map +1 -1
- package/dist/shell/topbar-controls.d.ts +5 -2
- package/dist/shell/topbar-controls.js +20 -15
- package/dist/shell/topbar-controls.js.map +1 -1
- package/dist/shell.d.ts +13 -0
- package/dist/shell.js +8 -0
- package/dist/shell.js.map +1 -0
- package/dist/theme/chart-palette.d.ts +19 -12
- package/dist/theme/chart-palette.js +24 -30
- package/dist/theme/chart-palette.js.map +1 -1
- package/dist/theme/color.d.ts +78 -0
- package/dist/theme/color.js +148 -0
- package/dist/theme/color.js.map +1 -0
- package/dist/theme/palette-derive.d.ts +140 -0
- package/dist/theme/palette-derive.js +376 -0
- package/dist/theme/palette-derive.js.map +1 -0
- package/dist/theme/palette-presets.d.ts +14 -1
- package/dist/theme/palette-presets.js +231 -3
- package/dist/theme/palette-presets.js.map +1 -1
- package/dist/theme/palette-store.js +1 -0
- package/dist/theme/palette-store.js.map +1 -1
- package/dist/theme/theme-store.js +1 -0
- package/dist/theme/theme-store.js.map +1 -1
- package/dist/tour/tour.d.ts +2 -1
- package/dist/tour/tour.js +15 -9
- package/dist/tour/tour.js.map +1 -1
- package/dist/tour.d.ts +2 -0
- package/dist/tour.js +3 -0
- package/dist/tour.js.map +1 -0
- package/dist/wizard/stepper-nav.js +10 -8
- package/dist/wizard/stepper-nav.js.map +1 -1
- package/dist/wizard/types.d.ts +18 -2
- package/dist/wizard/types.js +4 -1
- package/dist/wizard/types.js.map +1 -1
- package/dist/wizard/use-wizard.js +12 -4
- package/dist/wizard/use-wizard.js.map +1 -1
- package/dist/wizard/validation.js +1 -0
- package/dist/wizard/validation.js.map +1 -1
- package/dist/wizard/wizard-context.js +1 -0
- package/dist/wizard/wizard-context.js.map +1 -1
- package/dist/wizard/wizard-step.js +1 -0
- package/dist/wizard/wizard-step.js.map +1 -1
- package/dist/wizard/wizard-summary.js +5 -3
- package/dist/wizard/wizard-summary.js.map +1 -1
- package/dist/wizard.d.ts +8 -0
- package/dist/wizard.js +9 -0
- package/dist/wizard.js.map +1 -0
- package/package.json +66 -13
- package/src/chart.ts +22 -0
- package/src/components/account-settings.tsx +275 -0
- package/src/components/alert-banner.tsx +75 -0
- package/src/components/amount-input.tsx +471 -0
- package/src/components/calculator.tsx +252 -0
- package/src/components/chart-zoom.tsx +499 -0
- package/src/components/chart.tsx +363 -0
- package/src/components/checkbox.tsx +222 -0
- package/src/components/chip.tsx +584 -0
- package/src/components/choice-parts.ts +33 -0
- package/src/components/combobox-core.tsx +540 -0
- package/src/components/combobox.tsx +1026 -0
- package/src/components/currency-select.tsx +283 -0
- package/src/components/data-table-filter-popover.tsx +252 -0
- package/src/components/data-table-filters.ts +176 -0
- package/src/components/data-table-labels.ts +190 -0
- package/src/components/data-table-pagination.tsx +126 -0
- package/src/components/data-table-sort.ts +70 -0
- package/src/components/data-table.tsx +1740 -0
- package/src/components/date-picker.tsx +656 -0
- package/src/components/dropdown.tsx +341 -0
- package/src/components/entity-combobox.tsx +215 -0
- package/src/components/facing-pair.ts +86 -0
- package/src/components/field-sync.tsx +472 -0
- package/src/components/file-dropzone.tsx +181 -0
- package/src/components/full-bleed-dialog.tsx +179 -0
- package/src/components/grouped-picker.tsx +157 -0
- package/src/components/hover-menu.tsx +183 -0
- package/src/components/mini-calendar.tsx +554 -0
- package/src/components/modal.tsx +287 -0
- package/src/components/month-picker.tsx +567 -0
- package/src/components/multi-entity-combobox.tsx +226 -0
- package/src/components/multi-select.tsx +303 -0
- package/src/components/number-field.tsx +225 -0
- package/src/components/number-input.tsx +211 -0
- package/src/components/numpad-sheet.tsx +264 -0
- package/src/components/page-contents.tsx +289 -0
- package/src/components/password-strength.tsx +258 -0
- package/src/components/picker-sheet.tsx +251 -0
- package/src/components/popover.tsx +198 -0
- package/src/components/search-field.tsx +146 -0
- package/src/components/series-chart-labels.ts +26 -0
- package/src/components/series-chart.tsx +481 -0
- package/src/components/settings-fields.tsx +68 -0
- package/src/components/signature-pad.tsx +630 -0
- package/src/components/slider.tsx +313 -0
- package/src/components/sparkline.tsx +329 -0
- package/src/components/stat-tile.tsx +448 -0
- package/src/components/swipeable-row.tsx +271 -0
- package/src/components/switch.tsx +170 -0
- package/src/components/time-input.tsx +107 -0
- package/src/components/toggle-group.tsx +153 -0
- package/src/components/toggle-legend.tsx +229 -0
- package/src/components/tooltip.tsx +477 -0
- package/src/components/treemap.tsx +390 -0
- package/src/components/trigger-aria.ts +42 -0
- package/src/components/ui.tsx +1295 -0
- package/src/components/use-mobile-reveal.ts +54 -0
- package/src/components/use-table-state.ts +295 -0
- package/src/components/user-avatar.tsx +61 -0
- package/src/components/wizard-stepper.tsx +37 -0
- package/src/data-table.ts +19 -0
- package/src/feedback/feedback-attachment.tsx +246 -0
- package/src/feedback/feedback-dialog.tsx +209 -0
- package/src/feedback/feedback-inbox.tsx +615 -0
- package/src/feedback.ts +8 -0
- package/src/hooks/use-anchored-panel.ts +169 -0
- package/src/hooks/use-anchored-rect.ts +78 -0
- package/src/hooks/use-announce.ts +85 -0
- package/src/hooks/use-body-scroll-lock.ts +94 -0
- package/src/hooks/use-close-transition.ts +99 -0
- package/src/hooks/use-dismiss.ts +77 -0
- package/src/hooks/use-focus-trap.ts +160 -0
- package/src/hooks/use-media-query.ts +23 -0
- package/src/hooks/use-overlay-history.ts +345 -0
- package/src/hooks/use-row-swipe.ts +212 -0
- package/src/i18n/defaults.ts +68 -0
- package/src/i18n/kit-labels.tsx +447 -0
- package/src/index.ts +169 -0
- package/src/lib/calc.ts +309 -0
- package/src/lib/cn.ts +5 -0
- package/src/lib/dates.ts +187 -0
- package/src/lib/logger.ts +73 -0
- package/src/lib/safe-storage.ts +37 -0
- package/src/search/command-palette.tsx +342 -0
- package/src/search.ts +3 -0
- package/src/shell/app-shell.tsx +772 -0
- package/src/shell/option-switcher-menu.tsx +72 -0
- package/src/shell/role-switcher.tsx +46 -0
- package/src/shell/top-bar.tsx +39 -0
- package/src/shell/topbar-action-menu.tsx +91 -0
- package/src/shell/topbar-controls.tsx +229 -0
- package/src/shell.ts +10 -0
- package/src/theme/chart-palette.ts +145 -0
- package/src/theme/color.ts +266 -0
- package/src/theme/palette-derive.ts +681 -0
- package/src/theme/palette-presets.ts +760 -0
- package/src/theme/palette-store.ts +94 -0
- package/src/theme/theme-store.ts +145 -0
- package/src/tour/tour.tsx +586 -0
- package/src/tour.ts +3 -0
- package/src/vite-env.d.ts +26 -0
- package/src/wizard/stepper-nav.tsx +221 -0
- package/src/wizard/types.ts +178 -0
- package/src/wizard/use-wizard.ts +345 -0
- package/src/wizard/validation.ts +37 -0
- package/src/wizard/wizard-context.tsx +29 -0
- package/src/wizard/wizard-step.tsx +14 -0
- package/src/wizard/wizard-summary.tsx +69 -0
- package/src/wizard.ts +14 -0
- package/tokens.css +222 -20
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useContext, useMemo } from "react";
|
|
4
|
+
const DEFAULT_COMMON_LABELS = {
|
|
5
|
+
close: "Close",
|
|
6
|
+
clear: "Clear",
|
|
7
|
+
search: "Search",
|
|
8
|
+
done: "Done",
|
|
9
|
+
cancel: "Cancel",
|
|
10
|
+
save: "Save",
|
|
11
|
+
back: "Back",
|
|
12
|
+
next: "Next",
|
|
13
|
+
remove: "Remove",
|
|
14
|
+
loading: "Loading\u2026",
|
|
15
|
+
noResults: "No results",
|
|
16
|
+
fieldValue: (field, value) => `${field}: ${value}`
|
|
17
|
+
};
|
|
18
|
+
const DEFAULT_DATE_PICKER_LABELS = {
|
|
19
|
+
panel: "Choose a date",
|
|
20
|
+
rangePanel: "Choose a date range",
|
|
21
|
+
clear: "Clear",
|
|
22
|
+
previousDay: "Previous day",
|
|
23
|
+
nextDay: "Next day",
|
|
24
|
+
today: "Today"
|
|
25
|
+
};
|
|
26
|
+
const DEFAULT_COMBOBOX_LABELS = {
|
|
27
|
+
search: "Search",
|
|
28
|
+
noResults: "No results",
|
|
29
|
+
clear: "Clear",
|
|
30
|
+
loading: "Loading\u2026",
|
|
31
|
+
create: (query) => `Create \u201C${query}\u201D`,
|
|
32
|
+
selectedCount: (count) => `${count} selected`
|
|
33
|
+
};
|
|
34
|
+
const DEFAULT_MULTI_SELECT_LABELS = {
|
|
35
|
+
search: "Search",
|
|
36
|
+
selectAll: "Select all",
|
|
37
|
+
clear: "Clear",
|
|
38
|
+
all: "All",
|
|
39
|
+
selectedCount: (count) => String(count)
|
|
40
|
+
};
|
|
41
|
+
const DEFAULT_CALCULATOR_LABELS = {
|
|
42
|
+
open: "Open calculator",
|
|
43
|
+
panel: "Calculator",
|
|
44
|
+
calculation: "Calculation",
|
|
45
|
+
backspace: "Backspace",
|
|
46
|
+
clear: "Clear",
|
|
47
|
+
equals: "Equals",
|
|
48
|
+
done: "Done",
|
|
49
|
+
plus: "Plus",
|
|
50
|
+
minus: "Minus",
|
|
51
|
+
times: "Times",
|
|
52
|
+
divide: "Divide",
|
|
53
|
+
decimal: "Decimal point"
|
|
54
|
+
};
|
|
55
|
+
const DEFAULT_CURRENCY_LABELS = {
|
|
56
|
+
currency: "Currency",
|
|
57
|
+
search: "Search currency"
|
|
58
|
+
};
|
|
59
|
+
const DEFAULT_APP_SHELL_LABELS = {
|
|
60
|
+
collapse: "Collapse sidebar",
|
|
61
|
+
expand: "Expand sidebar",
|
|
62
|
+
toggleGroup: (groupLabel) => `${groupLabel}: pages`
|
|
63
|
+
};
|
|
64
|
+
const DEFAULT_TOP_BAR_LABELS = {
|
|
65
|
+
theme: "Toggle theme",
|
|
66
|
+
palette: "Appearance preset",
|
|
67
|
+
language: "Language",
|
|
68
|
+
switchRole: "Switch role",
|
|
69
|
+
role: (value) => `Role: ${value}`
|
|
70
|
+
};
|
|
71
|
+
const DEFAULT_PICKER_SHEET_LABELS = { close: "Close" };
|
|
72
|
+
const DEFAULT_SWIPEABLE_ROW_LABELS = { actions: "Row actions" };
|
|
73
|
+
const DEFAULT_FILE_LABELS = {
|
|
74
|
+
size: (bytes) => formatFileSize(bytes)
|
|
75
|
+
};
|
|
76
|
+
function formatFileSize(bytes, locale) {
|
|
77
|
+
const units = ["byte", "kilobyte", "megabyte", "gigabyte"];
|
|
78
|
+
let value = bytes;
|
|
79
|
+
let i = 0;
|
|
80
|
+
while (value >= 1e3 && i < units.length - 1) {
|
|
81
|
+
value /= 1e3;
|
|
82
|
+
i += 1;
|
|
83
|
+
}
|
|
84
|
+
return new Intl.NumberFormat(locale, {
|
|
85
|
+
style: "unit",
|
|
86
|
+
unit: units[i],
|
|
87
|
+
unitDisplay: i === 0 ? "long" : "short",
|
|
88
|
+
maximumFractionDigits: value < 10 && i > 0 ? 1 : 0
|
|
89
|
+
}).format(value);
|
|
90
|
+
}
|
|
91
|
+
const KitI18nContext = createContext({});
|
|
92
|
+
function UiKitProvider({ labels, locale, children }) {
|
|
93
|
+
const outer = useContext(KitI18nContext);
|
|
94
|
+
const value = useMemo(
|
|
95
|
+
() => ({
|
|
96
|
+
locale: locale ?? outer.locale,
|
|
97
|
+
labels: mergeOverrides(outer.labels, labels)
|
|
98
|
+
}),
|
|
99
|
+
[outer, labels, locale]
|
|
100
|
+
);
|
|
101
|
+
return /* @__PURE__ */ jsx(KitI18nContext.Provider, { value, children });
|
|
102
|
+
}
|
|
103
|
+
function isRecord(v) {
|
|
104
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
105
|
+
}
|
|
106
|
+
function mergeNamespace(base, over) {
|
|
107
|
+
if (!over) return base;
|
|
108
|
+
const out = { ...base };
|
|
109
|
+
for (const [k, v] of Object.entries(over)) {
|
|
110
|
+
if (v === void 0) continue;
|
|
111
|
+
const prev = out[k];
|
|
112
|
+
out[k] = isRecord(prev) && isRecord(v) ? { ...prev, ...v } : v;
|
|
113
|
+
}
|
|
114
|
+
return out;
|
|
115
|
+
}
|
|
116
|
+
function mergeOverrides(a, b) {
|
|
117
|
+
if (!a) return b;
|
|
118
|
+
if (!b) return a;
|
|
119
|
+
const out = { ...a };
|
|
120
|
+
for (const [ns, v] of Object.entries(b)) {
|
|
121
|
+
out[ns] = mergeNamespace(out[ns] ?? {}, v);
|
|
122
|
+
}
|
|
123
|
+
return out;
|
|
124
|
+
}
|
|
125
|
+
function useKitLabelOverrides(ns) {
|
|
126
|
+
return useContext(KitI18nContext).labels?.[ns];
|
|
127
|
+
}
|
|
128
|
+
function useKitLabels(ns, defaults, prop) {
|
|
129
|
+
const fromProvider = useKitLabelOverrides(ns);
|
|
130
|
+
return useMemo(
|
|
131
|
+
() => mergeNamespace(mergeNamespace(defaults, fromProvider), prop),
|
|
132
|
+
[defaults, fromProvider, prop]
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
function useKitLocale(prop) {
|
|
136
|
+
const fromProvider = useContext(KitI18nContext).locale;
|
|
137
|
+
return prop ?? fromProvider;
|
|
138
|
+
}
|
|
139
|
+
function useKitFileLabels(prop) {
|
|
140
|
+
const locale = useKitLocale();
|
|
141
|
+
const defaults = useMemo(
|
|
142
|
+
() => ({ size: (bytes) => formatFileSize(bytes, locale) }),
|
|
143
|
+
[locale]
|
|
144
|
+
);
|
|
145
|
+
return useKitLabels("file", defaults, prop);
|
|
146
|
+
}
|
|
147
|
+
function missingKitLabels(labels, reference) {
|
|
148
|
+
const missing = [];
|
|
149
|
+
for (const [ns, keys] of Object.entries(reference)) {
|
|
150
|
+
const given = labels?.[ns];
|
|
151
|
+
for (const [key, value] of Object.entries(keys)) {
|
|
152
|
+
const got = given?.[key];
|
|
153
|
+
if (got === void 0) {
|
|
154
|
+
missing.push(`${ns}.${key}`);
|
|
155
|
+
} else if (isRecord(value) && isRecord(got)) {
|
|
156
|
+
for (const sub of Object.keys(value)) {
|
|
157
|
+
if (got[sub] === void 0) missing.push(`${ns}.${key}.${sub}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return missing;
|
|
163
|
+
}
|
|
164
|
+
export {
|
|
165
|
+
DEFAULT_APP_SHELL_LABELS,
|
|
166
|
+
DEFAULT_CALCULATOR_LABELS,
|
|
167
|
+
DEFAULT_COMBOBOX_LABELS,
|
|
168
|
+
DEFAULT_COMMON_LABELS,
|
|
169
|
+
DEFAULT_CURRENCY_LABELS,
|
|
170
|
+
DEFAULT_DATE_PICKER_LABELS,
|
|
171
|
+
DEFAULT_FILE_LABELS,
|
|
172
|
+
DEFAULT_MULTI_SELECT_LABELS,
|
|
173
|
+
DEFAULT_PICKER_SHEET_LABELS,
|
|
174
|
+
DEFAULT_SWIPEABLE_ROW_LABELS,
|
|
175
|
+
DEFAULT_TOP_BAR_LABELS,
|
|
176
|
+
UiKitProvider,
|
|
177
|
+
formatFileSize,
|
|
178
|
+
missingKitLabels,
|
|
179
|
+
useKitFileLabels,
|
|
180
|
+
useKitLabelOverrides,
|
|
181
|
+
useKitLabels,
|
|
182
|
+
useKitLocale
|
|
183
|
+
};
|
|
184
|
+
//# sourceMappingURL=kit-labels.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/i18n/kit-labels.tsx"],"sourcesContent":["import { createContext, useContext, useMemo } from \"react\";\nimport type { ReactNode } from \"react\";\nimport type { DataTableLabels } from \"../components/data-table-labels\";\nimport type { MiniCalendarLabels } from \"../components/mini-calendar\";\nimport type { PopoverLabels } from \"../components/popover\";\nimport type { ChipInputLabels } from \"../components/chip\";\nimport type { FieldSyncLabels } from \"../components/field-sync\";\nimport type { PasswordRevealLabels } from \"../components/ui\";\nimport type { WizardLabels } from \"../wizard/types\";\nimport type { TourLabels } from \"../tour/tour\";\nimport type { CommandPaletteLabels } from \"../search/command-palette\";\nimport type { MonthPickerLabels } from \"../components/month-picker\";\nimport type { PageContentsLabels } from \"../components/page-contents\";\nimport type { SeriesChartLabels } from \"../components/series-chart-labels\";\nimport type { SparklineLabels } from \"../components/sparkline\";\nimport type { StatTileLabels } from \"../components/stat-tile\";\nimport type { SignaturePadLabels } from \"../components/signature-pad\";\nimport type { PasswordStrengthLabels } from \"../components/password-strength\";\n\n/**\n * EVERY string the kit renders, as one typed tree — and an optional provider that\n * hands it to every component at once.\n *\n * WHY THIS EXISTS. The kit ships no catalogue and resolves no strings, and that stays\n * true: the app supplies every word. What was wrong was HOW it had to supply them —\n * one `labels` prop per component instance, under a different prop name per\n * component (`labels`, `calendarLabels`, `passwordLabels`, `clearLabel`,\n * `searchPlaceholder`, `ariaLabel` …). A translated app therefore rendered English\n * wherever one call site forgot one prop, and nothing told it so: a German showcase\n * still said \"Rows per page\", \"Collapse sidebar\" and \"Popover\" in seven languages.\n *\n * Now there is one key per string, addressed by a dot path (`dataTable.pageSize`,\n * `datePicker.today`), and three sources in a fixed order of precedence:\n *\n * the component's own prop > <UiKitProvider labels> > English default\n *\n * A consumer writes its translation ONCE, as a `UiKitLabels` (or a partial of it),\n * mounts `<UiKitProvider labels={…} locale={…}>` at the root, and every kit component\n * below speaks that language — including the ones nested inside other kit components\n * (the calendar inside the data table's date filter, the popover inside the date\n * picker), which no prop at the outer call site could reach before.\n *\n * Messages that carry a value are FUNCTIONS of that value, never a template to fill:\n * a number glued into an English sentence is untranslatable, because the grammar\n * around it moves with it in most languages.\n */\n\n/* ── Namespaces that had no labels type of their own ─────────────────────── */\n\n/** The words several components share. A component's own namespace wins over these\n * where both exist; these are what a new component reaches for first. */\nexport interface CommonLabels {\n close: string;\n clear: string;\n search: string;\n done: string;\n cancel: string;\n save: string;\n back: string;\n next: string;\n remove: string;\n loading: string;\n noResults: string;\n /** \"Name: value\" — how a field's accessible name is composed with its value.\n * A colon-and-space is not universal punctuation (French puts a space before\n * the colon, Chinese uses a full-width one). */\n fieldValue: (field: string, value: string) => string;\n}\n\n/** `DatePicker` / `DateRangePicker` chrome. The calendar inside has its own\n * namespace, `miniCalendar`. */\nexport interface DatePickerLabels {\n /** Accessible name of the popover panel the calendar opens in. */\n panel: string;\n /** The same, for `DateRangePicker`'s panel. */\n rangePanel: string;\n clear: string;\n previousDay: string;\n nextDay: string;\n today: string;\n}\n\n/** The whole combobox family: `Combobox`, `EntityCombobox`,\n * `MultiEntityCombobox`, `InlineEntityCombobox`. */\nexport interface ComboboxLabels {\n search: string;\n noResults: string;\n clear: string;\n loading: string;\n /** The \"add this\" row when free entry is allowed. */\n create: (query: string) => string;\n /** Trigger summary once more than one value is picked. */\n selectedCount: (count: number) => string;\n}\n\nexport interface MultiSelectLabels {\n search: string;\n selectAll: string;\n clear: string;\n /** Trigger text when nothing is picked, which a multi-select reads as \"all\". */\n all: string;\n /** Trigger summary once some (but not all) values are picked. The English\n * default is the bare count, which is what the trigger has always shown. */\n selectedCount: (count: number) => string;\n}\n\n/** `CalculatorButton` (desktop popover keypad) and `NumberPadSheet` (phone sheet). */\nexport interface CalculatorLabels {\n /** The button that opens the calculator. */\n open: string;\n /** The popover / sheet itself. */\n panel: string;\n calculation: string;\n backspace: string;\n clear: string;\n equals: string;\n /** The primary key of the phone pad — visible text, not an aria-label. */\n done: string;\n /** Names of the operator keys and the decimal key. Their glyphs are not names a\n * screen reader agrees on — \"÷\" is read as \"division sign\", \"divided by\" or\n * nothing at all depending on the reader — so each says what it does. */\n plus: string;\n minus: string;\n times: string;\n divide: string;\n decimal: string;\n}\n\n/** `CurrencySelect` and the currency half of `AmountInput`. */\nexport interface CurrencyLabels {\n currency: string;\n search: string;\n}\n\nexport interface AppShellLabels {\n collapse: string;\n expand: string;\n /** Accessible name of an inline group's disclosure button (`subNav=\"inline\"`). */\n toggleGroup: (groupLabel: string) => string;\n}\n\nexport interface TopBarLabels {\n theme: string;\n palette: string;\n language: string;\n switchRole: string;\n /** The role switcher's tooltip, given the active role's name. */\n role: (value: string) => string;\n}\n\nexport interface PickerSheetLabels {\n close: string;\n}\n\nexport interface SwipeableRowLabels {\n actions: string;\n}\n\nexport interface FileLabels {\n /** A file size for display, given its size in BYTES. The default uses\n * `Intl.NumberFormat`'s unit formatting in the provider's locale. */\n size: (bytes: number) => string;\n}\n\n/** The complete tree. `UiKitProvider` takes any partial of it. */\nexport interface UiKitLabels {\n common: CommonLabels;\n dataTable: DataTableLabels;\n miniCalendar: MiniCalendarLabels;\n datePicker: DatePickerLabels;\n monthPicker: MonthPickerLabels;\n popover: PopoverLabels;\n combobox: ComboboxLabels;\n multiSelect: MultiSelectLabels;\n calculator: CalculatorLabels;\n currency: CurrencyLabels;\n chipInput: ChipInputLabels;\n fieldSync: FieldSyncLabels;\n passwordReveal: PasswordRevealLabels;\n appShell: AppShellLabels;\n pageContents: PageContentsLabels;\n topBar: TopBarLabels;\n pickerSheet: PickerSheetLabels;\n swipeableRow: SwipeableRowLabels;\n file: FileLabels;\n wizard: WizardLabels;\n tour: TourLabels;\n commandPalette: CommandPaletteLabels;\n seriesChart: SeriesChartLabels;\n sparkline: SparklineLabels;\n statTile: StatTileLabels;\n signaturePad: SignaturePadLabels;\n passwordStrength: PasswordStrengthLabels;\n}\n\n/** Any subset of the tree, one level deep — each namespace may be partial, and a\n * namespace that holds a record (`dataTable.presets`) is merged key by key. */\nexport type UiKitLabelOverrides = { [K in keyof UiKitLabels]?: Partial<UiKitLabels[K]> };\n\n/* ── English defaults for the namespaces defined here ────────────────────── */\n\nexport const DEFAULT_COMMON_LABELS: CommonLabels = {\n close: \"Close\",\n clear: \"Clear\",\n search: \"Search\",\n done: \"Done\",\n cancel: \"Cancel\",\n save: \"Save\",\n back: \"Back\",\n next: \"Next\",\n remove: \"Remove\",\n loading: \"Loading…\",\n noResults: \"No results\",\n fieldValue: (field, value) => `${field}: ${value}`,\n};\n\nexport const DEFAULT_DATE_PICKER_LABELS: DatePickerLabels = {\n panel: \"Choose a date\",\n rangePanel: \"Choose a date range\",\n clear: \"Clear\",\n previousDay: \"Previous day\",\n nextDay: \"Next day\",\n today: \"Today\",\n};\n\nexport const DEFAULT_COMBOBOX_LABELS: ComboboxLabels = {\n search: \"Search\",\n noResults: \"No results\",\n clear: \"Clear\",\n loading: \"Loading…\",\n create: (query) => `Create “${query}”`,\n selectedCount: (count) => `${count} selected`,\n};\n\nexport const DEFAULT_MULTI_SELECT_LABELS: MultiSelectLabels = {\n search: \"Search\",\n selectAll: \"Select all\",\n clear: \"Clear\",\n all: \"All\",\n selectedCount: (count) => String(count),\n};\n\nexport const DEFAULT_CALCULATOR_LABELS: CalculatorLabels = {\n open: \"Open calculator\",\n panel: \"Calculator\",\n calculation: \"Calculation\",\n backspace: \"Backspace\",\n clear: \"Clear\",\n equals: \"Equals\",\n done: \"Done\",\n plus: \"Plus\",\n minus: \"Minus\",\n times: \"Times\",\n divide: \"Divide\",\n decimal: \"Decimal point\",\n};\n\nexport const DEFAULT_CURRENCY_LABELS: CurrencyLabels = {\n currency: \"Currency\",\n search: \"Search currency\",\n};\n\nexport const DEFAULT_APP_SHELL_LABELS: AppShellLabels = {\n collapse: \"Collapse sidebar\",\n expand: \"Expand sidebar\",\n toggleGroup: (groupLabel) => `${groupLabel}: pages`,\n};\n\nexport const DEFAULT_TOP_BAR_LABELS: TopBarLabels = {\n theme: \"Toggle theme\",\n palette: \"Appearance preset\",\n language: \"Language\",\n switchRole: \"Switch role\",\n role: (value) => `Role: ${value}`,\n};\n\nexport const DEFAULT_PICKER_SHEET_LABELS: PickerSheetLabels = { close: \"Close\" };\n\nexport const DEFAULT_SWIPEABLE_ROW_LABELS: SwipeableRowLabels = { actions: \"Row actions\" };\n\n/** Formats with the locale the provider was given (see {@link useKitFileLabels}).\n * This static default has no locale to hand and falls back to the runtime's. */\nexport const DEFAULT_FILE_LABELS: FileLabels = {\n size: (bytes) => formatFileSize(bytes),\n};\n\n/** \"12 kB\", \"3.4 MB\" — `Intl`'s unit formatting, so the digits, the decimal mark and\n * the unit's spelling all follow `locale`. */\nexport function formatFileSize(bytes: number, locale?: string): string {\n const units = [\"byte\", \"kilobyte\", \"megabyte\", \"gigabyte\"] as const;\n let value = bytes;\n let i = 0;\n while (value >= 1000 && i < units.length - 1) {\n value /= 1000;\n i += 1;\n }\n return new Intl.NumberFormat(locale, {\n style: \"unit\",\n unit: units[i],\n unitDisplay: i === 0 ? \"long\" : \"short\",\n maximumFractionDigits: value < 10 && i > 0 ? 1 : 0,\n }).format(value);\n}\n\n/* ── The provider ────────────────────────────────────────────────────────── */\n\ninterface KitI18n {\n labels?: UiKitLabelOverrides;\n locale?: string;\n}\n\nconst KitI18nContext = createContext<KitI18n>({});\n\nexport interface UiKitProviderProps {\n /** Any part of {@link UiKitLabels}. Missing keys fall back to English. */\n labels?: UiKitLabelOverrides;\n /**\n * BCP 47 tag used by every kit component that formats something — dates, numbers,\n * month and weekday names, file sizes — when it is not handed a `locale` prop of\n * its own. Without a provider, and without a prop, those use the runtime default.\n */\n locale?: string;\n children: ReactNode;\n}\n\n/**\n * Hand every kit component below this point its strings and its locale.\n *\n * Optional: a component outside any provider behaves exactly as it did before the\n * provider existed. Nesting works as a merge — an inner provider overrides only what\n * it names, so a page can re-label one table's `dataTable.table` without restating\n * the language.\n */\nexport function UiKitProvider({ labels, locale, children }: UiKitProviderProps) {\n const outer = useContext(KitI18nContext);\n const value = useMemo<KitI18n>(\n () => ({\n locale: locale ?? outer.locale,\n labels: mergeOverrides(outer.labels, labels),\n }),\n [outer, labels, locale],\n );\n return <KitI18nContext.Provider value={value}>{children}</KitI18nContext.Provider>;\n}\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n\n/** Two levels: namespaces, and inside a namespace a record-valued key (presets). */\nfunction mergeNamespace<T extends object>(base: T, over: Partial<T> | undefined): T {\n if (!over) return base;\n const out = { ...base } as Record<string, unknown>;\n for (const [k, v] of Object.entries(over)) {\n if (v === undefined) continue;\n const prev = out[k];\n out[k] = isRecord(prev) && isRecord(v) ? { ...prev, ...v } : v;\n }\n return out as T;\n}\n\nfunction mergeOverrides(\n a: UiKitLabelOverrides | undefined,\n b: UiKitLabelOverrides | undefined,\n): UiKitLabelOverrides | undefined {\n if (!a) return b;\n if (!b) return a;\n const out: Record<string, unknown> = { ...a };\n for (const [ns, v] of Object.entries(b)) {\n out[ns] = mergeNamespace((out[ns] as object | undefined) ?? {}, v as object);\n }\n return out as UiKitLabelOverrides;\n}\n\n/** What the nearest provider says about one namespace — `undefined` outside one.\n * For a component whose own resolver does more than a merge (the data table\n * derives `columnsCount` from `columns`): feed `{ ...overrides, ...props }` to it. */\nexport function useKitLabelOverrides<K extends keyof UiKitLabels>(\n ns: K,\n): Partial<UiKitLabels[K]> | undefined {\n return useContext(KitI18nContext).labels?.[ns] as Partial<UiKitLabels[K]> | undefined;\n}\n\n/**\n * One namespace, resolved: `defaults`, then the provider, then the component's own\n * `prop`. Record-valued keys are merged key by key at each step.\n */\nexport function useKitLabels<K extends keyof UiKitLabels>(\n ns: K,\n defaults: UiKitLabels[K],\n prop?: Partial<UiKitLabels[K]>,\n): UiKitLabels[K] {\n const fromProvider = useKitLabelOverrides(ns);\n return useMemo(\n () => mergeNamespace(mergeNamespace(defaults, fromProvider), prop),\n [defaults, fromProvider, prop],\n );\n}\n\n/** The component's own `locale` prop, else the provider's, else `undefined` (which\n * every `Intl` API reads as \"the runtime's default\"). */\nexport function useKitLocale(prop?: string): string | undefined {\n const fromProvider = useContext(KitI18nContext).locale;\n return prop ?? fromProvider;\n}\n\n/** {@link DEFAULT_FILE_LABELS}, but formatting in the provider's locale. */\nexport function useKitFileLabels(prop?: Partial<FileLabels>): FileLabels {\n const locale = useKitLocale();\n const defaults = useMemo<FileLabels>(\n () => ({ size: (bytes) => formatFileSize(bytes, locale) }),\n [locale],\n );\n return useKitLabels(\"file\", defaults, prop);\n}\n\n/**\n * The dot paths of every key `labels` does NOT supply — the ones a translated app is\n * still showing in English. Assert on it in the app's own test:\n *\n * expect(missingKitLabels(de)).toEqual([]);\n *\n * `reference` is the complete tree to check against — pass\n * {@link DEFAULT_UI_KIT_LABELS} (src/i18n/defaults.ts). It is a parameter rather than an import\n * because the defaults live beside their components, and this module is imported BY\n * those components.\n */\nexport function missingKitLabels(\n labels: UiKitLabelOverrides | undefined,\n reference: UiKitLabels,\n): string[] {\n const missing: string[] = [];\n for (const [ns, keys] of Object.entries(reference)) {\n const given = (labels as Record<string, Record<string, unknown> | undefined> | undefined)?.[ns];\n for (const [key, value] of Object.entries(keys as Record<string, unknown>)) {\n const got = given?.[key];\n if (got === undefined) {\n missing.push(`${ns}.${key}`);\n } else if (isRecord(value) && isRecord(got)) {\n for (const sub of Object.keys(value)) {\n if (got[sub] === undefined) missing.push(`${ns}.${key}.${sub}`);\n }\n }\n }\n }\n return missing;\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,51 +6,74 @@ export { useBodyScrollLock } from './hooks/use-body-scroll-lock.js';
|
|
|
6
6
|
export { AnchorRect, useAnchoredRect } from './hooks/use-anchored-rect.js';
|
|
7
7
|
export { AnchoredPanel, AnchoredPanelOptions, ViewportBox, anchoredPanelPlacement, useAnchoredPanel, useVisualViewport } from './hooks/use-anchored-panel.js';
|
|
8
8
|
export { useEscapeKey, useOutsideClick } from './hooks/use-dismiss.js';
|
|
9
|
+
export { FocusTrapOptions, useFocusTrap } from './hooks/use-focus-trap.js';
|
|
10
|
+
export { AnnounceRegionProps, UseAnnounceOptions, UseAnnounceReturn, useAnnounce } from './hooks/use-announce.js';
|
|
9
11
|
export { useOverlayHistory } from './hooks/use-overlay-history.js';
|
|
10
12
|
export { OVERLAY_EXIT_MS, useCloseTransition } from './hooks/use-close-transition.js';
|
|
11
13
|
export { RowSwipeOptions, RowSwipeReturn, SwipeStage, useRowSwipe } from './hooks/use-row-swipe.js';
|
|
12
14
|
export { CHART_COLORS, HEATMAP_HEX, HeatStops, PALETTE_HEX, lerpHex, paletteFor, textOn } from './theme/chart-palette.js';
|
|
13
|
-
export {
|
|
15
|
+
export { CvdType, Oklch, Rgb, contrast, deltaE, hexToOklch, luminance, oklchToHex, oklchToRgb, parseHex, rgbToOklch, simulateCvd, solveLightness, toHex } from './theme/color.js';
|
|
16
|
+
export { AnchorRole, ChartRampReport, ContrastCheck, ContrastReport, DeriveOptions, DerivedPalette, PaletteAnchors, SemanticTokens, auditChartRamp, auditPalette, deriveChartRamp, derivePalette, describe } from './theme/palette-derive.js';
|
|
17
|
+
export { ALTERNATIVE_PRESETS, DEFAULT_PRESET, DERIVED_PRESETS, IMPRINT_PRESET, PALETTES, PalettePreset, TokenSet, applyTokenSet, presetById } from './theme/palette-presets.js';
|
|
14
18
|
export { ThemeMode, ThemePreference, ThemeState, ThemeStore, applyPersistedTheme, createThemeStore } from './theme/theme-store.js';
|
|
15
19
|
export { PaletteStore, applyPersistedPalette, createPaletteStore } from './theme/palette-store.js';
|
|
16
|
-
export { Button, ButtonVariant, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, EmptyState, FIELD_BASE, FIELD_DISPLAY, FIELD_FLOATING_PAD, FIELD_INVALID, FIELD_TRIGGER, FIELD_WRITABLE_LOOK, FLOATING_INPUT_CLASS, FLOATING_LABEL_CLASS, FLOATING_LABEL_STATIC, FieldChevron, FieldHint, FieldLabel, FloatingField, IconButton, Input, PHONE_QUERY, Select, Spinner, Tabs, TabsProps, Textarea, buttonClasses } from './components/ui.js';
|
|
20
|
+
export { Button, ButtonProps, ButtonVariant, Card, CardAction, CardActionProps, CardContent, CardContentProps, CardDescription, CardDescriptionProps, CardFooter, CardFooterProps, CardHeader, CardHeaderProps, CardProps, CardTitle, CardTitleProps, DEFAULT_PASSWORD_REVEAL_LABELS, EmptyState, EmptyStateProps, FIELD_BASE, FIELD_DISPLAY, FIELD_FLOATING_PAD, FIELD_INVALID, FIELD_TRIGGER, FIELD_WRITABLE_LOOK, FLOATING_INPUT_CLASS, FLOATING_LABEL_CLASS, FLOATING_LABEL_STATIC, FieldChevron, FieldChevronProps, FieldHint, FieldHintProps, FieldLabel, FieldLabelProps, FloatingField, FloatingFieldProps, IconButton, IconButtonProps, Input, InputProps, PHONE_QUERY, PasswordRevealLabels, Select, SelectProps, Spinner, SpinnerProps, Tabs, TabsProps, Textarea, TextareaProps, buttonClasses, resolvePasswordRevealLabels } from './components/ui.js';
|
|
17
21
|
export { SearchField, SearchFieldProps } from './components/search-field.js';
|
|
18
|
-
export { DropdownPanel, DropdownSearchHeader, useDropdown, useDropdownSearch } from './components/dropdown.js';
|
|
19
|
-
export { Popover } from './components/popover.js';
|
|
22
|
+
export { DropdownPanel, DropdownPanelProps, DropdownSearchHeader, DropdownSearchHeaderProps, useDropdown, useDropdownSearch } from './components/dropdown.js';
|
|
23
|
+
export { DEFAULT_POPOVER_LABELS, Popover, PopoverLabels, PopoverProps } from './components/popover.js';
|
|
20
24
|
export { SwipeAction, SwipeableRow, SwipeableRowProps } from './components/swipeable-row.js';
|
|
21
25
|
export { CalculatorButton, CalculatorButtonLabels } from './components/calculator.js';
|
|
22
26
|
export { NumberPadSheet, NumberPadSheetLabels } from './components/numpad-sheet.js';
|
|
23
27
|
export { NumberInput } from './components/number-input.js';
|
|
24
|
-
export { CURRENCIES, CurrencyFlag, CurrencyOption, CurrencySelect, getCurrency } from './components/currency-select.js';
|
|
28
|
+
export { CURRENCIES, CurrencyFlag, CurrencyFlagProps, CurrencyOption, CurrencySelect, CurrencySelectProps, currencyName, getCurrency } from './components/currency-select.js';
|
|
25
29
|
export { AmountInput } from './components/amount-input.js';
|
|
26
|
-
export { Combobox, InlineEntityCombobox } from './components/combobox.js';
|
|
27
|
-
export { PickerSheet, SHEET_ROW_CLASS } from './components/picker-sheet.js';
|
|
30
|
+
export { Combobox, ComboboxProps, InlineEntityCombobox, InlineEntityComboboxProps } from './components/combobox.js';
|
|
31
|
+
export { PickerSheet, PickerSheetProps, SHEET_ROW_CLASS } from './components/picker-sheet.js';
|
|
28
32
|
export { EntityCombobox, EntityComboboxProps } from './components/entity-combobox.js';
|
|
29
33
|
export { MultiEntityCombobox, MultiEntityComboboxProps } from './components/multi-entity-combobox.js';
|
|
30
|
-
export { MultiSelect, MultiSelectOption } from './components/multi-select.js';
|
|
31
|
-
export { Tooltip, TooltipPlacement, TooltipSize, TooltipViewport, placeTooltip } from './components/tooltip.js';
|
|
34
|
+
export { MultiSelect, MultiSelectOption, MultiSelectProps } from './components/multi-select.js';
|
|
35
|
+
export { Tooltip, TooltipPlacement, TooltipProps, TooltipSize, TooltipViewport, placeTooltip } from './components/tooltip.js';
|
|
32
36
|
export { UserAvatar, UserAvatarProps, avatarInitials } from './components/user-avatar.js';
|
|
33
37
|
export { LanguageSetting, LanguageSettingProps, ThemeSetting, ThemeSettingProps } from './components/settings-fields.js';
|
|
38
|
+
export { DEFAULT_FIELD_SYNC_LABELS, FIELD_SYNC_FRAME, FIELD_SYNC_SAVED_MS, FieldSyncIndicator, FieldSyncIndicatorProps, FieldSyncLabels, FieldSyncRow, FieldSyncRowProps, FieldSyncState, UseFieldSyncOptions, UseFieldSyncReturn, resolveFieldSyncLabels, useFieldSync } from './components/field-sync.js';
|
|
39
|
+
export { DEFAULT_MONTH_PICKER_LABELS, MonthPicker, MonthPickerLabels, MonthPickerProps } from './components/month-picker.js';
|
|
40
|
+
export { Checkbox, CheckboxProps } from './components/checkbox.js';
|
|
41
|
+
export { Switch, SwitchProps, SwitchSize } from './components/switch.js';
|
|
42
|
+
export { Slider, SliderMark, SliderProps, fromLogPosition, toLogPosition } from './components/slider.js';
|
|
43
|
+
export { TimeInput, TimeInputProps, isTimeInRange, normalizeTime } from './components/time-input.js';
|
|
44
|
+
export { NumberField, NumberFieldProps } from './components/number-field.js';
|
|
45
|
+
export { DEFAULT_SPARKLINE_LABELS, Sparkline, SparklineLabels, SparklineProps, SparklineTone, sparklineSummary } from './components/sparkline.js';
|
|
46
|
+
export { DEFAULT_STAT_TILE_LABELS, StatTile, StatTileDelta, StatTileGrid, StatTileGridProps, StatTileLabels, StatTileLinkProps, StatTileProps, StatTileSubValue, StatTileTone } from './components/stat-tile.js';
|
|
47
|
+
export { DEFAULT_SIGNATURE_PAD_LABELS, SignatureDetail, SignaturePad, SignaturePadHandle, SignaturePadLabels, SignaturePadProps } from './components/signature-pad.js';
|
|
48
|
+
export { DEFAULT_PASSWORD_STRENGTH_LABELS, PasswordRule, PasswordRuleId, PasswordScoreOptions, PasswordStrengthLabels, PasswordStrengthMeter, PasswordStrengthMeterProps, PasswordStrengthScore, passwordByteLength, passwordRules, scorePassword } from './components/password-strength.js';
|
|
49
|
+
export { DEFAULT_PAGE_CONTENTS_LABELS, PageContents, PageContentsItem, PageContentsLabels, PageContentsLayout, PageContentsLayoutProps, PageContentsProps, UseScrollSpyOptions, useScrollSpy } from './components/page-contents.js';
|
|
50
|
+
export { Treemap, TreemapCell, TreemapCellProps, TreemapNode, TreemapProps, fitLabel } from './components/treemap.js';
|
|
51
|
+
export { AXIS_TICK_WIDTH, AXIS_TITLE_STRIP, SeriesChart, SeriesChartAxis, SeriesChartProps, SeriesChartSeries, SeriesChartSpan, SeriesChartX, SeriesSource, StaticSeriesChart, axisBandWidth, mergeSeries, oneAxis, padBand, paddedDomain, seriesKey, soleSeriesColor } from './components/series-chart.js';
|
|
52
|
+
export { DEFAULT_Y_AXIS, NO_ZOOM, SharedXZoom, ZOOM_MIN_DRAG, ZOOM_SQUARE_ENOUGH, ZoomAxes, ZoomBinding, ZoomDrag, ZoomFitSource, ZoomSelection, ZoomState, ZoomTarget, fitXToY, fitYToX, selectionFromDrag, withChartZoom, zoomAfter, zoomAxesFor, zoomDomains } from './components/chart-zoom.js';
|
|
53
|
+
export { LegendColumn, LegendEntry, LegendGroup, STEP_DASH, STROKE_PATTERNS, ToggleLegend, ToggleLegendProps, strokeDash, toggleHidden } from './components/toggle-legend.js';
|
|
54
|
+
export { FACING_SIDES, FacingSide, facingAxes, facingBand, facingHeadingPad } from './components/facing-pair.js';
|
|
55
|
+
export { DEFAULT_SERIES_CHART_LABELS, SeriesChartLabels } from './components/series-chart-labels.js';
|
|
34
56
|
export { PasswordSetting, PasswordSettingLabels, ProfileSetting, ProfileSettingLabels, TwoFactorSetting, TwoFactorSettingLabels } from './components/account-settings.js';
|
|
35
|
-
export { AlertBanner, AlertTone, alertFrameClass, toneFrameClass } from './components/alert-banner.js';
|
|
36
|
-
export { ToggleGroup } from './components/toggle-group.js';
|
|
57
|
+
export { AlertBanner, AlertBannerProps, AlertTone, alertFrameClass, toneFrameClass } from './components/alert-banner.js';
|
|
58
|
+
export { ToggleGroup, ToggleGroupProps, ToggleOption } from './components/toggle-group.js';
|
|
59
|
+
export { Chip, ChipInput, ChipInputLabels, ChipInputProps, ChipProps, ChipSize, ChipTone, DEFAULT_CHIP_INPUT_LABELS, resolveChipInputLabels } from './components/chip.js';
|
|
37
60
|
export { WizardStepper } from './components/wizard-stepper.js';
|
|
38
|
-
export { HoverMenu } from './components/hover-menu.js';
|
|
61
|
+
export { HoverMenu, HoverMenuProps } from './components/hover-menu.js';
|
|
39
62
|
export { Modal, ModalProps, useBackdropClose } from './components/modal.js';
|
|
40
|
-
export { FullBleedDialog } from './components/full-bleed-dialog.js';
|
|
41
|
-
export { GroupedPicker, PickerGroup } from './components/grouped-picker.js';
|
|
42
|
-
export { FileDropzone } from './components/file-dropzone.js';
|
|
43
|
-
export { MiniCalendar, MiniCalendarProps } from './components/mini-calendar.js';
|
|
63
|
+
export { FullBleedDialog, FullBleedDialogProps } from './components/full-bleed-dialog.js';
|
|
64
|
+
export { GroupedPicker, GroupedPickerProps, PickerGroup } from './components/grouped-picker.js';
|
|
65
|
+
export { FileDropzone, FileDropzoneProps } from './components/file-dropzone.js';
|
|
66
|
+
export { DEFAULT_MINI_CALENDAR_LABELS, MiniCalendar, MiniCalendarLabels, MiniCalendarProps, WeekDay } from './components/mini-calendar.js';
|
|
44
67
|
export { DatePicker, DatePickerProps, DateRangePicker, DateRangePickerPreset, DateRangePickerProps } from './components/date-picker.js';
|
|
45
68
|
export { ChartConfig, ChartContainer, ChartLegend, ChartLegendContent, ChartSeriesConfig, ChartTooltip, ChartTooltipContent, useChart } from './components/chart.js';
|
|
46
|
-
export { DEFAULT_DATA_TABLE_LABELS, DataTableLabels, resolveDataTableLabels } from './components/data-table-labels.js';
|
|
69
|
+
export { DEFAULT_DATA_TABLE_LABELS, DataTableLabels, missingDataTableLabels, resolveDataTableLabels } from './components/data-table-labels.js';
|
|
47
70
|
export { SortDir, SortState, decodeSorts, encodeSorts, nextSorts, normalizeSorts } from './components/data-table-sort.js';
|
|
48
|
-
export { C as ColumnFilter, D as DataTable, a as DataTableColumn, b as DataTableProps, F as FilterState, c as FilterValue, S as ServerPagination, d as decodeFilterValue, e as decodeFilterValueOfType, f as defaultFilterState, g as encodeFilterValue, i as isFilterActive, r as resolveFilter, h as rowMatches } from './data-table-filters-
|
|
71
|
+
export { C as ColumnFilter, D as DataTable, a as DataTableColumn, b as DataTableProps, F as FilterState, c as FilterValue, S as ServerPagination, d as decodeFilterValue, e as decodeFilterValueOfType, f as defaultFilterState, g as encodeFilterValue, i as isFilterActive, r as resolveFilter, h as rowMatches } from './data-table-filters-DM1auUfH.js';
|
|
49
72
|
export { PAGE_SIZE_OPTIONS, Pagination } from './components/data-table-pagination.js';
|
|
50
73
|
export { FilterPopover } from './components/data-table-filter-popover.js';
|
|
51
74
|
export { LanguageMenu, LanguageOption, PaletteMenu, TOPBAR_MENU_ITEM_CLASS, TOPBAR_TRIGGER_CLASS, ThemeToggle } from './shell/topbar-controls.js';
|
|
52
|
-
export { TopBar } from './shell/top-bar.js';
|
|
53
|
-
export { AppShell, AppShellNavItem, AppShellSubItem } from './shell/app-shell.js';
|
|
75
|
+
export { TopBar, TopBarProps } from './shell/top-bar.js';
|
|
76
|
+
export { AppShell, AppShellNavItem, AppShellProps, AppShellSubItem } from './shell/app-shell.js';
|
|
54
77
|
export { OptionSwitcherMenu, OptionSwitcherOption } from './shell/option-switcher-menu.js';
|
|
55
78
|
export { RoleSwitcher, RoleSwitcherProps } from './shell/role-switcher.js';
|
|
56
79
|
export { TopBarActionMenu, TopBarMenuEntry } from './shell/topbar-action-menu.js';
|
|
@@ -64,8 +87,10 @@ export { RequiredFieldSpec, requiredFieldsValidator } from './wizard/validation.
|
|
|
64
87
|
export { WizardStep } from './wizard/wizard-step.js';
|
|
65
88
|
export { WizardSummary } from './wizard/wizard-summary.js';
|
|
66
89
|
export { StepperNav } from './wizard/stepper-nav.js';
|
|
67
|
-
export { TourLabels, TourPlacement, TourProvider, TourStep, useTour, useTourOptional } from './tour/tour.js';
|
|
68
|
-
export { CommandItem, CommandPalette, CommandPaletteLabels, useCommandKey } from './search/command-palette.js';
|
|
90
|
+
export { DEFAULT_TOUR_LABELS, TourLabels, TourPlacement, TourProvider, TourStep, useTour, useTourOptional } from './tour/tour.js';
|
|
91
|
+
export { CommandItem, CommandPalette, CommandPaletteLabels, DEFAULT_COMMAND_PALETTE_LABELS, useCommandKey } from './search/command-palette.js';
|
|
92
|
+
export { AppShellLabels, CalculatorLabels, ComboboxLabels, CommonLabels, CurrencyLabels, DEFAULT_APP_SHELL_LABELS, DEFAULT_CALCULATOR_LABELS, DEFAULT_COMBOBOX_LABELS, DEFAULT_COMMON_LABELS, DEFAULT_CURRENCY_LABELS, DEFAULT_DATE_PICKER_LABELS, DEFAULT_FILE_LABELS, DEFAULT_MULTI_SELECT_LABELS, DEFAULT_PICKER_SHEET_LABELS, DEFAULT_SWIPEABLE_ROW_LABELS, DEFAULT_TOP_BAR_LABELS, DatePickerLabels, FileLabels, MultiSelectLabels, PickerSheetLabels, SwipeableRowLabels, TopBarLabels, UiKitLabelOverrides, UiKitLabels, UiKitProvider, UiKitProviderProps, formatFileSize, missingKitLabels, useKitFileLabels, useKitLabelOverrides, useKitLabels, useKitLocale } from './i18n/kit-labels.js';
|
|
93
|
+
export { DEFAULT_UI_KIT_LABELS } from './i18n/defaults.js';
|
|
69
94
|
export { ComboOption } from './components/combobox-core.js';
|
|
70
95
|
import 'clsx';
|
|
71
96
|
import 'zustand';
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
export * from "./lib/calc.js";
|
|
2
3
|
import { cn } from "./lib/cn.js";
|
|
3
4
|
import { logger, setStoreLog } from "./lib/logger.js";
|
|
@@ -6,10 +7,14 @@ import { useBodyScrollLock } from "./hooks/use-body-scroll-lock.js";
|
|
|
6
7
|
import { useAnchoredRect } from "./hooks/use-anchored-rect.js";
|
|
7
8
|
import { useAnchoredPanel, anchoredPanelPlacement, useVisualViewport } from "./hooks/use-anchored-panel.js";
|
|
8
9
|
import { useEscapeKey, useOutsideClick } from "./hooks/use-dismiss.js";
|
|
10
|
+
import { useFocusTrap } from "./hooks/use-focus-trap.js";
|
|
11
|
+
import { useAnnounce } from "./hooks/use-announce.js";
|
|
9
12
|
import { useOverlayHistory } from "./hooks/use-overlay-history.js";
|
|
10
13
|
import { useCloseTransition, OVERLAY_EXIT_MS } from "./hooks/use-close-transition.js";
|
|
11
14
|
import { useRowSwipe } from "./hooks/use-row-swipe.js";
|
|
12
15
|
export * from "./theme/chart-palette.js";
|
|
16
|
+
export * from "./theme/color.js";
|
|
17
|
+
export * from "./theme/palette-derive.js";
|
|
13
18
|
export * from "./theme/palette-presets.js";
|
|
14
19
|
export * from "./theme/theme-store.js";
|
|
15
20
|
export * from "./theme/palette-store.js";
|
|
@@ -31,9 +36,28 @@ export * from "./components/multi-select.js";
|
|
|
31
36
|
export * from "./components/tooltip.js";
|
|
32
37
|
export * from "./components/user-avatar.js";
|
|
33
38
|
export * from "./components/settings-fields.js";
|
|
39
|
+
export * from "./components/field-sync.js";
|
|
40
|
+
export * from "./components/month-picker.js";
|
|
41
|
+
export * from "./components/checkbox.js";
|
|
42
|
+
export * from "./components/switch.js";
|
|
43
|
+
export * from "./components/slider.js";
|
|
44
|
+
export * from "./components/time-input.js";
|
|
45
|
+
export * from "./components/number-field.js";
|
|
46
|
+
export * from "./components/sparkline.js";
|
|
47
|
+
export * from "./components/stat-tile.js";
|
|
48
|
+
export * from "./components/signature-pad.js";
|
|
49
|
+
export * from "./components/password-strength.js";
|
|
50
|
+
export * from "./components/page-contents.js";
|
|
51
|
+
export * from "./components/treemap.js";
|
|
52
|
+
export * from "./components/series-chart.js";
|
|
53
|
+
export * from "./components/chart-zoom.js";
|
|
54
|
+
export * from "./components/toggle-legend.js";
|
|
55
|
+
export * from "./components/facing-pair.js";
|
|
56
|
+
export * from "./components/series-chart-labels.js";
|
|
34
57
|
export * from "./components/account-settings.js";
|
|
35
58
|
export * from "./components/alert-banner.js";
|
|
36
59
|
export * from "./components/toggle-group.js";
|
|
60
|
+
export * from "./components/chip.js";
|
|
37
61
|
export * from "./components/wizard-stepper.js";
|
|
38
62
|
export * from "./components/hover-menu.js";
|
|
39
63
|
export * from "./components/modal.js";
|
|
@@ -67,6 +91,8 @@ export * from "./wizard/wizard-summary.js";
|
|
|
67
91
|
export * from "./wizard/stepper-nav.js";
|
|
68
92
|
export * from "./tour/tour.js";
|
|
69
93
|
export * from "./search/command-palette.js";
|
|
94
|
+
export * from "./i18n/kit-labels.js";
|
|
95
|
+
export * from "./i18n/defaults.js";
|
|
70
96
|
export {
|
|
71
97
|
DataTable,
|
|
72
98
|
FilterPopover,
|
|
@@ -78,9 +104,11 @@ export {
|
|
|
78
104
|
setStoreLog,
|
|
79
105
|
useAnchoredPanel,
|
|
80
106
|
useAnchoredRect,
|
|
107
|
+
useAnnounce,
|
|
81
108
|
useBodyScrollLock,
|
|
82
109
|
useCloseTransition,
|
|
83
110
|
useEscapeKey,
|
|
111
|
+
useFocusTrap,
|
|
84
112
|
useMediaQuery,
|
|
85
113
|
useOutsideClick,
|
|
86
114
|
useOverlayHistory,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// @eifi1/ui-kit — shared design-system barrel.\n//\n// Domain-free UI + theme surface shared across apps (lead app: Keksdose). Consumers import\n// components/theme from \"@eifi1/ui-kit\" and the token stylesheet from \"@eifi1/ui-kit/tokens.css\".\n\n// ── lib ────────────────────────────────────────────────────────────────────\nexport * from \"./lib/calc\";\nexport { cn } from \"./lib/cn\";\nexport { logger, setStoreLog } from \"./lib/logger\";\n// Date helpers are also available via the \"@eifi1/ui-kit/dates\" subpath.\n\n// ── hooks ────────────────────────────────────────────────────────────────────\nexport { useMediaQuery } from \"./hooks/use-media-query\";\nexport { useBodyScrollLock } from \"./hooks/use-body-scroll-lock\";\nexport { useAnchoredRect } from \"./hooks/use-anchored-rect\";\nexport type { AnchorRect } from \"./hooks/use-anchored-rect\";\nexport { useAnchoredPanel, anchoredPanelPlacement, useVisualViewport } from \"./hooks/use-anchored-panel\";\nexport type {\n AnchoredPanel,\n AnchoredPanelOptions,\n ViewportBox,\n} from \"./hooks/use-anchored-panel\";\nexport { useEscapeKey, useOutsideClick } from \"./hooks/use-dismiss\";\nexport { useOverlayHistory } from \"./hooks/use-overlay-history\";\nexport { useCloseTransition, OVERLAY_EXIT_MS } from \"./hooks/use-close-transition\";\nexport { useRowSwipe } from \"./hooks/use-row-swipe\";\nexport type { SwipeStage, RowSwipeOptions, RowSwipeReturn } from \"./hooks/use-row-swipe\";\n\n// ── theme / palettes ─────────────────────────────────────────────────────────\nexport * from \"./theme/chart-palette\";\nexport * from \"./theme/palette-presets\";\nexport * from \"./theme/theme-store\";\nexport * from \"./theme/palette-store\";\n\n// ── components ───────────────────────────────────────────────────────────────\nexport * from \"./components/ui\";\nexport * from \"./components/search-field\";\nexport * from \"./components/dropdown\";\nexport * from \"./components/popover\";\nexport { SwipeableRow } from \"./components/swipeable-row\";\nexport type { SwipeAction, SwipeableRowProps } from \"./components/swipeable-row\";\nexport * from \"./components/calculator\";\nexport * from \"./components/numpad-sheet\";\nexport * from \"./components/number-input\";\nexport * from \"./components/currency-select\";\nexport * from \"./components/amount-input\";\nexport * from \"./components/combobox\";\nexport * from \"./components/picker-sheet\";\nexport * from \"./components/entity-combobox\";\nexport * from \"./components/multi-entity-combobox\";\nexport * from \"./components/multi-select\";\nexport * from \"./components/tooltip\";\nexport * from \"./components/user-avatar\";\nexport * from \"./components/settings-fields\";\nexport * from \"./components/account-settings\";\nexport * from \"./components/alert-banner\";\nexport * from \"./components/toggle-group\";\nexport * from \"./components/wizard-stepper\";\nexport * from \"./components/hover-menu\";\nexport * from \"./components/modal\";\nexport * from \"./components/full-bleed-dialog\";\nexport * from \"./components/grouped-picker\";\nexport * from \"./components/file-dropzone\";\nexport * from \"./components/mini-calendar\";\nexport * from \"./components/date-picker\";\nexport * from \"./components/chart\";\n\n// ── data-table suite ─────────────────────────────────────────────────────────\nexport * from \"./components/data-table-labels\";\nexport * from \"./components/data-table-sort\";\nexport * from \"./components/data-table-filters\";\nexport * from \"./components/data-table-pagination\";\nexport { FilterPopover } from \"./components/data-table-filter-popover\";\n// data-table re-exports SortState internally; export the rest explicitly to\n// avoid a duplicate SortState star-export (it comes from data-table-sort).\nexport { DataTable } from \"./components/data-table\";\nexport type { DataTableColumn, DataTableProps, ServerPagination, FilterState } from \"./components/data-table\";\n\n// ── shell (composable app chrome) ────────────────────────────────────────────\nexport * from \"./shell/topbar-controls\";\nexport * from \"./shell/top-bar\";\nexport * from \"./shell/app-shell\";\nexport * from \"./shell/option-switcher-menu\";\nexport * from \"./shell/role-switcher\";\nexport * from \"./shell/topbar-action-menu\";\n\n// ── feedback ─────────────────────────────────────────────────────────────────\n// The form somebody files a report with, and the parts an inbox is built from:\n// the status vocabulary both apps share value for value, the policy about what a\n// row may move to from where it stands, and the look of a status control, a\n// category badge and an opened report. The app still wires its own API, columns\n// and strings — see the note at the top of `feedback-inbox.tsx` for what is\n// deliberately left to it.\nexport * from \"./feedback/feedback-attachment\";\nexport * from \"./feedback/feedback-dialog\";\nexport * from \"./feedback/feedback-inbox\";\n\n// ── multi-step wizard ────────────────────────────────────────────────────────\n// The engine (step machine, validators, collected data), the chrome around it\n// (indicator + nav bar + cancel confirm) and the review step it ends on.\n// `components/wizard-stepper` next door is a different, much smaller thing: a bare\n// step indicator for a two-step import flow, with no engine.\n//\n// Two modules were removed here rather than kept as stock. `wizard-field` held a\n// `WizardField`/`WizardSelectField` pair that had never been rendered in any app —\n// a field group nothing was built from, which this comment used to advertise. And\n// `use-rhf-wizard-step` was the only thing in the package that touched\n// react-hook-form, for a hook neither consumer called: keeping it meant an optional\n// peer, a dev dependency and a type import in every consumer's typecheck, bought\n// for nobody. A design system may carry stock; untested stock nothing has ever\n// rendered is not stock, it is a liability with an export.\nexport * from \"./wizard/types\";\nexport * from \"./wizard/use-wizard\";\nexport * from \"./wizard/wizard-context\";\nexport * from \"./wizard/validation\";\nexport * from \"./wizard/wizard-step\";\nexport * from \"./wizard/wizard-summary\";\nexport * from \"./wizard/stepper-nav\";\n\n// ── guided tours ─────────────────────────────────────────────────────────────\nexport * from \"./tour/tour\";\n\n// ── command palette / global search ──────────────────────────────────────────\nexport * from \"./search/command-palette\";\n"],"mappings":"AAMA,cAAc;AACd,SAAS,UAAU;AACnB,SAAS,QAAQ,mBAAmB;AAIpC,SAAS,qBAAqB;AAC9B,SAAS,yBAAyB;AAClC,SAAS,uBAAuB;AAEhC,SAAS,kBAAkB,wBAAwB,yBAAyB;AAM5E,SAAS,cAAc,uBAAuB;AAC9C,SAAS,yBAAyB;AAClC,SAAS,oBAAoB,uBAAuB;AACpD,SAAS,mBAAmB;AAI5B,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,SAAS,oBAAoB;AAE7B,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,SAAS,qBAAqB;AAG9B,SAAS,iBAAiB;AAI1B,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AASd,cAAc;AACd,cAAc;AACd,cAAc;AAgBd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AAGd,cAAc;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// @eifi1/ui-kit — shared design-system barrel.\n//\n// Domain-free UI + theme surface shared across apps (lead app: Keksdose). Consumers import\n// components/theme from \"@eifi1/ui-kit\" and the token stylesheet from \"@eifi1/ui-kit/tokens.css\".\n\n// ── lib ────────────────────────────────────────────────────────────────────\nexport * from \"./lib/calc\";\nexport { cn } from \"./lib/cn\";\nexport { logger, setStoreLog } from \"./lib/logger\";\n// Date helpers are also available via the \"@eifi1/ui-kit/dates\" subpath.\n\n// ── hooks ────────────────────────────────────────────────────────────────────\nexport { useMediaQuery } from \"./hooks/use-media-query\";\nexport { useBodyScrollLock } from \"./hooks/use-body-scroll-lock\";\nexport { useAnchoredRect } from \"./hooks/use-anchored-rect\";\nexport type { AnchorRect } from \"./hooks/use-anchored-rect\";\nexport { useAnchoredPanel, anchoredPanelPlacement, useVisualViewport } from \"./hooks/use-anchored-panel\";\nexport type {\n AnchoredPanel,\n AnchoredPanelOptions,\n ViewportBox,\n} from \"./hooks/use-anchored-panel\";\nexport { useEscapeKey, useOutsideClick } from \"./hooks/use-dismiss\";\n// Focus containment for an overlay, and a live region for a change that moves no focus.\n// Both were extracted from the two components that already did them correctly (Modal and\n// CommandPalette) so the rest of the kit stops being the exception.\nexport { useFocusTrap } from \"./hooks/use-focus-trap\";\nexport type { FocusTrapOptions } from \"./hooks/use-focus-trap\";\nexport { useAnnounce } from \"./hooks/use-announce\";\nexport type { UseAnnounceReturn, UseAnnounceOptions, AnnounceRegionProps } from \"./hooks/use-announce\";\nexport { useOverlayHistory } from \"./hooks/use-overlay-history\";\nexport { useCloseTransition, OVERLAY_EXIT_MS } from \"./hooks/use-close-transition\";\nexport { useRowSwipe } from \"./hooks/use-row-swipe\";\nexport type { SwipeStage, RowSwipeOptions, RowSwipeReturn } from \"./hooks/use-row-swipe\";\n\n// ── theme / palettes ─────────────────────────────────────────────────────────\nexport * from \"./theme/chart-palette\";\n// Colour maths (sRGB ↔ OKLCH, WCAG contrast, CVD simulation) and the palette deriver\n// that builds a whole, contrast-solved palette from one brand colour plus any colours\n// pinned by hand. `auditPalette` / `auditChartRamp` measure a palette rather than\n// trusting a comment about it.\nexport * from \"./theme/color\";\nexport * from \"./theme/palette-derive\";\nexport * from \"./theme/palette-presets\";\nexport * from \"./theme/theme-store\";\nexport * from \"./theme/palette-store\";\n\n// ── components ───────────────────────────────────────────────────────────────\nexport * from \"./components/ui\";\nexport * from \"./components/search-field\";\nexport * from \"./components/dropdown\";\nexport * from \"./components/popover\";\nexport { SwipeableRow } from \"./components/swipeable-row\";\nexport type { SwipeAction, SwipeableRowProps } from \"./components/swipeable-row\";\nexport * from \"./components/calculator\";\nexport * from \"./components/numpad-sheet\";\nexport * from \"./components/number-input\";\nexport * from \"./components/currency-select\";\nexport * from \"./components/amount-input\";\nexport * from \"./components/combobox\";\nexport * from \"./components/picker-sheet\";\nexport * from \"./components/entity-combobox\";\nexport * from \"./components/multi-entity-combobox\";\nexport * from \"./components/multi-select\";\nexport * from \"./components/tooltip\";\nexport * from \"./components/user-avatar\";\nexport * from \"./components/settings-fields\";\n// Sync state for a database-backed field: the engine (`useFieldSync`) and the\n// affordance (`FieldSyncIndicator`), kept separate because the state is useful\n// without the dot — a form can gate its submit on any field being `pending`.\nexport * from \"./components/field-sync\";\nexport * from \"./components/month-picker\";\nexport * from \"./components/checkbox\";\nexport * from \"./components/switch\";\nexport * from \"./components/slider\";\nexport * from \"./components/time-input\";\nexport * from \"./components/number-field\";\nexport * from \"./components/sparkline\";\nexport * from \"./components/stat-tile\";\nexport * from \"./components/signature-pad\";\nexport * from \"./components/password-strength\";\nexport * from \"./components/page-contents\";\nexport * from \"./components/treemap\";\nexport * from \"./components/series-chart\";\nexport * from \"./components/chart-zoom\";\nexport * from \"./components/toggle-legend\";\nexport * from \"./components/facing-pair\";\nexport * from \"./components/series-chart-labels\";\nexport * from \"./components/account-settings\";\nexport * from \"./components/alert-banner\";\nexport * from \"./components/toggle-group\";\n// A pill carrying one VALUE — inert, a link, or a toggle, depending on which prop it is\n// given — and the list field built from it. Distinct from Button on purpose: a row of\n// buttons reads as \"choose an action\", a row of chips as \"here are the things\".\nexport * from \"./components/chip\";\nexport * from \"./components/wizard-stepper\";\nexport * from \"./components/hover-menu\";\nexport * from \"./components/modal\";\nexport * from \"./components/full-bleed-dialog\";\nexport * from \"./components/grouped-picker\";\nexport * from \"./components/file-dropzone\";\nexport * from \"./components/mini-calendar\";\nexport * from \"./components/date-picker\";\nexport * from \"./components/chart\";\n\n// ── data-table suite ─────────────────────────────────────────────────────────\nexport * from \"./components/data-table-labels\";\nexport * from \"./components/data-table-sort\";\nexport * from \"./components/data-table-filters\";\nexport * from \"./components/data-table-pagination\";\nexport { FilterPopover } from \"./components/data-table-filter-popover\";\n// data-table re-exports SortState internally; export the rest explicitly to\n// avoid a duplicate SortState star-export (it comes from data-table-sort).\nexport { DataTable } from \"./components/data-table\";\nexport type { DataTableColumn, DataTableProps, ServerPagination, FilterState } from \"./components/data-table\";\n\n// ── shell (composable app chrome) ────────────────────────────────────────────\nexport * from \"./shell/topbar-controls\";\nexport * from \"./shell/top-bar\";\nexport * from \"./shell/app-shell\";\nexport * from \"./shell/option-switcher-menu\";\nexport * from \"./shell/role-switcher\";\nexport * from \"./shell/topbar-action-menu\";\n\n// ── feedback ─────────────────────────────────────────────────────────────────\n// The form somebody files a report with, and the parts an inbox is built from:\n// the status vocabulary both apps share value for value, the policy about what a\n// row may move to from where it stands, and the look of a status control, a\n// category badge and an opened report. The app still wires its own API, columns\n// and strings — see the note at the top of `feedback-inbox.tsx` for what is\n// deliberately left to it.\nexport * from \"./feedback/feedback-attachment\";\nexport * from \"./feedback/feedback-dialog\";\nexport * from \"./feedback/feedback-inbox\";\n\n// ── multi-step wizard ────────────────────────────────────────────────────────\n// The engine (step machine, validators, collected data), the chrome around it\n// (indicator + nav bar + cancel confirm) and the review step it ends on.\n// `components/wizard-stepper` next door is a different, much smaller thing: a bare\n// step indicator for a two-step import flow, with no engine.\n//\n// Two modules were removed here rather than kept as stock. `wizard-field` held a\n// `WizardField`/`WizardSelectField` pair that had never been rendered in any app —\n// a field group nothing was built from, which this comment used to advertise. And\n// `use-rhf-wizard-step` was the only thing in the package that touched\n// react-hook-form, for a hook neither consumer called: keeping it meant an optional\n// peer, a dev dependency and a type import in every consumer's typecheck, bought\n// for nobody. A design system may carry stock; untested stock nothing has ever\n// rendered is not stock, it is a liability with an export.\nexport * from \"./wizard/types\";\nexport * from \"./wizard/use-wizard\";\nexport * from \"./wizard/wizard-context\";\nexport * from \"./wizard/validation\";\nexport * from \"./wizard/wizard-step\";\nexport * from \"./wizard/wizard-summary\";\nexport * from \"./wizard/stepper-nav\";\n\n// ── guided tours ─────────────────────────────────────────────────────────────\nexport * from \"./tour/tour\";\n\n// ── command palette / global search ──────────────────────────────────────────\nexport * from \"./search/command-palette\";\n\n// ── i18n: one label tree, one optional provider ──────────────────────────────\n// `UiKitLabels` names every string the kit renders; `<UiKitProvider labels locale>`\n// hands a translation to every component below it. Precedence: a component's own\n// prop > the provider > the English default. See src/i18n/kit-labels.tsx.\nexport * from \"./i18n/kit-labels\";\nexport * from \"./i18n/defaults\";\n"],"mappings":";AAMA,cAAc;AACd,SAAS,UAAU;AACnB,SAAS,QAAQ,mBAAmB;AAIpC,SAAS,qBAAqB;AAC9B,SAAS,yBAAyB;AAClC,SAAS,uBAAuB;AAEhC,SAAS,kBAAkB,wBAAwB,yBAAyB;AAM5E,SAAS,cAAc,uBAAuB;AAI9C,SAAS,oBAAoB;AAE7B,SAAS,mBAAmB;AAE5B,SAAS,yBAAyB;AAClC,SAAS,oBAAoB,uBAAuB;AACpD,SAAS,mBAAmB;AAI5B,cAAc;AAKd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,SAAS,oBAAoB;AAE7B,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAId,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAId,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,SAAS,qBAAqB;AAG9B,SAAS,iBAAiB;AAI1B,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AASd,cAAc;AACd,cAAc;AACd,cAAc;AAgBd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AAGd,cAAc;AAMd,cAAc;AACd,cAAc;","names":[]}
|
package/dist/lib/calc.js
CHANGED
package/dist/lib/calc.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/lib/calc.ts"],"sourcesContent":["/**\n * A tiny, dependency-free arithmetic evaluator for the numeric input fields.\n * It lets users type a calculation (e.g. \"12.50+3.20\" or \"100/3\") straight into\n * an amount field, or build one in the calculator popover, and have it resolve\n * to a number. Deliberately NOT backed by `eval`/`Function` — it's a hand-rolled\n * tokenizer + recursive-descent parser over a closed grammar (digits, decimals,\n * `+ - * /`, unary minus, parentheses), so no arbitrary code can run.\n */\n\ntype Token =\n | { kind: \"num\"; value: number }\n | { kind: \"op\"; value: \"+\" | \"-\" | \"*\" | \"/\" }\n | { kind: \"lparen\" }\n | { kind: \"rparen\" };\n\nfunction tokenize(input: string): Token[] | null {\n const tokens: Token[] = [];\n let i = 0;\n while (i < input.length) {\n const ch = input[i];\n if (ch === \" \") {\n i++;\n continue;\n }\n if (ch === \"+\" || ch === \"-\" || ch === \"*\" || ch === \"/\") {\n tokens.push({ kind: \"op\", value: ch });\n i++;\n continue;\n }\n if (ch === \"(\") {\n tokens.push({ kind: \"lparen\" });\n i++;\n continue;\n }\n if (ch === \")\") {\n tokens.push({ kind: \"rparen\" });\n i++;\n continue;\n }\n if ((ch >= \"0\" && ch <= \"9\") || ch === \".\") {\n let j = i;\n let dotSeen = false;\n while (j < input.length && ((input[j] >= \"0\" && input[j] <= \"9\") || input[j] === \".\")) {\n if (input[j] === \".\") {\n if (dotSeen) return null; // two dots in one number → invalid\n dotSeen = true;\n }\n j++;\n }\n const num = Number(input.slice(i, j));\n if (!Number.isFinite(num)) return null;\n tokens.push({ kind: \"num\", value: num });\n i = j;\n continue;\n }\n return null; // unknown character\n }\n return tokens;\n}\n\n/**\n * Recursive-descent parse honouring `* /` over `+ -` and left-associativity.\n * Returns `null` for any malformed input (the `null` sentinel is safe because a\n * valid result of 0 is distinct from it). Division by zero is treated as invalid.\n *\n * expr := term (('+' | '-') term)*\n * term := factor (('*' | '/') factor)*\n * factor := ('+' | '-') factor | number | '(' expr ')'\n */\nfunction parse(tokens: Token[]): number | null {\n let pos = 0;\n\n function parseExpr(): number | null {\n let value = parseTerm();\n if (value === null) return null;\n while (pos < tokens.length) {\n const tok = tokens[pos];\n if (tok.kind === \"op\" && (tok.value === \"+\" || tok.value === \"-\")) {\n pos++;\n const rhs = parseTerm();\n if (rhs === null) return null;\n value = tok.value === \"+\" ? value + rhs : value - rhs;\n } else break;\n }\n return value;\n }\n\n function parseTerm(): number | null {\n let value = parseFactor();\n if (value === null) return null;\n while (pos < tokens.length) {\n const tok = tokens[pos];\n if (tok.kind === \"op\" && (tok.value === \"*\" || tok.value === \"/\")) {\n pos++;\n const rhs = parseFactor();\n if (rhs === null) return null;\n if (tok.value === \"/\") {\n if (rhs === 0) return null;\n value = value / rhs;\n } else {\n value = value * rhs;\n }\n } else break;\n }\n return value;\n }\n\n function parseFactor(): number | null {\n const tok = tokens[pos];\n if (!tok) return null;\n if (tok.kind === \"op\" && (tok.value === \"+\" || tok.value === \"-\")) {\n pos++;\n const operand = parseFactor();\n if (operand === null) return null;\n return tok.value === \"-\" ? -operand : operand;\n }\n if (tok.kind === \"lparen\") {\n pos++;\n const inner = parseExpr();\n if (inner === null) return null;\n if (tokens[pos]?.kind !== \"rparen\") return null;\n pos++;\n return inner;\n }\n if (tok.kind === \"num\") {\n pos++;\n return tok.value;\n }\n return null;\n }\n\n const result = parseExpr();\n if (result === null) return null;\n if (pos !== tokens.length) return null; // leftover tokens → invalid\n return result;\n}\n\n/** Evaluate an arithmetic string, returning `null` if it isn't a valid sum.\n * Accepts the on-screen operator glyphs (`× ÷ −`) and comma decimals too. */\nexport function evaluateExpression(expr: string): number | null {\n const normalized = expr\n .replace(/×/g, \"*\")\n .replace(/÷/g, \"/\")\n .replace(/[−–—]/g, \"-\") // unicode minus / en / em dash → ascii\n .replace(/,/g, \".\")\n .trim();\n if (normalized === \"\") return null;\n const tokens = tokenize(normalized);\n if (tokens === null || tokens.length === 0) return null;\n const result = parse(tokens);\n if (result === null || !Number.isFinite(result)) return null;\n return result;\n}\n\n/** True when `s` carries arithmetic beyond a single leading minus — i.e. a plain\n * number (or a lone negative like \"-5\") is NOT an expression, but \"12+5\" is.\n * Used to decide whether a field's text should be evaluated on commit.\n *\n * The operator set is the one {@link evaluateExpression} accepts, on-screen glyphs\n * included: the calculator keypad inserts `× ÷ −`, and a `−` that this said was not\n * arithmetic went on to be read as a plain number — where the digits-only fallback\n * in {@link commitExpression} silently ate it, turning \"-42−−50\" (= 8) into a bare\n * 8 with no record that a sum had happened at all. */\nexport function looksLikeExpression(s: string): boolean {\n const t = s.trim();\n if (t === \"\") return false;\n if (/^-?\\d*[.,]?\\d*$/.test(t)) return false; // plain (optionally negative) decimal\n return /[+\\-*/×÷−–—()]/.test(t.replace(/^-/, \"\"));\n}\n\n/** Render an evaluated number back to a field-friendly string, trimming binary\n * float noise (so 0.1 + 0.2 reads \"0.3\", not \"0.30000000000000004\").\n *\n * FIXED notation, always, and that is the whole point of the function rather than a\n * detail of it. This used to end in `parseFloat(n.toFixed(10)).toString()`, and\n * `Number.prototype.toString` switches to EXPONENT notation below 1e-6 and at or\n * above 1e21 — an alphabet containing `e`, `+` and `-`. Neither function that reads a\n * field's text back accepts it: {@link tokenize} rejects `e` as an unknown character\n * and {@link sanitizeLive} deletes it. So {@link commitExpression} fell through to\n * its digits-only cleanup, which stripped the `e` and CONCATENATED the mantissa to\n * the exponent. A field committed its own output as a different number:\n *\n * \"1/10000000\" -> \"1e-7\" -> \"17\" (AmountInput: \"6\")\n * \"999999999999*999999999999\" -> \"9.99999999998e+23\" -> \"9.9999999999823\"\n *\n * Both controls commit on blur AND on Enter, so Enter-then-click-away was enough on\n * its own, it was silent, and it was in a money field.\n *\n * The invariant, which the test asserts directly rather than by example:\n * **`commitExpression(formatResult(n))` equals `formatResult(n)` for every finite\n * `n`.** Anything rendered here has to survive being read back. */\nexport function formatResult(n: number): string {\n if (!Number.isFinite(n)) return \"\";\n // At or above 1e21 `toFixed` gives up and hands back `toString`'s exponent form —\n // but every double that large is an integer, so BigInt renders it exactly.\n if (Math.abs(n) >= 1e21) return BigInt(n).toString();\n return trimTrailingZeros(n.toFixed(10));\n}\n\n/** \"15.7000000000\" -> \"15.7\", \"0.0000000000\" -> \"0\". The ten decimals are where the\n * binary float noise gets rounded off; this is only about not showing the padding. */\nfunction trimTrailingZeros(fixed: string): string {\n if (!fixed.includes(\".\")) return fixed;\n const trimmed = fixed.replace(/0+$/, \"\").replace(/\\.$/, \"\");\n // `toFixed` keeps the sign on a magnitude that rounded away to nothing\n // (\"-0.0000000000\"); `toString` did not, and \"-0\" in an amount field is noise.\n return trimmed === \"-0\" || trimmed === \"\" ? \"0\" : trimmed;\n}\n\n/** The single \"on blur / Enter\" transform a numeric field applies: evaluate the\n * text if it's an expression, otherwise normalise it to a bare number string\n * (comma → dot, dropping stray characters, non-leading minuses and anything after\n * a second decimal point).\n *\n * The last clause is the backstop for Keksdose live #201. A field the user typed in\n * cannot reach here malformed any more — {@link sanitizeLive} runs on every change,\n * including a paste — but a value handed in from elsewhere (a recurring rule, an\n * import, a test) still can, and \"1.2.3\" is not an expression (no operator), so it\n * used to fall straight through unchanged and be read as NaN. Here the text is CUT\n * at the second dot (\"1.2\") rather than joined (\"1.23\"): with no keystroke to\n * ignore there is nothing to say which reading was meant, and the shorter one\n * cannot silently invent a bigger number. */\nexport function commitExpression(raw: string): string {\n const s = raw.trim();\n if (looksLikeExpression(s)) {\n const n = evaluateExpression(s);\n if (n !== null) return formatResult(n);\n // Unparseable (e.g. a half-typed \"12+\"): fall through to a digits-only clean.\n }\n // Global, like sanitizeLive's: these two are the two halves of one rule and must\n // not appear to state it differently. (The `[^0-9.-]` strip on the same line\n // already ate whatever commas a non-global replace missed, so this changes no\n // behaviour — it removes the need for the next reader to run it to find that out.)\n const cleaned = s.replace(/,/g, \".\").replace(/[^0-9.-]/g, \"\").replace(/(?!^)-/g, \"\");\n return cleaned.replace(/^(-?\\d*\\.?\\d*).*$/, \"$1\");\n}\n\n/** The live, per-keystroke transform a numeric field applies: comma → dot and\n * drop anything that isn't a digit, decimal point, arithmetic operator (incl.\n * the on-screen `× ÷` glyphs) or paren — so a typed calculation survives\n * keystroke-by-keystroke but stray characters can't be entered. A lone leading\n * `-` is kept — in a plain field it is simply a negative amount; in a field whose\n * caller owns the sign it is read off again by {@link splitLeadingSign}. The text\n * is resolved to a plain number on blur/Enter via {@link commitExpression}. */\nexport function sanitizeLive(raw: string): string {\n return dropExtraDots(raw.replace(/,/g, \".\").replace(/[^0-9.+\\-*/×÷()]/g, \"\"));\n}\n\n/**\n * At most ONE decimal point per number (Keksdose live #201).\n *\n * Per NUMBER, not per string: \"1.5+2.5\" is a legitimate calculation with two dots\n * in two operands, so the counter resets at every operator and parenthesis.\n *\n * A second dot inside one operand is a **no-op keystroke** — the digits after it\n * keep landing, so \"1.2\" + \".\" + \"3\" is \"1.23\". That is what every calculator does\n * with a repeated decimal point, and it is the only option that does not make the\n * field feel broken (\"my 3 disappeared\"). This runs on paste as well as on typing,\n * so the malformed value never reaches the rest of the app: everything downstream\n * reads the field with `Number()`, NaN became a silent 0, and on the create form\n * that 0 was painted with the income green — a figure that was not a number at all\n * asserting money was coming in.\n */\nfunction dropExtraDots(s: string): string {\n let out = \"\";\n let dotInNumber = false;\n for (const ch of s) {\n if (ch === \".\") {\n if (dotInNumber) continue;\n dotInNumber = true;\n } else if (ch < \"0\" || ch > \"9\") {\n // An operator or a paren ends the current operand.\n dotInNumber = false;\n }\n out += ch;\n }\n return out;\n}\n\n/** A bare, unsigned amount: digits with at most one decimal separator and nothing\n * else — \"42\", \"42.\", \".5\", \"0,5\". NOT \"\" (an empty field has no figure to put a\n * sign in front of), not \"-42\", not \"12+5\". It is the only shape a DISPLAYED sign\n * prefix makes sense in front of; an expression carries its own arithmetic and has\n * to survive keystroke-for-keystroke. */\nexport function isBareAmount(s: string): boolean {\n const t = s.trim();\n return t !== \"\" && /^\\d*[.,]?\\d*$/.test(t);\n}\n\n/**\n * Split a LEADING sign off a plain signed number (Keksdose live #201 rework):\n * `\"-42\"` → `{ sign: \"-\", rest: \"42\" }`, everything else → `{ sign: \"\", rest: text }`.\n *\n * Only in front of a bare amount, because a minus with arithmetic after it IS\n * arithmetic: \"12-30\" is a subtraction, and \"-12+5\" is -7, not -(12+5). Those come\n * back untouched and are resolved by {@link commitExpression} on blur — at which\n * point the RESULT is a plain signed number and this function does get to speak.\n *\n * A lone \"-\" splits (rest \"\"): the sign is a statement about the direction the\n * moment it is typed, before any digit exists.\n */\nexport function splitLeadingSign(text: string): { sign: \"\" | \"-\" | \"+\"; rest: string } {\n const trimmed = text.trimStart();\n const sign = trimmed.charAt(0);\n if (sign !== \"-\" && sign !== \"+\") return { sign: \"\", rest: text };\n const rest = trimmed.slice(1);\n if (rest !== \"\" && !isBareAmount(rest)) return { sign: \"\", rest: text };\n return { sign, rest };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/lib/calc.ts"],"sourcesContent":["/**\n * A tiny, dependency-free arithmetic evaluator for the numeric input fields.\n * It lets users type a calculation (e.g. \"12.50+3.20\" or \"100/3\") straight into\n * an amount field, or build one in the calculator popover, and have it resolve\n * to a number. Deliberately NOT backed by `eval`/`Function` — it's a hand-rolled\n * tokenizer + recursive-descent parser over a closed grammar (digits, decimals,\n * `+ - * /`, unary minus, parentheses), so no arbitrary code can run.\n */\n\ntype Token =\n | { kind: \"num\"; value: number }\n | { kind: \"op\"; value: \"+\" | \"-\" | \"*\" | \"/\" }\n | { kind: \"lparen\" }\n | { kind: \"rparen\" };\n\nfunction tokenize(input: string): Token[] | null {\n const tokens: Token[] = [];\n let i = 0;\n while (i < input.length) {\n const ch = input[i];\n if (ch === \" \") {\n i++;\n continue;\n }\n if (ch === \"+\" || ch === \"-\" || ch === \"*\" || ch === \"/\") {\n tokens.push({ kind: \"op\", value: ch });\n i++;\n continue;\n }\n if (ch === \"(\") {\n tokens.push({ kind: \"lparen\" });\n i++;\n continue;\n }\n if (ch === \")\") {\n tokens.push({ kind: \"rparen\" });\n i++;\n continue;\n }\n if ((ch >= \"0\" && ch <= \"9\") || ch === \".\") {\n let j = i;\n let dotSeen = false;\n while (j < input.length && ((input[j] >= \"0\" && input[j] <= \"9\") || input[j] === \".\")) {\n if (input[j] === \".\") {\n if (dotSeen) return null; // two dots in one number → invalid\n dotSeen = true;\n }\n j++;\n }\n const num = Number(input.slice(i, j));\n if (!Number.isFinite(num)) return null;\n tokens.push({ kind: \"num\", value: num });\n i = j;\n continue;\n }\n return null; // unknown character\n }\n return tokens;\n}\n\n/**\n * Recursive-descent parse honouring `* /` over `+ -` and left-associativity.\n * Returns `null` for any malformed input (the `null` sentinel is safe because a\n * valid result of 0 is distinct from it). Division by zero is treated as invalid.\n *\n * expr := term (('+' | '-') term)*\n * term := factor (('*' | '/') factor)*\n * factor := ('+' | '-') factor | number | '(' expr ')'\n */\nfunction parse(tokens: Token[]): number | null {\n let pos = 0;\n\n function parseExpr(): number | null {\n let value = parseTerm();\n if (value === null) return null;\n while (pos < tokens.length) {\n const tok = tokens[pos];\n if (tok.kind === \"op\" && (tok.value === \"+\" || tok.value === \"-\")) {\n pos++;\n const rhs = parseTerm();\n if (rhs === null) return null;\n value = tok.value === \"+\" ? value + rhs : value - rhs;\n } else break;\n }\n return value;\n }\n\n function parseTerm(): number | null {\n let value = parseFactor();\n if (value === null) return null;\n while (pos < tokens.length) {\n const tok = tokens[pos];\n if (tok.kind === \"op\" && (tok.value === \"*\" || tok.value === \"/\")) {\n pos++;\n const rhs = parseFactor();\n if (rhs === null) return null;\n if (tok.value === \"/\") {\n if (rhs === 0) return null;\n value = value / rhs;\n } else {\n value = value * rhs;\n }\n } else break;\n }\n return value;\n }\n\n function parseFactor(): number | null {\n const tok = tokens[pos];\n if (!tok) return null;\n if (tok.kind === \"op\" && (tok.value === \"+\" || tok.value === \"-\")) {\n pos++;\n const operand = parseFactor();\n if (operand === null) return null;\n return tok.value === \"-\" ? -operand : operand;\n }\n if (tok.kind === \"lparen\") {\n pos++;\n const inner = parseExpr();\n if (inner === null) return null;\n if (tokens[pos]?.kind !== \"rparen\") return null;\n pos++;\n return inner;\n }\n if (tok.kind === \"num\") {\n pos++;\n return tok.value;\n }\n return null;\n }\n\n const result = parseExpr();\n if (result === null) return null;\n if (pos !== tokens.length) return null; // leftover tokens → invalid\n return result;\n}\n\n/** Evaluate an arithmetic string, returning `null` if it isn't a valid sum.\n * Accepts the on-screen operator glyphs (`× ÷ −`) and comma decimals too. */\nexport function evaluateExpression(expr: string): number | null {\n const normalized = expr\n .replace(/×/g, \"*\")\n .replace(/÷/g, \"/\")\n .replace(/[−–—]/g, \"-\") // unicode minus / en / em dash → ascii\n .replace(/,/g, \".\")\n .trim();\n if (normalized === \"\") return null;\n const tokens = tokenize(normalized);\n if (tokens === null || tokens.length === 0) return null;\n const result = parse(tokens);\n if (result === null || !Number.isFinite(result)) return null;\n return result;\n}\n\n/** True when `s` carries arithmetic beyond a single leading minus — i.e. a plain\n * number (or a lone negative like \"-5\") is NOT an expression, but \"12+5\" is.\n * Used to decide whether a field's text should be evaluated on commit.\n *\n * The operator set is the one {@link evaluateExpression} accepts, on-screen glyphs\n * included: the calculator keypad inserts `× ÷ −`, and a `−` that this said was not\n * arithmetic went on to be read as a plain number — where the digits-only fallback\n * in {@link commitExpression} silently ate it, turning \"-42−−50\" (= 8) into a bare\n * 8 with no record that a sum had happened at all. */\nexport function looksLikeExpression(s: string): boolean {\n const t = s.trim();\n if (t === \"\") return false;\n if (/^-?\\d*[.,]?\\d*$/.test(t)) return false; // plain (optionally negative) decimal\n return /[+\\-*/×÷−–—()]/.test(t.replace(/^-/, \"\"));\n}\n\n/** Render an evaluated number back to a field-friendly string, trimming binary\n * float noise (so 0.1 + 0.2 reads \"0.3\", not \"0.30000000000000004\").\n *\n * FIXED notation, always, and that is the whole point of the function rather than a\n * detail of it. This used to end in `parseFloat(n.toFixed(10)).toString()`, and\n * `Number.prototype.toString` switches to EXPONENT notation below 1e-6 and at or\n * above 1e21 — an alphabet containing `e`, `+` and `-`. Neither function that reads a\n * field's text back accepts it: {@link tokenize} rejects `e` as an unknown character\n * and {@link sanitizeLive} deletes it. So {@link commitExpression} fell through to\n * its digits-only cleanup, which stripped the `e` and CONCATENATED the mantissa to\n * the exponent. A field committed its own output as a different number:\n *\n * \"1/10000000\" -> \"1e-7\" -> \"17\" (AmountInput: \"6\")\n * \"999999999999*999999999999\" -> \"9.99999999998e+23\" -> \"9.9999999999823\"\n *\n * Both controls commit on blur AND on Enter, so Enter-then-click-away was enough on\n * its own, it was silent, and it was in a money field.\n *\n * The invariant, which the test asserts directly rather than by example:\n * **`commitExpression(formatResult(n))` equals `formatResult(n)` for every finite\n * `n`.** Anything rendered here has to survive being read back. */\nexport function formatResult(n: number): string {\n if (!Number.isFinite(n)) return \"\";\n // At or above 1e21 `toFixed` gives up and hands back `toString`'s exponent form —\n // but every double that large is an integer, so BigInt renders it exactly.\n if (Math.abs(n) >= 1e21) return BigInt(n).toString();\n return trimTrailingZeros(n.toFixed(10));\n}\n\n/** \"15.7000000000\" -> \"15.7\", \"0.0000000000\" -> \"0\". The ten decimals are where the\n * binary float noise gets rounded off; this is only about not showing the padding. */\nfunction trimTrailingZeros(fixed: string): string {\n if (!fixed.includes(\".\")) return fixed;\n const trimmed = fixed.replace(/0+$/, \"\").replace(/\\.$/, \"\");\n // `toFixed` keeps the sign on a magnitude that rounded away to nothing\n // (\"-0.0000000000\"); `toString` did not, and \"-0\" in an amount field is noise.\n return trimmed === \"-0\" || trimmed === \"\" ? \"0\" : trimmed;\n}\n\n/** The single \"on blur / Enter\" transform a numeric field applies: evaluate the\n * text if it's an expression, otherwise normalise it to a bare number string\n * (comma → dot, dropping stray characters, non-leading minuses and anything after\n * a second decimal point).\n *\n * The last clause is the backstop for Keksdose live #201. A field the user typed in\n * cannot reach here malformed any more — {@link sanitizeLive} runs on every change,\n * including a paste — but a value handed in from elsewhere (a recurring rule, an\n * import, a test) still can, and \"1.2.3\" is not an expression (no operator), so it\n * used to fall straight through unchanged and be read as NaN. Here the text is CUT\n * at the second dot (\"1.2\") rather than joined (\"1.23\"): with no keystroke to\n * ignore there is nothing to say which reading was meant, and the shorter one\n * cannot silently invent a bigger number. */\nexport function commitExpression(raw: string): string {\n const s = raw.trim();\n if (looksLikeExpression(s)) {\n const n = evaluateExpression(s);\n if (n !== null) return formatResult(n);\n // Unparseable (e.g. a half-typed \"12+\"): fall through to a digits-only clean.\n }\n // Global, like sanitizeLive's: these two are the two halves of one rule and must\n // not appear to state it differently. (The `[^0-9.-]` strip on the same line\n // already ate whatever commas a non-global replace missed, so this changes no\n // behaviour — it removes the need for the next reader to run it to find that out.)\n const cleaned = s.replace(/,/g, \".\").replace(/[^0-9.-]/g, \"\").replace(/(?!^)-/g, \"\");\n return cleaned.replace(/^(-?\\d*\\.?\\d*).*$/, \"$1\");\n}\n\n/** The live, per-keystroke transform a numeric field applies: comma → dot and\n * drop anything that isn't a digit, decimal point, arithmetic operator (incl.\n * the on-screen `× ÷` glyphs) or paren — so a typed calculation survives\n * keystroke-by-keystroke but stray characters can't be entered. A lone leading\n * `-` is kept — in a plain field it is simply a negative amount; in a field whose\n * caller owns the sign it is read off again by {@link splitLeadingSign}. The text\n * is resolved to a plain number on blur/Enter via {@link commitExpression}. */\nexport function sanitizeLive(raw: string): string {\n return dropExtraDots(raw.replace(/,/g, \".\").replace(/[^0-9.+\\-*/×÷()]/g, \"\"));\n}\n\n/**\n * At most ONE decimal point per number (Keksdose live #201).\n *\n * Per NUMBER, not per string: \"1.5+2.5\" is a legitimate calculation with two dots\n * in two operands, so the counter resets at every operator and parenthesis.\n *\n * A second dot inside one operand is a **no-op keystroke** — the digits after it\n * keep landing, so \"1.2\" + \".\" + \"3\" is \"1.23\". That is what every calculator does\n * with a repeated decimal point, and it is the only option that does not make the\n * field feel broken (\"my 3 disappeared\"). This runs on paste as well as on typing,\n * so the malformed value never reaches the rest of the app: everything downstream\n * reads the field with `Number()`, NaN became a silent 0, and on the create form\n * that 0 was painted with the income green — a figure that was not a number at all\n * asserting money was coming in.\n */\nfunction dropExtraDots(s: string): string {\n let out = \"\";\n let dotInNumber = false;\n for (const ch of s) {\n if (ch === \".\") {\n if (dotInNumber) continue;\n dotInNumber = true;\n } else if (ch < \"0\" || ch > \"9\") {\n // An operator or a paren ends the current operand.\n dotInNumber = false;\n }\n out += ch;\n }\n return out;\n}\n\n/** A bare, unsigned amount: digits with at most one decimal separator and nothing\n * else — \"42\", \"42.\", \".5\", \"0,5\". NOT \"\" (an empty field has no figure to put a\n * sign in front of), not \"-42\", not \"12+5\". It is the only shape a DISPLAYED sign\n * prefix makes sense in front of; an expression carries its own arithmetic and has\n * to survive keystroke-for-keystroke. */\nexport function isBareAmount(s: string): boolean {\n const t = s.trim();\n return t !== \"\" && /^\\d*[.,]?\\d*$/.test(t);\n}\n\n/**\n * Split a LEADING sign off a plain signed number (Keksdose live #201 rework):\n * `\"-42\"` → `{ sign: \"-\", rest: \"42\" }`, everything else → `{ sign: \"\", rest: text }`.\n *\n * Only in front of a bare amount, because a minus with arithmetic after it IS\n * arithmetic: \"12-30\" is a subtraction, and \"-12+5\" is -7, not -(12+5). Those come\n * back untouched and are resolved by {@link commitExpression} on blur — at which\n * point the RESULT is a plain signed number and this function does get to speak.\n *\n * A lone \"-\" splits (rest \"\"): the sign is a statement about the direction the\n * moment it is typed, before any digit exists.\n */\nexport function splitLeadingSign(text: string): { sign: \"\" | \"-\" | \"+\"; rest: string } {\n const trimmed = text.trimStart();\n const sign = trimmed.charAt(0);\n if (sign !== \"-\" && sign !== \"+\") return { sign: \"\", rest: text };\n const rest = trimmed.slice(1);\n if (rest !== \"\" && !isBareAmount(rest)) return { sign: \"\", rest: text };\n return { sign, rest };\n}\n"],"mappings":";AAeA,SAAS,SAAS,OAA+B;AAC/C,QAAM,SAAkB,CAAC;AACzB,MAAI,IAAI;AACR,SAAO,IAAI,MAAM,QAAQ;AACvB,UAAM,KAAK,MAAM,CAAC;AAClB,QAAI,OAAO,KAAK;AACd;AACA;AAAA,IACF;AACA,QAAI,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,KAAK;AACxD,aAAO,KAAK,EAAE,MAAM,MAAM,OAAO,GAAG,CAAC;AACrC;AACA;AAAA,IACF;AACA,QAAI,OAAO,KAAK;AACd,aAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B;AACA;AAAA,IACF;AACA,QAAI,OAAO,KAAK;AACd,aAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B;AACA;AAAA,IACF;AACA,QAAK,MAAM,OAAO,MAAM,OAAQ,OAAO,KAAK;AAC1C,UAAI,IAAI;AACR,UAAI,UAAU;AACd,aAAO,IAAI,MAAM,WAAY,MAAM,CAAC,KAAK,OAAO,MAAM,CAAC,KAAK,OAAQ,MAAM,CAAC,MAAM,MAAM;AACrF,YAAI,MAAM,CAAC,MAAM,KAAK;AACpB,cAAI,QAAS,QAAO;AACpB,oBAAU;AAAA,QACZ;AACA;AAAA,MACF;AACA,YAAM,MAAM,OAAO,MAAM,MAAM,GAAG,CAAC,CAAC;AACpC,UAAI,CAAC,OAAO,SAAS,GAAG,EAAG,QAAO;AAClC,aAAO,KAAK,EAAE,MAAM,OAAO,OAAO,IAAI,CAAC;AACvC,UAAI;AACJ;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAWA,SAAS,MAAM,QAAgC;AAC7C,MAAI,MAAM;AAEV,WAAS,YAA2B;AAClC,QAAI,QAAQ,UAAU;AACtB,QAAI,UAAU,KAAM,QAAO;AAC3B,WAAO,MAAM,OAAO,QAAQ;AAC1B,YAAM,MAAM,OAAO,GAAG;AACtB,UAAI,IAAI,SAAS,SAAS,IAAI,UAAU,OAAO,IAAI,UAAU,MAAM;AACjE;AACA,cAAM,MAAM,UAAU;AACtB,YAAI,QAAQ,KAAM,QAAO;AACzB,gBAAQ,IAAI,UAAU,MAAM,QAAQ,MAAM,QAAQ;AAAA,MACpD,MAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAEA,WAAS,YAA2B;AAClC,QAAI,QAAQ,YAAY;AACxB,QAAI,UAAU,KAAM,QAAO;AAC3B,WAAO,MAAM,OAAO,QAAQ;AAC1B,YAAM,MAAM,OAAO,GAAG;AACtB,UAAI,IAAI,SAAS,SAAS,IAAI,UAAU,OAAO,IAAI,UAAU,MAAM;AACjE;AACA,cAAM,MAAM,YAAY;AACxB,YAAI,QAAQ,KAAM,QAAO;AACzB,YAAI,IAAI,UAAU,KAAK;AACrB,cAAI,QAAQ,EAAG,QAAO;AACtB,kBAAQ,QAAQ;AAAA,QAClB,OAAO;AACL,kBAAQ,QAAQ;AAAA,QAClB;AAAA,MACF,MAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAEA,WAAS,cAA6B;AACpC,UAAM,MAAM,OAAO,GAAG;AACtB,QAAI,CAAC,IAAK,QAAO;AACjB,QAAI,IAAI,SAAS,SAAS,IAAI,UAAU,OAAO,IAAI,UAAU,MAAM;AACjE;AACA,YAAM,UAAU,YAAY;AAC5B,UAAI,YAAY,KAAM,QAAO;AAC7B,aAAO,IAAI,UAAU,MAAM,CAAC,UAAU;AAAA,IACxC;AACA,QAAI,IAAI,SAAS,UAAU;AACzB;AACA,YAAM,QAAQ,UAAU;AACxB,UAAI,UAAU,KAAM,QAAO;AAC3B,UAAI,OAAO,GAAG,GAAG,SAAS,SAAU,QAAO;AAC3C;AACA,aAAO;AAAA,IACT;AACA,QAAI,IAAI,SAAS,OAAO;AACtB;AACA,aAAO,IAAI;AAAA,IACb;AACA,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,UAAU;AACzB,MAAI,WAAW,KAAM,QAAO;AAC5B,MAAI,QAAQ,OAAO,OAAQ,QAAO;AAClC,SAAO;AACT;AAIO,SAAS,mBAAmB,MAA6B;AAC9D,QAAM,aAAa,KAChB,QAAQ,MAAM,GAAG,EACjB,QAAQ,MAAM,GAAG,EACjB,QAAQ,UAAU,GAAG,EACrB,QAAQ,MAAM,GAAG,EACjB,KAAK;AACR,MAAI,eAAe,GAAI,QAAO;AAC9B,QAAM,SAAS,SAAS,UAAU;AAClC,MAAI,WAAW,QAAQ,OAAO,WAAW,EAAG,QAAO;AACnD,QAAM,SAAS,MAAM,MAAM;AAC3B,MAAI,WAAW,QAAQ,CAAC,OAAO,SAAS,MAAM,EAAG,QAAO;AACxD,SAAO;AACT;AAWO,SAAS,oBAAoB,GAAoB;AACtD,QAAM,IAAI,EAAE,KAAK;AACjB,MAAI,MAAM,GAAI,QAAO;AACrB,MAAI,kBAAkB,KAAK,CAAC,EAAG,QAAO;AACtC,SAAO,iBAAiB,KAAK,EAAE,QAAQ,MAAM,EAAE,CAAC;AAClD;AAuBO,SAAS,aAAa,GAAmB;AAC9C,MAAI,CAAC,OAAO,SAAS,CAAC,EAAG,QAAO;AAGhC,MAAI,KAAK,IAAI,CAAC,KAAK,KAAM,QAAO,OAAO,CAAC,EAAE,SAAS;AACnD,SAAO,kBAAkB,EAAE,QAAQ,EAAE,CAAC;AACxC;AAIA,SAAS,kBAAkB,OAAuB;AAChD,MAAI,CAAC,MAAM,SAAS,GAAG,EAAG,QAAO;AACjC,QAAM,UAAU,MAAM,QAAQ,OAAO,EAAE,EAAE,QAAQ,OAAO,EAAE;AAG1D,SAAO,YAAY,QAAQ,YAAY,KAAK,MAAM;AACpD;AAeO,SAAS,iBAAiB,KAAqB;AACpD,QAAM,IAAI,IAAI,KAAK;AACnB,MAAI,oBAAoB,CAAC,GAAG;AAC1B,UAAM,IAAI,mBAAmB,CAAC;AAC9B,QAAI,MAAM,KAAM,QAAO,aAAa,CAAC;AAAA,EAEvC;AAKA,QAAM,UAAU,EAAE,QAAQ,MAAM,GAAG,EAAE,QAAQ,aAAa,EAAE,EAAE,QAAQ,WAAW,EAAE;AACnF,SAAO,QAAQ,QAAQ,qBAAqB,IAAI;AAClD;AASO,SAAS,aAAa,KAAqB;AAChD,SAAO,cAAc,IAAI,QAAQ,MAAM,GAAG,EAAE,QAAQ,qBAAqB,EAAE,CAAC;AAC9E;AAiBA,SAAS,cAAc,GAAmB;AACxC,MAAI,MAAM;AACV,MAAI,cAAc;AAClB,aAAW,MAAM,GAAG;AAClB,QAAI,OAAO,KAAK;AACd,UAAI,YAAa;AACjB,oBAAc;AAAA,IAChB,WAAW,KAAK,OAAO,KAAK,KAAK;AAE/B,oBAAc;AAAA,IAChB;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAOO,SAAS,aAAa,GAAoB;AAC/C,QAAM,IAAI,EAAE,KAAK;AACjB,SAAO,MAAM,MAAM,gBAAgB,KAAK,CAAC;AAC3C;AAcO,SAAS,iBAAiB,MAAsD;AACrF,QAAM,UAAU,KAAK,UAAU;AAC/B,QAAM,OAAO,QAAQ,OAAO,CAAC;AAC7B,MAAI,SAAS,OAAO,SAAS,IAAK,QAAO,EAAE,MAAM,IAAI,MAAM,KAAK;AAChE,QAAM,OAAO,QAAQ,MAAM,CAAC;AAC5B,MAAI,SAAS,MAAM,CAAC,aAAa,IAAI,EAAG,QAAO,EAAE,MAAM,IAAI,MAAM,KAAK;AACtE,SAAO,EAAE,MAAM,KAAK;AACtB;","names":[]}
|
package/dist/lib/cn.js
CHANGED
package/dist/lib/cn.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/lib/cn.ts"],"sourcesContent":["import { clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/** Merge class lists with Tailwind conflict resolution (later wins). */\nexport const cn = (...inputs: Parameters<typeof clsx>) => twMerge(clsx(inputs));\n"],"mappings":"AAAA,SAAS,YAAY;AACrB,SAAS,eAAe;AAGjB,MAAM,KAAK,IAAI,WAAoC,QAAQ,KAAK,MAAM,CAAC;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/lib/cn.ts"],"sourcesContent":["import { clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/** Merge class lists with Tailwind conflict resolution (later wins). */\nexport const cn = (...inputs: Parameters<typeof clsx>) => twMerge(clsx(inputs));\n"],"mappings":";AAAA,SAAS,YAAY;AACrB,SAAS,eAAe;AAGjB,MAAM,KAAK,IAAI,WAAoC,QAAQ,KAAK,MAAM,CAAC;","names":[]}
|
package/dist/lib/dates.js
CHANGED