@happyvertical/smrt-ui 0.51.39 → 0.52.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 (212) hide show
  1. package/AGENTS.md +14 -2
  2. package/README.md +257 -5
  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 +118 -40
  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/ListSortSelect.svelte +121 -0
  31. package/dist/components/data/ListSortSelect.svelte.d.ts +22 -0
  32. package/dist/components/data/ListSortSelect.svelte.d.ts.map +1 -0
  33. package/dist/components/data/SortableHeader.svelte +169 -0
  34. package/dist/components/data/SortableHeader.svelte.d.ts +30 -0
  35. package/dist/components/data/SortableHeader.svelte.d.ts.map +1 -0
  36. package/dist/components/data/__tests__/CollectionList.test.js +37 -0
  37. package/dist/components/data/__tests__/DataTable.test.js +76 -0
  38. package/dist/components/data/__tests__/DataTableController.test.js +35 -0
  39. package/dist/components/data/__tests__/SortableHeader.test.js +101 -0
  40. package/dist/components/data/__tests__/link-step-surface.test.js +172 -0
  41. package/dist/components/data/__tests__/list-sort-state.svelte.test.js +71 -0
  42. package/dist/components/data/__tests__/list-sort.test.js +91 -0
  43. package/dist/components/data/__tests__/surface-navigation.test.js +121 -0
  44. package/dist/components/data/data-surface.d.ts +1 -0
  45. package/dist/components/data/data-surface.d.ts.map +1 -1
  46. package/dist/components/data/data-surface.js +1 -0
  47. package/dist/components/data/index.d.ts +6 -0
  48. package/dist/components/data/index.d.ts.map +1 -1
  49. package/dist/components/data/index.js +6 -0
  50. package/dist/components/data/link-surface.d.ts +79 -0
  51. package/dist/components/data/link-surface.d.ts.map +1 -0
  52. package/dist/components/data/link-surface.js +155 -0
  53. package/dist/components/data/list-sort-state.svelte.d.ts +39 -0
  54. package/dist/components/data/list-sort-state.svelte.d.ts.map +1 -0
  55. package/dist/components/data/list-sort-state.svelte.js +47 -0
  56. package/dist/components/data/list-sort.d.ts +94 -0
  57. package/dist/components/data/list-sort.d.ts.map +1 -0
  58. package/dist/components/data/list-sort.js +182 -0
  59. package/dist/components/data/step-surface.d.ts +73 -0
  60. package/dist/components/data/step-surface.d.ts.map +1 -0
  61. package/dist/components/data/step-surface.js +177 -0
  62. package/dist/components/data/surface-navigation.d.ts +49 -0
  63. package/dist/components/data/surface-navigation.d.ts.map +1 -0
  64. package/dist/components/data/surface-navigation.js +100 -0
  65. package/dist/components/data/types.d.ts +19 -0
  66. package/dist/components/data/types.d.ts.map +1 -1
  67. package/dist/components/feedback/PhoneSheet.svelte +224 -0
  68. package/dist/components/feedback/PhoneSheet.svelte.d.ts +35 -0
  69. package/dist/components/feedback/PhoneSheet.svelte.d.ts.map +1 -0
  70. package/dist/components/feedback/WorkingStrip.svelte +426 -0
  71. package/dist/components/feedback/WorkingStrip.svelte.d.ts +37 -0
  72. package/dist/components/feedback/WorkingStrip.svelte.d.ts.map +1 -0
  73. package/dist/components/feedback/__tests__/PhoneSheet.test.js +101 -0
  74. package/dist/components/feedback/__tests__/WorkingStrip.test.js +172 -0
  75. package/dist/components/feedback/index.d.ts +4 -0
  76. package/dist/components/feedback/index.d.ts.map +1 -1
  77. package/dist/components/feedback/index.js +5 -0
  78. package/dist/components/feedback/working-status.d.ts +34 -0
  79. package/dist/components/feedback/working-status.d.ts.map +1 -0
  80. package/dist/components/feedback/working-status.js +5 -0
  81. package/dist/components/forms/Checkbox.svelte +26 -2
  82. package/dist/components/forms/Combobox.svelte +68 -12
  83. package/dist/components/forms/Combobox.svelte.d.ts +6 -0
  84. package/dist/components/forms/Combobox.svelte.d.ts.map +1 -1
  85. package/dist/components/forms/DictationButton.svelte +128 -0
  86. package/dist/components/forms/DictationButton.svelte.d.ts +19 -0
  87. package/dist/components/forms/DictationButton.svelte.d.ts.map +1 -0
  88. package/dist/components/forms/DictationStatus.svelte +164 -0
  89. package/dist/components/forms/DictationStatus.svelte.d.ts +11 -0
  90. package/dist/components/forms/DictationStatus.svelte.d.ts.map +1 -0
  91. package/dist/components/forms/Fieldset.svelte +5 -1
  92. package/dist/components/forms/Fieldset.svelte.d.ts +2 -0
  93. package/dist/components/forms/Fieldset.svelte.d.ts.map +1 -1
  94. package/dist/components/forms/FormActionBar.svelte +84 -0
  95. package/dist/components/forms/FormActionBar.svelte.d.ts +23 -0
  96. package/dist/components/forms/FormActionBar.svelte.d.ts.map +1 -0
  97. package/dist/components/forms/Input.svelte +9 -0
  98. package/dist/components/forms/Radio.svelte +15 -4
  99. package/dist/components/forms/SearchInput.svelte +207 -0
  100. package/dist/components/forms/SearchInput.svelte.d.ts +22 -0
  101. package/dist/components/forms/SearchInput.svelte.d.ts.map +1 -0
  102. package/dist/components/forms/Select.svelte +9 -0
  103. package/dist/components/forms/StagedControlReview.svelte +21 -12
  104. package/dist/components/forms/StagedControlReview.svelte.d.ts.map +1 -1
  105. package/dist/components/forms/Switch.svelte +11 -5
  106. package/dist/components/forms/TagsInput.svelte +8 -1
  107. package/dist/components/forms/Textarea.svelte +8 -0
  108. package/dist/components/forms/__tests__/Combobox.test.js +87 -0
  109. package/dist/components/forms/__tests__/ControlHitArea.test.js +73 -0
  110. package/dist/components/forms/__tests__/DictationButton.test.js +176 -0
  111. package/dist/components/forms/__tests__/Fieldset.test.js +37 -0
  112. package/dist/components/forms/__tests__/FormActionBar.test.js +22 -0
  113. package/dist/components/forms/__tests__/SearchInput.test.js +92 -0
  114. package/dist/components/forms/__tests__/StagedControlReview.test.js +37 -3
  115. package/dist/components/forms/__tests__/combobox-labels.fixture.svelte +19 -0
  116. package/dist/components/forms/__tests__/combobox-labels.fixture.svelte.d.ts +11 -0
  117. package/dist/components/forms/__tests__/combobox-labels.fixture.svelte.d.ts.map +1 -0
  118. package/dist/components/forms/__tests__/composite-registration.fixture.svelte +29 -0
  119. package/dist/components/forms/__tests__/composite-registration.fixture.svelte.d.ts +8 -0
  120. package/dist/components/forms/__tests__/composite-registration.fixture.svelte.d.ts.map +1 -0
  121. package/dist/components/forms/__tests__/control-interaction.test.js +19 -1
  122. package/dist/components/forms/__tests__/control-proposals.test.js +63 -0
  123. package/dist/components/forms/__tests__/dictation-recording.test.js +582 -0
  124. package/dist/components/forms/__tests__/dictation.test.js +486 -0
  125. package/dist/components/forms/__tests__/long-press.test.js +175 -0
  126. package/dist/components/forms/__tests__/place-picker.fixture.svelte +33 -0
  127. package/dist/components/forms/__tests__/place-picker.fixture.svelte.d.ts +12 -0
  128. package/dist/components/forms/__tests__/place-picker.fixture.svelte.d.ts.map +1 -0
  129. package/dist/components/forms/audio-capture.d.ts +69 -0
  130. package/dist/components/forms/audio-capture.d.ts.map +1 -0
  131. package/dist/components/forms/audio-capture.js +193 -0
  132. package/dist/components/forms/control-interaction.d.ts +6 -0
  133. package/dist/components/forms/control-interaction.d.ts.map +1 -1
  134. package/dist/components/forms/control-interaction.js +12 -1
  135. package/dist/components/forms/control-proposals.d.ts +55 -0
  136. package/dist/components/forms/control-proposals.d.ts.map +1 -0
  137. package/dist/components/forms/control-proposals.js +188 -0
  138. package/dist/components/forms/dictation-transcribe.d.ts +36 -0
  139. package/dist/components/forms/dictation-transcribe.d.ts.map +1 -0
  140. package/dist/components/forms/dictation-transcribe.js +65 -0
  141. package/dist/components/forms/dictation.svelte.d.ts +200 -0
  142. package/dist/components/forms/dictation.svelte.d.ts.map +1 -0
  143. package/dist/components/forms/dictation.svelte.js +686 -0
  144. package/dist/components/forms/index.d.ts +14 -1
  145. package/dist/components/forms/index.d.ts.map +1 -1
  146. package/dist/components/forms/index.js +14 -1
  147. package/dist/components/forms/insert-text.d.ts +12 -0
  148. package/dist/components/forms/insert-text.d.ts.map +1 -0
  149. package/dist/components/forms/insert-text.js +38 -0
  150. package/dist/components/forms/long-press.d.ts +88 -0
  151. package/dist/components/forms/long-press.d.ts.map +1 -0
  152. package/dist/components/forms/long-press.js +213 -0
  153. package/dist/components/forms/ready-beep.d.ts +24 -0
  154. package/dist/components/forms/ready-beep.d.ts.map +1 -0
  155. package/dist/components/forms/ready-beep.js +82 -0
  156. package/dist/components/layout/PageHeader.svelte +151 -17
  157. package/dist/components/layout/PageHeader.svelte.d.ts +47 -7
  158. package/dist/components/layout/PageHeader.svelte.d.ts.map +1 -1
  159. package/dist/components/layout/__tests__/PageHeader.test.js +87 -1
  160. package/dist/components/layout/index.d.ts +1 -0
  161. package/dist/components/layout/index.d.ts.map +1 -1
  162. package/dist/components/layout/index.js +1 -0
  163. package/dist/components/layout/page-header-context.d.ts +25 -0
  164. package/dist/components/layout/page-header-context.d.ts.map +1 -0
  165. package/dist/components/layout/page-header-context.js +16 -0
  166. package/dist/components/nav/Tabs.svelte +241 -0
  167. package/dist/components/nav/Tabs.svelte.d.ts +15 -0
  168. package/dist/components/nav/Tabs.svelte.d.ts.map +1 -1
  169. package/dist/components/nav/__tests__/LinkTabs.test.js +117 -0
  170. package/dist/components/nav/index.d.ts +1 -0
  171. package/dist/components/nav/index.d.ts.map +1 -1
  172. package/dist/components/nav/index.js +1 -0
  173. package/dist/components/nav/tabs-overflow.d.ts +12 -0
  174. package/dist/components/nav/tabs-overflow.d.ts.map +1 -0
  175. package/dist/components/nav/tabs-overflow.js +17 -0
  176. package/dist/components/nav/types.d.ts +8 -0
  177. package/dist/components/nav/types.d.ts.map +1 -1
  178. package/dist/components/ui/Button.svelte +7 -0
  179. package/dist/components/ui/Card.svelte +14 -5
  180. package/dist/components/ui/Dropdown.svelte +55 -1
  181. package/dist/components/ui/Dropdown.svelte.d.ts +8 -0
  182. package/dist/components/ui/Dropdown.svelte.d.ts.map +1 -1
  183. package/dist/components/ui/IconToggle.svelte +139 -0
  184. package/dist/components/ui/IconToggle.svelte.d.ts +32 -0
  185. package/dist/components/ui/IconToggle.svelte.d.ts.map +1 -0
  186. package/dist/components/ui/IconToggleGroup.svelte +56 -0
  187. package/dist/components/ui/IconToggleGroup.svelte.d.ts +21 -0
  188. package/dist/components/ui/IconToggleGroup.svelte.d.ts.map +1 -0
  189. package/dist/components/ui/Pagination.svelte +1 -1
  190. package/dist/components/ui/Popover.svelte +17 -1
  191. package/dist/components/ui/Popover.svelte.d.ts +8 -0
  192. package/dist/components/ui/Popover.svelte.d.ts.map +1 -1
  193. package/dist/components/ui/__tests__/IconToggle.test.js +59 -0
  194. package/dist/components/ui/__tests__/IconToggleGroup.test.js +30 -0
  195. package/dist/components/ui/__tests__/Popover.test.js +44 -0
  196. package/dist/components/ui/__tests__/dropdown-popover-icon.test.js +125 -0
  197. package/dist/components/ui/__tests__/phone-touch-targets.test.js +39 -0
  198. package/dist/components/ui/index.d.ts +2 -0
  199. package/dist/components/ui/index.d.ts.map +1 -1
  200. package/dist/components/ui/index.js +2 -0
  201. package/dist/i18n/strings.ui.d.ts +41 -0
  202. package/dist/i18n/strings.ui.d.ts.map +1 -1
  203. package/dist/i18n/strings.ui.js +46 -0
  204. package/dist/svelte/__tests__/playground.test.js +1 -0
  205. package/dist/svelte/playground/CalendarPreview.svelte +140 -0
  206. package/dist/svelte/playground/CalendarPreview.svelte.d.ts +4 -0
  207. package/dist/svelte/playground/CalendarPreview.svelte.d.ts.map +1 -0
  208. package/dist/svelte/playground.d.ts.map +1 -1
  209. package/dist/svelte/playground.js +10 -0
  210. package/dist/types-generic.d.ts +2 -0
  211. package/dist/types-generic.d.ts.map +1 -1
  212. package/package.json +3 -3
