stimeo-ui 0.16.0 → 0.18.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 (337) hide show
  1. package/CHANGELOG.md +136 -0
  2. package/README.md +27 -11
  3. package/dist/cable/index.d.ts +88 -31
  4. package/dist/cable/index.js +384 -449
  5. package/dist/cable/index.js.map +1 -1
  6. package/dist/coerce-JtZVNG5h.d.ts +20 -0
  7. package/dist/controllers/accordion_controller.d.ts +4 -2
  8. package/dist/controllers/accordion_controller.js +174 -55
  9. package/dist/controllers/accordion_controller.js.map +1 -1
  10. package/dist/controllers/alert_dialog_controller.d.ts +12 -2
  11. package/dist/controllers/alert_dialog_controller.js +903 -235
  12. package/dist/controllers/alert_dialog_controller.js.map +1 -1
  13. package/dist/controllers/announcer_controller.d.ts +37 -5
  14. package/dist/controllers/announcer_controller.js +238 -205
  15. package/dist/controllers/announcer_controller.js.map +1 -1
  16. package/dist/controllers/aspect_ratio_controller.js +0 -10
  17. package/dist/controllers/aspect_ratio_controller.js.map +1 -1
  18. package/dist/controllers/auto_submit_controller.d.ts +30 -6
  19. package/dist/controllers/auto_submit_controller.js +414 -145
  20. package/dist/controllers/auto_submit_controller.js.map +1 -1
  21. package/dist/controllers/avatar_controller.js +185 -107
  22. package/dist/controllers/avatar_controller.js.map +1 -1
  23. package/dist/controllers/breadcrumb_controller.js +0 -130
  24. package/dist/controllers/breadcrumb_controller.js.map +1 -1
  25. package/dist/controllers/bulk_select_controller.d.ts +21 -3
  26. package/dist/controllers/bulk_select_controller.js +282 -58
  27. package/dist/controllers/bulk_select_controller.js.map +1 -1
  28. package/dist/controllers/calendar_controller.d.ts +38 -16
  29. package/dist/controllers/calendar_controller.js +228 -260
  30. package/dist/controllers/calendar_controller.js.map +1 -1
  31. package/dist/controllers/carousel_controller.d.ts +43 -12
  32. package/dist/controllers/carousel_controller.js +536 -436
  33. package/dist/controllers/carousel_controller.js.map +1 -1
  34. package/dist/controllers/character_counter_controller.d.ts +44 -7
  35. package/dist/controllers/character_counter_controller.js +493 -207
  36. package/dist/controllers/character_counter_controller.js.map +1 -1
  37. package/dist/controllers/checkbox_controller.d.ts +7 -2
  38. package/dist/controllers/checkbox_controller.js +38 -74
  39. package/dist/controllers/checkbox_controller.js.map +1 -1
  40. package/dist/controllers/clipboard_controller.d.ts +16 -5
  41. package/dist/controllers/clipboard_controller.js +261 -149
  42. package/dist/controllers/clipboard_controller.js.map +1 -1
  43. package/dist/controllers/collapsible_controller.d.ts +17 -5
  44. package/dist/controllers/collapsible_controller.js +304 -120
  45. package/dist/controllers/collapsible_controller.js.map +1 -1
  46. package/dist/controllers/color_picker_controller.d.ts +18 -6
  47. package/dist/controllers/color_picker_controller.js +178 -146
  48. package/dist/controllers/color_picker_controller.js.map +1 -1
  49. package/dist/controllers/combobox_controller.d.ts +24 -6
  50. package/dist/controllers/combobox_controller.js +522 -156
  51. package/dist/controllers/combobox_controller.js.map +1 -1
  52. package/dist/controllers/command_palette_controller.d.ts +51 -20
  53. package/dist/controllers/command_palette_controller.js +1156 -395
  54. package/dist/controllers/command_palette_controller.js.map +1 -1
  55. package/dist/controllers/conditional_fields_controller.d.ts +15 -2
  56. package/dist/controllers/conditional_fields_controller.js +300 -171
  57. package/dist/controllers/conditional_fields_controller.js.map +1 -1
  58. package/dist/controllers/confirm_controller.d.ts +49 -12
  59. package/dist/controllers/confirm_controller.js +980 -262
  60. package/dist/controllers/confirm_controller.js.map +1 -1
  61. package/dist/controllers/context_menu_controller.d.ts +80 -18
  62. package/dist/controllers/context_menu_controller.js +346 -153
  63. package/dist/controllers/context_menu_controller.js.map +1 -1
  64. package/dist/controllers/count_up_controller.d.ts +13 -1
  65. package/dist/controllers/count_up_controller.js +73 -21
  66. package/dist/controllers/count_up_controller.js.map +1 -1
  67. package/dist/controllers/countdown_controller.d.ts +47 -3
  68. package/dist/controllers/countdown_controller.js +281 -158
  69. package/dist/controllers/countdown_controller.js.map +1 -1
  70. package/dist/controllers/currency_input_controller.d.ts +93 -10
  71. package/dist/controllers/currency_input_controller.js +575 -225
  72. package/dist/controllers/currency_input_controller.js.map +1 -1
  73. package/dist/controllers/data_grid_controller.d.ts +25 -12
  74. package/dist/controllers/data_grid_controller.js +248 -214
  75. package/dist/controllers/data_grid_controller.js.map +1 -1
  76. package/dist/controllers/date_range_picker_controller.d.ts +42 -14
  77. package/dist/controllers/date_range_picker_controller.js +338 -235
  78. package/dist/controllers/date_range_picker_controller.js.map +1 -1
  79. package/dist/controllers/dialog_controller.d.ts +17 -6
  80. package/dist/controllers/dialog_controller.js +899 -237
  81. package/dist/controllers/dialog_controller.js.map +1 -1
  82. package/dist/controllers/direct_upload_controller.d.ts +25 -8
  83. package/dist/controllers/direct_upload_controller.js +97 -167
  84. package/dist/controllers/direct_upload_controller.js.map +1 -1
  85. package/dist/controllers/dirty_form_controller.d.ts +6 -1
  86. package/dist/controllers/dirty_form_controller.js +72 -69
  87. package/dist/controllers/dirty_form_controller.js.map +1 -1
  88. package/dist/controllers/dismissible_controller.d.ts +19 -0
  89. package/dist/controllers/dismissible_controller.js +196 -24
  90. package/dist/controllers/dismissible_controller.js.map +1 -1
  91. package/dist/controllers/drawer_controller.d.ts +39 -11
  92. package/dist/controllers/drawer_controller.js +974 -355
  93. package/dist/controllers/drawer_controller.js.map +1 -1
  94. package/dist/controllers/dropdown_controller.d.ts +31 -1
  95. package/dist/controllers/dropdown_controller.js +339 -96
  96. package/dist/controllers/dropdown_controller.js.map +1 -1
  97. package/dist/controllers/editable_controller.d.ts +12 -1
  98. package/dist/controllers/editable_controller.js +315 -88
  99. package/dist/controllers/editable_controller.js.map +1 -1
  100. package/dist/controllers/empty_state_controller.js +79 -58
  101. package/dist/controllers/empty_state_controller.js.map +1 -1
  102. package/dist/controllers/file_dropzone_controller.d.ts +63 -18
  103. package/dist/controllers/file_dropzone_controller.js +322 -211
  104. package/dist/controllers/file_dropzone_controller.js.map +1 -1
  105. package/dist/controllers/filter_controller.js +77 -42
  106. package/dist/controllers/filter_controller.js.map +1 -1
  107. package/dist/controllers/flash_controller.d.ts +35 -12
  108. package/dist/controllers/flash_controller.js +238 -347
  109. package/dist/controllers/flash_controller.js.map +1 -1
  110. package/dist/controllers/focus_controller.d.ts +15 -6
  111. package/dist/controllers/focus_controller.js +679 -240
  112. package/dist/controllers/focus_controller.js.map +1 -1
  113. package/dist/controllers/form_field_controller.js +156 -132
  114. package/dist/controllers/form_field_controller.js.map +1 -1
  115. package/dist/controllers/form_validation_controller.d.ts +3 -3
  116. package/dist/controllers/form_validation_controller.js +31 -97
  117. package/dist/controllers/form_validation_controller.js.map +1 -1
  118. package/dist/controllers/frame_loading_controller.d.ts +47 -14
  119. package/dist/controllers/frame_loading_controller.js +275 -217
  120. package/dist/controllers/frame_loading_controller.js.map +1 -1
  121. package/dist/controllers/highlight_controller.d.ts +27 -6
  122. package/dist/controllers/highlight_controller.js +107 -75
  123. package/dist/controllers/highlight_controller.js.map +1 -1
  124. package/dist/controllers/hover_card_controller.d.ts +60 -4
  125. package/dist/controllers/hover_card_controller.js +327 -130
  126. package/dist/controllers/hover_card_controller.js.map +1 -1
  127. package/dist/controllers/idle_controller.d.ts +48 -6
  128. package/dist/controllers/idle_controller.js +271 -101
  129. package/dist/controllers/idle_controller.js.map +1 -1
  130. package/dist/controllers/input_mask_controller.d.ts +30 -13
  131. package/dist/controllers/input_mask_controller.js +483 -97
  132. package/dist/controllers/input_mask_controller.js.map +1 -1
  133. package/dist/controllers/intersection_controller.d.ts +32 -13
  134. package/dist/controllers/intersection_controller.js +150 -106
  135. package/dist/controllers/intersection_controller.js.map +1 -1
  136. package/dist/controllers/lazy_frame_controller.d.ts +19 -2
  137. package/dist/controllers/lazy_frame_controller.js +24 -68
  138. package/dist/controllers/lazy_frame_controller.js.map +1 -1
  139. package/dist/controllers/listbox_controller.d.ts +44 -9
  140. package/dist/controllers/listbox_controller.js +523 -240
  141. package/dist/controllers/listbox_controller.js.map +1 -1
  142. package/dist/controllers/local_time_controller.d.ts +9 -7
  143. package/dist/controllers/local_time_controller.js +102 -77
  144. package/dist/controllers/local_time_controller.js.map +1 -1
  145. package/dist/controllers/masonry_controller.d.ts +11 -3
  146. package/dist/controllers/masonry_controller.js +80 -96
  147. package/dist/controllers/masonry_controller.js.map +1 -1
  148. package/dist/controllers/menu_controller.d.ts +55 -11
  149. package/dist/controllers/menu_controller.js +302 -188
  150. package/dist/controllers/menu_controller.js.map +1 -1
  151. package/dist/controllers/menubar_controller.d.ts +51 -9
  152. package/dist/controllers/menubar_controller.js +232 -345
  153. package/dist/controllers/menubar_controller.js.map +1 -1
  154. package/dist/controllers/meter_controller.d.ts +33 -20
  155. package/dist/controllers/meter_controller.js +417 -87
  156. package/dist/controllers/meter_controller.js.map +1 -1
  157. package/dist/controllers/multi_select_controller.d.ts +48 -18
  158. package/dist/controllers/multi_select_controller.js +785 -393
  159. package/dist/controllers/multi_select_controller.js.map +1 -1
  160. package/dist/controllers/navigation_menu_controller.d.ts +27 -6
  161. package/dist/controllers/navigation_menu_controller.js +190 -250
  162. package/dist/controllers/navigation_menu_controller.js.map +1 -1
  163. package/dist/controllers/nested_form_controller.d.ts +10 -0
  164. package/dist/controllers/nested_form_controller.js +396 -192
  165. package/dist/controllers/nested_form_controller.js.map +1 -1
  166. package/dist/controllers/network_status_controller.d.ts +23 -0
  167. package/dist/controllers/network_status_controller.js +268 -62
  168. package/dist/controllers/network_status_controller.js.map +1 -1
  169. package/dist/controllers/number_input_controller.d.ts +50 -8
  170. package/dist/controllers/number_input_controller.js +610 -303
  171. package/dist/controllers/number_input_controller.js.map +1 -1
  172. package/dist/controllers/optimistic_controller.d.ts +8 -5
  173. package/dist/controllers/optimistic_controller.js +45 -87
  174. package/dist/controllers/optimistic_controller.js.map +1 -1
  175. package/dist/controllers/otp_controller.d.ts +55 -8
  176. package/dist/controllers/otp_controller.js +658 -255
  177. package/dist/controllers/otp_controller.js.map +1 -1
  178. package/dist/controllers/overflow_indicator_controller.d.ts +5 -0
  179. package/dist/controllers/overflow_indicator_controller.js +122 -113
  180. package/dist/controllers/overflow_indicator_controller.js.map +1 -1
  181. package/dist/controllers/overflow_menu_controller.d.ts +58 -20
  182. package/dist/controllers/overflow_menu_controller.js +470 -295
  183. package/dist/controllers/overflow_menu_controller.js.map +1 -1
  184. package/dist/controllers/pagination_controller.d.ts +37 -7
  185. package/dist/controllers/pagination_controller.js +332 -123
  186. package/dist/controllers/pagination_controller.js.map +1 -1
  187. package/dist/controllers/password_reveal_controller.d.ts +46 -8
  188. package/dist/controllers/password_reveal_controller.js +392 -121
  189. package/dist/controllers/password_reveal_controller.js.map +1 -1
  190. package/dist/controllers/password_strength_controller.d.ts +15 -6
  191. package/dist/controllers/password_strength_controller.js +111 -158
  192. package/dist/controllers/password_strength_controller.js.map +1 -1
  193. package/dist/controllers/persist_controller.d.ts +11 -4
  194. package/dist/controllers/persist_controller.js +165 -111
  195. package/dist/controllers/persist_controller.js.map +1 -1
  196. package/dist/controllers/pointer_drag_controller.d.ts +35 -12
  197. package/dist/controllers/pointer_drag_controller.js +434 -188
  198. package/dist/controllers/pointer_drag_controller.js.map +1 -1
  199. package/dist/controllers/popover_controller.d.ts +41 -5
  200. package/dist/controllers/popover_controller.js +269 -113
  201. package/dist/controllers/popover_controller.js.map +1 -1
  202. package/dist/controllers/portal_controller.d.ts +44 -4
  203. package/dist/controllers/portal_controller.js +215 -76
  204. package/dist/controllers/portal_controller.js.map +1 -1
  205. package/dist/controllers/preview_guard_controller.d.ts +10 -4
  206. package/dist/controllers/preview_guard_controller.js +243 -116
  207. package/dist/controllers/preview_guard_controller.js.map +1 -1
  208. package/dist/controllers/progress_controller.d.ts +20 -19
  209. package/dist/controllers/progress_controller.js +391 -78
  210. package/dist/controllers/progress_controller.js.map +1 -1
  211. package/dist/controllers/radio_group_controller.d.ts +21 -9
  212. package/dist/controllers/radio_group_controller.js +278 -211
  213. package/dist/controllers/radio_group_controller.js.map +1 -1
  214. package/dist/controllers/range_slider_controller.d.ts +47 -6
  215. package/dist/controllers/range_slider_controller.js +220 -113
  216. package/dist/controllers/range_slider_controller.js.map +1 -1
  217. package/dist/controllers/rating_controller.d.ts +20 -4
  218. package/dist/controllers/rating_controller.js +458 -211
  219. package/dist/controllers/rating_controller.js.map +1 -1
  220. package/dist/controllers/read_more_controller.d.ts +2 -0
  221. package/dist/controllers/read_more_controller.js +138 -63
  222. package/dist/controllers/read_more_controller.js.map +1 -1
  223. package/dist/controllers/reading_progress_controller.d.ts +1 -1
  224. package/dist/controllers/reading_progress_controller.js +166 -137
  225. package/dist/controllers/reading_progress_controller.js.map +1 -1
  226. package/dist/controllers/relative_time_controller.d.ts +20 -6
  227. package/dist/controllers/relative_time_controller.js +211 -112
  228. package/dist/controllers/relative_time_controller.js.map +1 -1
  229. package/dist/controllers/reset_on_restore_controller.d.ts +85 -0
  230. package/dist/controllers/{reset_before_cache_controller.js → reset_on_restore_controller.js} +103 -38
  231. package/dist/controllers/reset_on_restore_controller.js.map +1 -0
  232. package/dist/controllers/resizable_controller.d.ts +31 -2
  233. package/dist/controllers/resizable_controller.js +299 -150
  234. package/dist/controllers/resizable_controller.js.map +1 -1
  235. package/dist/controllers/roving_controller.d.ts +3 -3
  236. package/dist/controllers/roving_controller.js +49 -88
  237. package/dist/controllers/roving_controller.js.map +1 -1
  238. package/dist/controllers/scroll_area_controller.d.ts +7 -3
  239. package/dist/controllers/scroll_area_controller.js +490 -246
  240. package/dist/controllers/scroll_area_controller.js.map +1 -1
  241. package/dist/controllers/scroll_restore_controller.d.ts +3 -3
  242. package/dist/controllers/scroll_restore_controller.js +14 -55
  243. package/dist/controllers/scroll_restore_controller.js.map +1 -1
  244. package/dist/controllers/scroll_visibility_controller.d.ts +28 -12
  245. package/dist/controllers/scroll_visibility_controller.js +432 -149
  246. package/dist/controllers/scroll_visibility_controller.js.map +1 -1
  247. package/dist/controllers/scrollspy_controller.d.ts +6 -1
  248. package/dist/controllers/scrollspy_controller.js +193 -248
  249. package/dist/controllers/scrollspy_controller.js.map +1 -1
  250. package/dist/controllers/separator_controller.d.ts +20 -5
  251. package/dist/controllers/separator_controller.js +285 -142
  252. package/dist/controllers/separator_controller.js.map +1 -1
  253. package/dist/controllers/sidebar_controller.d.ts +65 -8
  254. package/dist/controllers/sidebar_controller.js +1069 -404
  255. package/dist/controllers/sidebar_controller.js.map +1 -1
  256. package/dist/controllers/skeleton_controller.d.ts +23 -0
  257. package/dist/controllers/skeleton_controller.js +259 -101
  258. package/dist/controllers/skeleton_controller.js.map +1 -1
  259. package/dist/controllers/slider_controller.d.ts +29 -2
  260. package/dist/controllers/slider_controller.js +187 -86
  261. package/dist/controllers/slider_controller.js.map +1 -1
  262. package/dist/controllers/smart_sticky_header_controller.d.ts +22 -4
  263. package/dist/controllers/smart_sticky_header_controller.js +173 -66
  264. package/dist/controllers/smart_sticky_header_controller.js.map +1 -1
  265. package/dist/controllers/sortable_controller.d.ts +4 -4
  266. package/dist/controllers/sortable_controller.js +26 -125
  267. package/dist/controllers/sortable_controller.js.map +1 -1
  268. package/dist/controllers/spinner_controller.d.ts +39 -4
  269. package/dist/controllers/spinner_controller.js +288 -173
  270. package/dist/controllers/spinner_controller.js.map +1 -1
  271. package/dist/controllers/step_indicator_controller.d.ts +9 -4
  272. package/dist/controllers/step_indicator_controller.js +105 -46
  273. package/dist/controllers/step_indicator_controller.js.map +1 -1
  274. package/dist/controllers/stepper_controller.d.ts +14 -6
  275. package/dist/controllers/stepper_controller.js +120 -73
  276. package/dist/controllers/stepper_controller.js.map +1 -1
  277. package/dist/controllers/stick_to_bottom_controller.d.ts +9 -1
  278. package/dist/controllers/stick_to_bottom_controller.js +275 -140
  279. package/dist/controllers/stick_to_bottom_controller.js.map +1 -1
  280. package/dist/controllers/sticky_observer_controller.d.ts +11 -0
  281. package/dist/controllers/sticky_observer_controller.js +220 -49
  282. package/dist/controllers/sticky_observer_controller.js.map +1 -1
  283. package/dist/controllers/submit_once_controller.d.ts +24 -8
  284. package/dist/controllers/submit_once_controller.js +376 -227
  285. package/dist/controllers/submit_once_controller.js.map +1 -1
  286. package/dist/controllers/switch_controller.d.ts +18 -4
  287. package/dist/controllers/switch_controller.js +201 -84
  288. package/dist/controllers/switch_controller.js.map +1 -1
  289. package/dist/controllers/tabs_controller.d.ts +9 -6
  290. package/dist/controllers/tabs_controller.js +41 -30
  291. package/dist/controllers/tabs_controller.js.map +1 -1
  292. package/dist/controllers/tags_input_controller.d.ts +16 -3
  293. package/dist/controllers/tags_input_controller.js +293 -173
  294. package/dist/controllers/tags_input_controller.js.map +1 -1
  295. package/dist/controllers/textarea_autosize_controller.d.ts +11 -1
  296. package/dist/controllers/textarea_autosize_controller.js +108 -74
  297. package/dist/controllers/textarea_autosize_controller.js.map +1 -1
  298. package/dist/controllers/theme_controller.d.ts +24 -11
  299. package/dist/controllers/theme_controller.js +140 -116
  300. package/dist/controllers/theme_controller.js.map +1 -1
  301. package/dist/controllers/time_picker_controller.d.ts +55 -5
  302. package/dist/controllers/time_picker_controller.js +331 -127
  303. package/dist/controllers/time_picker_controller.js.map +1 -1
  304. package/dist/controllers/toast_controller.d.ts +40 -16
  305. package/dist/controllers/toast_controller.js +244 -324
  306. package/dist/controllers/toast_controller.js.map +1 -1
  307. package/dist/controllers/toggle_group_controller.d.ts +14 -6
  308. package/dist/controllers/toggle_group_controller.js +252 -191
  309. package/dist/controllers/toggle_group_controller.js.map +1 -1
  310. package/dist/controllers/toolbar_controller.d.ts +8 -6
  311. package/dist/controllers/toolbar_controller.js +219 -120
  312. package/dist/controllers/toolbar_controller.js.map +1 -1
  313. package/dist/controllers/tooltip_controller.d.ts +49 -4
  314. package/dist/controllers/tooltip_controller.js +158 -124
  315. package/dist/controllers/tooltip_controller.js.map +1 -1
  316. package/dist/controllers/transition_controller.d.ts +22 -4
  317. package/dist/controllers/transition_controller.js +123 -119
  318. package/dist/controllers/transition_controller.js.map +1 -1
  319. package/dist/controllers/tree_view_controller.d.ts +22 -12
  320. package/dist/controllers/tree_view_controller.js +283 -369
  321. package/dist/controllers/tree_view_controller.js.map +1 -1
  322. package/dist/index.d.ts +10 -5
  323. package/dist/index.js +8573 -10410
  324. package/dist/index.js.map +1 -1
  325. package/dist/inspector/cli.d.ts +38 -14
  326. package/dist/inspector/cli.js +108 -40
  327. package/dist/inspector/cli.js.map +1 -1
  328. package/dist/inspector/cli_bin.js +145 -64
  329. package/dist/inspector/cli_bin.js.map +1 -1
  330. package/dist/inspector/examples.json +20 -20
  331. package/dist/inspector/manifest.json +802 -101
  332. package/dist/positioning/index.d.ts +15 -7
  333. package/dist/positioning/index.js +154 -47
  334. package/dist/positioning/index.js.map +1 -1
  335. package/package.json +11 -10
  336. package/dist/controllers/reset_before_cache_controller.d.ts +0 -76
  337. package/dist/controllers/reset_before_cache_controller.js.map +0 -1
