@k2b/ui 0.33.0 → 0.35.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 (310) hide show
  1. package/dist/base.css +14 -1
  2. package/dist/browser/actions/ContextMenu.js +13 -0
  3. package/dist/browser/actions/ContextMenu.js.map +1 -1
  4. package/dist/browser/actions/Dropdown.js +16 -4
  5. package/dist/browser/actions/Dropdown.js.map +1 -1
  6. package/dist/browser/actions/SelectionToolbar.js +129 -0
  7. package/dist/browser/actions/SelectionToolbar.js.map +1 -0
  8. package/dist/browser/actions/index.js +1 -0
  9. package/dist/browser/actions/index.js.map +1 -1
  10. package/dist/browser/charts.js +6 -0
  11. package/dist/browser/charts.js.map +1 -0
  12. package/dist/browser/chat/ChatComposer.js +525 -407
  13. package/dist/browser/chat/ChatComposer.js.map +1 -1
  14. package/dist/browser/chat/chat-messages.js +4 -0
  15. package/dist/browser/chat/chat-messages.js.map +1 -1
  16. package/dist/browser/chat/composer-document.js +19 -0
  17. package/dist/browser/chat/composer-document.js.map +1 -1
  18. package/dist/browser/chat/index.js.map +1 -1
  19. package/dist/browser/content/Chart.js +8 -0
  20. package/dist/browser/content/Chart.js.map +1 -1
  21. package/dist/browser/content/FileGrid.js +231 -9
  22. package/dist/browser/content/FileGrid.js.map +1 -1
  23. package/dist/browser/content/FileTypeIcon.js +15 -0
  24. package/dist/browser/content/FileTypeIcon.js.map +1 -1
  25. package/dist/browser/content/FileView.js +11 -4
  26. package/dist/browser/content/FileView.js.map +1 -1
  27. package/dist/browser/content/MatchText.js +61 -0
  28. package/dist/browser/content/MatchText.js.map +1 -0
  29. package/dist/browser/content/MessageRow.js +73 -53
  30. package/dist/browser/content/MessageRow.js.map +1 -1
  31. package/dist/browser/content/ReactionBar.js +3 -1
  32. package/dist/browser/content/ReactionBar.js.map +1 -1
  33. package/dist/browser/content/calendar-day-scroll.js +4 -3
  34. package/dist/browser/content/calendar-day-scroll.js.map +1 -1
  35. package/dist/browser/content/chart-bar.js +476 -0
  36. package/dist/browser/content/chart-bar.js.map +1 -0
  37. package/dist/browser/content/file-list-messages.js +52 -0
  38. package/dist/browser/content/file-list-messages.js.map +1 -0
  39. package/dist/browser/content/index.js +2 -1
  40. package/dist/browser/content/index.js.map +1 -1
  41. package/dist/browser/feedback/Tooltip.js +31 -14
  42. package/dist/browser/feedback/Tooltip.js.map +1 -1
  43. package/dist/browser/inputs/ChoiceList.js +178 -0
  44. package/dist/browser/inputs/ChoiceList.js.map +1 -0
  45. package/dist/browser/inputs/ChoiceSlider.js +314 -0
  46. package/dist/browser/inputs/ChoiceSlider.js.map +1 -0
  47. package/dist/browser/inputs/ChoiceTiles.js +135 -0
  48. package/dist/browser/inputs/ChoiceTiles.js.map +1 -0
  49. package/dist/browser/inputs/ColorChoices.js +120 -0
  50. package/dist/browser/inputs/ColorChoices.js.map +1 -0
  51. package/dist/browser/inputs/QrScanner.js +95 -13
  52. package/dist/browser/inputs/QrScanner.js.map +1 -1
  53. package/dist/browser/inputs/TextInput.js +15 -13
  54. package/dist/browser/inputs/TextInput.js.map +1 -1
  55. package/dist/browser/inputs/index.js +4 -0
  56. package/dist/browser/inputs/index.js.map +1 -1
  57. package/dist/browser/inputs/qr-messages.js +2 -0
  58. package/dist/browser/inputs/qr-messages.js.map +1 -1
  59. package/dist/browser/internal/radio-keys.js +13 -0
  60. package/dist/browser/internal/radio-keys.js.map +1 -0
  61. package/dist/browser/layout/AnchoredPopover.js +180 -0
  62. package/dist/browser/layout/AnchoredPopover.js.map +1 -0
  63. package/dist/browser/layout/AppWorkspace.js +155 -20
  64. package/dist/browser/layout/AppWorkspace.js.map +1 -1
  65. package/dist/browser/layout/DetailPanel.js +443 -333
  66. package/dist/browser/layout/DetailPanel.js.map +1 -1
  67. package/dist/browser/layout/MobileShell.js +21 -7
  68. package/dist/browser/layout/MobileShell.js.map +1 -1
  69. package/dist/browser/layout/Settings.js +283 -175
  70. package/dist/browser/layout/Settings.js.map +1 -1
  71. package/dist/browser/layout/SidebarRailHint.js +79 -0
  72. package/dist/browser/layout/SidebarRailHint.js.map +1 -0
  73. package/dist/browser/layout/SidebarSwitcher.js +79 -66
  74. package/dist/browser/layout/SidebarSwitcher.js.map +1 -1
  75. package/dist/browser/layout/TabBar.js +18 -4
  76. package/dist/browser/layout/TabBar.js.map +1 -1
  77. package/dist/browser/layout/app-workspace-controller.js +11 -4
  78. package/dist/browser/layout/app-workspace-controller.js.map +1 -1
  79. package/dist/browser/layout/detail-panel-messages.js +4 -2
  80. package/dist/browser/layout/detail-panel-messages.js.map +1 -1
  81. package/dist/browser/layout/index.js +2 -1
  82. package/dist/browser/layout/index.js.map +1 -1
  83. package/dist/browser/layout/settings-messages.js +26 -2
  84. package/dist/browser/layout/settings-messages.js.map +1 -1
  85. package/dist/browser/surfaces/Avatar.js +2 -14
  86. package/dist/browser/surfaces/Avatar.js.map +1 -1
  87. package/dist/browser/surfaces/DotStrip.js +70 -0
  88. package/dist/browser/surfaces/DotStrip.js.map +1 -0
  89. package/dist/browser/surfaces/ProgressRing.js +3 -0
  90. package/dist/browser/surfaces/ProgressRing.js.map +1 -1
  91. package/dist/browser/surfaces/ResourceCard.js +125 -68
  92. package/dist/browser/surfaces/ResourceCard.js.map +1 -1
  93. package/dist/browser/surfaces/index.js +2 -0
  94. package/dist/browser/surfaces/index.js.map +1 -1
  95. package/dist/browser/surfaces/person-color.js +18 -0
  96. package/dist/browser/surfaces/person-color.js.map +1 -0
  97. package/dist/browser/surfaces/resource-messages.js +6 -2
  98. package/dist/browser/surfaces/resource-messages.js.map +1 -1
  99. package/dist/browser/text-editor/TextEditor.js +1358 -0
  100. package/dist/browser/text-editor/TextEditor.js.map +1 -0
  101. package/dist/browser/text-editor/clipboard-html.js +152 -0
  102. package/dist/browser/text-editor/clipboard-html.js.map +1 -0
  103. package/dist/browser/text-editor/clipboard-loading.js +68 -0
  104. package/dist/browser/text-editor/clipboard-loading.js.map +1 -0
  105. package/dist/browser/text-editor/clipboard.js +51 -0
  106. package/dist/browser/text-editor/clipboard.js.map +1 -0
  107. package/dist/browser/text-editor/engine.js +125 -0
  108. package/dist/browser/text-editor/engine.js.map +1 -0
  109. package/dist/browser/text-editor/format.js +218 -0
  110. package/dist/browser/text-editor/format.js.map +1 -0
  111. package/dist/browser/text-editor/formatted.js +164 -0
  112. package/dist/browser/text-editor/formatted.js.map +1 -0
  113. package/dist/browser/text-editor/language.js +19 -0
  114. package/dist/browser/text-editor/language.js.map +1 -0
  115. package/dist/browser/text-editor/markdown-table.js +563 -0
  116. package/dist/browser/text-editor/markdown-table.js.map +1 -0
  117. package/dist/browser/text-editor/messages.js +233 -0
  118. package/dist/browser/text-editor/messages.js.map +1 -0
  119. package/dist/browser/text-editor/paste.js +115 -0
  120. package/dist/browser/text-editor/paste.js.map +1 -0
  121. package/dist/browser/text-editor/table.js +1760 -0
  122. package/dist/browser/text-editor/table.js.map +1 -0
  123. package/dist/browser/text-editor.js +5 -0
  124. package/dist/browser/text-editor.js.map +1 -0
  125. package/dist/browser/widgets/Widget.js +3 -2
  126. package/dist/browser/widgets/Widget.js.map +1 -1
  127. package/dist/ssr/actions/ContextMenu.js +9 -0
  128. package/dist/ssr/actions/ContextMenu.js.map +1 -1
  129. package/dist/ssr/actions/Dropdown.js +15 -4
  130. package/dist/ssr/actions/Dropdown.js.map +1 -1
  131. package/dist/ssr/actions/SelectionToolbar.js +104 -0
  132. package/dist/ssr/actions/SelectionToolbar.js.map +1 -0
  133. package/dist/ssr/actions/index.js +1 -0
  134. package/dist/ssr/actions/index.js.map +1 -1
  135. package/dist/ssr/charts.js +6 -0
  136. package/dist/ssr/charts.js.map +1 -0
  137. package/dist/ssr/chat/ChatComposer.js +132 -53
  138. package/dist/ssr/chat/ChatComposer.js.map +1 -1
  139. package/dist/ssr/chat/chat-messages.js +4 -0
  140. package/dist/ssr/chat/chat-messages.js.map +1 -1
  141. package/dist/ssr/chat/composer-document.js +19 -0
  142. package/dist/ssr/chat/composer-document.js.map +1 -1
  143. package/dist/ssr/chat/index.js.map +1 -1
  144. package/dist/ssr/content/Chart.js +8 -0
  145. package/dist/ssr/content/Chart.js.map +1 -1
  146. package/dist/ssr/content/FileGrid.js +132 -5
  147. package/dist/ssr/content/FileGrid.js.map +1 -1
  148. package/dist/ssr/content/FileTypeIcon.js +15 -0
  149. package/dist/ssr/content/FileTypeIcon.js.map +1 -1
  150. package/dist/ssr/content/FileView.js +11 -4
  151. package/dist/ssr/content/FileView.js.map +1 -1
  152. package/dist/ssr/content/MatchText.js +56 -0
  153. package/dist/ssr/content/MatchText.js.map +1 -0
  154. package/dist/ssr/content/MessageRow.js +16 -6
  155. package/dist/ssr/content/MessageRow.js.map +1 -1
  156. package/dist/ssr/content/ReactionBar.js +3 -1
  157. package/dist/ssr/content/ReactionBar.js.map +1 -1
  158. package/dist/ssr/content/calendar-day-scroll.js +4 -3
  159. package/dist/ssr/content/calendar-day-scroll.js.map +1 -1
  160. package/dist/ssr/content/chart-bar.js +476 -0
  161. package/dist/ssr/content/chart-bar.js.map +1 -0
  162. package/dist/ssr/content/file-list-messages.js +52 -0
  163. package/dist/ssr/content/file-list-messages.js.map +1 -0
  164. package/dist/ssr/content/index.js +2 -1
  165. package/dist/ssr/content/index.js.map +1 -1
  166. package/dist/ssr/feedback/Tooltip.js +31 -14
  167. package/dist/ssr/feedback/Tooltip.js.map +1 -1
  168. package/dist/ssr/inputs/ChoiceList.js +95 -0
  169. package/dist/ssr/inputs/ChoiceList.js.map +1 -0
  170. package/dist/ssr/inputs/ChoiceSlider.js +191 -0
  171. package/dist/ssr/inputs/ChoiceSlider.js.map +1 -0
  172. package/dist/ssr/inputs/ChoiceTiles.js +61 -0
  173. package/dist/ssr/inputs/ChoiceTiles.js.map +1 -0
  174. package/dist/ssr/inputs/ColorChoices.js +60 -0
  175. package/dist/ssr/inputs/ColorChoices.js.map +1 -0
  176. package/dist/ssr/inputs/QrScanner.js +89 -10
  177. package/dist/ssr/inputs/QrScanner.js.map +1 -1
  178. package/dist/ssr/inputs/TextInput.js +13 -1
  179. package/dist/ssr/inputs/TextInput.js.map +1 -1
  180. package/dist/ssr/inputs/index.js +4 -0
  181. package/dist/ssr/inputs/index.js.map +1 -1
  182. package/dist/ssr/inputs/qr-messages.js +2 -0
  183. package/dist/ssr/inputs/qr-messages.js.map +1 -1
  184. package/dist/ssr/internal/radio-keys.js +13 -0
  185. package/dist/ssr/internal/radio-keys.js.map +1 -0
  186. package/dist/ssr/layout/AnchoredPopover.js +142 -0
  187. package/dist/ssr/layout/AnchoredPopover.js.map +1 -0
  188. package/dist/ssr/layout/AppWorkspace.js +154 -20
  189. package/dist/ssr/layout/AppWorkspace.js.map +1 -1
  190. package/dist/ssr/layout/DetailPanel.js +181 -108
  191. package/dist/ssr/layout/DetailPanel.js.map +1 -1
  192. package/dist/ssr/layout/MobileShell.js +20 -6
  193. package/dist/ssr/layout/MobileShell.js.map +1 -1
  194. package/dist/ssr/layout/Settings.js +122 -45
  195. package/dist/ssr/layout/Settings.js.map +1 -1
  196. package/dist/ssr/layout/SidebarRailHint.js +79 -0
  197. package/dist/ssr/layout/SidebarRailHint.js.map +1 -0
  198. package/dist/ssr/layout/SidebarSwitcher.js +13 -3
  199. package/dist/ssr/layout/SidebarSwitcher.js.map +1 -1
  200. package/dist/ssr/layout/TabBar.js +11 -3
  201. package/dist/ssr/layout/TabBar.js.map +1 -1
  202. package/dist/ssr/layout/app-workspace-controller.js +11 -4
  203. package/dist/ssr/layout/app-workspace-controller.js.map +1 -1
  204. package/dist/ssr/layout/detail-panel-messages.js +4 -2
  205. package/dist/ssr/layout/detail-panel-messages.js.map +1 -1
  206. package/dist/ssr/layout/index.js +2 -1
  207. package/dist/ssr/layout/index.js.map +1 -1
  208. package/dist/ssr/layout/settings-messages.js +26 -2
  209. package/dist/ssr/layout/settings-messages.js.map +1 -1
  210. package/dist/ssr/surfaces/Avatar.js +2 -14
  211. package/dist/ssr/surfaces/Avatar.js.map +1 -1
  212. package/dist/ssr/surfaces/DotStrip.js +31 -0
  213. package/dist/ssr/surfaces/DotStrip.js.map +1 -0
  214. package/dist/ssr/surfaces/ProgressRing.js +3 -0
  215. package/dist/ssr/surfaces/ProgressRing.js.map +1 -1
  216. package/dist/ssr/surfaces/ResourceCard.js +40 -15
  217. package/dist/ssr/surfaces/ResourceCard.js.map +1 -1
  218. package/dist/ssr/surfaces/index.js +2 -0
  219. package/dist/ssr/surfaces/index.js.map +1 -1
  220. package/dist/ssr/surfaces/person-color.js +18 -0
  221. package/dist/ssr/surfaces/person-color.js.map +1 -0
  222. package/dist/ssr/surfaces/resource-messages.js +6 -2
  223. package/dist/ssr/surfaces/resource-messages.js.map +1 -1
  224. package/dist/ssr/text-editor/TextEditor.js +1155 -0
  225. package/dist/ssr/text-editor/TextEditor.js.map +1 -0
  226. package/dist/ssr/text-editor/clipboard-html.js +152 -0
  227. package/dist/ssr/text-editor/clipboard-html.js.map +1 -0
  228. package/dist/ssr/text-editor/clipboard-loading.js +68 -0
  229. package/dist/ssr/text-editor/clipboard-loading.js.map +1 -0
  230. package/dist/ssr/text-editor/clipboard.js +51 -0
  231. package/dist/ssr/text-editor/clipboard.js.map +1 -0
  232. package/dist/ssr/text-editor/engine.js +125 -0
  233. package/dist/ssr/text-editor/engine.js.map +1 -0
  234. package/dist/ssr/text-editor/format.js +218 -0
  235. package/dist/ssr/text-editor/format.js.map +1 -0
  236. package/dist/ssr/text-editor/formatted.js +164 -0
  237. package/dist/ssr/text-editor/formatted.js.map +1 -0
  238. package/dist/ssr/text-editor/language.js +19 -0
  239. package/dist/ssr/text-editor/language.js.map +1 -0
  240. package/dist/ssr/text-editor/markdown-table.js +563 -0
  241. package/dist/ssr/text-editor/markdown-table.js.map +1 -0
  242. package/dist/ssr/text-editor/messages.js +233 -0
  243. package/dist/ssr/text-editor/messages.js.map +1 -0
  244. package/dist/ssr/text-editor/paste.js +115 -0
  245. package/dist/ssr/text-editor/paste.js.map +1 -0
  246. package/dist/ssr/text-editor/table.js +1760 -0
  247. package/dist/ssr/text-editor/table.js.map +1 -0
  248. package/dist/ssr/text-editor.js +5 -0
  249. package/dist/ssr/text-editor.js.map +1 -0
  250. package/dist/ssr/widgets/Widget.js +3 -2
  251. package/dist/ssr/widgets/Widget.js.map +1 -1
  252. package/dist/styles.css +1 -1
  253. package/dist/types/actions/ContextMenu.d.ts +5 -0
  254. package/dist/types/actions/Dropdown.d.ts +7 -0
  255. package/dist/types/actions/SelectionToolbar.d.ts +38 -0
  256. package/dist/types/actions/index.d.ts +2 -0
  257. package/dist/types/charts.d.ts +5 -0
  258. package/dist/types/chat/ChatComposer.d.ts +15 -0
  259. package/dist/types/chat/chat-messages.d.ts +2 -0
  260. package/dist/types/chat/composer-document.d.ts +5 -0
  261. package/dist/types/chat/index.d.ts +1 -1
  262. package/dist/types/content/Chart.d.ts +2 -1
  263. package/dist/types/content/FileGrid.d.ts +43 -3
  264. package/dist/types/content/FileTypeIcon.d.ts +10 -0
  265. package/dist/types/content/FileView.d.ts +5 -1
  266. package/dist/types/content/MatchText.d.ts +21 -0
  267. package/dist/types/content/MessageRow.d.ts +2 -0
  268. package/dist/types/content/calendar-day-scroll.d.ts +2 -1
  269. package/dist/types/content/chart-bar.d.ts +60 -0
  270. package/dist/types/content/file-list-messages.d.ts +24 -0
  271. package/dist/types/content/index.d.ts +3 -2
  272. package/dist/types/feedback/Tooltip.d.ts +8 -2
  273. package/dist/types/inputs/ChoiceList.d.ts +28 -0
  274. package/dist/types/inputs/ChoiceSlider.d.ts +36 -0
  275. package/dist/types/inputs/ChoiceTiles.d.ts +25 -0
  276. package/dist/types/inputs/ColorChoices.d.ts +19 -0
  277. package/dist/types/inputs/index.d.ts +8 -0
  278. package/dist/types/inputs/qr-messages.d.ts +1 -0
  279. package/dist/types/internal/radio-keys.d.ts +5 -0
  280. package/dist/types/layout/AnchoredPopover.d.ts +31 -0
  281. package/dist/types/layout/AppWorkspace.d.ts +10 -0
  282. package/dist/types/layout/DetailPanel.d.ts +17 -0
  283. package/dist/types/layout/MobileShell.d.ts +5 -2
  284. package/dist/types/layout/Settings.d.ts +22 -0
  285. package/dist/types/layout/SidebarRailHint.d.ts +26 -0
  286. package/dist/types/layout/TabBar.d.ts +5 -0
  287. package/dist/types/layout/detail-panel-messages.d.ts +1 -0
  288. package/dist/types/layout/index.d.ts +3 -2
  289. package/dist/types/layout/settings-messages.d.ts +12 -0
  290. package/dist/types/surfaces/DotStrip.d.ts +22 -0
  291. package/dist/types/surfaces/ProgressRing.d.ts +2 -1
  292. package/dist/types/surfaces/ResourceCard.d.ts +9 -0
  293. package/dist/types/surfaces/index.d.ts +4 -1
  294. package/dist/types/surfaces/person-color.d.ts +10 -0
  295. package/dist/types/surfaces/resource-messages.d.ts +2 -0
  296. package/dist/types/text-editor/TextEditor.d.ts +69 -0
  297. package/dist/types/text-editor/clipboard-html.d.ts +9 -0
  298. package/dist/types/text-editor/clipboard-loading.d.ts +8 -0
  299. package/dist/types/text-editor/clipboard.d.ts +20 -0
  300. package/dist/types/text-editor/engine.d.ts +34 -0
  301. package/dist/types/text-editor/format.d.ts +34 -0
  302. package/dist/types/text-editor/formatted.d.ts +1 -0
  303. package/dist/types/text-editor/language.d.ts +8 -0
  304. package/dist/types/text-editor/markdown-table.d.ts +105 -0
  305. package/dist/types/text-editor/messages.d.ts +113 -0
  306. package/dist/types/text-editor/paste.d.ts +6 -0
  307. package/dist/types/text-editor/table.d.ts +81 -0
  308. package/dist/types/text-editor.d.ts +4 -0
  309. package/dist/types/widgets/Widget.d.ts +3 -2
  310. package/package.json +28 -3