@@ -11,24 +11,36 @@
11
11
  * dependency. The Provider-REQUIRED inputs (`CheckboxInput`, `TextInput`,
12
12
  * `MoneyInput`, the rich `Form`, …) stay in `@happyvertical/smrt-svelte/forms`.
13
13
  */
14
+ export { canCaptureDictationAudio, createMediaRecorderCapture, DICTATION_AUDIO_MIME_TYPES, DICTATION_MAX_BYTES, DICTATION_MAX_DURATION_MS, type DictationAudioCapture, type DictationAudioCaptureFactory, type DictationAudioCaptureOptions, DictationError, type DictationRecording, pickDictationMimeType, } from './audio-capture.js';
14
15
  export { default as Checkbox } from './Checkbox.svelte';
15
16
  export { default as Combobox } from './Combobox.svelte';
17
+ export { emitControlChange, focusControl, highlightControl, revealControl, } from './control-dom.js';
16
18
  export { type ControlBatchResult, type ControlCapability, type ControlCommand, type ControlCommandAction, type ControlCommandContext, type ControlCommandResult, type ControlCommandSource, type ControlConstraints, type ControlExtensionContext, type ControlIdentity, type ControlInteractionEvent, type ControlInteractionOptions, type ControlInteractionPolicy, type ControlInteractionRegistry, type ControlKind, type ControlMetadata, type ControlOption, type ControlRegistration, type ControlRuntimeState, type ControlSensitivity, type ControlSnapshot, type ControlStagedEntry, type ControlStagedProvenance, type ControlSubject, type ControlValueValidationResult, createControlInteractionRegistry, executeLocalControlBatch, executeLocalControlCommand, } from './control-interaction.js';
