@k2b/ui 0.40.0 → 0.42.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/dist/base.css +22 -0
- package/dist/browser/actions/Dropdown.js +220 -110
- package/dist/browser/actions/Dropdown.js.map +1 -1
- package/dist/browser/actions/index.js.map +1 -1
- package/dist/browser/actions/menu-search.js +166 -0
- package/dist/browser/actions/menu-search.js.map +1 -0
- package/dist/browser/actions/menu-sheet.js +107 -13
- package/dist/browser/actions/menu-sheet.js.map +1 -1
- package/dist/browser/chat/ChatComposer.js +759 -570
- package/dist/browser/chat/ChatComposer.js.map +1 -1
- package/dist/browser/content/CalendarWeekView.js +13 -1
- package/dist/browser/content/CalendarWeekView.js.map +1 -1
- package/dist/browser/inputs/ChoiceGroups.js +30 -18
- package/dist/browser/inputs/ChoiceGroups.js.map +1 -1
- package/dist/browser/inputs/IconChoices.js +121 -0
- package/dist/browser/inputs/IconChoices.js.map +1 -0
- package/dist/browser/inputs/Select.js +32 -19
- package/dist/browser/inputs/Select.js.map +1 -1
- package/dist/browser/inputs/SpecialInputs.js +54 -25
- package/dist/browser/inputs/SpecialInputs.js.map +1 -1
- package/dist/browser/inputs/choice.js +4 -1
- package/dist/browser/inputs/choice.js.map +1 -1
- package/dist/browser/inputs/dictation/Dictation.js +546 -0
- package/dist/browser/inputs/dictation/Dictation.js.map +1 -0
- package/dist/browser/inputs/dictation/create-dictation.js +324 -0
- package/dist/browser/inputs/dictation/create-dictation.js.map +1 -0
- package/dist/browser/inputs/dictation/dictation-messages.js +115 -0
- package/dist/browser/inputs/dictation/dictation-messages.js.map +1 -0
- package/dist/browser/inputs/dictation/text-dictation.js +152 -0
- package/dist/browser/inputs/dictation/text-dictation.js.map +1 -0
- package/dist/browser/inputs/dictation/types.js +2 -0
- package/dist/browser/inputs/dictation/types.js.map +1 -0
- package/dist/browser/inputs/icon-messages.js +29 -2
- package/dist/browser/inputs/icon-messages.js.map +1 -1
- package/dist/browser/inputs/icon-texts.js +172 -0
- package/dist/browser/inputs/icon-texts.js.map +1 -0
- package/dist/browser/inputs/index.js +3 -0
- package/dist/browser/inputs/index.js.map +1 -1
- package/dist/browser/intl/messages.js +6 -0
- package/dist/browser/intl/messages.js.map +1 -1
- package/dist/browser/layout/AnchoredPopover.js +1 -1
- package/dist/browser/layout/AnchoredPopover.js.map +1 -1
- package/dist/browser/layout/AppWorkspace.js +118 -93
- package/dist/browser/layout/AppWorkspace.js.map +1 -1
- package/dist/browser/layout/SettingsModal.js +10 -5
- package/dist/browser/layout/SettingsModal.js.map +1 -1
- package/dist/browser/text-editor/TextEditor.js +74 -25
- package/dist/browser/text-editor/TextEditor.js.map +1 -1
- package/dist/browser/text-editor/dictation.js +166 -0
- package/dist/browser/text-editor/dictation.js.map +1 -0
- package/dist/browser/text-editor/format.js +11 -7
- package/dist/browser/text-editor/format.js.map +1 -1
- package/dist/browser/text-editor/table.js +39 -11
- package/dist/browser/text-editor/table.js.map +1 -1
- package/dist/browser/text-editor.js +2 -1
- package/dist/browser/text-editor.js.map +1 -1
- package/dist/ssr/actions/Dropdown.js +118 -40
- package/dist/ssr/actions/Dropdown.js.map +1 -1
- package/dist/ssr/actions/index.js.map +1 -1
- package/dist/ssr/actions/menu-search.js +113 -0
- package/dist/ssr/actions/menu-search.js.map +1 -0
- package/dist/ssr/actions/menu-sheet.js +82 -13
- package/dist/ssr/actions/menu-sheet.js.map +1 -1
- package/dist/ssr/chat/ChatComposer.js +271 -99
- package/dist/ssr/chat/ChatComposer.js.map +1 -1
- package/dist/ssr/content/CalendarWeekView.js +13 -1
- package/dist/ssr/content/CalendarWeekView.js.map +1 -1
- package/dist/ssr/inputs/ChoiceGroups.js +12 -3
- package/dist/ssr/inputs/ChoiceGroups.js.map +1 -1
- package/dist/ssr/inputs/IconChoices.js +59 -0
- package/dist/ssr/inputs/IconChoices.js.map +1 -0
- package/dist/ssr/inputs/Select.js +8 -2
- package/dist/ssr/inputs/Select.js.map +1 -1
- package/dist/ssr/inputs/SpecialInputs.js +54 -25
- package/dist/ssr/inputs/SpecialInputs.js.map +1 -1
- package/dist/ssr/inputs/choice.js +4 -1
- package/dist/ssr/inputs/choice.js.map +1 -1
- package/dist/ssr/inputs/dictation/Dictation.js +386 -0
- package/dist/ssr/inputs/dictation/Dictation.js.map +1 -0
- package/dist/ssr/inputs/dictation/create-dictation.js +324 -0
- package/dist/ssr/inputs/dictation/create-dictation.js.map +1 -0
- package/dist/ssr/inputs/dictation/dictation-messages.js +115 -0
- package/dist/ssr/inputs/dictation/dictation-messages.js.map +1 -0
- package/dist/ssr/inputs/dictation/text-dictation.js +152 -0
- package/dist/ssr/inputs/dictation/text-dictation.js.map +1 -0
- package/dist/ssr/inputs/dictation/types.js +2 -0
- package/dist/ssr/inputs/dictation/types.js.map +1 -0
- package/dist/ssr/inputs/icon-messages.js +29 -2
- package/dist/ssr/inputs/icon-messages.js.map +1 -1
- package/dist/ssr/inputs/icon-texts.js +172 -0
- package/dist/ssr/inputs/icon-texts.js.map +1 -0
- package/dist/ssr/inputs/index.js +3 -0
- package/dist/ssr/inputs/index.js.map +1 -1
- package/dist/ssr/intl/messages.js +6 -0
- package/dist/ssr/intl/messages.js.map +1 -1
- package/dist/ssr/layout/AnchoredPopover.js +1 -1
- package/dist/ssr/layout/AnchoredPopover.js.map +1 -1
- package/dist/ssr/layout/AppWorkspace.js +40 -20
- package/dist/ssr/layout/AppWorkspace.js.map +1 -1
- package/dist/ssr/layout/SettingsModal.js +10 -5
- package/dist/ssr/layout/SettingsModal.js.map +1 -1
- package/dist/ssr/text-editor/TextEditor.js +74 -25
- package/dist/ssr/text-editor/TextEditor.js.map +1 -1
- package/dist/ssr/text-editor/dictation.js +166 -0
- package/dist/ssr/text-editor/dictation.js.map +1 -0
- package/dist/ssr/text-editor/format.js +11 -7
- package/dist/ssr/text-editor/format.js.map +1 -1
- package/dist/ssr/text-editor/table.js +39 -11
- package/dist/ssr/text-editor/table.js.map +1 -1
- package/dist/ssr/text-editor.js +2 -1
- package/dist/ssr/text-editor.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/types/actions/Dropdown.d.ts +34 -3
- package/dist/types/actions/index.d.ts +1 -1
- package/dist/types/actions/menu-search.d.ts +27 -0
- package/dist/types/actions/menu-sheet.d.ts +5 -1
- package/dist/types/chat/ChatComposer.d.ts +9 -0
- package/dist/types/inputs/IconChoices.d.ts +19 -0
- package/dist/types/inputs/SpecialInputs.d.ts +8 -0
- package/dist/types/inputs/dictation/Dictation.d.ts +26 -0
- package/dist/types/inputs/dictation/create-dictation.d.ts +77 -0
- package/dist/types/inputs/dictation/dictation-messages.d.ts +54 -0
- package/dist/types/inputs/dictation/text-dictation.d.ts +36 -0
- package/dist/types/inputs/dictation/types.d.ts +74 -0
- package/dist/types/inputs/icon-messages.d.ts +14 -0
- package/dist/types/inputs/icon-texts.d.ts +13 -0
- package/dist/types/inputs/index.d.ts +7 -0
- package/dist/types/intl/messages.d.ts +3 -0
- package/dist/types/layout/AnchoredPopover.d.ts +5 -0
- package/dist/types/layout/AppWorkspace.d.ts +6 -1
- package/dist/types/text-editor/TextEditor.d.ts +10 -1
- package/dist/types/text-editor/dictation.d.ts +20 -0
- package/dist/types/text-editor/table.d.ts +2 -0
- package/dist/types/text-editor.d.ts +2 -1
- package/package.json +3 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["inputs/ChoiceGroups.tsx"],"sourcesContent":["import { createEffect, createSignal, For, type JSX, onCleanup, onMount, Show } from \"solid-js\";\nimport { suppressTextSelection } from \"../internal/text-selection\";\n\ntype ChoiceGroup = { value: string | null; label: string; icon?: string };\n\n/**\n * A single-choice row of chips that scrolls sideways instead of wrapping, so its height never changes. Select and\n * MultiSelect use it for their filters; `ChoiceChips` is the public field around it.\n */\nexport function ChoiceGroups(props: {\n choices: readonly ChoiceGroup[];\n value: string | null;\n onValueChange: (value: string | null) => void;\n ariaLabel?: string;\n /** The field label that names the group; replaces `ariaLabel`. */\n labelledBy?: string;\n describedBy?: string;\n controls?: string;\n disabled?: boolean;\n}): JSX.Element {\n let viewport: HTMLDivElement | undefined;\n let buttons: HTMLButtonElement[] = [];\n let dragOffset = 0;\n const [scrollbar, setScrollbar] = createSignal({ overflow: false, left: 0, width: 0 });\n\n const syncScrollbar = () => {\n if (!viewport) return;\n const { clientWidth, scrollLeft, scrollWidth } = viewport;\n if (clientWidth <= 0 || scrollWidth <= clientWidth) {\n setScrollbar({ overflow: false, left: 0, width: 0 });\n return;\n }\n const width = Math.min(clientWidth, Math.max(24, (clientWidth * clientWidth) / scrollWidth));\n const left = (scrollLeft / (scrollWidth - clientWidth)) * (clientWidth - width);\n setScrollbar({ overflow: true, left, width });\n };\n\n // With no matching choice the first chip takes the tab stop, so the group stays reachable by keyboard.\n const tabStop = (value: string | null, index: number) =>\n props.value === value || (index === 0 && !props.choices.some((choice) => choice.value === props.value));\n const choose = (index: number, focus = false) => {\n const choice = props.choices[index];\n if (!choice || props.disabled) return;\n props.onValueChange(choice.value);\n if (!focus) return;\n queueMicrotask(() => {\n buttons[index]?.focus();\n buttons[index]?.scrollIntoView({ block: \"nearest\", inline: \"nearest\" });\n });\n };\n const move = (index: number, direction: 1 | -1) => choose((index + direction + props.choices.length) % props.choices.length, true);\n const focusEdge = (last: boolean) => choose(last ? props.choices.length - 1 : 0, true);\n\n const scrollFromPointer = (event: PointerEvent & { currentTarget: HTMLDivElement }) => {\n if (!viewport) return;\n const track = event.currentTarget;\n const { width } = scrollbar();\n const rect = track.getBoundingClientRect();\n const available = Math.max(1, rect.width - width);\n const thumbLeft = Math.min(available, Math.max(0, event.clientX - rect.left - dragOffset));\n viewport.scrollLeft = (thumbLeft / available) * (viewport.scrollWidth - viewport.clientWidth);\n syncScrollbar();\n };\n const startScrollbarDrag = (event: PointerEvent & { currentTarget: HTMLDivElement }) => {\n if (event.button !== 0) return;\n event.preventDefault();\n const track = event.currentTarget;\n const current = scrollbar();\n dragOffset =\n event.target === track\n ? current.width / 2\n : Math.min(current.width, Math.max(0, event.clientX - track.getBoundingClientRect().left - current.left));\n track.setPointerCapture(event.pointerId);\n // The track's own pointerup or pointercancel ends the hold.\n suppressTextSelection(event.pointerId);\n scrollFromPointer(event);\n };\n\n onMount(() => {\n syncScrollbar();\n const observer = typeof ResizeObserver === \"undefined\" ? null : new ResizeObserver(syncScrollbar);\n if (viewport) observer?.observe(viewport);\n onCleanup(() => observer?.disconnect());\n });\n createEffect(() => {\n props.choices.map((choice) => `${choice.value ?? \"\"}:${choice.label}`).join(\"|\");\n queueMicrotask(syncScrollbar);\n });\n\n return (\n <div class=\"k2b-choice-groups-shell\" onPointerEnter={syncScrollbar} onFocusIn={syncScrollbar}>\n <div\n ref={viewport}\n class=\"k2b-choice-groups\"\n role=\"radiogroup\"\n aria-label={props.labelledBy ? undefined : props.ariaLabel}\n aria-labelledby={props.labelledBy}\n aria-describedby={props.describedBy}\n aria-disabled={props.disabled ? \"true\" : undefined}\n onScroll={syncScrollbar}\n >\n <For each={props.choices}>\n {(group, index) => (\n <button\n ref={(element) => (buttons[index()] = element)}\n type=\"button\"\n role=\"radio\"\n aria-checked={props.value === group.value}\n aria-controls={props.controls}\n disabled={props.disabled}\n tabIndex={tabStop(group.value, index()) ? 0 : -1}\n onClick={() => choose(index())}\n onKeyDown={(event) => {\n if (event.key === \"ArrowRight\" || event.key === \"ArrowDown\") {\n event.preventDefault();\n move(index(), 1);\n } else if (event.key === \"ArrowLeft\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n move(index(), -1);\n } else if (event.key === \"Home\" || event.key === \"End\") {\n event.preventDefault();\n focusEdge(event.key === \"End\");\n }\n }}\n >\n {group.icon && <i class={group.icon} aria-hidden=\"true\" />}\n {group.label}\n </button>\n )}\n </For>\n </div>\n <Show when={scrollbar().overflow}>\n <div\n class=\"k2b-choice-groups-scrollbar\"\n aria-hidden=\"true\"\n onPointerDown={startScrollbarDrag}\n onPointerMove={(event) => {\n if (event.currentTarget.hasPointerCapture(event.pointerId)) scrollFromPointer(event);\n }}\n onPointerUp={(event) => event.currentTarget.releasePointerCapture(event.pointerId)}\n onPointerCancel={(event) => event.currentTarget.releasePointerCapture(event.pointerId)}\n >\n <span\n style={{\n \"--k2b-choice-scroll-left\": `${scrollbar().left}px`,\n \"--k2b-choice-scroll-width\": `${scrollbar().width}px`,\n }}\n />\n </div>\n </Show>\n </div>\n );\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["inputs/ChoiceGroups.tsx"],"sourcesContent":["import { createEffect, createSignal, For, type JSX, onCleanup, onMount, Show } from \"solid-js\";\nimport { suppressTextSelection } from \"../internal/text-selection\";\n\ntype ChoiceGroup = { value: string | null; label: string; icon?: string };\n\n/**\n * A single-choice row of chips that scrolls sideways instead of wrapping, so its height never changes. Select and\n * MultiSelect use it for their filters; `ChoiceChips` is the public field around it.\n */\nexport function ChoiceGroups(props: {\n choices: readonly ChoiceGroup[];\n value: string | null;\n onValueChange: (value: string | null) => void;\n ariaLabel?: string;\n /** The field label that names the group; replaces `ariaLabel`. */\n labelledBy?: string;\n describedBy?: string;\n controls?: string;\n disabled?: boolean;\n}): JSX.Element {\n let viewport: HTMLDivElement | undefined;\n let buttons: HTMLButtonElement[] = [];\n let dragOffset = 0;\n const [scrollbar, setScrollbar] = createSignal({ overflow: false, left: 0, width: 0 });\n\n const syncScrollbar = () => {\n if (!viewport) return;\n const { clientWidth, scrollLeft, scrollWidth } = viewport;\n if (clientWidth <= 0 || scrollWidth <= clientWidth) {\n setScrollbar({ overflow: false, left: 0, width: 0 });\n return;\n }\n const width = Math.min(clientWidth, Math.max(24, (clientWidth * clientWidth) / scrollWidth));\n const left = (scrollLeft / (scrollWidth - clientWidth)) * (clientWidth - width);\n setScrollbar({ overflow: true, left, width });\n };\n\n const overflowEdges = () => {\n const { overflow, left, width } = scrollbar();\n if (!overflow || !viewport) return undefined;\n const edges = [left > 0.5 ? \"start\" : \"\", left + width < viewport.clientWidth - 0.5 ? \"end\" : \"\"].filter(Boolean).join(\" \");\n return edges || undefined;\n };\n // With no matching choice the first chip takes the tab stop, so the group stays reachable by keyboard.\n const tabStop = (value: string | null, index: number) =>\n props.value === value || (index === 0 && !props.choices.some((choice) => choice.value === props.value));\n const choose = (index: number, focus = false) => {\n const choice = props.choices[index];\n if (!choice || props.disabled) return;\n props.onValueChange(choice.value);\n if (!focus) return;\n queueMicrotask(() => {\n buttons[index]?.focus();\n buttons[index]?.scrollIntoView({ block: \"nearest\", inline: \"nearest\" });\n });\n };\n const move = (index: number, direction: 1 | -1) => choose((index + direction + props.choices.length) % props.choices.length, true);\n const focusEdge = (last: boolean) => choose(last ? props.choices.length - 1 : 0, true);\n\n const scrollFromPointer = (event: PointerEvent & { currentTarget: HTMLDivElement }) => {\n if (!viewport) return;\n const track = event.currentTarget;\n const { width } = scrollbar();\n const rect = track.getBoundingClientRect();\n const available = Math.max(1, rect.width - width);\n const thumbLeft = Math.min(available, Math.max(0, event.clientX - rect.left - dragOffset));\n viewport.scrollLeft = (thumbLeft / available) * (viewport.scrollWidth - viewport.clientWidth);\n syncScrollbar();\n };\n const startScrollbarDrag = (event: PointerEvent & { currentTarget: HTMLDivElement }) => {\n if (event.button !== 0) return;\n event.preventDefault();\n const track = event.currentTarget;\n const current = scrollbar();\n dragOffset =\n event.target === track\n ? current.width / 2\n : Math.min(current.width, Math.max(0, event.clientX - track.getBoundingClientRect().left - current.left));\n track.setPointerCapture(event.pointerId);\n // The track's own pointerup or pointercancel ends the hold.\n suppressTextSelection(event.pointerId);\n scrollFromPointer(event);\n };\n\n onMount(() => {\n syncScrollbar();\n const observer = typeof ResizeObserver === \"undefined\" ? null : new ResizeObserver(syncScrollbar);\n if (viewport) observer?.observe(viewport);\n onCleanup(() => observer?.disconnect());\n });\n createEffect(() => {\n props.choices.map((choice) => `${choice.value ?? \"\"}:${choice.label}`).join(\"|\");\n queueMicrotask(syncScrollbar);\n });\n\n return (\n <div class=\"k2b-choice-groups-shell\" data-overflow={overflowEdges()} onPointerEnter={syncScrollbar} onFocusIn={syncScrollbar}>\n <div\n ref={viewport}\n class=\"k2b-choice-groups\"\n role=\"radiogroup\"\n aria-label={props.labelledBy ? undefined : props.ariaLabel}\n aria-labelledby={props.labelledBy}\n aria-describedby={props.describedBy}\n aria-disabled={props.disabled ? \"true\" : undefined}\n onScroll={syncScrollbar}\n >\n <For each={props.choices}>\n {(group, index) => (\n <button\n ref={(element) => (buttons[index()] = element)}\n type=\"button\"\n role=\"radio\"\n aria-checked={props.value === group.value}\n aria-controls={props.controls}\n disabled={props.disabled}\n tabIndex={tabStop(group.value, index()) ? 0 : -1}\n onClick={() => choose(index())}\n onKeyDown={(event) => {\n if (event.key === \"ArrowRight\" || event.key === \"ArrowDown\") {\n event.preventDefault();\n move(index(), 1);\n } else if (event.key === \"ArrowLeft\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n move(index(), -1);\n } else if (event.key === \"Home\" || event.key === \"End\") {\n event.preventDefault();\n focusEdge(event.key === \"End\");\n }\n }}\n >\n {group.icon && <i class={group.icon} aria-hidden=\"true\" />}\n {group.label}\n </button>\n )}\n </For>\n </div>\n <Show when={scrollbar().overflow}>\n <div\n class=\"k2b-choice-groups-scrollbar\"\n aria-hidden=\"true\"\n onPointerDown={startScrollbarDrag}\n onPointerMove={(event) => {\n if (event.currentTarget.hasPointerCapture(event.pointerId)) scrollFromPointer(event);\n }}\n onPointerUp={(event) => event.currentTarget.releasePointerCapture(event.pointerId)}\n onPointerCancel={(event) => event.currentTarget.releasePointerCapture(event.pointerId)}\n >\n <span\n style={{\n \"--k2b-choice-scroll-left\": `${scrollbar().left}px`,\n \"--k2b-choice-scroll-width\": `${scrollbar().width}px`,\n }}\n />\n </div>\n </Show>\n </div>\n );\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { ssr as _$ssr } from "solid-js/web";
|
|
2
|
+
import { createComponent as _$createComponent } from "solid-js/web";
|
|
3
|
+
import { ssrAttribute as _$ssrAttribute } from "solid-js/web";
|
|
4
|
+
import { escape as _$escape } from "solid-js/web";
|
|
5
|
+
var _tmpl$ = ["<div class=\"k2b-icon-choices__group\" role=\"radiogroup\"", ">", "</div>"],
|
|
6
|
+
_tmpl$2 = ["<button type=\"button\" role=\"radio\" class=\"k2b-icon-choices__option\"", "", "><i", " aria-hidden=\"true\"></i></button>"];
|
|
7
|
+
import { For } from "solid-js";
|
|
8
|
+
import { createFieldMeta, Field, fieldDescribedBy } from "../internal/field";
|
|
9
|
+
import { radioKeyTarget } from "../internal/radio-keys";
|
|
10
|
+
import { resolveMaybeAccessor } from "./field-contract";
|
|
11
|
+
/**
|
|
12
|
+
* A labeled single choice from a few named icons, shown as a row of icon buttons. Use `IconInput` when any icon of the
|
|
13
|
+
* catalogue is allowed.
|
|
14
|
+
*/
|
|
15
|
+
export function IconChoices(props) {
|
|
16
|
+
const meta = createFieldMeta(props.id);
|
|
17
|
+
let group;
|
|
18
|
+
const value = () => resolveMaybeAccessor(props.value) ?? null;
|
|
19
|
+
const tabStop = (option, index) => value() === option.value || index === 0 && !props.options.some(candidate => candidate.value === value());
|
|
20
|
+
const choose = (index, focus = false) => {
|
|
21
|
+
const option = props.options[index];
|
|
22
|
+
if (!option || props.disabled) return;
|
|
23
|
+
props.onValueChange?.(option.value);
|
|
24
|
+
props.onValueCommit?.(option.value);
|
|
25
|
+
// The radios in their current DOM order: options may have been reordered since they rendered.
|
|
26
|
+
if (focus) queueMicrotask(() => group?.querySelectorAll('[role="radio"]')[index]?.focus());
|
|
27
|
+
};
|
|
28
|
+
return _$createComponent(Field, {
|
|
29
|
+
meta: meta,
|
|
30
|
+
labelFor: false,
|
|
31
|
+
get ["class"]() {
|
|
32
|
+
return props.class;
|
|
33
|
+
},
|
|
34
|
+
get label() {
|
|
35
|
+
return props.label;
|
|
36
|
+
},
|
|
37
|
+
get description() {
|
|
38
|
+
return props.description;
|
|
39
|
+
},
|
|
40
|
+
get error() {
|
|
41
|
+
return props.error;
|
|
42
|
+
},
|
|
43
|
+
get required() {
|
|
44
|
+
return props.required;
|
|
45
|
+
},
|
|
46
|
+
get disabled() {
|
|
47
|
+
return props.disabled;
|
|
48
|
+
},
|
|
49
|
+
get children() {
|
|
50
|
+
return _$ssr(_tmpl$, _$ssrAttribute("aria-label", props.label ? _$escape(undefined, true) : _$escape(props["aria-label"], true), false) + _$ssrAttribute("aria-labelledby", props.label ? _$escape(meta.labelId, true) : _$escape(undefined, true), false) + _$ssrAttribute("aria-describedby", _$escape(fieldDescribedBy(meta, props), true), false) + _$ssrAttribute("aria-disabled", props.disabled ? "true" : _$escape(undefined, true), false), _$escape(_$createComponent(For, {
|
|
51
|
+
get each() {
|
|
52
|
+
return props.options;
|
|
53
|
+
},
|
|
54
|
+
children: (option, index) => _$ssr(_tmpl$2, _$ssrAttribute("aria-checked", _$escape(value(), true) === _$escape(option.value, true), false) + _$ssrAttribute("aria-label", _$escape(option.label, true), false) + _$ssrAttribute("title", _$escape(option.label, true), false), _$ssrAttribute("disabled", props.disabled, true) + _$ssrAttribute("tabindex", tabStop(option, index()) ? 0 : -1, false), _$ssrAttribute("class", _$escape(option.icon, true), false))
|
|
55
|
+
})));
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=IconChoices.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sources":["inputs/IconChoices.tsx"],"sourcesContent":["import { For, type JSX } from \"solid-js\";\nimport { createFieldMeta, Field, fieldDescribedBy } from \"../internal/field\";\nimport { radioKeyTarget } from \"../internal/radio-keys\";\nimport type { ValueFieldProps } from \"./field-contract\";\nimport { resolveMaybeAccessor } from \"./field-contract\";\n\nexport type IconChoiceOption<T extends string = string> = {\n value: T;\n /** What the icon shows; screen readers and the tooltip use it, so the picture is never the only signal. */\n label: string;\n /** An icon class, such as `ti ti-report`. */\n icon: string;\n};\n\nexport type IconChoicesProps<T extends string = string> = Omit<ValueFieldProps<T | null>, \"onValueChange\" | \"onValueCommit\"> & {\n options: readonly IconChoiceOption<T>[];\n onValueChange?: (value: T) => void;\n onValueCommit?: (value: T) => void;\n};\n\n/**\n * A labeled single choice from a few named icons, shown as a row of icon buttons. Use `IconInput` when any icon of the\n * catalogue is allowed.\n */\nexport function IconChoices<T extends string = string>(props: IconChoicesProps<T>): JSX.Element {\n const meta = createFieldMeta(props.id);\n let group: HTMLDivElement | undefined;\n const value = () => resolveMaybeAccessor(props.value) ?? null;\n const tabStop = (option: IconChoiceOption<T>, index: number) =>\n value() === option.value || (index === 0 && !props.options.some((candidate) => candidate.value === value()));\n const choose = (index: number, focus = false) => {\n const option = props.options[index];\n if (!option || props.disabled) return;\n props.onValueChange?.(option.value);\n props.onValueCommit?.(option.value);\n // The radios in their current DOM order: options may have been reordered since they rendered.\n if (focus) queueMicrotask(() => group?.querySelectorAll<HTMLButtonElement>('[role=\"radio\"]')[index]?.focus());\n };\n return (\n <Field\n meta={meta}\n labelFor={false}\n class={props.class}\n label={props.label}\n description={props.description}\n error={props.error}\n required={props.required}\n disabled={props.disabled}\n >\n <div\n class=\"k2b-icon-choices__group\"\n ref={group}\n role=\"radiogroup\"\n aria-label={props.label ? undefined : props[\"aria-label\"]}\n aria-labelledby={props.label ? meta.labelId : undefined}\n aria-describedby={fieldDescribedBy(meta, props)}\n aria-disabled={props.disabled ? \"true\" : undefined}\n >\n <For each={props.options}>\n {(option, index) => (\n <button\n type=\"button\"\n role=\"radio\"\n class=\"k2b-icon-choices__option\"\n aria-checked={value() === option.value}\n aria-label={option.label}\n title={option.label}\n disabled={props.disabled}\n tabIndex={tabStop(option, index()) ? 0 : -1}\n onClick={() => choose(index())}\n onKeyDown={(event) => {\n const target = radioKeyTarget(event.key, index(), props.options.length);\n if (target === undefined) return;\n event.preventDefault();\n choose(target, true);\n }}\n >\n <i class={option.icon} aria-hidden=\"true\" />\n </button>\n )}\n </For>\n </div>\n </Field>\n );\n}\n"],"mappings":";;;;;;AAAA,SAAS,GAAG,QAAkB,UAAU;AACxC,SAAS,eAAe,EAAE,KAAK,EAAE,gBAAgB,QAAQ,mBAAmB;AAC5E,SAAS,cAAc,QAAQ,wBAAwB;AAEvD,SAAS,oBAAoB,QAAQ,kBAAkB;AAgBvD;AACA;AACA;AACA;AACA,OAAO,SAAS,WAAW,CAA4B,KAA0B,EAAe;EAC9F,MAAM,IAAI,GAAG,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;EACtC,IAAI,KAAiC;EACrC,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,IAAI;EAC7D,MAAM,OAAO,GAAG,CAAC,MAA2B,EAAE,KAAa,KACzD,KAAK,CAAC,CAAC,KAAK,MAAM,CAAC,KAAK,IAAK,KAAK,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAE,SAAS,IAAK,SAAS,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC,CAAE;EAC9G,MAAM,MAAM,GAAG,CAAC,KAAa,EAAE,KAAK,GAAG,KAAK,KAAK;IAC/C,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;IACnC,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC,QAAQ,EAAE;IAC/B,KAAK,CAAC,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC;IACnC,KAAK,CAAC,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC;IACnC;IACA,IAAI,KAAK,EAAE,cAAc,CAAC,MAAM,KAAK,EAAE,gBAAgB,CAAoB,gBAAgB,CAAC,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;EAC/G,CAAC;EACD,yBACG,KAAK;IACJ,IAAI,EAAE,IAAI;IACV,QAAQ,EAAE,KAAK;IAAA;MAAA,OACR,KAAK,CAAC,KAAK;IAAA;IAAA,IAClB,KAAK;MAAA,OAAE,KAAK,CAAC,KAAK;IAAA;IAAA,IAClB,WAAW;MAAA,OAAE,KAAK,CAAC,WAAW;IAAA;IAAA,IAC9B,KAAK;MAAA,OAAE,KAAK,CAAC,KAAK;IAAA;IAAA,IAClB,QAAQ;MAAA,OAAE,KAAK,CAAC,QAAQ;IAAA;IAAA,IACxB,QAAQ;MAAA,OAAE,KAAK,CAAC,QAAQ;IAAA;IAAA;MAAA,kDAMV,KAAK,CAAC,KAAK,YAAG,SAAS,mBAAG,KAAK,CAAC,YAAY,CAAC,oDACxC,KAAK,CAAC,KAAK,YAAG,IAAI,CAAC,OAAO,mBAAG,SAAS,8DACrC,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,kDAChC,KAAK,CAAC,QAAQ,GAAG,MAAM,YAAG,SAAS,4CAEjD,GAAG;QAAA,IAAC,IAAI;UAAA,OAAE,KAAK,CAAC,OAAO;QAAA;QAAA,UACrB,CAAC,MAAM,EAAE,KAAK,mDAKG,cAAK,CAAC,CAAC,qBAAK,MAAM,CAAC,KAAK,wDAC1B,MAAM,CAAC,KAAK,mDACjB,MAAM,CAAC,KAAK,4CACT,KAAK,CAAC,QAAQ,qCACd,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,2CASjC,MAAM,CAAC,IAAI;MAExB;IAAA;EAAA;AAKX","ignoreList":[]}
|
|
@@ -13,7 +13,7 @@ var _tmpl$ = ["<span class=\"k2b-choice-trigger__value\"", ">", "</span>"],
|
|
|
13
13
|
_tmpl$5 = ["<button type=\"button\" class=\"k2b-choice-view-toggle\"", "><i", " aria-hidden=\"true\"></i></button>"],
|
|
14
14
|
_tmpl$6 = ["<div class=\"k2b-choice-toolbar\">", "", "</div>"],
|
|
15
15
|
_tmpl$7 = ["<div class=\"k2b-choice-status\"><i class=\"ti ti-loader-2 k2b-spin\" aria-hidden=\"true\"></i><span>", "</span></div>"],
|
|
16
|
-
_tmpl$8 = ["<div class=\"k2b-choice-control\"", ">", "", "", "<div popover=\"manual\" class=\"k2b-choice-popover\" role=\"group\"", ">", "", "<div", " class=\"k2b-choice-options\" role=\"listbox\"", ">", "", "", "</div></div></div>"],
|
|
16
|
+
_tmpl$8 = ["<div class=\"k2b-choice-control\"", ">", "", "", "<div popover=\"manual\" class=\"k2b-choice-popover\"", " role=\"group\"", ">", "", "<div", " class=\"k2b-choice-options\" role=\"listbox\"", ">", "", "", "</div></div></div>"],
|
|
17
17
|
_tmpl$9 = "<span class=\"k2b-choice-dot\" data-empty=\"true\" aria-hidden=\"true\"></span>",
|
|
18
18
|
_tmpl$0 = ["<i", " aria-hidden=\"true\"></i>"],
|
|
19
19
|
_tmpl$1 = ["<span class=\"k2b-choice-dot\" style=\"", "\" aria-hidden=\"true\"></span>"],
|
|
@@ -57,6 +57,8 @@ export function Select(props) {
|
|
|
57
57
|
const [cache, setCache] = createSignal({});
|
|
58
58
|
const [selectedGroup, setSelectedGroup] = createSignal(props.defaultGroup ?? null);
|
|
59
59
|
const [selectedView, setSelectedView] = createSignal(props.defaultView ?? "list");
|
|
60
|
+
// Whether the person picked the group, rather than seeing the default one.
|
|
61
|
+
let groupChosen = false;
|
|
60
62
|
let searchRef;
|
|
61
63
|
let optionRefs = [];
|
|
62
64
|
const value = () => resolveMaybeAccessor(props.value) ?? null;
|
|
@@ -116,6 +118,7 @@ export function Select(props) {
|
|
|
116
118
|
};
|
|
117
119
|
const move = direction => focus(nextEnabledChoiceIndex(listOptions(), focusedIndex(), direction));
|
|
118
120
|
const chooseGroup = group => {
|
|
121
|
+
groupChosen = true;
|
|
119
122
|
if (group === activeGroup()) return;
|
|
120
123
|
setSelectedGroup(group);
|
|
121
124
|
setFocusedIndex(nextEnabledChoiceIndex(listOptions(), -1, 1));
|
|
@@ -124,6 +127,9 @@ export function Select(props) {
|
|
|
124
127
|
const open = () => {
|
|
125
128
|
if (props.disabled) return;
|
|
126
129
|
setQuery("");
|
|
130
|
+
// A static list that only left its default group for a search starts
|
|
131
|
+
// there again; a group the person picked, or a remote filter, stays.
|
|
132
|
+
if (!isAsync() && !groupChosen) setSelectedGroup(props.defaultGroup ?? null);
|
|
127
133
|
if (isAsync()) loader.load("", true);
|
|
128
134
|
const selectedIndex = listOptions().findIndex(option => option.value === (value() ?? CLEAR_VALUE));
|
|
129
135
|
focus(selectedIndex >= 0 ? selectedIndex : nextEnabledChoiceIndex(listOptions(), -1, 1));
|
|
@@ -272,7 +278,7 @@ export function Select(props) {
|
|
|
272
278
|
get children() {
|
|
273
279
|
return _$ssr(_tmpl$3, _$ssrAttribute("aria-label", _$escape(messages().clearSelection, true), false));
|
|
274
280
|
}
|
|
275
|
-
})), _$ssrAttribute("aria-label", typeof props.label === "string" ? _$escape(props.label, true) : _$escape(props["aria-label"] ?? messages().options, true), false), _$escape(_$createComponent(Show, {
|
|
281
|
+
})), _$ssrAttribute("data-toolbar", (props.groups?.length ?? 0) > 0 || props.viewToggle ? "true" : _$escape(undefined, true), false), _$ssrAttribute("aria-label", typeof props.label === "string" ? _$escape(props.label, true) : _$escape(props["aria-label"] ?? messages().options, true), false), _$escape(_$createComponent(Show, {
|
|
276
282
|
get when() {
|
|
277
283
|
return isSearchable();
|
|
278
284
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["inputs/Select.tsx"],"sourcesContent":["import { createMemo, createSignal, For, type JSX, Show } from \"solid-js\";\nimport { createFieldMeta, Field, fieldControlAria } from \"../internal/field\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { ChoiceGroups } from \"./ChoiceGroups\";\nimport { type ChoiceOption, createChoiceLoader, createChoicePopover, filterChoiceOptions, nextEnabledChoiceIndex } from \"./choice\";\nimport type { ValueFieldProps } from \"./field-contract\";\nimport { commitFieldValue, resolveMaybeAccessor } from \"./field-contract\";\nimport { useSelectMessages } from \"./select-messages\";\n\nexport type SelectOption = ChoiceOption<string>;\nexport type SelectGroup = {\n value: string;\n label: string;\n};\nexport type SelectView = \"list\" | \"grid\";\nexport type SelectGridSize = \"sm\" | \"md\" | \"lg\";\n/**\n * `field` draws the boxed form control. `plain` shows the value as text for\n * property rows: no box, no chevron, and a quiet surface on hover or while\n * open. Its surface and hit area cover the nearest positioned ancestor, such as\n * a `DescriptionList` row, so the whole row opens the picker.\n */\nexport type ChoiceAppearance = \"field\" | \"plain\";\nexport type SelectSourceOption =\n | string\n | {\n id: string;\n label?: string;\n description?: string;\n icon?: string;\n color?: string;\n groups?: readonly string[];\n }\n | SelectOption;\n\nexport type SelectProps = ValueFieldProps<string | null> & {\n placeholder?: string;\n icon?: string;\n activeIcon?: string;\n options?: SelectSourceOption[];\n fetchData?: (query: string, signal: AbortSignal, group: string | null) => Promise<SelectSourceOption[]>;\n loadOptions?: (query: string, signal: AbortSignal, group: string | null) => Promise<readonly ChoiceOption<string>[]>;\n selectedOption?: ChoiceOption<string>;\n selectedLabel?: () => string | undefined;\n fetchDebounceMs?: number;\n debounceMs?: number;\n searchable?: boolean;\n /** Optional synchronous filter for static options. */\n filterOptions?: (options: readonly SelectOption[], query: string) => readonly SelectOption[];\n /** Optional filters. An option may belong to more than one group. */\n groups?: readonly SelectGroup[];\n /** Group selected when the component is created. Omit to start with all options. */\n defaultGroup?: string;\n groupsAriaLabel?: string;\n allGroupLabel?: string;\n /** Show a local list/grid layout toggle in the dropdown. */\n viewToggle?: boolean;\n /** Initial dropdown layout when `viewToggle` is enabled. */\n defaultView?: SelectView;\n /** Tile density for the grid layout. */\n gridSize?: SelectGridSize;\n searchPlaceholder?: string;\n clearable?: boolean;\n name?: string;\n appearance?: ChoiceAppearance;\n /** Icon class shown before the placeholder while nothing is selected. */\n placeholderIcon?: string;\n};\n\ntype NormalizedOption = ChoiceOption<string>;\n/** The list entry that clears a plain select. It cannot collide with a real option value. */\nconst CLEAR_VALUE = \"\\u0000k2b-select-clear\";\n\nconst normalize = (option: SelectSourceOption): NormalizedOption =>\n typeof option === \"string\"\n ? { value: option, label: option }\n : \"value\" in option\n ? option\n : { ...option, value: option.id, label: option.label || option.id };\n\nexport function Select(props: SelectProps): JSX.Element {\n const messages = useUiMessages();\n const selectMessages = useSelectMessages();\n const meta = createFieldMeta(props.id);\n const listboxId = `${meta.controlId}-listbox`;\n const [query, setQuery] = createSignal(\"\");\n const [focusedIndex, setFocusedIndex] = createSignal(-1);\n const [cache, setCache] = createSignal<Record<string, NormalizedOption>>({});\n const [selectedGroup, setSelectedGroup] = createSignal<string | null>(props.defaultGroup ?? null);\n const [selectedView, setSelectedView] = createSignal<SelectView>(props.defaultView ?? \"list\");\n let searchRef: HTMLInputElement | undefined;\n let optionRefs: HTMLButtonElement[] = [];\n const value = () => resolveMaybeAccessor(props.value) ?? null;\n const error = () => resolveMaybeAccessor(props.error);\n const activeGroup = createMemo(() => {\n const current = selectedGroup();\n return current && props.groups?.some((group) => group.value === current) ? current : null;\n });\n const groupChoices = createMemo(() => [{ value: null, label: props.allGroupLabel ?? messages().all }, ...(props.groups ?? [])]);\n const activeView = () => (props.viewToggle ? selectedView() : \"list\");\n\n const loader = createChoiceLoader(\n () =>\n props.fetchData\n ? async (value, signal) => (await props.fetchData!(value, signal, activeGroup())).map(normalize)\n : props.loadOptions\n ? (value, signal) => props.loadOptions!(value, signal, activeGroup())\n : undefined,\n () => props.fetchDebounceMs ?? props.debounceMs ?? 200,\n );\n const isAsync = () => Boolean(props.fetchData || props.loadOptions);\n const isSearchable = () => isAsync() || Boolean(props.searchable);\n const sourceOptions = createMemo(() => (isAsync() ? loader.options() : (props.options ?? []).map(normalize)));\n const groupedOptions = createMemo(() => {\n const group = activeGroup();\n return !isAsync() && group ? sourceOptions().filter((option) => option.groups?.includes(group)) : sourceOptions();\n });\n // Remote loaders filter server-side; a static list has to be filtered here or\n // the search field would render but do nothing.\n const options = createMemo(() =>\n isAsync() || !props.searchable\n ? groupedOptions()\n : props.filterOptions\n ? [...props.filterOptions(groupedOptions(), query())]\n : filterChoiceOptions(groupedOptions(), query()),\n );\n const plain = () => props.appearance === \"plain\";\n // A plain select has no room for a clear button beside its value, so\n // clearing becomes the last list entry, named by the placeholder.\n const clearOption = createMemo<NormalizedOption | undefined>(() =>\n plain() && props.clearable && !query() ? { value: CLEAR_VALUE, label: props.placeholder ?? messages().clearSelection } : undefined,\n );\n const listOptions = createMemo(() => {\n const clear = clearOption();\n return clear && !loader.error() ? [...options(), clear] : options();\n });\n // Colour dots mark the options, so an empty plain value keeps the column with a hollow dot.\n const emptyDot = () => plain() && !props.placeholderIcon && sourceOptions().some((option) => option.color);\n const selected = createMemo(() => {\n const current = value();\n if (current === null) return undefined;\n // Resolve against the unfiltered list so typing in the search field never\n // blanks the trigger label of the current selection.\n return (\n sourceOptions().find((option) => option.value === current) ??\n cache()[current] ??\n (props.selectedOption?.value === current ? props.selectedOption : undefined) ?? {\n value: current,\n label: props.selectedLabel?.() ?? current,\n }\n );\n });\n const hasClearAction = () => Boolean(props.clearable && selected() && !props.disabled && !plain());\n const accessibleLabel = () =>\n props[\"aria-label\"] ?? (typeof props.label === \"string\" ? undefined : (props.placeholder ?? selectMessages().selectOption));\n const popover = createChoicePopover(() => Boolean(props.disabled));\n const focusedOption = () => listOptions()[focusedIndex()];\n const focus = (index: number) => {\n setFocusedIndex(index);\n optionRefs[index]?.scrollIntoView({ block: \"nearest\" });\n };\n const move = (direction: 1 | -1) => focus(nextEnabledChoiceIndex(listOptions(), focusedIndex(), direction));\n const chooseGroup = (group: string | null) => {\n if (group === activeGroup()) return;\n setSelectedGroup(group);\n setFocusedIndex(nextEnabledChoiceIndex(listOptions(), -1, 1));\n if (isAsync()) loader.load(query(), true);\n };\n const open = () => {\n if (props.disabled) return;\n setQuery(\"\");\n if (isAsync()) loader.load(\"\", true);\n const selectedIndex = listOptions().findIndex((option) => option.value === (value() ?? CLEAR_VALUE));\n focus(selectedIndex >= 0 ? selectedIndex : nextEnabledChoiceIndex(listOptions(), -1, 1));\n popover.show();\n if (isSearchable()) queueMicrotask(() => searchRef?.focus());\n };\n const close = (restoreFocus = false) => {\n // Hide the top-layer surface before any reactive cleanup or consumer\n // callback can rerender its contents. Selection must feel atomic: the old\n // listbox must never remain visible with the next value.\n popover.hide(restoreFocus);\n loader.cancel();\n setQuery(\"\");\n setFocusedIndex(-1);\n };\n const select = (option: NormalizedOption) => {\n if (option.disabled) return;\n close(true);\n if (option.value === CLEAR_VALUE) {\n commitFieldValue(props, null);\n return;\n }\n setCache({ ...cache(), [option.value]: option });\n commitFieldValue(props, option.value);\n };\n const onKeyDown = (event: KeyboardEvent) => {\n const inToolbar = Boolean((event.target as HTMLElement | null)?.closest?.(\".k2b-choice-toolbar\"));\n if (inToolbar && event.key !== \"Escape\" && event.key !== \"Tab\") return;\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n if (!popover.open()) open();\n else move(event.key === \"ArrowDown\" ? 1 : -1);\n } else if ((event.key === \"Enter\" || event.key === \" \") && !popover.open()) {\n event.preventDefault();\n open();\n } else if (event.key === \"Enter\" && focusedOption()) {\n event.preventDefault();\n select(focusedOption()!);\n } else if (event.key === \"Escape\" && popover.open()) {\n // Only swallow Escape while the list is open — a closed select must let\n // the key bubble to an enclosing dialog or drawer.\n event.preventDefault();\n close(true);\n } else if (event.key === \"Tab\" && popover.open()) close();\n };\n const clear = (event: MouseEvent) => {\n event.stopPropagation();\n commitFieldValue(props, null);\n popover.trigger()?.focus();\n };\n\n return (\n <Field\n class={props.class}\n label={props.label}\n description={props.description}\n error={error()}\n meta={meta}\n required={props.required}\n disabled={props.disabled}\n >\n <div class=\"k2b-choice-control\" data-appearance={props.appearance ?? \"field\"} data-invalid={error() ? \"true\" : undefined}>\n <button\n ref={popover.setTrigger}\n id={meta.controlId}\n type=\"button\"\n class=\"k2b-choice-trigger\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n aria-expanded={popover.open()}\n aria-controls={listboxId}\n aria-activedescendant={focusedOption() ? `${listboxId}-${focusedIndex()}` : undefined}\n data-clearable={hasClearAction() ? \"true\" : undefined}\n {...fieldControlAria(meta, {\n ...props,\n \"aria-label\": accessibleLabel(),\n })}\n disabled={props.disabled}\n onClick={() => (popover.open() ? close() : open())}\n onKeyDown={onKeyDown}\n >\n <Show\n when={selected()}\n fallback={\n <Show\n when={props.placeholderIcon}\n fallback={<Show when={emptyDot()}>{<span class=\"k2b-choice-dot\" data-empty=\"true\" aria-hidden=\"true\" />}</Show>}\n >\n {(icon) => <i class={`${icon()} k2b-choice-trigger__placeholder-icon`} aria-hidden=\"true\" />}\n </Show>\n }\n >\n <Show\n when={selected()?.color}\n fallback={<Show when={selected()?.icon}>{(icon) => <i class={icon()} aria-hidden=\"true\" />}</Show>}\n >\n {(color) => <span class=\"k2b-choice-dot\" style={{ \"background-color\": color() }} aria-hidden=\"true\" />}\n </Show>\n </Show>\n <span class=\"k2b-choice-trigger__value\" data-placeholder={selected() ? undefined : \"true\"}>\n {selected()?.label ?? props.placeholder ?? messages().select}\n </span>\n <i\n class={`${popover.open() ? (props.activeIcon ?? \"ti ti-chevron-up\") : (props.icon ?? \"ti ti-chevron-down\")} k2b-choice-trigger__chevron`}\n aria-hidden=\"true\"\n />\n </button>\n <Show when={props.name}>{(name) => <input type=\"hidden\" name={name()} value={value() ?? \"\"} />}</Show>\n <Show when={hasClearAction()}>\n <button\n type=\"button\"\n class=\"k2b-choice-control__clear k2b-input-clear-action\"\n aria-label={messages().clearSelection}\n onClick={clear}\n >\n <i class=\"ti ti-x\" aria-hidden=\"true\" />\n </button>\n </Show>\n <div\n ref={popover.setPopover}\n popover=\"manual\"\n class=\"k2b-choice-popover\"\n role=\"group\"\n onKeyDown={onKeyDown}\n aria-label={typeof props.label === \"string\" ? props.label : (props[\"aria-label\"] ?? messages().options)}\n >\n <Show when={isSearchable()}>\n <div class=\"k2b-choice-search\">\n <i class=\"ti ti-search\" aria-hidden=\"true\" />\n <input\n ref={searchRef}\n type=\"search\"\n value={query()}\n placeholder={props.searchPlaceholder ?? messages().search}\n aria-label={props.searchPlaceholder ?? selectMessages().searchOptions}\n aria-controls={listboxId}\n aria-activedescendant={focusedOption() ? `${listboxId}-${focusedIndex()}` : undefined}\n onInput={(event) => {\n setQuery(event.currentTarget.value);\n if (isAsync()) loader.load(event.currentTarget.value);\n focus(isAsync() ? -1 : nextEnabledChoiceIndex(options(), -1, 1));\n }}\n />\n </div>\n </Show>\n <Show when={(props.groups?.length ?? 0) > 0 || props.viewToggle}>\n <div class=\"k2b-choice-toolbar\">\n <Show when={(props.groups?.length ?? 0) > 0}>\n <ChoiceGroups\n choices={groupChoices()}\n value={activeGroup()}\n onValueChange={chooseGroup}\n ariaLabel={props.groupsAriaLabel ?? selectMessages().filterOptions}\n controls={listboxId}\n />\n </Show>\n <Show when={props.viewToggle}>\n <button\n type=\"button\"\n class=\"k2b-choice-view-toggle\"\n aria-label={activeView() === \"list\" ? selectMessages().showGridView : selectMessages().showListView}\n aria-controls={listboxId}\n onClick={() => setSelectedView(activeView() === \"list\" ? \"grid\" : \"list\")}\n >\n <i class={activeView() === \"list\" ? \"ti ti-category-2\" : \"ti ti-list-details\"} aria-hidden=\"true\" />\n </button>\n </Show>\n </div>\n </Show>\n <div\n id={listboxId}\n class=\"k2b-choice-options\"\n role=\"listbox\"\n data-view={activeView()}\n data-grid-size={activeView() === \"grid\" ? (props.gridSize ?? \"md\") : undefined}\n >\n <Show when={loader.error()}>\n {(message) => (\n <div class=\"k2b-choice-status\" data-tone=\"danger\">\n <span>{message()}</span>\n <button type=\"button\" onClick={loader.retry}>\n {messages().retry}\n </button>\n </div>\n )}\n </Show>\n <Show when={loader.loading() && options().length === 0}>\n <div class=\"k2b-choice-status\">\n <i class=\"ti ti-loader-2 k2b-spin\" aria-hidden=\"true\" />\n <span>{messages().loading}</span>\n </div>\n </Show>\n <For\n each={loader.error() ? [] : listOptions()}\n fallback={\n <Show when={!loader.loading() && !loader.error()}>\n <div class=\"k2b-choice-status\">{isSearchable() ? messages().noResults : selectMessages().noOptions}</div>\n </Show>\n }\n >\n {(option, index) => (\n <button\n ref={(element) => (optionRefs[index()] = element)}\n type=\"button\"\n id={`${listboxId}-${index()}`}\n class=\"k2b-choice-option\"\n role=\"option\"\n aria-label={option.label}\n aria-selected={option.value === (value() ?? CLEAR_VALUE)}\n data-focused={index() === focusedIndex() ? \"true\" : undefined}\n data-clear={option.value === CLEAR_VALUE ? \"true\" : undefined}\n disabled={option.disabled}\n onPointerMove={() => focus(index())}\n onClick={() => select(option)}\n >\n <Show\n when={option.value === CLEAR_VALUE}\n fallback={\n <Show\n when={option.color}\n fallback={<Show when={option.icon}>{(icon) => <i class={icon()} aria-hidden=\"true\" />}</Show>}\n >\n {(color) => <span class=\"k2b-choice-dot\" style={{ \"background-color\": color() }} aria-hidden=\"true\" />}\n </Show>\n }\n >\n <Show\n when={props.placeholderIcon}\n fallback={<Show when={emptyDot()}>{<span class=\"k2b-choice-dot\" data-empty=\"true\" aria-hidden=\"true\" />}</Show>}\n >\n {(icon) => <i class={icon()} aria-hidden=\"true\" />}\n </Show>\n </Show>\n <span>\n <strong>{option.label}</strong>\n <Show when={option.description}>{(description) => <small>{description()}</small>}</Show>\n </span>\n </button>\n )}\n </For>\n </div>\n </div>\n </div>\n </Field>\n );\n}\n\nexport default Select;\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["inputs/Select.tsx"],"sourcesContent":["import { createMemo, createSignal, For, type JSX, Show } from \"solid-js\";\nimport { createFieldMeta, Field, fieldControlAria } from \"../internal/field\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { ChoiceGroups } from \"./ChoiceGroups\";\nimport { type ChoiceOption, createChoiceLoader, createChoicePopover, filterChoiceOptions, nextEnabledChoiceIndex } from \"./choice\";\nimport type { ValueFieldProps } from \"./field-contract\";\nimport { commitFieldValue, resolveMaybeAccessor } from \"./field-contract\";\nimport { useSelectMessages } from \"./select-messages\";\n\nexport type SelectOption = ChoiceOption<string>;\nexport type SelectGroup = {\n value: string;\n label: string;\n};\nexport type SelectView = \"list\" | \"grid\";\nexport type SelectGridSize = \"sm\" | \"md\" | \"lg\";\n/**\n * `field` draws the boxed form control. `plain` shows the value as text for\n * property rows: no box, no chevron, and a quiet surface on hover or while\n * open. Its surface and hit area cover the nearest positioned ancestor, such as\n * a `DescriptionList` row, so the whole row opens the picker.\n */\nexport type ChoiceAppearance = \"field\" | \"plain\";\nexport type SelectSourceOption =\n | string\n | {\n id: string;\n label?: string;\n description?: string;\n icon?: string;\n color?: string;\n groups?: readonly string[];\n }\n | SelectOption;\n\nexport type SelectProps = ValueFieldProps<string | null> & {\n placeholder?: string;\n icon?: string;\n activeIcon?: string;\n options?: SelectSourceOption[];\n fetchData?: (query: string, signal: AbortSignal, group: string | null) => Promise<SelectSourceOption[]>;\n loadOptions?: (query: string, signal: AbortSignal, group: string | null) => Promise<readonly ChoiceOption<string>[]>;\n selectedOption?: ChoiceOption<string>;\n selectedLabel?: () => string | undefined;\n fetchDebounceMs?: number;\n debounceMs?: number;\n searchable?: boolean;\n /** Optional synchronous filter for static options. */\n filterOptions?: (options: readonly SelectOption[], query: string) => readonly SelectOption[];\n /** Optional filters. An option may belong to more than one group. */\n groups?: readonly SelectGroup[];\n /** Group selected when the component is created. Omit to start with all options. */\n defaultGroup?: string;\n groupsAriaLabel?: string;\n allGroupLabel?: string;\n /** Show a local list/grid layout toggle in the dropdown. */\n viewToggle?: boolean;\n /** Initial dropdown layout when `viewToggle` is enabled. */\n defaultView?: SelectView;\n /** Tile density for the grid layout. */\n gridSize?: SelectGridSize;\n searchPlaceholder?: string;\n clearable?: boolean;\n name?: string;\n appearance?: ChoiceAppearance;\n /** Icon class shown before the placeholder while nothing is selected. */\n placeholderIcon?: string;\n};\n\ntype NormalizedOption = ChoiceOption<string>;\n/** The list entry that clears a plain select. It cannot collide with a real option value. */\nconst CLEAR_VALUE = \"\\u0000k2b-select-clear\";\n\nconst normalize = (option: SelectSourceOption): NormalizedOption =>\n typeof option === \"string\"\n ? { value: option, label: option }\n : \"value\" in option\n ? option\n : { ...option, value: option.id, label: option.label || option.id };\n\nexport function Select(props: SelectProps): JSX.Element {\n const messages = useUiMessages();\n const selectMessages = useSelectMessages();\n const meta = createFieldMeta(props.id);\n const listboxId = `${meta.controlId}-listbox`;\n const [query, setQuery] = createSignal(\"\");\n const [focusedIndex, setFocusedIndex] = createSignal(-1);\n const [cache, setCache] = createSignal<Record<string, NormalizedOption>>({});\n const [selectedGroup, setSelectedGroup] = createSignal<string | null>(props.defaultGroup ?? null);\n const [selectedView, setSelectedView] = createSignal<SelectView>(props.defaultView ?? \"list\");\n // Whether the person picked the group, rather than seeing the default one.\n let groupChosen = false;\n let searchRef: HTMLInputElement | undefined;\n let optionRefs: HTMLButtonElement[] = [];\n const value = () => resolveMaybeAccessor(props.value) ?? null;\n const error = () => resolveMaybeAccessor(props.error);\n const activeGroup = createMemo(() => {\n const current = selectedGroup();\n return current && props.groups?.some((group) => group.value === current) ? current : null;\n });\n const groupChoices = createMemo(() => [{ value: null, label: props.allGroupLabel ?? messages().all }, ...(props.groups ?? [])]);\n const activeView = () => (props.viewToggle ? selectedView() : \"list\");\n\n const loader = createChoiceLoader(\n () =>\n props.fetchData\n ? async (value, signal) => (await props.fetchData!(value, signal, activeGroup())).map(normalize)\n : props.loadOptions\n ? (value, signal) => props.loadOptions!(value, signal, activeGroup())\n : undefined,\n () => props.fetchDebounceMs ?? props.debounceMs ?? 200,\n );\n const isAsync = () => Boolean(props.fetchData || props.loadOptions);\n const isSearchable = () => isAsync() || Boolean(props.searchable);\n const sourceOptions = createMemo(() => (isAsync() ? loader.options() : (props.options ?? []).map(normalize)));\n const groupedOptions = createMemo(() => {\n const group = activeGroup();\n return !isAsync() && group ? sourceOptions().filter((option) => option.groups?.includes(group)) : sourceOptions();\n });\n // Remote loaders filter server-side; a static list has to be filtered here or\n // the search field would render but do nothing.\n const options = createMemo(() =>\n isAsync() || !props.searchable\n ? groupedOptions()\n : props.filterOptions\n ? [...props.filterOptions(groupedOptions(), query())]\n : filterChoiceOptions(groupedOptions(), query()),\n );\n const plain = () => props.appearance === \"plain\";\n // A plain select has no room for a clear button beside its value, so\n // clearing becomes the last list entry, named by the placeholder.\n const clearOption = createMemo<NormalizedOption | undefined>(() =>\n plain() && props.clearable && !query() ? { value: CLEAR_VALUE, label: props.placeholder ?? messages().clearSelection } : undefined,\n );\n const listOptions = createMemo(() => {\n const clear = clearOption();\n return clear && !loader.error() ? [...options(), clear] : options();\n });\n // Colour dots mark the options, so an empty plain value keeps the column with a hollow dot.\n const emptyDot = () => plain() && !props.placeholderIcon && sourceOptions().some((option) => option.color);\n const selected = createMemo(() => {\n const current = value();\n if (current === null) return undefined;\n // Resolve against the unfiltered list so typing in the search field never\n // blanks the trigger label of the current selection.\n return (\n sourceOptions().find((option) => option.value === current) ??\n cache()[current] ??\n (props.selectedOption?.value === current ? props.selectedOption : undefined) ?? {\n value: current,\n label: props.selectedLabel?.() ?? current,\n }\n );\n });\n const hasClearAction = () => Boolean(props.clearable && selected() && !props.disabled && !plain());\n const accessibleLabel = () =>\n props[\"aria-label\"] ?? (typeof props.label === \"string\" ? undefined : (props.placeholder ?? selectMessages().selectOption));\n const popover = createChoicePopover(() => Boolean(props.disabled));\n const focusedOption = () => listOptions()[focusedIndex()];\n const focus = (index: number) => {\n setFocusedIndex(index);\n optionRefs[index]?.scrollIntoView({ block: \"nearest\" });\n };\n const move = (direction: 1 | -1) => focus(nextEnabledChoiceIndex(listOptions(), focusedIndex(), direction));\n const chooseGroup = (group: string | null) => {\n groupChosen = true;\n if (group === activeGroup()) return;\n setSelectedGroup(group);\n setFocusedIndex(nextEnabledChoiceIndex(listOptions(), -1, 1));\n if (isAsync()) loader.load(query(), true);\n };\n const open = () => {\n if (props.disabled) return;\n setQuery(\"\");\n // A static list that only left its default group for a search starts\n // there again; a group the person picked, or a remote filter, stays.\n if (!isAsync() && !groupChosen) setSelectedGroup(props.defaultGroup ?? null);\n if (isAsync()) loader.load(\"\", true);\n const selectedIndex = listOptions().findIndex((option) => option.value === (value() ?? CLEAR_VALUE));\n focus(selectedIndex >= 0 ? selectedIndex : nextEnabledChoiceIndex(listOptions(), -1, 1));\n popover.show();\n if (isSearchable()) queueMicrotask(() => searchRef?.focus());\n };\n const close = (restoreFocus = false) => {\n // Hide the top-layer surface before any reactive cleanup or consumer\n // callback can rerender its contents. Selection must feel atomic: the old\n // listbox must never remain visible with the next value.\n popover.hide(restoreFocus);\n loader.cancel();\n setQuery(\"\");\n setFocusedIndex(-1);\n };\n const select = (option: NormalizedOption) => {\n if (option.disabled) return;\n close(true);\n if (option.value === CLEAR_VALUE) {\n commitFieldValue(props, null);\n return;\n }\n setCache({ ...cache(), [option.value]: option });\n commitFieldValue(props, option.value);\n };\n const onKeyDown = (event: KeyboardEvent) => {\n const inToolbar = Boolean((event.target as HTMLElement | null)?.closest?.(\".k2b-choice-toolbar\"));\n if (inToolbar && event.key !== \"Escape\" && event.key !== \"Tab\") return;\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n if (!popover.open()) open();\n else move(event.key === \"ArrowDown\" ? 1 : -1);\n } else if ((event.key === \"Enter\" || event.key === \" \") && !popover.open()) {\n event.preventDefault();\n open();\n } else if (event.key === \"Enter\" && focusedOption()) {\n event.preventDefault();\n select(focusedOption()!);\n } else if (event.key === \"Escape\" && popover.open()) {\n // Only swallow Escape while the list is open — a closed select must let\n // the key bubble to an enclosing dialog or drawer.\n event.preventDefault();\n close(true);\n } else if (event.key === \"Tab\" && popover.open()) close();\n };\n const clear = (event: MouseEvent) => {\n event.stopPropagation();\n commitFieldValue(props, null);\n popover.trigger()?.focus();\n };\n\n return (\n <Field\n class={props.class}\n label={props.label}\n description={props.description}\n error={error()}\n meta={meta}\n required={props.required}\n disabled={props.disabled}\n >\n <div class=\"k2b-choice-control\" data-appearance={props.appearance ?? \"field\"} data-invalid={error() ? \"true\" : undefined}>\n <button\n ref={popover.setTrigger}\n id={meta.controlId}\n type=\"button\"\n class=\"k2b-choice-trigger\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n aria-expanded={popover.open()}\n aria-controls={listboxId}\n aria-activedescendant={focusedOption() ? `${listboxId}-${focusedIndex()}` : undefined}\n data-clearable={hasClearAction() ? \"true\" : undefined}\n {...fieldControlAria(meta, {\n ...props,\n \"aria-label\": accessibleLabel(),\n })}\n disabled={props.disabled}\n onClick={() => (popover.open() ? close() : open())}\n onKeyDown={onKeyDown}\n >\n <Show\n when={selected()}\n fallback={\n <Show\n when={props.placeholderIcon}\n fallback={<Show when={emptyDot()}>{<span class=\"k2b-choice-dot\" data-empty=\"true\" aria-hidden=\"true\" />}</Show>}\n >\n {(icon) => <i class={`${icon()} k2b-choice-trigger__placeholder-icon`} aria-hidden=\"true\" />}\n </Show>\n }\n >\n <Show\n when={selected()?.color}\n fallback={<Show when={selected()?.icon}>{(icon) => <i class={icon()} aria-hidden=\"true\" />}</Show>}\n >\n {(color) => <span class=\"k2b-choice-dot\" style={{ \"background-color\": color() }} aria-hidden=\"true\" />}\n </Show>\n </Show>\n <span class=\"k2b-choice-trigger__value\" data-placeholder={selected() ? undefined : \"true\"}>\n {selected()?.label ?? props.placeholder ?? messages().select}\n </span>\n <i\n class={`${popover.open() ? (props.activeIcon ?? \"ti ti-chevron-up\") : (props.icon ?? \"ti ti-chevron-down\")} k2b-choice-trigger__chevron`}\n aria-hidden=\"true\"\n />\n </button>\n <Show when={props.name}>{(name) => <input type=\"hidden\" name={name()} value={value() ?? \"\"} />}</Show>\n <Show when={hasClearAction()}>\n <button\n type=\"button\"\n class=\"k2b-choice-control__clear k2b-input-clear-action\"\n aria-label={messages().clearSelection}\n onClick={clear}\n >\n <i class=\"ti ti-x\" aria-hidden=\"true\" />\n </button>\n </Show>\n <div\n ref={popover.setPopover}\n popover=\"manual\"\n class=\"k2b-choice-popover\"\n data-toolbar={(props.groups?.length ?? 0) > 0 || props.viewToggle ? \"true\" : undefined}\n role=\"group\"\n onKeyDown={onKeyDown}\n aria-label={typeof props.label === \"string\" ? props.label : (props[\"aria-label\"] ?? messages().options)}\n >\n <Show when={isSearchable()}>\n <div class=\"k2b-choice-search\">\n <i class=\"ti ti-search\" aria-hidden=\"true\" />\n <input\n ref={searchRef}\n type=\"search\"\n value={query()}\n placeholder={props.searchPlaceholder ?? messages().search}\n aria-label={props.searchPlaceholder ?? selectMessages().searchOptions}\n aria-controls={listboxId}\n aria-activedescendant={focusedOption() ? `${listboxId}-${focusedIndex()}` : undefined}\n onInput={(event) => {\n // A default group, such as \"Recommended\", is a starting view,\n // not a filter: a static search leaves it for \"All\". A group\n // the person chose keeps narrowing the results.\n if (!isAsync() && !groupChosen && event.currentTarget.value) setSelectedGroup(null);\n setQuery(event.currentTarget.value);\n if (isAsync()) loader.load(event.currentTarget.value);\n focus(isAsync() ? -1 : nextEnabledChoiceIndex(options(), -1, 1));\n }}\n />\n </div>\n </Show>\n <Show when={(props.groups?.length ?? 0) > 0 || props.viewToggle}>\n <div class=\"k2b-choice-toolbar\">\n <Show when={(props.groups?.length ?? 0) > 0}>\n <ChoiceGroups\n choices={groupChoices()}\n value={activeGroup()}\n onValueChange={chooseGroup}\n ariaLabel={props.groupsAriaLabel ?? selectMessages().filterOptions}\n controls={listboxId}\n />\n </Show>\n <Show when={props.viewToggle}>\n <button\n type=\"button\"\n class=\"k2b-choice-view-toggle\"\n aria-label={activeView() === \"list\" ? selectMessages().showGridView : selectMessages().showListView}\n aria-controls={listboxId}\n onClick={() => setSelectedView(activeView() === \"list\" ? \"grid\" : \"list\")}\n >\n <i class={activeView() === \"list\" ? \"ti ti-category-2\" : \"ti ti-list-details\"} aria-hidden=\"true\" />\n </button>\n </Show>\n </div>\n </Show>\n <div\n id={listboxId}\n class=\"k2b-choice-options\"\n role=\"listbox\"\n data-view={activeView()}\n data-grid-size={activeView() === \"grid\" ? (props.gridSize ?? \"md\") : undefined}\n >\n <Show when={loader.error()}>\n {(message) => (\n <div class=\"k2b-choice-status\" data-tone=\"danger\">\n <span>{message()}</span>\n <button type=\"button\" onClick={loader.retry}>\n {messages().retry}\n </button>\n </div>\n )}\n </Show>\n <Show when={loader.loading() && options().length === 0}>\n <div class=\"k2b-choice-status\">\n <i class=\"ti ti-loader-2 k2b-spin\" aria-hidden=\"true\" />\n <span>{messages().loading}</span>\n </div>\n </Show>\n <For\n each={loader.error() ? [] : listOptions()}\n fallback={\n <Show when={!loader.loading() && !loader.error()}>\n <div class=\"k2b-choice-status\">{isSearchable() ? messages().noResults : selectMessages().noOptions}</div>\n </Show>\n }\n >\n {(option, index) => (\n <button\n ref={(element) => (optionRefs[index()] = element)}\n type=\"button\"\n id={`${listboxId}-${index()}`}\n class=\"k2b-choice-option\"\n role=\"option\"\n aria-label={option.label}\n aria-selected={option.value === (value() ?? CLEAR_VALUE)}\n data-focused={index() === focusedIndex() ? \"true\" : undefined}\n data-clear={option.value === CLEAR_VALUE ? \"true\" : undefined}\n disabled={option.disabled}\n onPointerMove={() => focus(index())}\n onClick={() => select(option)}\n >\n <Show\n when={option.value === CLEAR_VALUE}\n fallback={\n <Show\n when={option.color}\n fallback={<Show when={option.icon}>{(icon) => <i class={icon()} aria-hidden=\"true\" />}</Show>}\n >\n {(color) => <span class=\"k2b-choice-dot\" style={{ \"background-color\": color() }} aria-hidden=\"true\" />}\n </Show>\n }\n >\n <Show\n when={props.placeholderIcon}\n fallback={<Show when={emptyDot()}>{<span class=\"k2b-choice-dot\" data-empty=\"true\" aria-hidden=\"true\" />}</Show>}\n >\n {(icon) => <i class={icon()} aria-hidden=\"true\" />}\n </Show>\n </Show>\n <span>\n <strong>{option.label}</strong>\n <Show when={option.description}>{(description) => <small>{description()}</small>}</Show>\n </span>\n </button>\n )}\n </For>\n </div>\n </div>\n </div>\n </Field>\n );\n}\n\nexport default Select;\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,37 +1,66 @@
|
|
|
1
1
|
import { createComponent as _$createComponent } from "solid-js/web";
|
|
2
2
|
import { memo as _$memo } from "solid-js/web";
|
|
3
|
-
import { fuzzy } from "@k2b/stdlib";
|
|
4
3
|
import { createMemo } from "solid-js";
|
|
4
|
+
import { useLocale } from "../intl/locale";
|
|
5
5
|
import { useUiMessages } from "../intl/messages";
|
|
6
6
|
import { resolveMaybeAccessor } from "./field-contract";
|
|
7
|
-
import { useIconMessages } from "./icon-messages";
|
|
8
|
-
import { DEFAULT_ICON_GROUPS
|
|
7
|
+
import { useIconLocale, useIconMessages } from "./icon-messages";
|
|
8
|
+
import { DEFAULT_ICON_GROUPS } from "./icon-options";
|
|
9
|
+
import { localizedIconOptions } from "./icon-texts";
|
|
9
10
|
import { Select } from "./Select";
|
|
11
|
+
/** Lowercase without diacritics, so "gross" finds "Groß" and "uber" finds "Über". */
|
|
12
|
+
const fold = text => text.normalize("NFD").replace(/\p{Diacritic}/gu, "").replace(/ß/g, "ss").toLowerCase();
|
|
13
|
+
const words = text => fold(text).split(/[^\p{L}\p{N}$€%]+/u).filter(Boolean);
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Every query word has to appear in the icon's names or keywords: as the start
|
|
17
|
+
* of a word, or anywhere in one once it has three letters, so German compounds
|
|
18
|
+
* such as "Kreditkarte" match "karte". A loose subsequence match let "gro" find
|
|
19
|
+
* "warninG eRrOr", so it is not used. Ranked by where the query hits: the label
|
|
20
|
+
* start, a label word, a keyword, then anywhere.
|
|
21
|
+
*/
|
|
22
|
+
export const searchIconOptions = (source, query, limit) => {
|
|
23
|
+
const tokens = words(query);
|
|
24
|
+
if (tokens.length === 0) return [...source];
|
|
25
|
+
const ranked = [];
|
|
26
|
+
for (const option of source) {
|
|
27
|
+
const labelWords = words(String(option.label));
|
|
28
|
+
const keywordWords = (option.keywords ?? []).flatMap(words);
|
|
29
|
+
const all = [...labelWords, ...keywordWords];
|
|
30
|
+
let rank = 0;
|
|
31
|
+
for (const token of tokens) {
|
|
32
|
+
const tokenRank = labelWords.some(word => word.startsWith(token)) ? 1 : keywordWords.some(word => word.startsWith(token)) ? 2 : token.length >= 3 && all.some(word => word.includes(token)) ? 3 : undefined;
|
|
33
|
+
if (tokenRank === undefined) {
|
|
34
|
+
rank = -1;
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
rank = Math.max(rank, tokenRank);
|
|
38
|
+
}
|
|
39
|
+
if (rank < 0) continue;
|
|
40
|
+
if (rank === 1 && labelWords[0]?.startsWith(tokens[0])) rank = 0;
|
|
41
|
+
ranked.push({
|
|
42
|
+
option,
|
|
43
|
+
rank
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
return ranked.sort((left, right) => left.rank - right.rank || String(left.option.label).localeCompare(String(right.option.label))).slice(0, limit).map(entry => entry.option);
|
|
47
|
+
};
|
|
10
48
|
export function IconInput(props) {
|
|
11
49
|
const messages = useUiMessages();
|
|
12
50
|
const iconMessages = useIconMessages();
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
// is already the first keyword (see `icon()` in ./icon-options), so
|
|
27
|
-
// nothing is lost by dropping it.
|
|
28
|
-
key: option => {
|
|
29
|
-
const keywords = "keywords" in option && Array.isArray(option.keywords) ? option.keywords.join(" ") : "";
|
|
30
|
-
return `${String(option.label)} ${keywords}`.toLowerCase();
|
|
31
|
-
},
|
|
32
|
-
limit: props.searchLimit ?? 50
|
|
33
|
-
}).map(match => match.item);
|
|
34
|
-
};
|
|
51
|
+
const locale = useLocale();
|
|
52
|
+
// The bundled catalogue speaks the render locale and stays searchable by
|
|
53
|
+
// its English names, so a mixed team finds the same icon either way.
|
|
54
|
+
const iconLocale = useIconLocale();
|
|
55
|
+
const defaultOptions = createMemo(() => localizedIconOptions(iconLocale()));
|
|
56
|
+
const options = () => props.options ?? defaultOptions();
|
|
57
|
+
const groups = () => props.groups ?? (props.options === undefined ? DEFAULT_ICON_GROUPS.map(group => ({
|
|
58
|
+
value: group.value,
|
|
59
|
+
label: iconMessages()[group.value]
|
|
60
|
+
})) : undefined);
|
|
61
|
+
const filterOptions = (source, query) => query.trim() ? searchIconOptions(source, query, props.searchLimit ?? 50) : [...source].sort((left, right) => String(left.label).localeCompare(String(right.label), locale(), {
|
|
62
|
+
sensitivity: "base"
|
|
63
|
+
}));
|
|
35
64
|
const selectedOption = createMemo(() => options().find(option => option.value === resolveMaybeAccessor(props.value)));
|
|
36
65
|
return _$createComponent(Select, {
|
|
37
66
|
get id() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["inputs/SpecialInputs.tsx"],"sourcesContent":["import { fuzzy } from \"@k2b/stdlib\";\nimport { createMemo, type JSX } from \"solid-js\";\nimport { useUiMessages } from \"../intl/messages\";\nimport type { ValueFieldProps } from \"./field-contract\";\nimport { resolveMaybeAccessor } from \"./field-contract\";\nimport { useIconMessages } from \"./icon-messages\";\nimport { DEFAULT_ICON_GROUPS, DEFAULT_ICON_OPTIONS } from \"./icon-options\";\nimport { Select, type SelectGridSize, type SelectGroup, type SelectOption, type SelectView } from \"./Select\";\n\nexport type IconOption = SelectOption & { keywords?: readonly string[] };\nexport type IconInputProps = ValueFieldProps<string | null> & {\n options?: readonly IconOption[];\n placeholder?: string;\n clearable?: boolean;\n searchLimit?: number;\n groups?: readonly SelectGroup[];\n defaultGroup?: string;\n groupsAriaLabel?: string;\n allGroupLabel?: string;\n viewToggle?: boolean;\n defaultView?: SelectView;\n gridSize?: SelectGridSize;\n name?: string;\n};\n\nexport function IconInput(props: IconInputProps): JSX.Element {\n const messages = useUiMessages();\n const iconMessages = useIconMessages();\n const options = () => props.options ?? DEFAULT_ICON_OPTIONS;\n const groups = () => props.groups ?? (props.options === undefined ? DEFAULT_ICON_GROUPS : undefined);\n const filterOptions = (source: readonly SelectOption[], query: string): readonly SelectOption[] => {\n const normalized = query.trim().toLowerCase();\n if (!normalized) {\n return [...source].sort((left, right) => String(left.label).localeCompare(String(right.label), undefined, { sensitivity: \"base\" }));\n }\n return fuzzy\n .filter(normalized, source, {\n // Cloud's key is `[label, ...keywords]`. Including `value` as well put\n // the literal \"ti ti-\" in front of every entry, so short queries matched\n // the whole catalogue and fuzzy scores were skewed. The bare glyph name\n // is already the first keyword (see `icon()` in ./icon-options), so\n // nothing is lost by dropping it.\n key: (option) => {\n const keywords = \"keywords\" in option && Array.isArray(option.keywords) ? option.keywords.join(\" \") : \"\";\n return `${String(option.label)} ${keywords}`.toLowerCase();\n },\n limit: props.searchLimit ?? 50,\n })\n .map((match) => match.item);\n };\n const selectedOption = createMemo(() => options().find((option) => option.value === resolveMaybeAccessor(props.value)));\n\n return (\n <Select\n id={props.id}\n name={props.name}\n class={props.class}\n label={props.label}\n description={props.description}\n error={props.error}\n aria-label={props[\"aria-label\"]}\n aria-describedby={props[\"aria-describedby\"]}\n placeholder={props.placeholder ?? iconMessages().pickIcon}\n disabled={props.disabled}\n required={props.required}\n clearable={props.clearable ?? true}\n value={resolveMaybeAccessor(props.value)}\n selectedOption={selectedOption()}\n onValueChange={props.onValueChange}\n onValueCommit={props.onValueCommit}\n options={[...options()]}\n groups={groups()}\n defaultGroup={props.defaultGroup ?? (props.options === undefined ? \"recommended\" : undefined)}\n groupsAriaLabel={props.groupsAriaLabel ?? iconMessages().filterIcons}\n allGroupLabel={props.allGroupLabel}\n viewToggle={props.viewToggle ?? true}\n defaultView={props.defaultView ?? \"grid\"}\n gridSize={props.gridSize ?? \"sm\"}\n searchable\n filterOptions={filterOptions}\n searchPlaceholder={messages().search}\n icon={selectedOption()?.icon ?? \"ti ti-icons\"}\n />\n );\n}\n"],"mappings":";;AAAA,SAAS,KAAK,QAAQ,aAAa;AACnC,SAAS,UAAU,QAAkB,UAAU;AAC/C,SAAS,aAAa,QAAQ,kBAAkB;AAEhD,SAAS,oBAAoB,QAAQ,kBAAkB;AACvD,SAAS,eAAe,QAAQ,iBAAiB;AACjD,SAAS,mBAAmB,EAAE,oBAAoB,QAAQ,gBAAgB;AAC1E,SAAS,MAAM,QAAmF,UAAU;AAkB5G,OAAO,SAAS,SAAS,CAAC,KAAqB,EAAe;EAC5D,MAAM,QAAQ,GAAG,aAAa,CAAC,CAAC;EAChC,MAAM,YAAY,GAAG,eAAe,CAAC,CAAC;EACtC,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,OAAO,IAAI,oBAAoB;EAC3D,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,OAAO,KAAK,SAAS,GAAG,mBAAmB,GAAG,SAAS,CAAC;EACpG,MAAM,aAAa,GAAG,CAAC,MAA+B,EAAE,KAAa,KAA8B;IACjG,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IAC7C,IAAI,CAAC,UAAU,EAAE;MACf,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,KAAK,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE;QAAE,WAAW,EAAE;MAAO,CAAC,CAAC,CAAC;IACrI;IACA,OAAO,KAAK,CACT,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE;MAC1B;MACA;MACA;MACA;MACA;MACA,GAAG,EAAG,MAAM,IAAK;QACf,MAAM,QAAQ,GAAG,UAAU,IAAI,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE;QACxG,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,QAAQ,EAAE,CAAC,WAAW,CAAC,CAAC;MAC5D,CAAC;MACD,KAAK,EAAE,KAAK,CAAC,WAAW,IAAI;IAC9B,CAAC,CAAC,CACD,GAAG,CAAE,KAAK,IAAK,KAAK,CAAC,IAAI,CAAC;EAC/B,CAAC;EACD,MAAM,cAAc,GAAG,UAAU,CAAC,MAAM,OAAO,CAAC,CAAC,CAAC,IAAI,CAAE,MAAM,IAAK,MAAM,CAAC,KAAK,KAAK,oBAAoB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;EAEvH,yBACG,MAAM;IAAA,IACL,EAAE;MAAA,OAAE,KAAK,CAAC,EAAE;IAAA;IAAA,IACZ,IAAI;MAAA,OAAE,KAAK,CAAC,IAAI;IAAA;IAAA;MAAA,OACT,KAAK,CAAC,KAAK;IAAA;IAAA,IAClB,KAAK;MAAA,OAAE,KAAK,CAAC,KAAK;IAAA;IAAA,IAClB,WAAW;MAAA,OAAE,KAAK,CAAC,WAAW;IAAA;IAAA,IAC9B,KAAK;MAAA,OAAE,KAAK,CAAC,KAAK;IAAA;IAAA;MAAA,OACN,KAAK,CAAC,YAAY,CAAC;IAAA;IAAA;MAAA,OACb,KAAK,CAAC,kBAAkB,CAAC;IAAA;IAAA,IAC3C,WAAW;MAAA,OAAE,KAAK,CAAC,WAAW,IAAI,YAAY,CAAC,CAAC,CAAC,QAAQ;IAAA;IAAA,IACzD,QAAQ;MAAA,OAAE,KAAK,CAAC,QAAQ;IAAA;IAAA,IACxB,QAAQ;MAAA,OAAE,KAAK,CAAC,QAAQ;IAAA;IAAA,IACxB,SAAS;MAAA,OAAE,KAAK,CAAC,SAAS,IAAI,IAAI;IAAA;IAAA,IAClC,KAAK;MAAA,OAAE,oBAAoB,CAAC,KAAK,CAAC,KAAK,CAAC;IAAA;IAAA,IACxC,cAAc;MAAA,OAAE,cAAc,CAAC,CAAC;IAAA;IAAA,IAChC,aAAa;MAAA,OAAE,KAAK,CAAC,aAAa;IAAA;IAAA,IAClC,aAAa;MAAA,OAAE,KAAK,CAAC,aAAa;IAAA;IAAA,IAClC,OAAO;MAAA,OAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAAA;IAAA,IACvB,MAAM;MAAA,OAAE,MAAM,CAAC,CAAC;IAAA;IAAA,IAChB,YAAY;MAAA,OAAE,KAAK,CAAC,YAAY,KAAK,KAAK,CAAC,OAAO,KAAK,SAAS,GAAG,aAAa,GAAG,SAAS,CAAC;IAAA;IAAA,IAC7F,eAAe;MAAA,OAAE,KAAK,CAAC,eAAe,IAAI,YAAY,CAAC,CAAC,CAAC,WAAW;IAAA;IAAA,IACpE,aAAa;MAAA,OAAE,KAAK,CAAC,aAAa;IAAA;IAAA,IAClC,UAAU;MAAA,OAAE,KAAK,CAAC,UAAU,IAAI,IAAI;IAAA;IAAA,IACpC,WAAW;MAAA,OAAE,KAAK,CAAC,WAAW,IAAI,MAAM;IAAA;IAAA,IACxC,QAAQ;MAAA,OAAE,KAAK,CAAC,QAAQ,IAAI,IAAI;IAAA;IAChC,UAAU;IACV,aAAa,EAAE,aAAa;IAAA,IAC5B,iBAAiB;MAAA,OAAE,QAAQ,CAAC,CAAC,CAAC,MAAM;IAAA;IAAA,IACpC,IAAI;MAAA,OAAE,cAAc,CAAC,CAAC,EAAE,IAAI,IAAI,aAAa;IAAA;EAAA;AAGnD","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["inputs/SpecialInputs.tsx"],"sourcesContent":["import { createMemo, type JSX } from \"solid-js\";\nimport { useLocale } from \"../intl/locale\";\nimport { useUiMessages } from \"../intl/messages\";\nimport type { ValueFieldProps } from \"./field-contract\";\nimport { resolveMaybeAccessor } from \"./field-contract\";\nimport { type IconGroupMessage, useIconLocale, useIconMessages } from \"./icon-messages\";\nimport { DEFAULT_ICON_GROUPS } from \"./icon-options\";\nimport { localizedIconOptions } from \"./icon-texts\";\nimport { Select, type SelectGridSize, type SelectGroup, type SelectOption, type SelectView } from \"./Select\";\n\nexport type IconOption = SelectOption & { keywords?: readonly string[] };\nexport type IconInputProps = ValueFieldProps<string | null> & {\n options?: readonly IconOption[];\n placeholder?: string;\n clearable?: boolean;\n searchLimit?: number;\n groups?: readonly SelectGroup[];\n defaultGroup?: string;\n groupsAriaLabel?: string;\n allGroupLabel?: string;\n viewToggle?: boolean;\n defaultView?: SelectView;\n gridSize?: SelectGridSize;\n name?: string;\n};\n\n/** Lowercase without diacritics, so \"gross\" finds \"Groß\" and \"uber\" finds \"Über\". */\nconst fold = (text: string) =>\n text\n .normalize(\"NFD\")\n .replace(/\\p{Diacritic}/gu, \"\")\n .replace(/ß/g, \"ss\")\n .toLowerCase();\nconst words = (text: string) =>\n fold(text)\n .split(/[^\\p{L}\\p{N}$€%]+/u)\n .filter(Boolean);\n\n/**\n * Every query word has to appear in the icon's names or keywords: as the start\n * of a word, or anywhere in one once it has three letters, so German compounds\n * such as \"Kreditkarte\" match \"karte\". A loose subsequence match let \"gro\" find\n * \"warninG eRrOr\", so it is not used. Ranked by where the query hits: the label\n * start, a label word, a keyword, then anywhere.\n */\nexport const searchIconOptions = <T extends IconOption>(source: readonly T[], query: string, limit: number): T[] => {\n const tokens = words(query);\n if (tokens.length === 0) return [...source];\n const ranked: { option: T; rank: number }[] = [];\n for (const option of source) {\n const labelWords = words(String(option.label));\n const keywordWords = (option.keywords ?? []).flatMap(words);\n const all = [...labelWords, ...keywordWords];\n let rank = 0;\n for (const token of tokens) {\n const tokenRank = labelWords.some((word) => word.startsWith(token))\n ? 1\n : keywordWords.some((word) => word.startsWith(token))\n ? 2\n : token.length >= 3 && all.some((word) => word.includes(token))\n ? 3\n : undefined;\n if (tokenRank === undefined) {\n rank = -1;\n break;\n }\n rank = Math.max(rank, tokenRank);\n }\n if (rank < 0) continue;\n if (rank === 1 && labelWords[0]?.startsWith(tokens[0]!)) rank = 0;\n ranked.push({ option, rank });\n }\n return ranked\n .sort((left, right) => left.rank - right.rank || String(left.option.label).localeCompare(String(right.option.label)))\n .slice(0, limit)\n .map((entry) => entry.option);\n};\n\nexport function IconInput(props: IconInputProps): JSX.Element {\n const messages = useUiMessages();\n const iconMessages = useIconMessages();\n const locale = useLocale();\n // The bundled catalogue speaks the render locale and stays searchable by\n // its English names, so a mixed team finds the same icon either way.\n const iconLocale = useIconLocale();\n const defaultOptions = createMemo(() => localizedIconOptions(iconLocale()));\n const options = () => props.options ?? defaultOptions();\n const groups = () =>\n props.groups ??\n (props.options === undefined\n ? DEFAULT_ICON_GROUPS.map((group) => ({ value: group.value, label: iconMessages()[group.value satisfies IconGroupMessage] }))\n : undefined);\n const filterOptions = (source: readonly SelectOption[], query: string): readonly SelectOption[] =>\n query.trim()\n ? searchIconOptions(source, query, props.searchLimit ?? 50)\n : [...source].sort((left, right) => String(left.label).localeCompare(String(right.label), locale(), { sensitivity: \"base\" }));\n const selectedOption = createMemo(() => options().find((option) => option.value === resolveMaybeAccessor(props.value)));\n\n return (\n <Select\n id={props.id}\n name={props.name}\n class={props.class}\n label={props.label}\n description={props.description}\n error={props.error}\n aria-label={props[\"aria-label\"]}\n aria-describedby={props[\"aria-describedby\"]}\n placeholder={props.placeholder ?? iconMessages().pickIcon}\n disabled={props.disabled}\n required={props.required}\n clearable={props.clearable ?? true}\n value={resolveMaybeAccessor(props.value)}\n selectedOption={selectedOption()}\n onValueChange={props.onValueChange}\n onValueCommit={props.onValueCommit}\n options={[...options()]}\n groups={groups()}\n defaultGroup={props.defaultGroup ?? (props.options === undefined ? \"recommended\" : undefined)}\n groupsAriaLabel={props.groupsAriaLabel ?? iconMessages().filterIcons}\n allGroupLabel={props.allGroupLabel}\n viewToggle={props.viewToggle ?? true}\n defaultView={props.defaultView ?? \"grid\"}\n gridSize={props.gridSize ?? \"sm\"}\n searchable\n filterOptions={filterOptions}\n searchPlaceholder={messages().search}\n icon={selectedOption()?.icon ?? \"ti ti-icons\"}\n />\n );\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -124,8 +124,11 @@ export const placeChoicePopover = (trigger, popover, placement = {}) => {
|
|
|
124
124
|
// panel that no longer lines up with the control it belongs to.
|
|
125
125
|
const triggerWidth = Math.min(triggerRect.width, window.innerWidth - margin * 2);
|
|
126
126
|
if (placement.width !== "own") popover.style.width = `${triggerWidth}px`;
|
|
127
|
+
|
|
128
|
+
// A stylesheet minimum, such as a popover with filter chips, can make it
|
|
129
|
+
// wider than the trigger, so the clamp below uses the rendered width.
|
|
127
130
|
const popoverRect = popover.getBoundingClientRect();
|
|
128
|
-
const width =
|
|
131
|
+
const width = popoverRect.width;
|
|
129
132
|
const left = Math.max(margin, Math.min(triggerRect.left, window.innerWidth - width - margin));
|
|
130
133
|
const roomBelow = window.innerHeight - triggerRect.bottom - gap - margin;
|
|
131
134
|
const roomAbove = triggerRect.top - gap - margin;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["inputs/choice.ts"],"sourcesContent":["import { createEffect, createSignal, onCleanup, type Setter } from \"solid-js\";\nimport { returnFocus, ringOnReturn } from \"../internal/focus-return\";\n\nexport type ChoiceOption<T extends string = string> = {\n value: T;\n label: string;\n description?: string;\n icon?: string;\n color?: string;\n disabled?: boolean;\n /** Optional overlapping groups used by choice controls that expose group filtering. */\n groups?: readonly string[];\n};\n\nexport type ChoiceOptionsLoader<T extends string = string> = (query: string, signal: AbortSignal) => Promise<readonly ChoiceOption<T>[]>;\n\n/** Matches label, description, value, and optional extra keywords. */\nexport const filterChoiceOptions = <\n O extends Pick<ChoiceOption<string>, \"label\" | \"description\" | \"value\"> & { keywords?: readonly string[] },\n>(\n options: readonly O[],\n query: string,\n): readonly O[] => {\n const normalized = query.trim().toLocaleLowerCase();\n if (!normalized) return options;\n return options.filter((option) =>\n [option.label, option.description, option.value, ...(option.keywords ?? [])].some((part) =>\n part?.toLocaleLowerCase().includes(normalized),\n ),\n );\n};\n\n/**\n * Moves through the options and wraps at the ends, skipping `disabled` ones. A\n * RichSelect row that cannot be chosen carries a `disabledReason` instead, so\n * the arrow keys still reach it and its reason can be read.\n */\nexport const nextEnabledChoiceIndex = <O extends { label: string; disabled?: boolean }>(\n options: readonly O[],\n current: number,\n direction: 1 | -1,\n): number => {\n if (options.length === 0 || options.every((option) => option.disabled)) return -1;\n\n let index = current;\n for (let visited = 0; visited < options.length; visited += 1) {\n index = (index + direction + options.length) % options.length;\n if (!options[index]?.disabled) return index;\n }\n return -1;\n};\n\n/**\n * Counts the leading pills that fit into `available` pixels and measures the\n * whole row. When not all of them fit, the rest collapse into a summary pill\n * of width `more`; the first pill always stays and truncates when even it does\n * not fit. Without a measured width (no layout yet) every pill stays. Half a\n * pixel of slack absorbs layout rounding, so a row given exactly its own\n * `rowWidth` always fits.\n */\nexport const fitChoicePills = (\n available: number,\n widths: readonly number[],\n gap: number,\n more: number,\n): { visible: number; rowWidth: number } => {\n const rowWidth = widths.reduce((sum, width) => sum + width, 0) + gap * Math.max(0, widths.length - 1);\n if (available <= 0 || rowWidth <= available + 0.5) return { visible: widths.length, rowWidth };\n let used = more;\n let visible = 0;\n for (const width of widths) {\n used += gap + width;\n if (used > available) break;\n visible += 1;\n }\n return { visible: Math.max(1, visible), rowWidth };\n};\n\nconst errorMessage = (error: unknown): string => (error instanceof Error ? error.message : \"Failed to load options\");\n\nexport function createChoiceLoader<T extends string>(\n loader: () => ChoiceOptionsLoader<T> | undefined,\n debounceMs: () => number,\n): {\n options: () => readonly ChoiceOption<T>[];\n loading: () => boolean;\n error: () => string | undefined;\n load: (query: string, immediate?: boolean) => void;\n retry: () => void;\n cancel: () => void;\n} {\n const [options, setOptions] = createSignal<readonly ChoiceOption<T>[]>([]);\n const [loading, setLoading] = createSignal(false);\n const [error, setError] = createSignal<string>();\n let controller: AbortController | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let request = 0;\n let lastQuery = \"\";\n\n const cancel = () => {\n if (timer) clearTimeout(timer);\n timer = undefined;\n controller?.abort();\n controller = undefined;\n };\n\n const run = async (query: string) => {\n const loadOptions = loader();\n if (!loadOptions) return;\n\n controller?.abort();\n controller = new AbortController();\n const currentController = controller;\n const currentRequest = ++request;\n setLoading(true);\n setError(undefined);\n\n try {\n const next = await loadOptions(query, currentController.signal);\n if (currentRequest === request && !currentController.signal.aborted) setOptions(next);\n } catch (reason) {\n if (currentRequest === request && !currentController.signal.aborted) {\n setOptions([]);\n setError(errorMessage(reason));\n }\n } finally {\n if (currentRequest === request) setLoading(false);\n }\n };\n\n const load = (query: string, immediate = false) => {\n lastQuery = query;\n if (timer) clearTimeout(timer);\n timer = undefined;\n if (immediate || debounceMs() <= 0) {\n void run(query);\n return;\n }\n timer = setTimeout(() => {\n timer = undefined;\n void run(query);\n }, debounceMs());\n };\n\n onCleanup(cancel);\n return { options, loading, error, load, retry: () => load(lastQuery, true), cancel };\n}\n\nconst popoverIsOpen = (popover: HTMLElement | undefined): boolean => {\n if (!popover) return false;\n try {\n return popover.matches(\":popover-open\");\n } catch {\n return false;\n }\n};\n\nexport type ChoicePopoverPlacement = {\n /**\n * `trigger` (default) gives the popover the trigger's width; `own` keeps the\n * width its stylesheet sets, such as a RichSelect with a preview.\n */\n width?: \"trigger\" | \"own\";\n /** The side tried first. The popover flips when the other side has more room. */\n side?: \"below\" | \"above\";\n};\n\nexport const placeChoicePopover = (trigger: HTMLElement, popover: HTMLElement, placement: ChoicePopoverPlacement = {}): void => {\n const margin = 8;\n const gap = 4;\n const triggerRect = trigger.getBoundingClientRect();\n // Cloud sizes its dropdowns to the trigger exactly (`dialog.style.width =\n // rect.width`). Keep that so a narrow toolbar select does not open a wide\n // panel that no longer lines up with the control it belongs to.\n const triggerWidth = Math.min(triggerRect.width, window.innerWidth - margin * 2);\n if (placement.width !== \"own\") popover.style.width = `${triggerWidth}px`;\n\n const popoverRect = popover.getBoundingClientRect();\n const width = placement.width === \"own\" ? popoverRect.width : triggerWidth;\n const left = Math.max(margin, Math.min(triggerRect.left, window.innerWidth - width - margin));\n const roomBelow = window.innerHeight - triggerRect.bottom - gap - margin;\n const roomAbove = triggerRect.top - gap - margin;\n const opensAbove =\n placement.side === \"above\"\n ? popoverRect.height <= roomAbove || roomAbove > roomBelow\n : popoverRect.height > roomBelow && roomAbove > roomBelow;\n const top = opensAbove\n ? Math.max(margin, triggerRect.top - popoverRect.height - gap)\n : Math.min(triggerRect.bottom + gap, window.innerHeight - popoverRect.height - margin);\n\n popover.style.left = `${left}px`;\n popover.style.top = `${Math.max(margin, top)}px`;\n};\n\nexport function createChoicePopover(\n disabled: () => boolean,\n placement: () => ChoicePopoverPlacement = () => ({}),\n): {\n open: () => boolean;\n setTrigger: Setter<HTMLElement | undefined>;\n setPopover: Setter<HTMLElement | undefined>;\n show: () => void;\n hide: (restoreFocus?: boolean) => void;\n toggle: () => void;\n trigger: () => HTMLElement | undefined;\n} {\n const [open, setOpen] = createSignal(false);\n const [trigger, setTrigger] = createSignal<HTMLElement>();\n const [popover, setPopover] = createSignal<HTMLElement>();\n let triggerRing = true;\n\n const place = () => {\n const triggerElement = trigger();\n const popoverElement = popover();\n if (triggerElement && popoverElement && open()) placeChoicePopover(triggerElement, popoverElement, placement());\n };\n\n const show = () => {\n const popoverElement = popover();\n if (disabled() || !popoverElement || popoverIsOpen(popoverElement)) return;\n triggerRing = ringOnReturn(trigger());\n popoverElement.showPopover();\n setOpen(true);\n queueMicrotask(place);\n };\n\n const hide = (restoreFocus = false) => {\n const popoverElement = popover();\n // Before hiding, so the popover does not return focus on its own.\n if (restoreFocus) returnFocus(trigger(), triggerRing);\n if (popoverIsOpen(popoverElement)) popoverElement?.hidePopover();\n setOpen(false);\n };\n\n createEffect(() => {\n const popoverElement = popover();\n if (!popoverElement) return;\n const syncOpenState = () => setOpen(popoverIsOpen(popoverElement));\n const containWheel = (event: WheelEvent) => {\n if (event.ctrlKey) return;\n event.preventDefault();\n\n const target = event.target instanceof Element ? event.target : undefined;\n const groups = target?.closest<HTMLElement>(\".k2b-choice-groups\");\n const horizontalDelta = event.shiftKey && event.deltaX === 0 ? event.deltaY : event.deltaX;\n if (groups && (event.shiftKey || Math.abs(event.deltaX) > Math.abs(event.deltaY)) && groups.scrollWidth > groups.clientWidth) {\n const unit = event.deltaMode === 1 ? 16 : event.deltaMode === 2 ? groups.clientWidth : 1;\n groups.scrollLeft += horizontalDelta * unit;\n return;\n }\n\n // A popover with more than one scrolling region, such as a list beside a\n // preview, marks them; the wheel scrolls the one under the pointer.\n const options =\n target?.closest<HTMLElement>(\"[data-choice-scroll]\") ?? popoverElement.querySelector<HTMLElement>(\".k2b-choice-options\");\n if (!options || options.scrollHeight <= options.clientHeight) return;\n const unit = event.deltaMode === 1 ? 16 : event.deltaMode === 2 ? options.clientHeight : 1;\n options.scrollTop += event.deltaY * unit;\n };\n popoverElement.addEventListener(\"toggle\", syncOpenState);\n popoverElement.addEventListener(\"wheel\", containWheel, { passive: false });\n onCleanup(() => {\n popoverElement.removeEventListener(\"toggle\", syncOpenState);\n popoverElement.removeEventListener(\"wheel\", containWheel);\n });\n });\n\n createEffect(() => {\n if (!open()) return;\n\n const dismiss = (event: PointerEvent) => {\n const target = event.target;\n if (!(target instanceof Node) || trigger()?.contains(target) || popover()?.contains(target)) return;\n hide();\n };\n const reposition = () => place();\n\n // Async option lists arrive after the popover is already open, so the first\n // placement measures an empty panel. Re-place whenever the panel resizes,\n // otherwise a dropdown that grows past the viewport bottom stays clipped.\n const popoverElement = popover();\n const observer = popoverElement && typeof ResizeObserver !== \"undefined\" ? new ResizeObserver(reposition) : undefined;\n if (popoverElement) observer?.observe(popoverElement);\n\n document.addEventListener(\"pointerdown\", dismiss, true);\n window.addEventListener(\"resize\", reposition);\n window.addEventListener(\"scroll\", reposition, true);\n onCleanup(() => {\n observer?.disconnect();\n document.removeEventListener(\"pointerdown\", dismiss, true);\n window.removeEventListener(\"resize\", reposition);\n window.removeEventListener(\"scroll\", reposition, true);\n });\n });\n\n onCleanup(() => hide());\n return {\n open,\n setTrigger,\n setPopover,\n show,\n hide,\n toggle: () => (open() ? hide() : show()),\n trigger,\n };\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["inputs/choice.ts"],"sourcesContent":["import { createEffect, createSignal, onCleanup, type Setter } from \"solid-js\";\nimport { returnFocus, ringOnReturn } from \"../internal/focus-return\";\n\nexport type ChoiceOption<T extends string = string> = {\n value: T;\n label: string;\n description?: string;\n icon?: string;\n color?: string;\n disabled?: boolean;\n /** Optional overlapping groups used by choice controls that expose group filtering. */\n groups?: readonly string[];\n};\n\nexport type ChoiceOptionsLoader<T extends string = string> = (query: string, signal: AbortSignal) => Promise<readonly ChoiceOption<T>[]>;\n\n/** Matches label, description, value, and optional extra keywords. */\nexport const filterChoiceOptions = <\n O extends Pick<ChoiceOption<string>, \"label\" | \"description\" | \"value\"> & { keywords?: readonly string[] },\n>(\n options: readonly O[],\n query: string,\n): readonly O[] => {\n const normalized = query.trim().toLocaleLowerCase();\n if (!normalized) return options;\n return options.filter((option) =>\n [option.label, option.description, option.value, ...(option.keywords ?? [])].some((part) =>\n part?.toLocaleLowerCase().includes(normalized),\n ),\n );\n};\n\n/**\n * Moves through the options and wraps at the ends, skipping `disabled` ones. A\n * RichSelect row that cannot be chosen carries a `disabledReason` instead, so\n * the arrow keys still reach it and its reason can be read.\n */\nexport const nextEnabledChoiceIndex = <O extends { label: string; disabled?: boolean }>(\n options: readonly O[],\n current: number,\n direction: 1 | -1,\n): number => {\n if (options.length === 0 || options.every((option) => option.disabled)) return -1;\n\n let index = current;\n for (let visited = 0; visited < options.length; visited += 1) {\n index = (index + direction + options.length) % options.length;\n if (!options[index]?.disabled) return index;\n }\n return -1;\n};\n\n/**\n * Counts the leading pills that fit into `available` pixels and measures the\n * whole row. When not all of them fit, the rest collapse into a summary pill\n * of width `more`; the first pill always stays and truncates when even it does\n * not fit. Without a measured width (no layout yet) every pill stays. Half a\n * pixel of slack absorbs layout rounding, so a row given exactly its own\n * `rowWidth` always fits.\n */\nexport const fitChoicePills = (\n available: number,\n widths: readonly number[],\n gap: number,\n more: number,\n): { visible: number; rowWidth: number } => {\n const rowWidth = widths.reduce((sum, width) => sum + width, 0) + gap * Math.max(0, widths.length - 1);\n if (available <= 0 || rowWidth <= available + 0.5) return { visible: widths.length, rowWidth };\n let used = more;\n let visible = 0;\n for (const width of widths) {\n used += gap + width;\n if (used > available) break;\n visible += 1;\n }\n return { visible: Math.max(1, visible), rowWidth };\n};\n\nconst errorMessage = (error: unknown): string => (error instanceof Error ? error.message : \"Failed to load options\");\n\nexport function createChoiceLoader<T extends string>(\n loader: () => ChoiceOptionsLoader<T> | undefined,\n debounceMs: () => number,\n): {\n options: () => readonly ChoiceOption<T>[];\n loading: () => boolean;\n error: () => string | undefined;\n load: (query: string, immediate?: boolean) => void;\n retry: () => void;\n cancel: () => void;\n} {\n const [options, setOptions] = createSignal<readonly ChoiceOption<T>[]>([]);\n const [loading, setLoading] = createSignal(false);\n const [error, setError] = createSignal<string>();\n let controller: AbortController | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let request = 0;\n let lastQuery = \"\";\n\n const cancel = () => {\n if (timer) clearTimeout(timer);\n timer = undefined;\n controller?.abort();\n controller = undefined;\n };\n\n const run = async (query: string) => {\n const loadOptions = loader();\n if (!loadOptions) return;\n\n controller?.abort();\n controller = new AbortController();\n const currentController = controller;\n const currentRequest = ++request;\n setLoading(true);\n setError(undefined);\n\n try {\n const next = await loadOptions(query, currentController.signal);\n if (currentRequest === request && !currentController.signal.aborted) setOptions(next);\n } catch (reason) {\n if (currentRequest === request && !currentController.signal.aborted) {\n setOptions([]);\n setError(errorMessage(reason));\n }\n } finally {\n if (currentRequest === request) setLoading(false);\n }\n };\n\n const load = (query: string, immediate = false) => {\n lastQuery = query;\n if (timer) clearTimeout(timer);\n timer = undefined;\n if (immediate || debounceMs() <= 0) {\n void run(query);\n return;\n }\n timer = setTimeout(() => {\n timer = undefined;\n void run(query);\n }, debounceMs());\n };\n\n onCleanup(cancel);\n return { options, loading, error, load, retry: () => load(lastQuery, true), cancel };\n}\n\nconst popoverIsOpen = (popover: HTMLElement | undefined): boolean => {\n if (!popover) return false;\n try {\n return popover.matches(\":popover-open\");\n } catch {\n return false;\n }\n};\n\nexport type ChoicePopoverPlacement = {\n /**\n * `trigger` (default) gives the popover the trigger's width; `own` keeps the\n * width its stylesheet sets, such as a RichSelect with a preview.\n */\n width?: \"trigger\" | \"own\";\n /** The side tried first. The popover flips when the other side has more room. */\n side?: \"below\" | \"above\";\n};\n\nexport const placeChoicePopover = (trigger: HTMLElement, popover: HTMLElement, placement: ChoicePopoverPlacement = {}): void => {\n const margin = 8;\n const gap = 4;\n const triggerRect = trigger.getBoundingClientRect();\n // Cloud sizes its dropdowns to the trigger exactly (`dialog.style.width =\n // rect.width`). Keep that so a narrow toolbar select does not open a wide\n // panel that no longer lines up with the control it belongs to.\n const triggerWidth = Math.min(triggerRect.width, window.innerWidth - margin * 2);\n if (placement.width !== \"own\") popover.style.width = `${triggerWidth}px`;\n\n // A stylesheet minimum, such as a popover with filter chips, can make it\n // wider than the trigger, so the clamp below uses the rendered width.\n const popoverRect = popover.getBoundingClientRect();\n const width = popoverRect.width;\n const left = Math.max(margin, Math.min(triggerRect.left, window.innerWidth - width - margin));\n const roomBelow = window.innerHeight - triggerRect.bottom - gap - margin;\n const roomAbove = triggerRect.top - gap - margin;\n const opensAbove =\n placement.side === \"above\"\n ? popoverRect.height <= roomAbove || roomAbove > roomBelow\n : popoverRect.height > roomBelow && roomAbove > roomBelow;\n const top = opensAbove\n ? Math.max(margin, triggerRect.top - popoverRect.height - gap)\n : Math.min(triggerRect.bottom + gap, window.innerHeight - popoverRect.height - margin);\n\n popover.style.left = `${left}px`;\n popover.style.top = `${Math.max(margin, top)}px`;\n};\n\nexport function createChoicePopover(\n disabled: () => boolean,\n placement: () => ChoicePopoverPlacement = () => ({}),\n): {\n open: () => boolean;\n setTrigger: Setter<HTMLElement | undefined>;\n setPopover: Setter<HTMLElement | undefined>;\n show: () => void;\n hide: (restoreFocus?: boolean) => void;\n toggle: () => void;\n trigger: () => HTMLElement | undefined;\n} {\n const [open, setOpen] = createSignal(false);\n const [trigger, setTrigger] = createSignal<HTMLElement>();\n const [popover, setPopover] = createSignal<HTMLElement>();\n let triggerRing = true;\n\n const place = () => {\n const triggerElement = trigger();\n const popoverElement = popover();\n if (triggerElement && popoverElement && open()) placeChoicePopover(triggerElement, popoverElement, placement());\n };\n\n const show = () => {\n const popoverElement = popover();\n if (disabled() || !popoverElement || popoverIsOpen(popoverElement)) return;\n triggerRing = ringOnReturn(trigger());\n popoverElement.showPopover();\n setOpen(true);\n queueMicrotask(place);\n };\n\n const hide = (restoreFocus = false) => {\n const popoverElement = popover();\n // Before hiding, so the popover does not return focus on its own.\n if (restoreFocus) returnFocus(trigger(), triggerRing);\n if (popoverIsOpen(popoverElement)) popoverElement?.hidePopover();\n setOpen(false);\n };\n\n createEffect(() => {\n const popoverElement = popover();\n if (!popoverElement) return;\n const syncOpenState = () => setOpen(popoverIsOpen(popoverElement));\n const containWheel = (event: WheelEvent) => {\n if (event.ctrlKey) return;\n event.preventDefault();\n\n const target = event.target instanceof Element ? event.target : undefined;\n const groups = target?.closest<HTMLElement>(\".k2b-choice-groups\");\n const horizontalDelta = event.shiftKey && event.deltaX === 0 ? event.deltaY : event.deltaX;\n if (groups && (event.shiftKey || Math.abs(event.deltaX) > Math.abs(event.deltaY)) && groups.scrollWidth > groups.clientWidth) {\n const unit = event.deltaMode === 1 ? 16 : event.deltaMode === 2 ? groups.clientWidth : 1;\n groups.scrollLeft += horizontalDelta * unit;\n return;\n }\n\n // A popover with more than one scrolling region, such as a list beside a\n // preview, marks them; the wheel scrolls the one under the pointer.\n const options =\n target?.closest<HTMLElement>(\"[data-choice-scroll]\") ?? popoverElement.querySelector<HTMLElement>(\".k2b-choice-options\");\n if (!options || options.scrollHeight <= options.clientHeight) return;\n const unit = event.deltaMode === 1 ? 16 : event.deltaMode === 2 ? options.clientHeight : 1;\n options.scrollTop += event.deltaY * unit;\n };\n popoverElement.addEventListener(\"toggle\", syncOpenState);\n popoverElement.addEventListener(\"wheel\", containWheel, { passive: false });\n onCleanup(() => {\n popoverElement.removeEventListener(\"toggle\", syncOpenState);\n popoverElement.removeEventListener(\"wheel\", containWheel);\n });\n });\n\n createEffect(() => {\n if (!open()) return;\n\n const dismiss = (event: PointerEvent) => {\n const target = event.target;\n if (!(target instanceof Node) || trigger()?.contains(target) || popover()?.contains(target)) return;\n hide();\n };\n const reposition = () => place();\n\n // Async option lists arrive after the popover is already open, so the first\n // placement measures an empty panel. Re-place whenever the panel resizes,\n // otherwise a dropdown that grows past the viewport bottom stays clipped.\n const popoverElement = popover();\n const observer = popoverElement && typeof ResizeObserver !== \"undefined\" ? new ResizeObserver(reposition) : undefined;\n if (popoverElement) observer?.observe(popoverElement);\n\n document.addEventListener(\"pointerdown\", dismiss, true);\n window.addEventListener(\"resize\", reposition);\n window.addEventListener(\"scroll\", reposition, true);\n onCleanup(() => {\n observer?.disconnect();\n document.removeEventListener(\"pointerdown\", dismiss, true);\n window.removeEventListener(\"resize\", reposition);\n window.removeEventListener(\"scroll\", reposition, true);\n });\n });\n\n onCleanup(() => hide());\n return {\n open,\n setTrigger,\n setPopover,\n show,\n hide,\n toggle: () => (open() ? hide() : show()),\n trigger,\n };\n}\n"],"mappings":"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","ignoreList":[]}
|