@@ -3,15 +3,17 @@ import { setAttribute as _$setAttribute } from "solid-js/web";
3
3
  import { className as _$className } from "solid-js/web";
4
4
  import { effect as _$effect } from "solid-js/web";
5
5
  import { getNextMarker as _$getNextMarker } from "solid-js/web";
6
- import { createComponent as _$createComponent } from "solid-js/web";
7
6
  import { getNextElement as _$getNextElement } from "solid-js/web";
7
+ import { createComponent as _$createComponent } from "solid-js/web";
8
8
  import { insert as _$insert } from "solid-js/web";
9
9
  import { memo as _$memo } from "solid-js/web";
10
10
  import { use as _$use } from "solid-js/web";
11
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><!$><!/>`);
12
+ _tmpl$2 = /*#__PURE__*/_$template(`<div><div class=k2b-qr-scanner__preview><video autoplay muted playsinline></video></div><p role=status></p><!$><!/><!$><!/>`);
13
13
  import { timed } from "@k2b/stdlib/solid";
14
14
  import { createSignal, onCleanup, onMount, Show } from "solid-js";
15
+ import { Button } from "../actions/Button";
16
+ import { useUiMessages } from "../intl/messages";
15
17
  import { prefersReducedMotion } from "../motion";
16
18
  import { useQrMessages } from "./qr-messages";
17
19
 
@@ -93,6 +95,12 @@ const openCamera = async closed => {
93
95
  error
94
96
  };
95
97
  };
98
+
99
+ /**
100
+ * How long the camera may take to show its first picture. A working camera shows one well within a second; after three
101
+ * the person has looked at a black square long enough to need a way to start it again.
102
+ */
103
+ const firstPictureMs = 3000;
96
104
  const stopStream = stream => {
97
105
  for (const track of stream.getTracks()) track.stop();
98
106
  };
@@ -104,7 +112,9 @@ const stopStream = stream => {
104
112
  */
105
113
  export function QrScanner(props) {
106
114
  const qrMessages = useQrMessages();
115
+ const uiMessages = useUiMessages();
107
116
  const [starting, setStarting] = createSignal(true);
117
+ const [stalled, setStalled] = createSignal(false);
108
118
  const [invalid, setInvalid] = createSignal(false);
109
119
  let lastRejected;
110
120
  const resetRejected = timed.debounce(() => {
@@ -113,17 +123,21 @@ export function QrScanner(props) {
113
123
  const resetFeedback = timed.debounce(() => setInvalid(false), 1500);
114
124
  let video;
115
125
  let scanner;
126
+ let stream;
116
127
  let closed = false;
117
- let cleanupMotion;
128
+ const detach = [];
118
129
  const destroy = () => {
119
130
  closed = true;
120
- cleanupMotion?.();
131
+ for (const listener of detach.splice(0)) listener();
121
132
  resetRejected.cancel();
122
133
  resetFeedback.cancel();
123
- // pause(true) stops the camera stream immediately.
134
+ // pause(true) stops the camera stream immediately while the engine runs; a stream it never started stops here.
124
135
  void scanner?.pause(true);
125
136
  scanner?.destroy();
126
137
  scanner = undefined;
138
+ if (stream) stopStream(stream);
139
+ stream = undefined;
140
+ video.srcObject = null;
127
141
  };
128
142
  // Once closed, the host has unmounted the scanner or heard why it stopped; later failures stay silent.
129
143
  const fail = reason => {
@@ -131,6 +145,40 @@ export function QrScanner(props) {
131
145
  destroy();
132
146
  props.onError(reason);
133
147
  };
148
+ /**
149
+ * Waits for the camera picture. WebKit, above all in an installed web app, can leave a stream black: play() never
150
+ * settles or is refused. The scanner then offers to try again rather than wait in silence, and a picture that starts
151
+ * late still clears that offer.
152
+ */
153
+ let attempt = 0;
154
+ const show = async play => {
155
+ const current = ++attempt;
156
+ const latest = () => !closed && current === attempt;
157
+ setStalled(false);
158
+ const playing = play().then(() => video.videoWidth > 0, () => false);
159
+ let timer;
160
+ const shown = await Promise.race([playing, new Promise(resolve => {
161
+ timer = setTimeout(resolve, firstPictureMs, false);
162
+ })]);
163
+ clearTimeout(timer);
164
+ if (!latest()) return;
165
+ if (!shown) {
166
+ setStalled(true);
167
+ if (!(await playing) || !latest()) return;
168
+ }
169
+ setStalled(false);
170
+ setStarting(false);
171
+ };
172
+ /**
173
+ * Attaching the stream again restarts a player that stalled on it, and play() runs within the click, the gesture a
174
+ * refused play() may need. The engine already runs from its first start and scans from the play event it hears.
175
+ */
176
+ const retry = () => {
177
+ if (closed || !stream) return;
178
+ video.srcObject = null;
179
+ video.srcObject = stream;
180
+ void show(() => video.play());
181
+ };
134
182
  onMount(() => {
135
183
  const hidden = () => {
136
184
  if (document.visibilityState !== "visible") props.onStop();
@@ -188,15 +236,30 @@ export function QrScanner(props) {
188
236
  };
189
237
  applyMotion();
190
238
  motion.addEventListener("change", applyMotion);
191
- cleanupMotion = () => motion.removeEventListener("change", applyMotion);
239
+ detach.push(() => motion.removeEventListener("change", applyMotion));
240
+ // The engine places its scan region and frame on loadedmetadata, play, and a window resize. It misses a picture
241
+ // that turns, as when a tablet rotates, and a preview that changes size alone; replay loadedmetadata for both,
242
+ // or the region stays where the old picture had it and the frame sits off-centre.
243
+ const relayout = () => {
244
+ if (video.videoWidth > 0) video.dispatchEvent(new Event("loadedmetadata"));
245
+ };
246
+ video.addEventListener("resize", relayout);
247
+ const resized = new ResizeObserver(relayout);
248
+ resized.observe(video);
249
+ detach.push(() => {
250
+ video.removeEventListener("resize", relayout);
251
+ resized.disconnect();
252
+ });
192
253
  const camera = await openCamera(() => closed);
193
254
  if ("error" in camera) return fail(camera.error);
194
255
  if (closed) return stopStream(camera.stream);
195
256
  // qr-scanner plays a stream that is already set instead of opening its own.
196
- video.srcObject = camera.stream;
257
+ stream = camera.stream;
258
+ video.srcObject = stream;
197
259
  video.style.transform = camera.mirrored ? "scaleX(-1)" : "";
198
- await scanner.start();
199
- if (!closed) setStarting(false);
260
+ // start() awaits the engine's play() of this stream.
261
+ const engine = scanner;
262
+ await show(() => engine.start());
200
263
  } catch {
201
264
  fail("unavailable");
202
265
  }
@@ -208,13 +271,32 @@ export function QrScanner(props) {
208
271
  _el$3 = _el$2.firstChild,
209
272
  _el$4 = _el$2.nextSibling,
210
273
  _el$6 = _el$4.nextSibling,
211
- [_el$7, _co$] = _$getNextMarker(_el$6.nextSibling);
274
+ [_el$7, _co$] = _$getNextMarker(_el$6.nextSibling),
275
+ _el$8 = _el$7.nextSibling,
276
+ [_el$9, _co$2] = _$getNextMarker(_el$8.nextSibling);
212
277
  var _ref$ = video;
213
278
  typeof _ref$ === "function" ? _$use(_ref$, _el$3) : video = _el$3;
214
279
  _$insert(_el$4, (() => {
215
- var _c$ = _$memo(() => !!starting());
216
- return () => _c$() ? qrMessages().qrCameraStarting : props.instructions ?? qrMessages().qrCameraInstructions;
280
+ var _c$ = _$memo(() => !!stalled());
281
+ return () => _c$() ? qrMessages().qrCameraStalled : _$memo(() => !!starting())() ? qrMessages().qrCameraStarting : props.instructions ?? qrMessages().qrCameraInstructions;
217
282
  })());
283
+ _$insert(_el$, _$createComponent(Show, {
284
+ get when() {
285
+ return stalled();
286
+ },
287
+ get children() {
288
+ return _$createComponent(Button, {
289
+ type: "button",
290
+ size: "sm",
291
+ variant: "secondary",
292
+ "class": "k2b-qr-scanner__retry",
293
+ onClick: retry,
294
+ get children() {
295
+ return uiMessages().tryAgain;
296
+ }
297
+ });
298
+ }
299
+ }), _el$7, _co$);
218
300
  _$insert(_el$, _$createComponent(Show, {
219
301
  get when() {
220
302
  return !starting();
@@ -224,7 +306,7 @@ export function QrScanner(props) {
224
306
  _$insert(_el$5, () => qrMessages().qrCameraPrivacy);
225
307
  return _el$5;
226
308
  }
227
- }), _el$7, _co$);
309
+ }), _el$9, _co$2);
228
310
  _$effect(_p$ => {
229
311
  var _v$ = props.class ? `k2b-qr-scanner ${props.class}` : "k2b-qr-scanner",
230
312
  _v$2 = invalid() || undefined,
@@ -1 +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 { prefersReducedMotion } from \"../motion\";\nimport { useQrMessages } from \"./qr-messages\";\n\n/**\n * Why the scanner could not start, as far as the browser tells: `\"denied\"` when camera access is off, `\"no-camera\"`\n * when the device has no camera, `\"in-use\"` when the camera is busy or could not start, most often because another app\n * holds it, and `\"unavailable\"` for anything else, including a scanning engine that cannot load.\n */\nexport type QrScannerError = \"denied\" | \"no-camera\" | \"in-use\" | \"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 /**\n * The camera or the scanning engine could not start; the scanner has stopped. Offer another way in. A frame that\n * cannot be decoded never ends here.\n */\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\nconst sizes: MediaTrackConstraints[] = [{ width: { min: 1024 } }, { width: { min: 768 } }, {}];\n/** The rear camera at a resolution that keeps small codes readable, then any camera: the order qr-scanner tries. */\nconst cameraRequests: MediaTrackConstraints[] = [...sizes.map((size) => ({ ...size, facingMode: { exact: \"environment\" } })), ...sizes];\n\nconst errorName = (error: unknown): string => (typeof error === \"object\" && error !== null && \"name\" in error ? String(error.name) : \"\");\n\nconst cameraFailure = (name: string): QrScannerError => {\n if (name === \"NotAllowedError\" || name === \"SecurityError\") return \"denied\";\n if (name === \"NotFoundError\" || name === \"OverconstrainedError\") return \"no-camera\";\n if (name === \"NotReadableError\") return \"in-use\";\n return \"unavailable\";\n};\n\n/** The facing a track reports, or else the one its label names, as qr-scanner reads it. */\nconst facingOf = (track: MediaStreamTrack | undefined): string | undefined => {\n if (!track) return undefined;\n const { facingMode } = track.getSettings();\n if (facingMode) return facingMode;\n if (/rear|back|environment/i.test(track.label)) return \"environment\";\n if (/front|user|face/i.test(track.label)) return \"user\";\n return undefined;\n};\n\n/**\n * Opens the camera here rather than in qr-scanner, which turns every failure into \"Camera not found.\". A refusal ends\n * the search, because asking again could show the permission prompt again. Any other failure may belong to the request,\n * such as a camera that cannot start at the larger size, so the next, looser request follows, as in qr-scanner. When\n * none succeeds, a camera that exists but fails outweighs a request no camera could meet. A closed scanner asks no more.\n */\nconst openCamera = async (closed: () => boolean): Promise<{ stream: MediaStream; mirrored: boolean } | { error: QrScannerError }> => {\n if (!navigator.mediaDevices) return { error: \"unavailable\" };\n let error: QrScannerError = \"no-camera\";\n for (const video of cameraRequests) {\n if (closed()) break;\n try {\n const stream = await navigator.mediaDevices.getUserMedia({ video, audio: false });\n const facing = facingOf(stream.getVideoTracks()[0]);\n // Like qr-scanner, mirror a front camera, and a camera of unknown facing that the rear request did not find.\n return { stream, mirrored: facing ? facing === \"user\" : !video.facingMode };\n } catch (failure) {\n const reason = cameraFailure(errorName(failure));\n if (reason === \"denied\") return { error: reason };\n if (reason !== \"no-camera\") error = reason;\n }\n }\n return { error };\n};\n\nconst stopStream = (stream: MediaStream) => {\n for (const track of stream.getTracks()) track.stop();\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 qrMessages = useQrMessages();\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 let cleanupMotion: (() => void) | undefined;\n const destroy = () => {\n closed = true;\n cleanupMotion?.();\n resetRejected.cancel();\n resetFeedback.cancel();\n // pause(true) stops the camera stream immediately.\n void scanner?.pause(true);\n scanner?.destroy();\n scanner = undefined;\n };\n // Once closed, the host has unmounted the scanner or heard why it stopped; later failures stay silent.\n const fail = (reason: QrScannerError) => {\n if (closed) return;\n destroy();\n props.onError(reason);\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 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 highlightScanRegion: true,\n // A frame that cannot be decoded never ends the session: the camera runs, and the next frame may read.\n // An engine error other than an empty frame, which the native BarcodeDetector reports as \"Scanner error:\n // No QR code found\", means the detector cannot read on this device. Fall back to the bundled worker for\n // the page through the flag qr-scanner 1.4.2 sets itself for \"not implemented\" and \"service unavailable\";\n // it swaps engines after this frame. Worker errors carry the same prefix; the flag changes nothing there.\n // qr-scanner reports frames only as strings: an Error means the engine itself did not load, such as a\n // decoder chunk gone after a deploy or a worker that cannot start, and no later frame can read. Never log\n // decoded content or frame data.\n onDecodeError: (error) => {\n if (typeof error !== \"string\") return fail(\"unavailable\");\n if (error.startsWith(\"Scanner error: \") && !error.endsWith(Engine.NO_QR_CODE_FOUND)) {\n Reflect.set(Engine, \"_disableBarcodeDetector\", true);\n }\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 (prefersReducedMotion()) animation.pause();\n else animation.play();\n }\n };\n applyMotion();\n motion.addEventListener(\"change\", applyMotion);\n cleanupMotion = () => motion.removeEventListener(\"change\", applyMotion);\n const camera = await openCamera(() => closed);\n if (\"error\" in camera) return fail(camera.error);\n if (closed) return stopStream(camera.stream);\n // qr-scanner plays a stream that is already set instead of opening its own.\n video.srcObject = camera.stream;\n video.style.transform = camera.mirrored ? \"scaleX(-1)\" : \"\";\n await scanner.start();\n if (!closed) setStarting(false);\n } catch {\n fail(\"unavailable\");\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={qrMessages().qrCameraPreview} />\n </div>\n <p role=\"status\">{starting() ? qrMessages().qrCameraStarting : (props.instructions ?? qrMessages().qrCameraInstructions)}</p>\n <Show when={!starting()}>\n <p class=\"k2b-qr-scanner__note\">{qrMessages().qrCameraPrivacy}</p>\n </Show>\n </div>\n );\n}\n\nexport default QrScanner;\n"],"mappings":"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","ignoreList":[]}
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 { Button } from \"../actions/Button\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { prefersReducedMotion } from \"../motion\";\nimport { useQrMessages } from \"./qr-messages\";\n\n/**\n * Why the scanner could not start, as far as the browser tells: `\"denied\"` when camera access is off, `\"no-camera\"`\n * when the device has no camera, `\"in-use\"` when the camera is busy or could not start, most often because another app\n * holds it, and `\"unavailable\"` for anything else, including a scanning engine that cannot load.\n */\nexport type QrScannerError = \"denied\" | \"no-camera\" | \"in-use\" | \"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 /**\n * The camera or the scanning engine could not start; the scanner has stopped. Offer another way in. A frame that\n * cannot be decoded never ends here.\n */\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\nconst sizes: MediaTrackConstraints[] = [{ width: { min: 1024 } }, { width: { min: 768 } }, {}];\n/** The rear camera at a resolution that keeps small codes readable, then any camera: the order qr-scanner tries. */\nconst cameraRequests: MediaTrackConstraints[] = [...sizes.map((size) => ({ ...size, facingMode: { exact: \"environment\" } })), ...sizes];\n\nconst errorName = (error: unknown): string => (typeof error === \"object\" && error !== null && \"name\" in error ? String(error.name) : \"\");\n\nconst cameraFailure = (name: string): QrScannerError => {\n if (name === \"NotAllowedError\" || name === \"SecurityError\") return \"denied\";\n if (name === \"NotFoundError\" || name === \"OverconstrainedError\") return \"no-camera\";\n if (name === \"NotReadableError\") return \"in-use\";\n return \"unavailable\";\n};\n\n/** The facing a track reports, or else the one its label names, as qr-scanner reads it. */\nconst facingOf = (track: MediaStreamTrack | undefined): string | undefined => {\n if (!track) return undefined;\n const { facingMode } = track.getSettings();\n if (facingMode) return facingMode;\n if (/rear|back|environment/i.test(track.label)) return \"environment\";\n if (/front|user|face/i.test(track.label)) return \"user\";\n return undefined;\n};\n\n/**\n * Opens the camera here rather than in qr-scanner, which turns every failure into \"Camera not found.\". A refusal ends\n * the search, because asking again could show the permission prompt again. Any other failure may belong to the request,\n * such as a camera that cannot start at the larger size, so the next, looser request follows, as in qr-scanner. When\n * none succeeds, a camera that exists but fails outweighs a request no camera could meet. A closed scanner asks no more.\n */\nconst openCamera = async (closed: () => boolean): Promise<{ stream: MediaStream; mirrored: boolean } | { error: QrScannerError }> => {\n if (!navigator.mediaDevices) return { error: \"unavailable\" };\n let error: QrScannerError = \"no-camera\";\n for (const video of cameraRequests) {\n if (closed()) break;\n try {\n const stream = await navigator.mediaDevices.getUserMedia({ video, audio: false });\n const facing = facingOf(stream.getVideoTracks()[0]);\n // Like qr-scanner, mirror a front camera, and a camera of unknown facing that the rear request did not find.\n return { stream, mirrored: facing ? facing === \"user\" : !video.facingMode };\n } catch (failure) {\n const reason = cameraFailure(errorName(failure));\n if (reason === \"denied\") return { error: reason };\n if (reason !== \"no-camera\") error = reason;\n }\n }\n return { error };\n};\n\n/**\n * How long the camera may take to show its first picture. A working camera shows one well within a second; after three\n * the person has looked at a black square long enough to need a way to start it again.\n */\nconst firstPictureMs = 3000;\n\nconst stopStream = (stream: MediaStream) => {\n for (const track of stream.getTracks()) track.stop();\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 qrMessages = useQrMessages();\n const uiMessages = useUiMessages();\n const [starting, setStarting] = createSignal(true);\n const [stalled, setStalled] = createSignal(false);\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 stream: MediaStream | undefined;\n let closed = false;\n const detach: (() => void)[] = [];\n const destroy = () => {\n closed = true;\n for (const listener of detach.splice(0)) listener();\n resetRejected.cancel();\n resetFeedback.cancel();\n // pause(true) stops the camera stream immediately while the engine runs; a stream it never started stops here.\n void scanner?.pause(true);\n scanner?.destroy();\n scanner = undefined;\n if (stream) stopStream(stream);\n stream = undefined;\n video.srcObject = null;\n };\n // Once closed, the host has unmounted the scanner or heard why it stopped; later failures stay silent.\n const fail = (reason: QrScannerError) => {\n if (closed) return;\n destroy();\n props.onError(reason);\n };\n /**\n * Waits for the camera picture. WebKit, above all in an installed web app, can leave a stream black: play() never\n * settles or is refused. The scanner then offers to try again rather than wait in silence, and a picture that starts\n * late still clears that offer.\n */\n let attempt = 0;\n const show = async (play: () => Promise<void>) => {\n const current = ++attempt;\n const latest = () => !closed && current === attempt;\n setStalled(false);\n const playing = play().then(\n () => video.videoWidth > 0,\n () => false,\n );\n let timer: ReturnType<typeof setTimeout> | undefined;\n const shown = await Promise.race([\n playing,\n new Promise<false>((resolve) => {\n timer = setTimeout(resolve, firstPictureMs, false);\n }),\n ]);\n clearTimeout(timer);\n if (!latest()) return;\n if (!shown) {\n setStalled(true);\n if (!(await playing) || !latest()) return;\n }\n setStalled(false);\n setStarting(false);\n };\n /**\n * Attaching the stream again restarts a player that stalled on it, and play() runs within the click, the gesture a\n * refused play() may need. The engine already runs from its first start and scans from the play event it hears.\n */\n const retry = () => {\n if (closed || !stream) return;\n video.srcObject = null;\n video.srcObject = stream;\n void show(() => video.play());\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 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 highlightScanRegion: true,\n // A frame that cannot be decoded never ends the session: the camera runs, and the next frame may read.\n // An engine error other than an empty frame, which the native BarcodeDetector reports as \"Scanner error:\n // No QR code found\", means the detector cannot read on this device. Fall back to the bundled worker for\n // the page through the flag qr-scanner 1.4.2 sets itself for \"not implemented\" and \"service unavailable\";\n // it swaps engines after this frame. Worker errors carry the same prefix; the flag changes nothing there.\n // qr-scanner reports frames only as strings: an Error means the engine itself did not load, such as a\n // decoder chunk gone after a deploy or a worker that cannot start, and no later frame can read. Never log\n // decoded content or frame data.\n onDecodeError: (error) => {\n if (typeof error !== \"string\") return fail(\"unavailable\");\n if (error.startsWith(\"Scanner error: \") && !error.endsWith(Engine.NO_QR_CODE_FOUND)) {\n Reflect.set(Engine, \"_disableBarcodeDetector\", true);\n }\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 (prefersReducedMotion()) animation.pause();\n else animation.play();\n }\n };\n applyMotion();\n motion.addEventListener(\"change\", applyMotion);\n detach.push(() => motion.removeEventListener(\"change\", applyMotion));\n // The engine places its scan region and frame on loadedmetadata, play, and a window resize. It misses a picture\n // that turns, as when a tablet rotates, and a preview that changes size alone; replay loadedmetadata for both,\n // or the region stays where the old picture had it and the frame sits off-centre.\n const relayout = () => {\n if (video.videoWidth > 0) video.dispatchEvent(new Event(\"loadedmetadata\"));\n };\n video.addEventListener(\"resize\", relayout);\n const resized = new ResizeObserver(relayout);\n resized.observe(video);\n detach.push(() => {\n video.removeEventListener(\"resize\", relayout);\n resized.disconnect();\n });\n const camera = await openCamera(() => closed);\n if (\"error\" in camera) return fail(camera.error);\n if (closed) return stopStream(camera.stream);\n // qr-scanner plays a stream that is already set instead of opening its own.\n stream = camera.stream;\n video.srcObject = stream;\n video.style.transform = camera.mirrored ? \"scaleX(-1)\" : \"\";\n // start() awaits the engine's play() of this stream.\n const engine = scanner;\n await show(() => engine.start());\n } catch {\n fail(\"unavailable\");\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} autoplay muted playsinline aria-label={qrMessages().qrCameraPreview} />\n </div>\n <p role=\"status\">\n {stalled()\n ? qrMessages().qrCameraStalled\n : starting()\n ? qrMessages().qrCameraStarting\n : (props.instructions ?? qrMessages().qrCameraInstructions)}\n </p>\n <Show when={stalled()}>\n <Button type=\"button\" size=\"sm\" variant=\"secondary\" class=\"k2b-qr-scanner__retry\" onClick={retry}>\n {uiMessages().tryAgain}\n </Button>\n </Show>\n <Show when={!starting()}>\n <p class=\"k2b-qr-scanner__note\">{qrMessages().qrCameraPrivacy}</p>\n </Show>\n </div>\n );\n}\n\nexport default QrScanner;\n"],"mappings":"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","ignoreList":[]}
@@ -30,7 +30,7 @@ import { MarkdownEditor } from "./markdown/MarkdownEditor";
30
30
  export function TextInput(props) {
31
31
  const messages = useUiMessages();
32
32
  const inputMessages = useInputMessages();
33
- const [local, rest] = splitProps(props, ["activeIcon", "aria-describedby", "aria-label", "class", "clearLabel", "clearable", "completions", "description", "error", "externalErrorId", "icon", "id", "label", "lines", "markdown", "minLength", "maxLength", "monospace", "multiline", "onClear", "onValueCommit", "onSubmit", "onValueChange", "password", "prefix", "required", "suffix", "type", "value", "variant", "abbreviations"]);
33
+ const [local, rest] = splitProps(props, ["activeIcon", "aria-describedby", "aria-label", "class", "clearLabel", "clearable", "completions", "description", "error", "externalErrorId", "icon", "id", "label", "lines", "markdown", "minLength", "maxLength", "onKeyDown", "monospace", "multiline", "onClear", "onValueCommit", "onSubmit", "onValueChange", "password", "prefix", "required", "suffix", "type", "value", "variant", "abbreviations"]);
34
34
  const meta = createFieldMeta(local.id);
35
35
  const value = () => resolveMaybeAccessor(local.value) ?? "";
36
36
  const error = () => resolveMaybeAccessor(local.error);
@@ -55,6 +55,18 @@ export function TextInput(props) {
55
55
  const verbatim = () => local.password || local.type === "email" || local.type === "url" || /\b(username|email|url)\b/.test(String(rest.autocomplete ?? ""));
56
56
  const input = next => local.onValueChange?.(next);
57
57
  const commit = next => local.onValueCommit?.(next);
58
+ const submitOnEnter = event => {
59
+ if (local.onSubmit && event.key === "Enter" && !event.shiftKey && !event.metaKey) {
60
+ event.preventDefault();
61
+ local.onSubmit();
62
+ }
63
+ };
64
+ /** The caller's key handler runs first; Enter submits unless it handled the key. */
65
+ const keyDown = event => {
66
+ const handler = local.onKeyDown;
67
+ if (typeof handler === "function") handler(event);else if (Array.isArray(handler)) handler[0](handler[1], event);
68
+ if (!event.defaultPrevented) submitOnEnter(event);
69
+ };
58
70
  const clear = event => {
59
71
  // Clearing removes the button. Return to the field before notifying the caller, whose handler
60
72
  // may deliberately navigate or move focus somewhere else.
@@ -180,12 +192,7 @@ export function TextInput(props) {
180
192
  input(event.currentTarget.value);
181
193
  },
182
194
  "onChange": event => commit(event.currentTarget.value),
183
- "onKeyDown": event => {
184
- if (local.onSubmit && event.key === "Enter" && !event.shiftKey && !event.metaKey) {
185
- event.preventDefault();
186
- local.onSubmit();
187
- }
188
- }
195
+ "onKeyDown": keyDown
189
196
  }), false, false);
