@eifi1/ui-kit 0.4.0 → 0.5.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/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 +128 -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 +91 -20
- 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 +107 -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 +232 -94
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/dropdown.d.ts +96 -20
- package/dist/components/dropdown.js +77 -33
- 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 +38 -6
- package/dist/components/file-dropzone.js +34 -9
- 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 +342 -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 +28 -2
- package/dist/components/number-input.js +12 -2
- package/dist/components/number-input.js.map +1 -1
- package/dist/components/numpad-sheet.d.ts +32 -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 +52 -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/ui.d.ts +159 -46
- package/dist/components/ui.js +220 -115
- 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 +15 -4
- package/dist/components/user-avatar.js +5 -4
- 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 +27 -5
- package/dist/theme/palette-presets.js +231 -33
- 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 +67 -14
- 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 +570 -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 +269 -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 +631 -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 +549 -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 +195 -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/ui.tsx +1284 -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,51 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { InputHTMLAttributes, ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface CheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "type"> {
|
|
5
|
+
/**
|
|
6
|
+
* The words beside the box. Rendered as a `<label for>` rather than a label that
|
|
7
|
+
* wraps the input, so `description` and `error` can sit under it without becoming
|
|
8
|
+
* part of the accessible NAME — a wrapping label would have the screen reader read
|
|
9
|
+
* the whole paragraph as the checkbox's name.
|
|
10
|
+
*/
|
|
11
|
+
label?: ReactNode;
|
|
12
|
+
/** Secondary text under the label ("Used when no account is chosen"). Pointed at by
|
|
13
|
+
* `aria-describedby`, merged with any the caller passed. Kastlan's
|
|
14
|
+
* `CheckboxField` `description` variant. */
|
|
15
|
+
description?: ReactNode;
|
|
16
|
+
/**
|
|
17
|
+
* "Some but not all" — the header box of a list whose rows are partly selected.
|
|
18
|
+
* A DOM property with no HTML attribute, so it is set on the element after every
|
|
19
|
+
* render; it does not touch `checked`, and a click clears it (the browser's rule,
|
|
20
|
+
* and the caller's `onChange` decides what the click means).
|
|
21
|
+
*/
|
|
22
|
+
indeterminate?: boolean;
|
|
23
|
+
/** See {@link Input}'s `invalid`: paints the box and sets `aria-invalid` together,
|
|
24
|
+
* so the two cannot be spelled separately. */
|
|
25
|
+
invalid?: boolean;
|
|
26
|
+
/** What is wrong, in the caller's words ("Accept the terms to continue"). Rendered
|
|
27
|
+
* under the label, attached with `aria-describedby`, and implies `invalid`. */
|
|
28
|
+
error?: ReactNode;
|
|
29
|
+
/** The checked state as a boolean — the `(next) => …` shape Lenkbank's
|
|
30
|
+
* `CheckboxField` and Radix's `onCheckedChange` both used, so a migration does not
|
|
31
|
+
* have to unwrap `event.target.checked` at every call site. Fires alongside
|
|
32
|
+
* `onChange`, never instead of it. */
|
|
33
|
+
onCheckedChange?: (checked: boolean) => void;
|
|
34
|
+
/** Classes for the `<input>` itself. `className` styles the OUTERMOST element —
|
|
35
|
+
* the row when there is a label, the box's own wrapper when there is not — which
|
|
36
|
+
* is where layout (`self-end pb-2` to sit on a field's baseline) belongs. */
|
|
37
|
+
inputClassName?: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* A native checkbox in the kit's tokens, with an optional label, description and
|
|
41
|
+
* error.
|
|
42
|
+
*
|
|
43
|
+
* Without `label`, `description` or `error` it renders the box and nothing else, so
|
|
44
|
+
* it drops into a table cell or a caller's own `<label>` exactly as the raw input
|
|
45
|
+
* did — give it an `aria-label` there. Every other prop reaches the `<input>`
|
|
46
|
+
* (`checked`, `defaultChecked`, `name`, `required`, `data-*`, `aria-*`), so it works
|
|
47
|
+
* controlled, uncontrolled, and inside a plain `<form>`.
|
|
48
|
+
*/
|
|
49
|
+
declare const Checkbox: react.ForwardRefExoticComponent<CheckboxProps & react.RefAttributes<HTMLInputElement>>;
|
|
50
|
+
|
|
51
|
+
export { Checkbox, type CheckboxProps };
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { forwardRef, useCallback, useEffect, useId, useRef } from "react";
|
|
4
|
+
import { Check, Minus } from "lucide-react";
|
|
5
|
+
import { cn } from "../lib/cn.js";
|
|
6
|
+
import { assignRef, hasMessage, mergeDescribedBy } from "./choice-parts.js";
|
|
7
|
+
const BOX = "peer size-4 shrink-0 cursor-pointer appearance-none rounded-[4px] border border-[var(--border-strong)] bg-[var(--bg-surface)] shadow-sm transition-colors checked:border-[var(--brand)] checked:bg-[var(--brand)] focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--brand)] focus-visible:ring-offset-1 focus-visible:ring-offset-[var(--bg-surface)] disabled:cursor-not-allowed";
|
|
8
|
+
const BOX_MIXED = "border-[var(--brand)] bg-[var(--brand)]";
|
|
9
|
+
const BOX_INVALID = "border-[var(--danger-border)] ring-1 ring-[var(--danger-border)] checked:border-[var(--danger-border)] focus-visible:ring-[var(--danger)]";
|
|
10
|
+
const ERROR_CLASS = "mt-1 text-[11px] leading-tight text-[var(--danger)]";
|
|
11
|
+
const Checkbox = forwardRef(function Checkbox2({
|
|
12
|
+
label,
|
|
13
|
+
description,
|
|
14
|
+
indeterminate = false,
|
|
15
|
+
invalid,
|
|
16
|
+
error,
|
|
17
|
+
onCheckedChange,
|
|
18
|
+
onChange,
|
|
19
|
+
className,
|
|
20
|
+
inputClassName,
|
|
21
|
+
id,
|
|
22
|
+
disabled,
|
|
23
|
+
...rest
|
|
24
|
+
}, ref) {
|
|
25
|
+
const generated = useId();
|
|
26
|
+
const inputId = id ?? generated;
|
|
27
|
+
const descriptionId = `${inputId}-description`;
|
|
28
|
+
const errorId = `${inputId}-error`;
|
|
29
|
+
const showError = hasMessage(error);
|
|
30
|
+
const showDescription = hasMessage(description);
|
|
31
|
+
const isInvalid = Boolean(invalid) || showError;
|
|
32
|
+
const bare = label === void 0 && !showDescription && !showError;
|
|
33
|
+
const local = useRef(null);
|
|
34
|
+
const setRef = useCallback(
|
|
35
|
+
(node) => {
|
|
36
|
+
local.current = node;
|
|
37
|
+
assignRef(ref, node);
|
|
38
|
+
},
|
|
39
|
+
[ref]
|
|
40
|
+
);
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
if (local.current) local.current.indeterminate = indeterminate;
|
|
43
|
+
});
|
|
44
|
+
const box = /* @__PURE__ */ jsxs("span", { className: cn("relative inline-flex shrink-0", bare && className), children: [
|
|
45
|
+
/* @__PURE__ */ jsx(
|
|
46
|
+
"input",
|
|
47
|
+
{
|
|
48
|
+
ref: setRef,
|
|
49
|
+
id: bare ? id : inputId,
|
|
50
|
+
disabled,
|
|
51
|
+
...rest,
|
|
52
|
+
type: "checkbox",
|
|
53
|
+
"aria-invalid": isInvalid || rest["aria-invalid"] || void 0,
|
|
54
|
+
"aria-describedby": mergeDescribedBy(
|
|
55
|
+
rest["aria-describedby"],
|
|
56
|
+
showDescription && descriptionId,
|
|
57
|
+
showError && errorId
|
|
58
|
+
),
|
|
59
|
+
onChange: (e) => {
|
|
60
|
+
onChange?.(e);
|
|
61
|
+
onCheckedChange?.(e.target.checked);
|
|
62
|
+
},
|
|
63
|
+
className: cn(BOX, indeterminate && BOX_MIXED, isInvalid && BOX_INVALID, inputClassName)
|
|
64
|
+
}
|
|
65
|
+
),
|
|
66
|
+
indeterminate ? /* @__PURE__ */ jsx(
|
|
67
|
+
Minus,
|
|
68
|
+
{
|
|
69
|
+
"aria-hidden": true,
|
|
70
|
+
strokeWidth: 3,
|
|
71
|
+
className: "pointer-events-none absolute inset-0 m-auto size-3 text-[var(--brand-contrast)]"
|
|
72
|
+
}
|
|
73
|
+
) : /* @__PURE__ */ jsx(
|
|
74
|
+
Check,
|
|
75
|
+
{
|
|
76
|
+
"aria-hidden": true,
|
|
77
|
+
strokeWidth: 3,
|
|
78
|
+
className: "pointer-events-none invisible absolute inset-0 m-auto size-3 text-[var(--brand-contrast)] peer-checked:visible"
|
|
79
|
+
}
|
|
80
|
+
)
|
|
81
|
+
] });
|
|
82
|
+
if (bare) return box;
|
|
83
|
+
return /* @__PURE__ */ jsxs(
|
|
84
|
+
"div",
|
|
85
|
+
{
|
|
86
|
+
className: cn(
|
|
87
|
+
// `items-start` + a 20px cell for the box: the box centres on the label's FIRST
|
|
88
|
+
// line (text-sm is 20px tall), so a label that wraps keeps the box at the top
|
|
89
|
+
// rather than floating to the middle of a paragraph.
|
|
90
|
+
"flex items-start gap-2",
|
|
91
|
+
// The whole row fades, the way ToggleGroup and the fields do, so the label does
|
|
92
|
+
// not stay at full strength beside a box you cannot change.
|
|
93
|
+
disabled && "opacity-60",
|
|
94
|
+
className
|
|
95
|
+
),
|
|
96
|
+
children: [
|
|
97
|
+
/* @__PURE__ */ jsx("span", { className: "flex h-5 shrink-0 items-center", children: box }),
|
|
98
|
+
/* @__PURE__ */ jsxs("span", { className: "min-w-0", children: [
|
|
99
|
+
label !== void 0 && /* @__PURE__ */ jsx(
|
|
100
|
+
"label",
|
|
101
|
+
{
|
|
102
|
+
htmlFor: inputId,
|
|
103
|
+
className: cn(
|
|
104
|
+
"block text-sm leading-5 text-[var(--text-primary)]",
|
|
105
|
+
// `select-none`: a double-click to toggle twice would otherwise select the
|
|
106
|
+
// words, and a drag that starts on them starts a native text drag.
|
|
107
|
+
disabled ? "cursor-not-allowed" : "cursor-pointer select-none"
|
|
108
|
+
),
|
|
109
|
+
children: label
|
|
110
|
+
}
|
|
111
|
+
),
|
|
112
|
+
showDescription && /* @__PURE__ */ jsx("span", { id: descriptionId, className: "mt-0.5 block text-xs text-[var(--text-muted)]", children: description }),
|
|
113
|
+
showError && /* @__PURE__ */ jsx("span", { id: errorId, className: cn("block", ERROR_CLASS), children: error })
|
|
114
|
+
] })
|
|
115
|
+
]
|
|
116
|
+
}
|
|
117
|
+
);
|
|
118
|
+
});
|
|
119
|
+
Checkbox.displayName = "Checkbox";
|
|
120
|
+
export {
|
|
121
|
+
Checkbox
|
|
122
|
+
};
|
|
123
|
+
//# sourceMappingURL=checkbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/checkbox.tsx"],"sourcesContent":["import { forwardRef, useCallback, useEffect, useId, useRef } from \"react\";\nimport { Check, Minus } from \"lucide-react\";\nimport type { ChangeEvent, InputHTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { assignRef, hasMessage, mergeDescribedBy } from \"./choice-parts\";\n\n/**\n * A checkbox that is still `<input type=\"checkbox\">`.\n *\n * The three consuming apps had three answers: ~30 raw inputs in Keksdose leaning on\n * `tokens.css`'s `accent-color`, a label-plus-box `CheckboxField` in Lenkbank, and a\n * Radix `<button role=\"checkbox\">` in Kastlan. The native element is the one that\n * needs no ARIA to be a checkbox — it submits with its form, answers to `required`,\n * resets with the form and takes a `<label for>` click — so it stays underneath, and\n * only its paint is replaced (`appearance-none`, a token-coloured box, and a glyph\n * laid over it that ignores the pointer so the click still lands on the input).\n *\n * `accent-color` alone was not enough: it tints the native box but cannot change its\n * border, so an INVALID checkbox had no way to say so, and the unchecked box kept the\n * browser's own grey outline in both themes.\n */\n\n// The box. 16px, like every raw checkbox it replaces, so a migration moves nothing.\n//\n// `focus-visible`, with an offset in the surface colour: a --brand ring touching a\n// --brand-filled (checked) box would be a ring painted in the colour it sits on —\n// present in the DOM and invisible on screen. The offset is what separates the two.\nconst BOX =\n \"peer size-4 shrink-0 cursor-pointer appearance-none rounded-[4px] border border-[var(--border-strong)] bg-[var(--bg-surface)] shadow-sm transition-colors \" +\n \"checked:border-[var(--brand)] checked:bg-[var(--brand)] \" +\n \"focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--brand)] focus-visible:ring-offset-1 focus-visible:ring-offset-[var(--bg-surface)] \" +\n \"disabled:cursor-not-allowed\";\n\n// A mixed box wears the checked fill whether or not the underlying input is checked:\n// `indeterminate` is a property the browser keeps separately from `checked`, and the\n// dash means \"some\", which is neither answer.\nconst BOX_MIXED = \"border-[var(--brand)] bg-[var(--brand)]\";\n\n// The same geometry as FIELD_INVALID — a border plus a 1px ring, so the highlight\n// survives fractional display scaling on every edge (see the note in ui.tsx). The\n// focus ring turns danger too, so focusing a wrong box does not repaint it as fine.\nconst BOX_INVALID =\n \"border-[var(--danger-border)] ring-1 ring-[var(--danger-border)] checked:border-[var(--danger-border)] focus-visible:ring-[var(--danger)]\";\n\nconst ERROR_CLASS = \"mt-1 text-[11px] leading-tight text-[var(--danger)]\";\n\nexport interface CheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, \"type\"> {\n /**\n * The words beside the box. Rendered as a `<label for>` rather than a label that\n * wraps the input, so `description` and `error` can sit under it without becoming\n * part of the accessible NAME — a wrapping label would have the screen reader read\n * the whole paragraph as the checkbox's name.\n */\n label?: ReactNode;\n /** Secondary text under the label (\"Used when no account is chosen\"). Pointed at by\n * `aria-describedby`, merged with any the caller passed. Kastlan's\n * `CheckboxField` `description` variant. */\n description?: ReactNode;\n /**\n * \"Some but not all\" — the header box of a list whose rows are partly selected.\n * A DOM property with no HTML attribute, so it is set on the element after every\n * render; it does not touch `checked`, and a click clears it (the browser's rule,\n * and the caller's `onChange` decides what the click means).\n */\n indeterminate?: boolean;\n /** See {@link Input}'s `invalid`: paints the box and sets `aria-invalid` together,\n * so the two cannot be spelled separately. */\n invalid?: boolean;\n /** What is wrong, in the caller's words (\"Accept the terms to continue\"). Rendered\n * under the label, attached with `aria-describedby`, and implies `invalid`. */\n error?: ReactNode;\n /** The checked state as a boolean — the `(next) => …` shape Lenkbank's\n * `CheckboxField` and Radix's `onCheckedChange` both used, so a migration does not\n * have to unwrap `event.target.checked` at every call site. Fires alongside\n * `onChange`, never instead of it. */\n onCheckedChange?: (checked: boolean) => void;\n /** Classes for the `<input>` itself. `className` styles the OUTERMOST element —\n * the row when there is a label, the box's own wrapper when there is not — which\n * is where layout (`self-end pb-2` to sit on a field's baseline) belongs. */\n inputClassName?: string;\n}\n\n/**\n * A native checkbox in the kit's tokens, with an optional label, description and\n * error.\n *\n * Without `label`, `description` or `error` it renders the box and nothing else, so\n * it drops into a table cell or a caller's own `<label>` exactly as the raw input\n * did — give it an `aria-label` there. Every other prop reaches the `<input>`\n * (`checked`, `defaultChecked`, `name`, `required`, `data-*`, `aria-*`), so it works\n * controlled, uncontrolled, and inside a plain `<form>`.\n */\nexport const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(function Checkbox(\n {\n label,\n description,\n indeterminate = false,\n invalid,\n error,\n onCheckedChange,\n onChange,\n className,\n inputClassName,\n id,\n disabled,\n ...rest\n },\n ref,\n) {\n const generated = useId();\n const inputId = id ?? generated;\n const descriptionId = `${inputId}-description`;\n const errorId = `${inputId}-error`;\n const showError = hasMessage(error);\n const showDescription = hasMessage(description);\n const isInvalid = Boolean(invalid) || showError;\n // Nothing to lay out beside the box: render the box alone, as the raw input was.\n const bare = label === undefined && !showDescription && !showError;\n\n const local = useRef<HTMLInputElement | null>(null);\n const setRef = useCallback(\n (node: HTMLInputElement | null) => {\n local.current = node;\n assignRef(ref, node);\n },\n [ref],\n );\n // After EVERY render, not only when the prop changes: a click clears the property\n // in the DOM, and a controlled caller that keeps `indeterminate` true expects the\n // dash back on the next render even though the prop never changed.\n useEffect(() => {\n if (local.current) local.current.indeterminate = indeterminate;\n });\n\n const box = (\n <span className={cn(\"relative inline-flex shrink-0\", bare && className)}>\n <input\n ref={setRef}\n id={bare ? id : inputId}\n disabled={disabled}\n {...rest}\n // After the spread, like Switch: a props object spread at a checkbox must not\n // be able to turn it into something else.\n type=\"checkbox\"\n // OR-ed with the spread so a caller's own `aria-invalid` survives — Input's rule.\n aria-invalid={isInvalid || rest[\"aria-invalid\"] || undefined}\n aria-describedby={mergeDescribedBy(\n rest[\"aria-describedby\"],\n showDescription && descriptionId,\n showError && errorId,\n )}\n onChange={(e: ChangeEvent<HTMLInputElement>) => {\n onChange?.(e);\n onCheckedChange?.(e.target.checked);\n }}\n className={cn(BOX, indeterminate && BOX_MIXED, isInvalid && BOX_INVALID, inputClassName)}\n />\n {/* The glyph is drawn over the box, not inside it (an input has no children),\n and ignores the pointer so a click on the tick still toggles the input. The\n tick is shown by `peer-checked`, so an UNCONTROLLED box shows it too; the\n dash replaces it outright while `indeterminate` holds. */}\n {indeterminate ? (\n <Minus\n aria-hidden\n strokeWidth={3}\n className=\"pointer-events-none absolute inset-0 m-auto size-3 text-[var(--brand-contrast)]\"\n />\n ) : (\n <Check\n aria-hidden\n strokeWidth={3}\n className=\"pointer-events-none invisible absolute inset-0 m-auto size-3 text-[var(--brand-contrast)] peer-checked:visible\"\n />\n )}\n </span>\n );\n\n if (bare) return box;\n\n return (\n <div\n className={cn(\n // `items-start` + a 20px cell for the box: the box centres on the label's FIRST\n // line (text-sm is 20px tall), so a label that wraps keeps the box at the top\n // rather than floating to the middle of a paragraph.\n \"flex items-start gap-2\",\n // The whole row fades, the way ToggleGroup and the fields do, so the label does\n // not stay at full strength beside a box you cannot change.\n disabled && \"opacity-60\",\n className,\n )}\n >\n <span className=\"flex h-5 shrink-0 items-center\">{box}</span>\n <span className=\"min-w-0\">\n {label !== undefined && (\n <label\n htmlFor={inputId}\n className={cn(\n \"block text-sm leading-5 text-[var(--text-primary)]\",\n // `select-none`: a double-click to toggle twice would otherwise select the\n // words, and a drag that starts on them starts a native text drag.\n disabled ? \"cursor-not-allowed\" : \"cursor-pointer select-none\",\n )}\n >\n {label}\n </label>\n )}\n {showDescription && (\n <span id={descriptionId} className=\"mt-0.5 block text-xs text-[var(--text-muted)]\">\n {description}\n </span>\n )}\n {showError && (\n <span id={errorId} className={cn(\"block\", ERROR_CLASS)}>\n {error}\n </span>\n )}\n </span>\n </div>\n );\n});\nCheckbox.displayName = \"Checkbox\";\n"],"mappings":";AAuII,SACE,KADF;AAvIJ,SAAS,YAAY,aAAa,WAAW,OAAO,cAAc;AAClE,SAAS,OAAO,aAAa;AAE7B,SAAS,UAAU;AACnB,SAAS,WAAW,YAAY,wBAAwB;AAuBxD,MAAM,MACJ;AAQF,MAAM,YAAY;AAKlB,MAAM,cACJ;AAEF,MAAM,cAAc;AAgDb,MAAM,WAAW,WAA4C,SAASA,UAC3E;AAAA,EACE;AAAA,EACA;AAAA,EACA,gBAAgB;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GACA,KACA;AACA,QAAM,YAAY,MAAM;AACxB,QAAM,UAAU,MAAM;AACtB,QAAM,gBAAgB,GAAG,OAAO;AAChC,QAAM,UAAU,GAAG,OAAO;AAC1B,QAAM,YAAY,WAAW,KAAK;AAClC,QAAM,kBAAkB,WAAW,WAAW;AAC9C,QAAM,YAAY,QAAQ,OAAO,KAAK;AAEtC,QAAM,OAAO,UAAU,UAAa,CAAC,mBAAmB,CAAC;AAEzD,QAAM,QAAQ,OAAgC,IAAI;AAClD,QAAM,SAAS;AAAA,IACb,CAAC,SAAkC;AACjC,YAAM,UAAU;AAChB,gBAAU,KAAK,IAAI;AAAA,IACrB;AAAA,IACA,CAAC,GAAG;AAAA,EACN;AAIA,YAAU,MAAM;AACd,QAAI,MAAM,QAAS,OAAM,QAAQ,gBAAgB;AAAA,EACnD,CAAC;AAED,QAAM,MACJ,qBAAC,UAAK,WAAW,GAAG,iCAAiC,QAAQ,SAAS,GACpE;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,IAAI,OAAO,KAAK;AAAA,QAChB;AAAA,QACC,GAAG;AAAA,QAGJ,MAAK;AAAA,QAEL,gBAAc,aAAa,KAAK,cAAc,KAAK;AAAA,QACnD,oBAAkB;AAAA,UAChB,KAAK,kBAAkB;AAAA,UACvB,mBAAmB;AAAA,UACnB,aAAa;AAAA,QACf;AAAA,QACA,UAAU,CAAC,MAAqC;AAC9C,qBAAW,CAAC;AACZ,4BAAkB,EAAE,OAAO,OAAO;AAAA,QACpC;AAAA,QACA,WAAW,GAAG,KAAK,iBAAiB,WAAW,aAAa,aAAa,cAAc;AAAA;AAAA,IACzF;AAAA,IAKC,gBACC;AAAA,MAAC;AAAA;AAAA,QACC,eAAW;AAAA,QACX,aAAa;AAAA,QACb,WAAU;AAAA;AAAA,IACZ,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,eAAW;AAAA,QACX,aAAa;AAAA,QACb,WAAU;AAAA;AAAA,IACZ;AAAA,KAEJ;AAGF,MAAI,KAAM,QAAO;AAEjB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA;AAAA;AAAA;AAAA,QAIT;AAAA;AAAA;AAAA,QAGA,YAAY;AAAA,QACZ;AAAA,MACF;AAAA,MAEA;AAAA,4BAAC,UAAK,WAAU,kCAAkC,eAAI;AAAA,QACtD,qBAAC,UAAK,WAAU,WACb;AAAA,oBAAU,UACT;AAAA,YAAC;AAAA;AAAA,cACC,SAAS;AAAA,cACT,WAAW;AAAA,gBACT;AAAA;AAAA;AAAA,gBAGA,WAAW,uBAAuB;AAAA,cACpC;AAAA,cAEC;AAAA;AAAA,UACH;AAAA,UAED,mBACC,oBAAC,UAAK,IAAI,eAAe,WAAU,iDAChC,uBACH;AAAA,UAED,aACC,oBAAC,UAAK,IAAI,SAAS,WAAW,GAAG,SAAS,WAAW,GAClD,iBACH;AAAA,WAEJ;AAAA;AAAA;AAAA,EACF;AAEJ,CAAC;AACD,SAAS,cAAc;","names":["Checkbox"]}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode, KeyboardEvent, ComponentPropsWithoutRef } from 'react';
|
|
3
|
+
import { LucideIcon } from 'lucide-react';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A chip: a compact pill carrying one value.
|
|
7
|
+
*
|
|
8
|
+
* Three jobs, deliberately one component. A chip can be inert (a tag on a row), a link
|
|
9
|
+
* (a jump to a section), or a toggle (a filter that is on or off) — and the difference is
|
|
10
|
+
* which prop you pass, not which component you pick. Keeping them together is what stops
|
|
11
|
+
* an app growing three near-identical pills that drift apart; it is the shape this kit
|
|
12
|
+
* already uses for `Button`, which is a link when it is given an href.
|
|
13
|
+
*
|
|
14
|
+
* A chip is not a `Button`. It is smaller, it is rounded to a pill, and it reads as a
|
|
15
|
+
* VALUE rather than as an action — which matters because a row of eight buttons says
|
|
16
|
+
* "choose one of eight things to do" and a row of eight chips says "here are eight
|
|
17
|
+
* things". Using `Button` for both is the mistake this exists to prevent.
|
|
18
|
+
*/
|
|
19
|
+
type ChipTone = "neutral" | "brand" | "danger" | "warning" | "success" | "info";
|
|
20
|
+
type ChipSize = "sm" | "md";
|
|
21
|
+
interface ChipProps {
|
|
22
|
+
children: ReactNode;
|
|
23
|
+
tone?: ChipTone;
|
|
24
|
+
size?: ChipSize;
|
|
25
|
+
icon?: LucideIcon;
|
|
26
|
+
/** Marks the chip as the current one — `aria-current` on a link, `aria-pressed` on a toggle. */
|
|
27
|
+
selected?: boolean;
|
|
28
|
+
/** Renders the chip as a link. Mutually exclusive with `onClick`. */
|
|
29
|
+
href?: string;
|
|
30
|
+
/** Renders the chip as a toggle button. Mutually exclusive with `href`. */
|
|
31
|
+
onClick?: () => void;
|
|
32
|
+
/** Renders a dismiss affordance. Works alongside `href`/`onClick` — see the note below. */
|
|
33
|
+
onRemove?: () => void;
|
|
34
|
+
/** Accessible name for the dismiss button. Default: `common.remove` from the
|
|
35
|
+
* {@link UiKitProvider}, else "Remove". */
|
|
36
|
+
removeLabel?: string;
|
|
37
|
+
disabled?: boolean;
|
|
38
|
+
className?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Roving focus, for a container that manages a row of chips (see {@link ChipInput}).
|
|
41
|
+
* A chip with no `href`/`onClick` is inert and unfocusable by default; give it a
|
|
42
|
+
* `tabIndex` and a `role` and it becomes the thing arrow keys move between.
|
|
43
|
+
*/
|
|
44
|
+
tabIndex?: number;
|
|
45
|
+
role?: string;
|
|
46
|
+
onKeyDown?: (e: KeyboardEvent<HTMLElement>) => void;
|
|
47
|
+
onFocus?: () => void;
|
|
48
|
+
/** Accessible name, when the visible text is not the whole story. */
|
|
49
|
+
"aria-label"?: string;
|
|
50
|
+
/** Escape hatch for a test id, a `data-tour` anchor, or an `aria-describedby`. */
|
|
51
|
+
[key: `data-${string}`]: unknown;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Note on `onRemove` with `href`/`onClick`: a button cannot be nested inside a button or
|
|
55
|
+
* a link, so when both are present the chip renders a wrapper holding TWO siblings — the
|
|
56
|
+
* interactive body and the dismiss control. That is why the outer element is not always
|
|
57
|
+
* the interactive one, and why the focus ring is drawn on the body rather than the
|
|
58
|
+
* wrapper.
|
|
59
|
+
*/
|
|
60
|
+
declare const Chip: react.ForwardRefExoticComponent<ChipProps & react.RefAttributes<HTMLElement>>;
|
|
61
|
+
interface ChipInputLabels {
|
|
62
|
+
/** Announced after a value is added. Receives the value. */
|
|
63
|
+
added: (value: string) => string;
|
|
64
|
+
/** Announced after a value is removed. Receives the value. */
|
|
65
|
+
removed: (value: string) => string;
|
|
66
|
+
/** Accessible name for each chip's dismiss button. */
|
|
67
|
+
remove: string;
|
|
68
|
+
/** Shown when `max` is reached. Receives the limit. */
|
|
69
|
+
atLimit: (max: number) => string;
|
|
70
|
+
/** Shown when a duplicate is rejected. Receives the value. */
|
|
71
|
+
duplicate: (value: string) => string;
|
|
72
|
+
}
|
|
73
|
+
declare const DEFAULT_CHIP_INPUT_LABELS: ChipInputLabels;
|
|
74
|
+
declare function resolveChipInputLabels(labels?: Partial<ChipInputLabels>): ChipInputLabels;
|
|
75
|
+
/**
|
|
76
|
+
* `onChange` is the field's own — the whole LIST, not a DOM event — so the wrapper
|
|
77
|
+
* div's `onChange` is omitted rather than shadowed. `placeholder` is likewise this
|
|
78
|
+
* component's, forwarded to the inner `<input>`; the div has none of its own.
|
|
79
|
+
*/
|
|
80
|
+
interface ChipInputProps extends Omit<ComponentPropsWithoutRef<"div">, "onChange" | "placeholder" | "children"> {
|
|
81
|
+
value: string[];
|
|
82
|
+
onChange: (next: string[]) => void;
|
|
83
|
+
placeholder?: string;
|
|
84
|
+
/** Visible label, rendered above the field. Without one, name the field with
|
|
85
|
+
* `aria-label`. */
|
|
86
|
+
label?: string;
|
|
87
|
+
/**
|
|
88
|
+
* @deprecated Pass `aria-label` instead — the DOM spelling the rest of this kit
|
|
89
|
+
* now uses. Still honoured, and still second to `aria-label` when both are given.
|
|
90
|
+
*/
|
|
91
|
+
ariaLabel?: string;
|
|
92
|
+
/** Reject or rewrite a value on commit. Return a string to reject WITH that message. */
|
|
93
|
+
validate?: (raw: string) => string | null;
|
|
94
|
+
/** Characters that commit the current text, besides Enter. Default: comma. */
|
|
95
|
+
separators?: string[];
|
|
96
|
+
allowDuplicates?: boolean;
|
|
97
|
+
max?: number;
|
|
98
|
+
tone?: ChipTone;
|
|
99
|
+
size?: ChipSize;
|
|
100
|
+
disabled?: boolean;
|
|
101
|
+
invalid?: boolean;
|
|
102
|
+
/** Error text. Wires `aria-describedby` and implies `invalid`. */
|
|
103
|
+
error?: ReactNode;
|
|
104
|
+
labels?: Partial<ChipInputLabels>;
|
|
105
|
+
className?: string;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* A field whose value is a LIST, entered as chips.
|
|
109
|
+
*
|
|
110
|
+
* The keyboard model is the whole component; the pills are the easy part. Per the WAI
|
|
111
|
+
* pattern for a "tag" input:
|
|
112
|
+
*
|
|
113
|
+
* Enter, or any separator commit the typed text
|
|
114
|
+
* Backspace on empty text move focus to the last chip (does NOT delete it)
|
|
115
|
+
* ← → while on a chip move between chips
|
|
116
|
+
* Backspace / Delete remove the focused chip, focus its neighbour
|
|
117
|
+
* Escape clear what is typed but keep the committed chips
|
|
118
|
+
* paste splits on the separators, so a pasted CSV becomes chips
|
|
119
|
+
*
|
|
120
|
+
* The Backspace-on-empty behaviour is the one worth arguing about. Deleting immediately
|
|
121
|
+
* is more common and is a trap: it is a destructive action with no feedback on a key
|
|
122
|
+
* people hit by reflex, and the value it destroys may have taken a while to type. Moving
|
|
123
|
+
* focus first makes the second Backspace a deliberate one, and it is what lets a
|
|
124
|
+
* keyboard user reach a chip at all.
|
|
125
|
+
*/
|
|
126
|
+
declare function ChipInput({ value, onChange, placeholder, label, ariaLabel, validate, separators, allowDuplicates, max, tone, size, disabled, invalid, error, labels, className, "aria-label": ariaLabelAttr, ...rest }: ChipInputProps): react.JSX.Element;
|
|
127
|
+
|
|
128
|
+
export { Chip, ChipInput, type ChipInputLabels, type ChipInputProps, type ChipProps, type ChipSize, type ChipTone, DEFAULT_CHIP_INPUT_LABELS, resolveChipInputLabels };
|