@eifi1/ui-kit 0.4.1 → 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 +89 -19
- package/dist/components/combobox-core.js.map +1 -1
- package/dist/components/combobox.d.ts +43 -33
- package/dist/components/combobox.js +409 -340
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/currency-select.d.ts +48 -8
- package/dist/components/currency-select.js +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 +74 -19
- package/dist/components/dropdown.js +72 -22
- package/dist/components/dropdown.js.map +1 -1
- package/dist/components/entity-combobox.d.ts +5 -4
- package/dist/components/entity-combobox.js +107 -76
- package/dist/components/entity-combobox.js.map +1 -1
- package/dist/components/facing-pair.d.ts +36 -0
- package/dist/components/facing-pair.js +40 -0
- package/dist/components/facing-pair.js.map +1 -0
- package/dist/components/field-sync.d.ts +164 -0
- package/dist/components/field-sync.js +264 -0
- package/dist/components/field-sync.js.map +1 -0
- package/dist/components/file-dropzone.d.ts +21 -7
- package/dist/components/file-dropzone.js +28 -7
- package/dist/components/file-dropzone.js.map +1 -1
- package/dist/components/full-bleed-dialog.d.ts +37 -26
- package/dist/components/full-bleed-dialog.js +20 -5
- package/dist/components/full-bleed-dialog.js.map +1 -1
- package/dist/components/grouped-picker.d.ts +21 -10
- package/dist/components/grouped-picker.js +66 -52
- package/dist/components/grouped-picker.js.map +1 -1
- package/dist/components/hover-menu.d.ts +20 -4
- package/dist/components/hover-menu.js +15 -4
- package/dist/components/hover-menu.js.map +1 -1
- package/dist/components/mini-calendar.d.ts +102 -14
- package/dist/components/mini-calendar.js +256 -70
- package/dist/components/mini-calendar.js.map +1 -1
- package/dist/components/modal.d.ts +9 -3
- package/dist/components/modal.js +34 -45
- package/dist/components/modal.js.map +1 -1
- package/dist/components/month-picker.d.ts +79 -0
- package/dist/components/month-picker.js +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 +21 -2
- package/dist/components/number-input.js +2 -1
- package/dist/components/number-input.js.map +1 -1
- package/dist/components/numpad-sheet.d.ts +25 -4
- package/dist/components/numpad-sheet.js +30 -13
- package/dist/components/numpad-sheet.js.map +1 -1
- package/dist/components/page-contents.d.ts +90 -0
- package/dist/components/page-contents.js +170 -0
- package/dist/components/page-contents.js.map +1 -0
- package/dist/components/password-strength.d.ts +106 -0
- package/dist/components/password-strength.js +132 -0
- package/dist/components/password-strength.js.map +1 -0
- package/dist/components/picker-sheet.d.ts +23 -15
- package/dist/components/picker-sheet.js +34 -14
- package/dist/components/picker-sheet.js.map +1 -1
- package/dist/components/popover.d.ts +62 -4
- package/dist/components/popover.js +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 +5 -3
- package/dist/components/user-avatar.js +4 -2
- package/dist/components/user-avatar.js.map +1 -1
- package/dist/components/wizard-stepper.js +3 -2
- package/dist/components/wizard-stepper.js.map +1 -1
- package/dist/{data-table-filters-aXyf0Xub.d.ts → data-table-filters-DM1auUfH.d.ts} +27 -5
- package/dist/data-table.d.ts +7 -0
- package/dist/data-table.js +12 -0
- package/dist/data-table.js.map +1 -0
- package/dist/feedback/feedback-attachment.js +12 -11
- package/dist/feedback/feedback-attachment.js.map +1 -1
- package/dist/feedback/feedback-dialog.js +2 -1
- package/dist/feedback/feedback-dialog.js.map +1 -1
- package/dist/feedback/feedback-inbox.d.ts +33 -7
- package/dist/feedback/feedback-inbox.js +49 -37
- package/dist/feedback/feedback-inbox.js.map +1 -1
- package/dist/feedback.d.ts +5 -0
- package/dist/feedback.js +5 -0
- package/dist/feedback.js.map +1 -0
- package/dist/hooks/use-anchored-panel.js +1 -0
- package/dist/hooks/use-anchored-panel.js.map +1 -1
- package/dist/hooks/use-anchored-rect.js +1 -0
- package/dist/hooks/use-anchored-rect.js.map +1 -1
- package/dist/hooks/use-announce.d.ts +46 -0
- package/dist/hooks/use-announce.js +37 -0
- package/dist/hooks/use-announce.js.map +1 -0
- package/dist/hooks/use-body-scroll-lock.js +1 -0
- package/dist/hooks/use-body-scroll-lock.js.map +1 -1
- package/dist/hooks/use-close-transition.js +1 -0
- package/dist/hooks/use-close-transition.js.map +1 -1
- package/dist/hooks/use-dismiss.js +1 -0
- package/dist/hooks/use-dismiss.js.map +1 -1
- package/dist/hooks/use-focus-trap.d.ts +16 -0
- package/dist/hooks/use-focus-trap.js +67 -0
- package/dist/hooks/use-focus-trap.js.map +1 -0
- package/dist/hooks/use-media-query.js +1 -0
- package/dist/hooks/use-media-query.js.map +1 -1
- package/dist/hooks/use-overlay-history.js +27 -1
- package/dist/hooks/use-overlay-history.js.map +1 -1
- package/dist/hooks/use-row-swipe.js +1 -0
- package/dist/hooks/use-row-swipe.js.map +1 -1
- package/dist/i18n/defaults.d.ts +31 -0
- package/dist/i18n/defaults.js +63 -0
- package/dist/i18n/defaults.js.map +1 -0
- package/dist/i18n/kit-labels.d.ts +250 -0
- package/dist/i18n/kit-labels.js +184 -0
- package/dist/i18n/kit-labels.js.map +1 -0
- package/dist/index.d.ts +47 -22
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/calc.js +1 -0
- package/dist/lib/calc.js.map +1 -1
- package/dist/lib/cn.js +1 -0
- package/dist/lib/cn.js.map +1 -1
- package/dist/lib/dates.js +1 -0
- package/dist/lib/dates.js.map +1 -1
- package/dist/lib/logger.js +1 -0
- package/dist/lib/logger.js.map +1 -1
- package/dist/lib/safe-storage.js +1 -0
- package/dist/lib/safe-storage.js.map +1 -1
- package/dist/search/command-palette.d.ts +11 -1
- package/dist/search/command-palette.js +21 -15
- package/dist/search/command-palette.js.map +1 -1
- package/dist/search.d.ts +2 -0
- package/dist/search.js +3 -0
- package/dist/search.js.map +1 -0
- package/dist/shell/app-shell.d.ts +33 -4
- package/dist/shell/app-shell.js +275 -78
- package/dist/shell/app-shell.js.map +1 -1
- package/dist/shell/option-switcher-menu.js +3 -2
- package/dist/shell/option-switcher-menu.js.map +1 -1
- package/dist/shell/role-switcher.d.ts +6 -0
- package/dist/shell/role-switcher.js +7 -4
- package/dist/shell/role-switcher.js.map +1 -1
- package/dist/shell/top-bar.d.ts +15 -7
- package/dist/shell/top-bar.js +3 -5
- package/dist/shell/top-bar.js.map +1 -1
- package/dist/shell/topbar-action-menu.js +3 -2
- package/dist/shell/topbar-action-menu.js.map +1 -1
- package/dist/shell/topbar-controls.d.ts +5 -2
- package/dist/shell/topbar-controls.js +20 -15
- package/dist/shell/topbar-controls.js.map +1 -1
- package/dist/shell.d.ts +13 -0
- package/dist/shell.js +8 -0
- package/dist/shell.js.map +1 -0
- package/dist/theme/chart-palette.d.ts +19 -12
- package/dist/theme/chart-palette.js +24 -30
- package/dist/theme/chart-palette.js.map +1 -1
- package/dist/theme/color.d.ts +78 -0
- package/dist/theme/color.js +148 -0
- package/dist/theme/color.js.map +1 -0
- package/dist/theme/palette-derive.d.ts +140 -0
- package/dist/theme/palette-derive.js +376 -0
- package/dist/theme/palette-derive.js.map +1 -0
- package/dist/theme/palette-presets.d.ts +14 -1
- package/dist/theme/palette-presets.js +231 -3
- package/dist/theme/palette-presets.js.map +1 -1
- package/dist/theme/palette-store.js +1 -0
- package/dist/theme/palette-store.js.map +1 -1
- package/dist/theme/theme-store.js +1 -0
- package/dist/theme/theme-store.js.map +1 -1
- package/dist/tour/tour.d.ts +2 -1
- package/dist/tour/tour.js +15 -9
- package/dist/tour/tour.js.map +1 -1
- package/dist/tour.d.ts +2 -0
- package/dist/tour.js +3 -0
- package/dist/tour.js.map +1 -0
- package/dist/wizard/stepper-nav.js +10 -8
- package/dist/wizard/stepper-nav.js.map +1 -1
- package/dist/wizard/types.d.ts +18 -2
- package/dist/wizard/types.js +4 -1
- package/dist/wizard/types.js.map +1 -1
- package/dist/wizard/use-wizard.js +12 -4
- package/dist/wizard/use-wizard.js.map +1 -1
- package/dist/wizard/validation.js +1 -0
- package/dist/wizard/validation.js.map +1 -1
- package/dist/wizard/wizard-context.js +1 -0
- package/dist/wizard/wizard-context.js.map +1 -1
- package/dist/wizard/wizard-step.js +1 -0
- package/dist/wizard/wizard-step.js.map +1 -1
- package/dist/wizard/wizard-summary.js +5 -3
- package/dist/wizard/wizard-summary.js.map +1 -1
- package/dist/wizard.d.ts +8 -0
- package/dist/wizard.js +9 -0
- package/dist/wizard.js.map +1 -0
- package/package.json +66 -13
- package/src/chart.ts +22 -0
- package/src/components/account-settings.tsx +275 -0
- package/src/components/alert-banner.tsx +75 -0
- package/src/components/amount-input.tsx +471 -0
- package/src/components/calculator.tsx +252 -0
- package/src/components/chart-zoom.tsx +499 -0
- package/src/components/chart.tsx +363 -0
- package/src/components/checkbox.tsx +222 -0
- package/src/components/chip.tsx +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
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
3
|
import { Fragment, useId, useMemo, useRef, useState } from "react";
|
|
3
4
|
import { createPortal } from "react-dom";
|
|
@@ -8,7 +9,9 @@ import { useDropdown } from "./dropdown.js";
|
|
|
8
9
|
import { useAnchoredPanel } from "../hooks/use-anchored-panel.js";
|
|
9
10
|
import { useMediaQuery } from "../hooks/use-media-query.js";
|
|
10
11
|
import { PickerSheet, SHEET_ROW_CLASS } from "./picker-sheet.js";
|
|
11
|
-
|
|
12
|
+
import { useActiveOptionScroll } from "./combobox-core.js";
|
|
13
|
+
import { DEFAULT_COMBOBOX_LABELS, useKitLabels } from "../i18n/kit-labels.js";
|
|
14
|
+
const LIST_CLASS = "max-h-64 overflow-y-auto rounded-md border border-[var(--border)] bg-[var(--bg-surface)] py-1 shadow-lg";
|
|
12
15
|
function usePrimaryPressOnly() {
|
|
13
16
|
const auxPress = useRef(false);
|
|
14
17
|
return {
|
|
@@ -24,6 +27,7 @@ function usePrimaryPressOnly() {
|
|
|
24
27
|
};
|
|
25
28
|
}
|
|
26
29
|
function SuggestionList({
|
|
30
|
+
id,
|
|
27
31
|
anchorRef,
|
|
28
32
|
panelRef,
|
|
29
33
|
children
|
|
@@ -37,15 +41,15 @@ function SuggestionList({
|
|
|
37
41
|
ref: panelRef,
|
|
38
42
|
className: "fixed z-50",
|
|
39
43
|
style: { top, left: rect.left, width: rect.width },
|
|
40
|
-
children: /* @__PURE__ */ jsx("ul", { role: "listbox", className: LIST_CLASS, style: { maxHeight }, children })
|
|
44
|
+
children: /* @__PURE__ */ jsx("ul", { id, role: "listbox", className: LIST_CLASS, style: { maxHeight }, children })
|
|
41
45
|
}
|
|
42
46
|
),
|
|
43
47
|
document.body
|
|
44
48
|
);
|
|
45
49
|
}
|
|
46
50
|
const rowClass = (isActive) => cn(
|
|
47
|
-
"block w-full truncate px-3 py-1.5 text-left text-sm text-
|
|
48
|
-
isActive ? "bg-
|
|
51
|
+
"block w-full truncate px-3 py-1.5 text-left text-sm text-[var(--text-primary)]",
|
|
52
|
+
isActive ? "bg-[var(--bg-active)]" : "hover:bg-[var(--bg-hover)]"
|
|
49
53
|
);
|
|
50
54
|
function Combobox({
|
|
51
55
|
value,
|
|
@@ -65,10 +69,13 @@ function Combobox({
|
|
|
65
69
|
autoFocus,
|
|
66
70
|
onBlur,
|
|
67
71
|
onSubmit,
|
|
68
|
-
"aria-label": ariaLabel
|
|
72
|
+
"aria-label": ariaLabel,
|
|
73
|
+
...rest
|
|
69
74
|
}) {
|
|
70
75
|
const generated = useId();
|
|
71
76
|
const fieldId = id ?? generated;
|
|
77
|
+
const listboxId = `${generated}-listbox`;
|
|
78
|
+
const optionId = (index) => `${generated}-option-${index}`;
|
|
72
79
|
const isPhone = useMediaQuery(PHONE_QUERY, false);
|
|
73
80
|
const { open, setOpen, wrapperRef, panelRef } = useDropdown({ backCloses: !isPhone });
|
|
74
81
|
const primaryOnly = usePrimaryPressOnly();
|
|
@@ -100,194 +107,230 @@ function Combobox({
|
|
|
100
107
|
}
|
|
101
108
|
return [...byGroup.values()].flat();
|
|
102
109
|
}, [options, query, groupBy, maxSuggestions, isPhone]);
|
|
110
|
+
const groupHeadings = useMemo(() => {
|
|
111
|
+
if (!groupBy) return null;
|
|
112
|
+
const heads = /* @__PURE__ */ new Map();
|
|
113
|
+
let prev;
|
|
114
|
+
matches.forEach((o, i) => {
|
|
115
|
+
const group = groupBy(o);
|
|
116
|
+
if (group != null && group !== prev) heads.set(i, group);
|
|
117
|
+
prev = group;
|
|
118
|
+
});
|
|
119
|
+
return heads;
|
|
120
|
+
}, [matches, groupBy]);
|
|
103
121
|
const commit = (v) => {
|
|
104
122
|
onChange(v);
|
|
105
123
|
setOpen(false);
|
|
106
124
|
setActive(-1);
|
|
107
125
|
setTyping(false);
|
|
108
126
|
};
|
|
127
|
+
const activeId = !isPhone && active >= 0 && active < matches.length ? optionId(active) : void 0;
|
|
128
|
+
useActiveOptionScroll(activeId);
|
|
109
129
|
const typed = value.trim();
|
|
110
130
|
const createRow = createLabel && typed.length > 0 && !options.some((o) => o.toLowerCase() === typed.toLowerCase()) ? createLabel(typed) : null;
|
|
111
|
-
return
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
"
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
},
|
|
139
|
-
inputMode: isPhone ? "none" : void 0,
|
|
140
|
-
onChange: (e) => {
|
|
141
|
-
onChange(e.target.value);
|
|
142
|
-
setOpen(true);
|
|
143
|
-
setActive(-1);
|
|
144
|
-
setTyping(true);
|
|
145
|
-
},
|
|
146
|
-
onKeyDown: (e) => {
|
|
147
|
-
if (e.key === "ArrowDown") {
|
|
148
|
-
e.preventDefault();
|
|
131
|
+
return (
|
|
132
|
+
// `rest` dresses the outer box — a `data-tour` anchor, a test id, a form-level
|
|
133
|
+
// `aria-describedby`. Not the NAME: that belongs on the <input> below, which is
|
|
134
|
+
// the combobox a reader meets. Spread FIRST, so the field's ARIA and the
|
|
135
|
+
// handlers carrying live #309 and dev#549 cannot be replaced from outside.
|
|
136
|
+
/* @__PURE__ */ jsxs("div", { ...rest, ref: wrapperRef, className: cn("relative", className), children: [
|
|
137
|
+
label !== void 0 && /* @__PURE__ */ jsx(FieldLabel, { children: label }),
|
|
138
|
+
/* @__PURE__ */ jsxs("div", { ref: fieldRef, className: "relative", children: [
|
|
139
|
+
/* @__PURE__ */ jsx(
|
|
140
|
+
"input",
|
|
141
|
+
{
|
|
142
|
+
id: fieldId,
|
|
143
|
+
value,
|
|
144
|
+
placeholder,
|
|
145
|
+
"aria-label": ariaLabel ?? label,
|
|
146
|
+
role: "combobox",
|
|
147
|
+
"aria-expanded": open,
|
|
148
|
+
"aria-controls": listboxId,
|
|
149
|
+
"aria-activedescendant": activeId,
|
|
150
|
+
"aria-autocomplete": "list",
|
|
151
|
+
"aria-invalid": invalid || void 0,
|
|
152
|
+
autoComplete: "off",
|
|
153
|
+
autoFocus,
|
|
154
|
+
onBlur,
|
|
155
|
+
onMouseDown: primaryOnly.onMouseDown,
|
|
156
|
+
onFocus: () => {
|
|
157
|
+
if (primaryOnly.fromAuxButton()) return;
|
|
149
158
|
setOpen(true);
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
159
|
+
setTyping(false);
|
|
160
|
+
if (isPhone) sheetInputRef.current?.focus();
|
|
161
|
+
},
|
|
162
|
+
onClick: () => {
|
|
163
|
+
setOpen(true);
|
|
164
|
+
setTyping(false);
|
|
165
|
+
},
|
|
166
|
+
inputMode: isPhone ? "none" : void 0,
|
|
167
|
+
onChange: (e) => {
|
|
168
|
+
onChange(e.target.value);
|
|
169
|
+
setOpen(true);
|
|
170
|
+
setActive(-1);
|
|
171
|
+
setTyping(true);
|
|
172
|
+
},
|
|
173
|
+
onKeyDown: (e) => {
|
|
174
|
+
if (e.key === "ArrowDown") {
|
|
175
|
+
e.preventDefault();
|
|
176
|
+
setOpen(true);
|
|
177
|
+
setActive((i) => Math.min(i + 1, matches.length - 1));
|
|
178
|
+
} else if (e.key === "ArrowUp") {
|
|
156
179
|
e.preventDefault();
|
|
157
|
-
|
|
158
|
-
} else {
|
|
159
|
-
if (
|
|
180
|
+
setActive((i) => Math.max(i - 1, 0));
|
|
181
|
+
} else if (e.key === "Enter") {
|
|
182
|
+
if (open && active >= 0 && active < matches.length) {
|
|
183
|
+
e.preventDefault();
|
|
184
|
+
commit(matches[active]);
|
|
185
|
+
} else {
|
|
186
|
+
if (onSubmit) e.preventDefault();
|
|
187
|
+
setOpen(false);
|
|
188
|
+
onSubmit?.();
|
|
189
|
+
}
|
|
190
|
+
} else if (e.key === "Escape") {
|
|
191
|
+
setOpen(false);
|
|
192
|
+
setActive(-1);
|
|
193
|
+
} else if (e.key === "Tab") {
|
|
160
194
|
setOpen(false);
|
|
161
|
-
|
|
195
|
+
setActive(-1);
|
|
162
196
|
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
)
|
|
182
|
-
] }),
|
|
183
|
-
isPhone && /* @__PURE__ */ jsx(
|
|
184
|
-
PickerSheet,
|
|
185
|
-
{
|
|
186
|
-
open,
|
|
187
|
-
onClose: () => setOpen(false),
|
|
188
|
-
title: label,
|
|
189
|
-
query: value,
|
|
190
|
-
onQueryChange: (v) => {
|
|
191
|
-
onChange(v);
|
|
192
|
-
setTyping(true);
|
|
193
|
-
},
|
|
194
|
-
searchPlaceholder: searchPlaceholder ?? placeholder,
|
|
195
|
-
inputRef: sheetInputRef,
|
|
196
|
-
closeLabel,
|
|
197
|
-
children: /* @__PURE__ */ jsxs("ul", { role: "listbox", children: [
|
|
198
|
-
createRow && /* @__PURE__ */ jsx("li", { role: "option", "aria-selected": false, children: /* @__PURE__ */ jsx(
|
|
199
|
-
"button",
|
|
200
|
-
{
|
|
201
|
-
type: "button",
|
|
202
|
-
onClick: () => commit(typed),
|
|
203
|
-
className: cn(SHEET_ROW_CLASS, "font-medium text-teal-700 dark:text-teal-300"),
|
|
204
|
-
children: createRow
|
|
205
|
-
}
|
|
206
|
-
) }),
|
|
207
|
-
matches.map((o) => {
|
|
208
|
-
const group = groupBy?.(o);
|
|
209
|
-
const startsGroup = group != null && group !== (matches[matches.indexOf(o) - 1] && groupBy?.(matches[matches.indexOf(o) - 1]));
|
|
210
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
211
|
-
startsGroup && /* @__PURE__ */ jsx(
|
|
212
|
-
"li",
|
|
213
|
-
{
|
|
214
|
-
role: "presentation",
|
|
215
|
-
className: "px-4 pb-0.5 pt-3 text-[11px] font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400",
|
|
216
|
-
children: group
|
|
217
|
-
}
|
|
218
|
-
),
|
|
219
|
-
/* @__PURE__ */ jsx("li", { role: "option", "aria-selected": o === value, children: /* @__PURE__ */ jsxs(
|
|
220
|
-
"button",
|
|
221
|
-
{
|
|
222
|
-
type: "button",
|
|
223
|
-
onClick: () => commit(o),
|
|
224
|
-
className: cn(
|
|
225
|
-
SHEET_ROW_CLASS,
|
|
226
|
-
optionAdornment && "flex items-center justify-between gap-2"
|
|
227
|
-
),
|
|
228
|
-
children: [
|
|
229
|
-
optionAdornment ? /* @__PURE__ */ jsx("span", { className: "truncate", children: o }) : o,
|
|
230
|
-
optionAdornment?.(o)
|
|
231
|
-
]
|
|
232
|
-
}
|
|
233
|
-
) })
|
|
234
|
-
] }, o);
|
|
235
|
-
})
|
|
236
|
-
] })
|
|
237
|
-
}
|
|
238
|
-
),
|
|
239
|
-
!isPhone && open && (matches.length > 0 || createRow) && /* @__PURE__ */ jsxs(SuggestionList, { anchorRef: fieldRef, panelRef, children: [
|
|
240
|
-
createRow && /* @__PURE__ */ jsx("li", { role: "option", "aria-selected": false, children: /* @__PURE__ */ jsx(
|
|
241
|
-
"button",
|
|
197
|
+
},
|
|
198
|
+
className: cn(FIELD_BASE, label !== void 0 && FIELD_FLOATING_PAD, "pr-9", invalid && FIELD_INVALID)
|
|
199
|
+
}
|
|
200
|
+
),
|
|
201
|
+
/* @__PURE__ */ jsx(
|
|
202
|
+
ChevronDown,
|
|
203
|
+
{
|
|
204
|
+
"aria-hidden": true,
|
|
205
|
+
onMouseDown: (e) => {
|
|
206
|
+
e.preventDefault();
|
|
207
|
+
setOpen((o) => !o);
|
|
208
|
+
},
|
|
209
|
+
className: "absolute right-2.5 top-1/2 size-4 -translate-y-1/2 cursor-pointer text-[var(--text-placeholder)]"
|
|
210
|
+
}
|
|
211
|
+
)
|
|
212
|
+
] }),
|
|
213
|
+
isPhone && /* @__PURE__ */ jsx(
|
|
214
|
+
PickerSheet,
|
|
242
215
|
{
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
216
|
+
open,
|
|
217
|
+
onClose: () => setOpen(false),
|
|
218
|
+
title: label,
|
|
219
|
+
query: value,
|
|
220
|
+
onQueryChange: (v) => {
|
|
221
|
+
onChange(v);
|
|
222
|
+
setTyping(true);
|
|
247
223
|
},
|
|
248
|
-
|
|
249
|
-
|
|
224
|
+
searchPlaceholder: searchPlaceholder ?? placeholder,
|
|
225
|
+
inputRef: sheetInputRef,
|
|
226
|
+
closeLabel,
|
|
227
|
+
children: /* @__PURE__ */ jsxs("ul", { id: listboxId, role: "listbox", children: [
|
|
228
|
+
createRow && // `role="option"` rides the BUTTON, not the <li> around it: an option
|
|
229
|
+
// may not contain a separately focusable control, and the button is
|
|
230
|
+
// what a pointer presses. Same shape `CommandPalette` has always had.
|
|
231
|
+
/* @__PURE__ */ jsx("li", { role: "presentation", children: /* @__PURE__ */ jsx(
|
|
232
|
+
"button",
|
|
233
|
+
{
|
|
234
|
+
type: "button",
|
|
235
|
+
role: "option",
|
|
236
|
+
"aria-selected": false,
|
|
237
|
+
onClick: () => commit(typed),
|
|
238
|
+
className: cn(SHEET_ROW_CLASS, "font-medium text-[var(--brand)]"),
|
|
239
|
+
children: createRow
|
|
240
|
+
}
|
|
241
|
+
) }),
|
|
242
|
+
matches.map((o, i) => {
|
|
243
|
+
const group = groupHeadings?.get(i);
|
|
244
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
245
|
+
group !== void 0 && /* @__PURE__ */ jsx(
|
|
246
|
+
"li",
|
|
247
|
+
{
|
|
248
|
+
role: "presentation",
|
|
249
|
+
className: "px-4 pb-0.5 pt-3 text-[11px] font-semibold uppercase tracking-wide text-[var(--text-muted)]",
|
|
250
|
+
children: group
|
|
251
|
+
}
|
|
252
|
+
),
|
|
253
|
+
/* @__PURE__ */ jsx("li", { role: "presentation", children: /* @__PURE__ */ jsxs(
|
|
254
|
+
"button",
|
|
255
|
+
{
|
|
256
|
+
type: "button",
|
|
257
|
+
role: "option",
|
|
258
|
+
"aria-selected": o === value,
|
|
259
|
+
onClick: () => commit(o),
|
|
260
|
+
className: cn(
|
|
261
|
+
SHEET_ROW_CLASS,
|
|
262
|
+
optionAdornment && "flex items-center justify-between gap-2"
|
|
263
|
+
),
|
|
264
|
+
children: [
|
|
265
|
+
optionAdornment ? /* @__PURE__ */ jsx("span", { className: "truncate", children: o }) : o,
|
|
266
|
+
optionAdornment?.(o)
|
|
267
|
+
]
|
|
268
|
+
}
|
|
269
|
+
) })
|
|
270
|
+
] }, o);
|
|
271
|
+
})
|
|
272
|
+
] })
|
|
250
273
|
}
|
|
251
|
-
)
|
|
252
|
-
matches.
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
"
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
274
|
+
),
|
|
275
|
+
!isPhone && open && (matches.length > 0 || createRow) && /* @__PURE__ */ jsxs(SuggestionList, { id: listboxId, anchorRef: fieldRef, panelRef, children: [
|
|
276
|
+
createRow && /* @__PURE__ */ jsx("li", { role: "presentation", children: /* @__PURE__ */ jsx(
|
|
277
|
+
"button",
|
|
278
|
+
{
|
|
279
|
+
type: "button",
|
|
280
|
+
role: "option",
|
|
281
|
+
"aria-selected": false,
|
|
282
|
+
tabIndex: -1,
|
|
283
|
+
onMouseDown: (e) => {
|
|
284
|
+
e.preventDefault();
|
|
285
|
+
commit(typed);
|
|
286
|
+
},
|
|
287
|
+
className: cn(rowClass(false), "font-medium text-[var(--brand)]"),
|
|
288
|
+
children: createRow
|
|
289
|
+
}
|
|
290
|
+
) }),
|
|
291
|
+
matches.map((o, i) => {
|
|
292
|
+
const group = groupHeadings?.get(i);
|
|
293
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
294
|
+
group !== void 0 && /* @__PURE__ */ jsx(
|
|
295
|
+
"li",
|
|
296
|
+
{
|
|
297
|
+
role: "presentation",
|
|
298
|
+
className: "px-3 pb-0.5 pt-2 text-[11px] font-semibold uppercase tracking-wide text-[var(--text-muted)] first:pt-1",
|
|
299
|
+
children: group
|
|
300
|
+
}
|
|
301
|
+
),
|
|
302
|
+
/* @__PURE__ */ jsx("li", { role: "presentation", children: /* @__PURE__ */ jsxs(
|
|
303
|
+
"button",
|
|
304
|
+
{
|
|
305
|
+
type: "button",
|
|
306
|
+
id: optionId(i),
|
|
307
|
+
role: "option",
|
|
308
|
+
"aria-selected": o === value,
|
|
309
|
+
tabIndex: -1,
|
|
310
|
+
onMouseDown: (e) => {
|
|
311
|
+
e.preventDefault();
|
|
312
|
+
commit(o);
|
|
313
|
+
},
|
|
314
|
+
onMouseEnter: () => setActive(i),
|
|
315
|
+
className: cn(
|
|
316
|
+
rowClass(i === active),
|
|
317
|
+
group != null && "pl-6",
|
|
318
|
+
// A row with a badge is a flex row so the label truncates and the
|
|
319
|
+
// badge keeps its width; without one it stays the plain block the
|
|
320
|
+
// other lists render, so nothing shifts for callers that pass none.
|
|
321
|
+
optionAdornment && "flex items-center justify-between gap-2"
|
|
322
|
+
),
|
|
323
|
+
children: [
|
|
324
|
+
optionAdornment ? /* @__PURE__ */ jsx("span", { className: "truncate", children: o }) : o,
|
|
325
|
+
optionAdornment?.(o)
|
|
326
|
+
]
|
|
327
|
+
}
|
|
328
|
+
) })
|
|
329
|
+
] }, o);
|
|
330
|
+
})
|
|
331
|
+
] })
|
|
289
332
|
] })
|
|
290
|
-
|
|
333
|
+
);
|
|
291
334
|
}
|
|
292
335
|
function InlineEntityCombobox({
|
|
293
336
|
value,
|
|
@@ -305,10 +348,13 @@ function InlineEntityCombobox({
|
|
|
305
348
|
clearable,
|
|
306
349
|
clearLabel,
|
|
307
350
|
invalid,
|
|
308
|
-
"aria-label": ariaLabel
|
|
351
|
+
"aria-label": ariaLabel,
|
|
352
|
+
...rest
|
|
309
353
|
}) {
|
|
310
354
|
const generated = useId();
|
|
311
355
|
const fieldId = id ?? generated;
|
|
356
|
+
const listboxId = `${generated}-listbox`;
|
|
357
|
+
const optionId = (index) => `${generated}-option-${index}`;
|
|
312
358
|
const isPhone = useMediaQuery(PHONE_QUERY, false);
|
|
313
359
|
const { open, setOpen, wrapperRef, panelRef } = useDropdown({ backCloses: !isPhone });
|
|
314
360
|
const primaryOnly = usePrimaryPressOnly();
|
|
@@ -317,6 +363,11 @@ function InlineEntityCombobox({
|
|
|
317
363
|
const sheetInputRef = useRef(null);
|
|
318
364
|
const fieldRef = useRef(null);
|
|
319
365
|
const [sheetQuery, setSheetQuery] = useState("");
|
|
366
|
+
const labels = useKitLabels("combobox", DEFAULT_COMBOBOX_LABELS, {
|
|
367
|
+
search: searchPlaceholder,
|
|
368
|
+
noResults: emptyLabel,
|
|
369
|
+
clear: clearLabel
|
|
370
|
+
});
|
|
320
371
|
const selected = useMemo(
|
|
321
372
|
() => value == null ? null : options.find((o) => o.value === value) ?? null,
|
|
322
373
|
[options, value]
|
|
@@ -330,10 +381,10 @@ function InlineEntityCombobox({
|
|
|
330
381
|
if (query) {
|
|
331
382
|
const hit = (s) => s?.toLowerCase().includes(query) ?? false;
|
|
332
383
|
const starts = options.filter((o) => o.label.toLowerCase().startsWith(query));
|
|
333
|
-
const
|
|
384
|
+
const rest2 = options.filter(
|
|
334
385
|
(o) => !o.label.toLowerCase().startsWith(query) && (hit(o.label) || hit(o.sublabel) || hit(o.group))
|
|
335
386
|
);
|
|
336
|
-
ranked = [...starts, ...
|
|
387
|
+
ranked = [...starts, ...rest2];
|
|
337
388
|
}
|
|
338
389
|
if (!ranked.some((o) => o.group)) return ranked;
|
|
339
390
|
const blocks = /* @__PURE__ */ new Map();
|
|
@@ -344,6 +395,8 @@ function InlineEntityCombobox({
|
|
|
344
395
|
}
|
|
345
396
|
return [...blocks.values()].flat();
|
|
346
397
|
}, [options, query]);
|
|
398
|
+
const activeId = !isPhone && active >= 0 && active < matches.length ? optionId(active) : void 0;
|
|
399
|
+
useActiveOptionScroll(activeId);
|
|
347
400
|
const close = () => {
|
|
348
401
|
setOpen(false);
|
|
349
402
|
setActive(-1);
|
|
@@ -368,180 +421,196 @@ function InlineEntityCombobox({
|
|
|
368
421
|
}
|
|
369
422
|
close();
|
|
370
423
|
};
|
|
371
|
-
return
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
"
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
setText(e.target.value);
|
|
402
|
-
setOpen(true);
|
|
403
|
-
setActive(-1);
|
|
404
|
-
},
|
|
405
|
-
onKeyDown: (e) => {
|
|
406
|
-
if (e.key === "ArrowDown") {
|
|
407
|
-
e.preventDefault();
|
|
424
|
+
return (
|
|
425
|
+
// `rest` dresses the outer box — a `data-tour` anchor, a test id, a form-level
|
|
426
|
+
// `aria-describedby`. Not the NAME: that belongs on the <input> below, which is
|
|
427
|
+
// the combobox a reader meets. Spread FIRST, so the field's ARIA and the
|
|
428
|
+
// handlers carrying live #309 and dev#549 cannot be replaced from outside.
|
|
429
|
+
/* @__PURE__ */ jsxs("div", { ...rest, ref: wrapperRef, className: cn("relative", className), children: [
|
|
430
|
+
label !== void 0 && /* @__PURE__ */ jsx(FieldLabel, { children: label }),
|
|
431
|
+
/* @__PURE__ */ jsxs("div", { ref: fieldRef, className: "relative", children: [
|
|
432
|
+
/* @__PURE__ */ jsx(
|
|
433
|
+
"input",
|
|
434
|
+
{
|
|
435
|
+
id: fieldId,
|
|
436
|
+
value: shown,
|
|
437
|
+
placeholder,
|
|
438
|
+
"aria-label": ariaLabel ?? (typeof label === "string" ? label : void 0),
|
|
439
|
+
role: "combobox",
|
|
440
|
+
"aria-expanded": open,
|
|
441
|
+
"aria-controls": listboxId,
|
|
442
|
+
"aria-activedescendant": activeId,
|
|
443
|
+
"aria-autocomplete": "list",
|
|
444
|
+
"aria-invalid": invalid || void 0,
|
|
445
|
+
autoComplete: "off",
|
|
446
|
+
disabled,
|
|
447
|
+
autoFocus,
|
|
448
|
+
inputMode: isPhone ? "none" : void 0,
|
|
449
|
+
onMouseDown: primaryOnly.onMouseDown,
|
|
450
|
+
onFocus: (e) => {
|
|
451
|
+
if (primaryOnly.fromAuxButton()) return;
|
|
452
|
+
setText(shown);
|
|
453
|
+
e.currentTarget.select();
|
|
408
454
|
setOpen(true);
|
|
409
|
-
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
}
|
|
414
|
-
|
|
455
|
+
if (isPhone) sheetInputRef.current?.focus();
|
|
456
|
+
},
|
|
457
|
+
onBlur: () => {
|
|
458
|
+
if (!isPhone) reconcile();
|
|
459
|
+
},
|
|
460
|
+
onChange: (e) => {
|
|
461
|
+
setText(e.target.value);
|
|
462
|
+
setOpen(true);
|
|
463
|
+
setActive(-1);
|
|
464
|
+
},
|
|
465
|
+
onKeyDown: (e) => {
|
|
466
|
+
if (e.key === "ArrowDown") {
|
|
415
467
|
e.preventDefault();
|
|
416
|
-
|
|
417
|
-
|
|
468
|
+
setOpen(true);
|
|
469
|
+
setActive((i) => Math.min(i + 1, matches.length - 1));
|
|
470
|
+
} else if (e.key === "ArrowUp") {
|
|
471
|
+
e.preventDefault();
|
|
472
|
+
setActive((i) => Math.max(i - 1, 0));
|
|
473
|
+
} else if (e.key === "Enter") {
|
|
474
|
+
if (open && active >= 0 && active < matches.length) {
|
|
475
|
+
e.preventDefault();
|
|
476
|
+
commit(matches[active]);
|
|
477
|
+
} else {
|
|
478
|
+
reconcile();
|
|
479
|
+
}
|
|
480
|
+
} else if (e.key === "Escape") {
|
|
481
|
+
setText(null);
|
|
482
|
+
close();
|
|
483
|
+
} else if (e.key === "Tab") {
|
|
418
484
|
reconcile();
|
|
419
485
|
}
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
close();
|
|
423
|
-
}
|
|
424
|
-
},
|
|
425
|
-
className: cn(FIELD_BASE, label !== void 0 && FIELD_FLOATING_PAD, "pr-9", invalid && FIELD_INVALID)
|
|
426
|
-
}
|
|
427
|
-
),
|
|
428
|
-
showClear ? /* @__PURE__ */ jsx(
|
|
429
|
-
"button",
|
|
430
|
-
{
|
|
431
|
-
type: "button",
|
|
432
|
-
tabIndex: -1,
|
|
433
|
-
"aria-label": clearLabel ?? "Clear",
|
|
434
|
-
onMouseDown: (e) => e.preventDefault(),
|
|
435
|
-
onClick: () => {
|
|
436
|
-
setText(null);
|
|
437
|
-
close();
|
|
438
|
-
onChange(null);
|
|
439
|
-
},
|
|
440
|
-
className: cn(
|
|
441
|
-
"absolute right-2 top-1/2 -translate-y-1/2 rounded p-0.5 text-slate-400",
|
|
442
|
-
"hover:text-slate-600 dark:text-slate-500 dark:hover:text-slate-300"
|
|
443
|
-
),
|
|
444
|
-
children: /* @__PURE__ */ jsx(X, { "aria-hidden": true, className: "size-4" })
|
|
445
|
-
}
|
|
446
|
-
) : /* @__PURE__ */ jsx(
|
|
447
|
-
ChevronDown,
|
|
448
|
-
{
|
|
449
|
-
"aria-hidden": true,
|
|
450
|
-
onMouseDown: (e) => {
|
|
451
|
-
e.preventDefault();
|
|
452
|
-
setOpen((o) => !o);
|
|
453
|
-
},
|
|
454
|
-
className: cn(
|
|
455
|
-
"absolute right-2.5 top-1/2 size-4 -translate-y-1/2 text-slate-400 dark:text-slate-500",
|
|
456
|
-
disabled ? "opacity-50" : "cursor-pointer"
|
|
457
|
-
)
|
|
458
|
-
}
|
|
459
|
-
)
|
|
460
|
-
] }),
|
|
461
|
-
isPhone && /* @__PURE__ */ jsx(
|
|
462
|
-
PickerSheet,
|
|
463
|
-
{
|
|
464
|
-
open,
|
|
465
|
-
onClose: reconcile,
|
|
466
|
-
title: label,
|
|
467
|
-
query: sheetQuery,
|
|
468
|
-
onQueryChange: (v) => {
|
|
469
|
-
setSheetQuery(v);
|
|
470
|
-
setActive(-1);
|
|
471
|
-
},
|
|
472
|
-
searchPlaceholder: searchPlaceholder ?? placeholder,
|
|
473
|
-
inputRef: sheetInputRef,
|
|
474
|
-
closeLabel,
|
|
475
|
-
children: /* @__PURE__ */ jsxs("ul", { role: "listbox", children: [
|
|
476
|
-
matches.map((o, i) => (
|
|
477
|
-
// Keyed by group AND value, like combobox-core.tsx: an option may
|
|
478
|
-
// deliberately appear twice (see `reconcile`), and a bare value key
|
|
479
|
-
// would collide.
|
|
480
|
-
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
481
|
-
o.group && o.group !== matches[i - 1]?.group && /* @__PURE__ */ jsx(
|
|
482
|
-
"li",
|
|
483
|
-
{
|
|
484
|
-
role: "presentation",
|
|
485
|
-
className: "px-4 pb-0.5 pt-3 text-[11px] font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400",
|
|
486
|
-
children: o.group
|
|
487
|
-
}
|
|
488
|
-
),
|
|
489
|
-
/* @__PURE__ */ jsx("li", { role: "option", "aria-selected": o.value === value, children: /* @__PURE__ */ jsx(
|
|
490
|
-
"button",
|
|
491
|
-
{
|
|
492
|
-
type: "button",
|
|
493
|
-
onClick: () => commit(o),
|
|
494
|
-
className: cn(SHEET_ROW_CLASS, o.value === value && "font-medium"),
|
|
495
|
-
children: o.label
|
|
496
|
-
}
|
|
497
|
-
) })
|
|
498
|
-
] }, `${o.group ?? ""}|${String(o.value)}`)
|
|
499
|
-
)),
|
|
500
|
-
matches.length === 0 && emptyLabel && /* @__PURE__ */ jsx("li", { className: "px-4 py-3 text-sm text-slate-500 dark:text-slate-400", children: emptyLabel })
|
|
501
|
-
] })
|
|
502
|
-
}
|
|
503
|
-
),
|
|
504
|
-
!isPhone && open && matches.length > 0 && /* @__PURE__ */ jsx(SuggestionList, { anchorRef: fieldRef, panelRef, children: matches.map((o, i) => (
|
|
505
|
-
// A group heading is emitted at each group boundary rather than repeating
|
|
506
|
-
// the group on every row (feedback #136). `matches` is group-contiguous,
|
|
507
|
-
// so comparing with the previous row is enough. Fragment key sits here;
|
|
508
|
-
// the heading and the option carry their own list semantics — keyed by
|
|
509
|
-
// group AND value, because an option may deliberately appear twice (see
|
|
510
|
-
// `reconcile`).
|
|
511
|
-
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
512
|
-
o.group && o.group !== matches[i - 1]?.group && /* @__PURE__ */ jsx(
|
|
513
|
-
"li",
|
|
514
|
-
{
|
|
515
|
-
role: "presentation",
|
|
516
|
-
className: "px-3 pb-0.5 pt-2 text-[11px] font-semibold uppercase tracking-wide text-slate-500 first:pt-1 dark:text-slate-400",
|
|
517
|
-
children: o.group
|
|
486
|
+
},
|
|
487
|
+
className: cn(FIELD_BASE, label !== void 0 && FIELD_FLOATING_PAD, "pr-9", invalid && FIELD_INVALID)
|
|
518
488
|
}
|
|
519
489
|
),
|
|
520
|
-
|
|
490
|
+
showClear ? /* @__PURE__ */ jsx(
|
|
521
491
|
"button",
|
|
522
492
|
{
|
|
523
493
|
type: "button",
|
|
494
|
+
tabIndex: -1,
|
|
495
|
+
"aria-label": labels.clear,
|
|
496
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
497
|
+
onClick: () => {
|
|
498
|
+
setText(null);
|
|
499
|
+
close();
|
|
500
|
+
onChange(null);
|
|
501
|
+
},
|
|
502
|
+
className: cn(
|
|
503
|
+
"absolute right-2 top-1/2 -translate-y-1/2 rounded p-0.5 text-[var(--text-placeholder)]",
|
|
504
|
+
"hover:text-[var(--text-secondary)]"
|
|
505
|
+
),
|
|
506
|
+
children: /* @__PURE__ */ jsx(X, { "aria-hidden": true, className: "size-4" })
|
|
507
|
+
}
|
|
508
|
+
) : /* @__PURE__ */ jsx(
|
|
509
|
+
ChevronDown,
|
|
510
|
+
{
|
|
511
|
+
"aria-hidden": true,
|
|
524
512
|
onMouseDown: (e) => {
|
|
525
513
|
e.preventDefault();
|
|
526
|
-
|
|
514
|
+
setOpen((o) => !o);
|
|
527
515
|
},
|
|
528
|
-
onMouseEnter: () => setActive(i),
|
|
529
516
|
className: cn(
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
o.group && "pl-6",
|
|
534
|
-
o.value === value && "font-medium"
|
|
535
|
-
),
|
|
536
|
-
children: [
|
|
537
|
-
o.label,
|
|
538
|
-
o.sublabel && /* @__PURE__ */ jsx("span", { className: "ml-2 text-xs text-slate-400 dark:text-slate-500", children: o.sublabel })
|
|
539
|
-
]
|
|
517
|
+
"absolute right-2.5 top-1/2 size-4 -translate-y-1/2 text-[var(--text-placeholder)]",
|
|
518
|
+
disabled ? "opacity-50" : "cursor-pointer"
|
|
519
|
+
)
|
|
540
520
|
}
|
|
541
|
-
)
|
|
542
|
-
] },
|
|
543
|
-
|
|
544
|
-
|
|
521
|
+
)
|
|
522
|
+
] }),
|
|
523
|
+
isPhone && /* @__PURE__ */ jsx(
|
|
524
|
+
PickerSheet,
|
|
525
|
+
{
|
|
526
|
+
open,
|
|
527
|
+
onClose: reconcile,
|
|
528
|
+
title: label,
|
|
529
|
+
query: sheetQuery,
|
|
530
|
+
onQueryChange: (v) => {
|
|
531
|
+
setSheetQuery(v);
|
|
532
|
+
setActive(-1);
|
|
533
|
+
},
|
|
534
|
+
searchPlaceholder: searchPlaceholder ?? placeholder ?? labels.search,
|
|
535
|
+
inputRef: sheetInputRef,
|
|
536
|
+
closeLabel,
|
|
537
|
+
children: /* @__PURE__ */ jsxs("ul", { id: listboxId, role: "listbox", children: [
|
|
538
|
+
matches.map((o, i) => (
|
|
539
|
+
// Keyed by group AND value, like combobox-core.tsx: an option may
|
|
540
|
+
// deliberately appear twice (see `reconcile`), and a bare value key
|
|
541
|
+
// would collide.
|
|
542
|
+
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
543
|
+
o.group && o.group !== matches[i - 1]?.group && /* @__PURE__ */ jsx(
|
|
544
|
+
"li",
|
|
545
|
+
{
|
|
546
|
+
role: "presentation",
|
|
547
|
+
className: "px-4 pb-0.5 pt-3 text-[11px] font-semibold uppercase tracking-wide text-[var(--text-muted)]",
|
|
548
|
+
children: o.group
|
|
549
|
+
}
|
|
550
|
+
),
|
|
551
|
+
/* @__PURE__ */ jsx("li", { role: "presentation", children: /* @__PURE__ */ jsx(
|
|
552
|
+
"button",
|
|
553
|
+
{
|
|
554
|
+
type: "button",
|
|
555
|
+
role: "option",
|
|
556
|
+
"aria-selected": o.value === value,
|
|
557
|
+
onClick: () => commit(o),
|
|
558
|
+
className: cn(SHEET_ROW_CLASS, o.value === value && "font-medium"),
|
|
559
|
+
children: o.label
|
|
560
|
+
}
|
|
561
|
+
) })
|
|
562
|
+
] }, `${o.group ?? ""}|${String(o.value)}`)
|
|
563
|
+
)),
|
|
564
|
+
matches.length === 0 && /* @__PURE__ */ jsx("li", { className: "px-4 py-3 text-sm text-[var(--text-muted)]", children: labels.noResults })
|
|
565
|
+
] })
|
|
566
|
+
}
|
|
567
|
+
),
|
|
568
|
+
!isPhone && open && matches.length > 0 && /* @__PURE__ */ jsx(SuggestionList, { id: listboxId, anchorRef: fieldRef, panelRef, children: matches.map((o, i) => (
|
|
569
|
+
// A group heading is emitted at each group boundary rather than repeating
|
|
570
|
+
// the group on every row (feedback #136). `matches` is group-contiguous,
|
|
571
|
+
// so comparing with the previous row is enough. Fragment key sits here;
|
|
572
|
+
// the heading and the option carry their own list semantics — keyed by
|
|
573
|
+
// group AND value, because an option may deliberately appear twice (see
|
|
574
|
+
// `reconcile`).
|
|
575
|
+
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
576
|
+
o.group && o.group !== matches[i - 1]?.group && /* @__PURE__ */ jsx(
|
|
577
|
+
"li",
|
|
578
|
+
{
|
|
579
|
+
role: "presentation",
|
|
580
|
+
className: "px-3 pb-0.5 pt-2 text-[11px] font-semibold uppercase tracking-wide text-[var(--text-muted)] first:pt-1",
|
|
581
|
+
children: o.group
|
|
582
|
+
}
|
|
583
|
+
),
|
|
584
|
+
/* @__PURE__ */ jsx("li", { role: "presentation", children: /* @__PURE__ */ jsxs(
|
|
585
|
+
"button",
|
|
586
|
+
{
|
|
587
|
+
type: "button",
|
|
588
|
+
id: optionId(i),
|
|
589
|
+
role: "option",
|
|
590
|
+
"aria-selected": o.value === value,
|
|
591
|
+
tabIndex: -1,
|
|
592
|
+
onMouseDown: (e) => {
|
|
593
|
+
e.preventDefault();
|
|
594
|
+
commit(o);
|
|
595
|
+
},
|
|
596
|
+
onMouseEnter: () => setActive(i),
|
|
597
|
+
className: cn(
|
|
598
|
+
rowClass(i === active),
|
|
599
|
+
// Indented under its heading, so the hierarchy is readable at a
|
|
600
|
+
// glance instead of inferred from grey trailing text.
|
|
601
|
+
o.group && "pl-6",
|
|
602
|
+
o.value === value && "font-medium"
|
|
603
|
+
),
|
|
604
|
+
children: [
|
|
605
|
+
o.label,
|
|
606
|
+
o.sublabel && /* @__PURE__ */ jsx("span", { className: "ml-2 text-xs text-[var(--text-placeholder)]", children: o.sublabel })
|
|
607
|
+
]
|
|
608
|
+
}
|
|
609
|
+
) })
|
|
610
|
+
] }, `${o.group ?? ""}|${String(o.value)}`)
|
|
611
|
+
)) })
|
|
612
|
+
] })
|
|
613
|
+
);
|
|
545
614
|
}
|
|
546
615
|
export {
|
|
547
616
|
Combobox,
|