@k2b/ui 0.30.0 → 0.32.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 (186) hide show
  1. package/README.md +1 -1
  2. package/dist/base.css +2 -0
  3. package/dist/browser/actions/Toolbar.js +2 -0
  4. package/dist/browser/actions/Toolbar.js.map +1 -1
  5. package/dist/browser/actions/ViewTabs.js +8 -0
  6. package/dist/browser/actions/ViewTabs.js.map +1 -1
  7. package/dist/browser/chat/ChatDecision.js +28 -2
  8. package/dist/browser/chat/ChatDecision.js.map +1 -1
  9. package/dist/browser/content/Chart.js +104 -55
  10. package/dist/browser/content/Chart.js.map +1 -1
  11. package/dist/browser/content/ChartExplorer.js +5 -3
  12. package/dist/browser/content/ChartExplorer.js.map +1 -1
  13. package/dist/browser/content/MapAttribution.js +27 -0
  14. package/dist/browser/content/MapAttribution.js.map +1 -0
  15. package/dist/browser/content/MapView.js +553 -0
  16. package/dist/browser/content/MapView.js.map +1 -0
  17. package/dist/browser/content/MapViewFrame.js +395 -0
  18. package/dist/browser/content/MapViewFrame.js.map +1 -0
  19. package/dist/browser/content/chart-inspection-core.js +4 -1
  20. package/dist/browser/content/chart-inspection-core.js.map +1 -1
  21. package/dist/browser/content/code-highlight.js +66 -0
  22. package/dist/browser/content/code-highlight.js.map +1 -1
  23. package/dist/browser/content/index.js +6 -0
  24. package/dist/browser/content/index.js.map +1 -1
  25. package/dist/browser/content/map-palette.js +39 -0
  26. package/dist/browser/content/map-palette.js.map +1 -0
  27. package/dist/browser/content/map-style.js +276 -0
  28. package/dist/browser/content/map-style.js.map +1 -0
  29. package/dist/browser/content/map-view-geometry.js +269 -0
  30. package/dist/browser/content/map-view-geometry.js.map +1 -0
  31. package/dist/browser/content/map-view-live.js +65 -0
  32. package/dist/browser/content/map-view-live.js.map +1 -0
  33. package/dist/browser/content/map-view-messages.js +53 -0
  34. package/dist/browser/content/map-view-messages.js.map +1 -0
  35. package/dist/browser/content/map-view-types.js +2 -0
  36. package/dist/browser/content/map-view-types.js.map +1 -0
  37. package/dist/browser/content/map-view-worker.js +10 -0
  38. package/dist/browser/feedback/dialog-core.js +19 -0
  39. package/dist/browser/feedback/dialog-core.js.map +1 -1
  40. package/dist/browser/inputs/AutocompleteEditor.js +167 -104
  41. package/dist/browser/inputs/AutocompleteEditor.js.map +1 -1
  42. package/dist/browser/inputs/RichSelect.js +1474 -0
  43. package/dist/browser/inputs/RichSelect.js.map +1 -0
  44. package/dist/browser/inputs/TextInput.js +95 -60
  45. package/dist/browser/inputs/TextInput.js.map +1 -1
  46. package/dist/browser/inputs/choice.js +19 -8
  47. package/dist/browser/inputs/choice.js.map +1 -1
  48. package/dist/browser/inputs/index.js +1 -0
  49. package/dist/browser/inputs/index.js.map +1 -1
  50. package/dist/browser/inputs/rich-select-messages.js +46 -0
  51. package/dist/browser/inputs/rich-select-messages.js.map +1 -0
  52. package/dist/browser/layout/AppWorkspace.js +194 -144
  53. package/dist/browser/layout/AppWorkspace.js.map +1 -1
  54. package/dist/browser/layout/DetailPanel.js +10 -1
  55. package/dist/browser/layout/DetailPanel.js.map +1 -1
  56. package/dist/browser/layout/Navigation.js +14 -5
  57. package/dist/browser/layout/Navigation.js.map +1 -1
  58. package/dist/browser/layout/PageTitle.js +9 -3
  59. package/dist/browser/layout/PageTitle.js.map +1 -1
  60. package/dist/browser/layout/ResizeSeparator.js +8 -2
  61. package/dist/browser/layout/ResizeSeparator.js.map +1 -1
  62. package/dist/browser/layout/app-workspace-controller.js +301 -34
  63. package/dist/browser/layout/app-workspace-controller.js.map +1 -1
  64. package/dist/browser/layout/app-workspace-width.js +26 -0
  65. package/dist/browser/layout/app-workspace-width.js.map +1 -0
  66. package/dist/browser/layout/index.js +1 -1
  67. package/dist/browser/layout/index.js.map +1 -1
  68. package/dist/browser/layout/navigation-model.js.map +1 -1
  69. package/dist/browser/layout/resize-separator.js +25 -1
  70. package/dist/browser/layout/resize-separator.js.map +1 -1
  71. package/dist/browser/surfaces/Skeleton.js +14 -0
  72. package/dist/browser/surfaces/Skeleton.js.map +1 -0
  73. package/dist/browser/surfaces/index.js +1 -0
  74. package/dist/browser/surfaces/index.js.map +1 -1
  75. package/dist/licenses/maplibre-gl.txt +116 -0
  76. package/dist/ssr/actions/Toolbar.js +2 -0
  77. package/dist/ssr/actions/Toolbar.js.map +1 -1
  78. package/dist/ssr/actions/ViewTabs.js +8 -0
  79. package/dist/ssr/actions/ViewTabs.js.map +1 -1
  80. package/dist/ssr/chat/ChatDecision.js +11 -0
  81. package/dist/ssr/chat/ChatDecision.js.map +1 -1
  82. package/dist/ssr/content/Chart.js +27 -7
  83. package/dist/ssr/content/Chart.js.map +1 -1
  84. package/dist/ssr/content/ChartExplorer.js +5 -3
  85. package/dist/ssr/content/ChartExplorer.js.map +1 -1
  86. package/dist/ssr/content/MapAttribution.js +19 -0
  87. package/dist/ssr/content/MapAttribution.js.map +1 -0
  88. package/dist/ssr/content/MapView.js +474 -0
  89. package/dist/ssr/content/MapView.js.map +1 -0
  90. package/dist/ssr/content/MapViewFrame.js +193 -0
  91. package/dist/ssr/content/MapViewFrame.js.map +1 -0
  92. package/dist/ssr/content/chart-inspection-core.js +4 -1
  93. package/dist/ssr/content/chart-inspection-core.js.map +1 -1
  94. package/dist/ssr/content/code-highlight.js +66 -0
  95. package/dist/ssr/content/code-highlight.js.map +1 -1
  96. package/dist/ssr/content/index.js +6 -0
  97. package/dist/ssr/content/index.js.map +1 -1
  98. package/dist/ssr/content/map-palette.js +39 -0
  99. package/dist/ssr/content/map-palette.js.map +1 -0
  100. package/dist/ssr/content/map-style.js +276 -0
  101. package/dist/ssr/content/map-style.js.map +1 -0
  102. package/dist/ssr/content/map-view-geometry.js +269 -0
  103. package/dist/ssr/content/map-view-geometry.js.map +1 -0
  104. package/dist/ssr/content/map-view-live.js +1 -0
  105. package/dist/ssr/content/map-view-messages.js +53 -0
  106. package/dist/ssr/content/map-view-messages.js.map +1 -0
  107. package/dist/ssr/content/map-view-types.js +2 -0
  108. package/dist/ssr/content/map-view-types.js.map +1 -0
  109. package/dist/ssr/feedback/dialog-core.js +19 -0
  110. package/dist/ssr/feedback/dialog-core.js.map +1 -1
  111. package/dist/ssr/inputs/AutocompleteEditor.js +64 -24
  112. package/dist/ssr/inputs/AutocompleteEditor.js.map +1 -1
  113. package/dist/ssr/inputs/RichSelect.js +950 -0
  114. package/dist/ssr/inputs/RichSelect.js.map +1 -0
  115. package/dist/ssr/inputs/TextInput.js +40 -16
  116. package/dist/ssr/inputs/TextInput.js.map +1 -1
  117. package/dist/ssr/inputs/choice.js +19 -8
  118. package/dist/ssr/inputs/choice.js.map +1 -1
  119. package/dist/ssr/inputs/index.js +1 -0
  120. package/dist/ssr/inputs/index.js.map +1 -1
  121. package/dist/ssr/inputs/rich-select-messages.js +46 -0
  122. package/dist/ssr/inputs/rich-select-messages.js.map +1 -0
  123. package/dist/ssr/layout/AppWorkspace.js +53 -16
  124. package/dist/ssr/layout/AppWorkspace.js.map +1 -1
  125. package/dist/ssr/layout/DetailPanel.js +1 -1
  126. package/dist/ssr/layout/DetailPanel.js.map +1 -1
  127. package/dist/ssr/layout/Navigation.js +1 -1
  128. package/dist/ssr/layout/Navigation.js.map +1 -1
  129. package/dist/ssr/layout/PageTitle.js +9 -3
  130. package/dist/ssr/layout/PageTitle.js.map +1 -1
  131. package/dist/ssr/layout/ResizeSeparator.js +4 -1
  132. package/dist/ssr/layout/ResizeSeparator.js.map +1 -1
  133. package/dist/ssr/layout/app-workspace-controller.js +301 -34
  134. package/dist/ssr/layout/app-workspace-controller.js.map +1 -1
  135. package/dist/ssr/layout/app-workspace-width.js +26 -0
  136. package/dist/ssr/layout/app-workspace-width.js.map +1 -0
  137. package/dist/ssr/layout/index.js +1 -1
  138. package/dist/ssr/layout/index.js.map +1 -1
  139. package/dist/ssr/layout/navigation-model.js.map +1 -1
  140. package/dist/ssr/layout/resize-separator.js +25 -1
  141. package/dist/ssr/layout/resize-separator.js.map +1 -1
  142. package/dist/ssr/surfaces/Skeleton.js +8 -0
  143. package/dist/ssr/surfaces/Skeleton.js.map +1 -0
  144. package/dist/ssr/surfaces/index.js +1 -0
  145. package/dist/ssr/surfaces/index.js.map +1 -1
  146. package/dist/styles.css +1 -1
  147. package/dist/types/content/Chart.d.ts +4 -2
  148. package/dist/types/content/ChartExplorer.d.ts +0 -1
  149. package/dist/types/content/MapAttribution.d.ts +6 -0
  150. package/dist/types/content/MapView.d.ts +5 -0
  151. package/dist/types/content/MapViewFrame.d.ts +31 -0
  152. package/dist/types/content/code-highlight.d.ts +3 -1
  153. package/dist/types/content/index.d.ts +7 -0
  154. package/dist/types/content/map-palette.d.ts +58 -0
  155. package/dist/types/content/map-style.d.ts +29 -0
  156. package/dist/types/content/map-view-geometry.d.ts +55 -0
  157. package/dist/types/content/map-view-live.d.ts +2 -0
  158. package/dist/types/content/map-view-messages.d.ts +21 -0
  159. package/dist/types/content/map-view-types.d.ts +63 -0
  160. package/dist/types/feedback/dialog-core.d.ts +1 -0
  161. package/dist/types/inputs/AutocompleteEditor.d.ts +6 -1
  162. package/dist/types/inputs/RichSelect.d.ts +93 -0
  163. package/dist/types/inputs/TextInput.d.ts +5 -2
  164. package/dist/types/inputs/choice.d.ts +24 -4
  165. package/dist/types/inputs/index.d.ts +2 -0
  166. package/dist/types/inputs/rich-select-messages.d.ts +21 -0
  167. package/dist/types/layout/AppWorkspace.d.ts +14 -3
  168. package/dist/types/layout/DetailPanel.d.ts +2 -0
  169. package/dist/types/layout/app-workspace-controller.d.ts +2 -0
  170. package/dist/types/layout/app-workspace-width.d.ts +13 -0
  171. package/dist/types/layout/index.d.ts +2 -2
  172. package/dist/types/layout/navigation-model.d.ts +2 -0
  173. package/dist/types/layout/resize-separator.d.ts +1 -0
  174. package/dist/types/surfaces/Skeleton.d.ts +6 -0
  175. package/dist/types/surfaces/index.d.ts +1 -0
  176. package/map-glyphs/IBM Plex Sans Medium/0-255.pbf +0 -0
  177. package/map-glyphs/IBM Plex Sans Medium/1024-1279.pbf +0 -0
  178. package/map-glyphs/IBM Plex Sans Medium/256-511.pbf +0 -0
  179. package/map-glyphs/IBM Plex Sans Medium/512-767.pbf +0 -0
  180. package/map-glyphs/IBM Plex Sans Medium/768-1023.pbf +0 -0
  181. package/map-glyphs/IBM Plex Sans Medium/7680-7935.pbf +0 -0
  182. package/map-glyphs/IBM Plex Sans Medium/8192-8447.pbf +0 -0
  183. package/map-glyphs/IBM Plex Sans Medium/8448-8703.pbf +0 -0
  184. package/map-glyphs/IBM Plex Sans Medium/8704-8959.pbf +0 -0
  185. package/map-glyphs/OFL.txt +93 -0
  186. package/package.json +11 -6
