@k2b/ui 0.11.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/README.md +1 -1
  2. package/dist/browser/content/FileView.js +203 -136
  3. package/dist/browser/content/FileView.js.map +1 -1
  4. package/dist/browser/content/PdfPreview.js +5 -2
  5. package/dist/browser/content/PdfPreview.js.map +1 -1
  6. package/dist/browser/content/markdown-title.js +52 -0
  7. package/dist/browser/content/markdown-title.js.map +1 -0
  8. package/dist/browser/feedback/InstallGuide.js +267 -0
  9. package/dist/browser/feedback/InstallGuide.js.map +1 -0
  10. package/dist/browser/feedback/announce.js +50 -0
  11. package/dist/browser/feedback/announce.js.map +1 -0
  12. package/dist/browser/feedback/dialog-core.js +82 -1
  13. package/dist/browser/feedback/dialog-core.js.map +1 -1
  14. package/dist/browser/feedback/index.js +4 -0
  15. package/dist/browser/feedback/index.js.map +1 -1
  16. package/dist/browser/feedback/install.js +99 -0
  17. package/dist/browser/feedback/install.js.map +1 -0
  18. package/dist/browser/feedback/prompts.js +29 -20
  19. package/dist/browser/feedback/prompts.js.map +1 -1
  20. package/dist/browser/feedback/theme-color.js +15 -0
  21. package/dist/browser/feedback/theme-color.js.map +1 -0
  22. package/dist/browser/feedback/toast.js +329 -122
  23. package/dist/browser/feedback/toast.js.map +1 -1
  24. package/dist/browser/inputs/DatePicker.js +263 -222
  25. package/dist/browser/inputs/DatePicker.js.map +1 -1
  26. package/dist/browser/inputs/MultiSelectInput.js +139 -105
  27. package/dist/browser/inputs/MultiSelectInput.js.map +1 -1
  28. package/dist/browser/inputs/NumberInput.js +209 -122
  29. package/dist/browser/inputs/NumberInput.js.map +1 -1
  30. package/dist/browser/inputs/QrScanner.js +164 -0
  31. package/dist/browser/inputs/QrScanner.js.map +1 -0
  32. package/dist/browser/inputs/Select.js +184 -92
  33. package/dist/browser/inputs/Select.js.map +1 -1
  34. package/dist/browser/inputs/index.js +1 -0
  35. package/dist/browser/inputs/index.js.map +1 -1
  36. package/dist/browser/intl/messages.js +90 -2
  37. package/dist/browser/intl/messages.js.map +1 -1
  38. package/dist/browser/layout/DetailPanel.js +2 -1
  39. package/dist/browser/layout/DetailPanel.js.map +1 -1
  40. package/dist/browser/layout/Discussion.js +2 -1
  41. package/dist/browser/layout/Discussion.js.map +1 -1
  42. package/dist/browser/layout/MobileShell.js +242 -0
  43. package/dist/browser/layout/MobileShell.js.map +1 -0
  44. package/dist/browser/layout/Navigation.js +1 -0
  45. package/dist/browser/layout/Navigation.js.map +1 -1
  46. package/dist/browser/layout/PanelDialog.js +1 -0
  47. package/dist/browser/layout/PanelDialog.js.map +1 -1
  48. package/dist/browser/layout/Settings.js +2 -2
  49. package/dist/browser/layout/Settings.js.map +1 -1
  50. package/dist/browser/layout/TabBar.js +65 -0
  51. package/dist/browser/layout/TabBar.js.map +1 -0
  52. package/dist/browser/layout/index.js +2 -0
  53. package/dist/browser/layout/index.js.map +1 -1
  54. package/dist/browser/surfaces/NoticeCard.js +55 -60
  55. package/dist/browser/surfaces/NoticeCard.js.map +1 -1
  56. package/dist/browser/surfaces/index.js +1 -1
  57. package/dist/browser/surfaces/index.js.map +1 -1
  58. package/dist/ssr/content/FileView.js +141 -81
  59. package/dist/ssr/content/FileView.js.map +1 -1
  60. package/dist/ssr/content/PdfPreview.js +4 -2
  61. package/dist/ssr/content/PdfPreview.js.map +1 -1
  62. package/dist/ssr/content/markdown-title.js +52 -0
  63. package/dist/ssr/content/markdown-title.js.map +1 -0
  64. package/dist/ssr/feedback/InstallGuide.js +201 -0
  65. package/dist/ssr/feedback/InstallGuide.js.map +1 -0
  66. package/dist/ssr/feedback/announce.js +50 -0
  67. package/dist/ssr/feedback/announce.js.map +1 -0
  68. package/dist/ssr/feedback/dialog-core.js +82 -1
  69. package/dist/ssr/feedback/dialog-core.js.map +1 -1
  70. package/dist/ssr/feedback/index.js +4 -0
  71. package/dist/ssr/feedback/index.js.map +1 -1
  72. package/dist/ssr/feedback/install.js +99 -0
  73. package/dist/ssr/feedback/install.js.map +1 -0
  74. package/dist/ssr/feedback/prompts.js +12 -2
  75. package/dist/ssr/feedback/prompts.js.map +1 -1
  76. package/dist/ssr/feedback/theme-color.js +15 -0
  77. package/dist/ssr/feedback/theme-color.js.map +1 -0
  78. package/dist/ssr/feedback/toast.js +329 -122
  79. package/dist/ssr/feedback/toast.js.map +1 -1
  80. package/dist/ssr/inputs/DatePicker.js +78 -52
  81. package/dist/ssr/inputs/DatePicker.js.map +1 -1
  82. package/dist/ssr/inputs/MultiSelectInput.js +52 -32
  83. package/dist/ssr/inputs/MultiSelectInput.js.map +1 -1
  84. package/dist/ssr/inputs/NumberInput.js +93 -40
  85. package/dist/ssr/inputs/NumberInput.js.map +1 -1
  86. package/dist/ssr/inputs/QrScanner.js +128 -0
  87. package/dist/ssr/inputs/QrScanner.js.map +1 -0
  88. package/dist/ssr/inputs/Select.js +108 -29
  89. package/dist/ssr/inputs/Select.js.map +1 -1
  90. package/dist/ssr/inputs/index.js +1 -0
  91. package/dist/ssr/inputs/index.js.map +1 -1
  92. package/dist/ssr/intl/messages.js +90 -2
  93. package/dist/ssr/intl/messages.js.map +1 -1
  94. package/dist/ssr/layout/DetailPanel.js +2 -1
  95. package/dist/ssr/layout/DetailPanel.js.map +1 -1
  96. package/dist/ssr/layout/Discussion.js +2 -1
  97. package/dist/ssr/layout/Discussion.js.map +1 -1
  98. package/dist/ssr/layout/MobileShell.js +211 -0
  99. package/dist/ssr/layout/MobileShell.js.map +1 -0
  100. package/dist/ssr/layout/Navigation.js +1 -0
  101. package/dist/ssr/layout/Navigation.js.map +1 -1
  102. package/dist/ssr/layout/PanelDialog.js +1 -0
  103. package/dist/ssr/layout/PanelDialog.js.map +1 -1
  104. package/dist/ssr/layout/Settings.js +2 -2
  105. package/dist/ssr/layout/Settings.js.map +1 -1
  106. package/dist/ssr/layout/TabBar.js +24 -0
  107. package/dist/ssr/layout/TabBar.js.map +1 -0
  108. package/dist/ssr/layout/index.js +2 -0
  109. package/dist/ssr/layout/index.js.map +1 -1
  110. package/dist/ssr/surfaces/NoticeCard.js +21 -30
  111. package/dist/ssr/surfaces/NoticeCard.js.map +1 -1
  112. package/dist/ssr/surfaces/index.js +1 -1
  113. package/dist/ssr/surfaces/index.js.map +1 -1
  114. package/dist/styles.css +1 -1
  115. package/dist/tabler.css +1 -1
  116. package/dist/types/content/FileView.d.ts +11 -1
  117. package/dist/types/content/markdown-title.d.ts +9 -0
  118. package/dist/types/feedback/InstallGuide.d.ts +26 -0
  119. package/dist/types/feedback/announce.d.ts +19 -0
  120. package/dist/types/feedback/dialog-core.d.ts +5 -0
  121. package/dist/types/feedback/index.d.ts +8 -1
  122. package/dist/types/feedback/install.d.ts +32 -0
  123. package/dist/types/feedback/prompts.d.ts +2 -0
  124. package/dist/types/feedback/theme-color.d.ts +6 -0
  125. package/dist/types/feedback/toast.d.ts +7 -0
  126. package/dist/types/inputs/DatePicker.d.ts +11 -2
  127. package/dist/types/inputs/MultiSelectInput.d.ts +5 -1
  128. package/dist/types/inputs/NumberInput.d.ts +14 -0
  129. package/dist/types/inputs/QrScanner.d.ts +20 -0
  130. package/dist/types/inputs/Select.d.ts +10 -0
  131. package/dist/types/inputs/index.d.ts +3 -1
  132. package/dist/types/intl/messages.d.ts +44 -0
  133. package/dist/types/layout/MobileShell.d.ts +40 -0
  134. package/dist/types/layout/Settings.d.ts +2 -2
  135. package/dist/types/layout/TabBar.d.ts +23 -0
  136. package/dist/types/layout/index.d.ts +4 -0
  137. package/dist/types/surfaces/NoticeCard.d.ts +4 -4
  138. package/dist/types/surfaces/index.d.ts +1 -1
  139. package/package.json +3 -2
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["inputs/MultiSelectInput.tsx"],"sourcesContent":["import { createEffect, createMemo, createSignal, For, type JSX, onCleanup, onMount, Show } from \"solid-js\";\nimport { colorTintStyle, normalizeHexColor } from \"../internal/color\";\nimport { createFieldMeta, Field, fieldControlAria } from \"../internal/field\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { ChoiceGroups } from \"./ChoiceGroups\";\nimport {\n type ChoiceOption,\n createChoiceLoader,\n createChoicePopover,\n filterChoiceOptions,\n fitChoicePills,\n nextEnabledChoiceIndex,\n} from \"./choice\";\nimport type { ValueFieldProps } from \"./field-contract\";\nimport { commitFieldValue, resolveMaybeAccessor } from \"./field-contract\";\nimport type { SelectGroup } from \"./Select\";\n\nexport type MultiSelectOption =\n | string\n | { id: string; label?: string; description?: string; icon?: string; color?: string; groups?: readonly string[] }\n | ChoiceOption<string>;\ntype NormalizedOption = ChoiceOption<string>;\nexport type MultiSelectFetchDataFn = (query: string, signal: AbortSignal, group: string | null) => Promise<MultiSelectOption[]>;\n\nexport type MultiSelectInputProps = ValueFieldProps<string[]> & {\n options?: MultiSelectOption[];\n fetchData?: MultiSelectFetchDataFn;\n selectedOptions?: () => MultiSelectOption[];\n placeholder?: string;\n icon?: string;\n activeIcon?: string;\n fetchDebounceMs?: number;\n debounceMs?: number;\n loadOptions?: (query: string, signal: AbortSignal, group: string | null) => Promise<readonly ChoiceOption<string>[]>;\n groups?: readonly SelectGroup[];\n defaultGroup?: string;\n groupsAriaLabel?: string;\n allGroupLabel?: string;\n searchable?: boolean;\n clearable?: boolean;\n name?: string;\n renderOption?: (option: ChoiceOption<string>) => JSX.Element;\n renderValue?: (option: ChoiceOption<string>) => JSX.Element;\n searchPlaceholder?: string;\n loadingLabel?: string;\n noResultsLabel?: string;\n emptyLabel?: string;\n retryLabel?: string;\n clearLabel?: string;\n};\n\n/** Cloud tints the option icon with the option color instead of adding a dot. */\nconst iconColor = (color: string | undefined): JSX.CSSProperties | undefined => {\n const normalized = normalizeHexColor(color);\n return normalized ? { color: normalized } : undefined;\n};\n\nconst normalize = (option: MultiSelectOption): 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 MultiSelectInput(props: MultiSelectInputProps): JSX.Element {\n const messages = useUiMessages();\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 let searchRef: HTMLInputElement | undefined;\n\n const values = () => resolveMaybeAccessor(props.value) ?? [];\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 asyncOptions = createChoiceLoader(\n () =>\n props.fetchData\n ? async (query, signal) => (await props.fetchData!(query, signal, activeGroup())).map(normalize)\n : props.loadOptions\n ? (query, signal) => props.loadOptions!(query, signal, activeGroup())\n : undefined,\n () => props.fetchDebounceMs ?? props.debounceMs ?? 200,\n );\n const isAsync = () => Boolean(props.fetchData || props.loadOptions);\n const sourceOptions = createMemo(() => (isAsync() ? asyncOptions.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 // Cloud's multi-select always renders its search field, and filters a static\n // option list client-side while a remote loader filters server-side.\n const searchable = () => isAsync() || (props.searchable ?? true);\n const visibleOptions = createMemo(() =>\n isAsync() ? groupedOptions() : filterChoiceOptions(groupedOptions(), searchable() ? query() : \"\"),\n );\n const optionByValue = createMemo(() => {\n const options = new Map<string, NormalizedOption>();\n for (const option of Object.values(cache())) options.set(option.value, option);\n for (const option of (props.selectedOptions?.() ?? []).map(normalize)) options.set(option.value, option);\n for (const option of sourceOptions()) options.set(option.value, option);\n return options;\n });\n const selected = createMemo(() => values().map((value) => optionByValue().get(value) ?? ({ value, label: value } as NormalizedOption)));\n const hasClearAction = () => Boolean(props.clearable && selected().length > 0 && !props.disabled);\n const selectedValues = createMemo(() => new Set(values()));\n const popover = createChoicePopover(() => Boolean(props.disabled));\n const focusedOption = () => visibleOptions()[focusedIndex()];\n\n // Pills that do not fit the trigger collapse into a \"+N\" summary. Until the\n // browser measures them (server HTML, hidden containers) every pill stays.\n let valuesRef: HTMLSpanElement | undefined;\n let moreRef: HTMLSpanElement | undefined;\n const [visibleCount, setVisibleCount] = createSignal(Number.POSITIVE_INFINITY);\n const hiddenOptions = createMemo(() => selected().slice(visibleCount()));\n // While every pill fits, the invisible summary carries the largest count it\n // could show, so measuring it reserves enough room for the real one.\n const moreCount = () => hiddenOptions().length || selected().length - 1;\n const fitValues = () => {\n const values = valuesRef;\n if (!values?.isConnected) return;\n // Measuring releases a truncated first pill to its natural width; the\n // browser paints only the final state.\n values.dataset.measuring = \"true\";\n const pills = Array.from(\n values.querySelectorAll<HTMLElement>(\":scope > .k2b-choice-pill\"),\n (pill) => pill.getBoundingClientRect().width,\n );\n const fit = fitChoicePills(\n values.getBoundingClientRect().width,\n pills,\n Number.parseFloat(getComputedStyle(values).columnGap) || 0,\n moreRef?.isConnected ? moreRef.getBoundingClientRect().width : 0,\n );\n delete values.dataset.measuring;\n // Hidden pills leave the flow. While any are hidden the strip keeps the\n // whole row as its preferred width, so a container sized by its content\n // does not shrink with the collapse and grows back once it has room. The\n // strip still flexes to the trigger's width.\n values.style.width = fit.visible < pills.length ? `${fit.rowWidth}px` : \"\";\n setVisibleCount(fit.visible);\n };\n const resizeObserver = typeof ResizeObserver === \"undefined\" ? undefined : new ResizeObserver(() => fitValues());\n onCleanup(() => resizeObserver?.disconnect());\n createEffect(() => {\n selected();\n fitValues();\n });\n onMount(() => {\n if (\"fonts\" in document) void document.fonts.ready.then(fitValues);\n });\n\n const emit = (next: readonly string[]) => {\n const unique = [...new Set(next)];\n commitFieldValue(props, unique);\n };\n const isSelected = (value: string) => selectedValues().has(value);\n const focusFirst = () => setFocusedIndex(nextEnabledChoiceIndex(visibleOptions(), -1, 1));\n const chooseGroup = (group: string | null) => {\n if (group === activeGroup()) return;\n setSelectedGroup(group);\n focusFirst();\n if (isAsync()) asyncOptions.load(query(), true);\n };\n const open = () => {\n if (props.disabled) return;\n setQuery(\"\");\n if (isAsync()) asyncOptions.load(\"\", true);\n focusFirst();\n popover.show();\n if (searchable()) queueMicrotask(() => searchRef?.focus());\n };\n const close = (restoreFocus = false) => {\n asyncOptions.cancel();\n setQuery(\"\");\n setFocusedIndex(-1);\n popover.hide(restoreFocus);\n };\n const toggleOption = (option: NormalizedOption) => {\n if (option.disabled) return;\n setCache({ ...cache(), [option.value]: option });\n emit(isSelected(option.value) ? values().filter((value) => value !== option.value) : [...values(), option.value]);\n };\n const remove = (value: string) => emit(values().filter((item) => item !== value));\n const move = (direction: 1 | -1) => {\n setFocusedIndex(nextEnabledChoiceIndex(visibleOptions(), focusedIndex(), direction));\n };\n const handleKeyDown = (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 return;\n }\n if ((event.key === \"Enter\" || event.key === \" \") && !popover.open()) {\n event.preventDefault();\n open();\n return;\n }\n if (event.key === \"Enter\" && popover.open()) {\n const option = focusedOption();\n if (option) {\n event.preventDefault();\n toggleOption(option);\n }\n return;\n }\n if (event.key === \"Backspace\" && popover.open() && !query() && values().length > 0) {\n event.preventDefault();\n const last = values().at(-1);\n if (last) remove(last);\n return;\n }\n if (event.key === \"Escape\" && popover.open()) {\n event.preventDefault();\n close(true);\n } else if (event.key === \"Tab\" && popover.open()) {\n close();\n }\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 labelFor={false}\n required={props.required}\n disabled={props.disabled}\n >\n <div class=\"k2b-choice-control\" data-invalid={error() ? \"true\" : undefined}>\n <div\n ref={(element) => {\n popover.setTrigger(element);\n resizeObserver?.observe(element);\n }}\n id={meta.controlId}\n class=\"k2b-multi-select-trigger\"\n role=\"combobox\"\n tabIndex={props.disabled ? -1 : 0}\n aria-haspopup=\"listbox\"\n aria-expanded={popover.open()}\n aria-controls={listboxId}\n aria-activedescendant={focusedOption() ? `${listboxId}-${focusedIndex()}` : undefined}\n {...fieldControlAria(meta, props)}\n aria-disabled={props.disabled}\n data-disabled={props.disabled ? \"true\" : undefined}\n onClick={() => (popover.open() ? close() : open())}\n onKeyDown={handleKeyDown}\n >\n <Show\n when={selected().length > 0}\n fallback={\n <span class=\"k2b-choice-trigger__value\" data-placeholder=\"true\">\n {props.placeholder ?? messages().select}\n </span>\n }\n >\n <span\n ref={valuesRef}\n class=\"k2b-multi-select-trigger__values\"\n data-overflowing={hiddenOptions().length > 0 ? \"true\" : undefined}\n >\n <For each={selected()}>\n {(option, index) => (\n <span\n class=\"k2b-choice-pill\"\n style={colorTintStyle(option.color)}\n title={option.label}\n data-hidden={index() >= visibleCount() ? \"true\" : undefined}\n >\n <Show\n when={props.renderValue}\n fallback={\n <>\n <Show when={option.icon}>{(icon) => <i class={icon()} aria-hidden=\"true\" />}</Show>\n <span>{option.label}</span>\n </>\n }\n >\n {(render) => <span class=\"k2b-choice-pill__content\">{render()(option)}</span>}\n </Show>\n <button\n type=\"button\"\n aria-label={messages().removeNamed({ name: option.label })}\n disabled={props.disabled}\n tabIndex={-1}\n onClick={(event) => {\n event.stopPropagation();\n remove(option.value);\n }}\n >\n <i class=\"ti ti-x\" aria-hidden=\"true\" />\n </button>\n </span>\n )}\n </For>\n <Show when={selected().length > 1}>\n <span\n ref={(element) => {\n moreRef = element;\n resizeObserver?.observe(element);\n onCleanup(() => resizeObserver?.unobserve(element));\n }}\n class=\"k2b-multi-select-trigger__more\"\n title={\n hiddenOptions()\n .map((option) => option.label)\n .join(\", \") || undefined\n }\n data-hidden={hiddenOptions().length === 0 ? \"true\" : undefined}\n >\n <span aria-hidden=\"true\">+{moreCount()}</span>\n <span class=\"k2b-sr-only\">{messages().moreSelected({ count: moreCount() })}</span>\n </span>\n </Show>\n </span>\n </Show>\n <Show when={!hasClearAction()}>\n <i\n class={`${popover.open() ? (props.activeIcon ?? \"ti ti-chevron-up\") : (props.icon ?? \"ti ti-chevron-down\")} k2b-multi-select-trigger__chevron`}\n aria-hidden=\"true\"\n />\n </Show>\n </div>\n <Show when={hasClearAction()}>\n <button\n type=\"button\"\n class=\"k2b-choice-control__clear k2b-input-clear-action\"\n aria-label={props.clearLabel ?? messages().clearSelection}\n onClick={(event) => {\n event.stopPropagation();\n emit([]);\n popover.trigger()?.focus();\n }}\n >\n <i class=\"ti ti-x\" aria-hidden=\"true\" />\n </button>\n </Show>\n\n <div\n ref={popover.setPopover}\n popover=\"manual\"\n class=\"k2b-choice-popover\"\n role=\"group\"\n onKeyDown={handleKeyDown}\n aria-label={typeof props.label === \"string\" ? props.label : (props[\"aria-label\"] ?? messages().options)}\n >\n <Show when={searchable()}>\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 ?? messages().searchOptions}\n aria-controls={listboxId}\n aria-activedescendant={focusedOption() ? `${listboxId}-${focusedIndex()}` : undefined}\n onInput={(event) => {\n const next = event.currentTarget.value;\n setQuery(next);\n if (isAsync()) asyncOptions.load(next);\n focusFirst();\n }}\n />\n </div>\n </Show>\n <Show when={(props.groups?.length ?? 0) > 0}>\n <div class=\"k2b-choice-toolbar\">\n <ChoiceGroups\n choices={groupChoices()}\n value={activeGroup()}\n onValueChange={chooseGroup}\n ariaLabel={props.groupsAriaLabel ?? messages().filterOptions}\n controls={listboxId}\n />\n </div>\n </Show>\n <div id={listboxId} class=\"k2b-choice-options\" role=\"listbox\" aria-multiselectable=\"true\">\n <Show when={asyncOptions.error()}>\n {(message) => (\n <div class=\"k2b-choice-status\" data-tone=\"danger\">\n <span>{message()}</span>\n <button type=\"button\" onClick={asyncOptions.retry}>\n {props.retryLabel ?? messages().retry}\n </button>\n </div>\n )}\n </Show>\n <Show when={asyncOptions.loading() && visibleOptions().length === 0}>\n <div class=\"k2b-choice-status\">\n <i class=\"ti ti-loader-2 k2b-spin\" aria-hidden=\"true\" />\n <span>{props.loadingLabel ?? messages().loading}</span>\n </div>\n </Show>\n <For\n each={asyncOptions.error() ? [] : visibleOptions()}\n fallback={\n <Show when={!asyncOptions.loading() && !asyncOptions.error()}>\n <div class=\"k2b-choice-status\">\n {isAsync() || query() ? (props.noResultsLabel ?? messages().noResults) : (props.emptyLabel ?? messages().noOptions)}\n </div>\n </Show>\n }\n >\n {(option, index) => (\n <button\n type=\"button\"\n id={`${listboxId}-${index()}`}\n class=\"k2b-choice-option\"\n role=\"option\"\n aria-label={option.label}\n aria-selected={isSelected(option.value)}\n data-focused={index() === focusedIndex() ? \"true\" : undefined}\n disabled={option.disabled}\n onPointerMove={() => !option.disabled && setFocusedIndex(index())}\n onClick={() => toggleOption(option)}\n >\n <span class=\"k2b-choice-option__checkbox\" aria-hidden=\"true\">\n <i class=\"ti ti-check\" />\n </span>\n <Show\n when={option.icon}\n fallback={\n <Show when={normalizeHexColor(option.color)}>\n {(color) => <span class=\"k2b-choice-dot\" style={{ background: color() }} aria-hidden=\"true\" />}\n </Show>\n }\n >\n {(icon) => <i class={icon()} style={iconColor(option.color)} aria-hidden=\"true\" />}\n </Show>\n <span class=\"k2b-choice-option__content\">\n <Show\n when={props.renderOption}\n fallback={\n <>\n <strong>{option.label}</strong>\n <Show when={option.description}>{(description) => <small>{description()}</small>}</Show>\n </>\n }\n >\n {(render) => render()(option)}\n </Show>\n </span>\n </button>\n )}\n </For>\n </div>\n </div>\n <Show when={props.name}>{(name) => <input type=\"hidden\" name={name()} value={values().join(\",\")} />}</Show>\n </div>\n </Field>\n );\n}\n\nexport default MultiSelectInput;\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["inputs/MultiSelectInput.tsx"],"sourcesContent":["import { createEffect, createMemo, createSignal, For, type JSX, onCleanup, onMount, Show } from \"solid-js\";\nimport { colorTintStyle, normalizeHexColor } from \"../internal/color\";\nimport { createFieldMeta, Field, fieldControlAria } from \"../internal/field\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { ChoiceGroups } from \"./ChoiceGroups\";\nimport {\n type ChoiceOption,\n createChoiceLoader,\n createChoicePopover,\n filterChoiceOptions,\n fitChoicePills,\n nextEnabledChoiceIndex,\n} from \"./choice\";\nimport type { ValueFieldProps } from \"./field-contract\";\nimport { commitFieldValue, resolveMaybeAccessor } from \"./field-contract\";\nimport type { ChoiceAppearance, SelectGroup } from \"./Select\";\n\nexport type MultiSelectOption =\n | string\n | { id: string; label?: string; description?: string; icon?: string; color?: string; groups?: readonly string[] }\n | ChoiceOption<string>;\ntype NormalizedOption = ChoiceOption<string>;\nexport type MultiSelectFetchDataFn = (query: string, signal: AbortSignal, group: string | null) => Promise<MultiSelectOption[]>;\n\nexport type MultiSelectInputProps = ValueFieldProps<string[]> & {\n options?: MultiSelectOption[];\n fetchData?: MultiSelectFetchDataFn;\n selectedOptions?: () => MultiSelectOption[];\n placeholder?: string;\n icon?: string;\n activeIcon?: string;\n fetchDebounceMs?: number;\n debounceMs?: number;\n loadOptions?: (query: string, signal: AbortSignal, group: string | null) => Promise<readonly ChoiceOption<string>[]>;\n groups?: readonly SelectGroup[];\n defaultGroup?: string;\n groupsAriaLabel?: string;\n allGroupLabel?: string;\n searchable?: boolean;\n clearable?: boolean;\n name?: string;\n renderOption?: (option: ChoiceOption<string>) => JSX.Element;\n renderValue?: (option: ChoiceOption<string>) => JSX.Element;\n searchPlaceholder?: string;\n loadingLabel?: string;\n noResultsLabel?: string;\n emptyLabel?: string;\n retryLabel?: string;\n clearLabel?: string;\n /** `plain` shows the selection as wrapping pills without a box; options are removed in the list. */\n appearance?: ChoiceAppearance;\n /** Icon class shown before the placeholder while nothing is selected. */\n placeholderIcon?: string;\n};\n\n/** Cloud tints the option icon with the option color instead of adding a dot. */\nconst iconColor = (color: string | undefined): JSX.CSSProperties | undefined => {\n const normalized = normalizeHexColor(color);\n return normalized ? { color: normalized } : undefined;\n};\n\nconst normalize = (option: MultiSelectOption): 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 MultiSelectInput(props: MultiSelectInputProps): JSX.Element {\n const messages = useUiMessages();\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 let searchRef: HTMLInputElement | undefined;\n\n const values = () => resolveMaybeAccessor(props.value) ?? [];\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 asyncOptions = createChoiceLoader(\n () =>\n props.fetchData\n ? async (query, signal) => (await props.fetchData!(query, signal, activeGroup())).map(normalize)\n : props.loadOptions\n ? (query, signal) => props.loadOptions!(query, signal, activeGroup())\n : undefined,\n () => props.fetchDebounceMs ?? props.debounceMs ?? 200,\n );\n const isAsync = () => Boolean(props.fetchData || props.loadOptions);\n const sourceOptions = createMemo(() => (isAsync() ? asyncOptions.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 // Cloud's multi-select always renders its search field, and filters a static\n // option list client-side while a remote loader filters server-side.\n const searchable = () => isAsync() || (props.searchable ?? true);\n const visibleOptions = createMemo(() =>\n isAsync() ? groupedOptions() : filterChoiceOptions(groupedOptions(), searchable() ? query() : \"\"),\n );\n const optionByValue = createMemo(() => {\n const options = new Map<string, NormalizedOption>();\n for (const option of Object.values(cache())) options.set(option.value, option);\n for (const option of (props.selectedOptions?.() ?? []).map(normalize)) options.set(option.value, option);\n for (const option of sourceOptions()) options.set(option.value, option);\n return options;\n });\n const selected = createMemo(() => values().map((value) => optionByValue().get(value) ?? ({ value, label: value } as NormalizedOption)));\n const plain = () => props.appearance === \"plain\";\n const hasClearAction = () => Boolean(props.clearable && selected().length > 0 && !props.disabled && !plain());\n const selectedValues = createMemo(() => new Set(values()));\n const popover = createChoicePopover(() => Boolean(props.disabled));\n const focusedOption = () => visibleOptions()[focusedIndex()];\n\n // Pills that do not fit the trigger collapse into a \"+N\" summary. Until the\n // browser measures them (server HTML, hidden containers) every pill stays.\n let valuesRef: HTMLSpanElement | undefined;\n let moreRef: HTMLSpanElement | undefined;\n const [visibleCount, setVisibleCount] = createSignal(Number.POSITIVE_INFINITY);\n const hiddenOptions = createMemo(() => selected().slice(visibleCount()));\n // While every pill fits, the invisible summary carries the largest count it\n // could show, so measuring it reserves enough room for the real one.\n const moreCount = () => hiddenOptions().length || selected().length - 1;\n const fitValues = () => {\n const values = valuesRef;\n if (!values?.isConnected) return;\n // Plain pills wrap, so every one stays visible.\n if (plain()) {\n values.style.width = \"\";\n setVisibleCount(Number.POSITIVE_INFINITY);\n return;\n }\n // Measuring releases a truncated first pill to its natural width; the\n // browser paints only the final state.\n values.dataset.measuring = \"true\";\n const pills = Array.from(\n values.querySelectorAll<HTMLElement>(\":scope > .k2b-choice-pill\"),\n (pill) => pill.getBoundingClientRect().width,\n );\n const fit = fitChoicePills(\n values.getBoundingClientRect().width,\n pills,\n Number.parseFloat(getComputedStyle(values).columnGap) || 0,\n moreRef?.isConnected ? moreRef.getBoundingClientRect().width : 0,\n );\n delete values.dataset.measuring;\n // Hidden pills leave the flow. While any are hidden the strip keeps the\n // whole row as its preferred width, so a container sized by its content\n // does not shrink with the collapse and grows back once it has room. The\n // strip still flexes to the trigger's width.\n values.style.width = fit.visible < pills.length ? `${fit.rowWidth}px` : \"\";\n setVisibleCount(fit.visible);\n };\n const resizeObserver = typeof ResizeObserver === \"undefined\" ? undefined : new ResizeObserver(() => fitValues());\n onCleanup(() => resizeObserver?.disconnect());\n createEffect(() => {\n selected();\n fitValues();\n });\n onMount(() => {\n if (\"fonts\" in document) void document.fonts.ready.then(fitValues);\n });\n\n const emit = (next: readonly string[]) => {\n const unique = [...new Set(next)];\n commitFieldValue(props, unique);\n };\n const isSelected = (value: string) => selectedValues().has(value);\n const focusFirst = () => setFocusedIndex(nextEnabledChoiceIndex(visibleOptions(), -1, 1));\n const chooseGroup = (group: string | null) => {\n if (group === activeGroup()) return;\n setSelectedGroup(group);\n focusFirst();\n if (isAsync()) asyncOptions.load(query(), true);\n };\n const open = () => {\n if (props.disabled) return;\n setQuery(\"\");\n if (isAsync()) asyncOptions.load(\"\", true);\n focusFirst();\n popover.show();\n if (searchable()) queueMicrotask(() => searchRef?.focus());\n };\n const close = (restoreFocus = false) => {\n asyncOptions.cancel();\n setQuery(\"\");\n setFocusedIndex(-1);\n popover.hide(restoreFocus);\n };\n const toggleOption = (option: NormalizedOption) => {\n if (option.disabled) return;\n setCache({ ...cache(), [option.value]: option });\n emit(isSelected(option.value) ? values().filter((value) => value !== option.value) : [...values(), option.value]);\n };\n const remove = (value: string) => emit(values().filter((item) => item !== value));\n const move = (direction: 1 | -1) => {\n setFocusedIndex(nextEnabledChoiceIndex(visibleOptions(), focusedIndex(), direction));\n };\n const handleKeyDown = (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 return;\n }\n if ((event.key === \"Enter\" || event.key === \" \") && !popover.open()) {\n event.preventDefault();\n open();\n return;\n }\n if (event.key === \"Enter\" && popover.open()) {\n const option = focusedOption();\n if (option) {\n event.preventDefault();\n toggleOption(option);\n }\n return;\n }\n if (event.key === \"Backspace\" && popover.open() && !query() && values().length > 0) {\n event.preventDefault();\n const last = values().at(-1);\n if (last) remove(last);\n return;\n }\n if (event.key === \"Escape\" && popover.open()) {\n event.preventDefault();\n close(true);\n } else if (event.key === \"Tab\" && popover.open()) {\n close();\n }\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 labelFor={false}\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 <div\n ref={(element) => {\n popover.setTrigger(element);\n resizeObserver?.observe(element);\n }}\n id={meta.controlId}\n class=\"k2b-multi-select-trigger\"\n role=\"combobox\"\n tabIndex={props.disabled ? -1 : 0}\n aria-haspopup=\"listbox\"\n aria-expanded={popover.open()}\n aria-controls={listboxId}\n aria-activedescendant={focusedOption() ? `${listboxId}-${focusedIndex()}` : undefined}\n {...fieldControlAria(meta, props)}\n aria-disabled={props.disabled}\n data-disabled={props.disabled ? \"true\" : undefined}\n onClick={() => (popover.open() ? close() : open())}\n onKeyDown={handleKeyDown}\n >\n <Show\n when={selected().length > 0}\n fallback={\n <>\n <Show when={props.placeholderIcon}>\n {(icon) => <i class={`${icon()} k2b-choice-trigger__placeholder-icon`} aria-hidden=\"true\" />}\n </Show>\n <span class=\"k2b-choice-trigger__value\" data-placeholder=\"true\">\n {props.placeholder ?? messages().select}\n </span>\n </>\n }\n >\n <span\n ref={valuesRef}\n class=\"k2b-multi-select-trigger__values\"\n data-overflowing={hiddenOptions().length > 0 ? \"true\" : undefined}\n >\n <For each={selected()}>\n {(option, index) => (\n <span\n class=\"k2b-choice-pill\"\n style={colorTintStyle(option.color)}\n title={option.label}\n data-hidden={index() >= visibleCount() ? \"true\" : undefined}\n >\n <Show\n when={props.renderValue}\n fallback={\n <>\n <Show when={option.icon}>{(icon) => <i class={icon()} aria-hidden=\"true\" />}</Show>\n <span>{option.label}</span>\n </>\n }\n >\n {(render) => <span class=\"k2b-choice-pill__content\">{render()(option)}</span>}\n </Show>\n <Show when={!plain()}>\n <button\n type=\"button\"\n aria-label={messages().removeNamed({ name: option.label })}\n disabled={props.disabled}\n tabIndex={-1}\n onClick={(event) => {\n event.stopPropagation();\n remove(option.value);\n }}\n >\n <i class=\"ti ti-x\" aria-hidden=\"true\" />\n </button>\n </Show>\n </span>\n )}\n </For>\n <Show when={selected().length > 1 && !plain()}>\n <span\n ref={(element) => {\n moreRef = element;\n resizeObserver?.observe(element);\n onCleanup(() => resizeObserver?.unobserve(element));\n }}\n class=\"k2b-multi-select-trigger__more\"\n title={\n hiddenOptions()\n .map((option) => option.label)\n .join(\", \") || undefined\n }\n data-hidden={hiddenOptions().length === 0 ? \"true\" : undefined}\n >\n <span aria-hidden=\"true\">+{moreCount()}</span>\n <span class=\"k2b-sr-only\">{messages().moreSelected({ count: moreCount() })}</span>\n </span>\n </Show>\n </span>\n </Show>\n <Show when={!hasClearAction()}>\n <i\n class={`${popover.open() ? (props.activeIcon ?? \"ti ti-chevron-up\") : (props.icon ?? \"ti ti-chevron-down\")} k2b-multi-select-trigger__chevron`}\n aria-hidden=\"true\"\n />\n </Show>\n </div>\n <Show when={hasClearAction()}>\n <button\n type=\"button\"\n class=\"k2b-choice-control__clear k2b-input-clear-action\"\n aria-label={props.clearLabel ?? messages().clearSelection}\n onClick={(event) => {\n event.stopPropagation();\n emit([]);\n popover.trigger()?.focus();\n }}\n >\n <i class=\"ti ti-x\" aria-hidden=\"true\" />\n </button>\n </Show>\n\n <div\n ref={popover.setPopover}\n popover=\"manual\"\n class=\"k2b-choice-popover\"\n role=\"group\"\n onKeyDown={handleKeyDown}\n aria-label={typeof props.label === \"string\" ? props.label : (props[\"aria-label\"] ?? messages().options)}\n >\n <Show when={searchable()}>\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 ?? messages().searchOptions}\n aria-controls={listboxId}\n aria-activedescendant={focusedOption() ? `${listboxId}-${focusedIndex()}` : undefined}\n onInput={(event) => {\n const next = event.currentTarget.value;\n setQuery(next);\n if (isAsync()) asyncOptions.load(next);\n focusFirst();\n }}\n />\n </div>\n </Show>\n <Show when={(props.groups?.length ?? 0) > 0}>\n <div class=\"k2b-choice-toolbar\">\n <ChoiceGroups\n choices={groupChoices()}\n value={activeGroup()}\n onValueChange={chooseGroup}\n ariaLabel={props.groupsAriaLabel ?? messages().filterOptions}\n controls={listboxId}\n />\n </div>\n </Show>\n <div id={listboxId} class=\"k2b-choice-options\" role=\"listbox\" aria-multiselectable=\"true\">\n <Show when={asyncOptions.error()}>\n {(message) => (\n <div class=\"k2b-choice-status\" data-tone=\"danger\">\n <span>{message()}</span>\n <button type=\"button\" onClick={asyncOptions.retry}>\n {props.retryLabel ?? messages().retry}\n </button>\n </div>\n )}\n </Show>\n <Show when={asyncOptions.loading() && visibleOptions().length === 0}>\n <div class=\"k2b-choice-status\">\n <i class=\"ti ti-loader-2 k2b-spin\" aria-hidden=\"true\" />\n <span>{props.loadingLabel ?? messages().loading}</span>\n </div>\n </Show>\n <For\n each={asyncOptions.error() ? [] : visibleOptions()}\n fallback={\n <Show when={!asyncOptions.loading() && !asyncOptions.error()}>\n <div class=\"k2b-choice-status\">\n {isAsync() || query() ? (props.noResultsLabel ?? messages().noResults) : (props.emptyLabel ?? messages().noOptions)}\n </div>\n </Show>\n }\n >\n {(option, index) => (\n <button\n type=\"button\"\n id={`${listboxId}-${index()}`}\n class=\"k2b-choice-option\"\n role=\"option\"\n aria-label={option.label}\n aria-selected={isSelected(option.value)}\n data-focused={index() === focusedIndex() ? \"true\" : undefined}\n disabled={option.disabled}\n onPointerMove={() => !option.disabled && setFocusedIndex(index())}\n onClick={() => toggleOption(option)}\n >\n <span class=\"k2b-choice-option__checkbox\" aria-hidden=\"true\">\n <i class=\"ti ti-check\" />\n </span>\n <Show\n when={option.icon}\n fallback={\n <Show when={normalizeHexColor(option.color)}>\n {(color) => <span class=\"k2b-choice-dot\" style={{ background: color() }} aria-hidden=\"true\" />}\n </Show>\n }\n >\n {(icon) => <i class={icon()} style={iconColor(option.color)} aria-hidden=\"true\" />}\n </Show>\n <span class=\"k2b-choice-option__content\">\n <Show\n when={props.renderOption}\n fallback={\n <>\n <strong>{option.label}</strong>\n <Show when={option.description}>{(description) => <small>{description()}</small>}</Show>\n </>\n }\n >\n {(render) => render()(option)}\n </Show>\n </span>\n </button>\n )}\n </For>\n </div>\n </div>\n <Show when={props.name}>{(name) => <input type=\"hidden\" name={name()} value={values().join(\",\")} />}</Show>\n </div>\n </Field>\n );\n}\n\nexport default MultiSelectInput;\n"],"mappings":"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","ignoreList":[]}
@@ -1,16 +1,17 @@
1
- import { ssrElement as _$ssrElement } from "solid-js/web";
2
- import { mergeProps as _$mergeProps } from "solid-js/web";
3
1
  import { createComponent as _$createComponent } from "solid-js/web";
