@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
@@ -0,0 +1,164 @@
1
+ import { template as _$template } from "solid-js/web";
2
+ import { setAttribute as _$setAttribute } from "solid-js/web";
3
+ import { className as _$className } from "solid-js/web";
4
+ import { effect as _$effect } from "solid-js/web";
5
+ import { getNextMarker as _$getNextMarker } from "solid-js/web";
6
+ import { createComponent as _$createComponent } from "solid-js/web";
7
+ import { getNextElement as _$getNextElement } from "solid-js/web";
8
+ import { insert as _$insert } from "solid-js/web";
9
+ import { memo as _$memo } from "solid-js/web";
10
+ import { use as _$use } from "solid-js/web";
11
+ var _tmpl$ = /*#__PURE__*/_$template(`<p class=k2b-qr-scanner__note>`),
12
+ _tmpl$2 = /*#__PURE__*/_$template(`<div><div class=k2b-qr-scanner__preview><video muted playsinline></video></div><p role=status></p><!$><!/>`);
13
+ import { timed } from "@k2b/stdlib/solid";
14
+ import { createSignal, onCleanup, onMount, Show } from "solid-js";
15
+ import { useUiMessages } from "../intl/messages";
16
+ /**
17
+ * qr-scanner turns every getUserMedia failure into the string "Camera not found.", so only the Permissions API can
18
+ * tell a refusal apart. Safari and Chrome expose the camera permission; elsewhere a refusal counts as unavailable.
19
+ */
20
+ const cameraDenied = async () => {
21
+ try {
22
+ return (await navigator.permissions.query({
23
+ name: "camera"
24
+ })).state === "denied";
25
+ } catch {
26
+ return false;
27
+ }
28
+ };
29
+
30
+ /**
31
+ * Scans a QR code with the rear camera. Each mount owns exactly one camera session, which stops when the scanner
32
+ * unmounts, the page is hidden, or a result is accepted. The scanning engine loads only when the scanner mounts.
33
+ * Decoded content is never logged.
34
+ */
35
+ export function QrScanner(props) {
36
+ const messages = useUiMessages();
37
+ const [starting, setStarting] = createSignal(true);
38
+ const [invalid, setInvalid] = createSignal(false);
39
+ let lastRejected;
40
+ const resetRejected = timed.debounce(() => {
41
+ lastRejected = undefined;
42
+ }, 1000);
43
+ const resetFeedback = timed.debounce(() => setInvalid(false), 1500);
44
+ let video;
45
+ let scanner;
46
+ let closed = false;
47
+ /** The host has unmounted the scanner; it no longer hears about failures that finish later. */
48
+ let unmounted = false;
49
+ let cleanupMotion;
50
+ const destroy = () => {
51
+ closed = true;
52
+ cleanupMotion?.();
53
+ resetRejected.cancel();
54
+ resetFeedback.cancel();
55
+ // pause(true) stops existing tracks immediately; destroy also handles a still-pending permission request.
56
+ void scanner?.pause(true);
57
+ scanner?.destroy();
58
+ scanner = undefined;
59
+ };
60
+ const fail = async () => {
61
+ if (closed) return;
62
+ destroy();
63
+ const denied = await cameraDenied();
64
+ if (!unmounted) props.onError(denied ? "denied" : "unavailable");
65
+ };
66
+ onMount(() => {
67
+ const hidden = () => {
68
+ if (document.visibilityState !== "visible") props.onStop();
69
+ };
70
+ const leaving = () => props.onStop();
71
+ document.addEventListener("visibilitychange", hidden);
72
+ window.addEventListener("pagehide", leaving);
73
+ onCleanup(() => {
74
+ unmounted = true;
75
+ destroy();
76
+ document.removeEventListener("visibilitychange", hidden);
77
+ window.removeEventListener("pagehide", leaving);
78
+ });
79
+ void (async () => {
80
+ try {
81
+ const {
82
+ default: Engine
83
+ } = await import("qr-scanner");
84
+ if (closed || document.visibilityState !== "visible") return;
85
+ scanner = new Engine(video, result => {
86
+ if (closed) return;
87
+ // Rearm only after a full second without a decoded QR, not between individual frames.
88
+ resetRejected.debouncedFn();
89
+ if (result.data === lastRejected) return;
90
+ if (props.onResult(result.data)) {
91
+ destroy();
92
+ return;
93
+ }
94
+ lastRejected = result.data;
95
+ setInvalid(true);
96
+ resetFeedback.debouncedFn();
97
+ }, {
98
+ preferredCamera: "environment",
99
+ highlightScanRegion: true,
100
+ // Empty frames are expected. Never log decoded content or frame data.
101
+ onDecodeError: error => {
102
+ if (closed || error === Engine.NO_QR_CODE_FOUND) return;
103
+ void fail();
104
+ }
105
+ });
106
+ const motion = matchMedia("(prefers-reduced-motion: reduce)");
107
+ const applyMotion = () => {
108
+ for (const animation of scanner?.$overlay?.getAnimations({
109
+ subtree: true
110
+ }) ?? []) {
111
+ if (motion.matches) animation.pause();else animation.play();
112
+ }
113
+ };
114
+ applyMotion();
115
+ motion.addEventListener("change", applyMotion);
116
+ cleanupMotion = () => motion.removeEventListener("change", applyMotion);
117
+ await scanner.start();
118
+ if (!closed) setStarting(false);
119
+ } catch {
120
+ await fail();
121
+ }
122
+ })();
123
+ });
124
+ return (() => {
125
+ var _el$ = _$getNextElement(_tmpl$2),
126
+ _el$2 = _el$.firstChild,
127
+ _el$3 = _el$2.firstChild,
128
+ _el$4 = _el$2.nextSibling,
129
+ _el$6 = _el$4.nextSibling,
130
+ [_el$7, _co$] = _$getNextMarker(_el$6.nextSibling);
131
+ var _ref$ = video;
132
+ typeof _ref$ === "function" ? _$use(_ref$, _el$3) : video = _el$3;
133
+ _$insert(_el$4, (() => {
134
+ var _c$ = _$memo(() => !!starting());
135
+ return () => _c$() ? messages().qrCameraStarting : props.instructions ?? messages().qrCameraInstructions;
136
+ })());
137
+ _$insert(_el$, _$createComponent(Show, {
138
+ get when() {
139
+ return !starting();
140
+ },
141
+ get children() {
142
+ var _el$5 = _$getNextElement(_tmpl$);
143
+ _$insert(_el$5, () => messages().qrCameraPrivacy);
144
+ return _el$5;
145
+ }
146
+ }), _el$7, _co$);
147
+ _$effect(_p$ => {
148
+ var _v$ = props.class ? `k2b-qr-scanner ${props.class}` : "k2b-qr-scanner",
149
+ _v$2 = invalid() || undefined,
150
+ _v$3 = messages().qrCameraPreview;
151
+ _v$ !== _p$.e && _$className(_el$, _p$.e = _v$);
152
+ _v$2 !== _p$.t && _$setAttribute(_el$2, "data-invalid", _p$.t = _v$2);
153
+ _v$3 !== _p$.a && _$setAttribute(_el$3, "aria-label", _p$.a = _v$3);
154
+ return _p$;
155
+ }, {
156
+ e: undefined,
157
+ t: undefined,
158
+ a: undefined
159
+ });
160
+ return _el$;
161
+ })();
162
+ }
163
+ export default QrScanner;
164
+ //# 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;IAAA;MAAA;MAAA;MAAA;MAAA;MAAA;IAAA,YAIkB,KAAK;IAAA,oDAAL,KAAK;IAAA;MAAA,yBAED,QAAQ,CAAC,CAAC;MAAA,aAAV,QAAa,QAAQ,CAAC,CAAC,CAAC,gBAAgB,GAAI,KAAK,CAAC,YAAY,IAAI,QAAQ,CAAC,CAAC,CAAC,oBAAqB;IAAA;IAAA,iCACnH,IAAI;MAAA,IAAC,IAAI;QAAA,OAAE,CAAC,QAAQ,CAAC,CAAC;MAAA;MAAA;QAAA;QAAA,sBACY,QAAQ,CAAC,CAAC,CAAC,eAAe;QAAA;MAAA;IAAA;IAAA;MAAA,UAPnD,KAAK,CAAC,KAAK,GAAG,kBAAkB,KAAK,CAAC,KAAK,EAAE,GAAG,gBAAgB;QAAA,OACvB,OAAO,CAAC,CAAC,IAAI,SAAS;QAAA,OAEtB,QAAQ,CAAC,CAAC,CAAC,eAAe;MAAA;MAAA;MAAA;MAAA;IAAA;MAAA;MAAA;MAAA;IAAA;IAAA;EAAA;AAQnF;AAEA,eAAe,SAAS","ignoreList":[]}
@@ -21,19 +21,30 @@ var _tmpl$ = /*#__PURE__*/_$template(`<button type=button class="k2b-choice-cont
21
21
  _tmpl$4 = /*#__PURE__*/_$template(`<div class=k2b-choice-toolbar><!$><!/><!$><!/>`),
22
22
  _tmpl$5 = /*#__PURE__*/_$template(`<div class=k2b-choice-status><i class="ti ti-loader-2 k2b-spin"aria-hidden=true></i><span>`),
23
23
  _tmpl$6 = /*#__PURE__*/_$template(`<div class=k2b-choice-control><button type=button class=k2b-choice-trigger role=combobox aria-haspopup=listbox><!$><!/><span class=k2b-choice-trigger__value></span><i aria-hidden=true></i></button><!$><!/><!$><!/><div popover=manual class=k2b-choice-popover role=group><!$><!/><!$><!/><div class=k2b-choice-options role=listbox><!$><!/><!$><!/><!$><!/>`),
24
- _tmpl$7 = /*#__PURE__*/_$template(`<i aria-hidden=true>`),
25
- _tmpl$8 = /*#__PURE__*/_$template(`<span class=k2b-choice-dot aria-hidden=true>`),
26
- _tmpl$9 = /*#__PURE__*/_$template(`<input type=hidden>`),
27
- _tmpl$0 = /*#__PURE__*/_$template(`<div class=k2b-choice-status data-tone=danger><span></span><button type=button>`),
28
- _tmpl$1 = /*#__PURE__*/_$template(`<div class=k2b-choice-status>`),
29
- _tmpl$10 = /*#__PURE__*/_$template(`<button type=button class=k2b-choice-option role=option><!$><!/><span><strong></strong><!$><!/>`),
30
- _tmpl$11 = /*#__PURE__*/_$template(`<small>`);
24
+ _tmpl$7 = /*#__PURE__*/_$template(`<span class=k2b-choice-dot data-empty=true aria-hidden=true>`),
25
+ _tmpl$8 = /*#__PURE__*/_$template(`<i aria-hidden=true>`),
26
+ _tmpl$9 = /*#__PURE__*/_$template(`<span class=k2b-choice-dot aria-hidden=true>`),
27
+ _tmpl$0 = /*#__PURE__*/_$template(`<input type=hidden>`),
28
+ _tmpl$1 = /*#__PURE__*/_$template(`<div class=k2b-choice-status data-tone=danger><span></span><button type=button>`),
29
+ _tmpl$10 = /*#__PURE__*/_$template(`<div class=k2b-choice-status>`),
30
+ _tmpl$11 = /*#__PURE__*/_$template(`<button type=button class=k2b-choice-option role=option><!$><!/><span><strong></strong><!$><!/>`),
31
+ _tmpl$12 = /*#__PURE__*/_$template(`<small>`);
31
32
  import { createMemo, createSignal, For, Show } from "solid-js";
32
33
  import { createFieldMeta, Field, fieldControlAria } from "../internal/field";
33
34
  import { useUiMessages } from "../intl/messages";
34
35
  import { ChoiceGroups } from "./ChoiceGroups";
35
36
  import { createChoiceLoader, createChoicePopover, filterChoiceOptions, nextEnabledChoiceIndex } from "./choice";
36
37
  import { commitFieldValue, resolveMaybeAccessor } from "./field-contract";
38
+
39
+ /**
40
+ * `field` draws the boxed form control. `plain` shows the value as text for
41
+ * property rows: no box, no chevron, and a quiet surface on hover or while
42
+ * open. Its surface and hit area cover the nearest positioned ancestor, such as
43
+ * a `DescriptionList` row, so the whole row opens the picker.
44
+ */
45
+
46
+ /** The list entry that clears a plain select. It cannot collide with a real option value. */
47
+ const CLEAR_VALUE = "\u0000k2b-select-clear";
37
48
  const normalize = option => typeof option === "string" ? {
38
49
  value: option,
39
50
  label: option
@@ -75,6 +86,19 @@ export function Select(props) {
75
86
  // Remote loaders filter server-side; a static list has to be filtered here or
76
87
  // the search field would render but do nothing.
77
88
  const options = createMemo(() => isAsync() || !props.searchable ? groupedOptions() : props.filterOptions ? [...props.filterOptions(groupedOptions(), query())] : filterChoiceOptions(groupedOptions(), query()));
89
+ const plain = () => props.appearance === "plain";
90
+ // A plain select has no room for a clear button beside its value, so
91
+ // clearing becomes the last list entry, named by the placeholder.
92
+ const clearOption = createMemo(() => plain() && props.clearable && !query() ? {
93
+ value: CLEAR_VALUE,
94
+ label: props.placeholder ?? messages().clearSelection
95
+ } : undefined);
96
+ const listOptions = createMemo(() => {
97
+ const clear = clearOption();
98
+ return clear && !loader.error() ? [...options(), clear] : options();
99
+ });
100
+ // Colour dots mark the options, so an empty plain value keeps the column with a hollow dot.
101
+ const emptyDot = () => plain() && !props.placeholderIcon && sourceOptions().some(option => option.color);
78
102
  const selected = createMemo(() => {
79
103
  const current = value();
80
104
  if (current === null) return undefined;
@@ -85,29 +109,29 @@ export function Select(props) {
85
109
  label: props.selectedLabel?.() ?? current
86
110
  };
87
111
  });
88
- const hasClearAction = () => Boolean(props.clearable && selected() && !props.disabled);
112
+ const hasClearAction = () => Boolean(props.clearable && selected() && !props.disabled && !plain());
89
113
  const accessibleLabel = () => props["aria-label"] ?? (typeof props.label === "string" ? undefined : props.placeholder ?? messages().selectOption);
90
114
  const popover = createChoicePopover(() => Boolean(props.disabled));
91
- const focusedOption = () => options()[focusedIndex()];
115
+ const focusedOption = () => listOptions()[focusedIndex()];
92
116
  const focus = index => {
93
117
  setFocusedIndex(index);
94
118
  optionRefs[index]?.scrollIntoView({
95
119
  block: "nearest"
96
120
  });
97
121
  };
98
- const move = direction => focus(nextEnabledChoiceIndex(options(), focusedIndex(), direction));
122
+ const move = direction => focus(nextEnabledChoiceIndex(listOptions(), focusedIndex(), direction));
99
123
  const chooseGroup = group => {
100
124
  if (group === activeGroup()) return;
101
125
  setSelectedGroup(group);
102
- setFocusedIndex(nextEnabledChoiceIndex(options(), -1, 1));
126
+ setFocusedIndex(nextEnabledChoiceIndex(listOptions(), -1, 1));
103
127
  if (isAsync()) loader.load(query(), true);
104
128
  };
105
129
  const open = () => {
106
130
  if (props.disabled) return;
107
131
  setQuery("");
108
132
  if (isAsync()) loader.load("", true);
109
- const selectedIndex = options().findIndex(option => option.value === value());
110
- focus(selectedIndex >= 0 ? selectedIndex : nextEnabledChoiceIndex(options(), -1, 1));
133
+ const selectedIndex = listOptions().findIndex(option => option.value === (value() ?? CLEAR_VALUE));
134
+ focus(selectedIndex >= 0 ? selectedIndex : nextEnabledChoiceIndex(listOptions(), -1, 1));
111
135
  popover.show();
112
136
  if (isSearchable()) queueMicrotask(() => searchRef?.focus());
113
137
  };
@@ -123,6 +147,10 @@ export function Select(props) {
123
147
  const select = option => {
124
148
  if (option.disabled) return;
125
149
  close(true);
150
+ if (option.value === CLEAR_VALUE) {
151
+ commitFieldValue(props, null);
152
+ return;
153
+ }
126
154
  setCache({
127
155
  ...cache(),
128
156
  [option.value]: option
@@ -224,25 +252,54 @@ export function Select(props) {
224
252
  }), false, true);
225
253
  _$insert(_el$2, _$createComponent(Show, {
226
254
  get when() {
227
- return selected()?.color;
255
+ return selected();
228
256
  },
229
257
  get fallback() {
230
258
  return _$createComponent(Show, {
231
259
  get when() {
232
- return selected()?.icon;
260
+ return props.placeholderIcon;
261
+ },
262
+ get fallback() {
263
+ return _$createComponent(Show, {
264
+ get when() {
265
+ return emptyDot();
266
+ },
267
+ get children() {
268
+ return _$getNextElement(_tmpl$7);
269
+ }
270
+ });
233
271
  },
234
272
  children: icon => (() => {
235
- var _el$35 = _$getNextElement(_tmpl$7);
236
- _$effect(() => _$className(_el$35, icon()));
237
- return _el$35;
273
+ var _el$36 = _$getNextElement(_tmpl$8);
274
+ _$effect(() => _$className(_el$36, `${icon()} k2b-choice-trigger__placeholder-icon`));
275
+ return _el$36;
238
276
  })()
239
277
  });
240
278
  },
241
- children: color => (() => {
242
- var _el$36 = _$getNextElement(_tmpl$8);
243
- _$effect(_$p => _$setStyleProperty(_el$36, "background-color", color()));
244
- return _el$36;
245
- })()
279
+ get children() {
280
+ return _$createComponent(Show, {
281
+ get when() {
282
+ return selected()?.color;
283
+ },
284
+ get fallback() {
285
+ return _$createComponent(Show, {
286
+ get when() {
287
+ return selected()?.icon;
288
+ },
289
+ children: icon => (() => {
290
+ var _el$37 = _$getNextElement(_tmpl$8);
291
+ _$effect(() => _$className(_el$37, icon()));
292
+ return _el$37;
293
+ })()
294
+ });
295
+ },
296
+ children: color => (() => {
297
+ var _el$38 = _$getNextElement(_tmpl$9);
298
+ _$effect(_$p => _$setStyleProperty(_el$38, "background-color", color()));
299
+ return _el$38;
300
+ })()
301
+ });
302
+ }
246
303
  }), _el$6, _co$);
247
304
  _$insert(_el$3, () => selected()?.label ?? props.placeholder ?? messages().select);
248
305
  _$insert(_el$, _$createComponent(Show, {
@@ -250,10 +307,10 @@ export function Select(props) {
250
307
  return props.name;
251
308
  },
252
309
  children: name => (() => {
253
- var _el$37 = _$getNextElement(_tmpl$9);
254
- _$effect(() => _$setAttribute(_el$37, "name", name()));
255
- _$effect(() => _$setProperty(_el$37, "value", value() ?? ""));
256
- return _el$37;
310
+ var _el$39 = _$getNextElement(_tmpl$0);
311
+ _$effect(() => _$setAttribute(_el$39, "name", name()));
312
+ _$effect(() => _$setProperty(_el$39, "value", value() ?? ""));
313
+ return _el$39;
257
314
  })()
258
315
  }), _el$32, _co$9);
259
316
  _$insert(_el$, _$createComponent(Show, {
@@ -367,14 +424,14 @@ export function Select(props) {
367
424
  return loader.error();
368
425
  },
369
426
  children: message => (() => {
370
- var _el$38 = _$getNextElement(_tmpl$0),
371
- _el$39 = _el$38.firstChild,
372
- _el$40 = _el$39.nextSibling;
373
- _$insert(_el$39, message);
374
- _$addEventListener(_el$40, "click", loader.retry, true);
375
- _$insert(_el$40, () => messages().retry);
427
+ var _el$40 = _$getNextElement(_tmpl$1),
428
+ _el$41 = _el$40.firstChild,
429
+ _el$42 = _el$41.nextSibling;
430
+ _$insert(_el$41, message);
431
+ _$addEventListener(_el$42, "click", loader.retry, true);
432
+ _$insert(_el$42, () => messages().retry);
376
433
  _$runHydrationEvents();
377
- return _el$38;
434
+ return _el$40;
378
435
  })()
379
436
  }), _el$22, _co$4);
380
437
  _$insert(_el$17, _$createComponent(Show, {
@@ -391,7 +448,7 @@ export function Select(props) {
391
448
  }), _el$24, _co$5);
392
449
  _$insert(_el$17, _$createComponent(For, {
393
450
  get each() {
394
- return _$memo(() => !!loader.error())() ? [] : options();
451
+ return _$memo(() => !!loader.error())() ? [] : listOptions();
395
452
  },
396
453
  get fallback() {
397
454
  return _$createComponent(Show, {
@@ -399,95 +456,129 @@ export function Select(props) {
399
456
  return _$memo(() => !!!loader.loading())() && !loader.error();
400
457
  },
401
458
  get children() {
402
- var _el$41 = _$getNextElement(_tmpl$1);
403
- _$insert(_el$41, (() => {
459
+ var _el$43 = _$getNextElement(_tmpl$10);
460
+ _$insert(_el$43, (() => {
404
461
  var _c$ = _$memo(() => !!isSearchable());
405
462
  return () => _c$() ? messages().noResults : messages().noOptions;
406
463
  })());
407
- return _el$41;
464
+ return _el$43;
408
465
  }
409
466
  });
410
467
  },
411
468
  children: (option, index) => (() => {
412
- var _el$42 = _$getNextElement(_tmpl$10),
413
- _el$47 = _el$42.firstChild,
414
- [_el$48, _co$10] = _$getNextMarker(_el$47.nextSibling),
415
- _el$43 = _el$48.nextSibling,
416
- _el$44 = _el$43.firstChild,
417
- _el$45 = _el$44.nextSibling,
418
- [_el$46, _co$1] = _$getNextMarker(_el$45.nextSibling);
419
- _el$42.$$click = () => select(option);
420
- _el$42.$$pointermove = () => focus(index());
421
- _$use(element => optionRefs[index()] = element, _el$42);
422
- _$insert(_el$42, _$createComponent(Show, {
469
+ var _el$44 = _$getNextElement(_tmpl$11),
470
+ _el$49 = _el$44.firstChild,
471
+ [_el$50, _co$10] = _$getNextMarker(_el$49.nextSibling),
472
+ _el$45 = _el$50.nextSibling,
473
+ _el$46 = _el$45.firstChild,
474
+ _el$47 = _el$46.nextSibling,
475
+ [_el$48, _co$1] = _$getNextMarker(_el$47.nextSibling);
476
+ _el$44.$$click = () => select(option);
477
+ _el$44.$$pointermove = () => focus(index());
478
+ _$use(element => optionRefs[index()] = element, _el$44);
479
+ _$insert(_el$44, _$createComponent(Show, {
423
480
  get when() {
424
- return option.color;
481
+ return option.value === CLEAR_VALUE;
425
482
  },
426
483
  get fallback() {
427
484
  return _$createComponent(Show, {
428
485
  get when() {
429
- return option.icon;
486
+ return option.color;
430
487
  },
431
- children: icon => (() => {
432
- var _el$49 = _$getNextElement(_tmpl$7);
433
- _$effect(() => _$className(_el$49, icon()));
434
- return _el$49;
488
+ get fallback() {
489
+ return _$createComponent(Show, {
490
+ get when() {
491
+ return option.icon;
492
+ },
493
+ children: icon => (() => {
494
+ var _el$51 = _$getNextElement(_tmpl$8);
495
+ _$effect(() => _$className(_el$51, icon()));
496
+ return _el$51;
497
+ })()
498
+ });
499
+ },
500
+ children: color => (() => {
501
+ var _el$52 = _$getNextElement(_tmpl$9);
502
+ _$effect(_$p => _$setStyleProperty(_el$52, "background-color", color()));
503
+ return _el$52;
435
504
  })()
436
505
  });
437
506
  },
438
- children: color => (() => {
439
- var _el$50 = _$getNextElement(_tmpl$8);
440
- _$effect(_$p => _$setStyleProperty(_el$50, "background-color", color()));
441
- return _el$50;
442
- })()
443
- }), _el$48, _co$10);
444
- _$insert(_el$44, () => option.label);
445
- _$insert(_el$43, _$createComponent(Show, {
507
+ get children() {
508
+ return _$createComponent(Show, {
509
+ get when() {
510
+ return props.placeholderIcon;
511
+ },
512
+ get fallback() {
513
+ return _$createComponent(Show, {
514
+ get when() {
515
+ return emptyDot();
516
+ },
517
+ get children() {
518
+ return _$getNextElement(_tmpl$7);
519
+ }
520
+ });
521
+ },
522
+ children: icon => (() => {
523
+ var _el$54 = _$getNextElement(_tmpl$8);
524
+ _$effect(() => _$className(_el$54, icon()));
525
+ return _el$54;
526
+ })()
527
+ });
528
+ }
529
+ }), _el$50, _co$10);
530
+ _$insert(_el$46, () => option.label);
531
+ _$insert(_el$45, _$createComponent(Show, {
446
532
  get when() {
447
533
  return option.description;
448
534
  },
449
535
  children: description => (() => {
450
- var _el$51 = _$getNextElement(_tmpl$11);
451
- _$insert(_el$51, description);
452
- return _el$51;
536
+ var _el$55 = _$getNextElement(_tmpl$12);
537
+ _$insert(_el$55, description);
538
+ return _el$55;
453
539
  })()
454
- }), _el$46, _co$1);
540
+ }), _el$48, _co$1);
455
541
  _$effect(_p$ => {
456
- var _v$10 = `${listboxId}-${index()}`,
457
- _v$11 = option.label,
458
- _v$12 = option.value === value(),
459
- _v$13 = index() === focusedIndex() ? "true" : undefined,
460
- _v$14 = option.disabled;
461
- _v$10 !== _p$.e && _$setAttribute(_el$42, "id", _p$.e = _v$10);
462
- _v$11 !== _p$.t && _$setAttribute(_el$42, "aria-label", _p$.t = _v$11);
463
- _v$12 !== _p$.a && _$setAttribute(_el$42, "aria-selected", _p$.a = _v$12);
464
- _v$13 !== _p$.o && _$setAttribute(_el$42, "data-focused", _p$.o = _v$13);
465
- _v$14 !== _p$.i && _$setProperty(_el$42, "disabled", _p$.i = _v$14);
542
+ var _v$11 = `${listboxId}-${index()}`,
543
+ _v$12 = option.label,
544
+ _v$13 = option.value === (value() ?? CLEAR_VALUE),
545
+ _v$14 = index() === focusedIndex() ? "true" : undefined,
546
+ _v$15 = option.value === CLEAR_VALUE ? "true" : undefined,
547
+ _v$16 = option.disabled;
548
+ _v$11 !== _p$.e && _$setAttribute(_el$44, "id", _p$.e = _v$11);
549
+ _v$12 !== _p$.t && _$setAttribute(_el$44, "aria-label", _p$.t = _v$12);
550
+ _v$13 !== _p$.a && _$setAttribute(_el$44, "aria-selected", _p$.a = _v$13);
551
+ _v$14 !== _p$.o && _$setAttribute(_el$44, "data-focused", _p$.o = _v$14);
552
+ _v$15 !== _p$.i && _$setAttribute(_el$44, "data-clear", _p$.i = _v$15);
553
+ _v$16 !== _p$.n && _$setProperty(_el$44, "disabled", _p$.n = _v$16);
466
554
  return _p$;
467
555
  }, {
468
556
  e: undefined,
469
557
  t: undefined,
470
558
  a: undefined,
471
559
  o: undefined,
472
- i: undefined
560
+ i: undefined,
561
+ n: undefined
473
562
  });
474
563
  _$runHydrationEvents();
475
- return _el$42;
564
+ return _el$44;
476
565
  })()
477
566
  }), _el$26, _co$6);
478
567
  _$effect(_p$ => {
479
- var _v$6 = error() ? "true" : undefined,
480
- _v$7 = selected() ? undefined : "true",
481
- _v$8 = popover.open() ? props.activeIcon ?? "ti ti-chevron-up" : props.icon ?? "ti ti-chevron-down",
482
- _v$9 = typeof props.label === "string" ? props.label : props["aria-label"] ?? messages().options,
483
- _v$0 = activeView(),
484
- _v$1 = activeView() === "grid" ? props.gridSize ?? "md" : undefined;
485
- _v$6 !== _p$.e && _$setAttribute(_el$, "data-invalid", _p$.e = _v$6);
486
- _v$7 !== _p$.t && _$setAttribute(_el$3, "data-placeholder", _p$.t = _v$7);
487
- _v$8 !== _p$.a && _$className(_el$4, _p$.a = _v$8);
488
- _v$9 !== _p$.o && _$setAttribute(_el$8, "aria-label", _p$.o = _v$9);
489
- _v$0 !== _p$.i && _$setAttribute(_el$17, "data-view", _p$.i = _v$0);
490
- _v$1 !== _p$.n && _$setAttribute(_el$17, "data-grid-size", _p$.n = _v$1);
568
+ var _v$6 = props.appearance ?? "field",
569
+ _v$7 = error() ? "true" : undefined,
570
+ _v$8 = selected() ? undefined : "true",
571
+ _v$9 = `${popover.open() ? props.activeIcon ?? "ti ti-chevron-up" : props.icon ?? "ti ti-chevron-down"} k2b-choice-trigger__chevron`,
572
+ _v$0 = typeof props.label === "string" ? props.label : props["aria-label"] ?? messages().options,
573
+ _v$1 = activeView(),
574
+ _v$10 = activeView() === "grid" ? props.gridSize ?? "md" : undefined;
575
+ _v$6 !== _p$.e && _$setAttribute(_el$, "data-appearance", _p$.e = _v$6);
576
+ _v$7 !== _p$.t && _$setAttribute(_el$, "data-invalid", _p$.t = _v$7);
577
+ _v$8 !== _p$.a && _$setAttribute(_el$3, "data-placeholder", _p$.a = _v$8);
578
+ _v$9 !== _p$.o && _$className(_el$4, _p$.o = _v$9);
579
+ _v$0 !== _p$.i && _$setAttribute(_el$8, "aria-label", _p$.i = _v$0);
580
+ _v$1 !== _p$.n && _$setAttribute(_el$17, "data-view", _p$.n = _v$1);
581
+ _v$10 !== _p$.s && _$setAttribute(_el$17, "data-grid-size", _p$.s = _v$10);
491
582
  return _p$;
492
583
  }, {
493
584
  e: undefined,
@@ -495,7 +586,8 @@ export function Select(props) {
495
586
  a: undefined,
496
587
  o: undefined,
497
588
  i: undefined,
498
- n: undefined
589
+ n: undefined,
590
+ s: undefined
499
591
  });
500
592
  _$runHydrationEvents();
501
593
  return _el$;