@@ -0,0 +1,950 @@
1
+ import { ssrElement as _$ssrElement } from "solid-js/web";
2
+ import { mergeProps as _$mergeProps } from "solid-js/web";
3
+ import { memo as _$memo } from "solid-js/web";
4
+ import { ssrAttribute as _$ssrAttribute } from "solid-js/web";
5
+ import { ssrStyleProperty as _$ssrStyleProperty } from "solid-js/web";
6
+ import { ssr as _$ssr } from "solid-js/web";
7
+ import { escape as _$escape } from "solid-js/web";
8
+ import { createComponent as _$createComponent } from "solid-js/web";
9
+ var _tmpl$ = ["<span class=\"k2b-rich-select__visual\">", "</span>"],
10
+ _tmpl$2 = ["<span class=\"k2b-rich-select__visual\" aria-hidden=\"true\"><span class=\"k2b-rich-select__dot\" style=\"", "\"></span></span>"],
11
+ _tmpl$3 = ["<span class=\"k2b-rich-select__visual\" aria-hidden=\"true\"><i", "></i></span>"],
12
+ _tmpl$4 = ["<span class=\"k2b-rich-select__text\"><span", " class=\"k2b-rich-select__label\">", "</span>", "</span>"],
13
+ _tmpl$5 = ["<span", " class=\"k2b-rich-select__line\"", ">", "</span>"],
14
+ _tmpl$6 = "<span class=\"k2b-rich-select__placeholder-visual\"></span>",
15
+ _tmpl$7 = ["<div class=\"k2b-rich-select__placeholder\"", " aria-hidden=\"true\">", "<span class=\"k2b-rich-select__placeholder-lines\"><span style=\"", "\"></span><span style=\"", "\"></span></span></div>"],
16
+ _tmpl$8 = ["<div class=\"k2b-rich-select__state-text\">", "</div>"],
17
+ _tmpl$9 = ["<div class=\"k2b-rich-select__state\"", "><span class=\"k2b-rich-select__state-icon\" aria-hidden=\"true\"><i", "></i></span>", "</div>"],
18
+ _tmpl$0 = "<i class=\"ti ti-refresh\" aria-hidden=\"true\"></i>",
19
+ _tmpl$1 = ["<div", "><h3 class=\"k2b-rich-select__preview-title\">", "<span>", "</span></h3>", "</div>"],
20
+ _tmpl$10 = ["<ul class=\"k2b-rich-select__facts\">", "</ul>"],
21
+ _tmpl$11 = ["<li", "><i", " aria-hidden=\"true\"></i><span>", "</span></li>"],
22
+ _tmpl$12 = ["<div class=\"k2b-rich-select__footer\">", "</div>"],
23
+ _tmpl$13 = ["<button type=\"button\" class=\"k2b-rich-select__footer-action\"><span class=\"k2b-rich-select__visual\" aria-hidden=\"true\"><i", "></i></span><span class=\"k2b-rich-select__label\">", "</span></button>"],
24
+ _tmpl$14 = ["<div class=\"k2b-rich-select__create\"><input class=\"k2b-rich-select__create-input\"", " autocomplete=\"off\">", "</div>"],
25
+ _tmpl$15 = ["<div class=\"k2b-rich-select__title\" aria-hidden=\"true\">", "</div>"],
26
+ _tmpl$16 = ["<div", " role=\"listbox\"", "></div>"],
27
+ _tmpl$17 = ["<div class=\"k2b-choice-search k2b-rich-select__search\"><i class=\"ti ti-search\" aria-hidden=\"true\"></i><input type=\"search\" role=\"combobox\"", " aria-autocomplete=\"list\"", " autocomplete=\"off\"></div>"],
28
+ _tmpl$18 = ["<span class=\"k2b-sr-only\">", "</span>"],
29
+ _tmpl$19 = ["<div class=\"k2b-rich-select__body\"><div class=\"k2b-rich-select__column\">", "<div", " class=\"k2b-rich-select__list\" role=\"listbox\"", " data-choice-scroll>", "", "</div>", "</div>", "</div>"],
30
+ _tmpl$20 = ["<div class=\"k2b-choice-control k2b-rich-select\"", ">", "", "<div popover=\"manual\" class=\"k2b-choice-popover k2b-rich-select__popover\" role=\"group\"", " style=\"", "\">", "", "</div></div>"],
31
+ _tmpl$21 = ["<span class=\"k2b-choice-trigger__value\"", ">", "</span>"],
32
+ _tmpl$22 = "<i class=\"ti ti-selector k2b-choice-trigger__chevron\" aria-hidden=\"true\"></i>",
33
+ _tmpl$23 = ["<i", " aria-hidden=\"true\"></i>"],
34
+ _tmpl$24 = ["<input type=\"hidden\"", ">"],
35
+ _tmpl$25 = ["<div class=\"k2b-rich-select__no-results\">", "</div>"],
36
+ _tmpl$26 = ["<div class=\"k2b-rich-select__heading\" role=\"presentation\">", "</div>"],
37
+ _tmpl$27 = ["<div", " class=\"k2b-rich-select__option\" role=\"option\"", " aria-labelledby=\"", "\"", ">", "", "<i class=\"ti ti-check k2b-rich-select__check\" aria-hidden=\"true\"></i></div>"],
38
+ _tmpl$28 = "<span class=\"k2b-rich-select__visual\"></span>",
39
+ _tmpl$29 = ["<div class=\"k2b-rich-select__preview-placeholder\" aria-hidden=\"true\"><span></span><span style=\"", "\"></span><span style=\"", "\"></span><span style=\"", "\"></span></div>"],
40
+ _tmpl$30 = ["<div class=\"k2b-rich-select__preview\" data-choice-scroll>", "", "</div>"],
41
+ _tmpl$31 = ["<button type=\"button\" class=\"k2b-dialog__close\"", "><i class=\"ti ti-chevron-left\" aria-hidden=\"true\"></i></button>"],
42
+ _tmpl$32 = ["<header class=\"k2b-rich-select__sheet-header\">", "<h2>", "</h2><button type=\"button\" class=\"k2b-dialog__close\"", "><i class=\"ti ti-x\" aria-hidden=\"true\"></i></button></header>"],
43
+ _tmpl$33 = ["<div class=\"k2b-choice-search k2b-rich-select__search\"><i class=\"ti ti-search\" aria-hidden=\"true\"></i><input type=\"search\"", " autocomplete=\"off\"></div>"],
44
+ _tmpl$34 = ["<div class=\"k2b-rich-select__list\" role=\"list\"", ">", "", "</div>"],
45
+ _tmpl$35 = ["<button id=\"", "\" type=\"button\" class=\"k2b-rich-select__info\"", "><i class=\"ti ti-info-circle\" aria-hidden=\"true\"></i></button>"],
46
+ _tmpl$36 = ["<div class=\"k2b-rich-select__sheet-row\" role=\"listitem\"", "><button", " type=\"button\" class=\"k2b-rich-select__option\"", " aria-labelledby=\"", "\"", ">", "", "<i class=\"ti ti-check k2b-rich-select__check\" aria-hidden=\"true\"></i></button>", "</div>"],
47
+ _tmpl$37 = ["<div class=\"k2b-rich-select__heading\">", "</div>"],
48
+ _tmpl$38 = ["<div class=\"k2b-rich-select__preview\" data-level=\"detail\">", "</div>"],
49
+ _tmpl$39 = "<i class=\"ti ti-check\" aria-hidden=\"true\"></i>";
50
+ import { createEffect, createMemo, createSignal, createUniqueId, For, Match, onCleanup, onMount, Show, Switch, untrack } from "solid-js";
51
+ import { Button } from "../actions/Button";
52
+ import { dialogCore } from "../feedback/dialog-core";
53
+ import { createFieldMeta, Field, fieldControlAria } from "../internal/field";
54
+ import { LocaleProvider, useLocale } from "../intl/locale";
55
+ import BottomSheet, { bottomSheetOptions } from "../layout/BottomSheet";
56
+ import { createChoicePopover, filterChoiceOptions, nextEnabledChoiceIndex } from "./choice";
57
+ import { commitFieldValue, resolveMaybeAccessor } from "./field-contract";
58
+ import { useRichSelectMessages } from "./rich-select-messages";
59
+
60
+ /** One option: a name plus at most one short line. */
61
+
62
+ /** Search and section headings appear from this many options. */
63
+ export const RICH_SELECT_SEARCH_FROM = 8;
64
+ const PHONE_QUERY = "(max-width: 47.999rem)";
65
+ const PLACEHOLDER_ROWS = 4;
66
+ const isPhone = () => typeof matchMedia === "function" && matchMedia(PHONE_QUERY).matches;
67
+ function RichSelectVisual(props) {
68
+ return _$createComponent(Switch, {
69
+ get children() {
70
+ return [_$createComponent(Match, {
71
+ get when() {
72
+ return props.item.visual;
73
+ },
74
+ children: visual => _$ssr(_tmpl$, _$escape(visual()()))
75
+ }), _$createComponent(Match, {
76
+ get when() {
77
+ return props.item.color;
78
+ },
79
+ children: color => _$ssr(_tmpl$2, _$ssrStyleProperty("background-color:", _$escape(color(), true)))
80
+ }), _$createComponent(Match, {
81
+ get when() {
82
+ return props.item.icon;
83
+ },
84
+ children: icon => _$ssr(_tmpl$3, _$ssrAttribute("class", _$escape(icon(), true), false))
85
+ })];
86
+ }
87
+ });
88
+ }
89
+ const hasVisual = item => Boolean(item.visual || item.color || item.icon);
90
+
91
+ /** Name and second line. The reason of an unavailable row replaces the description. */
92
+ function RichSelectRowText(props) {
93
+ return _$ssr(_tmpl$4, _$ssrAttribute("id", _$escape(props.labelId, true), false), _$escape(props.item.label), _$escape(_$createComponent(Show, {
94
+ get when() {
95
+ return props.item.disabledReason ?? props.item.description;
96
+ },
97
+ children: line => _$ssr(_tmpl$5, _$ssrAttribute("id", _$escape(props.lineId, true), false), _$ssrAttribute("data-reason", props.item.disabledReason ? "true" : _$escape(undefined, true), false), _$escape(line()))
98
+ })));
99
+ }
100
+ function RichSelectPlaceholders(props) {
101
+ return _$createComponent(For, {
102
+ get each() {
103
+ return Array.from({
104
+ length: PLACEHOLDER_ROWS
105
+ }, (_, index) => index);
106
+ },
107
+ children: index => _$ssr(_tmpl$7, _$ssrAttribute("data-visual", props.visual ? "true" : _$escape(undefined, true), false), _$escape(_$createComponent(Show, {
108
+ get when() {
109
+ return props.visual;
110
+ },
111
+ get children() {
112
+ return _$ssr(_tmpl$6);
113
+ }
114
+ })), _$ssrStyleProperty("width:", `${_$escape([58, 46, 66, 50][index % 4], true)}%`), _$ssrStyleProperty("width:", `${_$escape([34, 28, 40, 30][index % 4], true)}%`))
115
+ });
116
+ }
117
+ function RichSelectState(props) {
118
+ let retryButton;
119
+ onCleanup(() => {
120
+ if (retryButton && document.activeElement === retryButton) queueMicrotask(() => props.restoreFocus?.());
121
+ });
122
+ return _$ssr(_tmpl$9, _$ssrAttribute("data-status", _$escape(props.status, true), false) + _$ssrAttribute("role", props.status === "error" ? "alert" : "status", false), _$ssrAttribute("class", props.status === "error" ? "ti ti-alert-triangle" : "ti ti-list-search", false), _$escape(_$createComponent(Show, {
123
+ get when() {
124
+ return props.status === "error";
125
+ },
126
+ get fallback() {
127
+ return _$ssr(_tmpl$8, _$escape(props.empty ?? props.messages.noOptions));
128
+ },
129
+ get children() {
130
+ return [_$ssr(_tmpl$8, _$escape(props.messages.couldNotLoad)), _$createComponent(Show, {
131
+ get when() {
132
+ return props.onRetry;
133
+ },
134
+ children: retry => _$createComponent(Button, {
135
+ variant: "secondary",
136
+ size: "sm",
137
+ onClick: () => retry()(),
138
+ get children() {
139
+ return [_$ssr(_tmpl$0), props.messages.retry];
140
+ }
141
+ })
142
+ })];
143
+ }
144
+ })));
145
+ }
146
+ function RichSelectPreview(props) {
147
+ return _$ssr(_tmpl$1, _$ssrAttribute("id", _$escape(props.id, true), false), _$escape(_$createComponent(RichSelectVisual, {
148
+ get item() {
149
+ return props.item;
150
+ }
151
+ })), _$escape(props.item.label), _$escape(props.render(props.item)));
152
+ }
153
+
154
+ /** Up to three short facts for a preview, each with an icon; warnings in the warning tone. */
155
+ export function RichSelectFacts(props) {
156
+ return _$ssr(_tmpl$10, _$escape(_$createComponent(For, {
157
+ get each() {
158
+ return props.facts.slice(0, 3);
159
+ },
160
+ children: fact => _$ssr(_tmpl$11, _$ssrAttribute("data-tone", fact.tone === "warning" ? "warning" : _$escape(undefined, true), false), _$ssrAttribute("class", _$escape(fact.icon, true), false), _$escape(fact.text))
161
+ })));
162
+ }
163
+ function RichSelectFooterControl(props) {
164
+ const [creating, setCreating] = createSignal(false);
165
+ const [name, setName] = createSignal("");
166
+ let input;
167
+ let start;
168
+ let controls;
169
+ onCleanup(() => {
170
+ if (controls?.contains(document.activeElement)) queueMicrotask(props.restoreFocus);
171
+ });
172
+ const create = () => {
173
+ const footer = props.footer;
174
+ const value = name().trim();
175
+ if (!("create" in footer) || !value) return;
176
+ props.done(() => footer.create.onCreate(value));
177
+ };
178
+ return _$ssr(_tmpl$12, _$escape(_$createComponent(Show, {
179
+ get when() {
180
+ return _$memo(() => !!(creating() && "create" in props.footer))() ? props.footer.create : undefined;
181
+ },
182
+ get fallback() {
183
+ return _$ssr(_tmpl$13, _$ssrAttribute("class", _$escape(props.footer.icon ?? "ti ti-plus", true), false), _$escape(props.footer.label));
184
+ },
185
+ children: create_ => _$ssr(_tmpl$14, _$ssrAttribute("value", _$escape(name(), true), false) + _$ssrAttribute("placeholder", _$escape(create_().placeholder, true), false) + _$ssrAttribute("aria-label", _$escape(props.footer.label, true), false), _$escape(_$createComponent(Button, {
186
+ type: "button",
187
+ variant: "primary",
188
+ size: "sm",
189
+ get disabled() {
190
+ return !name().trim();
191
+ },
192
+ onClick: create,
193
+ get children() {
194
+ return props.messages.create;
195
+ }
196
+ })))
197
+ })));
198
+ }
199
+
200
+ /**
201
+ * A dropdown whose rows explain each choice: a name plus one short line, an
202
+ * unavailable row with its reason, and an optional preview of what a choice
203
+ * changes. Desktop opens a popover beside the trigger; a phone opens a bottom
204
+ * sheet whose info buttons show the preview as a second level.
205
+ */
206
+ export function RichSelect(props) {
207
+ const messages = useRichSelectMessages();
208
+ const locale = useLocale();
209
+ const meta = createFieldMeta(props.id);
210
+ const listboxId = `${meta.controlId}-listbox`;
211
+ const previewId = `${meta.controlId}-preview`;
212
+ const [query, setQuery] = createSignal("");
213
+ const [active, setActive] = createSignal(-1);
214
+ const [height, setHeight] = createSignal();
215
+ const [sheetOpen, setSheetOpen] = createSignal(false);
216
+ const [phone, setPhone] = createSignal(false);
217
+ const [sheetId, setSheetId] = createSignal();
218
+ onMount(() => {
219
+ const media = window.matchMedia(PHONE_QUERY);
220
+ setPhone(media.matches);
221
+ const update = () => setPhone(media.matches);
222
+ media.addEventListener("change", update);
223
+ onCleanup(() => media.removeEventListener("change", update));
224
+ });
225
+ let searchRef;
226
+ let closeSheet;
227
+ const value = () => resolveMaybeAccessor(props.value) ?? null;
228
+ const error = () => resolveMaybeAccessor(props.error);
229
+ const status = () => props.status ?? "ready";
230
+ const withPreview = () => Boolean(props.renderPreview);
231
+ const title = () => props.title ?? (typeof props.label === "string" ? props.label : props["aria-label"] ?? props.placeholder ?? messages().chooseOption);
232
+ const searchable = () => status() === "ready" && props.items.length >= RICH_SELECT_SEARCH_FROM;
233
+ const visible = createMemo(() => searchable() ? filterChoiceOptions(props.items, query()) : props.items);
234
+ const anyVisual = createMemo(() => props.items.some(hasVisual));
235
+ const rows = createMemo(() => {
236
+ const headings = props.items.length >= RICH_SELECT_SEARCH_FROM && props.sections ? props.sections : undefined;
237
+ const result = [];
238
+ let section;
239
+ visible().forEach((item, index) => {
240
+ if (headings && item.section && item.section !== section) {
241
+ const heading = headings.find(candidate => candidate.id === item.section);
242
+ if (heading) result.push({
243
+ kind: "heading",
244
+ id: heading.id,
245
+ label: heading.label
246
+ });
247
+ }
248
+ section = item.section;
249
+ result.push({
250
+ kind: "item",
251
+ item,
252
+ index
253
+ });
254
+ });
255
+ return result;
256
+ });
257
+ const selected = createMemo(() => {
258
+ const current = value();
259
+ return current === null ? undefined : props.items.find(item => item.value === current);
260
+ });
261
+ const activeItem = () => status() === "ready" ? visible()[active()] : undefined;
262
+ const optionId = index => `${listboxId}-${index}`;
263
+ const popover = createChoicePopover(() => Boolean(props.disabled), () => ({
264
+ width: "own",
265
+ side: props.placement === "top-start" ? "above" : "below"
266
+ }));
267
+ const expanded = () => popover.open() || sheetOpen();
268
+ const restorePopoverFocus = () => {
269
+ if (popover.open()) (searchable() ? searchRef : popover.trigger())?.focus();
270
+ };
271
+ createEffect(() => {
272
+ if (props.disabled) {
273
+ popover.hide();
274
+ closeSheet?.();
275
+ }
276
+ });
277
+ createEffect(() => {
278
+ const count = visible().length;
279
+ if (!popover.open() || status() !== "ready") return;
280
+ const current = untrack(active);
281
+ if (current < 0 || current >= count) setActive(startIndex());
282
+ });
283
+ const scrollToActive = () => {
284
+ const element = document.getElementById(optionId(active()));
285
+ element?.scrollIntoView({
286
+ block: "nearest"
287
+ });
288
+ };
289
+ const move = next => {
290
+ if (next < 0) return;
291
+ setActive(next);
292
+ queueMicrotask(scrollToActive);
293
+ };
294
+ const startIndex = () => {
295
+ const index = visible().findIndex(item => item.value === value());
296
+ return index >= 0 ? index : visible().length > 0 ? 0 : -1;
297
+ };
298
+ const openPopover = () => {
299
+ setQuery("");
300
+ setActive(startIndex());
301
+ // The preview popover keeps one height while it is open, so moving
302
+ // through rows, filtering, or the end of loading never resizes it.
303
+ const rowsTall = status() === "ready" ? props.items.length : PLACEHOLDER_ROWS;
304
+ const rem = Math.min(27.5, Math.max(18.75, rowsTall * 3.625 + 1.5));
305
+ setHeight(props.size?.height ?? (withPreview() ? `${rem}rem` : undefined));
306
+ popover.show();
307
+ if (searchable()) queueMicrotask(() => searchRef?.focus());
308
+ queueMicrotask(scrollToActive);
309
+ };
310
+ const open = () => {
311
+ if (props.disabled || expanded()) return;
312
+ if (isPhone()) openSheet();else openPopover();
313
+ };
314
+ const close = (restoreFocus = false) => {
315
+ popover.hide(restoreFocus);
316
+ setQuery("");
317
+ setActive(-1);
318
+ };
319
+ const choose = item => {
320
+ if (props.disabled || status() !== "ready" || !item || item.disabledReason) return;
321
+ // Hide first: the old list must never stay visible with the next value.
322
+ close(true);
323
+ commitFieldValue(props, item.value);
324
+ };
325
+ const runFooter = run => {
326
+ close(true);
327
+ run();
328
+ };
329
+ const onKeyDown = event => {
330
+ if (event.isComposing) return;
331
+ const target = event.target;
332
+ if (event.key !== "Escape" && target instanceof Element && target !== popover.trigger() && target !== searchRef && target.closest("input, button, textarea, a, [contenteditable]")) return;
333
+ const isOpen = popover.open();
334
+ const count = visible().length;
335
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
336
+ event.preventDefault();
337
+ if (!isOpen) open();else if (status() === "ready") move(nextEnabledChoiceIndex(visible(), active(), event.key === "ArrowDown" ? 1 : -1));
338
+ } else if ((event.key === "Home" || event.key === "End") && isOpen) {
339
+ event.preventDefault();
340
+ if (status() === "ready" && count > 0) move(event.key === "Home" ? 0 : count - 1);
341
+ } else if ((event.key === "Enter" || event.key === " ") && !isOpen && event.target === popover.trigger()) {
342
+ event.preventDefault();
343
+ open();
344
+ } else if (event.key === "Enter" && isOpen) {
345
+ // Enter on an unavailable row does nothing; the list stays open.
346
+ event.preventDefault();
347
+ choose(activeItem());
348
+ } else if (event.key === "Escape" && isOpen) {
349
+ // A closed picker lets Escape reach an enclosing dialog.
350
+ event.preventDefault();
351
+ event.stopPropagation();
352
+ close(true);
353
+ } else if (isOpen && searchable() && event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey && event.target !== searchRef) {
354
+ // Typing anywhere in the open picker goes to the search field.
355
+ event.preventDefault();
356
+ setQuery(query() + event.key);
357
+ setActive(visible().length > 0 ? 0 : -1);
358
+ searchRef?.focus();
359
+ }
360
+ };
361
+ const onFocusOut = event => {
362
+ const next = event.relatedTarget;
363
+ if (!popover.open() || !(next instanceof Node)) return;
364
+ if (popover.trigger()?.contains(next) || popoverElement?.contains(next)) return;
365
+ close();
366
+ };
367
+ let popoverElement;
368
+ const openSheet = () => {
369
+ const current = locale();
370
+ const lifetime = new AbortController();
371
+ // dialogCore can wait for a previous sheet's history traversal. Disabling
372
+ // or unmounting the field must also cancel an opening that is still queued.
373
+ closeSheet = () => lifetime.abort();
374
+ let after;
375
+ setSheetOpen(true);
376
+ void dialogCore.open((closeDialog, context) => {
377
+ context.dialog.id ||= `${meta.controlId}-sheet`;
378
+ setSheetId(context.dialog.id);
379
+ return _$createComponent(LocaleProvider, {
380
+ locale: current,
381
+ get children() {
382
+ return _$createComponent(BottomSheet, {
383
+ get onDismiss() {
384
+ return context.requestDismiss;
385
+ },
386
+ get children() {
387
+ return _$createComponent(RichSelectSheet, {
388
+ props: props,
389
+ get title() {
390
+ return title();
391
+ },
392
+ value: value,
393
+ get dialog() {
394
+ return context.dialog;
395
+ },
396
+ close: () => closeDialog(),
397
+ done: run => {
398
+ after = run;
399
+ closeDialog();
400
+ }
401
+ });
402
+ }
403
+ });
404
+ }
405
+ });
406
+ }, {
407
+ ...bottomSheetOptions,
408
+ history: true,
409
+ signal: lifetime.signal,
410
+ // A phone keyboard must not cover the list as it opens: focus starts on the sheet.
411
+ initialFocus: dialog => {
412
+ dialog.tabIndex = -1;
413
+ return dialog;
414
+ }
415
+ }).then(() => {
416
+ if (!lifetime.signal.aborted) after?.();
417
+ }).finally(() => {
418
+ closeSheet = undefined;
419
+ setSheetOpen(false);
420
+ });
421
+ };
422
+ onCleanup(() => closeSheet?.());
423
+ const triggerText = () => props.triggerLabel ?? selected()?.label ?? props.placeholder ?? messages().chooseOption;
424
+ return _$createComponent(Field, {
425
+ get ["class"]() {
426
+ return props.class;
427
+ },
428
+ get label() {
429
+ return props.label;
430
+ },
431
+ get description() {
432
+ return props.description;
433
+ },
434
+ get error() {
435
+ return error();
436
+ },
437
+ meta: meta,
438
+ get required() {
439
+ return props.required;
440
+ },
441
+ get disabled() {
442
+ return props.disabled;
443
+ },
444
+ get children() {
445
+ return _$ssr(_tmpl$20, _$ssrAttribute("data-appearance", _$escape(props.appearance ?? "field", true), false) + _$ssrAttribute("data-invalid", error() ? "true" : _$escape(undefined, true), false), _$ssrElement("button", _$mergeProps({
446
+ get id() {
447
+ return meta.controlId;
448
+ },
449
+ type: "button",
450
+ "class": "k2b-choice-trigger k2b-rich-select__trigger",
451
+ role: "combobox",
452
+ get ["aria-haspopup"]() {
453
+ return sheetOpen() || !popover.open() && phone() ? "dialog" : "listbox";
454
+ },
455
+ get ["aria-expanded"]() {
456
+ return expanded();
457
+ },
458
+ get ["aria-controls"]() {
459
+ return sheetOpen() ? sheetId() : popover.open() ? listboxId : undefined;
460
+ },
461
+ get ["aria-activedescendant"]() {
462
+ return popover.open() && activeItem() ? optionId(active()) : undefined;
463
+ },
464
+ get ["data-tone"]() {
465
+ return props.tone === "warning" ? "warning" : undefined;
466
+ }
467
+ }, () => fieldControlAria(meta, {
468
+ ...props,
469
+ "aria-label": props["aria-label"] ?? (typeof props.label === "string" ? undefined : title())
470
+ }), {
471
+ get disabled() {
472
+ return props.disabled;
473
+ }
474
+ }), _$escape(_$createComponent(Show, {
475
+ get when() {
476
+ return props.renderTrigger;
477
+ },
478
+ get fallback() {
479
+ return [_$createComponent(Show, {
480
+ get when() {
481
+ return _$memo(() => !!(selected() && hasVisual(selected())))() ? selected() : undefined;
482
+ },
483
+ get fallback() {
484
+ return _$createComponent(Show, {
485
+ get when() {
486
+ return props.icon;
487
+ },
488
+ children: icon => _$ssr(_tmpl$23, _$ssrAttribute("class", _$escape(icon(), true), false))
489
+ });
490
+ },
491
+ children: item => _$createComponent(RichSelectVisual, {
492
+ get item() {
493
+ return item();
494
+ }
495
+ })
496
+ }), _$ssr(_tmpl$21, _$ssrAttribute("data-placeholder", selected() || props.triggerLabel ? _$escape(undefined, true) : "true", false), _$escape(triggerText())), _$ssr(_tmpl$22)];
497
+ },
498
+ children: render => render()(selected())
499
+ })), false), _$escape(_$createComponent(Show, {
500
+ get when() {
501
+ return props.name;
502
+ },
503
+ children: name => _$ssr(_tmpl$24, _$ssrAttribute("name", _$escape(name(), true), false) + _$ssrAttribute("value", _$escape(value() ?? "", true), false))
504
+ })), _$ssrAttribute("aria-label", _$escape(title(), true), false) + _$ssrAttribute("data-preview", withPreview() ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-status", _$escape(status(), true), false), _$ssrStyleProperty("width:", _$escape(props.size?.width, true)) + _$ssrStyleProperty(";height:", _$escape(height(), true)), _$escape(_$createComponent(Show, {
505
+ get when() {
506
+ return !withPreview();
507
+ },
508
+ get children() {
509
+ return _$ssr(_tmpl$15, _$escape(title()));
510
+ }
511
+ })), _$escape(_$createComponent(Switch, {
512
+ get children() {
513
+ return [_$createComponent(Match, {
514
+ get when() {
515
+ return status() === "error";
516
+ },
517
+ get children() {
518
+ return [_$ssr(_tmpl$16, _$ssrAttribute("id", _$escape(listboxId, true), false), _$ssrAttribute("aria-label", _$escape(title(), true), false)), _$createComponent(RichSelectState, {
519
+ status: "error",
520
+ get messages() {
521
+ return messages();
522
+ },
523
+ get onRetry() {
524
+ return props.onRetry;
525
+ },
526
+ restoreFocus: restorePopoverFocus
527
+ })];
528
+ }
529
+ }), _$createComponent(Match, {
530
+ get when() {
531
+ return _$memo(() => status() === "ready")() && props.items.length === 0;
532
+ },
533
+ get children() {
534
+ return [_$ssr(_tmpl$16, _$ssrAttribute("id", _$escape(listboxId, true), false), _$ssrAttribute("aria-label", _$escape(title(), true), false)), _$createComponent(RichSelectState, {
535
+ status: "empty",
536
+ get messages() {
537
+ return messages();
538
+ },
539
+ get empty() {
540
+ return props.empty;
541
+ }
542
+ }), _$createComponent(Show, {
543
+ get when() {
544
+ return props.footer;
545
+ },
546
+ children: footer => _$createComponent(RichSelectFooterControl, {
547
+ get footer() {
548
+ return footer();
549
+ },
550
+ initialName: query,
551
+ get messages() {
552
+ return messages();
553
+ },
554
+ done: runFooter,
555
+ restoreFocus: restorePopoverFocus
556
+ })
557
+ })];
558
+ }
559
+ }), _$createComponent(Match, {
560
+ when: true,
561
+ get children() {
562
+ return _$ssr(_tmpl$19, _$escape(_$createComponent(Show, {
563
+ get when() {
564
+ return searchable();
565
+ },
566
+ get children() {
567
+ return _$ssr(_tmpl$17, _$ssrAttribute("aria-expanded", _$escape(popover.open(), true), false), _$ssrAttribute("value", _$escape(query(), true), false) + _$ssrAttribute("placeholder", _$escape(props.searchPlaceholder ?? messages().search, true), false) + _$ssrAttribute("aria-label", _$escape(props.searchPlaceholder ?? messages().search, true), false) + _$ssrAttribute("aria-controls", _$escape(listboxId, true), false) + _$ssrAttribute("aria-activedescendant", activeItem() ? _$escape(optionId(active()), true) : _$escape(undefined, true), false));
568
+ }
569
+ })), _$ssrAttribute("id", _$escape(listboxId, true), false), _$ssrAttribute("aria-label", _$escape(title(), true), false) + _$ssrAttribute("aria-busy", status() === "loading" ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-visual", anyVisual() ? "true" : _$escape(undefined, true), false), _$escape(_$createComponent(Show, {
570
+ get when() {
571
+ return status() === "loading";
572
+ },
573
+ get children() {
574
+ return [_$ssr(_tmpl$18, _$escape(messages().loading)), _$createComponent(RichSelectPlaceholders, {
575
+ get visual() {
576
+ return anyVisual() || props.items.length === 0;
577
+ }
578
+ })];
579
+ }
580
+ })), _$escape(_$createComponent(Show, {
581
+ get when() {
582
+ return status() === "ready";
583
+ },
584
+ get children() {
585
+ return _$createComponent(For, {
586
+ get each() {
587
+ return rows();
588
+ },
589
+ get fallback() {
590
+ return _$ssr(_tmpl$25, _$escape(messages().noResults));
591
+ },
592
+ children: row => row.kind === "heading" ? _$ssr(_tmpl$26, _$escape(row.label)) : // biome-ignore lint/a11y/useKeyWithClickEvents: the trigger or search field handles the keys through aria-activedescendant.
593
+ _$ssr(_tmpl$27, _$ssrAttribute("id", _$escape(optionId(row.index), true), false), _$ssrAttribute("aria-selected", _$escape(row.item.value, true) === _$escape(value(), true), false) + _$ssrAttribute("aria-disabled", row.item.disabledReason ? "true" : _$escape(undefined, true), false), `${_$escape(optionId(row.index), true)}-label`, _$ssrAttribute("aria-describedby", _$escape([row.item.disabledReason || row.item.description ? `${optionId(row.index)}-line` : "", withPreview() && row.index === active() ? previewId : ""].filter(Boolean).join(" ") || undefined, true), false) + _$ssrAttribute("data-active", row.index === active() ? "true" : _$escape(undefined, true), false), _$escape(_$createComponent(Show, {
594
+ get when() {
595
+ return anyVisual();
596
+ },
597
+ get children() {
598
+ return _$createComponent(Show, {
599
+ get when() {
600
+ return hasVisual(row.item);
601
+ },
602
+ get fallback() {
603
+ return _$ssr(_tmpl$28);
604
+ },
605
+ get children() {
606
+ return _$createComponent(RichSelectVisual, {
607
+ get item() {
608
+ return row.item;
609
+ }
610
+ });
611
+ }
612
+ });
613
+ }
614
+ })), _$escape(_$createComponent(RichSelectRowText, {
615
+ get item() {
616
+ return row.item;
617
+ },
618
+ get labelId() {
619
+ return `${optionId(row.index)}-label`;
620
+ },
621
+ get lineId() {
622
+ return `${optionId(row.index)}-line`;
623
+ }
624
+ })))
625
+ });
626
+ }
627
+ })), _$escape(_$createComponent(Show, {
628
+ get when() {
629
+ return _$memo(() => !!props.footer)() && status() === "ready";
630
+ },
631
+ get children() {
632
+ return _$createComponent(RichSelectFooterControl, {
633
+ get footer() {
634
+ return props.footer;
635
+ },
636
+ initialName: query,
637
+ get messages() {
638
+ return messages();
639
+ },
640
+ done: runFooter,
641
+ restoreFocus: restorePopoverFocus
642
+ });
643
+ }
644
+ })), _$escape(_$createComponent(Show, {
645
+ get when() {
646
+ return props.renderPreview;
647
+ },
648
+ children: render => _$ssr(_tmpl$30, _$escape(_$createComponent(Show, {
649
+ get when() {
650
+ return status() === "loading";
651
+ },
652
+ get children() {
653
+ return _$ssr(_tmpl$29, _$ssrStyleProperty("width:", "86%"), _$ssrStyleProperty("width:", "72%"), _$ssrStyleProperty("width:", "80%"));
654
+ }
655
+ })), _$escape(_$createComponent(Show, {
656
+ get when() {
657
+ return activeItem();
658
+ },
659
+ children: item => _$createComponent(RichSelectPreview, {
660
+ id: previewId,
661
+ get item() {
662
+ return item();
663
+ },
664
+ get render() {
665
+ return render();
666
+ }
667
+ })
668
+ })))
669
+ })));
670
+ }
671
+ })];
672
+ }
673
+ })));
674
+ }
675
+ });
676
+ }
677
+
678
+ /**
679
+ * The phone presentation: a bottom sheet with the list. With a preview, an
680
+ * info button beside each row, unavailable rows included, opens the preview as
681
+ * a second level with Back and Choose.
682
+ */
683
+ function RichSelectSheet(sheet) {
684
+ const messages = useRichSelectMessages();
685
+ const props = sheet.props;
686
+ const uid = createUniqueId();
687
+ const [query, setQuery] = createSignal("");
688
+ const [detailValue, setDetailValue] = createSignal();
689
+ // Resolve from the current snapshot: access and availability can change while
690
+ // the detail level is open.
691
+ const detail = createMemo(() => props.items.find(item => item.value === detailValue()));
692
+ let back;
693
+ let returnValue;
694
+ const status = () => props.status ?? "ready";
695
+ const searchable = () => status() === "ready" && props.items.length >= RICH_SELECT_SEARCH_FROM;
696
+ const visible = createMemo(() => searchable() ? filterChoiceOptions(props.items, query()) : props.items);
697
+ const anyVisual = createMemo(() => props.items.some(hasVisual));
698
+ const headings = () => props.items.length >= RICH_SELECT_SEARCH_FROM && props.sections ? props.sections : undefined;
699
+ const restoreSheetFocus = () => {
700
+ if (sheet.dialog.open) sheet.dialog.focus();
701
+ };
702
+ const headingBefore = index => {
703
+ const item = visible()[index];
704
+ const list = headings();
705
+ if (!list || !item?.section || visible()[index - 1]?.section === item.section) return undefined;
706
+ return list.find(candidate => candidate.id === item.section)?.label;
707
+ };
708
+ const choose = item => {
709
+ if (props.disabled || status() !== "ready" || item.disabledReason) return;
710
+ sheet.done(() => {
711
+ const current = props.items.find(candidate => candidate.value === item.value);
712
+ if (!props.disabled && status() === "ready" && current && !current.disabledReason) commitFieldValue(props, current.value);
713
+ });
714
+ };
715
+ const rowId = index => `k2b-rich-select-sheet-${uid}-${index}`;
716
+ const showDetail = item => {
717
+ returnValue = item.value;
718
+ // The second level keeps the sheet's height, so Back and Choose stay where they are.
719
+ sheet.dialog.style.minHeight = `${sheet.dialog.getBoundingClientRect().height}px`;
720
+ setDetailValue(item.value);
721
+ queueMicrotask(() => back?.focus());
722
+ };
723
+ const leaveDetail = () => {
724
+ sheet.dialog.style.minHeight = "";
725
+ setDetailValue(undefined);
726
+ const value = returnValue;
727
+ queueMicrotask(() => {
728
+ const index = visible().findIndex(item => item.value === value);
729
+ const original = index >= 0 ? document.getElementById(`${rowId(index)}-info`) : undefined;
730
+ const fallback = sheet.dialog.querySelector(".k2b-rich-select__sheet-row > button");
731
+ (original ?? fallback ?? sheet.dialog).focus();
732
+ });
733
+ };
734
+ createEffect(() => {
735
+ if (detailValue() !== undefined && (!detail() || status() !== "ready")) leaveDetail();
736
+ });
737
+ // Escape on the second level goes back to the list instead of closing the sheet.
738
+ const onEscape = event => {
739
+ if (event.key !== "Escape" || !detail()) return;
740
+ event.preventDefault();
741
+ event.stopPropagation();
742
+ leaveDetail();
743
+ };
744
+ onMount(() => {
745
+ sheet.dialog.addEventListener("keydown", onEscape, true);
746
+ onCleanup(() => {
747
+ sheet.dialog.removeEventListener("keydown", onEscape, true);
748
+ // dialogCore may reuse the dialog element for the next dialog.
749
+ sheet.dialog.style.minHeight = "";
750
+ });
751
+ });
752
+ return [_$ssr(_tmpl$32, _$escape(_$createComponent(Show, {
753
+ get when() {
754
+ return detail();
755
+ },
756
+ get children() {
757
+ return _$ssr(_tmpl$31, _$ssrAttribute("aria-label", _$escape(messages().back, true), false));
758
+ }
759
+ })), _$escape(detail()?.label ?? sheet.title), _$ssrAttribute("aria-label", _$escape(messages().close, true), false)), _$createComponent(Show, {
760
+ get when() {
761
+ return detail();
762
+ },
763
+ get fallback() {
764
+ return _$createComponent(BottomSheet.Body, {
765
+ get children() {
766
+ return _$createComponent(Switch, {
767
+ get children() {
768
+ return [_$createComponent(Match, {
769
+ get when() {
770
+ return status() === "error";
771
+ },
772
+ get children() {
773
+ return _$createComponent(RichSelectState, {
774
+ status: "error",
775
+ get messages() {
776
+ return messages();
777
+ },
778
+ get onRetry() {
779
+ return props.onRetry;
780
+ },
781
+ restoreFocus: restoreSheetFocus
782
+ });
783
+ }
784
+ }), _$createComponent(Match, {
785
+ get when() {
786
+ return _$memo(() => status() === "ready")() && props.items.length === 0;
787
+ },
788
+ get children() {
789
+ return [_$createComponent(RichSelectState, {
790
+ status: "empty",
791
+ get messages() {
792
+ return messages();
793
+ },
794
+ get empty() {
795
+ return props.empty;
796
+ }
797
+ }), _$createComponent(Show, {
798
+ get when() {
799
+ return props.footer;
800
+ },
801
+ children: footer => _$createComponent(RichSelectFooterControl, {
802
+ get footer() {
803
+ return footer();
804
+ },
805
+ initialName: query,
806
+ get messages() {
807
+ return messages();
808
+ },
809
+ get done() {
810
+ return sheet.done;
811
+ },
812
+ restoreFocus: restoreSheetFocus
813
+ })
814
+ })];
815
+ }
816
+ }), _$createComponent(Match, {
817
+ when: true,
818
+ get children() {
819
+ return [_$createComponent(Show, {
820
+ get when() {
821
+ return searchable();
822
+ },
823
+ get children() {
824
+ return _$ssr(_tmpl$33, _$ssrAttribute("value", _$escape(query(), true), false) + _$ssrAttribute("placeholder", _$escape(props.searchPlaceholder ?? messages().search, true), false) + _$ssrAttribute("aria-label", _$escape(props.searchPlaceholder ?? messages().search, true), false));
825
+ }
826
+ }), _$ssr(_tmpl$34, _$ssrAttribute("aria-label", _$escape(sheet.title, true), false) + _$ssrAttribute("aria-busy", status() === "loading" ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-visual", anyVisual() ? "true" : _$escape(undefined, true), false), _$escape(_$createComponent(Show, {
827
+ get when() {
828
+ return status() === "loading";
829
+ },
830
+ get children() {
831
+ return [_$ssr(_tmpl$18, _$escape(messages().loading)), _$createComponent(RichSelectPlaceholders, {
832
+ get visual() {
833
+ return anyVisual() || props.items.length === 0;
834
+ }
835
+ })];
836
+ }
837
+ })), _$escape(_$createComponent(Show, {
838
+ get when() {
839
+ return status() === "ready";
840
+ },
841
+ get children() {
842
+ return _$createComponent(For, {
843
+ get each() {
844
+ return visible();
845
+ },
846
+ get fallback() {
847
+ return _$ssr(_tmpl$25, _$escape(messages().noResults));
848
+ },
849
+ children: (item, index) => [_$createComponent(Show, {
850
+ get when() {
851
+ return headingBefore(index());
852
+ },
853
+ children: label => _$ssr(_tmpl$37, _$escape(label()))
854
+ }), _$ssr(_tmpl$36, _$ssrAttribute("data-info", props.renderPreview ? "true" : _$escape(undefined, true), false), _$ssrAttribute("id", _$escape(rowId(index()), true), false), _$ssrAttribute("aria-current", item.value === sheet.value() ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("aria-disabled", item.disabledReason ? "true" : _$escape(undefined, true), false), `${_$escape(rowId(index()), true)}-label`, _$ssrAttribute("aria-describedby", item.disabledReason || item.description ? `${_$escape(rowId(index()), true)}-line` : _$escape(undefined, true), false), _$escape(_$createComponent(Show, {
855
+ get when() {
856
+ return anyVisual();
857
+ },
858
+ get children() {
859
+ return _$createComponent(Show, {
860
+ get when() {
861
+ return hasVisual(item);
862
+ },
863
+ get fallback() {
864
+ return _$ssr(_tmpl$28);
865
+ },
866
+ get children() {
867
+ return _$createComponent(RichSelectVisual, {
868
+ item: item
869
+ });
870
+ }
871
+ });
872
+ }
873
+ })), _$escape(_$createComponent(RichSelectRowText, {
874
+ item: item,
875
+ get labelId() {
876
+ return `${rowId(index())}-label`;
877
+ },
878
+ get lineId() {
879
+ return `${rowId(index())}-line`;
880
+ }
881
+ })), _$escape(_$createComponent(Show, {
882
+ get when() {
883
+ return props.renderPreview;
884
+ },
885
+ get children() {
886
+ return _$ssr(_tmpl$35, `${_$escape(rowId(index()), true)}-info`, _$ssrAttribute("aria-label", _$escape(messages().detailsFor({
887
+ name: item.label
888
+ }), true), false));
889
+ }
890
+ })))]
891
+ });
892
+ }
893
+ }))), _$createComponent(Show, {
894
+ get when() {
895
+ return _$memo(() => !!props.footer)() && status() === "ready";
896
+ },
897
+ get children() {
898
+ return _$createComponent(RichSelectFooterControl, {
899
+ get footer() {
900
+ return props.footer;
901
+ },
902
+ initialName: query,
903
+ get messages() {
904
+ return messages();
905
+ },
906
+ get done() {
907
+ return sheet.done;
908
+ },
909
+ restoreFocus: restoreSheetFocus
910
+ });
911
+ }
912
+ })];
913
+ }
914
+ })];
915
+ }
916
+ });
917
+ }
918
+ });
919
+ },
920
+ children: item => [_$createComponent(BottomSheet.Body, {
921
+ get children() {
922
+ return _$ssr(_tmpl$38, _$escape(_$createComponent(RichSelectPreview, {
923
+ get item() {
924
+ return item();
925
+ },
926
+ get render() {
927
+ return props.renderPreview;
928
+ }
929
+ })));
930
+ }
931
+ }), _$createComponent(BottomSheet.Footer, {
932
+ get children() {
933
+ return _$createComponent(Button, {
934
+ variant: "primary",
935
+ size: "lg",
936
+ "class": "k2b-rich-select__choose",
937
+ get disabled() {
938
+ return Boolean(item().disabledReason);
939
+ },
940
+ onClick: () => choose(item()),
941
+ get children() {
942
+ return [_$ssr(_tmpl$39), messages().choose];
943
+ }
944
+ });
945
+ }
946
+ })]
947
+ })];
948
+ }
949
+ export default RichSelect;
950
+ //# sourceMappingURL=RichSelect.js.map