4
2
  import { ssr as _$ssr } from "solid-js/web";
5
3
  import { memo as _$memo } from "solid-js/web";
6
4
  import { ssrAttribute as _$ssrAttribute } from "solid-js/web";
7
5
  import { escape as _$escape } from "solid-js/web";
6
+ import { ssrElement as _$ssrElement } from "solid-js/web";
7
+ import { mergeProps as _$mergeProps } from "solid-js/web";
8
8
  var _tmpl$ = ["<button type=\"button\" class=\"k2b-number-input__step\"", "", "><i class=\"ti ti-minus\" aria-hidden=\"true\"></i></button>"],
9
9
  _tmpl$2 = ["<span class=\"k2b-input-shell__icon k2b-text-input__icon\" aria-hidden=\"true\"><i", "></i><i", "></i></span>"],
10
10
  _tmpl$3 = ["<span class=\"k2b-input-shell__affix\">", "</span>"],
11
- _tmpl$4 = ["<button type=\"button\" class=\"k2b-input-shell__clear k2b-input-clear-action\"", "><i class=\"ti ti-x\" aria-hidden=\"true\"></i></button>"],
12
- _tmpl$5 = ["<button type=\"button\" class=\"k2b-number-input__step\"", "", "><i class=\"ti ti-plus\" aria-hidden=\"true\"></i></button>"],
13
- _tmpl$6 = ["<div class=\"k2b-input-shell k2b-number-input\"", ">", "<div class=\"k2b-number-input__value\">", "", "", "", "", "</div>", "</div>"];
11
+ _tmpl$4 = ["<span class=\"k2b-number-input__sizer\"", ">", "</span>"],
12
+ _tmpl$5 = ["<button type=\"button\" class=\"k2b-input-shell__clear k2b-input-clear-action\"", "><i class=\"ti ti-x\" aria-hidden=\"true\"></i></button>"],
13
+ _tmpl$6 = ["<button type=\"button\" class=\"k2b-number-input__step\"", "", "><i class=\"ti ti-plus\" aria-hidden=\"true\"></i></button>"],
14
+ _tmpl$7 = ["<div class=\"k2b-input-shell k2b-number-input\"", ">", "<div class=\"k2b-number-input__value\">", "", "", "", "", "</div>", "</div>"];
14
15
  import { createEffect, createMemo, createSignal, Show, splitProps } from "solid-js";
