@eifi1/ui-kit 0.11.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -34
- package/dist/chart.d.ts +3 -1
- package/dist/chart.js +2 -0
- package/dist/chart.js.map +1 -1
- package/dist/components/account-settings-labels.d.ts +105 -0
- package/dist/components/account-settings-labels.js +81 -0
- package/dist/components/account-settings-labels.js.map +1 -0
- package/dist/components/account-settings.d.ts +36 -52
- package/dist/components/account-settings.js +44 -8
- package/dist/components/account-settings.js.map +1 -1
- package/dist/components/amount-input.d.ts +40 -4
- package/dist/components/amount-input.js +50 -12
- package/dist/components/amount-input.js.map +1 -1
- package/dist/components/authed-image.d.ts +68 -0
- package/dist/components/authed-image.js +117 -0
- package/dist/components/authed-image.js.map +1 -0
- package/dist/components/breadcrumbs.d.ts +2 -1
- package/dist/components/breadcrumbs.js +5 -2
- package/dist/components/breadcrumbs.js.map +1 -1
- package/dist/components/bulk-action-bar.d.ts +10 -2
- package/dist/components/bulk-action-bar.js.map +1 -1
- package/dist/components/button-group.d.ts +51 -2
- package/dist/components/button-group.js +5 -1
- package/dist/components/button-group.js.map +1 -1
- package/dist/components/calculator.d.ts +15 -4
- package/dist/components/calendar-heatmap.d.ts +41 -3
- package/dist/components/calendar-heatmap.js +48 -7
- package/dist/components/calendar-heatmap.js.map +1 -1
- package/dist/components/chart.js +14 -8
- package/dist/components/chart.js.map +1 -1
- package/dist/components/chip.d.ts +2 -1
- package/dist/components/chip.js +26 -18
- package/dist/components/chip.js.map +1 -1
- package/dist/components/choice-card.d.ts +35 -3
- package/dist/components/choice-card.js +83 -25
- package/dist/components/choice-card.js.map +1 -1
- package/dist/components/combobox-core.d.ts +3 -1
- package/dist/components/combobox-core.js +18 -5
- package/dist/components/combobox-core.js.map +1 -1
- package/dist/components/combobox.d.ts +2 -2
- package/dist/components/combobox.js +31 -9
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/copy-button.d.ts +51 -70
- package/dist/components/copy-button.js +1 -1
- package/dist/components/copy-button.js.map +1 -1
- package/dist/components/data-table-cells.d.ts +63 -0
- package/dist/components/data-table-cells.js +64 -0
- package/dist/components/data-table-cells.js.map +1 -0
- package/dist/components/data-table-filter-popover.d.ts +1 -1
- package/dist/components/data-table-filter-popover.js +8 -1
- package/dist/components/data-table-filter-popover.js.map +1 -1
- package/dist/components/data-table-filters.d.ts +1 -1
- package/dist/components/data-table-filters.js +31 -1
- package/dist/components/data-table-filters.js.map +1 -1
- package/dist/components/data-table-labels.d.ts +13 -0
- package/dist/components/data-table-labels.js +8 -1
- package/dist/components/data-table-labels.js.map +1 -1
- package/dist/components/data-table.d.ts +1 -1
- package/dist/components/data-table.js +125 -27
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/date-picker.d.ts +3 -1
- package/dist/components/date-picker.js +15 -2
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/description-list.d.ts +23 -3
- package/dist/components/description-list.js +23 -3
- package/dist/components/description-list.js.map +1 -1
- package/dist/components/dialog-frame.d.ts +1 -0
- package/dist/components/entity-combobox.d.ts +1 -1
- package/dist/components/entity-combobox.js +40 -20
- package/dist/components/entity-combobox.js.map +1 -1
- package/dist/components/error-boundary.d.ts +281 -0
- package/dist/components/error-boundary.js +302 -0
- package/dist/components/error-boundary.js.map +1 -0
- package/dist/components/field-sync.js +90 -83
- package/dist/components/field-sync.js.map +1 -1
- package/dist/components/field.d.ts +30 -4
- package/dist/components/field.js +40 -17
- package/dist/components/field.js.map +1 -1
- package/dist/components/file-button.d.ts +50 -208
- package/dist/components/file-dropzone.d.ts +49 -2
- package/dist/components/floating-panel.d.ts +13 -4
- package/dist/components/floating-panel.js +7 -3
- package/dist/components/floating-panel.js.map +1 -1
- package/dist/components/form-actions.d.ts +53 -0
- package/dist/components/form-actions.js +98 -0
- package/dist/components/form-actions.js.map +1 -0
- package/dist/components/full-bleed-dialog.js +4 -0
- package/dist/components/full-bleed-dialog.js.map +1 -1
- package/dist/components/hover-menu.js +64 -56
- package/dist/components/hover-menu.js.map +1 -1
- package/dist/components/image-grid.d.ts +67 -0
- package/dist/components/image-grid.js +112 -0
- package/dist/components/image-grid.js.map +1 -0
- package/dist/components/lightbox.d.ts +104 -0
- package/dist/components/lightbox.js +229 -0
- package/dist/components/lightbox.js.map +1 -0
- package/dist/components/line-items.d.ts +114 -0
- package/dist/components/line-items.js +238 -0
- package/dist/components/line-items.js.map +1 -0
- package/dist/components/list.d.ts +37 -4
- package/dist/components/list.js +35 -14
- package/dist/components/list.js.map +1 -1
- package/dist/components/loading-state.d.ts +24 -0
- package/dist/components/loading-state.js +32 -0
- package/dist/components/loading-state.js.map +1 -0
- package/dist/components/menu-item.d.ts +2 -1
- package/dist/components/menu-item.js +5 -1
- package/dist/components/menu-item.js.map +1 -1
- package/dist/components/mini-calendar.d.ts +13 -1
- package/dist/components/mini-calendar.js +46 -2
- package/dist/components/mini-calendar.js.map +1 -1
- package/dist/components/modal.d.ts +20 -1
- package/dist/components/modal.js +26 -2
- package/dist/components/modal.js.map +1 -1
- package/dist/components/month-picker.d.ts +21 -1
- package/dist/components/month-picker.js +139 -26
- package/dist/components/month-picker.js.map +1 -1
- package/dist/components/multi-entity-combobox.d.ts +1 -1
- package/dist/components/multi-entity-combobox.js +42 -20
- package/dist/components/multi-entity-combobox.js.map +1 -1
- package/dist/components/nav-pills.d.ts +2 -1
- package/dist/components/nav-pills.js +5 -1
- package/dist/components/nav-pills.js.map +1 -1
- package/dist/components/number-field.d.ts +24 -5
- package/dist/components/number-field.js +5 -7
- package/dist/components/number-field.js.map +1 -1
- package/dist/components/number-input.d.ts +25 -5
- package/dist/components/number-input.js +7 -1
- package/dist/components/number-input.js.map +1 -1
- package/dist/components/numpad-sheet.d.ts +20 -5
- package/dist/components/numpad-sheet.js +3 -2
- package/dist/components/numpad-sheet.js.map +1 -1
- package/dist/components/page-header.d.ts +35 -6
- package/dist/components/page-header.js +7 -1
- package/dist/components/page-header.js.map +1 -1
- package/dist/components/passkeys-setting.d.ts +67 -0
- package/dist/components/passkeys-setting.js +214 -0
- package/dist/components/passkeys-setting.js.map +1 -0
- package/dist/components/picker-sheet.js +5 -1
- package/dist/components/picker-sheet.js.map +1 -1
- package/dist/components/pie-chart-labels.d.ts +20 -0
- package/dist/components/pie-chart-labels.js +12 -0
- package/dist/components/pie-chart-labels.js.map +1 -0
- package/dist/components/pie-chart.d.ts +101 -0
- package/dist/components/pie-chart.js +283 -0
- package/dist/components/pie-chart.js.map +1 -0
- package/dist/components/popover.js +3 -0
- package/dist/components/popover.js.map +1 -1
- package/dist/components/progress-bar.d.ts +44 -3
- package/dist/components/progress-bar.js +58 -22
- package/dist/components/progress-bar.js.map +1 -1
- package/dist/components/qr-code.d.ts +34 -0
- package/dist/components/qr-code.js +57 -0
- package/dist/components/qr-code.js.map +1 -0
- package/dist/components/search-field.d.ts +15 -3
- package/dist/components/search-field.js +5 -1
- package/dist/components/search-field.js.map +1 -1
- package/dist/components/settings-fields.d.ts +49 -1
- package/dist/components/signed-amount.d.ts +122 -0
- package/dist/components/signed-amount.js +152 -0
- package/dist/components/signed-amount.js.map +1 -0
- package/dist/components/skeleton.d.ts +10 -3
- package/dist/components/skeleton.js +12 -2
- package/dist/components/skeleton.js.map +1 -1
- package/dist/components/stat-tile.d.ts +2 -1
- package/dist/components/stat-tile.js +6 -3
- package/dist/components/stat-tile.js.map +1 -1
- package/dist/components/swipeable-row.js +4 -3
- package/dist/components/swipeable-row.js.map +1 -1
- package/dist/components/table.d.ts +39 -5
- package/dist/components/table.js +45 -11
- package/dist/components/table.js.map +1 -1
- package/dist/components/text-link.d.ts +238 -0
- package/dist/components/text-link.js +144 -0
- package/dist/components/text-link.js.map +1 -0
- package/dist/components/text.d.ts +26 -2
- package/dist/components/text.js +16 -2
- package/dist/components/text.js.map +1 -1
- package/dist/components/time-input.d.ts +49 -1
- package/dist/components/toggle-group.d.ts +35 -0
- package/dist/components/toggle-group.js +43 -14
- package/dist/components/toggle-group.js.map +1 -1
- package/dist/components/toggle-legend.d.ts +53 -3
- package/dist/components/toggle-legend.js +54 -1
- package/dist/components/toggle-legend.js.map +1 -1
- package/dist/components/tooltip.d.ts +51 -1
- package/dist/components/tooltip.js +59 -35
- package/dist/components/tooltip.js.map +1 -1
- package/dist/components/ui.d.ts +51 -779
- package/dist/components/ui.js +364 -34
- package/dist/components/ui.js.map +1 -1
- package/dist/components/use-table-state.d.ts +3 -52
- package/dist/components/use-table-state.js +128 -30
- package/dist/components/use-table-state.js.map +1 -1
- package/dist/{data-table-filters-Dh9uF_S-.d.ts → data-table-Drun8Fk9.d.ts} +305 -61
- package/dist/data-table.d.ts +2 -1
- package/dist/data-table.js +5 -1
- package/dist/data-table.js.map +1 -1
- package/dist/feedback/feedback-attachment.js +4 -6
- package/dist/feedback/feedback-attachment.js.map +1 -1
- package/dist/feedback/feedback-dialog.d.ts +26 -3
- package/dist/feedback/feedback-dialog.js +21 -5
- package/dist/feedback/feedback-dialog.js.map +1 -1
- package/dist/feedback/feedback-inbox.js +86 -75
- package/dist/feedback/feedback-inbox.js.map +1 -1
- package/dist/feedback/feedback-thread.d.ts +173 -0
- package/dist/feedback/feedback-thread.js +264 -0
- package/dist/feedback/feedback-thread.js.map +1 -0
- package/dist/feedback.d.ts +2 -1
- package/dist/feedback.js +1 -0
- package/dist/feedback.js.map +1 -1
- package/dist/hooks/use-authed-src.d.ts +71 -0
- package/dist/hooks/use-authed-src.js +63 -0
- package/dist/hooks/use-authed-src.js.map +1 -0
- package/dist/hooks/use-file-drop.d.ts +49 -2
- package/dist/hooks/use-hotkey.d.ts +59 -0
- package/dist/hooks/use-hotkey.js +105 -0
- package/dist/hooks/use-hotkey.js.map +1 -0
- package/dist/hooks/use-search-param-state.d.ts +83 -0
- package/dist/hooks/use-search-param-state.js +94 -0
- package/dist/hooks/use-search-param-state.js.map +1 -0
- package/dist/i18n/defaults.d.ts +15 -4
- package/dist/i18n/defaults.js +31 -1
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +46 -312
- package/dist/i18n/kit-labels.js +20 -5
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/locales/de-CH-informal.d.ts +15 -4
- package/dist/i18n/locales/de-CH.d.ts +15 -4
- package/dist/i18n/locales/de-informal.d.ts +15 -4
- package/dist/i18n/locales/de.d.ts +15 -4
- package/dist/i18n/locales/de.js +164 -3
- package/dist/i18n/locales/de.js.map +1 -1
- package/dist/i18n/locales/es.d.ts +15 -4
- package/dist/i18n/locales/es.js +161 -3
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.d.ts +15 -4
- package/dist/i18n/locales/fr.js +161 -3
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.d.ts +15 -4
- package/dist/i18n/locales/hu.js +161 -3
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.d.ts +15 -4
- package/dist/i18n/locales/it.js +161 -3
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.d.ts +15 -4
- package/dist/i18n/locales/zh.js +161 -3
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/index.d.ts +39 -19
- package/dist/index.js +40 -1
- package/dist/index.js.map +1 -1
- package/dist/kit-labels-Mz8zZHIF.d.ts +1744 -0
- package/dist/lib/format.d.ts +162 -0
- package/dist/lib/format.js +151 -0
- package/dist/lib/format.js.map +1 -0
- package/dist/lib/qr-encode.d.ts +44 -0
- package/dist/lib/qr-encode.js +338 -0
- package/dist/lib/qr-encode.js.map +1 -0
- package/dist/rhf/fields.d.ts +283 -0
- package/dist/rhf/fields.js +631 -0
- package/dist/rhf/fields.js.map +1 -0
- package/dist/rhf/form.d.ts +49 -1
- package/dist/rhf/line-items.d.ts +31 -0
- package/dist/rhf/line-items.js +59 -0
- package/dist/rhf/line-items.js.map +1 -0
- package/dist/rhf.d.ts +61 -1
- package/dist/rhf.js +2 -0
- package/dist/rhf.js.map +1 -1
- package/dist/search/command-palette.js +20 -14
- package/dist/search/command-palette.js.map +1 -1
- package/dist/shell/app-shell.d.ts +99 -2
- package/dist/shell/app-shell.js +120 -57
- package/dist/shell/app-shell.js.map +1 -1
- package/dist/shell/auth-layout.d.ts +74 -0
- package/dist/shell/auth-layout.js +97 -0
- package/dist/shell/auth-layout.js.map +1 -0
- package/dist/shell/top-bar-brand.d.ts +81 -0
- package/dist/shell/top-bar-brand.js +47 -0
- package/dist/shell/top-bar-brand.js.map +1 -0
- package/dist/shell/topbar-action-menu.d.ts +21 -4
- package/dist/shell/topbar-action-menu.js +18 -2
- package/dist/shell/topbar-action-menu.js.map +1 -1
- package/dist/shell.d.ts +56 -1
- package/dist/shell.js +2 -0
- package/dist/shell.js.map +1 -1
- package/dist/tour/tour.js +10 -4
- package/dist/tour/tour.js.map +1 -1
- package/dist/wizard/stepper-nav.d.ts +48 -1
- package/dist/wizard/use-wizard.js +4 -2
- package/dist/wizard/use-wizard.js.map +1 -1
- package/dist/wizard/wizard-context.d.ts +24 -1
- package/dist/wizard/wizard-context.js +19 -2
- package/dist/wizard/wizard-context.js.map +1 -1
- package/dist/wizard/wizard-step.d.ts +30 -5
- package/dist/wizard/wizard-step.js +34 -3
- package/dist/wizard/wizard-step.js.map +1 -1
- package/dist/wizard.d.ts +50 -3
- package/package.json +6 -6
- package/src/chart.ts +4 -0
- package/src/components/account-settings-labels.ts +190 -0
- package/src/components/account-settings.tsx +110 -63
- package/src/components/amount-input.tsx +109 -10
- package/src/components/authed-image.tsx +190 -0
- package/src/components/breadcrumbs.tsx +8 -2
- package/src/components/bulk-action-bar.tsx +16 -3
- package/src/components/button-group.tsx +7 -2
- package/src/components/calendar-heatmap.tsx +105 -10
- package/src/components/chart.tsx +19 -8
- package/src/components/chip.tsx +14 -4
- package/src/components/choice-card.tsx +136 -25
- package/src/components/combobox-core.tsx +33 -9
- package/src/components/combobox.tsx +33 -9
- package/src/components/copy-button.tsx +3 -2
- package/src/components/data-table-cells.tsx +119 -0
- package/src/components/data-table-filter-popover.tsx +13 -5
- package/src/components/data-table-filters.ts +77 -0
- package/src/components/data-table-labels.ts +23 -0
- package/src/components/data-table.tsx +230 -13
- package/src/components/date-picker.tsx +19 -3
- package/src/components/description-list.tsx +52 -3
- package/src/components/entity-combobox.tsx +25 -7
- package/src/components/error-boundary.tsx +640 -0
- package/src/components/field-sync.tsx +48 -40
- package/src/components/field.tsx +56 -5
- package/src/components/floating-panel.tsx +20 -7
- package/src/components/form-actions.tsx +191 -0
- package/src/components/full-bleed-dialog.tsx +4 -0
- package/src/components/hover-menu.tsx +26 -17
- package/src/components/image-grid.tsx +181 -0
- package/src/components/lightbox.tsx +374 -0
- package/src/components/line-items.tsx +385 -0
- package/src/components/list.tsx +82 -19
- package/src/components/loading-state.tsx +47 -0
- package/src/components/menu-item.tsx +7 -2
- package/src/components/mini-calendar.tsx +72 -3
- package/src/components/modal.tsx +65 -3
- package/src/components/month-picker.tsx +181 -26
- package/src/components/multi-entity-combobox.tsx +27 -7
- package/src/components/nav-pills.tsx +8 -1
- package/src/components/number-field.tsx +15 -10
- package/src/components/number-input.tsx +17 -1
- package/src/components/numpad-sheet.tsx +6 -1
- package/src/components/page-header.tsx +42 -5
- package/src/components/passkeys-setting.tsx +331 -0
- package/src/components/picker-sheet.tsx +10 -1
- package/src/components/pie-chart-labels.ts +32 -0
- package/src/components/pie-chart.tsx +479 -0
- package/src/components/popover.tsx +3 -0
- package/src/components/progress-bar.tsx +129 -19
- package/src/components/qr-code.tsx +83 -0
- package/src/components/search-field.tsx +20 -4
- package/src/components/signed-amount.tsx +295 -0
- package/src/components/skeleton.tsx +21 -3
- package/src/components/stat-tile.tsx +11 -3
- package/src/components/swipeable-row.tsx +7 -7
- package/src/components/table.tsx +102 -13
- package/src/components/text-link.tsx +356 -0
- package/src/components/text.tsx +46 -2
- package/src/components/toggle-group.tsx +93 -20
- package/src/components/toggle-legend.tsx +108 -2
- package/src/components/tooltip.tsx +79 -8
- package/src/components/ui.tsx +707 -49
- package/src/components/use-table-state.ts +265 -33
- package/src/data-table.ts +10 -0
- package/src/feedback/feedback-attachment.tsx +10 -7
- package/src/feedback/feedback-dialog.tsx +49 -7
- package/src/feedback/feedback-inbox.tsx +7 -0
- package/src/feedback/feedback-thread.tsx +510 -0
- package/src/feedback.ts +1 -0
- package/src/hooks/use-authed-src.ts +161 -0
- package/src/hooks/use-hotkey.ts +172 -0
- package/src/hooks/use-search-param-state.ts +187 -0
- package/src/i18n/defaults.ts +30 -0
- package/src/i18n/kit-labels.tsx +118 -8
- package/src/i18n/locales/de.ts +161 -0
- package/src/i18n/locales/es.ts +158 -0
- package/src/i18n/locales/fr.ts +161 -0
- package/src/i18n/locales/hu.ts +159 -0
- package/src/i18n/locales/it.ts +159 -0
- package/src/i18n/locales/zh.ts +158 -0
- package/src/index.ts +59 -0
- package/src/lib/format.ts +348 -0
- package/src/lib/qr-encode.ts +420 -0
- package/src/rhf/fields.tsx +1135 -0
- package/src/rhf/line-items.tsx +130 -0
- package/src/rhf.ts +6 -0
- package/src/search/command-palette.tsx +29 -19
- package/src/shell/app-shell.tsx +153 -3
- package/src/shell/auth-layout.tsx +190 -0
- package/src/shell/top-bar-brand.tsx +76 -0
- package/src/shell/topbar-action-menu.tsx +32 -4
- package/src/shell.ts +2 -0
- package/src/tour/tour.tsx +16 -5
- package/src/wizard/use-wizard.ts +8 -4
- package/src/wizard/wizard-context.tsx +41 -1
- package/src/wizard/wizard-step.tsx +75 -6
- package/tokens.css +12 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactElement, ComponentPropsWithoutRef, ReactNode, Ref, MouseEvent, KeyboardEvent } from 'react';
|
|
3
|
+
import { LucideIcon } from 'lucide-react';
|
|
4
|
+
import { az as KitLinkComponent } from '../kit-labels-Mz8zZHIF.js';
|
|
5
|
+
import './data-table-labels.js';
|
|
6
|
+
import './mini-calendar.js';
|
|
7
|
+
import './calendar-heatmap.js';
|
|
8
|
+
import './popover.js';
|
|
9
|
+
import './chip.js';
|
|
10
|
+
import './field-sync.js';
|
|
11
|
+
import './tooltip.js';
|
|
12
|
+
import '../hooks/use-anchored-rect.js';
|
|
13
|
+
import '../lib/clipping.js';
|
|
14
|
+
import '../wizard/types.js';
|
|
15
|
+
import '../tour/tour.js';
|
|
16
|
+
import '../search/command-palette.js';
|
|
17
|
+
import '../search/global-search.js';
|
|
18
|
+
import '../search/search-index.js';
|
|
19
|
+
import './month-picker.js';
|
|
20
|
+
import './page-contents.js';
|
|
21
|
+
import './series-chart-labels.js';
|
|
22
|
+
import './pie-chart-labels.js';
|
|
23
|
+
import './sparkline.js';
|
|
24
|
+
import './stat-tile.js';
|
|
25
|
+
import './signature-pad.js';
|
|
26
|
+
import './password-strength.js';
|
|
27
|
+
import './danger-confirm.js';
|
|
28
|
+
import './swatch-picker.js';
|
|
29
|
+
import './tile-radio.js';
|
|
30
|
+
import './icon-picker.js';
|
|
31
|
+
import './dialog-frame.js';
|
|
32
|
+
import './modal.js';
|
|
33
|
+
import '../hooks/use-search-param-state.js';
|
|
34
|
+
import './measured-grid.js';
|
|
35
|
+
import '../feedback/feedback-attachment.js';
|
|
36
|
+
import '../feedback/feedback-dialog.js';
|
|
37
|
+
import '../feedback/feedback-thread.js';
|
|
38
|
+
import '../feedback/feedback-inbox.js';
|
|
39
|
+
import './account-settings-labels.js';
|
|
40
|
+
import './confirm-dialog.js';
|
|
41
|
+
import './floating-panel.js';
|
|
42
|
+
import './bulk-action-bar.js';
|
|
43
|
+
import './list.js';
|
|
44
|
+
import './breadcrumbs.js';
|
|
45
|
+
import './toast.js';
|
|
46
|
+
import './description-list.js';
|
|
47
|
+
import './line-items.js';
|
|
48
|
+
import './progress-bar.js';
|
|
49
|
+
import './signed-amount.js';
|
|
50
|
+
import './error-boundary.js';
|
|
51
|
+
import './authed-image.js';
|
|
52
|
+
import '../hooks/use-authed-src.js';
|
|
53
|
+
import './image-grid.js';
|
|
54
|
+
import './lightbox.js';
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* An `href` that leaves the app: a scheme (`https:`, `mailto:`, `tel:`) or a
|
|
58
|
+
* protocol-relative `//host`. A router's link is for paths inside the app, so the
|
|
59
|
+
* provider's `linkComponent` is never handed one of these — they stay a plain `<a>`.
|
|
60
|
+
*
|
|
61
|
+
* NOT external, and so handed to the router link: a path (`/x`, `x`, `?q=1`) and the
|
|
62
|
+
* hash-router form `#/x` — that IS a route in a `HashRouter` app, which maps it to
|
|
63
|
+
* `to="/x"`. A plain in-page anchor (`#section`) is not external either, but it is not
|
|
64
|
+
* a route: see {@link isInPageAnchor}.
|
|
65
|
+
*/
|
|
66
|
+
declare function isExternalHref(href: string): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* An `href` that only scrolls the current page: `#section` (or a bare `#`). The
|
|
69
|
+
* hash-router form `#/x` is a ROUTE, not an anchor, and is not one of these. A router
|
|
70
|
+
* link must not get an anchor — under a `HashRouter` `#section` would navigate to the
|
|
71
|
+
* path `/section` — so every kit link draws it as a plain `<a>`.
|
|
72
|
+
*/
|
|
73
|
+
declare function isInPageAnchor(href: string): boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Whether the provider's `linkComponent` (or a kit component's router fallback) draws
|
|
76
|
+
* `href`: an in-app path, `#/x` included — not an external `href`
|
|
77
|
+
* ({@link isExternalHref}) and not an in-page `#anchor` ({@link isInPageAnchor}).
|
|
78
|
+
*/
|
|
79
|
+
declare function isRoutableHref(href: string): boolean;
|
|
80
|
+
/**
|
|
81
|
+
* What draws a kit link to `href`: the component's own `renderLink` when it was given
|
|
82
|
+
* one (it always wins — the caller asked for it by name), else the
|
|
83
|
+
* `<UiKitProvider linkComponent>` for a routable `href` ({@link isRoutableHref}), else
|
|
84
|
+
* `undefined` — a plain `<a>`. The one rule every kit link follows: `https:` /
|
|
85
|
+
* `mailto:` / `//host` and `#section` stay plain anchors; `/x`, `x` and a hash-router
|
|
86
|
+
* `#/x` go to the router link. Every kit link props type is a subset of the anchor
|
|
87
|
+
* attributes `KitLinkProps` describes, which is what makes the cast sound.
|
|
88
|
+
* @internal Shared by the kit's link-bearing components; not part of the barrel.
|
|
89
|
+
*/
|
|
90
|
+
declare function pickLinkRenderer<P>(own: ((props: P) => ReactElement) | undefined, kitLink: KitLinkComponent | undefined, href: string | undefined): ((props: P) => ReactElement) | undefined;
|
|
91
|
+
/**
|
|
92
|
+
* The `onClick` of a PLAIN `<a>` whose kit link was asked to `replace` (keksdose F1).
|
|
93
|
+
*
|
|
94
|
+
* A router link replaces the history entry itself (it is handed `replace`, see
|
|
95
|
+
* {@link routerLinkNavigation}); a plain `<a>` has no attribute that says so, and the
|
|
96
|
+
* browser's own navigation always pushes. So a plain click is taken over — the caller's
|
|
97
|
+
* `onClick` runs first and may still `preventDefault` — and becomes
|
|
98
|
+
* `location.replace(href)`: the same document load, with Back skipping the one-shot URL.
|
|
99
|
+
* That is the case of `replace` together with `reloadDocument`, or an app with no
|
|
100
|
+
* `linkComponent`. A modified click (new tab) and a `target` other than `_self` are left
|
|
101
|
+
* to the browser: they do not navigate THIS history. Without `replace`, `onClick` comes
|
|
102
|
+
* back untouched.
|
|
103
|
+
* @internal
|
|
104
|
+
*/
|
|
105
|
+
declare function replacingClick(onClick: ((event: MouseEvent<HTMLAnchorElement>) => void) | undefined, href: string, replace: boolean | undefined, target?: string): ((event: MouseEvent<HTMLAnchorElement>) => void) | undefined;
|
|
106
|
+
/**
|
|
107
|
+
* What a ROUTER link is handed for `replace`: `{ replace: true }` when asked, else
|
|
108
|
+
* nothing at all — so a provider link that spreads its props onto a DOM `<a>` never
|
|
109
|
+
* receives an unknown attribute from a link that did not ask (see `KitLinkProps.replace`).
|
|
110
|
+
* @internal
|
|
111
|
+
*/
|
|
112
|
+
declare function routerLinkNavigation(replace: boolean | undefined): {
|
|
113
|
+
replace?: true;
|
|
114
|
+
};
|
|
115
|
+
/**
|
|
116
|
+
* Draws `props` through `render` as a component of its own, so a router link's hooks
|
|
117
|
+
* belong to it and not to the kit component calling it — for the kit components that
|
|
118
|
+
* call their own `renderLink` inline and reach the provider's link through here.
|
|
119
|
+
* @internal
|
|
120
|
+
*/
|
|
121
|
+
declare function RenderedKitLink<P>({ render, props }: {
|
|
122
|
+
render: (props: P) => ReactElement;
|
|
123
|
+
props: P;
|
|
124
|
+
}): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
125
|
+
/**
|
|
126
|
+
* `brand` (default) for a link in running text, `muted` for footer and meta links
|
|
127
|
+
* that should not compete with the content, `danger` for a destructive one ("Leave
|
|
128
|
+
* group"), `inherit` for a link that takes its surroundings' colour.
|
|
129
|
+
*
|
|
130
|
+
* `primary` and `secondary` are the body and the secondary text colour, UNDERLINED
|
|
131
|
+
* (keksdose F3): a link that must read as part of the text around it — a name in a
|
|
132
|
+
* list row, a reference in a card's meta line — where `brand` repaints it in the accent
|
|
133
|
+
* and `muted` is a step too light to read as content. `secondary` darkens to the body
|
|
134
|
+
* colour under the pointer, as `muted` does; `primary` has nowhere darker to go, so its
|
|
135
|
+
* underline thickens instead.
|
|
136
|
+
*
|
|
137
|
+
* `warning` is the kit's `--warning` text colour, underlined (kastlan 46): a link inside
|
|
138
|
+
* a `<Tone tone="warning">` sentence or a warning banner, which `brand` would paint in a
|
|
139
|
+
* second hue and `inherit` would leave indistinguishable from the sentence. Like
|
|
140
|
+
* `primary`, it keeps its colour on hover and thickens the underline.
|
|
141
|
+
*
|
|
142
|
+
* The three colours that sit IN the text default to `underline="always"`: with the
|
|
143
|
+
* colour of their surroundings, the underline is the only thing that says "link"
|
|
144
|
+
* (WCAG 1.4.1). An explicit `underline` still wins.
|
|
145
|
+
*/
|
|
146
|
+
type TextLinkTone = "brand" | "muted" | "danger" | "inherit" | "primary" | "secondary" | "warning";
|
|
147
|
+
/** `hover` (the default for `brand`, `muted`, `danger`, `inherit`): underlined under
|
|
148
|
+
* the pointer — the idiom all three apps draw. `always` (the default for `primary`,
|
|
149
|
+
* `secondary`, `warning`) for a link inside prose, where colour alone must not be the
|
|
150
|
+
* only mark (WCAG 1.4.1). `none` where the context already says "link" (a footer nav). */
|
|
151
|
+
type TextLinkUnderline = "hover" | "always" | "none";
|
|
152
|
+
/** The `aria-current` token. `true` on {@link TextLinkProps.current} means `page`. */
|
|
153
|
+
type TextLinkCurrent = "page" | "step" | "location" | "date" | "time" | "true";
|
|
154
|
+
/** What {@link TextLinkProps.renderLink} (and the provider's `linkComponent`) is
|
|
155
|
+
* handed. Spread it onto your router's link — `({ href, ...p }) => <Link to={href} {...p} />`. */
|
|
156
|
+
interface TextLinkRenderProps {
|
|
157
|
+
href: string;
|
|
158
|
+
/** The link's look — keep it, or the tone, underline and focus ring go. */
|
|
159
|
+
className: string;
|
|
160
|
+
children: ReactNode;
|
|
161
|
+
ref?: Ref<HTMLAnchorElement>;
|
|
162
|
+
onClick?: (event: MouseEvent<HTMLAnchorElement>) => void;
|
|
163
|
+
onKeyDown?: (event: KeyboardEvent<HTMLAnchorElement>) => void;
|
|
164
|
+
"aria-current"?: TextLinkCurrent;
|
|
165
|
+
id?: string;
|
|
166
|
+
title?: string;
|
|
167
|
+
/** Present, as `true`, only when the link was given `replace` — see
|
|
168
|
+
* `KitLinkProps.replace`. Map it to your router's replace; never onto a DOM `<a>`. */
|
|
169
|
+
replace?: boolean;
|
|
170
|
+
[key: `aria-${string}`]: string | boolean | number | undefined;
|
|
171
|
+
[key: `data-${string}`]: unknown;
|
|
172
|
+
}
|
|
173
|
+
interface TextLinkProps extends Omit<ComponentPropsWithoutRef<"a">, "href" | "children" | "aria-current" | "onClick" | "onKeyDown"> {
|
|
174
|
+
href: string;
|
|
175
|
+
children: ReactNode;
|
|
176
|
+
/** Default `brand`. */
|
|
177
|
+
tone?: TextLinkTone;
|
|
178
|
+
/** Default `always` for `primary`, `secondary` and `warning`, else `hover`. */
|
|
179
|
+
underline?: TextLinkUnderline;
|
|
180
|
+
/**
|
|
181
|
+
* Navigate by replacing the current history entry, so Back does not return to this
|
|
182
|
+
* URL — keksdose F1, a one-shot URL (a confirmation landing, a `?done=1` hop). Handed
|
|
183
|
+
* to the router link as `replace` (see `KitLinkProps.replace` for mapping it); on a
|
|
184
|
+
* plain `<a>` (no `linkComponent`, or `reloadDocument`) a plain click becomes
|
|
185
|
+
* `location.replace(href)`. Ignored on an `external` link, which opens a new tab.
|
|
186
|
+
*/
|
|
187
|
+
replace?: boolean;
|
|
188
|
+
/**
|
|
189
|
+
* A plain `<a>` for an in-app `href`: the browser loads the whole document instead of
|
|
190
|
+
* the router swapping the view — keksdose F1, a route served outside the SPA (a file
|
|
191
|
+
* download, a server-rendered page, a logout that must drop every in-memory cache).
|
|
192
|
+
* Wins over `renderLink` and the provider's `linkComponent`: it is the caller saying
|
|
193
|
+
* "not the router" for this one link.
|
|
194
|
+
*/
|
|
195
|
+
reloadDocument?: boolean;
|
|
196
|
+
/**
|
|
197
|
+
* The link leaves the app: a plain `<a target="_blank" rel="noopener noreferrer">`
|
|
198
|
+
* (never the router's), an external-link mark after the text (mirrored in RTL), and
|
|
199
|
+
* "opens in a new tab" (`common.opensInNewTab`) read after it — the mark says it
|
|
200
|
+
* only to the eye. kastlan's BWO / BFS source links (rent-increase-calculator-page).
|
|
201
|
+
*/
|
|
202
|
+
external?: boolean;
|
|
203
|
+
/**
|
|
204
|
+
* Keep the click (and the Enter that activates the link) from reaching an ancestor —
|
|
205
|
+
* a link in a DataTable row with `onRowClick` goes to its own target instead of
|
|
206
|
+
* running the row's action. kastlan's `CellLink` did this by hand.
|
|
207
|
+
*/
|
|
208
|
+
stopPropagation?: boolean;
|
|
209
|
+
/** Mark the link as the current one of a set — `true` is `aria-current="page"`, the
|
|
210
|
+
* legal footer's link to the page you are on. Drawn in semibold. */
|
|
211
|
+
current?: boolean | TextLinkCurrent;
|
|
212
|
+
/** A Lucide icon before the text, at the text's size — kastlan's "← Back" link. */
|
|
213
|
+
icon?: LucideIcon;
|
|
214
|
+
/** Your router's link for an in-app `href`. Default: the `<UiKitProvider
|
|
215
|
+
* linkComponent>`, then a plain `<a>`. Ignored on an `external` link. */
|
|
216
|
+
renderLink?: (props: TextLinkRenderProps) => ReactElement;
|
|
217
|
+
onClick?: (event: MouseEvent<HTMLAnchorElement>) => void;
|
|
218
|
+
onKeyDown?: (event: KeyboardEvent<HTMLAnchorElement>) => void;
|
|
219
|
+
ref?: Ref<HTMLAnchorElement>;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* The one inline link: a real `<a href>` (middle click, "open in new tab", link
|
|
223
|
+
* semantics) through the app's router for an in-app path, in one of four tones.
|
|
224
|
+
*
|
|
225
|
+
* kastlan draws this link a dozen ways by hand — `EntityLink` and `CellLink` (text-primary,
|
|
226
|
+
* hover underline, one stopping the row click), the legal pages' back link and footer,
|
|
227
|
+
* the feedback page's URL links, the calculator's external sources with a hand-placed
|
|
228
|
+
* ↗ and no word for a screen reader — and the lease wizard's unit step (lease-unit-step)
|
|
229
|
+
* used a raw `<a>` to an in-app route, which reloads the whole app. Here the router
|
|
230
|
+
* link comes from `<UiKitProvider linkComponent>`, set once.
|
|
231
|
+
*
|
|
232
|
+
* Inline, not `inline-flex`: a link inside a sentence must wrap with it. The icons sit
|
|
233
|
+
* on the text's baseline at the text's size, so they scale with whatever type the link
|
|
234
|
+
* is set in. The focus ring is an outline, which follows every line of a wrapped link.
|
|
235
|
+
*/
|
|
236
|
+
declare function TextLink({ href, children, tone, underline: underlineProp, external, replace, reloadDocument, stopPropagation, current, icon: Icon, renderLink, className, onClick, onKeyDown, ref, ...rest }: TextLinkProps): react.JSX.Element;
|
|
237
|
+
|
|
238
|
+
export { RenderedKitLink, TextLink, type TextLinkCurrent, type TextLinkProps, type TextLinkRenderProps, type TextLinkTone, type TextLinkUnderline, isExternalHref, isInPageAnchor, isRoutableHref, pickLinkRenderer, replacingClick, routerLinkNavigation };
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { ExternalLink } from "lucide-react";
|
|
4
|
+
import { cn } from "../lib/cn.js";
|
|
5
|
+
import { DEFAULT_COMMON_LABELS, useKitLabels, useKitLink } from "../i18n/kit-labels.js";
|
|
6
|
+
function isExternalHref(href) {
|
|
7
|
+
return /^(?:[a-z][a-z\d+.-]*:|\/\/)/i.test(href);
|
|
8
|
+
}
|
|
9
|
+
function isInPageAnchor(href) {
|
|
10
|
+
return href.startsWith("#") && !href.startsWith("#/");
|
|
11
|
+
}
|
|
12
|
+
function isRoutableHref(href) {
|
|
13
|
+
return !isExternalHref(href) && !isInPageAnchor(href);
|
|
14
|
+
}
|
|
15
|
+
function pickLinkRenderer(own, kitLink, href) {
|
|
16
|
+
if (own) return own;
|
|
17
|
+
if (!kitLink || href === void 0 || !isRoutableHref(href)) return void 0;
|
|
18
|
+
return kitLink;
|
|
19
|
+
}
|
|
20
|
+
function isPlainNavigationClick(event) {
|
|
21
|
+
return !event.defaultPrevented && event.button === 0 && !event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey;
|
|
22
|
+
}
|
|
23
|
+
function replacingClick(onClick, href, replace, target) {
|
|
24
|
+
if (!replace || target !== void 0 && target !== "" && target !== "_self") return onClick;
|
|
25
|
+
return (event) => {
|
|
26
|
+
onClick?.(event);
|
|
27
|
+
if (!isPlainNavigationClick(event)) return;
|
|
28
|
+
event.preventDefault();
|
|
29
|
+
window.location.replace(href);
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function routerLinkNavigation(replace) {
|
|
33
|
+
return replace ? { replace: true } : {};
|
|
34
|
+
}
|
|
35
|
+
function RenderedKitLink({ render, props }) {
|
|
36
|
+
return render(props);
|
|
37
|
+
}
|
|
38
|
+
const TONE = {
|
|
39
|
+
brand: "text-[var(--brand)] hover:text-[var(--brand-hover)]",
|
|
40
|
+
muted: "text-[var(--text-muted)] hover:text-[var(--text-primary)]",
|
|
41
|
+
danger: "text-[var(--danger)] hover:text-[var(--danger-hover)]",
|
|
42
|
+
inherit: "",
|
|
43
|
+
primary: "text-[var(--text-primary)] hover:decoration-2",
|
|
44
|
+
secondary: "text-[var(--text-secondary)] hover:text-[var(--text-primary)]",
|
|
45
|
+
warning: "text-[var(--warning)] hover:decoration-2"
|
|
46
|
+
};
|
|
47
|
+
const UNDERLINED_BY_DEFAULT = /* @__PURE__ */ new Set(["primary", "secondary", "warning"]);
|
|
48
|
+
const UNDERLINE = {
|
|
49
|
+
hover: "no-underline hover:underline",
|
|
50
|
+
always: "underline",
|
|
51
|
+
none: "no-underline"
|
|
52
|
+
};
|
|
53
|
+
function TextLink({
|
|
54
|
+
href,
|
|
55
|
+
children,
|
|
56
|
+
tone = "brand",
|
|
57
|
+
underline: underlineProp,
|
|
58
|
+
external = false,
|
|
59
|
+
replace,
|
|
60
|
+
reloadDocument = false,
|
|
61
|
+
stopPropagation = false,
|
|
62
|
+
current,
|
|
63
|
+
icon: Icon,
|
|
64
|
+
renderLink,
|
|
65
|
+
className,
|
|
66
|
+
onClick,
|
|
67
|
+
onKeyDown,
|
|
68
|
+
ref,
|
|
69
|
+
...rest
|
|
70
|
+
}) {
|
|
71
|
+
const common = useKitLabels("common", DEFAULT_COMMON_LABELS);
|
|
72
|
+
const kitLink = useKitLink();
|
|
73
|
+
const underline = underlineProp ?? (UNDERLINED_BY_DEFAULT.has(tone) ? "always" : "hover");
|
|
74
|
+
const ariaCurrent = current === true ? "page" : current === false ? void 0 : current;
|
|
75
|
+
const look = cn(
|
|
76
|
+
"rounded-sm underline-offset-2 transition-colors",
|
|
77
|
+
"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--brand)]",
|
|
78
|
+
TONE[tone],
|
|
79
|
+
UNDERLINE[underline],
|
|
80
|
+
ariaCurrent && "font-semibold",
|
|
81
|
+
className
|
|
82
|
+
);
|
|
83
|
+
const body = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
84
|
+
Icon && /* @__PURE__ */ jsx(Icon, { "aria-hidden": true, className: "me-1 inline size-[1em] shrink-0 align-[-0.125em]" }),
|
|
85
|
+
children,
|
|
86
|
+
external && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
87
|
+
/* @__PURE__ */ jsx(ExternalLink, { "aria-hidden": true, className: "ms-1 inline size-[0.85em] align-[-0.1em] rtl:-scale-x-100" }),
|
|
88
|
+
" ",
|
|
89
|
+
/* @__PURE__ */ jsxs("span", { className: "sr-only", children: [
|
|
90
|
+
"(",
|
|
91
|
+
common.opensInNewTab,
|
|
92
|
+
")"
|
|
93
|
+
] })
|
|
94
|
+
] })
|
|
95
|
+
] });
|
|
96
|
+
const handleClick = stopPropagation ? (event) => {
|
|
97
|
+
event.stopPropagation();
|
|
98
|
+
onClick?.(event);
|
|
99
|
+
} : onClick;
|
|
100
|
+
const props = {
|
|
101
|
+
...rest,
|
|
102
|
+
ref,
|
|
103
|
+
href,
|
|
104
|
+
className: look,
|
|
105
|
+
"aria-current": ariaCurrent,
|
|
106
|
+
onClick: handleClick,
|
|
107
|
+
onKeyDown: stopPropagation ? (event) => {
|
|
108
|
+
if (event.key === "Enter") event.stopPropagation();
|
|
109
|
+
onKeyDown?.(event);
|
|
110
|
+
} : onKeyDown,
|
|
111
|
+
children: body
|
|
112
|
+
};
|
|
113
|
+
const render = external || reloadDocument ? void 0 : pickLinkRenderer(renderLink, kitLink, href);
|
|
114
|
+
if (render) return /* @__PURE__ */ jsx(RenderedTextLink, { render, ...props, ...routerLinkNavigation(replace) });
|
|
115
|
+
const plainClick = external ? handleClick : replacingClick(handleClick, href, replace, rest.target);
|
|
116
|
+
const { children: content, ...anchor } = props;
|
|
117
|
+
return /* @__PURE__ */ jsx(
|
|
118
|
+
"a",
|
|
119
|
+
{
|
|
120
|
+
...anchor,
|
|
121
|
+
href,
|
|
122
|
+
onClick: plainClick,
|
|
123
|
+
...external ? { target: "_blank", rel: "noopener noreferrer" } : null,
|
|
124
|
+
children: content
|
|
125
|
+
}
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
function RenderedTextLink({
|
|
129
|
+
render,
|
|
130
|
+
...props
|
|
131
|
+
}) {
|
|
132
|
+
return render(props);
|
|
133
|
+
}
|
|
134
|
+
export {
|
|
135
|
+
RenderedKitLink,
|
|
136
|
+
TextLink,
|
|
137
|
+
isExternalHref,
|
|
138
|
+
isInPageAnchor,
|
|
139
|
+
isRoutableHref,
|
|
140
|
+
pickLinkRenderer,
|
|
141
|
+
replacingClick,
|
|
142
|
+
routerLinkNavigation
|
|
143
|
+
};
|
|
144
|
+
//# sourceMappingURL=text-link.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/text-link.tsx"],"sourcesContent":["import type { ComponentPropsWithoutRef, KeyboardEvent, MouseEvent, ReactElement, ReactNode, Ref } from \"react\";\nimport { ExternalLink } from \"lucide-react\";\nimport type { LucideIcon } from \"lucide-react\";\nimport { cn } from \"../lib/cn\";\nimport { DEFAULT_COMMON_LABELS, useKitLabels, useKitLink } from \"../i18n/kit-labels\";\nimport type { KitLinkComponent } from \"../i18n/kit-labels\";\n\n/* ── Choosing what draws a link ──────────────────────────────────────────── */\n\n/**\n * An `href` that leaves the app: a scheme (`https:`, `mailto:`, `tel:`) or a\n * protocol-relative `//host`. A router's link is for paths inside the app, so the\n * provider's `linkComponent` is never handed one of these — they stay a plain `<a>`.\n *\n * NOT external, and so handed to the router link: a path (`/x`, `x`, `?q=1`) and the\n * hash-router form `#/x` — that IS a route in a `HashRouter` app, which maps it to\n * `to=\"/x\"`. A plain in-page anchor (`#section`) is not external either, but it is not\n * a route: see {@link isInPageAnchor}.\n */\nexport function isExternalHref(href: string): boolean {\n return /^(?:[a-z][a-z\\d+.-]*:|\\/\\/)/i.test(href);\n}\n\n/**\n * An `href` that only scrolls the current page: `#section` (or a bare `#`). The\n * hash-router form `#/x` is a ROUTE, not an anchor, and is not one of these. A router\n * link must not get an anchor — under a `HashRouter` `#section` would navigate to the\n * path `/section` — so every kit link draws it as a plain `<a>`.\n */\nexport function isInPageAnchor(href: string): boolean {\n return href.startsWith(\"#\") && !href.startsWith(\"#/\");\n}\n\n/**\n * Whether the provider's `linkComponent` (or a kit component's router fallback) draws\n * `href`: an in-app path, `#/x` included — not an external `href`\n * ({@link isExternalHref}) and not an in-page `#anchor` ({@link isInPageAnchor}).\n */\nexport function isRoutableHref(href: string): boolean {\n return !isExternalHref(href) && !isInPageAnchor(href);\n}\n\n/**\n * What draws a kit link to `href`: the component's own `renderLink` when it was given\n * one (it always wins — the caller asked for it by name), else the\n * `<UiKitProvider linkComponent>` for a routable `href` ({@link isRoutableHref}), else\n * `undefined` — a plain `<a>`. The one rule every kit link follows: `https:` /\n * `mailto:` / `//host` and `#section` stay plain anchors; `/x`, `x` and a hash-router\n * `#/x` go to the router link. Every kit link props type is a subset of the anchor\n * attributes `KitLinkProps` describes, which is what makes the cast sound.\n * @internal Shared by the kit's link-bearing components; not part of the barrel.\n */\nexport function pickLinkRenderer<P>(\n own: ((props: P) => ReactElement) | undefined,\n kitLink: KitLinkComponent | undefined,\n href: string | undefined,\n): ((props: P) => ReactElement) | undefined {\n if (own) return own;\n if (!kitLink || href === undefined || !isRoutableHref(href)) return undefined;\n return kitLink as unknown as (props: P) => ReactElement;\n}\n\n/** The plain primary click a page navigates on — not a middle click, not ⌘ / Ctrl /\n * Shift / Alt (new tab, new window, download), and not one a handler already took. */\nfunction isPlainNavigationClick(event: MouseEvent<HTMLAnchorElement>): boolean {\n return (\n !event.defaultPrevented &&\n event.button === 0 &&\n !event.metaKey &&\n !event.ctrlKey &&\n !event.shiftKey &&\n !event.altKey\n );\n}\n\n/**\n * The `onClick` of a PLAIN `<a>` whose kit link was asked to `replace` (keksdose F1).\n *\n * A router link replaces the history entry itself (it is handed `replace`, see\n * {@link routerLinkNavigation}); a plain `<a>` has no attribute that says so, and the\n * browser's own navigation always pushes. So a plain click is taken over — the caller's\n * `onClick` runs first and may still `preventDefault` — and becomes\n * `location.replace(href)`: the same document load, with Back skipping the one-shot URL.\n * That is the case of `replace` together with `reloadDocument`, or an app with no\n * `linkComponent`. A modified click (new tab) and a `target` other than `_self` are left\n * to the browser: they do not navigate THIS history. Without `replace`, `onClick` comes\n * back untouched.\n * @internal\n */\nexport function replacingClick(\n onClick: ((event: MouseEvent<HTMLAnchorElement>) => void) | undefined,\n href: string,\n replace: boolean | undefined,\n target?: string,\n): ((event: MouseEvent<HTMLAnchorElement>) => void) | undefined {\n if (!replace || (target !== undefined && target !== \"\" && target !== \"_self\")) return onClick;\n return (event) => {\n onClick?.(event);\n if (!isPlainNavigationClick(event)) return;\n event.preventDefault();\n window.location.replace(href);\n };\n}\n\n/**\n * What a ROUTER link is handed for `replace`: `{ replace: true }` when asked, else\n * nothing at all — so a provider link that spreads its props onto a DOM `<a>` never\n * receives an unknown attribute from a link that did not ask (see `KitLinkProps.replace`).\n * @internal\n */\nexport function routerLinkNavigation(replace: boolean | undefined): { replace?: true } {\n return replace ? { replace: true } : {};\n}\n\n/**\n * Draws `props` through `render` as a component of its own, so a router link's hooks\n * belong to it and not to the kit component calling it — for the kit components that\n * call their own `renderLink` inline and reach the provider's link through here.\n * @internal\n */\nexport function RenderedKitLink<P>({ render, props }: { render: (props: P) => ReactElement; props: P }) {\n return render(props);\n}\n\n/* ── TextLink ─────────────────────────────────────────────────────────────── */\n\n/**\n * `brand` (default) for a link in running text, `muted` for footer and meta links\n * that should not compete with the content, `danger` for a destructive one (\"Leave\n * group\"), `inherit` for a link that takes its surroundings' colour.\n *\n * `primary` and `secondary` are the body and the secondary text colour, UNDERLINED\n * (keksdose F3): a link that must read as part of the text around it — a name in a\n * list row, a reference in a card's meta line — where `brand` repaints it in the accent\n * and `muted` is a step too light to read as content. `secondary` darkens to the body\n * colour under the pointer, as `muted` does; `primary` has nowhere darker to go, so its\n * underline thickens instead.\n *\n * `warning` is the kit's `--warning` text colour, underlined (kastlan 46): a link inside\n * a `<Tone tone=\"warning\">` sentence or a warning banner, which `brand` would paint in a\n * second hue and `inherit` would leave indistinguishable from the sentence. Like\n * `primary`, it keeps its colour on hover and thickens the underline.\n *\n * The three colours that sit IN the text default to `underline=\"always\"`: with the\n * colour of their surroundings, the underline is the only thing that says \"link\"\n * (WCAG 1.4.1). An explicit `underline` still wins.\n */\nexport type TextLinkTone = \"brand\" | \"muted\" | \"danger\" | \"inherit\" | \"primary\" | \"secondary\" | \"warning\";\n\n/** `hover` (the default for `brand`, `muted`, `danger`, `inherit`): underlined under\n * the pointer — the idiom all three apps draw. `always` (the default for `primary`,\n * `secondary`, `warning`) for a link inside prose, where colour alone must not be the\n * only mark (WCAG 1.4.1). `none` where the context already says \"link\" (a footer nav). */\nexport type TextLinkUnderline = \"hover\" | \"always\" | \"none\";\n\n/** The `aria-current` token. `true` on {@link TextLinkProps.current} means `page`. */\nexport type TextLinkCurrent = \"page\" | \"step\" | \"location\" | \"date\" | \"time\" | \"true\";\n\n/** What {@link TextLinkProps.renderLink} (and the provider's `linkComponent`) is\n * handed. Spread it onto your router's link — `({ href, ...p }) => <Link to={href} {...p} />`. */\nexport interface TextLinkRenderProps {\n href: string;\n /** The link's look — keep it, or the tone, underline and focus ring go. */\n className: string;\n children: ReactNode;\n ref?: Ref<HTMLAnchorElement>;\n onClick?: (event: MouseEvent<HTMLAnchorElement>) => void;\n onKeyDown?: (event: KeyboardEvent<HTMLAnchorElement>) => void;\n \"aria-current\"?: TextLinkCurrent;\n id?: string;\n title?: string;\n /** Present, as `true`, only when the link was given `replace` — see\n * `KitLinkProps.replace`. Map it to your router's replace; never onto a DOM `<a>`. */\n replace?: boolean;\n [key: `aria-${string}`]: string | boolean | number | undefined;\n [key: `data-${string}`]: unknown;\n}\n\nexport interface TextLinkProps\n extends Omit<ComponentPropsWithoutRef<\"a\">, \"href\" | \"children\" | \"aria-current\" | \"onClick\" | \"onKeyDown\"> {\n href: string;\n children: ReactNode;\n /** Default `brand`. */\n tone?: TextLinkTone;\n /** Default `always` for `primary`, `secondary` and `warning`, else `hover`. */\n underline?: TextLinkUnderline;\n /**\n * Navigate by replacing the current history entry, so Back does not return to this\n * URL — keksdose F1, a one-shot URL (a confirmation landing, a `?done=1` hop). Handed\n * to the router link as `replace` (see `KitLinkProps.replace` for mapping it); on a\n * plain `<a>` (no `linkComponent`, or `reloadDocument`) a plain click becomes\n * `location.replace(href)`. Ignored on an `external` link, which opens a new tab.\n */\n replace?: boolean;\n /**\n * A plain `<a>` for an in-app `href`: the browser loads the whole document instead of\n * the router swapping the view — keksdose F1, a route served outside the SPA (a file\n * download, a server-rendered page, a logout that must drop every in-memory cache).\n * Wins over `renderLink` and the provider's `linkComponent`: it is the caller saying\n * \"not the router\" for this one link.\n */\n reloadDocument?: boolean;\n /**\n * The link leaves the app: a plain `<a target=\"_blank\" rel=\"noopener noreferrer\">`\n * (never the router's), an external-link mark after the text (mirrored in RTL), and\n * \"opens in a new tab\" (`common.opensInNewTab`) read after it — the mark says it\n * only to the eye. kastlan's BWO / BFS source links (rent-increase-calculator-page).\n */\n external?: boolean;\n /**\n * Keep the click (and the Enter that activates the link) from reaching an ancestor —\n * a link in a DataTable row with `onRowClick` goes to its own target instead of\n * running the row's action. kastlan's `CellLink` did this by hand.\n */\n stopPropagation?: boolean;\n /** Mark the link as the current one of a set — `true` is `aria-current=\"page\"`, the\n * legal footer's link to the page you are on. Drawn in semibold. */\n current?: boolean | TextLinkCurrent;\n /** A Lucide icon before the text, at the text's size — kastlan's \"← Back\" link. */\n icon?: LucideIcon;\n /** Your router's link for an in-app `href`. Default: the `<UiKitProvider\n * linkComponent>`, then a plain `<a>`. Ignored on an `external` link. */\n renderLink?: (props: TextLinkRenderProps) => ReactElement;\n onClick?: (event: MouseEvent<HTMLAnchorElement>) => void;\n onKeyDown?: (event: KeyboardEvent<HTMLAnchorElement>) => void;\n ref?: Ref<HTMLAnchorElement>;\n}\n\nconst TONE: Record<TextLinkTone, string> = {\n brand: \"text-[var(--brand)] hover:text-[var(--brand-hover)]\",\n muted: \"text-[var(--text-muted)] hover:text-[var(--text-primary)]\",\n danger: \"text-[var(--danger)] hover:text-[var(--danger-hover)]\",\n inherit: \"\",\n primary: \"text-[var(--text-primary)] hover:decoration-2\",\n secondary: \"text-[var(--text-secondary)] hover:text-[var(--text-primary)]\",\n warning: \"text-[var(--warning)] hover:decoration-2\",\n};\n\n/** The tones whose colour is their surroundings' — underlined by default; see\n * {@link TextLinkTone}. */\nconst UNDERLINED_BY_DEFAULT = new Set<TextLinkTone>([\"primary\", \"secondary\", \"warning\"]);\n\nconst UNDERLINE: Record<TextLinkUnderline, string> = {\n hover: \"no-underline hover:underline\",\n always: \"underline\",\n none: \"no-underline\",\n};\n\n/**\n * The one inline link: a real `<a href>` (middle click, \"open in new tab\", link\n * semantics) through the app's router for an in-app path, in one of four tones.\n *\n * kastlan draws this link a dozen ways by hand — `EntityLink` and `CellLink` (text-primary,\n * hover underline, one stopping the row click), the legal pages' back link and footer,\n * the feedback page's URL links, the calculator's external sources with a hand-placed\n * ↗ and no word for a screen reader — and the lease wizard's unit step (lease-unit-step)\n * used a raw `<a>` to an in-app route, which reloads the whole app. Here the router\n * link comes from `<UiKitProvider linkComponent>`, set once.\n *\n * Inline, not `inline-flex`: a link inside a sentence must wrap with it. The icons sit\n * on the text's baseline at the text's size, so they scale with whatever type the link\n * is set in. The focus ring is an outline, which follows every line of a wrapped link.\n */\nexport function TextLink({\n href,\n children,\n tone = \"brand\",\n underline: underlineProp,\n external = false,\n replace,\n reloadDocument = false,\n stopPropagation = false,\n current,\n icon: Icon,\n renderLink,\n className,\n onClick,\n onKeyDown,\n ref,\n ...rest\n}: TextLinkProps) {\n const common = useKitLabels(\"common\", DEFAULT_COMMON_LABELS);\n const kitLink = useKitLink();\n const underline = underlineProp ?? (UNDERLINED_BY_DEFAULT.has(tone) ? \"always\" : \"hover\");\n const ariaCurrent: TextLinkCurrent | undefined =\n current === true ? \"page\" : current === false ? undefined : current;\n\n const look = cn(\n \"rounded-sm underline-offset-2 transition-colors\",\n \"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--brand)]\",\n TONE[tone],\n UNDERLINE[underline],\n ariaCurrent && \"font-semibold\",\n className,\n );\n\n const body = (\n <>\n {Icon && <Icon aria-hidden className=\"me-1 inline size-[1em] shrink-0 align-[-0.125em]\" />}\n {children}\n {external && (\n <>\n <ExternalLink aria-hidden className=\"ms-1 inline size-[0.85em] align-[-0.1em] rtl:-scale-x-100\" />\n {\" \"}\n <span className=\"sr-only\">({common.opensInNewTab})</span>\n </>\n )}\n </>\n );\n\n const handleClick: TextLinkRenderProps[\"onClick\"] = stopPropagation\n ? (event) => {\n event.stopPropagation();\n onClick?.(event);\n }\n : onClick;\n const props: TextLinkRenderProps = {\n ...(rest as Partial<TextLinkRenderProps>),\n ref,\n href,\n className: look,\n \"aria-current\": ariaCurrent,\n onClick: handleClick,\n onKeyDown: stopPropagation\n ? (event) => {\n if (event.key === \"Enter\") event.stopPropagation();\n onKeyDown?.(event);\n }\n : onKeyDown,\n children: body,\n };\n\n const render = external || reloadDocument ? undefined : pickLinkRenderer(renderLink, kitLink, href);\n if (render) return <RenderedTextLink render={render} {...props} {...routerLinkNavigation(replace)} />;\n // A plain `<a>` never gets `replace` as an attribute; asked for, it takes the click.\n const plainClick = external ? handleClick : replacingClick(handleClick, href, replace, rest.target);\n const { children: content, ...anchor } = props;\n return (\n <a\n {...anchor}\n href={href}\n onClick={plainClick}\n {...(external ? { target: \"_blank\", rel: \"noopener noreferrer\" } : null)}\n >\n {content}\n </a>\n );\n}\n\n/** Calls the link renderer as a component, so a router link's hooks are its own. */\nfunction RenderedTextLink({\n render,\n ...props\n}: TextLinkRenderProps & { render: (props: TextLinkRenderProps) => ReactElement }) {\n return render(props);\n}\n"],"mappings":";AA0Se,SAGP,UAHO,KAML,YANK;AAzSf,SAAS,oBAAoB;AAE7B,SAAS,UAAU;AACnB,SAAS,uBAAuB,cAAc,kBAAkB;AAezD,SAAS,eAAe,MAAuB;AACpD,SAAO,+BAA+B,KAAK,IAAI;AACjD;AAQO,SAAS,eAAe,MAAuB;AACpD,SAAO,KAAK,WAAW,GAAG,KAAK,CAAC,KAAK,WAAW,IAAI;AACtD;AAOO,SAAS,eAAe,MAAuB;AACpD,SAAO,CAAC,eAAe,IAAI,KAAK,CAAC,eAAe,IAAI;AACtD;AAYO,SAAS,iBACd,KACA,SACA,MAC0C;AAC1C,MAAI,IAAK,QAAO;AAChB,MAAI,CAAC,WAAW,SAAS,UAAa,CAAC,eAAe,IAAI,EAAG,QAAO;AACpE,SAAO;AACT;AAIA,SAAS,uBAAuB,OAA+C;AAC7E,SACE,CAAC,MAAM,oBACP,MAAM,WAAW,KACjB,CAAC,MAAM,WACP,CAAC,MAAM,WACP,CAAC,MAAM,YACP,CAAC,MAAM;AAEX;AAgBO,SAAS,eACd,SACA,MACA,SACA,QAC8D;AAC9D,MAAI,CAAC,WAAY,WAAW,UAAa,WAAW,MAAM,WAAW,QAAU,QAAO;AACtF,SAAO,CAAC,UAAU;AAChB,cAAU,KAAK;AACf,QAAI,CAAC,uBAAuB,KAAK,EAAG;AACpC,UAAM,eAAe;AACrB,WAAO,SAAS,QAAQ,IAAI;AAAA,EAC9B;AACF;AAQO,SAAS,qBAAqB,SAAkD;AACrF,SAAO,UAAU,EAAE,SAAS,KAAK,IAAI,CAAC;AACxC;AAQO,SAAS,gBAAmB,EAAE,QAAQ,MAAM,GAAqD;AACtG,SAAO,OAAO,KAAK;AACrB;AA0GA,MAAM,OAAqC;AAAA,EACzC,OAAO;AAAA,EACP,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AAAA,EACT,WAAW;AAAA,EACX,SAAS;AACX;AAIA,MAAM,wBAAwB,oBAAI,IAAkB,CAAC,WAAW,aAAa,SAAS,CAAC;AAEvF,MAAM,YAA+C;AAAA,EACnD,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,MAAM;AACR;AAiBO,SAAS,SAAS;AAAA,EACvB;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,WAAW;AAAA,EACX,WAAW;AAAA,EACX;AAAA,EACA,iBAAiB;AAAA,EACjB,kBAAkB;AAAA,EAClB;AAAA,EACA,MAAM;AAAA,EACN;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAkB;AAChB,QAAM,SAAS,aAAa,UAAU,qBAAqB;AAC3D,QAAM,UAAU,WAAW;AAC3B,QAAM,YAAY,kBAAkB,sBAAsB,IAAI,IAAI,IAAI,WAAW;AACjF,QAAM,cACJ,YAAY,OAAO,SAAS,YAAY,QAAQ,SAAY;AAE9D,QAAM,OAAO;AAAA,IACX;AAAA,IACA;AAAA,IACA,KAAK,IAAI;AAAA,IACT,UAAU,SAAS;AAAA,IACnB,eAAe;AAAA,IACf;AAAA,EACF;AAEA,QAAM,OACJ,iCACG;AAAA,YAAQ,oBAAC,QAAK,eAAW,MAAC,WAAU,oDAAmD;AAAA,IACvF;AAAA,IACA,YACC,iCACE;AAAA,0BAAC,gBAAa,eAAW,MAAC,WAAU,6DAA4D;AAAA,MAC/F;AAAA,MACD,qBAAC,UAAK,WAAU,WAAU;AAAA;AAAA,QAAE,OAAO;AAAA,QAAc;AAAA,SAAC;AAAA,OACpD;AAAA,KAEJ;AAGF,QAAM,cAA8C,kBAChD,CAAC,UAAU;AACT,UAAM,gBAAgB;AACtB,cAAU,KAAK;AAAA,EACjB,IACA;AACJ,QAAM,QAA6B;AAAA,IACjC,GAAI;AAAA,IACJ;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX,gBAAgB;AAAA,IAChB,SAAS;AAAA,IACT,WAAW,kBACP,CAAC,UAAU;AACT,UAAI,MAAM,QAAQ,QAAS,OAAM,gBAAgB;AACjD,kBAAY,KAAK;AAAA,IACnB,IACA;AAAA,IACJ,UAAU;AAAA,EACZ;AAEA,QAAM,SAAS,YAAY,iBAAiB,SAAY,iBAAiB,YAAY,SAAS,IAAI;AAClG,MAAI,OAAQ,QAAO,oBAAC,oBAAiB,QAAiB,GAAG,OAAQ,GAAG,qBAAqB,OAAO,GAAG;AAEnG,QAAM,aAAa,WAAW,cAAc,eAAe,aAAa,MAAM,SAAS,KAAK,MAAM;AAClG,QAAM,EAAE,UAAU,SAAS,GAAG,OAAO,IAAI;AACzC,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ;AAAA,MACA,SAAS;AAAA,MACR,GAAI,WAAW,EAAE,QAAQ,UAAU,KAAK,sBAAsB,IAAI;AAAA,MAElE;AAAA;AAAA,EACH;AAEJ;AAGA,SAAS,iBAAiB;AAAA,EACxB;AAAA,EACA,GAAG;AACL,GAAmF;AACjF,SAAO,OAAO,KAAK;AACrB;","names":[]}
|
|
@@ -14,6 +14,14 @@ import { ComponentPropsWithoutRef, ReactNode } from 'react';
|
|
|
14
14
|
* (support-thread:153/223) at `text-[11px]` by hand — 10px read as a footnote under a
|
|
15
15
|
* figure that size, 12px competed with it. Named `md` rather than slotted in order
|
|
16
16
|
* because `sm` was already the default and renaming it would move every caller.
|
|
17
|
+
*
|
|
18
|
+
* `md` is also the heading over a CHART COLUMN (lenkbank P9): the small label centred
|
|
19
|
+
* over each of a pair of facing charts, or over each column of a small-multiples grid.
|
|
20
|
+
* There the label names a plot, not a section of the page, so `sm` (12px, the page's
|
|
21
|
+
* section heading) out-ranks the card title above it, and `xs` (10px, a legend's
|
|
22
|
+
* title) sinks below the axis ticks it sits beside. Rule of thumb: `xs` inside a
|
|
23
|
+
* control (legend, menu), `md` over a figure or a plot, `sm` over a block of page
|
|
24
|
+
* content.
|
|
17
25
|
*/
|
|
18
26
|
type SectionLabelSize = "xs" | "md" | "sm";
|
|
19
27
|
/**
|
|
@@ -26,6 +34,19 @@ type SectionLabelSize = "xs" | "md" | "sm";
|
|
|
26
34
|
* case.
|
|
27
35
|
*/
|
|
28
36
|
declare const SECTION_LABEL_CLASS: Record<SectionLabelSize, string>;
|
|
37
|
+
/**
|
|
38
|
+
* `plain` (default): the label alone, as above.
|
|
39
|
+
*
|
|
40
|
+
* `band` (0.13, keksdose F5): the label on a full-width `surface-2` bar with a bottom
|
|
41
|
+
* border — the day-group header of keksdose's mobile transaction list
|
|
42
|
+
* (mobile-transaction-list.tsx:171), which separates one day's rows from the next.
|
|
43
|
+
* Its type is kept as keksdose drew it — `font-medium` in the SECONDARY text colour,
|
|
44
|
+
* not the plain label's semibold muted — so adopting the kit does not restyle a live
|
|
45
|
+
* list: the bar already sets the label apart, and needs no extra weight. The padding (`px-4 py-2`) lines the text up with a
|
|
46
|
+
* `ListItem density="comfortable"` row below it; override it with `className` for a
|
|
47
|
+
* list at another density. A sticky header is the caller's: add `sticky top-0`.
|
|
48
|
+
*/
|
|
49
|
+
type SectionLabelVariant = "plain" | "band";
|
|
29
50
|
type SectionLabelElement = "h2" | "h3" | "h4" | "h5" | "h6" | "p" | "span" | "div" | "legend";
|
|
30
51
|
interface SectionLabelProps extends ComponentPropsWithoutRef<"h3"> {
|
|
31
52
|
/**
|
|
@@ -36,6 +57,9 @@ interface SectionLabelProps extends ComponentPropsWithoutRef<"h3"> {
|
|
|
36
57
|
*/
|
|
37
58
|
as?: SectionLabelElement;
|
|
38
59
|
size?: SectionLabelSize;
|
|
60
|
+
/** `band` draws the label on a `surface-2` bar with a bottom border — a list's group
|
|
61
|
+
* header. See {@link SectionLabelVariant}. */
|
|
62
|
+
variant?: SectionLabelVariant;
|
|
39
63
|
children: ReactNode;
|
|
40
64
|
}
|
|
41
65
|
/**
|
|
@@ -45,7 +69,7 @@ interface SectionLabelProps extends ComponentPropsWithoutRef<"h3"> {
|
|
|
45
69
|
* 10px version on a menu row. One component, the token colour, and the level chosen
|
|
46
70
|
* where the outline is known.
|
|
47
71
|
*/
|
|
48
|
-
declare function SectionLabel({ as, size, className, children, ...rest }: SectionLabelProps): react.JSX.Element;
|
|
72
|
+
declare function SectionLabel({ as, size, variant, className, children, ...rest }: SectionLabelProps): react.JSX.Element;
|
|
49
73
|
/**
|
|
50
74
|
* The caption type as a class string: 11px, snug, muted. lenkbank's `CAPTION`
|
|
51
75
|
* (shared/ui/caption.ts:23) — written out 31 times before it was a constant — as a
|
|
@@ -67,4 +91,4 @@ interface CaptionProps extends ComponentPropsWithoutRef<"p"> {
|
|
|
67
91
|
*/
|
|
68
92
|
declare function Caption({ as, className, children, ...rest }: CaptionProps): react.JSX.Element;
|
|
69
93
|
|
|
70
|
-
export { CAPTION_CLASS, Caption, type CaptionProps, SECTION_LABEL_CLASS, SectionLabel, type SectionLabelProps, type SectionLabelSize };
|
|
94
|
+
export { CAPTION_CLASS, Caption, type CaptionProps, SECTION_LABEL_CLASS, SectionLabel, type SectionLabelProps, type SectionLabelSize, type SectionLabelVariant };
|
package/dist/components/text.js
CHANGED
|
@@ -6,9 +6,23 @@ const SECTION_LABEL_CLASS = {
|
|
|
6
6
|
md: "text-[11px] font-semibold uppercase tracking-wide text-[var(--text-muted)]",
|
|
7
7
|
sm: "text-xs font-semibold uppercase tracking-wide text-[var(--text-muted)]"
|
|
8
8
|
};
|
|
9
|
-
|
|
9
|
+
const SECTION_LABEL_BAND_CLASS = {
|
|
10
|
+
xs: "text-[10px]",
|
|
11
|
+
md: "text-[11px]",
|
|
12
|
+
sm: "text-xs"
|
|
13
|
+
};
|
|
14
|
+
const BAND = "block border-b border-[var(--border)] bg-[var(--bg-surface-2)] px-4 py-2 font-medium uppercase tracking-wide text-[var(--text-secondary)]";
|
|
15
|
+
function SectionLabel({
|
|
16
|
+
as = "h3",
|
|
17
|
+
size = "sm",
|
|
18
|
+
variant = "plain",
|
|
19
|
+
className,
|
|
20
|
+
children,
|
|
21
|
+
...rest
|
|
22
|
+
}) {
|
|
10
23
|
const Tag = as;
|
|
11
|
-
|
|
24
|
+
const type = variant === "band" ? cn(SECTION_LABEL_BAND_CLASS[size], BAND) : SECTION_LABEL_CLASS[size];
|
|
25
|
+
return /* @__PURE__ */ jsx(Tag, { ...rest, className: cn(type, className), children });
|
|
12
26
|
}
|
|
13
27
|
const CAPTION_CLASS = "text-[11px] leading-snug text-[var(--text-muted)]";
|
|
14
28
|
function Caption({ as = "p", className, children, ...rest }) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/text.tsx"],"sourcesContent":["import type { ComponentPropsWithoutRef, ElementType, ReactNode } from \"react\";\nimport { cn } from \"../lib/cn\";\n\n/* ── SectionLabel ─────────────────────────────────────────────────────────── */\n\n/**\n * `xs` is 10px — the size `LegendGroup`'s title and the top-bar menus' heading row draw;\n * `sm` (default) is 12px — the size `StatTile`'s label and lenkbank's section headings\n * (control-page.tsx:119/123/127) draw. Two sizes because the label sits either inside a\n * dense panel (a legend, a menu) or above a block of page content, and one size looked\n * wrong in the other place.\n *\n * `md` (0.11.0) is 11px, the rung between them: keksdose's budget-summary card labels\n * its figures (\"Assigned\", \"Activity\", \"Upcoming\", \"Available\" —\n * budget-summary-card:258/264/286/297) and its support thread its day divider and a message's meta line\n * (support-thread:153/223) at `text-[11px]` by hand — 10px read as a footnote under a\n * figure that size, 12px competed with it. Named `md` rather than slotted in order\n * because `sm` was already the default and renaming it would move every caller.\n */\nexport type SectionLabelSize = \"xs\" | \"md\" | \"sm\";\n\n/**\n * The small, uppercase, tracked, muted label — as a class string, per size.\n *\n * Exported because `LegendGroup` and `StatTile` already draw it inline, and a class a\n * caller has to position itself (a `<th>`, a `<legend>`, a menu `<li>`) is better\n * reached as a string than wrapped in a component that only takes a `className`. The\n * uppercase is CSS, so a screen reader reads the text as written: write it in normal\n * case.\n */\nexport const SECTION_LABEL_CLASS: Record<SectionLabelSize, string> = {\n xs: \"text-[10px] font-semibold uppercase tracking-wide text-[var(--text-muted)]\",\n md: \"text-[11px] font-semibold uppercase tracking-wide text-[var(--text-muted)]\",\n sm: \"text-xs font-semibold uppercase tracking-wide text-[var(--text-muted)]\",\n};\n\ntype SectionLabelElement = \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | \"span\" | \"div\" | \"legend\";\n\nexport interface SectionLabelProps extends ComponentPropsWithoutRef<\"h3\"> {\n /**\n * The element — which is the heading LEVEL, and so is the caller's to pick: the kit\n * cannot know where in the outline the label sits. Default `h3`, which is what\n * lenkbank's control page writes under its `h2` card title. Pass `span` or `p` for a\n * label that is not a heading at all (a legend group's title).\n */\n as?: SectionLabelElement;\n size?: SectionLabelSize;\n children: ReactNode;\n}\n\n/**\n * A section's small uppercase label. lenkbank spells\n * `text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400`\n * on every `<h3>` of its control page and more; keksdose's budget switcher writes the\n * 10px version on a menu row. One component, the token colour, and the level chosen\n * where the outline is known.\n */\nexport function SectionLabel({
|
|
1
|
+
{"version":3,"sources":["../../src/components/text.tsx"],"sourcesContent":["import type { ComponentPropsWithoutRef, ElementType, ReactNode } from \"react\";\nimport { cn } from \"../lib/cn\";\n\n/* ── SectionLabel ─────────────────────────────────────────────────────────── */\n\n/**\n * `xs` is 10px — the size `LegendGroup`'s title and the top-bar menus' heading row draw;\n * `sm` (default) is 12px — the size `StatTile`'s label and lenkbank's section headings\n * (control-page.tsx:119/123/127) draw. Two sizes because the label sits either inside a\n * dense panel (a legend, a menu) or above a block of page content, and one size looked\n * wrong in the other place.\n *\n * `md` (0.11.0) is 11px, the rung between them: keksdose's budget-summary card labels\n * its figures (\"Assigned\", \"Activity\", \"Upcoming\", \"Available\" —\n * budget-summary-card:258/264/286/297) and its support thread its day divider and a message's meta line\n * (support-thread:153/223) at `text-[11px]` by hand — 10px read as a footnote under a\n * figure that size, 12px competed with it. Named `md` rather than slotted in order\n * because `sm` was already the default and renaming it would move every caller.\n *\n * `md` is also the heading over a CHART COLUMN (lenkbank P9): the small label centred\n * over each of a pair of facing charts, or over each column of a small-multiples grid.\n * There the label names a plot, not a section of the page, so `sm` (12px, the page's\n * section heading) out-ranks the card title above it, and `xs` (10px, a legend's\n * title) sinks below the axis ticks it sits beside. Rule of thumb: `xs` inside a\n * control (legend, menu), `md` over a figure or a plot, `sm` over a block of page\n * content.\n */\nexport type SectionLabelSize = \"xs\" | \"md\" | \"sm\";\n\n/**\n * The small, uppercase, tracked, muted label — as a class string, per size.\n *\n * Exported because `LegendGroup` and `StatTile` already draw it inline, and a class a\n * caller has to position itself (a `<th>`, a `<legend>`, a menu `<li>`) is better\n * reached as a string than wrapped in a component that only takes a `className`. The\n * uppercase is CSS, so a screen reader reads the text as written: write it in normal\n * case.\n */\nexport const SECTION_LABEL_CLASS: Record<SectionLabelSize, string> = {\n xs: \"text-[10px] font-semibold uppercase tracking-wide text-[var(--text-muted)]\",\n md: \"text-[11px] font-semibold uppercase tracking-wide text-[var(--text-muted)]\",\n sm: \"text-xs font-semibold uppercase tracking-wide text-[var(--text-muted)]\",\n};\n\n/**\n * `plain` (default): the label alone, as above.\n *\n * `band` (0.13, keksdose F5): the label on a full-width `surface-2` bar with a bottom\n * border — the day-group header of keksdose's mobile transaction list\n * (mobile-transaction-list.tsx:171), which separates one day's rows from the next.\n * Its type is kept as keksdose drew it — `font-medium` in the SECONDARY text colour,\n * not the plain label's semibold muted — so adopting the kit does not restyle a live\n * list: the bar already sets the label apart, and needs no extra weight. The padding (`px-4 py-2`) lines the text up with a\n * `ListItem density=\"comfortable\"` row below it; override it with `className` for a\n * list at another density. A sticky header is the caller's: add `sticky top-0`.\n */\nexport type SectionLabelVariant = \"plain\" | \"band\";\n\n/** The band's own type and box, per size — spelled out rather than merged over\n * {@link SECTION_LABEL_CLASS}, so the result does not hang on tailwind-merge telling\n * a font-size `text-[…]` from a colour `text-[var(…)]`. */\nconst SECTION_LABEL_BAND_CLASS: Record<SectionLabelSize, string> = {\n xs: \"text-[10px]\",\n md: \"text-[11px]\",\n sm: \"text-xs\",\n};\nconst BAND =\n \"block border-b border-[var(--border)] bg-[var(--bg-surface-2)] px-4 py-2 font-medium uppercase tracking-wide text-[var(--text-secondary)]\";\n\ntype SectionLabelElement = \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | \"span\" | \"div\" | \"legend\";\n\nexport interface SectionLabelProps extends ComponentPropsWithoutRef<\"h3\"> {\n /**\n * The element — which is the heading LEVEL, and so is the caller's to pick: the kit\n * cannot know where in the outline the label sits. Default `h3`, which is what\n * lenkbank's control page writes under its `h2` card title. Pass `span` or `p` for a\n * label that is not a heading at all (a legend group's title).\n */\n as?: SectionLabelElement;\n size?: SectionLabelSize;\n /** `band` draws the label on a `surface-2` bar with a bottom border — a list's group\n * header. See {@link SectionLabelVariant}. */\n variant?: SectionLabelVariant;\n children: ReactNode;\n}\n\n/**\n * A section's small uppercase label. lenkbank spells\n * `text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400`\n * on every `<h3>` of its control page and more; keksdose's budget switcher writes the\n * 10px version on a menu row. One component, the token colour, and the level chosen\n * where the outline is known.\n */\nexport function SectionLabel({\n as = \"h3\",\n size = \"sm\",\n variant = \"plain\",\n className,\n children,\n ...rest\n}: SectionLabelProps) {\n const Tag = as as ElementType;\n const type = variant === \"band\" ? cn(SECTION_LABEL_BAND_CLASS[size], BAND) : SECTION_LABEL_CLASS[size];\n return (\n <Tag {...rest} className={cn(type, className)}>\n {children}\n </Tag>\n );\n}\n\n/* ── Caption ──────────────────────────────────────────────────────────────── */\n\n/**\n * The caption type as a class string: 11px, snug, muted. lenkbank's `CAPTION`\n * (shared/ui/caption.ts:23) — written out 31 times before it was a constant — as a\n * token colour rather than `slate-500 dark:slate-400`, so it follows the palette.\n * Exported for the same reason lenkbank's is a string: every caller positions it\n * differently (`mt-1`, `self-end pb-2`, `border-t`), and what must be one thing is the\n * type, not the box.\n */\nexport const CAPTION_CLASS = \"text-[11px] leading-snug text-[var(--text-muted)]\";\n\nexport interface CaptionProps extends ComponentPropsWithoutRef<\"p\"> {\n /** Default `p`; `span` for a caption inside a line of other content. */\n as?: \"p\" | \"span\" | \"div\";\n children: ReactNode;\n}\n\n/**\n * The small grey sentence under a field, a table or a button — prose ABOUT the thing\n * above it. Not `FieldHint`, which hides behind a field label's \"?\" so a paragraph does\n * not make one field taller than its neighbour (lenkbank feedback #27).\n */\nexport function Caption({ as = \"p\", className, children, ...rest }: CaptionProps) {\n const Tag = as as ElementType;\n return (\n <Tag {...rest} className={cn(CAPTION_CLASS, className)}>\n {children}\n </Tag>\n );\n}\n"],"mappings":";AAwGI;AAvGJ,SAAS,UAAU;AAqCZ,MAAM,sBAAwD;AAAA,EACnE,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAmBA,MAAM,2BAA6D;AAAA,EACjE,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AACA,MAAM,OACJ;AA0BK,SAAS,aAAa;AAAA,EAC3B,KAAK;AAAA,EACL,OAAO;AAAA,EACP,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAsB;AACpB,QAAM,MAAM;AACZ,QAAM,OAAO,YAAY,SAAS,GAAG,yBAAyB,IAAI,GAAG,IAAI,IAAI,oBAAoB,IAAI;AACrG,SACE,oBAAC,OAAK,GAAG,MAAM,WAAW,GAAG,MAAM,SAAS,GACzC,UACH;AAEJ;AAYO,MAAM,gBAAgB;AAatB,SAAS,QAAQ,EAAE,KAAK,KAAK,WAAW,UAAU,GAAG,KAAK,GAAiB;AAChF,QAAM,MAAM;AACZ,SACE,oBAAC,OAAK,GAAG,MAAM,WAAW,GAAG,eAAe,SAAS,GAClD,UACH;AAEJ;","names":[]}
|
|
@@ -1,8 +1,56 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { InputProps } from '
|
|
2
|
+
import { ay as InputProps } from '../kit-labels-Mz8zZHIF.js';
|
|
3
|
+
import './data-table-labels.js';
|
|
4
|
+
import './mini-calendar.js';
|
|
5
|
+
import './calendar-heatmap.js';
|
|
6
|
+
import './popover.js';
|
|
7
|
+
import './chip.js';
|
|
8
|
+
import 'lucide-react';
|
|
9
|
+
import './field-sync.js';
|
|
3
10
|
import './tooltip.js';
|
|
4
11
|
import '../hooks/use-anchored-rect.js';
|
|
5
12
|
import '../lib/clipping.js';
|
|
13
|
+
import '../wizard/types.js';
|
|
14
|
+
import '../tour/tour.js';
|
|
15
|
+
import '../search/command-palette.js';
|
|
16
|
+
import '../search/global-search.js';
|
|
17
|
+
import '../search/search-index.js';
|
|
18
|
+
import './month-picker.js';
|
|
19
|
+
import './page-contents.js';
|
|
20
|
+
import './series-chart-labels.js';
|
|
21
|
+
import './pie-chart-labels.js';
|
|
22
|
+
import './sparkline.js';
|
|
23
|
+
import './stat-tile.js';
|
|
24
|
+
import './signature-pad.js';
|
|
25
|
+
import './password-strength.js';
|
|
26
|
+
import './danger-confirm.js';
|
|
27
|
+
import './swatch-picker.js';
|
|
28
|
+
import './tile-radio.js';
|
|
29
|
+
import './icon-picker.js';
|
|
30
|
+
import './dialog-frame.js';
|
|
31
|
+
import './modal.js';
|
|
32
|
+
import '../hooks/use-search-param-state.js';
|
|
33
|
+
import './measured-grid.js';
|
|
34
|
+
import '../feedback/feedback-attachment.js';
|
|
35
|
+
import '../feedback/feedback-dialog.js';
|
|
36
|
+
import '../feedback/feedback-thread.js';
|
|
37
|
+
import '../feedback/feedback-inbox.js';
|
|
38
|
+
import './account-settings-labels.js';
|
|
39
|
+
import './confirm-dialog.js';
|
|
40
|
+
import './floating-panel.js';
|
|
41
|
+
import './bulk-action-bar.js';
|
|
42
|
+
import './list.js';
|
|
43
|
+
import './breadcrumbs.js';
|
|
44
|
+
import './toast.js';
|
|
45
|
+
import './description-list.js';
|
|
46
|
+
import './line-items.js';
|
|
47
|
+
import './progress-bar.js';
|
|
48
|
+
import './signed-amount.js';
|
|
49
|
+
import './error-boundary.js';
|
|
50
|
+
import './authed-image.js';
|
|
51
|
+
import '../hooks/use-authed-src.js';
|
|
52
|
+
import './image-grid.js';
|
|
53
|
+
import './lightbox.js';
|
|
6
54
|
|
|
7
55
|
/**
|
|
8
56
|
* A time of day, as a `"HH:mm"` string (`"HH:mm:ss"` once `step` asks for seconds).
|