17
- export { type ControlInteractionContextValue, getControlInteractionContext, setControlInteractionContext, tryGetControlInteractionContext, } from './control-interaction-context.js';
19
+ export { type ControlInteractionContextValue, getControlInteractionContext, recordControlUserEdit, setControlInteractionContext, tryGetControlInteractionContext, } from './control-interaction-context.js';
20
+ export { type ControlProposalOptions, controlProposalInputSchema, controlProposalProperties, controlProposalSchema, controlProposalToolName, isControlProposable, proposableControls, type StageControlProposalsResult, stageControlProposals, } from './control-proposals.js';
18
21
  export { default as DatePicker } from './DatePicker.svelte';
22
+ export { default as DictationButton } from './DictationButton.svelte';
23
+ export { default as DictationStatus } from './DictationStatus.svelte';
24
+ export { classifyDictationError, Dictation, type DictationErrorKind, type DictationLogEvent, type DictationOptions, type DictationSourceProvider, type DictationSpeechResult, type DictationSpeechSource, type DictationStartOptions, type DictationState, dictationErrorCode, } from './dictation.svelte.js';
25
+ export { createHttpTranscriber, type DictationTranscribe, type DictationTranscribeOptions, type HttpTranscriberOptions, } from './dictation-transcribe.js';
19
26
  export { default as ErrorSummary } from './ErrorSummary.svelte';