15
16
  import { createFieldMeta, Field, fieldControlAria } from "../internal/field";
16
17
  import { decimalSeparator, useLocale } from "../intl/locale";
@@ -23,8 +24,10 @@ function fractionDigits(value) {
23
24
  return Math.max(0, fraction - Number(exponent));
24
25
  }
25
26
  export function NumberInput(props) {
26
- const [local, rest] = splitProps(props, ["activeIcon", "allowNegative", "aria-describedby", "aria-label", "class", "clearLabel", "clearable", "decimalPlaces", "decreaseLabel", "description", "disableSteppers", "error", "icon", "id", "increaseLabel", "label", "locale", "max", "min", "onClear", "onValueCommit", "onValueChange", "prefix", "required", "showSteppers", "step", "suffix", "value"]);
27
+ const [local, rest] = splitProps(props, ["activeIcon", "appearance", "allowNegative", "aria-describedby", "aria-label", "class", "clearLabel", "clearable", "decimalPlaces", "decreaseLabel", "description", "disableSteppers", "error", "formatValue", "icon", "id", "increaseLabel", "label", "locale", "max", "min", "onClear", "onKeyDown", "onValueCommit", "onValueChange", "prefix", "required", "showSteppers", "step", "suffix", "value"]);
27
28
  const meta = createFieldMeta(local.id);
29
+ const plain = () => local.appearance === "plain";
30
+ let input;
28
31
  const [focused, setFocused] = createSignal(false);
29
32
  const value = () => resolveMaybeAccessor(local.value);
30
33
  const error = () => resolveMaybeAccessor(local.error);
@@ -86,6 +89,75 @@ export function NumberInput(props) {
86
89
  if (focused()) return;
87
90
  if (parse(raw()) !== value()) setRaw(display(value()));
88
91
  });