190
197
  _$runHydrationEvents();
191
198
  return _el$21;
@@ -218,12 +225,7 @@ export function TextInput(props) {
218
225
  input(event.currentTarget.value);
219
226
  },
220
227
  "onChange": event => commit(event.currentTarget.value),
221
- "onKeyDown": event => {
222
- if (local.onSubmit && event.key === "Enter" && !event.shiftKey && !event.metaKey) {
223
- event.preventDefault();
224
- local.onSubmit();
225
- }
226
- }
228
+ "onKeyDown": submitOnEnter
227
229
  }), false, true);
228
230
  _$insert(_el$6, () => isServer ? `\n${value()}` : undefined);
229
231
  _$runHydrationEvents();
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["inputs/TextInput.tsx"],"sourcesContent":["import { createSignal, type JSX, Show, splitProps } from \"solid-js\";\nimport { isServer } from \"solid-js/web\";\nimport { createFieldMeta, Field, fieldControlAria } from \"../internal/field\";\nimport { useUiMessages } from \"../intl/messages\";\nimport type { Completion } from \"./completion\";\nimport type { ValueFieldProps } from \"./field-contract\";\nimport { commitFieldValue, resolveMaybeAccessor } from \"./field-contract\";\nimport { useInputMessages } from \"./input-messages\";\nimport { MarkdownEditor } from \"./markdown/MarkdownEditor\";\n\nexport type TextInputProps = Omit<\n JSX.InputHTMLAttributes<HTMLInputElement>,\n \"onChange\" | \"onInput\" | \"prefix\" | \"suffix\" | \"type\" | \"value\" | keyof ValueFieldProps<string>\n> &\n ValueFieldProps<string> & {\n minLength?: number;\n maxLength?: number;\n type?: \"text\" | \"search\" | \"email\" | \"url\" | \"tel\";\n variant?: \"default\" | \"ai\" | \"compact\";\n /** Set false for a plain field without a leading icon. */\n icon?: string | false;\n activeIcon?: string;\n /** ID of a consumer-owned visible error; caller owns its announcement. Native controls only. */\n externalErrorId?: string;\n prefix?: JSX.Element;\n suffix?: JSX.Element;\n clearable?: boolean;\n onClear?: () => void;\n clearLabel?: string;\n multiline?: boolean;\n monospace?: boolean;\n password?: boolean;\n markdown?: boolean;\n onSubmit?: () => void;\n lines?: number;\n abbreviations?: Record<string, string>;\n completions?: readonly Completion[];\n };\n\nexport function TextInput(props: TextInputProps): JSX.Element {\n const messages = useUiMessages();\n const inputMessages = useInputMessages();\n const [local, rest] = splitProps(props, [\n \"activeIcon\",\n \"aria-describedby\",\n \"aria-label\",\n \"class\",\n \"clearLabel\",\n \"clearable\",\n \"completions\",\n \"description\",\n \"error\",\n \"externalErrorId\",\n \"icon\",\n \"id\",\n \"label\",\n \"lines\",\n \"markdown\",\n \"minLength\",\n \"maxLength\",\n \"monospace\",\n \"multiline\",\n \"onClear\",\n \"onValueCommit\",\n \"onSubmit\",\n \"onValueChange\",\n \"password\",\n \"prefix\",\n \"required\",\n \"suffix\",\n \"type\",\n \"value\",\n \"variant\",\n \"abbreviations\",\n ]);\n const meta = createFieldMeta(local.id);\n const value = () => resolveMaybeAccessor(local.value) ?? \"\";\n const error = () => resolveMaybeAccessor(local.error);\n // HTML IDs are single nonempty tokens; numeric starts and punctuation are valid.\n const externalErrorId = () => {\n const id = local.externalErrorId;\n return id && !/[\\t\\n\\f\\r ]/.test(id) ? id : undefined;\n };\n const controlMeta = {\n ...meta,\n get errorId() {\n return externalErrorId() ?? meta.errorId;\n },\n };\n const [passwordVisible, setPasswordVisible] = createSignal(false);\n const multiline = () => Boolean(local.multiline || local.markdown);\n const compact = () => local.variant === \"compact\";\n const icon = () =>\n local.icon === false\n ? \"\"\n : (local.icon ?? (local.variant === \"ai\" ? \"ti ti-sparkles\" : local.markdown ? \"ti ti-markdown\" : \"ti ti-cursor-text\"));\n // A custom icon stays while typing (a search field keeps its magnifier); only the default icon switches to the pencil.\n const activeIcon = () => local.activeIcon ?? (local.icon || undefined) ?? (local.variant === \"ai\" ? \"ti ti-sparkles\" : \"ti ti-pencil\");\n // Names, addresses and passwords are typed exactly: phone keyboards must not capitalize or \"correct\" them.\n const verbatim = () =>\n local.password || local.type === \"email\" || local.type === \"url\" || /\\b(username|email|url)\\b/.test(String(rest.autocomplete ?? \"\"));\n const input = (next: string) => local.onValueChange?.(next);\n const commit = (next: string) => local.onValueCommit?.(next);\n const clear: JSX.EventHandler<HTMLButtonElement, MouseEvent> = (event) => {\n // Clearing removes the button. Return to the field before notifying the caller, whose handler\n // may deliberately navigate or move focus somewhere else.\n event.currentTarget.ownerDocument.getElementById(meta.controlId)?.focus();\n if (local.onClear) {\n local.onClear();\n return;\n }\n commitFieldValue(local, \"\");\n };\n\n return (\n <Show\n when={local.markdown}\n fallback={\n <Field\n class={local.class}\n label={local.label}\n description={local.description}\n error={externalErrorId() ? undefined : error()}\n meta={meta}\n required={local.required}\n disabled={rest.disabled}\n >\n <div\n class=\"k2b-input-shell k2b-text-input\"\n data-variant={compact() ? \"compact\" : undefined}\n data-invalid={error() ? \"true\" : undefined}\n data-ai={local.variant === \"ai\" ? \"true\" : undefined}\n data-multiline={multiline() ? \"true\" : undefined}\n data-monospace={local.monospace ? \"true\" : undefined}\n style={multiline() ? { \"--k2b-editor-lines\": String(local.lines ?? 3) } : undefined}\n >\n <Show when={!compact() && local.icon !== false}>\n <span class=\"k2b-input-shell__icon k2b-text-input__icon\" aria-hidden=\"true\">\n <i class={icon()} />\n <i class={activeIcon()} />\n </span>\n </Show>\n <Show when={local.prefix}>\n <span class=\"k2b-input-shell__affix\">{local.prefix}</span>\n </Show>\n <Show\n when={multiline()}\n fallback={\n <input\n autocapitalize={verbatim() ? \"none\" : undefined}\n autocorrect={verbatim() ? \"off\" : undefined}\n spellcheck={verbatim() ? false : undefined}\n {...rest}\n id={meta.controlId}\n class=\"k2b-input\"\n size={rest.size ?? (compact() ? 9 : undefined)}\n type={local.password && !passwordVisible() ? \"password\" : (local.type ?? \"text\")}\n value={value()}\n minlength={local.minLength}\n maxlength={local.maxLength}\n required={local.required}\n {...fieldControlAria(controlMeta, local)}\n onInput={(event) => {\n input(event.currentTarget.value);\n }}\n onChange={(event) => commit(event.currentTarget.value)}\n onKeyDown={(event) => {\n if (local.onSubmit && event.key === \"Enter\" && !event.shiftKey && !event.metaKey) {\n event.preventDefault();\n local.onSubmit();\n }\n }}\n />\n }\n >\n <textarea\n {...(rest as unknown as JSX.TextareaHTMLAttributes<HTMLTextAreaElement>)}\n id={meta.controlId}\n class=\"k2b-input k2b-text-input__textarea\"\n value={value()}\n rows={local.lines ?? 3}\n required={local.required}\n minlength={local.minLength}\n maxlength={local.maxLength}\n {...fieldControlAria(controlMeta, local)}\n onInput={(event) => {\n input(event.currentTarget.value);\n }}\n onChange={(event) => commit(event.currentTarget.value)}\n onKeyDown={(event) => {\n if (local.onSubmit && event.key === \"Enter\" && !event.shiftKey && !event.metaKey) {\n event.preventDefault();\n local.onSubmit();\n }\n }}\n >\n {/* HTML consumes one leading newline in textarea content. */}\n {isServer ? `\\n${value()}` : undefined}\n </textarea>\n </Show>\n <Show when={local.suffix}>\n <span class=\"k2b-input-shell__affix\">{local.suffix}</span>\n </Show>\n <Show when={local.clearable && value() && !multiline() && !local.password && !rest.disabled && !rest.readOnly}>\n <button\n type=\"button\"\n class=\"k2b-input-shell__clear k2b-input-clear-action\"\n aria-label={local.clearLabel ?? messages().clear}\n onClick={clear}\n >\n <i class=\"ti ti-x\" aria-hidden=\"true\" />\n </button>\n </Show>\n <Show when={local.password && !multiline()}>\n <button\n type=\"button\"\n class=\"k2b-input-shell__clear\"\n aria-label={passwordVisible() ? inputMessages().hidePassword : inputMessages().showPassword}\n aria-pressed={passwordVisible()}\n disabled={rest.disabled}\n onClick={() => setPasswordVisible((visible) => !visible)}\n >\n <i class={passwordVisible() ? \"ti ti-eye-off\" : \"ti ti-eye\"} aria-hidden=\"true\" />\n </button>\n </Show>\n </div>\n </Field>\n }\n >\n <MarkdownEditor\n class={local.class}\n label={local.label}\n description={local.description}\n error={error()}\n id={meta.controlId}\n name={rest.name}\n value={value()}\n onValueChange={input}\n onValueCommit={local.onValueCommit}\n onSubmit={local.onSubmit}\n placeholder={rest.placeholder}\n disabled={rest.disabled}\n required={local.required}\n lines={local.lines}\n maxLength={local.maxLength}\n spellcheck={rest.spellcheck === undefined ? undefined : rest.spellcheck === true || rest.spellcheck === \"true\"}\n abbreviations={local.abbreviations}\n completions={local.completions}\n aria-label={local[\"aria-label\"]}\n aria-describedby={local[\"aria-describedby\"]}\n />\n </Show>\n );\n}\n\nexport default TextInput;\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["inputs/TextInput.tsx"],"sourcesContent":["import { createSignal, type JSX, Show, splitProps } from \"solid-js\";\nimport { isServer } from \"solid-js/web\";\nimport { createFieldMeta, Field, fieldControlAria } from \"../internal/field\";\nimport { useUiMessages } from \"../intl/messages\";\nimport type { Completion } from \"./completion\";\nimport type { ValueFieldProps } from \"./field-contract\";\nimport { commitFieldValue, resolveMaybeAccessor } from \"./field-contract\";\nimport { useInputMessages } from \"./input-messages\";\nimport { MarkdownEditor } from \"./markdown/MarkdownEditor\";\n\nexport type TextInputProps = Omit<\n JSX.InputHTMLAttributes<HTMLInputElement>,\n \"onChange\" | \"onInput\" | \"prefix\" | \"suffix\" | \"type\" | \"value\" | keyof ValueFieldProps<string>\n> &\n ValueFieldProps<string> & {\n minLength?: number;\n maxLength?: number;\n type?: \"text\" | \"search\" | \"email\" | \"url\" | \"tel\";\n variant?: \"default\" | \"ai\" | \"compact\";\n /** Set false for a plain field without a leading icon. */\n icon?: string | false;\n activeIcon?: string;\n /** ID of a consumer-owned visible error; caller owns its announcement. Native controls only. */\n externalErrorId?: string;\n prefix?: JSX.Element;\n suffix?: JSX.Element;\n clearable?: boolean;\n onClear?: () => void;\n clearLabel?: string;\n multiline?: boolean;\n monospace?: boolean;\n password?: boolean;\n markdown?: boolean;\n onSubmit?: () => void;\n lines?: number;\n abbreviations?: Record<string, string>;\n completions?: readonly Completion[];\n };\n\nexport function TextInput(props: TextInputProps): JSX.Element {\n const messages = useUiMessages();\n const inputMessages = useInputMessages();\n const [local, rest] = splitProps(props, [\n \"activeIcon\",\n \"aria-describedby\",\n \"aria-label\",\n \"class\",\n \"clearLabel\",\n \"clearable\",\n \"completions\",\n \"description\",\n \"error\",\n \"externalErrorId\",\n \"icon\",\n \"id\",\n \"label\",\n \"lines\",\n \"markdown\",\n \"minLength\",\n \"maxLength\",\n \"onKeyDown\",\n \"monospace\",\n \"multiline\",\n \"onClear\",\n \"onValueCommit\",\n \"onSubmit\",\n \"onValueChange\",\n \"password\",\n \"prefix\",\n \"required\",\n \"suffix\",\n \"type\",\n \"value\",\n \"variant\",\n \"abbreviations\",\n ]);\n const meta = createFieldMeta(local.id);\n const value = () => resolveMaybeAccessor(local.value) ?? \"\";\n const error = () => resolveMaybeAccessor(local.error);\n // HTML IDs are single nonempty tokens; numeric starts and punctuation are valid.\n const externalErrorId = () => {\n const id = local.externalErrorId;\n return id && !/[\\t\\n\\f\\r ]/.test(id) ? id : undefined;\n };\n const controlMeta = {\n ...meta,\n get errorId() {\n return externalErrorId() ?? meta.errorId;\n },\n };\n const [passwordVisible, setPasswordVisible] = createSignal(false);\n const multiline = () => Boolean(local.multiline || local.markdown);\n const compact = () => local.variant === \"compact\";\n const icon = () =>\n local.icon === false\n ? \"\"\n : (local.icon ?? (local.variant === \"ai\" ? \"ti ti-sparkles\" : local.markdown ? \"ti ti-markdown\" : \"ti ti-cursor-text\"));\n // A custom icon stays while typing (a search field keeps its magnifier); only the default icon switches to the pencil.\n const activeIcon = () => local.activeIcon ?? (local.icon || undefined) ?? (local.variant === \"ai\" ? \"ti ti-sparkles\" : \"ti ti-pencil\");\n // Names, addresses and passwords are typed exactly: phone keyboards must not capitalize or \"correct\" them.\n const verbatim = () =>\n local.password || local.type === \"email\" || local.type === \"url\" || /\\b(username|email|url)\\b/.test(String(rest.autocomplete ?? \"\"));\n const input = (next: string) => local.onValueChange?.(next);\n const commit = (next: string) => local.onValueCommit?.(next);\n const submitOnEnter = (event: KeyboardEvent) => {\n if (local.onSubmit && event.key === \"Enter\" && !event.shiftKey && !event.metaKey) {\n event.preventDefault();\n local.onSubmit();\n }\n };\n /** The caller's key handler runs first; Enter submits unless it handled the key. */\n const keyDown: JSX.EventHandler<HTMLInputElement, KeyboardEvent> = (event) => {\n const handler = local.onKeyDown;\n if (typeof handler === \"function\") handler(event);\n else if (Array.isArray(handler)) handler[0](handler[1], event);\n if (!event.defaultPrevented) submitOnEnter(event);\n };\n const clear: JSX.EventHandler<HTMLButtonElement, MouseEvent> = (event) => {\n // Clearing removes the button. Return to the field before notifying the caller, whose handler\n // may deliberately navigate or move focus somewhere else.\n event.currentTarget.ownerDocument.getElementById(meta.controlId)?.focus();\n if (local.onClear) {\n local.onClear();\n return;\n }\n commitFieldValue(local, \"\");\n };\n\n return (\n <Show\n when={local.markdown}\n fallback={\n <Field\n class={local.class}\n label={local.label}\n description={local.description}\n error={externalErrorId() ? undefined : error()}\n meta={meta}\n required={local.required}\n disabled={rest.disabled}\n >\n <div\n class=\"k2b-input-shell k2b-text-input\"\n data-variant={compact() ? \"compact\" : undefined}\n data-invalid={error() ? \"true\" : undefined}\n data-ai={local.variant === \"ai\" ? \"true\" : undefined}\n data-multiline={multiline() ? \"true\" : undefined}\n data-monospace={local.monospace ? \"true\" : undefined}\n style={multiline() ? { \"--k2b-editor-lines\": String(local.lines ?? 3) } : undefined}\n >\n <Show when={!compact() && local.icon !== false}>\n <span class=\"k2b-input-shell__icon k2b-text-input__icon\" aria-hidden=\"true\">\n <i class={icon()} />\n <i class={activeIcon()} />\n </span>\n </Show>\n <Show when={local.prefix}>\n <span class=\"k2b-input-shell__affix\">{local.prefix}</span>\n </Show>\n <Show\n when={multiline()}\n fallback={\n <input\n autocapitalize={verbatim() ? \"none\" : undefined}\n autocorrect={verbatim() ? \"off\" : undefined}\n spellcheck={verbatim() ? false : undefined}\n {...rest}\n id={meta.controlId}\n class=\"k2b-input\"\n size={rest.size ?? (compact() ? 9 : undefined)}\n type={local.password && !passwordVisible() ? \"password\" : (local.type ?? \"text\")}\n value={value()}\n minlength={local.minLength}\n maxlength={local.maxLength}\n required={local.required}\n {...fieldControlAria(controlMeta, local)}\n onInput={(event) => {\n input(event.currentTarget.value);\n }}\n onChange={(event) => commit(event.currentTarget.value)}\n onKeyDown={keyDown}\n />\n }\n >\n <textarea\n {...(rest as unknown as JSX.TextareaHTMLAttributes<HTMLTextAreaElement>)}\n id={meta.controlId}\n class=\"k2b-input k2b-text-input__textarea\"\n value={value()}\n rows={local.lines ?? 3}\n required={local.required}\n minlength={local.minLength}\n maxlength={local.maxLength}\n {...fieldControlAria(controlMeta, local)}\n onInput={(event) => {\n input(event.currentTarget.value);\n }}\n onChange={(event) => commit(event.currentTarget.value)}\n onKeyDown={submitOnEnter}\n >\n {/* HTML consumes one leading newline in textarea content. */}\n {isServer ? `\\n${value()}` : undefined}\n </textarea>\n </Show>\n <Show when={local.suffix}>\n <span class=\"k2b-input-shell__affix\">{local.suffix}</span>\n </Show>\n <Show when={local.clearable && value() && !multiline() && !local.password && !rest.disabled && !rest.readOnly}>\n <button\n type=\"button\"\n class=\"k2b-input-shell__clear k2b-input-clear-action\"\n aria-label={local.clearLabel ?? messages().clear}\n onClick={clear}\n >\n <i class=\"ti ti-x\" aria-hidden=\"true\" />\n </button>\n </Show>\n <Show when={local.password && !multiline()}>\n <button\n type=\"button\"\n class=\"k2b-input-shell__clear\"\n aria-label={passwordVisible() ? inputMessages().hidePassword : inputMessages().showPassword}\n aria-pressed={passwordVisible()}\n disabled={rest.disabled}\n onClick={() => setPasswordVisible((visible) => !visible)}\n >\n <i class={passwordVisible() ? \"ti ti-eye-off\" : \"ti ti-eye\"} aria-hidden=\"true\" />\n </button>\n </Show>\n </div>\n </Field>\n }\n >\n <MarkdownEditor\n class={local.class}\n label={local.label}\n description={local.description}\n error={error()}\n id={meta.controlId}\n name={rest.name}\n value={value()}\n onValueChange={input}\n onValueCommit={local.onValueCommit}\n onSubmit={local.onSubmit}\n placeholder={rest.placeholder}\n disabled={rest.disabled}\n required={local.required}\n lines={local.lines}\n maxLength={local.maxLength}\n spellcheck={rest.spellcheck === undefined ? undefined : rest.spellcheck === true || rest.spellcheck === \"true\"}\n abbreviations={local.abbreviations}\n completions={local.completions}\n aria-label={local[\"aria-label\"]}\n aria-describedby={local[\"aria-describedby\"]}\n />\n </Show>\n );\n}\n\nexport default TextInput;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,YAAY,EAAY,IAAI,EAAE,UAAU,QAAQ,UAAU;AACnE,SAAS,QAAQ,QAAQ,cAAc;AACvC,SAAS,eAAe,EAAE,KAAK,EAAE,gBAAgB,QAAQ,mBAAmB;AAC5E,SAAS,aAAa,QAAQ,kBAAkB;AAGhD,SAAS,gBAAgB,EAAE,oBAAoB,QAAQ,kBAAkB;AACzE,SAAS,gBAAgB,QAAQ,kBAAkB;AACnD,SAAS,cAAc,QAAQ,2BAA2B;AA+B1D,OAAO,SAAS,SAAS,CAAC,KAAqB,EAAe;EAC5D,MAAM,QAAQ,GAAG,aAAa,CAAC,CAAC;EAChC,MAAM,aAAa,GAAG,gBAAgB,CAAC,CAAC;EACxC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,UAAU,CAAC,KAAK,EAAE,CACtC,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,OAAO,EACP,YAAY,EACZ,WAAW,EACX,aAAa,EACb,aAAa,EACb,OAAO,EACP,iBAAiB,EACjB,MAAM,EACN,IAAI,EACJ,OAAO,EACP,OAAO,EACP,UAAU,EACV,WAAW,EACX,WAAW,EACX,WAAW,EACX,WAAW,EACX,WAAW,EACX,SAAS,EACT,eAAe,EACf,UAAU,EACV,eAAe,EACf,UAAU,EACV,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,MAAM,EACN,OAAO,EACP,SAAS,EACT,eAAe,CAChB,CAAC;EACF,MAAM,IAAI,GAAG,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;EACtC,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE;EAC3D,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,KAAK,CAAC,KAAK,CAAC;EACrD;EACA,MAAM,eAAe,GAAG,MAAM;IAC5B,MAAM,EAAE,GAAG,KAAK,CAAC,eAAe;IAChC,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,SAAS;EACvD,CAAC;EACD,MAAM,WAAW,GAAG;IAClB,GAAG,IAAI;IACP,IAAI,OAAO,GAAG;MACZ,OAAO,eAAe,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO;IAC1C;EACF,CAAC;EACD,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC;EACjE,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,QAAQ,CAAC;EAClE,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,OAAO,KAAK,SAAS;EACjD,MAAM,IAAI,GAAG,MACX,KAAK,CAAC,IAAI,KAAK,KAAK,GAChB,EAAE,GACD,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,OAAO,KAAK,IAAI,GAAG,gBAAgB,GAAG,KAAK,CAAC,QAAQ,GAAG,gBAAgB,GAAG,mBAAmB,CAAE;EAC3H;EACA,MAAM,UAAU,GAAG,MAAM,KAAK,CAAC,UAAU,KAAK,KAAK,CAAC,IAAI,IAAI,SAAS,CAAC,KAAK,KAAK,CAAC,OAAO,KAAK,IAAI,GAAG,gBAAgB,GAAG,cAAc,CAAC;EACtI;EACA,MAAM,QAAQ,GAAG,MACf,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,IAAI,0BAA0B,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC;EACtI,MAAM,KAAK,GAAI,IAAY,IAAK,KAAK,CAAC,aAAa,GAAG,IAAI,CAAC;EAC3D,MAAM,MAAM,GAAI,IAAY,IAAK,KAAK,CAAC,aAAa,GAAG,IAAI,CAAC;EAC5D,MAAM,aAAa,GAAI,KAAoB,IAAK;IAC9C,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE;MAChF,KAAK,CAAC,cAAc,CAAC,CAAC;MACtB,KAAK,CAAC,QAAQ,CAAC,CAAC;IAClB;EACF,CAAC;EACD;EACA,MAAM,OAA0D,GAAI,KAAK,IAAK;IAC5E,MAAM,OAAO,GAAG,KAAK,CAAC,SAAS;IAC/B,IAAI,OAAO,OAAO,KAAK,UAAU,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,KAC7C,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC;IAC9D,IAAI,CAAC,KAAK,CAAC,gBAAgB,EAAE,aAAa,CAAC,KAAK,CAAC;EACnD,CAAC;EACD,MAAM,KAAsD,GAAI,KAAK,IAAK;IACxE;IACA;IACA,KAAK,CAAC,aAAa,CAAC,aAAa,CAAC,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,CAAC,CAAC;IACzE,IAAI,KAAK,CAAC,OAAO,EAAE;MACjB,KAAK,CAAC,OAAO,CAAC,CAAC;MACf;IACF;IACA,gBAAgB,CAAC,KAAK,EAAE,EAAE,CAAC;EAC7B,CAAC;EAED,yBACG,IAAI;IAAA,IACH,IAAI;MAAA,OAAE,KAAK,CAAC,QAAQ;IAAA;IAAA,IACpB,QAAQ;MAAA,yBACL,KAAK;QAAA;UAAA,OACG,KAAK,CAAC,KAAK;QAAA;QAAA,IAClB,KAAK;UAAA,OAAE,KAAK,CAAC,KAAK;QAAA;QAAA,IAClB,WAAW;UAAA,OAAE,KAAK,CAAC,WAAW;QAAA;QAAA,IAC9B,KAAK;UAAA,OAAE,8BAAe,CAAC,CAAC,MAAG,SAAS,GAAG,KAAK,CAAC,CAAC;QAAA;QAC9C,IAAI,EAAE,IAAI;QAAA,IACV,QAAQ;UAAA,OAAE,KAAK,CAAC,QAAQ;QAAA;QAAA,IACxB,QAAQ;UAAA,OAAE,IAAI,CAAC,QAAQ;QAAA;QAAA;UAAA;YAAA;YAAA;YAAA;YAAA;YAAA;YAAA;YAAA;YAAA;YAAA;YAAA;YAAA;YAAA;UAAA,iCAWpB,IAAI;YAAA,IAAC,IAAI;cAAA,OAAE,gBAAC,OAAO,CAAC,CAAC,OAAI,KAAK,CAAC,IAAI,KAAK,KAAK;YAAA;YAAA;cAAA;gBAAA;gBAAA;cAAA;gBAAA,UAEhC,IAAI,CAAC,CAAC;kBAAA,OACN,UAAU,CAAC,CAAC;gBAAA;gBAAA;gBAAA;cAAA;gBAAA;gBAAA;cAAA;cAAA;YAAA;UAAA;UAAA,iCAGzB,IAAI;YAAA,IAAC,IAAI;cAAA,OAAE,KAAK,CAAC,MAAM;YAAA;YAAA;cAAA;cAAA,sBACgB,KAAK,CAAC,MAAM;cAAA;YAAA;UAAA;UAAA,iCAEnD,IAAI;YAAA,IACH,IAAI;cAAA,OAAE,SAAS,CAAC,CAAC;YAAA;YAAA,IACjB,QAAQ;cAAA;gBAAA;gBAAA;kBAAA,IAEJ,cAAc;oBAAA,OAAE,QAAQ,CAAC,CAAC,GAAG,MAAM,GAAG,SAAS;kBAAA;kBAAA,IAC/C,WAAW;oBAAA,OAAE,QAAQ,CAAC,CAAC,GAAG,KAAK,GAAG,SAAS;kBAAA;kBAAA,IAC3C,UAAU;oBAAA,OAAE,QAAQ,CAAC,CAAC,GAAG,KAAK,GAAG,SAAS;kBAAA;gBAAA,GACtC,IAAI;kBAAA,IACR,EAAE;oBAAA,OAAE,IAAI,CAAC,SAAS;kBAAA;kBAAA,SACZ,WAAW;kBAAA,IACjB,IAAI;oBAAA,OAAE,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;kBAAA;kBAAA,IAC9C,IAAI;oBAAA,OAAE,qBAAK,CAAC,QAAQ,IAAI,CAAC,eAAe,CAAC,CAAC,OAAG,UAAU,GAAI,KAAK,CAAC,IAAI,IAAI,MAAO;kBAAA;kBAAA,IAChF,KAAK;oBAAA,OAAE,KAAK,CAAC,CAAC;kBAAA;kBAAA,IACd,SAAS;oBAAA,OAAE,KAAK,CAAC,SAAS;kBAAA;kBAAA,IAC1B,SAAS;oBAAA,OAAE,KAAK,CAAC,SAAS;kBAAA;kBAAA,IAC1B,QAAQ;oBAAA,OAAE,KAAK,CAAC,QAAQ;kBAAA;gBAAA,SACpB,gBAAgB,CAAC,WAAW,EAAE,KAAK,CAAC;kBAAA,WAC9B,KAAK,IAAK;oBAClB,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC;kBAClC,CAAC;kBAAA,YACU,KAAK,IAAK,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC;kBAAA,aAC3C;gBAAO;gBAAA;gBAAA;cAAA;YAAA;YAAA;cAAA;cAAA,6BAKf,IAAI;gBAAA,IACT,EAAE;kBAAA,OAAE,IAAI,CAAC,SAAS;gBAAA;gBAAA,SACZ,oCAAoC;gBAAA,IAC1C,KAAK;kBAAA,OAAE,KAAK,CAAC,CAAC;gBAAA;gBAAA,IACd,IAAI;kBAAA,OAAE,KAAK,CAAC,KAAK,IAAI,CAAC;gBAAA;gBAAA,IACtB,QAAQ;kBAAA,OAAE,KAAK,CAAC,QAAQ;gBAAA;gBAAA,IACxB,SAAS;kBAAA,OAAE,KAAK,CAAC,SAAS;gBAAA;gBAAA,IAC1B,SAAS;kBAAA,OAAE,KAAK,CAAC,SAAS;gBAAA;cAAA,SACtB,gBAAgB,CAAC,WAAW,EAAE,KAAK,CAAC;gBAAA,WAC9B,KAAK,IAAK;kBAClB,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC;gBAClC,CAAC;gBAAA,YACU,KAAK,IAAK,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC;gBAAA,aAC3C;cAAa;cAAA,sBAGvB,QAAQ,GAAG,KAAK,KAAK,CAAC,CAAC,EAAE,GAAG,SAAS;cAAA;cAAA;YAAA;UAAA;UAAA,iCAGzC,IAAI;YAAA,IAAC,IAAI;cAAA,OAAE,KAAK,CAAC,MAAM;YAAA;YAAA;cAAA;cAAA,sBACgB,KAAK,CAAC,MAAM;cAAA;YAAA;UAAA;UAAA,iCAEnD,IAAI;YAAA,IAAC,IAAI;cAAA,OAAE,qBAAK,CAAC,SAAS,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,QAAQ,QAAI,CAAC,IAAI,CAAC,QAAQ;YAAA;YAAA;cAAA;cAAA,gBAKhG,KAAK;cAAA,mDADF,KAAK,CAAC,UAAU,IAAI,QAAQ,CAAC,CAAC,CAAC,KAAK;cAAA;cAAA;YAAA;UAAA;UAAA,iCAMnD,IAAI;YAAA,IAAC,IAAI;cAAA,OAAE,oBAAK,CAAC,QAAQ,OAAI,CAAC,SAAS,CAAC,CAAC;YAAA;YAAA;cAAA;gBAAA;cAAA,gBAO7B,MAAM,kBAAkB,CAAE,OAAO,IAAK,CAAC,OAAO,CAAC;cAAA;gBAAA,WAH5C,eAAe,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,YAAY,GAAG,aAAa,CAAC,CAAC,CAAC,YAAY;kBAAA,OAC7E,eAAe,CAAC,CAAC;kBAAA,OACrB,IAAI,CAAC,QAAQ;kBAAA,OAGb,eAAe,CAAC,CAAC,GAAG,eAAe,GAAG,WAAW;gBAAA;gBAAA;gBAAA;gBAAA;gBAAA;cAAA;gBAAA;gBAAA;gBAAA;gBAAA;cAAA;cAAA;cAAA;YAAA;UAAA;UAAA;YAAA,WAnFjD,OAAO,CAAC,CAAC,GAAG,SAAS,GAAG,SAAS;cAAA,OACjC,KAAK,CAAC,CAAC,GAAG,MAAM,GAAG,SAAS;cAAA,OACjC,KAAK,CAAC,OAAO,KAAK,IAAI,GAAG,MAAM,GAAG,SAAS;cAAA,OACpC,SAAS,CAAC,CAAC,GAAG,MAAM,GAAG,SAAS;cAAA,OAChC,KAAK,CAAC,SAAS,GAAG,MAAM,GAAG,SAAS;cAAA,QAC7C,SAAS,CAAC,CAAC,GAAG;gBAAE,oBAAoB,EAAE,MAAM,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC;cAAE,CAAC,GAAG,SAAS;YAAA;YAAA;YAAA;YAAA;YAAA;YAAA;YAAA;UAAA;YAAA;YAAA;YAAA;YAAA;YAAA;YAAA;UAAA;UAAA;QAAA;MAAA;IAAA;IAAA;MAAA,yBAqFxF,cAAc;QAAA;UAAA,OACN,KAAK,CAAC,KAAK;QAAA;QAAA,IAClB,KAAK;UAAA,OAAE,KAAK,CAAC,KAAK;QAAA;QAAA,IAClB,WAAW;UAAA,OAAE,KAAK,CAAC,WAAW;QAAA;QAAA,IAC9B,KAAK;UAAA,OAAE,KAAK,CAAC,CAAC;QAAA;QAAA,IACd,EAAE;UAAA,OAAE,IAAI,CAAC,SAAS;QAAA;QAAA,IAClB,IAAI;UAAA,OAAE,IAAI,CAAC,IAAI;QAAA;QAAA,IACf,KAAK;UAAA,OAAE,KAAK,CAAC,CAAC;QAAA;QACd,aAAa,EAAE,KAAK;QAAA,IACpB,aAAa;UAAA,OAAE,KAAK,CAAC,aAAa;QAAA;QAAA,IAClC,QAAQ;UAAA,OAAE,KAAK,CAAC,QAAQ;QAAA;QAAA,IACxB,WAAW;UAAA,OAAE,IAAI,CAAC,WAAW;QAAA;QAAA,IAC7B,QAAQ;UAAA,OAAE,IAAI,CAAC,QAAQ;QAAA;QAAA,IACvB,QAAQ;UAAA,OAAE,KAAK,CAAC,QAAQ;QAAA;QAAA,IACxB,KAAK;UAAA,OAAE,KAAK,CAAC,KAAK;QAAA;QAAA,IAClB,SAAS;UAAA,OAAE,KAAK,CAAC,SAAS;QAAA;QAAA,IAC1B,UAAU;UAAA,OAAE,iBAAI,CAAC,UAAU,KAAK,SAAS,MAAG,SAAS,GAAG,IAAI,CAAC,UAAU,KAAK,IAAI,IAAI,IAAI,CAAC,UAAU,KAAK,MAAM;QAAA;QAAA,IAC9G,aAAa;UAAA,OAAE,KAAK,CAAC,aAAa;QAAA;QAAA,IAClC,WAAW;UAAA,OAAE,KAAK,CAAC,WAAW;QAAA;QAAA;UAAA,OAClB,KAAK,CAAC,YAAY,CAAC;QAAA;QAAA;UAAA,OACb,KAAK,CAAC,kBAAkB,CAAC;QAAA;MAAA;IAAA;EAAA;AAInD;AAEA,eAAe,SAAS;AAAC","ignoreList":[]}
@@ -4,6 +4,10 @@ export { Checkbox } from "./Checkbox";
4
4
  export { CheckboxCard } from "./CheckboxCard";