20
27
  export { default as Fieldset } from './Fieldset.svelte';
21
28
  export { default as FilePicker } from './FilePicker.svelte';
22
29
  export { default as Form } from './Form.svelte';
30
+ export { default as FormActionBar } from './FormActionBar.svelte';
23
31
  export { default as Field, default as FormGroup } from './FormGroup.svelte';
24
32
  export { type FormGroupContextValue, nextFieldId, setFormGroupContext, tryGetFormGroupContext, } from './form-group-context.js';
25
33
  export { default as Input } from './Input.svelte';
26
34
  export { default as InputGroup } from './InputGroup.svelte';
35
+ export { insertTextAtCursor } from './insert-text.js';
27
36
  export { default as Listbox } from './Listbox.svelte';
37
+ export { createLongPress, LONG_PRESS_DEFAULT_DELAY_MS, LONG_PRESS_DEFAULT_MOVE_TOLERANCE_PX, type LongPressController, type LongPressDetail, type LongPressOptions, longPress, } from './long-press.js';
28
38
  export { default as MultiSelect } from './MultiSelect.svelte';
29
39
  export { default as Radio } from './Radio.svelte';
30
40
  export { default as RadioGroup } from './RadioGroup.svelte';
31
41
  export { default as RangeSlider } from './RangeSlider.svelte';
