@happyvertical/smrt-ui 0.51.39 → 0.53.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 (392) hide show
  1. package/AGENTS.md +25 -3
  2. package/README.md +558 -8
  3. package/dist/actions/__tests__/swipe-dismiss.test.js +69 -0
  4. package/dist/actions/swipe-dismiss.d.ts +42 -0
  5. package/dist/actions/swipe-dismiss.d.ts.map +1 -0
  6. package/dist/actions/swipe-dismiss.js +69 -0
  7. package/dist/components/calendar/Calendar.svelte +5 -0
  8. package/dist/components/calendar/Calendar.svelte.d.ts.map +1 -1
  9. package/dist/components/calendar/CalendarView.svelte +1250 -0
  10. package/dist/components/calendar/CalendarView.svelte.d.ts +66 -0
  11. package/dist/components/calendar/CalendarView.svelte.d.ts.map +1 -0
  12. package/dist/components/calendar/DayView.svelte +5 -0
  13. package/dist/components/calendar/DayView.svelte.d.ts.map +1 -1
  14. package/dist/components/calendar/__tests__/CalendarView.test.js +226 -0
  15. package/dist/components/calendar/__tests__/calendar-model.test.js +138 -0
  16. package/dist/components/calendar/calendar-model.d.ts +178 -0
  17. package/dist/components/calendar/calendar-model.d.ts.map +1 -0
  18. package/dist/components/calendar/calendar-model.js +362 -0
  19. package/dist/components/calendar/index.d.ts +12 -1
  20. package/dist/components/calendar/index.d.ts.map +1 -1
  21. package/dist/components/calendar/index.js +11 -1
  22. package/dist/components/data/CollectionList.svelte +23 -5
  23. package/dist/components/data/CollectionList.svelte.d.ts +8 -2
  24. package/dist/components/data/CollectionList.svelte.d.ts.map +1 -1
  25. package/dist/components/data/DataTable.svelte +178 -55
  26. package/dist/components/data/DataTable.svelte.d.ts.map +1 -1
  27. package/dist/components/data/DataTableController.d.ts +4 -0
  28. package/dist/components/data/DataTableController.d.ts.map +1 -1
  29. package/dist/components/data/DataTableController.js +11 -4
  30. package/dist/components/data/DataTableResponsive.d.ts +4 -0
  31. package/dist/components/data/DataTableResponsive.d.ts.map +1 -0
  32. package/dist/components/data/DataTableResponsive.js +22 -0
  33. package/dist/components/data/ListSortSelect.svelte +121 -0
  34. package/dist/components/data/ListSortSelect.svelte.d.ts +22 -0
  35. package/dist/components/data/ListSortSelect.svelte.d.ts.map +1 -0
  36. package/dist/components/data/SortableHeader.svelte +169 -0
  37. package/dist/components/data/SortableHeader.svelte.d.ts +30 -0
  38. package/dist/components/data/SortableHeader.svelte.d.ts.map +1 -0
  39. package/dist/components/data/__tests__/CollectionList.test.js +37 -0
  40. package/dist/components/data/__tests__/DataTable.test.js +76 -0
  41. package/dist/components/data/__tests__/DataTableController.test.js +35 -0
  42. package/dist/components/data/__tests__/DataTableResponsive.test.js +80 -0
  43. package/dist/components/data/__tests__/SortableHeader.test.js +101 -0
  44. package/dist/components/data/__tests__/link-step-surface.test.js +172 -0
  45. package/dist/components/data/__tests__/list-sort-state.svelte.test.js +71 -0
  46. package/dist/components/data/__tests__/list-sort.test.js +91 -0
  47. package/dist/components/data/__tests__/responsive-table.fixture.svelte +29 -0
  48. package/dist/components/data/__tests__/responsive-table.fixture.svelte.d.ts +7 -0
  49. package/dist/components/data/__tests__/responsive-table.fixture.svelte.d.ts.map +1 -0
  50. package/dist/components/data/__tests__/surface-navigation.test.js +121 -0
  51. package/dist/components/data/data-surface.d.ts +1 -0
  52. package/dist/components/data/data-surface.d.ts.map +1 -1
  53. package/dist/components/data/data-surface.js +1 -0
  54. package/dist/components/data/index.d.ts +6 -0
  55. package/dist/components/data/index.d.ts.map +1 -1
  56. package/dist/components/data/index.js +6 -0
  57. package/dist/components/data/link-surface.d.ts +79 -0
  58. package/dist/components/data/link-surface.d.ts.map +1 -0
  59. package/dist/components/data/link-surface.js +155 -0
  60. package/dist/components/data/list-sort-state.svelte.d.ts +39 -0
  61. package/dist/components/data/list-sort-state.svelte.d.ts.map +1 -0
  62. package/dist/components/data/list-sort-state.svelte.js +47 -0
  63. package/dist/components/data/list-sort.d.ts +94 -0
  64. package/dist/components/data/list-sort.d.ts.map +1 -0
  65. package/dist/components/data/list-sort.js +182 -0
  66. package/dist/components/data/step-surface.d.ts +73 -0
  67. package/dist/components/data/step-surface.d.ts.map +1 -0
  68. package/dist/components/data/step-surface.js +177 -0
  69. package/dist/components/data/surface-navigation.d.ts +49 -0
  70. package/dist/components/data/surface-navigation.d.ts.map +1 -0
  71. package/dist/components/data/surface-navigation.js +100 -0
  72. package/dist/components/data/types.d.ts +27 -0
  73. package/dist/components/data/types.d.ts.map +1 -1
  74. package/dist/components/display/DateDisplay.svelte +76 -14
  75. package/dist/components/display/DateDisplay.svelte.d.ts +2 -0
  76. package/dist/components/display/DateDisplay.svelte.d.ts.map +1 -1
  77. package/dist/components/display/Icon.svelte +3 -16
  78. package/dist/components/display/Icon.svelte.d.ts +0 -9
  79. package/dist/components/display/Icon.svelte.d.ts.map +1 -1
  80. package/dist/components/display/StatusBadge.svelte +29 -2
  81. package/dist/components/display/StatusBadge.svelte.d.ts +4 -2
  82. package/dist/components/display/StatusBadge.svelte.d.ts.map +1 -1
  83. package/dist/components/display/__tests__/DateDisplay.test.js +82 -1
  84. package/dist/components/display/__tests__/Icon.test.js +132 -2
  85. package/dist/components/display/__tests__/StatusBadge.test.js +78 -0
  86. package/dist/components/display/icons.svelte.d.ts +11 -0
  87. package/dist/components/display/icons.svelte.d.ts.map +1 -0
  88. package/dist/components/display/icons.svelte.js +60 -0
  89. package/dist/components/display/index.d.ts +3 -1
  90. package/dist/components/display/index.d.ts.map +1 -1
  91. package/dist/components/display/index.js +1 -0
  92. package/dist/components/display/types.d.ts +2 -0
  93. package/dist/components/display/types.d.ts.map +1 -1
  94. package/dist/components/feedback/ConfirmDialog.svelte +59 -48
  95. package/dist/components/feedback/ConfirmDialog.svelte.d.ts +14 -2
  96. package/dist/components/feedback/ConfirmDialog.svelte.d.ts.map +1 -1
  97. package/dist/components/feedback/PhoneSheet.svelte +224 -0
  98. package/dist/components/feedback/PhoneSheet.svelte.d.ts +35 -0
  99. package/dist/components/feedback/PhoneSheet.svelte.d.ts.map +1 -0
  100. package/dist/components/feedback/ToastViewport.svelte +156 -8
  101. package/dist/components/feedback/ToastViewport.svelte.d.ts +5 -1
  102. package/dist/components/feedback/ToastViewport.svelte.d.ts.map +1 -1
  103. package/dist/components/feedback/WorkingStrip.svelte +426 -0
  104. package/dist/components/feedback/WorkingStrip.svelte.d.ts +37 -0
  105. package/dist/components/feedback/WorkingStrip.svelte.d.ts.map +1 -0
  106. package/dist/components/feedback/__tests__/ConfirmDialog.test.js +38 -20
  107. package/dist/components/feedback/__tests__/PhoneSheet.test.js +101 -0
  108. package/dist/components/feedback/__tests__/WorkingStrip.test.js +172 -0
  109. package/dist/components/feedback/__tests__/confirm-message.fixture.svelte +9 -0
  110. package/dist/components/feedback/__tests__/confirm-message.fixture.svelte.d.ts +19 -0
  111. package/dist/components/feedback/__tests__/confirm-message.fixture.svelte.d.ts.map +1 -0
  112. package/dist/components/feedback/__tests__/toast.test.js +142 -1
  113. package/dist/components/feedback/index.d.ts +5 -1
  114. package/dist/components/feedback/index.d.ts.map +1 -1
  115. package/dist/components/feedback/index.js +5 -0
  116. package/dist/components/feedback/toast.d.ts +13 -1
  117. package/dist/components/feedback/toast.d.ts.map +1 -1
  118. package/dist/components/feedback/toast.js +51 -10
  119. package/dist/components/feedback/working-status.d.ts +34 -0
  120. package/dist/components/feedback/working-status.d.ts.map +1 -0
  121. package/dist/components/feedback/working-status.js +5 -0
  122. package/dist/components/forms/CameraCapture.svelte +619 -0
  123. package/dist/components/forms/CameraCapture.svelte.d.ts +42 -0
  124. package/dist/components/forms/CameraCapture.svelte.d.ts.map +1 -0
  125. package/dist/components/forms/Checkbox.svelte +34 -3
  126. package/dist/components/forms/Checkbox.svelte.d.ts +2 -0
  127. package/dist/components/forms/Checkbox.svelte.d.ts.map +1 -1
  128. package/dist/components/forms/Combobox.svelte +108 -12
  129. package/dist/components/forms/Combobox.svelte.d.ts +6 -0
  130. package/dist/components/forms/Combobox.svelte.d.ts.map +1 -1
  131. package/dist/components/forms/DictationButton.svelte +128 -0
  132. package/dist/components/forms/DictationButton.svelte.d.ts +19 -0
  133. package/dist/components/forms/DictationButton.svelte.d.ts.map +1 -0
  134. package/dist/components/forms/DictationStatus.svelte +164 -0
  135. package/dist/components/forms/DictationStatus.svelte.d.ts +11 -0
  136. package/dist/components/forms/DictationStatus.svelte.d.ts.map +1 -0
  137. package/dist/components/forms/Fieldset.svelte +5 -1
  138. package/dist/components/forms/Fieldset.svelte.d.ts +2 -0
  139. package/dist/components/forms/Fieldset.svelte.d.ts.map +1 -1
  140. package/dist/components/forms/Form.svelte +5 -0
  141. package/dist/components/forms/Form.svelte.d.ts +1 -0
  142. package/dist/components/forms/Form.svelte.d.ts.map +1 -1
  143. package/dist/components/forms/FormActionBar.svelte +84 -0
  144. package/dist/components/forms/FormActionBar.svelte.d.ts +23 -0
  145. package/dist/components/forms/FormActionBar.svelte.d.ts.map +1 -0
  146. package/dist/components/forms/Input.svelte +17 -1
  147. package/dist/components/forms/Input.svelte.d.ts +2 -0
  148. package/dist/components/forms/Input.svelte.d.ts.map +1 -1
  149. package/dist/components/forms/Listbox.svelte +39 -1
  150. package/dist/components/forms/Listbox.svelte.d.ts.map +1 -1
  151. package/dist/components/forms/MultiSelect.svelte +41 -1
  152. package/dist/components/forms/MultiSelect.svelte.d.ts.map +1 -1
  153. package/dist/components/forms/Radio.svelte +16 -4
  154. package/dist/components/forms/RadioGroup.svelte +7 -1
  155. package/dist/components/forms/RadioGroup.svelte.d.ts +2 -0
  156. package/dist/components/forms/RadioGroup.svelte.d.ts.map +1 -1
  157. package/dist/components/forms/SearchInput.svelte +207 -0
  158. package/dist/components/forms/SearchInput.svelte.d.ts +22 -0
  159. package/dist/components/forms/SearchInput.svelte.d.ts.map +1 -0
  160. package/dist/components/forms/SegmentedControl.svelte +152 -11
  161. package/dist/components/forms/SegmentedControl.svelte.d.ts +4 -0
  162. package/dist/components/forms/SegmentedControl.svelte.d.ts.map +1 -1
  163. package/dist/components/forms/Select.svelte +17 -1
  164. package/dist/components/forms/Select.svelte.d.ts +2 -0
  165. package/dist/components/forms/Select.svelte.d.ts.map +1 -1
  166. package/dist/components/forms/SignaturePad.svelte +436 -0
  167. package/dist/components/forms/SignaturePad.svelte.d.ts +32 -0
  168. package/dist/components/forms/SignaturePad.svelte.d.ts.map +1 -0
  169. package/dist/components/forms/StagedControlReview.svelte +21 -12
  170. package/dist/components/forms/StagedControlReview.svelte.d.ts.map +1 -1
  171. package/dist/components/forms/Switch.svelte +18 -5
  172. package/dist/components/forms/Switch.svelte.d.ts +2 -0
  173. package/dist/components/forms/Switch.svelte.d.ts.map +1 -1
  174. package/dist/components/forms/TagsInput.svelte +8 -1
  175. package/dist/components/forms/Textarea.svelte +16 -1
  176. package/dist/components/forms/Textarea.svelte.d.ts +2 -0
  177. package/dist/components/forms/Textarea.svelte.d.ts.map +1 -1
  178. package/dist/components/forms/__tests__/CameraCapture.test.js +504 -0
  179. package/dist/components/forms/__tests__/Combobox.test.js +354 -0
  180. package/dist/components/forms/__tests__/ControlHitArea.test.js +73 -0
  181. package/dist/components/forms/__tests__/DictationButton.test.js +176 -0
  182. package/dist/components/forms/__tests__/Fieldset.test.js +37 -0
  183. package/dist/components/forms/__tests__/Form.test.js +46 -0
  184. package/dist/components/forms/__tests__/FormActionBar.test.js +22 -0
  185. package/dist/components/forms/__tests__/Listbox.test.js +303 -0
  186. package/dist/components/forms/__tests__/MultiSelect.test.js +281 -0
  187. package/dist/components/forms/__tests__/SearchInput.test.js +92 -0
  188. package/dist/components/forms/__tests__/SignaturePad.test.js +338 -0
  189. package/dist/components/forms/__tests__/StagedControlReview.test.js +37 -3
  190. package/dist/components/forms/__tests__/camera-capture-session.test.js +207 -0
  191. package/dist/components/forms/__tests__/capture-form-retry.test.js +166 -0
  192. package/dist/components/forms/__tests__/capture-form.fixture.svelte +38 -0
  193. package/dist/components/forms/__tests__/capture-form.fixture.svelte.d.ts +10 -0
  194. package/dist/components/forms/__tests__/capture-form.fixture.svelte.d.ts.map +1 -0
  195. package/dist/components/forms/__tests__/capture-test-env.d.ts +70 -0
  196. package/dist/components/forms/__tests__/capture-test-env.d.ts.map +1 -0
  197. package/dist/components/forms/__tests__/capture-test-env.js +122 -0
  198. package/dist/components/forms/__tests__/capture-touch.fixture.svelte +15 -0
  199. package/dist/components/forms/__tests__/capture-touch.fixture.svelte.d.ts +8 -0
  200. package/dist/components/forms/__tests__/capture-touch.fixture.svelte.d.ts.map +1 -0
  201. package/dist/components/forms/__tests__/combobox-form.fixture.svelte +29 -0
  202. package/dist/components/forms/__tests__/combobox-form.fixture.svelte.d.ts +14 -0
  203. package/dist/components/forms/__tests__/combobox-form.fixture.svelte.d.ts.map +1 -0
  204. package/dist/components/forms/__tests__/combobox-labels.fixture.svelte +19 -0
  205. package/dist/components/forms/__tests__/combobox-labels.fixture.svelte.d.ts +11 -0
  206. package/dist/components/forms/__tests__/combobox-labels.fixture.svelte.d.ts.map +1 -0
  207. package/dist/components/forms/__tests__/composite-registration.fixture.svelte +29 -0
  208. package/dist/components/forms/__tests__/composite-registration.fixture.svelte.d.ts +8 -0
  209. package/dist/components/forms/__tests__/composite-registration.fixture.svelte.d.ts.map +1 -0
  210. package/dist/components/forms/__tests__/control-interaction.test.js +19 -1
  211. package/dist/components/forms/__tests__/control-proposals.test.js +63 -0
  212. package/dist/components/forms/__tests__/dictation-recording.test.js +582 -0
  213. package/dist/components/forms/__tests__/dictation.test.js +486 -0
  214. package/dist/components/forms/__tests__/form-attachment.fixture.svelte +28 -0
  215. package/dist/components/forms/__tests__/form-attachment.fixture.svelte.d.ts +11 -0
  216. package/dist/components/forms/__tests__/form-attachment.fixture.svelte.d.ts.map +1 -0
  217. package/dist/components/forms/__tests__/form-retry-form.fixture.svelte +31 -0
  218. package/dist/components/forms/__tests__/form-retry-form.fixture.svelte.d.ts +13 -0
  219. package/dist/components/forms/__tests__/form-retry-form.fixture.svelte.d.ts.map +1 -0
  220. package/dist/components/forms/__tests__/form-retry-form.test.js +107 -0
  221. package/dist/components/forms/__tests__/hidden-controls-form-retry.test.js +69 -0
  222. package/dist/components/forms/__tests__/hidden-controls-form.fixture.svelte +29 -0
  223. package/dist/components/forms/__tests__/hidden-controls-form.fixture.svelte.d.ts +9 -0
  224. package/dist/components/forms/__tests__/hidden-controls-form.fixture.svelte.d.ts.map +1 -0
  225. package/dist/components/forms/__tests__/listbox-form.fixture.svelte +27 -0
  226. package/dist/components/forms/__tests__/listbox-form.fixture.svelte.d.ts +13 -0
  227. package/dist/components/forms/__tests__/listbox-form.fixture.svelte.d.ts.map +1 -0
  228. package/dist/components/forms/__tests__/long-press.test.js +175 -0
  229. package/dist/components/forms/__tests__/multiselect-form.fixture.svelte +27 -0
  230. package/dist/components/forms/__tests__/multiselect-form.fixture.svelte.d.ts +13 -0
  231. package/dist/components/forms/__tests__/multiselect-form.fixture.svelte.d.ts.map +1 -0
  232. package/dist/components/forms/__tests__/native-file-field.test.js +177 -0
  233. package/dist/components/forms/__tests__/place-picker.fixture.svelte +33 -0
  234. package/dist/components/forms/__tests__/place-picker.fixture.svelte.d.ts +12 -0
  235. package/dist/components/forms/__tests__/place-picker.fixture.svelte.d.ts.map +1 -0
  236. package/dist/components/forms/__tests__/segmented-posting.fixture.svelte +28 -0
  237. package/dist/components/forms/__tests__/segmented-posting.fixture.svelte.d.ts +12 -0
  238. package/dist/components/forms/__tests__/segmented-posting.fixture.svelte.d.ts.map +1 -0
  239. package/dist/components/forms/__tests__/segmented-posting.test.js +92 -0
  240. package/dist/components/forms/__tests__/signature-pad-logic.test.js +54 -0
  241. package/dist/components/forms/__tests__/touch-density.fixture.svelte +34 -0
  242. package/dist/components/forms/__tests__/touch-density.fixture.svelte.d.ts +8 -0
  243. package/dist/components/forms/__tests__/touch-density.fixture.svelte.d.ts.map +1 -0
  244. package/dist/components/forms/__tests__/touch-density.test.js +66 -0
  245. package/dist/components/forms/audio-capture.d.ts +69 -0
  246. package/dist/components/forms/audio-capture.d.ts.map +1 -0
  247. package/dist/components/forms/audio-capture.js +193 -0
  248. package/dist/components/forms/camera-capture-session.d.ts +81 -0
  249. package/dist/components/forms/camera-capture-session.d.ts.map +1 -0
  250. package/dist/components/forms/camera-capture-session.js +130 -0
  251. package/dist/components/forms/control-interaction.d.ts +6 -0
  252. package/dist/components/forms/control-interaction.d.ts.map +1 -1
  253. package/dist/components/forms/control-interaction.js +12 -1
  254. package/dist/components/forms/control-proposals.d.ts +55 -0
  255. package/dist/components/forms/control-proposals.d.ts.map +1 -0
  256. package/dist/components/forms/control-proposals.js +188 -0
  257. package/dist/components/forms/dictation-transcribe.d.ts +36 -0
  258. package/dist/components/forms/dictation-transcribe.d.ts.map +1 -0
  259. package/dist/components/forms/dictation-transcribe.js +65 -0
  260. package/dist/components/forms/dictation.svelte.d.ts +200 -0
  261. package/dist/components/forms/dictation.svelte.d.ts.map +1 -0
  262. package/dist/components/forms/dictation.svelte.js +686 -0
  263. package/dist/components/forms/form-retry/__tests__/boundaries.test.js +23 -0
  264. package/dist/components/forms/form-retry/__tests__/content-digest.test.js +70 -0
  265. package/dist/components/forms/form-retry/__tests__/controller.test.js +802 -0
  266. package/dist/components/forms/form-retry/__tests__/fake-kit.d.ts +82 -0
  267. package/dist/components/forms/form-retry/__tests__/fake-kit.d.ts.map +1 -0
  268. package/dist/components/forms/form-retry/__tests__/fake-kit.js +180 -0
  269. package/dist/components/forms/form-retry/__tests__/form-draft.test.js +169 -0
  270. package/dist/components/forms/form-retry/__tests__/ssr.test.js +37 -0
  271. package/dist/components/forms/form-retry/__tests__/storage.d.ts +26 -0
  272. package/dist/components/forms/form-retry/__tests__/storage.d.ts.map +1 -0
  273. package/dist/components/forms/form-retry/__tests__/storage.js +63 -0
  274. package/dist/components/forms/form-retry/__tests__/submission-key.test.js +236 -0
  275. package/dist/components/forms/form-retry/__tests__/submitted-draft.test.js +334 -0
  276. package/dist/components/forms/form-retry/content-digest.d.ts +54 -0
  277. package/dist/components/forms/form-retry/content-digest.d.ts.map +1 -0
  278. package/dist/components/forms/form-retry/content-digest.js +169 -0
  279. package/dist/components/forms/form-retry/controller.d.ts +214 -0
  280. package/dist/components/forms/form-retry/controller.d.ts.map +1 -0
  281. package/dist/components/forms/form-retry/controller.js +404 -0
  282. package/dist/components/forms/form-retry/form-draft.d.ts +68 -0
  283. package/dist/components/forms/form-retry/form-draft.d.ts.map +1 -0
  284. package/dist/components/forms/form-retry/form-draft.js +161 -0
  285. package/dist/components/forms/form-retry/index.d.ts +19 -0
  286. package/dist/components/forms/form-retry/index.d.ts.map +1 -0
  287. package/dist/components/forms/form-retry/index.js +16 -0
  288. package/dist/components/forms/form-retry/submission-key.d.ts +244 -0
  289. package/dist/components/forms/form-retry/submission-key.d.ts.map +1 -0
  290. package/dist/components/forms/form-retry/submission-key.js +342 -0
  291. package/dist/components/forms/form-retry/submitted-draft.d.ts +112 -0
  292. package/dist/components/forms/form-retry/submitted-draft.d.ts.map +1 -0
  293. package/dist/components/forms/form-retry/submitted-draft.js +270 -0
  294. package/dist/components/forms/form-retry/types.d.ts +84 -0
  295. package/dist/components/forms/form-retry/types.d.ts.map +1 -0
  296. package/dist/components/forms/form-retry/types.js +13 -0
  297. package/dist/components/forms/index.d.ts +21 -2
  298. package/dist/components/forms/index.d.ts.map +1 -1
  299. package/dist/components/forms/index.js +22 -1
  300. package/dist/components/forms/insert-text.d.ts +12 -0
  301. package/dist/components/forms/insert-text.d.ts.map +1 -0
  302. package/dist/components/forms/insert-text.js +38 -0
  303. package/dist/components/forms/long-press.d.ts +88 -0
  304. package/dist/components/forms/long-press.d.ts.map +1 -0
  305. package/dist/components/forms/long-press.js +213 -0
  306. package/dist/components/forms/native-file-field.d.ts +94 -0
  307. package/dist/components/forms/native-file-field.d.ts.map +1 -0
  308. package/dist/components/forms/native-file-field.js +147 -0
  309. package/dist/components/forms/ready-beep.d.ts +24 -0
  310. package/dist/components/forms/ready-beep.d.ts.map +1 -0
  311. package/dist/components/forms/ready-beep.js +82 -0
  312. package/dist/components/forms/signature-pad-logic.d.ts +50 -0
  313. package/dist/components/forms/signature-pad-logic.d.ts.map +1 -0
  314. package/dist/components/forms/signature-pad-logic.js +48 -0
  315. package/dist/components/forms/types.d.ts +41 -0
  316. package/dist/components/forms/types.d.ts.map +1 -1
  317. package/dist/components/layout/PageHeader.svelte +151 -17
  318. package/dist/components/layout/PageHeader.svelte.d.ts +47 -7
  319. package/dist/components/layout/PageHeader.svelte.d.ts.map +1 -1
  320. package/dist/components/layout/__tests__/PageHeader.test.js +87 -1
  321. package/dist/components/layout/index.d.ts +1 -0
  322. package/dist/components/layout/index.d.ts.map +1 -1
  323. package/dist/components/layout/index.js +1 -0
  324. package/dist/components/layout/page-header-context.d.ts +25 -0
  325. package/dist/components/layout/page-header-context.d.ts.map +1 -0
  326. package/dist/components/layout/page-header-context.js +16 -0
  327. package/dist/components/nav/FilterChips.svelte +8 -1
  328. package/dist/components/nav/FilterChips.svelte.d.ts +2 -0
  329. package/dist/components/nav/FilterChips.svelte.d.ts.map +1 -1
  330. package/dist/components/nav/Tabs.svelte +241 -0
  331. package/dist/components/nav/Tabs.svelte.d.ts +15 -0
  332. package/dist/components/nav/Tabs.svelte.d.ts.map +1 -1
  333. package/dist/components/nav/__tests__/LinkTabs.test.js +117 -0
  334. package/dist/components/nav/index.d.ts +1 -0
  335. package/dist/components/nav/index.d.ts.map +1 -1
  336. package/dist/components/nav/index.js +1 -0
  337. package/dist/components/nav/tabs-overflow.d.ts +12 -0
  338. package/dist/components/nav/tabs-overflow.d.ts.map +1 -0
  339. package/dist/components/nav/tabs-overflow.js +17 -0
  340. package/dist/components/nav/types.d.ts +8 -0
  341. package/dist/components/nav/types.d.ts.map +1 -1
  342. package/dist/components/ui/Button.svelte +16 -2
  343. package/dist/components/ui/Button.svelte.d.ts +2 -0
  344. package/dist/components/ui/Button.svelte.d.ts.map +1 -1
  345. package/dist/components/ui/Card.svelte +14 -5
  346. package/dist/components/ui/Dropdown.svelte +55 -1
  347. package/dist/components/ui/Dropdown.svelte.d.ts +8 -0
  348. package/dist/components/ui/Dropdown.svelte.d.ts.map +1 -1
  349. package/dist/components/ui/IconToggle.svelte +139 -0
  350. package/dist/components/ui/IconToggle.svelte.d.ts +32 -0
  351. package/dist/components/ui/IconToggle.svelte.d.ts.map +1 -0
  352. package/dist/components/ui/IconToggleGroup.svelte +56 -0
  353. package/dist/components/ui/IconToggleGroup.svelte.d.ts +21 -0
  354. package/dist/components/ui/IconToggleGroup.svelte.d.ts.map +1 -0
  355. package/dist/components/ui/Pagination.svelte +1 -1
  356. package/dist/components/ui/Popover.svelte +17 -1
  357. package/dist/components/ui/Popover.svelte.d.ts +8 -0
  358. package/dist/components/ui/Popover.svelte.d.ts.map +1 -1
  359. package/dist/components/ui/__tests__/IconToggle.test.js +59 -0
  360. package/dist/components/ui/__tests__/IconToggleGroup.test.js +30 -0
  361. package/dist/components/ui/__tests__/Popover.test.js +44 -0
  362. package/dist/components/ui/__tests__/dropdown-popover-icon.test.js +125 -0
  363. package/dist/components/ui/__tests__/phone-touch-targets.test.js +39 -0
  364. package/dist/components/ui/index.d.ts +2 -0
  365. package/dist/components/ui/index.d.ts.map +1 -1
  366. package/dist/components/ui/index.js +2 -0
  367. package/dist/i18n/strings.ui.d.ts +65 -0
  368. package/dist/i18n/strings.ui.d.ts.map +1 -1
  369. package/dist/i18n/strings.ui.js +72 -0
  370. package/dist/styles/tokens.css +2 -0
  371. package/dist/svelte/__tests__/playground.test.js +3 -1
  372. package/dist/svelte/playground/CalendarPreview.svelte +140 -0
  373. package/dist/svelte/playground/CalendarPreview.svelte.d.ts +4 -0
  374. package/dist/svelte/playground/CalendarPreview.svelte.d.ts.map +1 -0
  375. package/dist/svelte/playground/CapturePreview.svelte +56 -0
  376. package/dist/svelte/playground/CapturePreview.svelte.d.ts +4 -0
  377. package/dist/svelte/playground/CapturePreview.svelte.d.ts.map +1 -0
  378. package/dist/svelte/playground.d.ts.map +1 -1
  379. package/dist/svelte/playground.js +20 -0
  380. package/dist/themes/ThemeProvider.svelte +9 -0
  381. package/dist/themes/ThemeProvider.svelte.d.ts +2 -0
  382. package/dist/themes/ThemeProvider.svelte.d.ts.map +1 -1
  383. package/dist/themes/css-generator.d.ts.map +1 -1
  384. package/dist/themes/css-generator.js +3 -0
  385. package/dist/themes/styles/glass.css +4 -0
  386. package/dist/themes/styles/happyvertical.css +4 -0
  387. package/dist/themes/styles/material.css +4 -0
  388. package/dist/themes/styles/smrt.css +4 -0
  389. package/dist/themes/styles/studio.css +4 -0
  390. package/dist/types-generic.d.ts +2 -0
  391. package/dist/types-generic.d.ts.map +1 -1
  392. package/package.json +9 -3
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Put text into a text field at the cursor, the way typing would.
3
+ *
4
+ * - Replaces the selection, if any.
5
+ * - A field that has never had the cursor in it gets the text at the end.
6
+ * - Adds a space before the text when it would otherwise run into a word,
7
+ * and after it when the next character is a letter or digit.
8
+ * - Leaves the cursor after the inserted text and fires `input`, so bound
9
+ * values (`bind:value`) and listeners see the change.
10
+ */
11
+ export function insertTextAtCursor(field, text) {
12
+ const words = text.trim();
13
+ if (!words)
14
+ return;
15
+ const value = field.value;
16
+ const focused = typeof document !== 'undefined' && document.activeElement === field;
17
+ let start = field.selectionStart ?? value.length;
18
+ let end = field.selectionEnd ?? value.length;
19
+ // An untouched field reports 0/0; dictation then belongs at the end.
20
+ if (!focused && start === 0 && end === 0 && value.length > 0) {
21
+ start = value.length;
22
+ end = value.length;
23
+ }
24
+ const before = value.slice(0, start);
25
+ const after = value.slice(end);
26
+ const lead = before.length > 0 && !/\s$/.test(before) ? ' ' : '';
27
+ const trail = /^[\p{L}\p{N}]/u.test(after) ? ' ' : '';
28
+ const inserted = `${lead}${words}${trail}`;
29
+ field.value = `${before}${inserted}${after}`;
30
+ const caret = before.length + inserted.length;
31
+ try {
32
+ field.setSelectionRange(caret, caret);
33
+ }
34
+ catch {
35
+ // Some input types do not support selection; the value is still set.
36
+ }
37
+ field.dispatchEvent(new Event('input', { bubbles: true }));
38
+ }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Long-press detection for pointer (mouse, pen) and touch input.
3
+ *
4
+ * A press counts as a long press when the primary pointer stays down, and
5
+ * within `moveTolerance` pixels of where it went down, for `delay`
6
+ * milliseconds (default 500ms, 10px). Moving further first is a drag or a
7
+ * scroll, never a long press, so a host's own drag gestures keep working.
8
+ * A native `dragstart` cancels a pending press for the same reason.
9
+ *
10
+ * - Only the primary button (left mouse, a finger, a pen tip) starts one; a
11
+ * right click is left alone, and so is the context menu it opens.
12
+ * - The `click` that follows a fired long press is swallowed so the release
13
+ * does not also "tap" the target.
14
+ * - `preventContextMenu` suppresses the context menu a touch long press
15
+ * opens (Android, desktop touch screens) — but only during a press this
16
+ * detector is tracking. Opt in only where the long press replaces that
17
+ * menu (for example on a picture), never on a text field.
18
+ *
19
+ * Framework-free: `createLongPress` returns handlers a host wires itself, and
20
+ * `longPress` is the Svelte action (`use:longPress={options}`) that wires
21
+ * them to an element.
22
+ */
23
+ /** What a long press was made on. */
24
+ export interface LongPressDetail {
25
+ /** The element the press is about (from `filter`, else the event target). */
26
+ target: Element;
27
+ /** `mouse`, `pen` or `touch`. */
28
+ pointerType: string;
29
+ clientX: number;
30
+ clientY: number;
31
+ }
32
+ export interface LongPressOptions {
33
+ /** How long the pointer must stay down, in ms. Default 500. */
34
+ delay?: number;
35
+ /** How far (px) the pointer may move before it is a drag instead. Default 10. */
36
+ moveTolerance?: number;
37
+ /**
38
+ * Which presses count. Return the element the press is about, or `null` /
39
+ * `false` to ignore the press (for example: only pictures inside an
40
+ * editor). Default: every press, about its event target.
41
+ */
42
+ filter?: (event: PointerEvent) => Element | null | boolean;
43
+ /** The pointer stayed down long enough. */
44
+ onLongPress: (detail: LongPressDetail) => void;
45
+ /** The pointer came up after a long press fired (a user gesture). */
46
+ onRelease?: (detail: LongPressDetail) => void;
47
+ /** The pointer went down on a counted target (before the delay). */
48
+ onPressStart?: (detail: LongPressDetail) => void;
49
+ /** A pending press ended without firing (a tap, a drag, a scroll). */
50
+ onCancel?: () => void;
51
+ /** Suppress the context menu during a tracked press. Default false. */
52
+ preventContextMenu?: boolean;
53
+ /** Ignore every press. */
54
+ disabled?: boolean;
55
+ }
56
+ export declare const LONG_PRESS_DEFAULT_DELAY_MS = 500;
57
+ export declare const LONG_PRESS_DEFAULT_MOVE_TOLERANCE_PX = 10;
58
+ export interface LongPressController {
59
+ handlePointerDown(event: PointerEvent): void;
60
+ handlePointerMove(event: PointerEvent): void;
61
+ handlePointerUp(event: PointerEvent): void;
62
+ handlePointerCancel(event: PointerEvent): void;
63
+ handleDragStart(): void;
64
+ handleContextMenu(event: Event): void;
65
+ /** Wire in the capture phase so the swallowed click never reaches the target. */
66
+ handleClick(event: Event): void;
67
+ /** Forget any press in progress (no callbacks). */
68
+ cancel(): void;
69
+ update(options: LongPressOptions): void;
70
+ /** A press is down and waiting for the delay. */
71
+ readonly pending: boolean;
72
+ /** The current press already fired (until the pointer comes up). */
73
+ readonly fired: boolean;
74
+ }
75
+ /** Long-press state and handlers (see the module comment). */
76
+ export declare function createLongPress(initial: LongPressOptions): LongPressController;
77
+ /**
78
+ * Svelte action: `use:longPress={{ onLongPress: () => … }}`.
79
+ *
80
+ * Listens on the element (presses bubble up from its children, so wrapping a
81
+ * field or an editor works). Pointer moves and releases are also tracked on
82
+ * the window so a release outside the element still ends the press.
83
+ */
84
+ export declare function longPress(node: HTMLElement, options: LongPressOptions): {
85
+ update(next: LongPressOptions): void;
86
+ destroy(): void;
87
+ };
88
+ //# sourceMappingURL=long-press.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"long-press.d.ts","sourceRoot":"","sources":["../../../src/components/forms/long-press.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,qCAAqC;AACrC,MAAM,WAAW,eAAe;IAC9B,6EAA6E;IAC7E,MAAM,EAAE,OAAO,CAAC;IAChB,iCAAiC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iFAAiF;IACjF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,GAAG,IAAI,GAAG,OAAO,CAAC;IAC3D,2CAA2C;IAC3C,WAAW,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,CAAC;IAC/C,qEAAqE;IACrE,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,CAAC;IAC9C,oEAAoE;IACpE,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,CAAC;IACjD,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,uEAAuE;IACvE,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,0BAA0B;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAC/C,eAAO,MAAM,oCAAoC,KAAK,CAAC;AAEvD,MAAM,WAAW,mBAAmB;IAClC,iBAAiB,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;IAC7C,iBAAiB,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;IAC7C,eAAe,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;IAC3C,mBAAmB,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;IAC/C,eAAe,IAAI,IAAI,CAAC;IACxB,iBAAiB,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACtC,iFAAiF;IACjF,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAChC,mDAAmD;IACnD,MAAM,IAAI,IAAI,CAAC;IACf,MAAM,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACxC,iDAAiD;IACjD,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,oEAAoE;IACpE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED,8DAA8D;AAC9D,wBAAgB,eAAe,CAC7B,OAAO,EAAE,gBAAgB,GACxB,mBAAmB,CA6IrB;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,gBAAgB;iBAmBrD,gBAAgB;;EAchC"}
@@ -0,0 +1,213 @@
1
+ /**
2
+ * Long-press detection for pointer (mouse, pen) and touch input.
3
+ *
4
+ * A press counts as a long press when the primary pointer stays down, and
5
+ * within `moveTolerance` pixels of where it went down, for `delay`
6
+ * milliseconds (default 500ms, 10px). Moving further first is a drag or a
7
+ * scroll, never a long press, so a host's own drag gestures keep working.
8
+ * A native `dragstart` cancels a pending press for the same reason.
9
+ *
10
+ * - Only the primary button (left mouse, a finger, a pen tip) starts one; a
11
+ * right click is left alone, and so is the context menu it opens.
12
+ * - The `click` that follows a fired long press is swallowed so the release
13
+ * does not also "tap" the target.
14
+ * - `preventContextMenu` suppresses the context menu a touch long press
15
+ * opens (Android, desktop touch screens) — but only during a press this
16
+ * detector is tracking. Opt in only where the long press replaces that
17
+ * menu (for example on a picture), never on a text field.
18
+ *
19
+ * Framework-free: `createLongPress` returns handlers a host wires itself, and
20
+ * `longPress` is the Svelte action (`use:longPress={options}`) that wires
21
+ * them to an element.
22
+ */
23
+ export const LONG_PRESS_DEFAULT_DELAY_MS = 500;
24
+ export const LONG_PRESS_DEFAULT_MOVE_TOLERANCE_PX = 10;
25
+ /** Long-press state and handlers (see the module comment). */
26
+ export function createLongPress(initial) {
27
+ let options = initial;
28
+ let timer = null;
29
+ let pointerId = null;
30
+ let startX = 0;
31
+ let startY = 0;
32
+ let detail = null;
33
+ let fired = false;
34
+ let swallowClick = false;
35
+ let swallowTimer = null;
36
+ function clearTimer() {
37
+ if (timer)
38
+ clearTimeout(timer);
39
+ timer = null;
40
+ }
41
+ function reset() {
42
+ clearTimer();
43
+ pointerId = null;
44
+ detail = null;
45
+ fired = false;
46
+ }
47
+ function cancelPending() {
48
+ if (!timer)
49
+ return;
50
+ reset();
51
+ options.onCancel?.();
52
+ }
53
+ function resolveTarget(event) {
54
+ const picked = options.filter ? options.filter(event) : true;
55
+ if (!picked)
56
+ return null;
57
+ if (picked === true) {
58
+ return event.target instanceof Element ? event.target : null;
59
+ }
60
+ return picked;
61
+ }
62
+ function armClickSwallow() {
63
+ swallowClick = true;
64
+ if (swallowTimer)
65
+ clearTimeout(swallowTimer);
66
+ // A click that never comes (the pointer moved off) must not eat a later one.
67
+ swallowTimer = setTimeout(() => {
68
+ swallowClick = false;
69
+ swallowTimer = null;
70
+ }, 400);
71
+ }
72
+ return {
73
+ handlePointerDown(event) {
74
+ if (options.disabled)
75
+ return;
76
+ if (!event.isPrimary)
77
+ return;
78
+ if (event.pointerType === 'mouse' && event.button !== 0)
79
+ return;
80
+ const target = resolveTarget(event);
81
+ if (!target)
82
+ return;
83
+ reset();
84
+ pointerId = event.pointerId;
85
+ startX = event.clientX;
86
+ startY = event.clientY;
87
+ detail = {
88
+ target,
89
+ pointerType: event.pointerType || 'mouse',
90
+ clientX: event.clientX,
91
+ clientY: event.clientY,
92
+ };
93
+ options.onPressStart?.(detail);
94
+ const pressed = detail;
95
+ timer = setTimeout(() => {
96
+ timer = null;
97
+ fired = true;
98
+ options.onLongPress(pressed);
99
+ }, options.delay ?? LONG_PRESS_DEFAULT_DELAY_MS);
100
+ },
101
+ handlePointerMove(event) {
102
+ if (!timer || event.pointerId !== pointerId)
103
+ return;
104
+ const tolerance = options.moveTolerance ?? LONG_PRESS_DEFAULT_MOVE_TOLERANCE_PX;
105
+ if (Math.hypot(event.clientX - startX, event.clientY - startY) > tolerance) {
106
+ cancelPending();
107
+ }
108
+ },
109
+ handlePointerUp(event) {
110
+ if (event.pointerId !== pointerId)
111
+ return;
112
+ if (timer) {
113
+ cancelPending();
114
+ return;
115
+ }
116
+ if (fired && detail) {
117
+ const released = detail;
118
+ armClickSwallow();
119
+ reset();
120
+ options.onRelease?.(released);
121
+ return;
122
+ }
123
+ reset();
124
+ },
125
+ handlePointerCancel(event) {
126
+ if (event.pointerId !== pointerId)
127
+ return;
128
+ if (timer) {
129
+ cancelPending();
130
+ return;
131
+ }
132
+ if (fired && detail) {
133
+ const released = detail;
134
+ reset();
135
+ options.onRelease?.(released);
136
+ return;
137
+ }
138
+ reset();
139
+ },
140
+ handleDragStart() {
141
+ cancelPending();
142
+ },
143
+ handleContextMenu(event) {
144
+ if (!options.preventContextMenu)
145
+ return;
146
+ if (timer || fired)
147
+ event.preventDefault();
148
+ },
149
+ handleClick(event) {
150
+ if (!swallowClick)
151
+ return;
152
+ swallowClick = false;
153
+ if (swallowTimer)
154
+ clearTimeout(swallowTimer);
155
+ swallowTimer = null;
156
+ event.preventDefault();
157
+ event.stopPropagation();
158
+ },
159
+ cancel() {
160
+ reset();
161
+ },
162
+ update(next) {
163
+ options = next;
164
+ if (next.disabled)
165
+ reset();
166
+ },
167
+ get pending() {
168
+ return timer !== null;
169
+ },
170
+ get fired() {
171
+ return fired;
172
+ },
173
+ };
174
+ }
175
+ /**
176
+ * Svelte action: `use:longPress={{ onLongPress: () => … }}`.
177
+ *
178
+ * Listens on the element (presses bubble up from its children, so wrapping a
179
+ * field or an editor works). Pointer moves and releases are also tracked on
180
+ * the window so a release outside the element still ends the press.
181
+ */
182
+ export function longPress(node, options) {
183
+ const controller = createLongPress(options);
184
+ const down = (event) => controller.handlePointerDown(event);
185
+ const move = (event) => controller.handlePointerMove(event);
186
+ const up = (event) => controller.handlePointerUp(event);
187
+ const cancel = (event) => controller.handlePointerCancel(event);
188
+ const drag = () => controller.handleDragStart();
189
+ const menu = (event) => controller.handleContextMenu(event);
190
+ const click = (event) => controller.handleClick(event);
191
+ node.addEventListener('pointerdown', down);
192
+ node.addEventListener('dragstart', drag);
193
+ node.addEventListener('contextmenu', menu);
194
+ node.addEventListener('click', click, true);
195
+ window.addEventListener('pointermove', move);
196
+ window.addEventListener('pointerup', up);
197
+ window.addEventListener('pointercancel', cancel);
198
+ return {
199
+ update(next) {
200
+ controller.update(next);
201
+ },
202
+ destroy() {
203
+ controller.cancel();
204
+ node.removeEventListener('pointerdown', down);
205
+ node.removeEventListener('dragstart', drag);
206
+ node.removeEventListener('contextmenu', menu);
207
+ node.removeEventListener('click', click, true);
208
+ window.removeEventListener('pointermove', move);
209
+ window.removeEventListener('pointerup', up);
210
+ window.removeEventListener('pointercancel', cancel);
211
+ },
212
+ };
213
+ }
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Framework-free helpers that let a capture component (`CameraCapture`,
3
+ * `SignaturePad`) post a `File` it created through a plain
4
+ * `<form method="POST" enctype="multipart/form-data">`, without the caller
5
+ * wiring a hidden input or intercepting submit.
6
+ *
7
+ * Two strategies, chosen once per page by {@link detectNativeFileFieldStrategy}:
8
+ *
9
+ * - `data-transfer` (preferred): the component renders a hidden
10
+ * `<input type="file" name>` and fills it with `new DataTransfer()`, so the
11
+ * browser posts the file exactly like a user-picked one. Needs a constructible
12
+ * `DataTransfer` whose `files` an input accepts (Chrome 60+, Firefox 62+,
13
+ * Safari 14.1+).
14
+ * - `formdata-event` (fallback when `DataTransfer` is unavailable): the hidden
15
+ * input carries no `name`, and a capture-phase `formdata` listener appends the
16
+ * file to the form's entry list while the browser builds it. The browser fires
17
+ * `formdata` for native navigation submits as well as `new FormData(form)`, so
18
+ * the request is the same.
19
+ * - `none`: neither API exists. Nothing is posted for the field; the
20
+ * component's `onCapture` callback remains the only channel. Components expose
21
+ * the active strategy as `data-smrt-file-field` for diagnostics.
22
+ *
23
+ * In both posting strategies an uncommitted field posts what an empty native
24
+ * file input posts (an empty, unnamed `application/octet-stream` file), so the
25
+ * server sees one shape regardless of strategy; inside a disabled `<fieldset>`
26
+ * both post nothing, as a disabled native control does. A reset of the owning form
27
+ * empties the field like a native file input ({@link attachFormResetListener}).
28
+ */
29
+ /** How a capture component posts its file in a native form. */
30
+ export type NativeFileFieldStrategy = 'data-transfer' | 'formdata-event' | 'none';
31
+ /** Globals the strategy probe reads; injectable for tests. */
32
+ export interface NativeFileFieldEnvironment {
33
+ DataTransfer?: unknown;
34
+ FormDataEvent?: unknown;
35
+ File?: unknown;
36
+ /** Creates a detached `<input type="file">` for the assignment probe. */
37
+ createFileInput?: () => HTMLInputElement;
38
+ }
39
+ /**
40
+ * Put `file` into `input` through a fresh `DataTransfer`. Returns `true` only
41
+ * when the input now holds exactly one file. Old engines expose a
42
+ * `DataTransfer` interface whose constructor throws ("Illegal constructor"), or
43
+ * reject the `files` assignment; both report `false`.
44
+ */
45
+ export declare function assignFileWithDataTransfer(input: HTMLInputElement, file: File, DataTransferCtor?: unknown): boolean;
46
+ /**
47
+ * Empty a file input so it posts the native "no file chosen" entry. Scripts may
48
+ * always set a file input's value to the empty string (only non-empty values
49
+ * throw).
50
+ */
51
+ export declare function clearFileInput(input: HTMLInputElement): void;
52
+ /** Pick the strategy for this page. Safe during SSR (returns `none`). */
53
+ export declare function detectNativeFileFieldStrategy(env?: NativeFileFieldEnvironment): NativeFileFieldStrategy;
54
+ /** The entry a `formdata`-event field contributes, read at submit time. */
55
+ export interface FormDataFieldEntry {
56
+ /** The form whose entry list receives the file (the hidden input's `form`). */
57
+ form: HTMLFormElement | null;
58
+ name: string;
59
+ /** The committed file, or `null` to post the native empty-file entry. */
60
+ file: File | null;
61
+ /**
62
+ * The component's hidden input. While it is `:disabled` (inside a disabled
63
+ * `<fieldset>`), nothing is appended — the browser leaves a disabled native
64
+ * control out of the entry list, and this appended entry must match.
65
+ */
66
+ source?: Element | null;
67
+ }
68
+ /** The native "no file chosen" entry: an empty, unnamed octet-stream file. */
69
+ export declare function emptyFileEntry(): File;
70
+ /**
71
+ * Install the `formdata`-event fallback. The listener runs in the capture
72
+ * phase on `target` (normally `document`), so it sees the event whichever form
73
+ * currently owns the field, then appends only for that form. Returns a disposer.
74
+ */
75
+ export declare function attachFormDataFallback(target: Pick<EventTarget, 'addEventListener' | 'removeEventListener'>, readEntry: () => FormDataFieldEntry | null): () => void;
76
+ /**
77
+ * Call `onReset` whenever the form returned by `readForm` resets
78
+ * (`form.reset()`, a reset button, or SvelteKit `enhance`'s `update()` after a
79
+ * success). A native file input is emptied by its form's reset; a capture
80
+ * component must empty its own committed state at the same moment, or it keeps
81
+ * showing a file that no longer posts.
82
+ *
83
+ * Like {@link attachFormDataFallback}, the listener runs in the capture phase
84
+ * on `target` (normally `document`) and reads the owning form at dispatch
85
+ * time, so a field moved between forms needs no re-wiring and a page listener
86
+ * that stops propagation cannot hide the reset. `reset` fires before the
87
+ * browser resets the controls, and `onReset` runs even if a later listener
88
+ * cancels it: the component and the posted entry are then both empty, which
89
+ * keeps what is shown equal to what posts. Returns a disposer.
90
+ */
91
+ export declare function attachFormResetListener(target: Pick<EventTarget, 'addEventListener' | 'removeEventListener'>, readForm: () => HTMLFormElement | null | undefined, onReset: () => void): () => void;
92
+ /** `photo` + `image/png` → `photo.png`; unknown types fall back to `bin`. */
93
+ export declare function fileNameForType(base: string, type: string): string;
94
+ //# sourceMappingURL=native-file-field.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-file-field.d.ts","sourceRoot":"","sources":["../../../src/components/forms/native-file-field.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,+DAA+D;AAC/D,MAAM,MAAM,uBAAuB,GAC/B,eAAe,GACf,gBAAgB,GAChB,MAAM,CAAC;AAEX,8DAA8D;AAC9D,MAAM,WAAW,0BAA0B;IACzC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,yEAAyE;IACzE,eAAe,CAAC,EAAE,MAAM,gBAAgB,CAAC;CAC1C;AAqBD;;;;;GAKG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,gBAAgB,EACvB,IAAI,EAAE,IAAI,EACV,gBAAgB,GAAE,OACH,GACd,OAAO,CAUT;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAE5D;AAED,yEAAyE;AACzE,wBAAgB,6BAA6B,CAC3C,GAAG,GAAE,0BAAiD,GACrD,uBAAuB,CAoBzB;AAED,2EAA2E;AAC3E,MAAM,WAAW,kBAAkB;IACjC,+EAA+E;IAC/E,IAAI,EAAE,eAAe,GAAG,IAAI,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,yEAAyE;IACzE,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAClB;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CACzB;AAED,8EAA8E;AAC9E,wBAAgB,cAAc,IAAI,IAAI,CAErC;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,kBAAkB,GAAG,qBAAqB,CAAC,EACrE,SAAS,EAAE,MAAM,kBAAkB,GAAG,IAAI,GACzC,MAAM,IAAI,CAYZ;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,kBAAkB,GAAG,qBAAqB,CAAC,EACrE,QAAQ,EAAE,MAAM,eAAe,GAAG,IAAI,GAAG,SAAS,EAClD,OAAO,EAAE,MAAM,IAAI,GAClB,MAAM,IAAI,CAOZ;AAQD,6EAA6E;AAC7E,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAElE"}
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Framework-free helpers that let a capture component (`CameraCapture`,
3
+ * `SignaturePad`) post a `File` it created through a plain
4
+ * `<form method="POST" enctype="multipart/form-data">`, without the caller
5
+ * wiring a hidden input or intercepting submit.
6
+ *
7
+ * Two strategies, chosen once per page by {@link detectNativeFileFieldStrategy}:
8
+ *
9
+ * - `data-transfer` (preferred): the component renders a hidden
10
+ * `<input type="file" name>` and fills it with `new DataTransfer()`, so the
11
+ * browser posts the file exactly like a user-picked one. Needs a constructible
12
+ * `DataTransfer` whose `files` an input accepts (Chrome 60+, Firefox 62+,
13
+ * Safari 14.1+).
14
+ * - `formdata-event` (fallback when `DataTransfer` is unavailable): the hidden
15
+ * input carries no `name`, and a capture-phase `formdata` listener appends the
16
+ * file to the form's entry list while the browser builds it. The browser fires
17
+ * `formdata` for native navigation submits as well as `new FormData(form)`, so
18
+ * the request is the same.
19
+ * - `none`: neither API exists. Nothing is posted for the field; the
20
+ * component's `onCapture` callback remains the only channel. Components expose
21
+ * the active strategy as `data-smrt-file-field` for diagnostics.
22
+ *
23
+ * In both posting strategies an uncommitted field posts what an empty native
24
+ * file input posts (an empty, unnamed `application/octet-stream` file), so the
25
+ * server sees one shape regardless of strategy; inside a disabled `<fieldset>`
26
+ * both post nothing, as a disabled native control does. A reset of the owning form
27
+ * empties the field like a native file input ({@link attachFormResetListener}).
28
+ */
29
+ function browserEnvironment() {
30
+ const scope = globalThis;
31
+ return {
32
+ DataTransfer: scope.DataTransfer,
33
+ FormDataEvent: scope.FormDataEvent,
34
+ File: scope.File,
35
+ createFileInput: typeof document === 'undefined'
36
+ ? undefined
37
+ : () => {
38
+ const input = document.createElement('input');
39
+ input.type = 'file';
40
+ return input;
41
+ },
42
+ };
43
+ }
44
+ /**
45
+ * Put `file` into `input` through a fresh `DataTransfer`. Returns `true` only
46
+ * when the input now holds exactly one file. Old engines expose a
47
+ * `DataTransfer` interface whose constructor throws ("Illegal constructor"), or
48
+ * reject the `files` assignment; both report `false`.
49
+ */
50
+ export function assignFileWithDataTransfer(input, file, DataTransferCtor = globalThis
51
+ .DataTransfer) {
52
+ if (typeof DataTransferCtor !== 'function')
53
+ return false;
54
+ try {
55
+ const transfer = new DataTransferCtor();
56
+ transfer.items.add(file);
57
+ input.files = transfer.files;
58
+ return input.files?.length === 1;
59
+ }
60
+ catch {
61
+ return false;
62
+ }
63
+ }
64
+ /**
65
+ * Empty a file input so it posts the native "no file chosen" entry. Scripts may
66
+ * always set a file input's value to the empty string (only non-empty values
67
+ * throw).
68
+ */
69
+ export function clearFileInput(input) {
70
+ input.value = '';
71
+ }
72
+ /** Pick the strategy for this page. Safe during SSR (returns `none`). */
73
+ export function detectNativeFileFieldStrategy(env = browserEnvironment()) {
74
+ const FileCtor = env.File;
75
+ if (env.createFileInput && typeof FileCtor === 'function') {
76
+ try {
77
+ const probe = new FileCtor([], 'probe.bin');
78
+ if (assignFileWithDataTransfer(env.createFileInput(), probe, env.DataTransfer)) {
79
+ return 'data-transfer';
80
+ }
81
+ }
82
+ catch {
83
+ // Fall through to the next strategy.
84
+ }
85
+ }
86
+ if (typeof env.FormDataEvent === 'function')
87
+ return 'formdata-event';
88
+ return 'none';
89
+ }
90
+ /** The native "no file chosen" entry: an empty, unnamed octet-stream file. */
91
+ export function emptyFileEntry() {
92
+ return new File([], '', { type: 'application/octet-stream' });
93
+ }
94
+ /**
95
+ * Install the `formdata`-event fallback. The listener runs in the capture
96
+ * phase on `target` (normally `document`), so it sees the event whichever form
97
+ * currently owns the field, then appends only for that form. Returns a disposer.
98
+ */
99
+ export function attachFormDataFallback(target, readEntry) {
100
+ const listener = (event) => {
101
+ const entry = readEntry();
102
+ if (!entry?.form || !entry.name || event.target !== entry.form)
103
+ return;
104
+ if (entry.source?.matches(':disabled'))
105
+ return;
106
+ const formData = event.formData;
107
+ if (!formData)
108
+ return;
109
+ const file = entry.file ?? emptyFileEntry();
110
+ formData.append(entry.name, file, file.name);
111
+ };
112
+ target.addEventListener('formdata', listener, true);
113
+ return () => target.removeEventListener('formdata', listener, true);
114
+ }
115
+ /**
116
+ * Call `onReset` whenever the form returned by `readForm` resets
117
+ * (`form.reset()`, a reset button, or SvelteKit `enhance`'s `update()` after a
118
+ * success). A native file input is emptied by its form's reset; a capture
119
+ * component must empty its own committed state at the same moment, or it keeps
120
+ * showing a file that no longer posts.
121
+ *
122
+ * Like {@link attachFormDataFallback}, the listener runs in the capture phase
123
+ * on `target` (normally `document`) and reads the owning form at dispatch
124
+ * time, so a field moved between forms needs no re-wiring and a page listener
125
+ * that stops propagation cannot hide the reset. `reset` fires before the
126
+ * browser resets the controls, and `onReset` runs even if a later listener
127
+ * cancels it: the component and the posted entry are then both empty, which
128
+ * keeps what is shown equal to what posts. Returns a disposer.
129
+ */
130
+ export function attachFormResetListener(target, readForm, onReset) {
131
+ const listener = (event) => {
132
+ const form = readForm();
133
+ if (form && event.target === form)
134
+ onReset();
135
+ };
136
+ target.addEventListener('reset', listener, true);
137
+ return () => target.removeEventListener('reset', listener, true);
138
+ }
139
+ const EXTENSIONS = {
140
+ 'image/jpeg': 'jpg',
141
+ 'image/png': 'png',
142
+ 'image/webp': 'webp',
143
+ };
144
+ /** `photo` + `image/png` → `photo.png`; unknown types fall back to `bin`. */
145
+ export function fileNameForType(base, type) {
146
+ return `${base}.${EXTENSIONS[type] ?? 'bin'}`;
147
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * A short "ready" beep, made with the Web Audio API (no sound files).
3
+ *
4
+ * Browsers only start audio after a user gesture. A long press fires from a
5
+ * timer while the finger is still down, which on touch screens is not a
6
+ * gesture yet, so `playReadyBeep` resolves `false` when the audio could not
7
+ * start; the host plays it again from the release (`pointerup` is a gesture).
8
+ * `primeReadyBeep` creates the audio context early, from a gesture, so later
9
+ * beeps start immediately.
10
+ */
11
+ /** Create (or wake) the audio context; call from a user gesture. */
12
+ export declare function primeReadyBeep(): void;
13
+ export interface ReadyBeepOptions {
14
+ /** Volume, 0–1. Default 0.12. */
15
+ volume?: number;
16
+ }
17
+ /**
18
+ * Play two quick rising tones (about 0.2s). Resolves `true` when it played,
19
+ * `false` when audio is unavailable or not allowed yet.
20
+ */
21
+ export declare function playReadyBeep(options?: ReadyBeepOptions): Promise<boolean>;
22
+ /** Tests: forget the shared audio context. */
23
+ export declare function resetReadyBeepForTests(): void;
24
+ //# sourceMappingURL=ready-beep.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ready-beep.d.ts","sourceRoot":"","sources":["../../../src/components/forms/ready-beep.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA4BH,oEAAoE;AACpE,wBAAgB,cAAc,IAAI,IAAI,CAKrC;AAED,MAAM,WAAW,gBAAgB;IAC/B,iCAAiC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAsB,aAAa,CACjC,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,OAAO,CAAC,CA6BlB;AAED,8CAA8C;AAC9C,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C"}