92
+ // Enter already committed the current text, so leaving the field does not commit it twice.
93
+ let committedOnEnter = false;
94
+ const onKeyDown = event => {
95
+ const handler = local.onKeyDown;
96
+ if (typeof handler === "function") handler(event);else if (Array.isArray(handler)) handler[0](handler[1], event);
97
+ if (!plain() || event.defaultPrevented) return;
98
+ // Both keys keep focus in the field, so keyboard and screen reader users stay in place.
99
+ if (event.key === "Enter") {
100
+ event.preventDefault();
101
+ commit(parse(raw()), true);
102
+ committedOnEnter = true;
103
+ } else if (event.key === "Escape" && parse(raw()) !== value()) {
104
+ // Only an edit in progress swallows Escape; otherwise it reaches an enclosing panel.
105
+ event.preventDefault();
106
+ event.stopPropagation();
107
+ setRaw(display(value()));
108
+ }
109
+ };
110
+ const placeholderText = () => typeof rest.placeholder === "string" ? rest.placeholder : "";
111
+ /** What a plain field shows: the formatted value at rest, the text being edited while focused. */
112
+ const shownText = () => {
113
+ const current = value();
114
+ if (!focused() && current != null && local.formatValue) return local.formatValue(current);
115
+ return raw() || placeholderText();
116
+ };
117
+ const valueText = () => {
118
+ if (rest["aria-valuetext"] !== undefined) return rest["aria-valuetext"];
119
+ const current = focused() ? parse(raw()) : value();
120
+ if (current == null) return undefined;
121
+ if (local.formatValue) return local.formatValue(current);
122
+ const unit = typeof local.suffix === "string" ? local.suffix : "";
123
+ return unit ? `${display(current)} ${unit}` : undefined;
124
+ };
125
+ const control = () => _$ssrElement("input", _$mergeProps(rest, {
126
+ get id() {
127
+ return meta.controlId;
128
+ },
129
+ "class": "k2b-input k2b-number-input__control",
130
+ get ["data-filled"]() {
131
+ return raw() ? "true" : undefined;
132
+ },
133
+ type: "text",
134
+ role: "spinbutton",
135
+ get inputmode() {
136
+ return places() === 0 ? "numeric" : "decimal";
137
+ },
138
+ get value() {
139
+ return raw();
140
+ },
141
+ get required() {
142
+ return local.required;
143
+ }
144
+ }, () => fieldControlAria(meta, local), {
145
+ get ["aria-valuemin"]() {
146
+ return Number.isFinite(min()) ? min() : undefined;
147
+ },
148
+ get ["aria-valuemax"]() {
149
+ return Number.isFinite(max()) ? max() : undefined;
150
+ },
151
+ get ["aria-valuenow"]() {
152
+ return (focused() ? parse(raw()) : value()) ?? undefined;
153
+ },
154
+ get ["aria-valuetext"]() {
155
+ return valueText();
156
+ },
157
+ get size() {
158
+ return plain() ? 1 : rest.size;
159
+ }
160
+ }), undefined, false);
89
161
  return _$createComponent(Field, {
90
162
  get ["class"]() {
91
163
  return local.class;
@@ -107,9 +179,9 @@ export function NumberInput(props) {
107
179
  return rest.disabled;
108
180
  },
109
181
  get children() {
110
- return _$ssr(_tmpl$6, _$ssrAttribute("data-disabled", rest.disabled ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-invalid", error() ? "true" : _$escape(undefined, true), false), _$escape(_$createComponent(Show, {
182
+ return _$ssr(_tmpl$7, _$ssrAttribute("data-appearance", _$escape(local.appearance ?? "field", true), false) + _$ssrAttribute("data-disabled", rest.disabled ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-invalid", error() ? "true" : _$escape(undefined, true), false), _$escape(_$createComponent(Show, {
111
183
  get when() {
112
- return local.showSteppers ?? true;
184
+ return local.showSteppers ?? !plain();
113
185
  },
114
186
  get children() {
115
187
  return _$ssr(_tmpl$, _$ssrAttribute("aria-label", _$escape(local.decreaseLabel ?? messages().decreaseValue, true), false), _$ssrAttribute("disabled", rest.disabled || local.disableSteppers || value() !== null && value() !== undefined && value() <= min(), true));
@@ -128,55 +200,36 @@ export function NumberInput(props) {
128
200
  get children() {
129
201
  return _$ssr(_tmpl$3, _$escape(local.prefix));
130
202
  }
131
- })), _$ssrElement("input", _$mergeProps(rest, {
132
- get id() {
133
- return meta.controlId;
134
- },
135
- "class": "k2b-input k2b-number-input__control",
136
- get ["data-filled"]() {
137
- return raw() ? "true" : undefined;
138
- },
139
- type: "text",
140
- role: "spinbutton",
141
- get inputmode() {
142
- return places() === 0 ? "numeric" : "decimal";
143
- },
144
- get value() {
145
- return raw();
146
- },
147
- get required() {
148
- return local.required;
149
- }
150
- }, () => fieldControlAria(meta, local), {
151
- get ["aria-valuemin"]() {
152
- return Number.isFinite(min()) ? min() : undefined;
203
+ })), _$escape(_$createComponent(Show, {
204
+ get when() {
205
+ return plain();
153
206
  },
154
- get ["aria-valuemax"]() {
155
- return Number.isFinite(max()) ? max() : undefined;
207
+ get fallback() {
208
+ return control();
156
209
  },
157
- get ["aria-valuenow"]() {
158
- return (focused() ? parse(raw()) : value()) ?? undefined;
210
+ get children() {
211
+ return _$ssr(_tmpl$4, _$ssrAttribute("data-value", _$escape(shownText(), true), false) + _$ssrAttribute("data-placeholder", raw() ? _$escape(undefined, true) : "true", false) + _$ssrAttribute("data-editing", focused() ? "true" : _$escape(undefined, true), false), _$escape(control()));
159
212
  }
160
- }), undefined, false), _$escape(_$createComponent(Show, {
213
+ })), _$escape(_$createComponent(Show, {
161
214
  get when() {
162
- return local.suffix;
215
+ return _$memo(() => !!local.suffix)() && (!plain() || raw() && (focused() || !local.formatValue));
163
216
  },
164
217
  get children() {
165
218
  return _$ssr(_tmpl$3, _$escape(local.suffix));
166
219
  }
167
220
  })), _$escape(_$createComponent(Show, {
168
221
  get when() {
169
- return _$memo(() => !!(local.clearable && raw() && !rest.disabled))() && !rest.readOnly;
222
+ return _$memo(() => !!(local.clearable && raw() && !rest.disabled && !rest.readOnly))() && !plain();
170
223
  },
171
224
  get children() {
172
- return _$ssr(_tmpl$4, _$ssrAttribute("aria-label", _$escape(local.clearLabel ?? messages().clear, true), false));
225
+ return _$ssr(_tmpl$5, _$ssrAttribute("aria-label", _$escape(local.clearLabel ?? messages().clear, true), false));
173
226
  }
174
227
  })), _$escape(_$createComponent(Show, {
175
228
  get when() {
176
- return local.showSteppers ?? true;
229
+ return local.showSteppers ?? !plain();
177
230
  },
178
231
  get children() {
179
- return _$ssr(_tmpl$5, _$ssrAttribute("aria-label", _$escape(local.increaseLabel ?? messages().increaseValue, true), false), _$ssrAttribute("disabled", rest.disabled || local.disableSteppers || value() !== null && value() !== undefined && value() >= max(), true));
232
+ return _$ssr(_tmpl$6, _$ssrAttribute("aria-label", _$escape(local.increaseLabel ?? messages().increaseValue, true), false), _$ssrAttribute("disabled", rest.disabled || local.disableSteppers || value() !== null && value() !== undefined && value() >= max(), true));
180
233
  }
181
234
  })));
182
235
  }
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["inputs/NumberInput.tsx"],"sourcesContent":["import { createEffect, createMemo, createSignal, type JSX, Show, splitProps } from \"solid-js\";\nimport { createFieldMeta, Field, fieldControlAria } from \"../internal/field\";\nimport { decimalSeparator, useLocale } from \"../intl/locale\";\nimport { useUiMessages } from \"../intl/messages\";\nimport type { ValueFieldProps } from \"./field-contract\";\nimport { resolveMaybeAccessor } from \"./field-contract\";\n\nexport type NumberInputProps = Omit<\n JSX.InputHTMLAttributes<HTMLInputElement>,\n \"max\" | \"min\" | \"onChange\" | \"onInput\" | \"prefix\" | \"step\" | \"type\" | \"value\" | keyof ValueFieldProps<number | null>\n> &\n ValueFieldProps<number | null> & {\n max?: number;\n min?: number;\n /** Stepper increment and commit grid; defaults to `1`. A fractional step also sets the default `decimalPlaces`. */\n step?: number;\n /** Accepted fraction digits. Defaults to the fraction digits of `step` (`0.01` → `2`, `1` → `0`); an explicit value wins. */\n decimalPlaces?: number;\n allowNegative?: boolean;\n clearable?: boolean;\n onClear?: () => void;\n clearLabel?: string;\n increaseLabel?: string;\n decreaseLabel?: string;\n /** Explicit locale for the decimal separator; defaults to the inherited render locale. */\n locale?: string;\n showSteppers?: boolean;\n disableSteppers?: boolean;\n icon?: string;\n activeIcon?: string;\n prefix?: JSX.Element;\n suffix?: JSX.Element;\n };\n\nfunction fractionDigits(value: number): number {\n if (!Number.isFinite(value)) return 0;\n const [mantissa = \"\", exponent = \"0\"] = String(value).split(\"e\");\n const fraction = mantissa.split(\".\")[1]?.length ?? 0;\n return Math.max(0, fraction - Number(exponent));\n}\n\nexport function NumberInput(props: NumberInputProps): JSX.Element {\n const [local, rest] = splitProps(props, [\n \"activeIcon\",\n \"allowNegative\",\n \"aria-describedby\",\n \"aria-label\",\n \"class\",\n \"clearLabel\",\n \"clearable\",\n \"decimalPlaces\",\n \"decreaseLabel\",\n \"description\",\n \"disableSteppers\",\n \"error\",\n \"icon\",\n \"id\",\n \"increaseLabel\",\n \"label\",\n \"locale\",\n \"max\",\n \"min\",\n \"onClear\",\n \"onValueCommit\",\n \"onValueChange\",\n \"prefix\",\n \"required\",\n \"showSteppers\",\n \"step\",\n \"suffix\",\n \"value\",\n ]);\n const meta = createFieldMeta(local.id);\n const [focused, setFocused] = createSignal(false);\n const value = () => resolveMaybeAccessor(local.value);\n const error = () => resolveMaybeAccessor(local.error);\n const contextLocale = useLocale();\n const messages = useUiMessages();\n const separator = createMemo(() => decimalSeparator(local.locale ?? contextLocale()));\n // The visible text keeps the canonical number, only the decimal separator\n // follows the effective locale; grouping is never rendered while editing.\n const display = (value: number | null | undefined) => (value == null ? \"\" : String(value).replace(\".\", separator()));\n const [raw, setRaw] = createSignal(display(value()));\n const min = () => local.min ?? -Infinity;\n const max = () => local.max ?? Infinity;\n const step = () => local.step ?? 1;\n // `step` and the accepted decimals never disagree: a fractional step implies\n // its own precision unless the caller states `decimalPlaces` explicitly.\n const places = () => Math.max(0, local.decimalPlaces ?? fractionDigits(step()));\n\n const filter = (input: string) => {\n let output = \"\";\n let decimal = false;\n for (const character of input) {\n if (/\\d/.test(character)) output += character;\n else if (character === \"-\" && output === \"\" && (local.allowNegative ?? true)) output += character;\n else if ((character === \".\" || character === \",\" || character === separator()) && !decimal && places() > 0) {\n output += separator();\n decimal = true;\n }\n }\n if (decimal) {\n const [integer = \"\", fraction = \"\"] = output.split(separator());\n return `${integer}${separator()}${fraction.slice(0, places())}`;\n }\n return output;\n };\n const parse = (input: string) => {\n const canonical = input.replace(separator(), \".\");\n if (!canonical || canonical === \"-\" || canonical === \".\") return null;\n const number = places() === 0 ? Number.parseInt(canonical, 10) : Number(canonical);\n return Number.isFinite(number) ? number : null;\n };\n const normalize = (value: number | null) => {\n if (value === null) return null;\n const clamped = Math.max(min(), Math.min(max(), value));\n const anchor = Number.isFinite(min()) ? min() : 0;\n const snapped = step() > 0 ? Math.round((clamped - anchor) / step()) * step() + anchor : clamped;\n const bounded = Math.max(min(), Math.min(max(), snapped));\n return places() === 0 ? Math.round(bounded) : Number(bounded.toFixed(places()));\n };\n const emit = (value: number | null) => local.onValueChange?.(value);\n const commit = (value: number | null, changeAlreadyEmitted = false) => {\n const next = normalize(value);\n setRaw(display(next));\n if (!changeAlreadyEmitted || !Object.is(next, value)) emit(next);\n local.onValueCommit?.(next);\n };\n const stepBy = (direction: number) => {\n if (rest.disabled || local.disableSteppers) return;\n const seed = value() ?? (Number.isFinite(min()) ? min() : 0);\n commit(seed + direction * step());\n };\n\n createEffect(() => {\n if (focused()) return;\n if (parse(raw()) !== value()) setRaw(display(value()));\n });\n\n return (\n <Field\n class={local.class}\n label={local.label}\n description={local.description}\n error={error()}\n meta={meta}\n required={local.required}\n disabled={rest.disabled}\n >\n <div\n class=\"k2b-input-shell k2b-number-input\"\n data-disabled={rest.disabled ? \"true\" : undefined}\n data-invalid={error() ? \"true\" : undefined}\n >\n <Show when={local.showSteppers ?? true}>\n <button\n type=\"button\"\n class=\"k2b-number-input__step\"\n aria-label={local.decreaseLabel ?? messages().decreaseValue}\n disabled={rest.disabled || local.disableSteppers || (value() !== null && value() !== undefined && value()! <= min())}\n onClick={() => stepBy(-1)}\n >\n <i class=\"ti ti-minus\" aria-hidden=\"true\" />\n </button>\n </Show>\n <div class=\"k2b-number-input__value\">\n <Show when={local.icon}>\n <span class=\"k2b-input-shell__icon k2b-text-input__icon\" aria-hidden=\"true\">\n <i class={local.icon} />\n <i class={local.activeIcon ?? local.icon} />\n </span>\n </Show>\n <Show when={local.prefix}>\n <span class=\"k2b-input-shell__affix\">{local.prefix}</span>\n </Show>\n <input\n {...rest}\n id={meta.controlId}\n class=\"k2b-input k2b-number-input__control\"\n data-filled={raw() ? \"true\" : undefined}\n type=\"text\"\n role=\"spinbutton\"\n inputmode={places() === 0 ? \"numeric\" : \"decimal\"}\n value={raw()}\n required={local.required}\n {...fieldControlAria(meta, local)}\n aria-valuemin={Number.isFinite(min()) ? min() : undefined}\n aria-valuemax={Number.isFinite(max()) ? max() : undefined}\n aria-valuenow={(focused() ? parse(raw()) : value()) ?? undefined}\n onFocus={() => setFocused(true)}\n onInput={(event) => {\n const input = event.currentTarget;\n const current = input.value;\n const selectionStart = input.selectionStart;\n const selectionEnd = input.selectionEnd;\n const next = filter(current);\n // Only write back when the filter actually dropped something —\n // re-assigning an unchanged value moves the caret to the end.\n if (current !== next) {\n input.value = next;\n if (selectionStart !== null && selectionEnd !== null) {\n input.setSelectionRange(filter(current.slice(0, selectionStart)).length, filter(current.slice(0, selectionEnd)).length);\n }\n }\n setRaw(next);\n emit(parse(next));\n }}\n onBlur={() => {\n commit(parse(raw()), true);\n setFocused(false);\n }}\n />\n <Show when={local.suffix}>\n <span class=\"k2b-input-shell__affix\">{local.suffix}</span>\n </Show>\n <Show when={local.clearable && raw() && !rest.disabled && !rest.readOnly}>\n <button\n type=\"button\"\n class=\"k2b-input-shell__clear k2b-input-clear-action\"\n aria-label={local.clearLabel ?? messages().clear}\n onClick={() => (local.onClear ? local.onClear() : commit(null))}\n >\n <i class=\"ti ti-x\" aria-hidden=\"true\" />\n </button>\n </Show>\n </div>\n <Show when={local.showSteppers ?? true}>\n <button\n type=\"button\"\n class=\"k2b-number-input__step\"\n aria-label={local.increaseLabel ?? messages().increaseValue}\n disabled={rest.disabled || local.disableSteppers || (value() !== null && value() !== undefined && value()! >= max())}\n onClick={() => stepBy(1)}\n >\n <i class=\"ti ti-plus\" aria-hidden=\"true\" />\n </button>\n </Show>\n </div>\n </Field>\n );\n}\n\nexport default NumberInput;\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["inputs/NumberInput.tsx"],"sourcesContent":["import { createEffect, createMemo, createSignal, type JSX, Show, splitProps } from \"solid-js\";\nimport { createFieldMeta, Field, fieldControlAria } from \"../internal/field\";\nimport { decimalSeparator, useLocale } from \"../intl/locale\";\nimport { useUiMessages } from \"../intl/messages\";\nimport type { ValueFieldProps } from \"./field-contract\";\nimport { resolveMaybeAccessor } from \"./field-contract\";\nimport type { ChoiceAppearance } from \"./Select\";\n\nexport type NumberInputProps = Omit<\n JSX.InputHTMLAttributes<HTMLInputElement>,\n \"max\" | \"min\" | \"onChange\" | \"onInput\" | \"prefix\" | \"step\" | \"type\" | \"value\" | keyof ValueFieldProps<number | null>\n> &\n ValueFieldProps<number | null> & {\n max?: number;\n min?: number;\n /** Stepper increment and commit grid; defaults to `1`. A fractional step also sets the default `decimalPlaces`. */\n step?: number;\n /** Accepted fraction digits. Defaults to the fraction digits of `step` (`0.01` → `2`, `1` → `0`); an explicit value wins. */\n decimalPlaces?: number;\n allowNegative?: boolean;\n clearable?: boolean;\n onClear?: () => void;\n clearLabel?: string;\n increaseLabel?: string;\n decreaseLabel?: string;\n /** Explicit locale for the decimal separator; defaults to the inherited render locale. */\n locale?: string;\n showSteppers?: boolean;\n disableSteppers?: boolean;\n icon?: string;\n activeIcon?: string;\n prefix?: JSX.Element;\n suffix?: JSX.Element;\n /**\n * `plain` edits the value in place for property rows: no box and no steppers\n * or clear button. The field sizes to its text, Enter commits, Escape\n * restores the current value, and clearing the text clears the value. Focus\n * stays in the field.\n */\n appearance?: ChoiceAppearance;\n /**\n * Text for a set value while a plain field is not being edited, such as\n * `90` as \"1 h 30 min\". It also names the value for assistive technology.\n * The suffix then shows only while editing.\n */\n formatValue?: (value: number) => string;\n };\n\nfunction fractionDigits(value: number): number {\n if (!Number.isFinite(value)) return 0;\n const [mantissa = \"\", exponent = \"0\"] = String(value).split(\"e\");\n const fraction = mantissa.split(\".\")[1]?.length ?? 0;\n return Math.max(0, fraction - Number(exponent));\n}\n\nexport function NumberInput(props: NumberInputProps): JSX.Element {\n const [local, rest] = splitProps(props, [\n \"activeIcon\",\n \"appearance\",\n \"allowNegative\",\n \"aria-describedby\",\n \"aria-label\",\n \"class\",\n \"clearLabel\",\n \"clearable\",\n \"decimalPlaces\",\n \"decreaseLabel\",\n \"description\",\n \"disableSteppers\",\n \"error\",\n \"formatValue\",\n \"icon\",\n \"id\",\n \"increaseLabel\",\n \"label\",\n \"locale\",\n \"max\",\n \"min\",\n \"onClear\",\n \"onKeyDown\",\n \"onValueCommit\",\n \"onValueChange\",\n \"prefix\",\n \"required\",\n \"showSteppers\",\n \"step\",\n \"suffix\",\n \"value\",\n ]);\n const meta = createFieldMeta(local.id);\n const plain = () => local.appearance === \"plain\";\n let input: HTMLInputElement | undefined;\n const [focused, setFocused] = createSignal(false);\n const value = () => resolveMaybeAccessor(local.value);\n const error = () => resolveMaybeAccessor(local.error);\n const contextLocale = useLocale();\n const messages = useUiMessages();\n const separator = createMemo(() => decimalSeparator(local.locale ?? contextLocale()));\n // The visible text keeps the canonical number, only the decimal separator\n // follows the effective locale; grouping is never rendered while editing.\n const display = (value: number | null | undefined) => (value == null ? \"\" : String(value).replace(\".\", separator()));\n const [raw, setRaw] = createSignal(display(value()));\n const min = () => local.min ?? -Infinity;\n const max = () => local.max ?? Infinity;\n const step = () => local.step ?? 1;\n // `step` and the accepted decimals never disagree: a fractional step implies\n // its own precision unless the caller states `decimalPlaces` explicitly.\n const places = () => Math.max(0, local.decimalPlaces ?? fractionDigits(step()));\n\n const filter = (input: string) => {\n let output = \"\";\n let decimal = false;\n for (const character of input) {\n if (/\\d/.test(character)) output += character;\n else if (character === \"-\" && output === \"\" && (local.allowNegative ?? true)) output += character;\n else if ((character === \".\" || character === \",\" || character === separator()) && !decimal && places() > 0) {\n output += separator();\n decimal = true;\n }\n }\n if (decimal) {\n const [integer = \"\", fraction = \"\"] = output.split(separator());\n return `${integer}${separator()}${fraction.slice(0, places())}`;\n }\n return output;\n };\n const parse = (input: string) => {\n const canonical = input.replace(separator(), \".\");\n if (!canonical || canonical === \"-\" || canonical === \".\") return null;\n const number = places() === 0 ? Number.parseInt(canonical, 10) : Number(canonical);\n return Number.isFinite(number) ? number : null;\n };\n const normalize = (value: number | null) => {\n if (value === null) return null;\n const clamped = Math.max(min(), Math.min(max(), value));\n const anchor = Number.isFinite(min()) ? min() : 0;\n const snapped = step() > 0 ? Math.round((clamped - anchor) / step()) * step() + anchor : clamped;\n const bounded = Math.max(min(), Math.min(max(), snapped));\n return places() === 0 ? Math.round(bounded) : Number(bounded.toFixed(places()));\n };\n const emit = (value: number | null) => local.onValueChange?.(value);\n const commit = (value: number | null, changeAlreadyEmitted = false) => {\n const next = normalize(value);\n setRaw(display(next));\n if (!changeAlreadyEmitted || !Object.is(next, value)) emit(next);\n local.onValueCommit?.(next);\n };\n const stepBy = (direction: number) => {\n if (rest.disabled || local.disableSteppers) return;\n const seed = value() ?? (Number.isFinite(min()) ? min() : 0);\n commit(seed + direction * step());\n };\n\n createEffect(() => {\n if (focused()) return;\n if (parse(raw()) !== value()) setRaw(display(value()));\n });\n // Enter already committed the current text, so leaving the field does not commit it twice.\n let committedOnEnter = false;\n const onKeyDown: JSX.EventHandler<HTMLInputElement, KeyboardEvent> = (event) => {\n const handler = local.onKeyDown;\n if (typeof handler === \"function\") handler(event);\n else if (Array.isArray(handler)) handler[0](handler[1], event);\n if (!plain() || event.defaultPrevented) return;\n // Both keys keep focus in the field, so keyboard and screen reader users stay in place.\n if (event.key === \"Enter\") {\n event.preventDefault();\n commit(parse(raw()), true);\n committedOnEnter = true;\n } else if (event.key === \"Escape\" && parse(raw()) !== value()) {\n // Only an edit in progress swallows Escape; otherwise it reaches an enclosing panel.\n event.preventDefault();\n event.stopPropagation();\n setRaw(display(value()));\n }\n };\n const placeholderText = () => (typeof rest.placeholder === \"string\" ? rest.placeholder : \"\");\n /** What a plain field shows: the formatted value at rest, the text being edited while focused. */\n const shownText = () => {\n const current = value();\n if (!focused() && current != null && local.formatValue) return local.formatValue(current);\n return raw() || placeholderText();\n };\n const valueText = () => {\n if (rest[\"aria-valuetext\"] !== undefined) return rest[\"aria-valuetext\"];\n const current = focused() ? parse(raw()) : value();\n if (current == null) return undefined;\n if (local.formatValue) return local.formatValue(current);\n const unit = typeof local.suffix === \"string\" ? local.suffix : \"\";\n return unit ? `${display(current)} ${unit}` : undefined;\n };\n const control = () => (\n <input\n {...rest}\n ref={input}\n id={meta.controlId}\n class=\"k2b-input k2b-number-input__control\"\n data-filled={raw() ? \"true\" : undefined}\n type=\"text\"\n role=\"spinbutton\"\n inputmode={places() === 0 ? \"numeric\" : \"decimal\"}\n value={raw()}\n required={local.required}\n {...fieldControlAria(meta, local)}\n aria-valuemin={Number.isFinite(min()) ? min() : undefined}\n aria-valuemax={Number.isFinite(max()) ? max() : undefined}\n aria-valuenow={(focused() ? parse(raw()) : value()) ?? undefined}\n aria-valuetext={valueText()}\n // The plain sizer sets the width; the smallest intrinsic size keeps the input from widening it.\n size={plain() ? 1 : rest.size}\n onFocus={() => setFocused(true)}\n onKeyDown={onKeyDown}\n onInput={(event) => {\n const input = event.currentTarget;\n const current = input.value;\n const selectionStart = input.selectionStart;\n const selectionEnd = input.selectionEnd;\n const next = filter(current);\n // Only write back when the filter actually dropped something —\n // re-assigning an unchanged value moves the caret to the end.\n if (current !== next) {\n input.value = next;\n if (selectionStart !== null && selectionEnd !== null) {\n input.setSelectionRange(filter(current.slice(0, selectionStart)).length, filter(current.slice(0, selectionEnd)).length);\n }\n }\n setRaw(next);\n committedOnEnter = false;\n emit(parse(next));\n }}\n onBlur={() => {\n if (!committedOnEnter) commit(parse(raw()), true);\n committedOnEnter = false;\n setFocused(false);\n }}\n />\n );\n\n return (\n <Field\n class={local.class}\n label={local.label}\n description={local.description}\n error={error()}\n meta={meta}\n required={local.required}\n disabled={rest.disabled}\n >\n {/* biome-ignore lint/a11y/noStaticElementInteractions lint/a11y/useKeyWithClickEvents: the input inside is the keyboard target; a plain field's row only forwards a pointer click beside the text to it. */}\n <div\n class=\"k2b-input-shell k2b-number-input\"\n data-appearance={local.appearance ?? \"field\"}\n data-disabled={rest.disabled ? \"true\" : undefined}\n data-invalid={error() ? \"true\" : undefined}\n onClick={(event) => {\n if (plain() && event.target !== input && !rest.disabled) input?.focus();\n }}\n >\n <Show when={local.showSteppers ?? !plain()}>\n <button\n type=\"button\"\n class=\"k2b-number-input__step\"\n aria-label={local.decreaseLabel ?? messages().decreaseValue}\n disabled={rest.disabled || local.disableSteppers || (value() !== null && value() !== undefined && value()! <= min())}\n onClick={() => stepBy(-1)}\n >\n <i class=\"ti ti-minus\" aria-hidden=\"true\" />\n </button>\n </Show>\n <div class=\"k2b-number-input__value\">\n <Show when={local.icon}>\n <span class=\"k2b-input-shell__icon k2b-text-input__icon\" aria-hidden=\"true\">\n <i class={local.icon} />\n <i class={local.activeIcon ?? local.icon} />\n </span>\n </Show>\n <Show when={local.prefix}>\n <span class=\"k2b-input-shell__affix\">{local.prefix}</span>\n </Show>\n <Show when={plain()} fallback={control()}>\n {/* The sizer shows the text in the input's grid cell, so the field is as wide as what it shows. At rest it is\n the visible value; while editing the input takes over. */}\n <span\n class=\"k2b-number-input__sizer\"\n data-value={shownText()}\n data-placeholder={raw() ? undefined : \"true\"}\n data-editing={focused() ? \"true\" : undefined}\n >\n {control()}\n </span>\n </Show>\n <Show when={local.suffix && (!plain() || (raw() && (focused() || !local.formatValue)))}>\n <span class=\"k2b-input-shell__affix\">{local.suffix}</span>\n </Show>\n <Show when={local.clearable && raw() && !rest.disabled && !rest.readOnly && !plain()}>\n <button\n type=\"button\"\n class=\"k2b-input-shell__clear k2b-input-clear-action\"\n aria-label={local.clearLabel ?? messages().clear}\n onClick={() => (local.onClear ? local.onClear() : commit(null))}\n >\n <i class=\"ti ti-x\" aria-hidden=\"true\" />\n </button>\n </Show>\n </div>\n <Show when={local.showSteppers ?? !plain()}>\n <button\n type=\"button\"\n class=\"k2b-number-input__step\"\n aria-label={local.increaseLabel ?? messages().increaseValue}\n disabled={rest.disabled || local.disableSteppers || (value() !== null && value() !== undefined && value()! >= max())}\n onClick={() => stepBy(1)}\n >\n <i class=\"ti ti-plus\" aria-hidden=\"true\" />\n </button>\n </Show>\n </div>\n </Field>\n );\n}\n\nexport default NumberInput;\n"],"mappings":";;;;;;;;;;;;;;AAAA,SAAS,YAAY,EAAE,UAAU,EAAE,YAAY,EAAY,IAAI,EAAE,UAAU,QAAQ,UAAU;AAC7F,SAAS,eAAe,EAAE,KAAK,EAAE,gBAAgB,QAAQ,mBAAmB;AAC5E,SAAS,gBAAgB,EAAE,SAAS,QAAQ,gBAAgB;AAC5D,SAAS,aAAa,QAAQ,kBAAkB;AAEhD,SAAS,oBAAoB,QAAQ,kBAAkB;AA2CvD,SAAS,cAAc,CAAC,KAAa,EAAU;EAC7C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;EACrC,MAAM,CAAC,QAAQ,GAAG,EAAE,EAAE,QAAQ,GAAG,GAAG,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC;EAChE,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,IAAI,CAAC;EACpD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;AACjD;AAEA,OAAO,SAAS,WAAW,CAAC,KAAuB,EAAe;EAChE,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,UAAU,CAAC,KAAK,EAAE,CACtC,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,kBAAkB,EAClB,YAAY,EACZ,OAAO,EACP,YAAY,EACZ,WAAW,EACX,eAAe,EACf,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,OAAO,EACP,aAAa,EACb,MAAM,EACN,IAAI,EACJ,eAAe,EACf,OAAO,EACP,QAAQ,EACR,KAAK,EACL,KAAK,EACL,SAAS,EACT,WAAW,EACX,eAAe,EACf,eAAe,EACf,QAAQ,EACR,UAAU,EACV,cAAc,EACd,MAAM,EACN,QAAQ,EACR,OAAO,CACR,CAAC;EACF,MAAM,IAAI,GAAG,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;EACtC,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,UAAU,KAAK,OAAO;EAChD,IAAI,KAAmC;EACvC,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC;EACjD,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,KAAK,CAAC,KAAK,CAAC;EACrD,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,KAAK,CAAC,KAAK,CAAC;EACrD,MAAM,aAAa,GAAG,SAAS,CAAC,CAAC;EACjC,MAAM,QAAQ,GAAG,aAAa,CAAC,CAAC;EAChC,MAAM,SAAS,GAAG,UAAU,CAAC,MAAM,gBAAgB,CAAC,KAAK,CAAC,MAAM,IAAI,aAAa,CAAC,CAAC,CAAC,CAAC;EACrF;EACA;EACA,MAAM,OAAO,GAAI,KAAgC,IAAM,KAAK,IAAI,IAAI,GAAG,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC,CAAE;EACpH,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;EACpD,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,QAAQ;EACxC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,QAAQ;EACvC,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC;EAClC;EACA;EACA,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;EAE/E,MAAM,MAAM,GAAI,KAAa,IAAK;IAChC,IAAI,MAAM,GAAG,EAAE;IACf,IAAI,OAAO,GAAG,KAAK;IACnB,KAAK,MAAM,SAAS,IAAI,KAAK,EAAE;MAC7B,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,IAAI,SAAS,CAAC,KACzC,IAAI,SAAS,KAAK,GAAG,IAAI,MAAM,KAAK,EAAE,KAAK,KAAK,CAAC,aAAa,IAAI,IAAI,CAAC,EAAE,MAAM,IAAI,SAAS,CAAC,KAC7F,IAAI,CAAC,SAAS,KAAK,GAAG,IAAI,SAAS,KAAK,GAAG,IAAI,SAAS,KAAK,SAAS,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE;QAC1G,MAAM,IAAI,SAAS,CAAC,CAAC;QACrB,OAAO,GAAG,IAAI;MAChB;IACF;IACA,IAAI,OAAO,EAAE;MACX,MAAM,CAAC,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,EAAE,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;MAC/D,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE;IACjE;IACA,OAAO,MAAM;EACf,CAAC;EACD,MAAM,KAAK,GAAI,KAAa,IAAK;IAC/B,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC;IACjD,IAAI,CAAC,SAAS,IAAI,SAAS,KAAK,GAAG,IAAI,SAAS,KAAK,GAAG,EAAE,OAAO,IAAI;IACrE,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,GAAG,MAAM,CAAC,SAAS,CAAC;IAClF,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,MAAM,GAAG,IAAI;EAChD,CAAC;EACD,MAAM,SAAS,GAAI,KAAoB,IAAK;IAC1C,IAAI,KAAK,KAAK,IAAI,EAAE,OAAO,IAAI;IAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACvD,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC;IACjD,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,MAAM,GAAG,OAAO;IAChG,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACzD,OAAO,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;EACjF,CAAC;EACD,MAAM,IAAI,GAAI,KAAoB,IAAK,KAAK,CAAC,aAAa,GAAG,KAAK,CAAC;EACnE,MAAM,MAAM,GAAG,CAAC,KAAoB,EAAE,oBAAoB,GAAG,KAAK,KAAK;IACrE,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC;IAC7B,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACrB,IAAI,CAAC,oBAAoB,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC;IAChE,KAAK,CAAC,aAAa,GAAG,IAAI,CAAC;EAC7B,CAAC;EACD,MAAM,MAAM,GAAI,SAAiB,IAAK;IACpC,IAAI,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,eAAe,EAAE;IAC5C,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,KAAK,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;IAC5D,MAAM,CAAC,IAAI,GAAG,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC;EACnC,CAAC;EAED,YAAY,CAAC,MAAM;IACjB,IAAI,OAAO,CAAC,CAAC,EAAE;IACf,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;EACxD,CAAC,CAAC;EACF;EACA,IAAI,gBAAgB,GAAG,KAAK;EAC5B,MAAM,SAA4D,GAAI,KAAK,IAAK;IAC9E,MAAM,OAAO,GAAG,KAAK,CAAC,SAAS;IAC/B,IAAI,OAAO,OAAO,KAAK,UAAU,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,KAC7C,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC;IAC9D,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,gBAAgB,EAAE;IACxC;IACA,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,EAAE;MACzB,KAAK,CAAC,cAAc,CAAC,CAAC;MACtB,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;MAC1B,gBAAgB,GAAG,IAAI;IACzB,CAAC,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,EAAE;MAC7D;MACA,KAAK,CAAC,cAAc,CAAC,CAAC;MACtB,KAAK,CAAC,eAAe,CAAC,CAAC;MACvB,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC1B;EACF,CAAC;EACD,MAAM,eAAe,GAAG,MAAO,OAAO,IAAI,CAAC,WAAW,KAAK,QAAQ,GAAG,IAAI,CAAC,WAAW,GAAG,EAAG;EAC5F;EACA,MAAM,SAAS,GAAG,MAAM;IACtB,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC;IACvB,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,OAAO,IAAI,IAAI,IAAI,KAAK,CAAC,WAAW,EAAE,OAAO,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC;IACzF,OAAO,GAAG,CAAC,CAAC,IAAI,eAAe,CAAC,CAAC;EACnC,CAAC;EACD,MAAM,SAAS,GAAG,MAAM;IACtB,IAAI,IAAI,CAAC,gBAAgB,CAAC,KAAK,SAAS,EAAE,OAAO,IAAI,CAAC,gBAAgB,CAAC;IACvE,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC;IAClD,IAAI,OAAO,IAAI,IAAI,EAAE,OAAO,SAAS;IACrC,IAAI,KAAK,CAAC,WAAW,EAAE,OAAO,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC;IACxD,MAAM,IAAI,GAAG,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ,GAAG,KAAK,CAAC,MAAM,GAAG,EAAE;IACjE,OAAO,IAAI,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE,GAAG,SAAS;EACzD,CAAC;EACD,MAAM,OAAO,GAAG,yCAER,IAAI;IAAA,IAER,EAAE;MAAA,OAAE,IAAI,CAAC,SAAS;IAAA;IAAA,SACZ,qCAAqC;IAAA;MAAA,OAC9B,GAAG,CAAC,CAAC,GAAG,MAAM,GAAG,SAAS;IAAA;IACvC,IAAI,EAAC,MAAM;IACX,IAAI,EAAC,YAAY;IAAA,IACjB,SAAS;MAAA,OAAE,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,SAAS,GAAG,SAAS;IAAA;IAAA,IACjD,KAAK;MAAA,OAAE,GAAG,CAAC,CAAC;IAAA;IAAA,IACZ,QAAQ;MAAA,OAAE,KAAK,CAAC,QAAQ;IAAA;EAAA,SACpB,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC;IAAA;MAAA,OAClB,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,SAAS;IAAA;IAAA;MAAA,OAC1C,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,SAAS;IAAA;IAAA;MAAA,OAC1C,CAAC,OAAO,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,KAAK,SAAS;IAAA;IAAA;MAAA,OAChD,SAAS,CAAC,CAAC;IAAA;IAAA,IAE3B,IAAI;MAAA,OAAE,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI;IAAA;EAAA,qBA2BhC;EAED,yBACG,KAAK;IAAA;MAAA,OACG,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,CAAC;IAAA;IACd,IAAI,EAAE,IAAI;IAAA,IACV,QAAQ;MAAA,OAAE,KAAK,CAAC,QAAQ;IAAA;IAAA,IACxB,QAAQ;MAAA,OAAE,IAAI,CAAC,QAAQ;IAAA;IAAA;MAAA,iEAKJ,KAAK,CAAC,UAAU,IAAI,OAAO,kDAC7B,IAAI,CAAC,QAAQ,GAAG,MAAM,YAAG,SAAS,iDACnC,KAAK,CAAC,CAAC,GAAG,MAAM,YAAG,SAAS,4CAKzC,IAAI;QAAA,IAAC,IAAI;UAAA,OAAE,KAAK,CAAC,YAAY,IAAI,CAAC,KAAK,CAAC,CAAC;QAAA;QAAA;UAAA,2DAI1B,KAAK,CAAC,aAAa,IAAI,QAAQ,CAAC,CAAC,CAAC,aAAa,4CACjD,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,eAAe,IAAK,KAAK,CAAC,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,CAAC,KAAK,SAAS,IAAI,KAAK,CAAC,CAAC,IAAK,GAAG,CAAC,CAAE;QAAA;MAAA,gCAOrH,IAAI;QAAA,IAAC,IAAI;UAAA,OAAE,KAAK,CAAC,IAAI;QAAA;QAAA;UAAA,uDAER,KAAK,CAAC,IAAI,kDACV,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,IAAI;QAAA;MAAA,gCAG3C,IAAI;QAAA,IAAC,IAAI;UAAA,OAAE,KAAK,CAAC,MAAM;QAAA;QAAA;UAAA,+BACgB,KAAK,CAAC,MAAM;QAAA;MAAA,gCAEnD,IAAI;QAAA,IAAC,IAAI;UAAA,OAAE,KAAK,CAAC,CAAC;QAAA;QAAA,IAAE,QAAQ;UAAA,OAAE,OAAO,CAAC,CAAC;QAAA;QAAA;UAAA,4DAKxB,SAAS,CAAC,CAAC,qDACL,GAAG,CAAC,CAAC,YAAG,SAAS,UAAG,MAAM,0CAC9B,OAAO,CAAC,CAAC,GAAG,MAAM,YAAG,SAAS,0BAE3C,OAAO,CAAC,CAAC;QAAA;MAAA,gCAGb,IAAI;QAAA,IAAC,IAAI;UAAA,OAAE,oBAAK,CAAC,MAAM,QAAK,CAAC,KAAK,CAAC,CAAC,IAAK,GAAG,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAE,CAAC;QAAA;QAAA;UAAA,+BAC9C,KAAK,CAAC,MAAM;QAAA;MAAA,gCAEnD,IAAI;QAAA,IAAC,IAAI;UAAA,OAAE,qBAAK,CAAC,SAAS,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,QAAQ,QAAI,CAAC,KAAK,CAAC,CAAC;QAAA;QAAA;UAAA,4DAIpE,KAAK,CAAC,UAAU,IAAI,QAAQ,CAAC,CAAC,CAAC,KAAK;QAAA;MAAA,gCAOrD,IAAI;QAAA,IAAC,IAAI;UAAA,OAAE,KAAK,CAAC,YAAY,IAAI,CAAC,KAAK,CAAC,CAAC;QAAA;QAAA;UAAA,4DAI1B,KAAK,CAAC,aAAa,IAAI,QAAQ,CAAC,CAAC,CAAC,aAAa,4CACjD,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,eAAe,IAAK,KAAK,CAAC,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,CAAC,KAAK,SAAS,IAAI,KAAK,CAAC,CAAC,IAAK,GAAG,CAAC,CAAE;QAAA;MAAA;IAAA;EAAA;AAShI;AAEA,eAAe,WAAW","ignoreList":[]}
@@ -0,0 +1,128 @@
1
+ import { createComponent as _$createComponent } from "solid-js/web";
2
+ import { ssr as _$ssr } 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$ = ["<p class=\"k2b-qr-scanner__note\">", "</p>"],
6
+ _tmpl$2 = ["<div", "><div class=\"k2b-qr-scanner__preview\"", "><video muted playsinline", "></video></div><p role=\"status\">", "</p>", "</div>"];
7
+ import { timed } from "@k2b/stdlib/solid";
8
+ import { createSignal, onCleanup, onMount, Show } from "solid-js";
9
+ import { useUiMessages } from "../intl/messages";
10
+ /**
11
+ * qr-scanner turns every getUserMedia failure into the string "Camera not found.", so only the Permissions API can
12
+ * tell a refusal apart. Safari and Chrome expose the camera permission; elsewhere a refusal counts as unavailable.
13
+ */
14
+ const cameraDenied = async () => {
15
+ try {
16
+ return (await navigator.permissions.query({
17
+ name: "camera"
18
+ })).state === "denied";
19
+ } catch {
20
+ return false;
21
+ }
22
+ };
23
+
24
+ /**
25
+ * Scans a QR code with the rear camera. Each mount owns exactly one camera session, which stops when the scanner
26
+ * unmounts, the page is hidden, or a result is accepted. The scanning engine loads only when the scanner mounts.
27
+ * Decoded content is never logged.
28
+ */
29
+ export function QrScanner(props) {
30
+ const messages = useUiMessages();
31
+ const [starting, setStarting] = createSignal(true);
32
+ const [invalid, setInvalid] = createSignal(false);
33
+ let lastRejected;
34
+ const resetRejected = timed.debounce(() => {
35
+ lastRejected = undefined;
36
+ }, 1000);
37
+ const resetFeedback = timed.debounce(() => setInvalid(false), 1500);
38
+ let video;
39
+ let scanner;
40
+ let closed = false;
41
+ /** The host has unmounted the scanner; it no longer hears about failures that finish later. */
42
+ let unmounted = false;
43
+ let cleanupMotion;
44
+ const destroy = () => {
45
+ closed = true;
46
+ cleanupMotion?.();
47
+ resetRejected.cancel();
48
+ resetFeedback.cancel();
49
+ // pause(true) stops existing tracks immediately; destroy also handles a still-pending permission request.
50
+ void scanner?.pause(true);
51
+ scanner?.destroy();
52
+ scanner = undefined;
53
+ };
54
+ const fail = async () => {
55
+ if (closed) return;
56
+ destroy();
57
+ const denied = await cameraDenied();
58
+ if (!unmounted) props.onError(denied ? "denied" : "unavailable");
59
+ };
60
+ onMount(() => {
61
+ const hidden = () => {
62
+ if (document.visibilityState !== "visible") props.onStop();
63
+ };
64
+ const leaving = () => props.onStop();
65
+ document.addEventListener("visibilitychange", hidden);
66
+ window.addEventListener("pagehide", leaving);
67
+ onCleanup(() => {
68
+ unmounted = true;
69
+ destroy();
70
+ document.removeEventListener("visibilitychange", hidden);
71
+ window.removeEventListener("pagehide", leaving);
72
+ });
73
+ void (async () => {
74
+ try {
75
+ const {
76
+ default: Engine
77
+ } = await import("qr-scanner");
78
+ if (closed || document.visibilityState !== "visible") return;
79
+ scanner = new Engine(video, result => {
80
+ if (closed) return;
81
+ // Rearm only after a full second without a decoded QR, not between individual frames.
82
+ resetRejected.debouncedFn();
83
+ if (result.data === lastRejected) return;
84
+ if (props.onResult(result.data)) {
85
+ destroy();
86
+ return;
87
+ }
88
+ lastRejected = result.data;
89
+ setInvalid(true);
90
+ resetFeedback.debouncedFn();
91
+ }, {
92
+ preferredCamera: "environment",
93
+ highlightScanRegion: true,
94
+ // Empty frames are expected. Never log decoded content or frame data.
95
+ onDecodeError: error => {
96
+ if (closed || error === Engine.NO_QR_CODE_FOUND) return;
97
+ void fail();
98
+ }
99
+ });
100
+ const motion = matchMedia("(prefers-reduced-motion: reduce)");
101
+ const applyMotion = () => {
102
+ for (const animation of scanner?.$overlay?.getAnimations({
103
+ subtree: true
104
+ }) ?? []) {
105
+ if (motion.matches) animation.pause();else animation.play();
106
+ }
107
+ };
108
+ applyMotion();
109
+ motion.addEventListener("change", applyMotion);
110
+ cleanupMotion = () => motion.removeEventListener("change", applyMotion);
111
+ await scanner.start();
112
+ if (!closed) setStarting(false);
113
+ } catch {
114
+ await fail();
115
+ }
116
+ })();
117
+ });
118
+ return _$ssr(_tmpl$2, _$ssrAttribute("class", props.class ? `k2b-qr-scanner ${_$escape(props.class, true)}` : "k2b-qr-scanner", false), _$ssrAttribute("data-invalid", _$escape(invalid() || undefined, true), false), _$ssrAttribute("aria-label", _$escape(messages().qrCameraPreview, true), false), starting() ? _$escape(messages().qrCameraStarting) : _$escape(props.instructions ?? messages().qrCameraInstructions), _$escape(_$createComponent(Show, {
119
+ get when() {
120
+ return !starting();
121
+ },
122
+ get children() {
123
+ return _$ssr(_tmpl$, _$escape(messages().qrCameraPrivacy));
124
+ }
125
+ })));
126
+ }
127
+ export default QrScanner;
128
+ //# sourceMappingURL=QrScanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sources":["inputs/QrScanner.tsx"],"sourcesContent":["import { timed } from \"@k2b/stdlib/solid\";\nimport type QrScannerEngine from \"qr-scanner\";\nimport { createSignal, type JSX, onCleanup, onMount, Show } from \"solid-js\";\nimport { useUiMessages } from \"../intl/messages\";\n\nexport type QrScannerError = \"denied\" | \"unavailable\";\n\nexport type QrScannerProps = {\n /** Decoded text is untrusted. Return `true` to accept it and stop the camera, `false` to reject it and keep scanning. */\n onResult: (text: string) => boolean;\n /** The page was hidden or left; unmount the scanner. */\n onStop: () => void;\n /** The camera could not start: access was denied, or there is no usable camera. Offer another way in. */\n onError: (reason: QrScannerError) => void;\n /** What to point the camera at. Defaults to a generic QR code hint. */\n instructions?: string;\n class?: string;\n};\n\n/**\n * qr-scanner turns every getUserMedia failure into the string \"Camera not found.\", so only the Permissions API can\n * tell a refusal apart. Safari and Chrome expose the camera permission; elsewhere a refusal counts as unavailable.\n */\nconst cameraDenied = async (): Promise<boolean> => {\n try {\n return (await navigator.permissions.query({ name: \"camera\" as PermissionName })).state === \"denied\";\n } catch {\n return false;\n }\n};\n\n/**\n * Scans a QR code with the rear camera. Each mount owns exactly one camera session, which stops when the scanner\n * unmounts, the page is hidden, or a result is accepted. The scanning engine loads only when the scanner mounts.\n * Decoded content is never logged.\n */\nexport function QrScanner(props: QrScannerProps): JSX.Element {\n const messages = useUiMessages();\n const [starting, setStarting] = createSignal(true);\n const [invalid, setInvalid] = createSignal(false);\n let lastRejected: string | undefined;\n const resetRejected = timed.debounce(() => {\n lastRejected = undefined;\n }, 1000);\n const resetFeedback = timed.debounce(() => setInvalid(false), 1500);\n let video!: HTMLVideoElement;\n let scanner: QrScannerEngine | undefined;\n let closed = false;\n /** The host has unmounted the scanner; it no longer hears about failures that finish later. */\n let unmounted = false;\n let cleanupMotion: (() => void) | undefined;\n const destroy = () => {\n closed = true;\n cleanupMotion?.();\n resetRejected.cancel();\n resetFeedback.cancel();\n // pause(true) stops existing tracks immediately; destroy also handles a still-pending permission request.\n void scanner?.pause(true);\n scanner?.destroy();\n scanner = undefined;\n };\n const fail = async () => {\n if (closed) return;\n destroy();\n const denied = await cameraDenied();\n if (!unmounted) props.onError(denied ? \"denied\" : \"unavailable\");\n };\n onMount(() => {\n const hidden = () => {\n if (document.visibilityState !== \"visible\") props.onStop();\n };\n const leaving = () => props.onStop();\n document.addEventListener(\"visibilitychange\", hidden);\n window.addEventListener(\"pagehide\", leaving);\n onCleanup(() => {\n unmounted = true;\n destroy();\n document.removeEventListener(\"visibilitychange\", hidden);\n window.removeEventListener(\"pagehide\", leaving);\n });\n void (async () => {\n try {\n const { default: Engine } = await import(\"qr-scanner\");\n if (closed || document.visibilityState !== \"visible\") return;\n scanner = new Engine(\n video,\n (result) => {\n if (closed) return;\n // Rearm only after a full second without a decoded QR, not between individual frames.\n resetRejected.debouncedFn();\n if (result.data === lastRejected) return;\n if (props.onResult(result.data)) {\n destroy();\n return;\n }\n lastRejected = result.data;\n setInvalid(true);\n resetFeedback.debouncedFn();\n },\n {\n preferredCamera: \"environment\",\n highlightScanRegion: true,\n // Empty frames are expected. Never log decoded content or frame data.\n onDecodeError: (error) => {\n if (closed || error === Engine.NO_QR_CODE_FOUND) return;\n void fail();\n },\n },\n );\n const motion = matchMedia(\"(prefers-reduced-motion: reduce)\");\n const applyMotion = () => {\n for (const animation of scanner?.$overlay?.getAnimations({ subtree: true }) ?? []) {\n if (motion.matches) animation.pause();\n else animation.play();\n }\n };\n applyMotion();\n motion.addEventListener(\"change\", applyMotion);\n cleanupMotion = () => motion.removeEventListener(\"change\", applyMotion);\n await scanner.start();\n if (!closed) setStarting(false);\n } catch {\n await fail();\n }\n })();\n });\n return (\n <div class={props.class ? `k2b-qr-scanner ${props.class}` : \"k2b-qr-scanner\"}>\n <div class=\"k2b-qr-scanner__preview\" data-invalid={invalid() || undefined}>\n {/* Live camera preview contains no prerecorded speech or audio. */}\n <video ref={video} muted playsinline aria-label={messages().qrCameraPreview} />\n </div>\n <p role=\"status\">{starting() ? messages().qrCameraStarting : (props.instructions ?? messages().qrCameraInstructions)}</p>\n <Show when={!starting()}>\n <p class=\"k2b-qr-scanner__note\">{messages().qrCameraPrivacy}</p>\n </Show>\n </div>\n );\n}\n\nexport default QrScanner;\n"],"mappings":";;;;;;AAAA,SAAS,KAAK,QAAQ,mBAAmB;AAEzC,SAAS,YAAY,EAAY,SAAS,EAAE,OAAO,EAAE,IAAI,QAAQ,UAAU;AAC3E,SAAS,aAAa,QAAQ,kBAAkB;AAgBhD;AACA;AACA;AACA;AACA,MAAM,YAAY,GAAG,YAA8B;EACjD,IAAI;IACF,OAAO,CAAC,MAAM,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC;MAAE,IAAI,EAAE;IAA2B,CAAC,CAAC,EAAE,KAAK,KAAK,QAAQ;EACrG,CAAC,CAAC,MAAM;IACN,OAAO,KAAK;EACd;AACF,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA,OAAO,SAAS,SAAS,CAAC,KAAqB,EAAe;EAC5D,MAAM,QAAQ,GAAG,aAAa,CAAC,CAAC;EAChC,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC;EAClD,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC;EACjD,IAAI,YAAgC;EACpC,MAAM,aAAa,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM;IACzC,YAAY,GAAG,SAAS;EAC1B,CAAC,EAAE,IAAI,CAAC;EACR,MAAM,aAAa,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,UAAU,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC;EACnE,IAAI,KAAwB;EAC5B,IAAI,OAAoC;EACxC,IAAI,MAAM,GAAG,KAAK;EAClB;EACA,IAAI,SAAS,GAAG,KAAK;EACrB,IAAI,aAAuC;EAC3C,MAAM,OAAO,GAAG,MAAM;IACpB,MAAM,GAAG,IAAI;IACb,aAAa,GAAG,CAAC;IACjB,aAAa,CAAC,MAAM,CAAC,CAAC;IACtB,aAAa,CAAC,MAAM,CAAC,CAAC;IACtB;IACA,KAAK,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC,CAAC;IAClB,OAAO,GAAG,SAAS;EACrB,CAAC;EACD,MAAM,IAAI,GAAG,YAAY;IACvB,IAAI,MAAM,EAAE;IACZ,OAAO,CAAC,CAAC;IACT,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,CAAC;IACnC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,QAAQ,GAAG,aAAa,CAAC;EAClE,CAAC;EACD,OAAO,CAAC,MAAM;IACZ,MAAM,MAAM,GAAG,MAAM;MACnB,IAAI,QAAQ,CAAC,eAAe,KAAK,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC5D,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,CAAC;IACpC,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACrD,MAAM,CAAC,gBAAgB,CAAC,UAAU,EAAE,OAAO,CAAC;IAC5C,SAAS,CAAC,MAAM;MACd,SAAS,GAAG,IAAI;MAChB,OAAO,CAAC,CAAC;MACT,QAAQ,CAAC,mBAAmB,CAAC,kBAAkB,EAAE,MAAM,CAAC;MACxD,MAAM,CAAC,mBAAmB,CAAC,UAAU,EAAE,OAAO,CAAC;IACjD,CAAC,CAAC;IACF,KAAK,CAAC,YAAY;MAChB,IAAI;QACF,MAAM;UAAE,OAAO,EAAE;QAAO,CAAC,GAAG,MAAM,OAAO,YAAY,CAAC;QACtD,IAAI,MAAM,IAAI,QAAQ,CAAC,eAAe,KAAK,SAAS,EAAE;QACtD,OAAO,GAAG,IAAI,MAAM,CAClB,KAAK,EACJ,MAAM,IAAK;UACV,IAAI,MAAM,EAAE;UACZ;UACA,aAAa,CAAC,WAAW,CAAC,CAAC;UAC3B,IAAI,MAAM,CAAC,IAAI,KAAK,YAAY,EAAE;UAClC,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;YAC/B,OAAO,CAAC,CAAC;YACT;UACF;UACA,YAAY,GAAG,MAAM,CAAC,IAAI;UAC1B,UAAU,CAAC,IAAI,CAAC;UAChB,aAAa,CAAC,WAAW,CAAC,CAAC;QAC7B,CAAC,EACD;UACE,eAAe,EAAE,aAAa;UAC9B,mBAAmB,EAAE,IAAI;UACzB;UACA,aAAa,EAAG,KAAK,IAAK;YACxB,IAAI,MAAM,IAAI,KAAK,KAAK,MAAM,CAAC,gBAAgB,EAAE;YACjD,KAAK,IAAI,CAAC,CAAC;UACb;QACF,CACF,CAAC;QACD,MAAM,MAAM,GAAG,UAAU,CAAC,kCAAkC,CAAC;QAC7D,MAAM,WAAW,GAAG,MAAM;UACxB,KAAK,MAAM,SAAS,IAAI,OAAO,EAAE,QAAQ,EAAE,aAAa,CAAC;YAAE,OAAO,EAAE;UAAK,CAAC,CAAC,IAAI,EAAE,EAAE;YACjF,IAAI,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,KACjC,SAAS,CAAC,IAAI,CAAC,CAAC;UACvB;QACF,CAAC;QACD,WAAW,CAAC,CAAC;QACb,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,WAAW,CAAC;QAC9C,aAAa,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,WAAW,CAAC;QACvE,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;QACrB,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,KAAK,CAAC;MACjC,CAAC,CAAC,MAAM;QACN,MAAM,IAAI,CAAC,CAAC;MACd;IACF,CAAC,EAAE,CAAC;EACN,CAAC,CAAC;EACF,8CACc,KAAK,CAAC,KAAK,GAAG,2BAAkB,KAAK,CAAC,KAAK,SAAE,GAAG,gBAAgB,kDACvB,OAAO,CAAC,CAAC,IAAI,SAAS,uDAEtB,QAAQ,CAAC,CAAC,CAAC,eAAe,iBAE3D,QAAQ,CAAC,CAAC,YAAG,QAAQ,CAAC,CAAC,CAAC,gBAAgB,aAAI,KAAK,CAAC,YAAY,IAAI,QAAQ,CAAC,CAAC,CAAC,oBAAoB,CAAC,6BACnH,IAAI;IAAA,IAAC,IAAI;MAAA,OAAE,CAAC,QAAQ,CAAC,CAAC;IAAA;IAAA;MAAA,8BACY,QAAQ,CAAC,CAAC,CAAC,eAAe;IAAA;EAAA;AAInE;AAEA,eAAe,SAAS","ignoreList":[]}