42
+ export { playReadyBeep, primeReadyBeep, type ReadyBeepOptions, } from './ready-beep.js';
43
+ export { default as SearchInput } from './SearchInput.svelte';
32
44
  export { default as SegmentedControl } from './SegmentedControl.svelte';
33
45
  export { default as Select } from './Select.svelte';
34
46
  export { default as Slider } from './Slider.svelte';
@@ -41,4 +53,5 @@ export { default as TimePicker } from './TimePicker.svelte';
41
53
  export { default as Toggle } from './Toggle.svelte';
42
54
  export { default as ToggleButton } from './ToggleButton.svelte';
43
55
  export type { FormError, RangeSliderValue, SegmentedControlOption, } from './types.js';
56
+ export { type ControlRegistrationDescriptor, useControlRegistration, } from './use-control-registration.svelte.js';
44
57
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/forms/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,eAAe,EACpB,KAAK,uBAAuB,EAC5B,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,cAAc,EACnB,KAAK,4BAA4B,EACjC,gCAAgC,EAChC,wBAAwB,EACxB,0BAA0B,GAC3B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,KAAK,8BAA8B,EACnC,4BAA4B,EAC5B,4BAA4B,EAC5B,+BAA+B,GAChC,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EACL,KAAK,qBAAqB,EAC1B,WAAW,EACX,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACpD,YAAY,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAC5E,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,YAAY,EACV,SAAS,EACT,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/forms/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EACL,wBAAwB,EACxB,0BAA0B,EAC1B,0BAA0B,EAC1B,mBAAmB,EACnB,yBAAyB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,4BAA4B,EACjC,KAAK,4BAA4B,EACjC,cAAc,EACd,KAAK,kBAAkB,EACvB,qBAAqB,GACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,gBAAgB,EAChB,aAAa,GACd,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,eAAe,EACpB,KAAK,uBAAuB,EAC5B,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,cAAc,EACnB,KAAK,4BAA4B,EACjC,gCAAgC,EAChC,wBAAwB,EACxB,0BAA0B,GAC3B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,KAAK,8BAA8B,EACnC,4BAA4B,EAC5B,qBAAqB,EACrB,4BAA4B,EAC5B,+BAA+B,GAChC,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,KAAK,sBAAsB,EAC3B,0BAA0B,EAC1B,yBAAyB,EACzB,qBAAqB,EACrB,uBAAuB,EACvB,mBAAmB,EACnB,kBAAkB,EAClB,KAAK,2BAA2B,EAChC,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EACL,sBAAsB,EACtB,SAAS,EACT,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,kBAAkB,GACnB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,qBAAqB,EACrB,KAAK,mBAAmB,EACxB,KAAK,0BAA0B,EAC/B,KAAK,sBAAsB,GAC5B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EACL,KAAK,qBAAqB,EAC1B,WAAW,EACX,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EACL,eAAe,EACf,2BAA2B,EAC3B,oCAAoC,EACpC,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,SAAS,GACV,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EACL,aAAa,EACb,cAAc,EACd,KAAK,gBAAgB,GACtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACpD,YAAY,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAC5E,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,YAAY,EACV,SAAS,EACT,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,KAAK,6BAA6B,EAClC,sBAAsB,GACvB,MAAM,sCAAsC,CAAC"}
@@ -11,24 +11,36 @@
11
11
  * dependency. The Provider-REQUIRED inputs (`CheckboxInput`, `TextInput`,
12
12
  * `MoneyInput`, the rich `Form`, …) stay in `@happyvertical/smrt-svelte/forms`.