5
5
  export { ChoiceChips } from "./ChoiceChips";
6
6
  export { ColorInput, PinInput, Slider } from "./ChoiceInputs";
7
+ export { ChoiceList } from "./ChoiceList";
8
+ export { ChoiceSlider } from "./ChoiceSlider";
9
+ export { ChoiceTiles } from "./ChoiceTiles";
10
+ export { ColorChoices } from "./ColorChoices";
7
11
  export { Combobox } from "./Combobox";
8
12
  export { abbreviations } from "./completion";
9
13
  export { DatePicker, DateRangePicker, DateTimePicker } from "./DatePicker";
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["inputs/index.ts"],"sourcesContent":["export type { AutocompleteEditorProps } from \"./AutocompleteEditor\";\nexport { AutocompleteEditor } from \"./AutocompleteEditor\";\nexport type {\n AutocompleteSelectOption,\n AutocompleteSelectProps,\n AutocompleteSelectSearchResult,\n} from \"./AutocompleteSelect\";\nexport { AutocompleteSelect } from \"./AutocompleteSelect\";\nexport type { CheckboxProps } from \"./Checkbox\";\nexport { Checkbox } from \"./Checkbox\";\nexport type { CheckboxCardProps } from \"./CheckboxCard\";\nexport { CheckboxCard } from \"./CheckboxCard\";\nexport type { ChoiceChipOption, ChoiceChipsProps } from \"./ChoiceChips\";\nexport { ChoiceChips } from \"./ChoiceChips\";\nexport type {\n ColorInputProps,\n PinInputProps,\n SliderProps,\n} from \"./ChoiceInputs\";\nexport { ColorInput, PinInput, Slider } from \"./ChoiceInputs\";\nexport type { ComboboxOption, ComboboxProps } from \"./Combobox\";\nexport { Combobox } from \"./Combobox\";\nexport type { ChoiceOption, ChoiceOptionsLoader } from \"./choice\";\nexport type {\n Completion,\n QueryContext,\n SuggestContext,\n Suggestion,\n} from \"./completion\";\nexport { abbreviations } from \"./completion\";\nexport type {\n DatePickerBaseProps,\n DatePickerProps,\n DatePreset,\n DateRangePickerProps,\n DateRangeValue,\n DateTimePickerProps,\n DurationPreset,\n} from \"./DatePicker\";\nexport { DatePicker, DateRangePicker, DateTimePicker } from \"./DatePicker\";\nexport type { EmojiPickerPopoverProps, EmojiPickerProps } from \"./emoji/EmojiPicker\";\nexport { EmojiPicker } from \"./emoji/EmojiPicker\";\nexport type { EmojiSkinTone } from \"./emoji/emoji-index\";\nexport { rememberEmoji } from \"./emoji/emoji-index\";\nexport type { FileDropDetails, FileDropOptions, FileDropRejection, FileDropTargetProps } from \"./FileDropTarget\";\nexport { FileDropTarget, fileDropTarget } from \"./FileDropTarget\";\nexport type { FileDropzoneProps, ImageCropperProps, ImageInputProps } from \"./FileInputs\";\nexport { FileDropzone, ImageCropper, ImageInput } from \"./FileInputs\";\nexport type { DateContext, FieldProps, MaybeAccessor, ValueFieldProps } from \"./field-contract\";\nexport { DEFAULT_ICON_GROUPS, DEFAULT_ICON_OPTIONS } from \"./icon-options\";\nexport type {\n ImageCropAspect,\n ImageCropOutput,\n ImageCropRect,\n ImageCropRotation,\n ImageCropSize,\n ImageCropSource,\n ImageCropState,\n} from \"./image-crop\";\nexport {\n clampImageCropRect,\n createCroppedImageCanvas,\n createCroppedImageDataUrl,\n getInitialImageCropRect,\n imageCropRectToPixels,\n normalizeImageCropRotation,\n resizeImageCropAroundCenter,\n rotateImageCropRight,\n} from \"./image-crop\";\nexport type {\n MultiSelectFetchDataFn,\n MultiSelectInputProps,\n MultiSelectOption,\n} from \"./MultiSelectInput\";\nexport { MultiSelectInput } from \"./MultiSelectInput\";\nexport type { MarkdownEditorProps } from \"./markdown/MarkdownEditor\";\nexport { MarkdownEditor } from \"./markdown/MarkdownEditor\";\nexport type { NumberInputProps } from \"./NumberInput\";\nexport { NumberInput } from \"./NumberInput\";\nexport type { QrScannerError, QrScannerProps } from \"./QrScanner\";\nexport { QrScanner } from \"./QrScanner\";\nexport type {\n RichSelectFact,\n RichSelectFooter,\n RichSelectItem,\n RichSelectProps,\n RichSelectSection,\n RichSelectStatus,\n} from \"./RichSelect\";\nexport { RichSelect, RichSelectFacts } from \"./RichSelect\";\nexport type { ChoiceAppearance, SelectGridSize, SelectGroup, SelectOption, SelectProps, SelectSourceOption, SelectView } from \"./Select\";\nexport { Select } from \"./Select\";\nexport type { SelectChipOption, SelectChipProps } from \"./SelectChip\";\nexport { SelectChip } from \"./SelectChip\";\nexport type { SignatureInputProps } from \"./SignatureInput\";\nexport { SignatureInput } from \"./SignatureInput\";\nexport type { IconInputProps, IconOption } from \"./SpecialInputs\";\nexport { IconInput } from \"./SpecialInputs\";\nexport type { SwitchProps } from \"./Switch\";\nexport { Switch } from \"./Switch\";\nexport type { SignaturePngOptions, SignatureValue } from \"./signature\";\nexport { parseSignature, signatureToPng } from \"./signature\";\nexport type { TagEditorItem, TagEditorLabels, TagEditorProps, TagEditorValue } from \"./TagEditor\";\nexport { TagEditor } from \"./TagEditor\";\nexport type { TagsInputProps } from \"./TagsInput\";\nexport { TagsInput } from \"./TagsInput\";\nexport type {\n TemplateEditorLayout,\n TemplateEditorProps,\n TemplatePreviewProps,\n TemplateSampleDataProps,\n TemplateVariable,\n TemplateVariableKind,\n} from \"./TemplateEditor\";\nexport {\n createTemplateEditorPanesLayout,\n TemplateEditor,\n TemplatePreview,\n TemplateSampleData,\n} from \"./TemplateEditor\";\nexport type { TextInputProps } from \"./TextInput\";\nexport { TextInput } from \"./TextInput\";\n"],"mappings":"AACA,SAAS,kBAAkB,QAAQ,sBAAsB;AAMzD,SAAS,kBAAkB,QAAQ,sBAAsB;AAEzD,SAAS,QAAQ,QAAQ,YAAY;AAErC,SAAS,YAAY,QAAQ,gBAAgB;AAE7C,SAAS,WAAW,QAAQ,eAAe;AAM3C,SAAS,UAAU,EAAE,QAAQ,EAAE,MAAM,QAAQ,gBAAgB;AAE7D,SAAS,QAAQ,QAAQ,YAAY;AAQrC,SAAS,aAAa,QAAQ,cAAc;AAU5C,SAAS,UAAU,EAAE,eAAe,EAAE,cAAc,QAAQ,cAAc;AAE1E,SAAS,WAAW,QAAQ,qBAAqB;AAEjD,SAAS,aAAa,QAAQ,qBAAqB;AAEnD,SAAS,cAAc,EAAE,cAAc,QAAQ,kBAAkB;AAEjE,SAAS,YAAY,EAAE,YAAY,EAAE,UAAU,QAAQ,cAAc;AAErE,SAAS,mBAAmB,EAAE,oBAAoB,QAAQ,gBAAgB;AAU1E,SACE,kBAAkB,EAClB,wBAAwB,EACxB,yBAAyB,EACzB,uBAAuB,EACvB,qBAAqB,EACrB,0BAA0B,EAC1B,2BAA2B,EAC3B,oBAAoB,QACf,cAAc;AAMrB,SAAS,gBAAgB,QAAQ,oBAAoB;AAErD,SAAS,cAAc,QAAQ,2BAA2B;AAE1D,SAAS,WAAW,QAAQ,eAAe;AAE3C,SAAS,SAAS,QAAQ,aAAa;AASvC,SAAS,UAAU,EAAE,eAAe,QAAQ,cAAc;AAE1D,SAAS,MAAM,QAAQ,UAAU;AAEjC,SAAS,UAAU,QAAQ,cAAc;AAEzC,SAAS,cAAc,QAAQ,kBAAkB;AAEjD,SAAS,SAAS,QAAQ,iBAAiB;AAE3C,SAAS,MAAM,QAAQ,UAAU;AAEjC,SAAS,cAAc,EAAE,cAAc,QAAQ,aAAa;AAE5D,SAAS,SAAS,QAAQ,aAAa;AAEvC,SAAS,SAAS,QAAQ,aAAa;AASvC,SACE,+BAA+B,EAC/B,cAAc,EACd,eAAe,EACf,kBAAkB,QACb,kBAAkB;AAEzB,SAAS,SAAS,QAAQ,aAAa","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["inputs/index.ts"],"sourcesContent":["export type { AutocompleteEditorProps } from \"./AutocompleteEditor\";\nexport { AutocompleteEditor } from \"./AutocompleteEditor\";\nexport type {\n AutocompleteSelectOption,\n AutocompleteSelectProps,\n AutocompleteSelectSearchResult,\n} from \"./AutocompleteSelect\";\nexport { AutocompleteSelect } from \"./AutocompleteSelect\";\nexport type { CheckboxProps } from \"./Checkbox\";\nexport { Checkbox } from \"./Checkbox\";\nexport type { CheckboxCardProps } from \"./CheckboxCard\";\nexport { CheckboxCard } from \"./CheckboxCard\";\nexport type { ChoiceChipOption, ChoiceChipsProps } from \"./ChoiceChips\";\nexport { ChoiceChips } from \"./ChoiceChips\";\nexport type {\n ColorInputProps,\n PinInputProps,\n SliderProps,\n} from \"./ChoiceInputs\";\nexport { ColorInput, PinInput, Slider } from \"./ChoiceInputs\";\nexport type { ChoiceListOption, ChoiceListProps } from \"./ChoiceList\";\nexport { ChoiceList } from \"./ChoiceList\";\nexport type { ChoiceSliderOption, ChoiceSliderProps } from \"./ChoiceSlider\";\nexport { ChoiceSlider } from \"./ChoiceSlider\";\nexport type { ChoiceTileOption, ChoiceTilesProps } from \"./ChoiceTiles\";\nexport { ChoiceTiles } from \"./ChoiceTiles\";\nexport type { ColorChoiceOption, ColorChoicesProps } from \"./ColorChoices\";\nexport { ColorChoices } from \"./ColorChoices\";\nexport type { ComboboxOption, ComboboxProps } from \"./Combobox\";\nexport { Combobox } from \"./Combobox\";\nexport type { ChoiceOption, ChoiceOptionsLoader } from \"./choice\";\nexport type {\n Completion,\n QueryContext,\n SuggestContext,\n Suggestion,\n} from \"./completion\";\nexport { abbreviations } from \"./completion\";\nexport type {\n DatePickerBaseProps,\n DatePickerProps,\n DatePreset,\n DateRangePickerProps,\n DateRangeValue,\n DateTimePickerProps,\n DurationPreset,\n} from \"./DatePicker\";\nexport { DatePicker, DateRangePicker, DateTimePicker } from \"./DatePicker\";\nexport type { EmojiPickerPopoverProps, EmojiPickerProps } from \"./emoji/EmojiPicker\";\nexport { EmojiPicker } from \"./emoji/EmojiPicker\";\nexport type { EmojiSkinTone } from \"./emoji/emoji-index\";\nexport { rememberEmoji } from \"./emoji/emoji-index\";\nexport type { FileDropDetails, FileDropOptions, FileDropRejection, FileDropTargetProps } from \"./FileDropTarget\";\nexport { FileDropTarget, fileDropTarget } from \"./FileDropTarget\";\nexport type { FileDropzoneProps, ImageCropperProps, ImageInputProps } from \"./FileInputs\";\nexport { FileDropzone, ImageCropper, ImageInput } from \"./FileInputs\";\nexport type { DateContext, FieldProps, MaybeAccessor, ValueFieldProps } from \"./field-contract\";\nexport { DEFAULT_ICON_GROUPS, DEFAULT_ICON_OPTIONS } from \"./icon-options\";\nexport type {\n ImageCropAspect,\n ImageCropOutput,\n ImageCropRect,\n ImageCropRotation,\n ImageCropSize,\n ImageCropSource,\n ImageCropState,\n} from \"./image-crop\";\nexport {\n clampImageCropRect,\n createCroppedImageCanvas,\n createCroppedImageDataUrl,\n getInitialImageCropRect,\n imageCropRectToPixels,\n normalizeImageCropRotation,\n resizeImageCropAroundCenter,\n rotateImageCropRight,\n} from \"./image-crop\";\nexport type {\n MultiSelectFetchDataFn,\n MultiSelectInputProps,\n MultiSelectOption,\n} from \"./MultiSelectInput\";\nexport { MultiSelectInput } from \"./MultiSelectInput\";\nexport type { MarkdownEditorProps } from \"./markdown/MarkdownEditor\";\nexport { MarkdownEditor } from \"./markdown/MarkdownEditor\";\nexport type { NumberInputProps } from \"./NumberInput\";\nexport { NumberInput } from \"./NumberInput\";\nexport type { QrScannerError, QrScannerProps } from \"./QrScanner\";\nexport { QrScanner } from \"./QrScanner\";\nexport type {\n RichSelectFact,\n RichSelectFooter,\n RichSelectItem,\n RichSelectProps,\n RichSelectSection,\n RichSelectStatus,\n} from \"./RichSelect\";\nexport { RichSelect, RichSelectFacts } from \"./RichSelect\";\nexport type { ChoiceAppearance, SelectGridSize, SelectGroup, SelectOption, SelectProps, SelectSourceOption, SelectView } from \"./Select\";\nexport { Select } from \"./Select\";\nexport type { SelectChipOption, SelectChipProps } from \"./SelectChip\";\nexport { SelectChip } from \"./SelectChip\";\nexport type { SignatureInputProps } from \"./SignatureInput\";\nexport { SignatureInput } from \"./SignatureInput\";\nexport type { IconInputProps, IconOption } from \"./SpecialInputs\";\nexport { IconInput } from \"./SpecialInputs\";\nexport type { SwitchProps } from \"./Switch\";\nexport { Switch } from \"./Switch\";\nexport type { SignaturePngOptions, SignatureValue } from \"./signature\";\nexport { parseSignature, signatureToPng } from \"./signature\";\nexport type { TagEditorItem, TagEditorLabels, TagEditorProps, TagEditorValue } from \"./TagEditor\";\nexport { TagEditor } from \"./TagEditor\";\nexport type { TagsInputProps } from \"./TagsInput\";\nexport { TagsInput } from \"./TagsInput\";\nexport type {\n TemplateEditorLayout,\n TemplateEditorProps,\n TemplatePreviewProps,\n TemplateSampleDataProps,\n TemplateVariable,\n TemplateVariableKind,\n} from \"./TemplateEditor\";\nexport {\n createTemplateEditorPanesLayout,\n TemplateEditor,\n TemplatePreview,\n TemplateSampleData,\n} from \"./TemplateEditor\";\nexport type { TextInputProps } from \"./TextInput\";\nexport { TextInput } from \"./TextInput\";\n"],"mappings":"AACA,SAAS,kBAAkB,QAAQ,sBAAsB;AAMzD,SAAS,kBAAkB,QAAQ,sBAAsB;AAEzD,SAAS,QAAQ,QAAQ,YAAY;AAErC,SAAS,YAAY,QAAQ,gBAAgB;AAE7C,SAAS,WAAW,QAAQ,eAAe;AAM3C,SAAS,UAAU,EAAE,QAAQ,EAAE,MAAM,QAAQ,gBAAgB;AAE7D,SAAS,UAAU,QAAQ,cAAc;AAEzC,SAAS,YAAY,QAAQ,gBAAgB;AAE7C,SAAS,WAAW,QAAQ,eAAe;AAE3C,SAAS,YAAY,QAAQ,gBAAgB;AAE7C,SAAS,QAAQ,QAAQ,YAAY;AAQrC,SAAS,aAAa,QAAQ,cAAc;AAU5C,SAAS,UAAU,EAAE,eAAe,EAAE,cAAc,QAAQ,cAAc;AAE1E,SAAS,WAAW,QAAQ,qBAAqB;AAEjD,SAAS,aAAa,QAAQ,qBAAqB;AAEnD,SAAS,cAAc,EAAE,cAAc,QAAQ,kBAAkB;AAEjE,SAAS,YAAY,EAAE,YAAY,EAAE,UAAU,QAAQ,cAAc;AAErE,SAAS,mBAAmB,EAAE,oBAAoB,QAAQ,gBAAgB;AAU1E,SACE,kBAAkB,EAClB,wBAAwB,EACxB,yBAAyB,EACzB,uBAAuB,EACvB,qBAAqB,EACrB,0BAA0B,EAC1B,2BAA2B,EAC3B,oBAAoB,QACf,cAAc;AAMrB,SAAS,gBAAgB,QAAQ,oBAAoB;AAErD,SAAS,cAAc,QAAQ,2BAA2B;AAE1D,SAAS,WAAW,QAAQ,eAAe;AAE3C,SAAS,SAAS,QAAQ,aAAa;AASvC,SAAS,UAAU,EAAE,eAAe,QAAQ,cAAc;AAE1D,SAAS,MAAM,QAAQ,UAAU;AAEjC,SAAS,UAAU,QAAQ,cAAc;AAEzC,SAAS,cAAc,QAAQ,kBAAkB;AAEjD,SAAS,SAAS,QAAQ,iBAAiB;AAE3C,SAAS,MAAM,QAAQ,UAAU;AAEjC,SAAS,cAAc,EAAE,cAAc,QAAQ,aAAa;AAE5D,SAAS,SAAS,QAAQ,aAAa;AAEvC,SAAS,SAAS,QAAQ,aAAa;AASvC,SACE,+BAA+B,EAC/B,cAAc,EACd,eAAe,EACf,kBAAkB,QACb,kBAAkB;AAEzB,SAAS,SAAS,QAAQ,aAAa","ignoreList":[]}
@@ -7,12 +7,14 @@ const qrMessages = i18n.define({
7
7
  qrCameraPreview: "Camera preview for scanning a QR code",
8
8
  qrCameraStarting: "Starting camera…",
9
9
  qrCameraInstructions: "Point the camera at a QR code.",
10
+ qrCameraStalled: "The camera is on, but its picture did not start.",
10
11
  qrCameraPrivacy: "Camera images stay on this device."
11
12
  },
12
13
  de: {
13
14
  qrCameraPreview: "Kameravorschau zum Scannen eines QR-Codes",
14
15
  qrCameraStarting: "Kamera wird gestartet…",
15
16
  qrCameraInstructions: "Richte die Kamera auf einen QR-Code.",
17
+ qrCameraStalled: "Die Kamera ist an, aber ihr Bild ist nicht gestartet.",
16
18
  qrCameraPrivacy: "Kamerabilder bleiben auf diesem Gerät."
17
19
  }
18
20
  }
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["inputs/qr-messages.ts"],"sourcesContent":["import { i18n } from \"@k2b/stdlib\";\nimport { useLocale } from \"../intl/locale\";\n\nconst qrMessages = i18n.define({\n baseLocale: \"en\",\n messages: {\n en: {\n qrCameraPreview: \"Camera preview for scanning a QR code\",\n qrCameraStarting: \"Starting camera…\",\n qrCameraInstructions: \"Point the camera at a QR code.\",\n qrCameraPrivacy: \"Camera images stay on this device.\",\n },\n de: {\n qrCameraPreview: \"Kameravorschau zum Scannen eines QR-Codes\",\n qrCameraStarting: \"Kamera wird gestartet…\",\n qrCameraInstructions: \"Richte die Kamera auf einen QR-Code.\",\n qrCameraPrivacy: \"Kamerabilder bleiben auf diesem Gerät.\",\n },\n },\n});\n\nexport type QrMessages = ReturnType<(typeof qrMessages)[\"resolve\"]>[\"t\"];\n\n/** Resolved from the inherited render locale. */\nexport const useQrMessages = (): (() => QrMessages) => {\n const locale = useLocale();\n return () => qrMessages.resolve([locale()]).t;\n};\n\nexport const checkQrMessages = () => qrMessages.check();\n"],"mappings":"AAAA,SAAS,IAAI,QAAQ,aAAa;AAClC,SAAS,SAAS,QAAQ,gBAAgB;AAE1C,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC;EAC7B,UAAU,EAAE,IAAI;EAChB,QAAQ,EAAE;IACR,EAAE,EAAE;MACF,eAAe,EAAE,uCAAuC;MACxD,gBAAgB,EAAE,kBAAkB;MACpC,oBAAoB,EAAE,gCAAgC;MACtD,eAAe,EAAE;IACnB,CAAC;IACD,EAAE,EAAE;MACF,eAAe,EAAE,2CAA2C;MAC5D,gBAAgB,EAAE,wBAAwB;MAC1C,oBAAoB,EAAE,sCAAsC;MAC5D,eAAe,EAAE;IACnB;EACF;AACF,CAAC,CAAC;AAIF;AACA,OAAO,MAAM,aAAa,GAAG,MAA0B;EACrD,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC;EAC1B,OAAO,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED,OAAO,MAAM,eAAe,GAAG,MAAM,UAAU,CAAC,KAAK,CAAC,CAAC","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["inputs/qr-messages.ts"],"sourcesContent":["import { i18n } from \"@k2b/stdlib\";\nimport { useLocale } from \"../intl/locale\";\n\nconst qrMessages = i18n.define({\n baseLocale: \"en\",\n messages: {\n en: {\n qrCameraPreview: \"Camera preview for scanning a QR code\",\n qrCameraStarting: \"Starting camera…\",\n qrCameraInstructions: \"Point the camera at a QR code.\",\n qrCameraStalled: \"The camera is on, but its picture did not start.\",\n qrCameraPrivacy: \"Camera images stay on this device.\",\n },\n de: {\n qrCameraPreview: \"Kameravorschau zum Scannen eines QR-Codes\",\n qrCameraStarting: \"Kamera wird gestartet…\",\n qrCameraInstructions: \"Richte die Kamera auf einen QR-Code.\",\n qrCameraStalled: \"Die Kamera ist an, aber ihr Bild ist nicht gestartet.\",\n qrCameraPrivacy: \"Kamerabilder bleiben auf diesem Gerät.\",\n },\n },\n});\n\nexport type QrMessages = ReturnType<(typeof qrMessages)[\"resolve\"]>[\"t\"];\n\n/** Resolved from the inherited render locale. */\nexport const useQrMessages = (): (() => QrMessages) => {\n const locale = useLocale();\n return () => qrMessages.resolve([locale()]).t;\n};\n\nexport const checkQrMessages = () => qrMessages.check();\n"],"mappings":"AAAA,SAAS,IAAI,QAAQ,aAAa;AAClC,SAAS,SAAS,QAAQ,gBAAgB;AAE1C,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC;EAC7B,UAAU,EAAE,IAAI;EAChB,QAAQ,EAAE;IACR,EAAE,EAAE;MACF,eAAe,EAAE,uCAAuC;MACxD,gBAAgB,EAAE,kBAAkB;MACpC,oBAAoB,EAAE,gCAAgC;MACtD,eAAe,EAAE,kDAAkD;MACnE,eAAe,EAAE;IACnB,CAAC;IACD,EAAE,EAAE;MACF,eAAe,EAAE,2CAA2C;MAC5D,gBAAgB,EAAE,wBAAwB;MAC1C,oBAAoB,EAAE,sCAAsC;MAC5D,eAAe,EAAE,uDAAuD;MACxE,eAAe,EAAE;IACnB;EACF;AACF,CAAC,CAAC;AAIF;AACA,OAAO,MAAM,aAAa,GAAG,MAA0B;EACrD,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC;EAC1B,OAAO,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED,OAAO,MAAM,eAAe,GAAG,MAAM,UAAU,CAAC,KAAK,CAAC,CAAC","ignoreList":[]}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Roving focus for a single-choice radio group: arrows move and select with wrapping, Home and End select the first
3
+ * and last option. Returns the index to select, or `undefined` for keys the group does not handle.
4
+ */
5
+ export const radioKeyTarget = (key, index, count) => {
6
+ if (count === 0) return undefined;
7
+ if (key === "ArrowRight" || key === "ArrowDown") return (index + 1) % count;
8
+ if (key === "ArrowLeft" || key === "ArrowUp") return (index - 1 + count) % count;
9
+ if (key === "Home") return 0;
10
+ if (key === "End") return count - 1;
11
+ return undefined;
12
+ };
13
+ //# sourceMappingURL=radio-keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sources":["internal/radio-keys.ts"],"sourcesContent":["/**\n * Roving focus for a single-choice radio group: arrows move and select with wrapping, Home and End select the first\n * and last option. Returns the index to select, or `undefined` for keys the group does not handle.\n */\nexport const radioKeyTarget = (key: string, index: number, count: number): number | undefined => {\n if (count === 0) return undefined;\n if (key === \"ArrowRight\" || key === \"ArrowDown\") return (index + 1) % count;\n if (key === \"ArrowLeft\" || key === \"ArrowUp\") return (index - 1 + count) % count;\n if (key === \"Home\") return 0;\n if (key === \"End\") return count - 1;\n return undefined;\n};\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA,OAAO,MAAM,cAAc,GAAG,CAAC,GAAW,EAAE,KAAa,EAAE,KAAa,KAAyB;EAC/F,IAAI,KAAK,KAAK,CAAC,EAAE,OAAO,SAAS;EACjC,IAAI,GAAG,KAAK,YAAY,IAAI,GAAG,KAAK,WAAW,EAAE,OAAO,CAAC,KAAK,GAAG,CAAC,IAAI,KAAK;EAC3E,IAAI,GAAG,KAAK,WAAW,IAAI,GAAG,KAAK,SAAS,EAAE,OAAO,CAAC,KAAK,GAAG,CAAC,GAAG,KAAK,IAAI,KAAK;EAChF,IAAI,GAAG,KAAK,MAAM,EAAE,OAAO,CAAC;EAC5B,IAAI,GAAG,KAAK,KAAK,EAAE,OAAO,KAAK,GAAG,CAAC;EACnC,OAAO,SAAS;AAClB,CAAC","ignoreList":[]}