@@ -1,87 +1,190 @@
1
1
  import { Controller } from '@hotwired/stimulus';
2
2
 
3
- // src/controllers/input_mask_controller.ts
4
-
5
- // src/utils/composition_tracker.ts
6
3
  var COMPOSITION_INPUT_TYPES = /* @__PURE__ */ new Set([
7
4
  "insertCompositionText",
8
5
  "insertFromComposition",
9
6
  "deleteCompositionText",
10
7
  "deleteByComposition"
11
8
  ]);
9
+ function isCompositionInputType(inputType) {
10
+ return inputType !== void 0 && COMPOSITION_INPUT_TYPES.has(inputType);
11
+ }
12
+ var BEFORE_MORPH_ATTRIBUTE = "turbo:before-morph-attribute";
13
+ var textOf = (element) => element.value;
14
+ var holdsFocus = (element) => element instanceof Node && element.getRootNode().activeElement === element;
12
15
  var CompositionTracker = class {
13
16
  #observedTargets = /* @__PURE__ */ new Set();
14
- #activeTargets = /* @__PURE__ */ new Set();
17
+ #composition = null;
15
18
  #onStart;
16
19
  #onEnd;
17
- /** The field whose confirming `input` is still owed, while the window is open. */
20
+ #onAbandon;
18
21
  #confirmedTarget = null;
22
+ #keyComposing = false;
23
+ #connected = false;
24
+ #abandoned = null;
19
25
  constructor(options = {}) {
20
26
  this.#onStart = options.onStart;
21
27
  this.#onEnd = options.onEnd;
28
+ this.#onAbandon = options.onAbandon;
22
29
  }
23
- /** Starts lifecycle tracking for `target`; repeated calls are idempotent. */
24
30
  observe(target) {
31
+ this.#connected = true;
25
32
  if (this.#observedTargets.has(target)) return;
26
33
  target.addEventListener("compositionstart", this.#handleStart);
27
34
  target.addEventListener("compositionend", this.#handleEnd);
28
- target.addEventListener("keydown", this.#handleKeydown);
35
+ target.addEventListener("keydown", this.#handleKeydown, true);
36
+ target.addEventListener("beforeinput", this.#handleBeforeInput, true);
37
+ target.addEventListener("input", this.#handleInput, true);
38
+ target.addEventListener("blur", this.#handleBlur, true);
39
+ target.addEventListener(BEFORE_MORPH_ATTRIBUTE, this.#handleBeforeMorphAttribute);
29
40
  this.#observedTargets.add(target);
30
41
  }
31
- /** Stops tracking one target and clears any active composition it owned. */
32
42
  unobserve(target) {
33
43
  if (!this.#observedTargets.delete(target)) return;
34
- target.removeEventListener("compositionstart", this.#handleStart);
35
- target.removeEventListener("compositionend", this.#handleEnd);
36
- target.removeEventListener("keydown", this.#handleKeydown);
37
- this.#activeTargets.delete(target);
44
+ this.#release(target);
45
+ if (this.#composition?.target === target) this.#letGo();
38
46
  if (this.#confirmedTarget === target) this.#confirmedTarget = null;
39
47
  }
40
- /** Releases every listener and clears state so reconnect starts cleanly. */
41
48
  disconnect() {
42
- for (const target of this.#observedTargets) {
43
- target.removeEventListener("compositionstart", this.#handleStart);
44
- target.removeEventListener("compositionend", this.#handleEnd);
45
- target.removeEventListener("keydown", this.#handleKeydown);
46
- }
49
+ this.#connected = false;
50
+ for (const target of this.#observedTargets) this.#release(target);
47
51
  this.#observedTargets.clear();
48
- this.#activeTargets.clear();
52
+ this.#letGo();
49
53
  this.#confirmedTarget = null;
54
+ this.#keyComposing = false;
55
+ this.#abandoned = null;
50
56
  }
51
- /** True when lifecycle tracking or the current event reports composition. */
52
57
  isComposing(event) {
53
- return this.#activeTargets.size > 0 || event?.isComposing === true;
54
- }
55
- /**
56
- * Whether `event` is the `input` echoing the composition just confirmed.
57
- *
58
- * Asking closes the window either way, so one confirmation is folded at most
59
- * once and a consumer asks once per `input`.
60
- */
58
+ this.#settle();
59
+ return event?.isComposing === true || this.#composition !== null;
60
+ }
61
+ composingElement() {
62
+ this.#settle();
63
+ return this.#composition?.element ?? null;
64
+ }
65
+ owns(event) {
66
+ const element = this.composingElement();
67
+ return event.isComposing === true || element !== null && element === event.target;
68
+ }
61
69
  consumesConfirmedInput(event) {
62
70
  const confirmed = this.#confirmedTarget;
63
71
  this.#confirmedTarget = null;
64
72
  if (confirmed === null || confirmed !== event.target) return false;
65
73
  const inputType = event.inputType;
66
- return !inputType || COMPOSITION_INPUT_TYPES.has(inputType);
74
+ return !inputType || isCompositionInputType(inputType);
75
+ }
76
+ #release(target) {
77
+ target.removeEventListener("compositionstart", this.#handleStart);
78
+ target.removeEventListener("compositionend", this.#handleEnd);
79
+ target.removeEventListener("keydown", this.#handleKeydown, true);
80
+ target.removeEventListener("beforeinput", this.#handleBeforeInput, true);
81
+ target.removeEventListener("input", this.#handleInput, true);
82
+ target.removeEventListener("blur", this.#handleBlur, true);
83
+ target.removeEventListener(BEFORE_MORPH_ATTRIBUTE, this.#handleBeforeMorphAttribute);
67
84
  }
85
+ #letGo() {
86
+ const composition = this.#composition;
87
+ if (composition === null) return;
88
+ if (!holdsFocus(composition.element)) {
89
+ this.#composition = null;
90
+ return;
91
+ }
92
+ queueMicrotask(() => {
93
+ if (this.#composition !== composition || this.#observedTargets.has(composition.target)) {
94
+ return;
95
+ }
96
+ this.#composition = null;
97
+ if (!this.#connected) return;
98
+ this.#abandoned = { element: composition.element, inPlace: true };
99
+ this.#runAbandon();
100
+ });
101
+ }
102
+ #settle() {
103
+ const composition = this.#composition;
104
+ if (composition === null) return;
105
+ const { target, element, text } = composition;
106
+ if (target instanceof Node && element instanceof Node && !target.contains(element)) {
107
+ this.#composition = null;
108
+ } else if (textOf(element) !== text) {
109
+ this.#abandon(false);
110
+ }
111
+ }
112
+ #abandon(inPlace) {
113
+ this.#owe(inPlace);
114
+ this.#composition = null;
115
+ queueMicrotask(this.#runAbandon);
116
+ }
117
+ #owe(inPlace) {
118
+ const composition = this.#composition;
119
+ if (composition !== null) this.#abandoned = { element: composition.element, inPlace };
120
+ }
121
+ #runAbandon = () => {
122
+ const abandoned = this.#abandoned;
123
+ if (abandoned === null) return;
124
+ this.#abandoned = null;
125
+ this.#onAbandon?.(abandoned.element, abandoned.inPlace);
126
+ };
68
127
  #handleStart = (event) => {
69
128
  this.#confirmedTarget = null;
70
- if (event.currentTarget) this.#activeTargets.add(event.currentTarget);
129
+ this.#settle();
130
+ this.#owe(true);
131
+ const target = event.currentTarget;
132
+ const element = event.target;
133
+ this.#composition = { target, element, text: textOf(element) };
134
+ this.#runAbandon();
71
135
  this.#onStart?.(event);
72
136
  };
73
137
  #handleEnd = (event) => {
74
- if (event.currentTarget) this.#activeTargets.delete(event.currentTarget);
138
+ this.#runAbandon();
139
+ if (this.#composition?.target === event.currentTarget) this.#composition = null;
75
140
  this.#confirmedTarget = event.target;
76
141
  this.#onEnd?.(event);
77
142
  };
78
- /** A key on an observed field opens an edit of its own, so no echo is owed. */
79
- #handleKeydown = () => {
143
+ #handleKeydown = (event) => {
144
+ this.#settle();
145
+ this.#runAbandon();
80
146
  this.#confirmedTarget = null;
147
+ this.#keyComposing = event.isComposing === true;
148
+ };
149
+ #handleBeforeInput = (event) => {
150
+ const keyComposing = this.#keyComposing;
151
+ this.#keyComposing = false;
152
+ this.#settle();
153
+ const { isComposing, inputType } = event;
154
+ if (this.#composition !== null && !keyComposing && !isComposing && inputType && !isCompositionInputType(inputType)) {
155
+ this.#abandon(true);
156
+ }
157
+ this.#runAbandon();
158
+ };
159
+ #handleInput = (event) => {
160
+ const composition = this.#composition;
161
+ const { isTrusted, isComposing, inputType } = event;
162
+ if (composition !== null && event.target === composition.element && (isTrusted || isComposing || isCompositionInputType(inputType))) {
163
+ composition.text = textOf(composition.element);
164
+ } else {
165
+ this.#settle();
166
+ }
167
+ this.#runAbandon();
168
+ };
169
+ #handleBlur = (event) => {
170
+ this.#settle();
171
+ this.#runAbandon();
172
+ const composition = this.#composition;
173
+ if (composition === null || composition.target === composition.element) return;
174
+ const { element } = composition;
175
+ if (!(element instanceof Node) || event.target !== element) return;
176
+ const root = element.getRootNode();
177
+ if (root.activeElement !== element) this.#composition = null;
178
+ };
179
+ #handleBeforeMorphAttribute = (event) => {
180
+ this.#settle();
181
+ const composition = this.#composition;
182
+ if (composition?.target !== event.currentTarget || event.target !== composition.element) return;
183
+ const detail = event.detail;
184
+ if (detail?.attributeName === "value") event.preventDefault();
81
185
  };
82
186
  };
83
187
 
84
- // src/utils/declared_value.ts
85
188
  function parseDeclared(raw, parse, fallback) {
86
189
  try {
87
190
  return parse(raw);
@@ -105,7 +208,43 @@ function parseJsonObject(raw) {
105
208
  return parsed;
106
209
  }
107
210
 
108
- // src/utils/focus_candidate.ts
211
+ var DetachGate = class _DetachGate {
212
+ #pending = false;
213
+ get pending() {
214
+ return this.#pending;
215
+ }
216
+ static isDetached(host) {
217
+ return !host.element.isConnected || !_DetachGate.#listed(host);
218
+ }
219
+ disconnected(host, teardown) {
220
+ const carried = _DetachGate.#carried(host);
221
+ if (!carried && _DetachGate.isDetached(host)) {
222
+ this.#pending = false;
223
+ teardown();
224
+ return;
225
+ }
226
+ this.#pending = true;
227
+ const probe = () => {
228
+ if (!this.#pending) return;
229
+ this.#pending = false;
230
+ teardown();
231
+ };
232
+ if (carried) setTimeout(probe, 0);
233
+ else queueMicrotask(probe);
234
+ }
235
+ static #carried(host) {
236
+ const element = host.element;
237
+ return !element.isConnected && element.closest("[data-turbo-permanent]") !== null && _DetachGate.#listed(host);
238
+ }
239
+ static #listed(host) {
240
+ const tokens = (host.element.getAttribute("data-controller") ?? "").split(/\s+/);
241
+ return tokens.includes(host.identifier);
242
+ }
243
+ cancel() {
244
+ this.#pending = false;
245
+ }
246
+ };
247
+
109
248
  function inheritsFieldsetDisabled(control) {
110
249
  let fieldset = control.closest("fieldset[disabled]");
111
250
  while (fieldset) {
@@ -116,7 +255,120 @@ function inheritsFieldsetDisabled(control) {
116
255
  return false;
117
256
  }
118
257
 
119
- // src/utils/half_width.ts
258
+ function sharedRegistry(key, create) {
259
+ const symbol = Symbol.for(key);
260
+ const scope = globalThis;
261
+ const existing = scope[symbol];
262
+ if (existing !== void 0) return existing;
263
+ const registry = create();
264
+ Object.defineProperty(globalThis, symbol, { value: registry });
265
+ return registry;
266
+ }
267
+
268
+ var PREFIX = "__stimeo_raw_v1_";
269
+ var documents = sharedRegistry(
270
+ "stimeo-ui.form-data-projection.registry.v1",
271
+ () => /* @__PURE__ */ new WeakMap()
272
+ );
273
+ function decodedName(key) {
274
+ if (!key.startsWith(PREFIX)) return null;
275
+ const separator = PREFIX.length + 32;
276
+ if (key[separator] !== ":") return null;
277
+ try {
278
+ const name = JSON.parse(key.slice(separator + 1));
279
+ return typeof name === "string" ? name : null;
280
+ } catch {
281
+ return null;
282
+ }
283
+ }
284
+ function projectedFieldName(name) {
285
+ return decodedName(name) ?? name;
286
+ }
287
+ function forDocument(document2) {
288
+ const existing = documents.get(document2);
289
+ if (existing) return existing;
290
+ const state = {
291
+ fields: /* @__PURE__ */ new Map(),
292
+ byField: /* @__PURE__ */ new WeakMap(),
293
+ handle: (event) => {
294
+ const data = event.formData;
295
+ if (!data) return;
296
+ const entries = [...data.entries()];
297
+ let changed = false;
298
+ const projected = entries.map(([key, value]) => {
299
+ const name = decodedName(key);
300
+ if (name === null) return [key, value];
301
+ changed = true;
302
+ const field = state.fields.get(key);
303
+ const live = field && field.field.name === key && field.field.form === event.target;
304
+ return [name, live ? field.project(value) : ""];
305
+ });
306
+ if (!changed) return;
307
+ for (const key of new Set(data.keys())) data.delete(key);
308
+ for (const [name, value] of projected) data.append(name, value);
309
+ }
310
+ };
311
+ documents.set(document2, state);
312
+ document2.addEventListener("formdata", state.handle, { capture: true });
313
+ return state;
314
+ }
315
+ function prepareFormDataProjection(form) {
316
+ const state = forDocument(form.ownerDocument);
317
+ form.addEventListener("formdata", state.handle, { capture: true });
318
+ }
319
+ var FormDataProjection = class {
320
+ #held = null;
321
+ hold(field, project) {
322
+ const held = this.#held;
323
+ if (held?.field === field && held.key === field.name && held.document === field.ownerDocument) {
324
+ if (field.form) prepareFormDataProjection(field.form);
325
+ return;
326
+ }
327
+ this.release();
328
+ const name = projectedFieldName(field.name);
329
+ if (name === "" || field.type === "hidden" && name.toLowerCase() === "_charset_") return;
330
+ const state = forDocument(field.ownerDocument);
331
+ if (field.form) prepareFormDataProjection(field.form);
332
+ const previous = state.byField.get(field);
333
+ if (previous) {
334
+ state.fields.delete(previous.key);
335
+ field.removeEventListener("turbo:morph-element", previous.restore);
336
+ }
337
+ const nonce = Array.from(
338
+ crypto.getRandomValues(new Uint8Array(16)),
339
+ (value) => value.toString(16).padStart(2, "0")
340
+ ).join("");
341
+ const key = `${PREFIX}${nonce}:${JSON.stringify(name)}`;
342
+ const projection = {
343
+ field,
344
+ key,
345
+ name,
346
+ project,
347
+ document: field.ownerDocument,
348
+ state,
349
+ restore: () => {
350
+ if (field.name === name) field.name = key;
351
+ }
352
+ };
353
+ state.fields.set(key, projection);
354
+ state.byField.set(field, projection);
355
+ this.#held = projection;
356
+ field.name = key;
357
+ field.addEventListener("turbo:morph-element", projection.restore);
358
+ }
359
+ release() {
360
+ const held = this.#held;
361
+ this.#held = null;
362
+ if (held === null) return;
363
+ held.field.removeEventListener("turbo:morph-element", held.restore);
364
+ const state = held.state;
365
+ if (state.byField.get(held.field) !== held) return;
366
+ state.fields.delete(held.key);
367
+ state.byField.delete(held.field);
368
+ if (held.field.name === held.key) held.field.name = held.name;
369
+ }
370
+ };
371
+
120
372
  var FULL_WIDTH_SHIFT = 65248;
121
373
  function halfWidthChar(char) {
122
374
  if (char >= "\uFF01" && char <= "\uFF5E") {
@@ -125,13 +377,123 @@ function halfWidthChar(char) {
125
377
  return char === "\u3000" ? " " : char;
126
378
  }
127
379
 
128
- // src/controllers/input_mask_controller.ts
380
+ var ListenerSet = class {
381
+ #abort = new AbortController();
382
+ add(target, type, handler, options) {
383
+ target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
384
+ }
385
+ dispose() {
386
+ this.#abort.abort();
387
+ this.#abort = new AbortController();
388
+ }
389
+ };
390
+
391
+ var MicrotaskCoalescer = class {
392
+ #run;
393
+ #queued = false;
394
+ #active = false;
395
+ #generation = 0;
396
+ constructor(run) {
397
+ this.#run = run;
398
+ }
399
+ activate() {
400
+ this.#active = true;
401
+ }
402
+ cancel() {
403
+ this.#active = false;
404
+ this.#queued = false;
405
+ this.#generation += 1;
406
+ }
407
+ get pending() {
408
+ return this.#queued;
409
+ }
410
+ schedule() {
411
+ if (!this.#active || this.#queued) return;
412
+ this.#queued = true;
413
+ const generation = this.#generation;
414
+ queueMicrotask(() => {
415
+ if (generation !== this.#generation || !this.#queued || !this.#active) return;
416
+ this.#queued = false;
417
+ this.#run();
418
+ });
419
+ }
420
+ };
421
+
422
+ var MorphRenderWatcher = class {
423
+ #listeners = new ListenerSet();
424
+ #pass;
425
+ #element = null;
426
+ #onMorph = () => this.#pass.schedule();
427
+ constructor(run) {
428
+ this.#pass = new MicrotaskCoalescer(run);
429
+ }
430
+ observe(element) {
431
+ if (this.#element === element) return;
432
+ this.disconnect();
433
+ this.#element = element;
434
+ this.#pass.activate();
435
+ this.#listeners.add(element, "turbo:morph-element", this.#onMorph);
436
+ }
437
+ schedule() {
438
+ this.#pass.schedule();
439
+ }
440
+ get pending() {
441
+ return this.#pass.pending;
442
+ }
443
+ disconnect() {
444
+ this.#listeners.dispose();
445
+ this.#pass.cancel();
446
+ this.#element = null;
447
+ }
448
+ };
449
+
450
+ var TimerRegistry = class {
451
+ ids = /* @__PURE__ */ new Set();
452
+ clear(id) {
453
+ if (this.ids.delete(id)) {
454
+ this.cancel(id);
455
+ }
456
+ }
457
+ clearAll() {
458
+ for (const id of this.ids) {
459
+ this.cancel(id);
460
+ }
461
+ this.ids.clear();
462
+ }
463
+ get size() {
464
+ return this.ids.size;
465
+ }
466
+ };
467
+ var SafeTimeout = class extends TimerRegistry {
468
+ set(callback, delay) {
469
+ const id = this.schedule(() => {
470
+ this.ids.delete(id);
471
+ callback();
472
+ }, delay);
473
+ this.ids.add(id);
474
+ return id;
475
+ }
476
+ schedule(callback, delay) {
477
+ return window.setTimeout(callback, delay);
478
+ }
479
+ cancel(id) {
480
+ window.clearTimeout(id);
481
+ }
482
+ };
483
+
484
+ function prepareInputMaskForm(form) {
485
+ prepareFormDataProjection(form);
486
+ }
129
487
  var DEFAULT_TOKENS = {
130
488
  "9": "\\d",
131
489
  a: "[A-Za-z]",
132
490
  "*": "[A-Za-z0-9]"
133
491
  };
134
492
  var UNMASK_ATTR = "unmask";
493
+ var rawWriters = sharedRegistry(
494
+ "stimeo-ui.input-mask-raw-writer.registry.v1",
495
+ () => /* @__PURE__ */ new WeakMap()
496
+ );
135
497
  function acceptedForm(regex, char) {
136
498
  if (regex.test(char)) return char;
137
499
  const half = halfWidthChar(char);
@@ -208,7 +570,6 @@ function tokenCharOffset(tokenFlags, n) {
208
570
  return -1;
209
571
  }
210
572
  var InputMaskController = class extends Controller {
211
- /** The attribute above, in the namespace this controller is registered under. */
212
573
  get #unmaskAttribute() {
213
574
  return `data-${this.identifier}-${UNMASK_ATTR}`;
214
575
  }
@@ -219,19 +580,16 @@ var InputMaskController = class extends Controller {
219
580
  };
220
581
  static actions = ["format"];
221
582
  static events = ["change", "reconcile"];
222
- /** The value this controller last committed, and the baseline both events compare. */
223
583
  #lastValue = null;
224
584
  #started = false;
225
- /** Validated token map; the hot path never parses the `tokens` declaration. */
585
+ #rawSink = null;
586
+ #rawValue = "";
587
+ #rawSourceForm = null;
588
+ #submission = new FormDataProjection();
226
589
  #tokens = compileTokens("");
227
- /** The field's text when the running composition began. */
228
590
  #textBeforeComposition = "";
229
- /**
230
- * Holds mid-composition input so the IME's uncommitted text is never rewritten,
231
- * and formats the confirmed text once when the composition ends. A composition
232
- * that ends on the text it began with committed nothing, so a re-format then is
233
- * the page's: the mask changed while it ran.
234
- */
591
+ #formatted = null;
592
+ #shown = { result: null, empty: true };
235
593
  #composition = new CompositionTracker({
236
594
  onStart: () => {
237
595
  this.#textBeforeComposition = this.element.value;
@@ -239,9 +597,11 @@ var InputMaskController = class extends Controller {
239
597
  onEnd: () => {
240
598
  const committedNothing = this.element.value === this.#textBeforeComposition;
241
599
  this.#reformat(committedNothing ? "reconcile" : "edit");
600
+ },
601
+ onAbandon: () => {
602
+ if (this.#formatted !== this.#declared) this.#reformat("reconcile");
242
603
  }
243
604
  });
244
- /** Re-parses the declaration and re-formats under the tokens it now selects. */
245
605
  tokensValueChanged() {
246
606
  this.#tokens = compileTokens(this.tokensValue);
247
607
  if (this.#started) this.#reformat("reconcile");
@@ -249,41 +609,55 @@ var InputMaskController = class extends Controller {
249
609
  patternValueChanged() {
250
610
  if (this.#started) this.#reformat("reconcile");
251
611
  }
252
- /** Clears a sink it stops maintaining so a submit cannot carry a stale raw value. */
253
612
  unmaskToHiddenValueChanged() {
254
613
  if (!this.#started) return;
255
- if (!this.unmaskToHiddenValue) {
256
- const sink = this.#resolveSink();
257
- if (sink) sink.value = "";
258
- }
614
+ if (!this.unmaskToHiddenValue) this.#withdraw();
259
615
  this.#reformat("reconcile");
260
616
  }
617
+ #withdraw() {
618
+ if (this.#retractRaw() && this.#composition.isComposing()) this.#formatted = null;
619
+ }
620
+ #morph = new MorphRenderWatcher(() => this.#reformat("reconcile"));
621
+ #gate = new DetachGate();
622
+ #adoption = new SafeTimeout();
261
623
  connect() {
624
+ this.#gate.cancel();
625
+ this.#morph.observe(this.element);
262
626
  this.#started = true;
263
627
  this.#composition.observe(this.element);
628
+ if (!this.unmaskToHiddenValue) this.#withdraw();
629
+ if (this.#composition.isComposing()) {
630
+ this.#reformat("reconcile");
631
+ return;
632
+ }
264
633
  this.#lastValue = this.element.value;
265
634
  this.#reformat("reconcile");
635
+ if (this.unmaskToHiddenValue && this.#rawSink === null) {
636
+ this.#adoption.set(() => this.#adoptSink(), 0);
637
+ }
266
638
  }
267
639
  disconnect() {
640
+ this.#morph.disconnect();
268
641
  this.#started = false;
269
642
  this.#composition.disconnect();
643
+ this.#adoption.clearAll();
644
+ this.#gate.disconnected(this, () => this.#retractRaw());
270
645
  }
271
- /** Formats the field on input, preserving the caret. Bound via `data-action`. */
272
646
  format(event) {
273
647
  if (this.#composition.isComposing(event)) return;
274
648
  this.#reformat("edit", deletionOf(event));
275
649
  }
276
- /**
277
- * Core reformat: mask the current value, restore the caret, sync the sink and
278
- * the state hooks, and report a moved value under the event `cause` selects.
279
- *
280
- * @stimeoRenderRoot
281
- */
282
650
  #reformat(cause, deletion = null) {
283
- if (this.#composition.isComposing()) return;
651
+ if (this.#composition.isComposing()) {
652
+ this.#showAgain();
653
+ return;
654
+ }
655
+ this.#formatted = this.#declared;
284
656
  const input = this.element;
285
657
  const raw = input.value;
286
658
  if (this.patternValue === "") {
659
+ this.#retractRaw();
660
+ this.#shown = { result: null, empty: raw.length === 0 };
287
661
  this.#flag("data-mask-complete", false);
288
662
  this.#flag("data-mask-empty", raw.length === 0);
289
663
  this.#lastValue = raw;
@@ -309,8 +683,10 @@ var InputMaskController = class extends Controller {
309
683
  this.#lastValue = raw;
310
684
  return;
311
685
  }
312
- input.value = result.masked;
313
- this.#restoreCaret(result.tokenFlags, anchor);
686
+ if (input.value !== result.masked) {
687
+ input.value = result.masked;
688
+ this.#restoreCaret(result.tokenFlags, anchor);
689
+ }
314
690
  this.#publish(result, result.masked);
315
691
  if (result.masked === this.#lastValue) return;
316
692
  this.#lastValue = result.masked;
@@ -318,24 +694,59 @@ var InputMaskController = class extends Controller {
318
694
  if (cause === "edit") this.dispatch("change", { detail });
319
695
  else this.dispatch("reconcile", { detail });
320
696
  }
321
- /** Syncs the raw-value sink and the state hooks for the `shown` field text. */
697
+ get #declared() {
698
+ return JSON.stringify([this.patternValue, this.tokensValue, this.unmaskToHiddenValue]);
699
+ }
322
700
  #publish(result, shown) {
701
+ this.#shown = { result, empty: shown.length === 0 };
323
702
  if (this.unmaskToHiddenValue) {
324
703
  const sink = this.#resolveSink();
325
- if (sink) sink.value = result.unmasked;
704
+ if (sink !== this.#rawSink) this.#retractRaw();
705
+ if (sink) {
706
+ sink.value = result.unmasked;
707
+ rawWriters.set(sink, this);
708
+ this.#rawSink = sink;
709
+ this.#rawValue = result.unmasked;
710
+ this.#rawSourceForm = this.element.form;
711
+ this.#submission.hold(sink, (value) => this.#submittedValue(sink, value));
712
+ }
326
713
  }
327
714
  this.#flag("data-mask-complete", result.complete);
328
715
  this.#flag("data-mask-empty", shown.length === 0);
329
716
  }
330
- /**
331
- * How many token slots the text before the caret fills. Masking that prefix is
332
- * what makes a rejected character — or a literal that also matches a token —
333
- * count exactly as the rendering counts it, so the caret cannot drift.
334
- */
717
+ #showAgain() {
718
+ const shown = this.#shown;
719
+ const sink = this.#rawSink;
720
+ if (shown.result !== null && this.unmaskToHiddenValue && sink !== null && rawWriters.get(sink) === this && this.#resolveSink() === sink) {
721
+ sink.value = shown.result.unmasked;
722
+ }
723
+ this.#flag("data-mask-complete", shown.result?.complete ?? false);
724
+ this.#flag("data-mask-empty", shown.empty);
725
+ }
726
+ #retractRaw() {
727
+ const sink = this.#rawSink;
728
+ this.#rawSink = null;
729
+ this.#submission.release();
730
+ if (sink === null || rawWriters.get(sink) !== this) return false;
731
+ rawWriters.delete(sink);
732
+ if (sink.value === this.#rawValue) sink.value = "";
733
+ return true;
734
+ }
735
+ #submittedValue(sink, value) {
736
+ if (rawWriters.get(sink) !== this || sink.value !== this.#rawValue || value !== this.#rawValue)
737
+ return value;
738
+ const source = this.element;
739
+ const listed = (source.getAttribute("data-controller") ?? "").split(/\s+/).includes(this.identifier);
740
+ const associated = source.form === null ? this.#rawSourceForm === null : source.form === sink.form;
741
+ const eligible = source.isConnected && this.application.element.contains(source) && listed && this.unmaskToHiddenValue && associated;
742
+ return eligible ? value : "";
743
+ }
744
+ #adoptSink() {
745
+ if (this.#resolveSink() !== null) this.#reformat("reconcile");
746
+ }
335
747
  #significantBefore(prefix) {
336
748
  return applyMask(prefix, this.patternValue, this.#tokens).unmasked.length;
337
749
  }
338
- /** Places the caret after the `n`-th token char (skipping following literals). */
339
750
  #restoreCaret(tokenFlags, n) {
340
751
  let position;
341
752
  if (n <= 0) {
@@ -357,23 +768,6 @@ var InputMaskController = class extends Controller {
357
768
  } catch {
358
769
  }
359
770
  }
360
- /**
361
- * The hidden raw-value sink for this input, resolved so several masked inputs
362
- * can coexist in one form:
363
- *
364
- * 1. **Explicit pairing** — a sink whose attribute value names this input's
365
- * `id` (`data-stimeo--input-mask-unmask="zip"`).
366
- * 2. **Nearest container** — otherwise, walking up from the input, the first
367
- * *value-less* sink in the closest ancestor. Wrapped input+sink pairs each
368
- * find their own sink, and a single form-level sink is found the same
369
- * way. A sink claimed by another input's id is never matched here.
370
- *
371
- * Both steps only ever consider the associated form's own controls, so a sink
372
- * belonging to a different form (or to none) is never written, while one the
373
- * `form` attribute associates from elsewhere in the document still resolves —
374
- * for either the input or the sink, neither of which needs to contain or be
375
- * contained by the form. A form-less input reads the document instead.
376
- */
377
771
  #resolveSink() {
378
772
  const candidates = this.#sinkCandidates();
379
773
  const id = this.element.id;
@@ -389,12 +783,6 @@ var InputMaskController = class extends Controller {
389
783
  }
390
784
  return null;
391
785
  }
392
- /**
393
- * Every sink the input's form owns, in document order — one collection read per
394
- * resolution, so the cost tracks the form's own controls and not the depth of
395
- * the markup around it. `form.elements` lists controls the `form` attribute
396
- * associates from anywhere in the document, and lists nothing another form owns.
397
- */
398
786
  #sinkCandidates() {
399
787
  const form = this.element.form;
400
788
  if (form === null) {
@@ -406,13 +794,11 @@ var InputMaskController = class extends Controller {
406
794
  (element) => element instanceof HTMLInputElement && element.hasAttribute(this.#unmaskAttribute)
407
795
  );
408
796
  }
409
- /** Sets a boolean `data-*` flag to `"true"` when `on`, else removes it. */
410
797
  #flag(name, on) {
411
798
  if (on) this.element.setAttribute(name, "true");
412
799
  else this.element.removeAttribute(name);
413
800
  }
414
801
  };
415
802
 
416
- export { InputMaskController, applyMask };
417
- //# sourceMappingURL=input_mask_controller.js.map
803
+ export { InputMaskController, applyMask, prepareInputMaskForm };
418
804
  //# sourceMappingURL=input_mask_controller.js.map