13
13
  */
14
+ export { canCaptureDictationAudio, createMediaRecorderCapture, DICTATION_AUDIO_MIME_TYPES, DICTATION_MAX_BYTES, DICTATION_MAX_DURATION_MS, DictationError, pickDictationMimeType, } from './audio-capture.js';
14
15
  export { default as Checkbox } from './Checkbox.svelte';
15
16
  export { default as Combobox } from './Combobox.svelte';
17
+ export { emitControlChange, focusControl, highlightControl, revealControl, } from './control-dom.js';
16
18
  export { createControlInteractionRegistry, executeLocalControlBatch, executeLocalControlCommand, } from './control-interaction.js';
17
- export { getControlInteractionContext, setControlInteractionContext, tryGetControlInteractionContext, } from './control-interaction-context.js';
19
+ export { getControlInteractionContext, recordControlUserEdit, setControlInteractionContext, tryGetControlInteractionContext, } from './control-interaction-context.js';
20
+ export { controlProposalInputSchema, controlProposalProperties, controlProposalSchema, controlProposalToolName, isControlProposable, proposableControls, stageControlProposals, } from './control-proposals.js';
18
21
  export { default as DatePicker } from './DatePicker.svelte';
22
+ export { default as DictationButton } from './DictationButton.svelte';
23
+ export { default as DictationStatus } from './DictationStatus.svelte';
24
+ export { classifyDictationError, Dictation, dictationErrorCode, } from './dictation.svelte.js';
25
+ export { createHttpTranscriber, } from './dictation-transcribe.js';
19
26
  export { default as ErrorSummary } from './ErrorSummary.svelte';
20
27
  export { default as Fieldset } from './Fieldset.svelte';
21
28
  export { default as FilePicker } from './FilePicker.svelte';
22
29
  export { default as Form } from './Form.svelte';
30
+ export { default as FormActionBar } from './FormActionBar.svelte';
23
31
  export { default as Field, default as FormGroup } from './FormGroup.svelte';
24
32
  export { nextFieldId, setFormGroupContext, tryGetFormGroupContext, } from './form-group-context.js';
25
33
  export { default as Input } from './Input.svelte';
26
34
  export { default as InputGroup } from './InputGroup.svelte';
35
+ export { insertTextAtCursor } from './insert-text.js';
27
36
  export { default as Listbox } from './Listbox.svelte';
37
+ export { createLongPress, LONG_PRESS_DEFAULT_DELAY_MS, LONG_PRESS_DEFAULT_MOVE_TOLERANCE_PX, longPress, } from './long-press.js';
28
38
  export { default as MultiSelect } from './MultiSelect.svelte';
29
39
  export { default as Radio } from './Radio.svelte';
30
40
  export { default as RadioGroup } from './RadioGroup.svelte';
31
41
  export { default as RangeSlider } from './RangeSlider.svelte';
42
+ export { playReadyBeep, primeReadyBeep, } from './ready-beep.js';
43
+ export { default as SearchInput } from './SearchInput.svelte';
32
44
  export { default as SegmentedControl } from './SegmentedControl.svelte';
33
45
  export { default as Select } from './Select.svelte';
34
46
  export { default as Slider } from './Slider.svelte';
@@ -39,3 +51,4 @@ export { default as Textarea } from './Textarea.svelte';
39
51
  export { default as TimePicker } from './TimePicker.svelte';
40
52
  export { default as Toggle } from './Toggle.svelte';
41
53
  export { default as ToggleButton } from './ToggleButton.svelte';
54
+ export { useControlRegistration, } from './use-control-registration.svelte.js';
@@ -0,0 +1,12 @@
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 declare function insertTextAtCursor(field: HTMLTextAreaElement | HTMLInputElement, text: string): void;
12
+ //# sourceMappingURL=insert-text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"insert-text.d.ts","sourceRoot":"","sources":["../../../src/components/forms/insert-text.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,mBAAmB,GAAG,gBAAgB,EAC7C,IAAI,EAAE,MAAM,GACX,IAAI,CA0BN"}
@@ -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,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"}
@@ -0,0 +1,82 @@
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
+ let context = null;
12
+ function audioContextCtor() {
13
+ if (typeof window === 'undefined')
14
+ return null;
15
+ const w = window;
16
+ return (w.AudioContext ??
17
+ w.webkitAudioContext ??
18
+ null);
19
+ }
20
+ function getContext() {
21
+ if (context)
22
+ return context;
23
+ const Ctor = audioContextCtor();
24
+ if (!Ctor)
25
+ return null;
26
+ try {
27
+ context = new Ctor();
28
+ }
29
+ catch {
30
+ context = null;
31
+ }
32
+ return context;
33
+ }
34
+ /** Create (or wake) the audio context; call from a user gesture. */
35
+ export function primeReadyBeep() {
36
+ const ctx = getContext();
37
+ if (ctx && ctx.state === 'suspended') {
38
+ void ctx.resume().catch(() => undefined);
39
+ }
40
+ }
41
+ /**
42
+ * Play two quick rising tones (about 0.2s). Resolves `true` when it played,
43
+ * `false` when audio is unavailable or not allowed yet.
44
+ */
45
+ export async function playReadyBeep(options = {}) {
46
+ const ctx = getContext();
47
+ if (!ctx)
48
+ return false;
49
+ try {
50
+ if (ctx.state === 'suspended')
51
+ await ctx.resume();
52
+ }
53
+ catch {
54
+ return false;
55
+ }
56
+ if (ctx.state !== 'running')
57
+ return false;
58
+ const volume = Math.max(0, Math.min(1, options.volume ?? 0.12));
59
+ const start = ctx.currentTime + 0.01;
60
+ const tones = [
61
+ [660, 0],
62
+ [990, 0.1],
63
+ ];
64
+ for (const [frequency, at] of tones) {
65
+ const oscillator = ctx.createOscillator();
66
+ const gain = ctx.createGain();
67
+ oscillator.type = 'sine';
68
+ oscillator.frequency.value = frequency;
69
+ gain.gain.setValueAtTime(0, start + at);
70
+ gain.gain.linearRampToValueAtTime(volume, start + at + 0.01);
71
+ gain.gain.exponentialRampToValueAtTime(0.0001, start + at + 0.09);
72
+ oscillator.connect(gain);
73
+ gain.connect(ctx.destination);
74
+ oscillator.start(start + at);
75
+ oscillator.stop(start + at + 0.1);
76
+ }
77
+ return true;
78
+ }
79
+ /** Tests: forget the shared audio context. */
80
+ export function resetReadyBeepForTests() {
81
+ context = null;
82
+ }