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
@@ -4,7 +4,7 @@ import { Controller } from '@hotwired/stimulus';
4
4
  * Headless progress UI for ActiveStorage Direct Uploads: subscribes to the
5
5
  * `direct-upload:*` events and renders a per-file progress row (no dedicated APG
6
6
  * pattern; the rows follow the `role="progressbar"` practice). The companion to
7
- * {@link FileDropzoneController}, which leaves transport out of scope.
7
+ * `stimeo--file-dropzone`, which leaves transport out of scope.
8
8
  *
9
9
  * Markup contract (identifier: `stimeo--direct-upload`):
10
10
  * <div data-controller="stimeo--direct-upload"
@@ -25,8 +25,8 @@ import { Controller } from '@hotwired/stimulus';
25
25
  * fills `[data-field="name"]` and becomes the row's `aria-label` unless the
26
26
  * template already authors one. The aggregate across live rows is mirrored on
27
27
  * the controller element as `data-upload-progress` plus the same custom
28
- * property, recomputed whenever a row is added, updated, or removed, and
29
- * withdrawn entirely once no rows remain.
28
+ * property, recomputed whenever a row is added, updated, or removed, or a `list`
29
+ * leaves, and withdrawn entirely once no rows remain.
30
30
  *
31
31
  * A row leaves `uploading` exactly once: `direct-upload:error` settles it as
32
32
  * `error`, and `direct-upload:end` — which ActiveStorage fires after success
@@ -49,7 +49,8 @@ import { Controller } from '@hotwired/stimulus';
49
49
  * - `stimeo--direct-upload:done` dispatches `{ id: string }` when an upload
50
50
  * completes successfully.
51
51
  * - `stimeo--direct-upload:reconcile` dispatches `{ ids: string[] }` — the uploads
52
- * the Turbo cache rewind discarded, none of which can still finish.
52
+ * whose rows a page restored from the Turbo cache still showed, none of which can
53
+ * still finish.
53
54
  * - `stimeo--direct-upload:error` dispatches `{ id: string, error: string }`
54
55
  * when an upload fails.
55
56
  *
@@ -57,10 +58,18 @@ import { Controller } from '@hotwired/stimulus';
57
58
  * Behavior only — no bars are drawn. The `direct-upload:*` listeners live on
58
59
  * `document` (the events bubble there) and are removed on `disconnect()` (Turbo
59
60
  * navigation included), along with any pending removal timers, so a callback
60
- * that arrives after teardown never touches a detached row. Rows are transient
61
- * UI: just before Turbo caches the page they are removed and the aggregate is
62
- * withdrawn, so a restored snapshot starts pristine instead of replaying stale
63
- * rows (a dead upload cannot resume after restoration). The live DOM stays the
61
+ * that arrives after teardown never touches a detached row. `removeOnDone` follows a
62
+ * change made while connected: turning it off cancels every pending removal, turning
63
+ * it on arms one for each completed row still shown, with the full delay from then,
64
+ * and a row never holds more than one pending removal. Rows are transient
65
+ * UI, and each carries `data-<identifier>-generated` with its upload id. A page Turbo
66
+ * restores from its cache is a copy that still shows them, so a connection holding no
67
+ * row of its own removes the marked rows in its list, withdraws the aggregate and
68
+ * reports the discarded ids as `reconcile` (a dead upload cannot resume after
69
+ * restoration). Nothing is removed on `turbo:before-cache`, which Turbo also
70
+ * dispatches on pages that stay — a promoted frame navigation, a state-less
71
+ * `popstate`, a refresh of a cached URL, a `data-turbo-permanent` element carried to
72
+ * the next page — where the uploads are still running. The live DOM stays the
64
73
  * source of truth — a row removed or replaced outside this controller is
65
74
  * forgotten and rebuilt on the next event for its id, and a clone stranded
66
75
  * outside the current `list` (a re-pointed target) is removed outright, so
@@ -106,6 +115,14 @@ declare class DirectUploadController extends Controller<HTMLElement> {
106
115
  disconnect(): void;
107
116
  /** Validates `scope` once so the per-event path never parses or throws. */
108
117
  scopeValueChanged(): void;
118
+ /**
119
+ * Follows `removeOnDone` changed at runtime: off cancels every pending removal, on
120
+ * arms one for each completed row that has none, with the full delay from now.
121
+ * Stimulus also calls this ahead of `connect()`, which arms the removals itself.
122
+ */
123
+ removeOnDoneValueChanged(): void;
124
+ /** Recounts the aggregate once a list leaves, retiring rows outside the list that stays. */
125
+ listTargetDisconnected(): void;
109
126
  }
110
127
 
111
128
  export { DirectUploadController };
@@ -1,8 +1,12 @@
1
1
  import { Controller } from '@hotwired/stimulus';
2
2
 
3
- // src/controllers/direct_upload_controller.ts
3
+ function fillTemplate(template, values) {
4
+ return template.replace(/\{([a-zA-Z][a-zA-Z0-9]*)\}/g, (match, name) => {
5
+ const replacement = Object.hasOwn(values, name) ? values[name] : void 0;
6
+ return replacement === void 0 ? match : String(replacement);
7
+ });
8
+ }
4
9
 
5
- // src/utils/announce.ts
6
10
  function announce(message, options = {}) {
7
11
  const text = message.trim();
8
12
  if (text.length === 0) return;
@@ -12,43 +16,7 @@ function announce(message, options = {}) {
12
16
  })
13
17
  );
14
18
  }
15
- function fillTemplate(template, values) {
16
- return template.replace(/\{([a-zA-Z][a-zA-Z0-9]*)\}/g, (match, name) => {
17
- const replacement = values[name];
18
- return replacement === void 0 ? match : String(replacement);
19
- });
20
- }
21
-
22
- // src/utils/before_cache_reset.ts
23
- var BeforeCacheReset = class _BeforeCacheReset {
24
- /** Every subscribed instance, iterated by the one shared document listener. */
25
- static #subscribers = /* @__PURE__ */ new Set();
26
- /** The shared listener; installed while at least one instance is subscribed. */
27
- static #onBeforeCache = () => {
28
- for (const subscriber of _BeforeCacheReset.#subscribers) subscriber.#rewind();
29
- };
30
- #rewind;
31
- /** @param rewind - the pass that returns this controller's state to its initial form. */
32
- constructor(rewind) {
33
- this.#rewind = rewind;
34
- }
35
- /** Subscribes to `turbo:before-cache`; call from `connect()`. Idempotent. */
36
- activate() {
37
- const first = _BeforeCacheReset.#subscribers.size === 0;
38
- _BeforeCacheReset.#subscribers.add(this);
39
- if (first) {
40
- document.addEventListener("turbo:before-cache", _BeforeCacheReset.#onBeforeCache);
41
- }
42
- }
43
- /** Unsubscribes; call from `disconnect()`. Safe when never subscribed. */
44
- deactivate() {
45
- _BeforeCacheReset.#subscribers.delete(this);
46
- if (_BeforeCacheReset.#subscribers.size > 0) return;
47
- document.removeEventListener("turbo:before-cache", _BeforeCacheReset.#onBeforeCache);
48
- }
49
- };
50
19
 
51
- // src/utils/declared_value.ts
52
20
  function parseDeclared(raw, parse, fallback) {
53
21
  try {
54
22
  return parse(raw);
@@ -68,43 +36,24 @@ function validSelector(element, raw, fallback) {
68
36
  );
69
37
  }
70
38
 
71
- // src/utils/safe_timeout.ts
72
39
  var TimerRegistry = class {
73
- /** Live timer ids that have not yet been cleared (or, for timeouts, fired). */
74
40
  ids = /* @__PURE__ */ new Set();
75
- /**
76
- * Cancels a single tracked timer.
77
- *
78
- * No-ops if the id is unknown (already cleared, fired, or never owned by this
79
- * registry), so callers can clear defensively without guarding.
80
- */
81
41
  clear(id) {
82
42
  if (this.ids.delete(id)) {
83
43
  this.cancel(id);
84
44
  }
85
45
  }
86
- /**
87
- * Cancels every tracked timer. Call this from a controller's `disconnect()`
88
- * to guarantee no timer outlives the element.
89
- */
90
46
  clearAll() {
91
47
  for (const id of this.ids) {
92
48
  this.cancel(id);
93
49
  }
94
50
  this.ids.clear();
95
51
  }
96
- /** Number of timers currently tracked (pending). */
97
52
  get size() {
98
53
  return this.ids.size;
99
54
  }
100
55
  };
101
56
  var SafeTimeout = class extends TimerRegistry {
102
- /**
103
- * Schedules `callback` after `delay` ms and returns the timer id.
104
- *
105
- * The id is removed from the registry automatically when the timeout fires,
106
- * so {@link TimerRegistry.size | size} reflects only still-pending timers.
107
- */
108
57
  set(callback, delay) {
109
58
  const id = this.schedule(() => {
110
59
  this.ids.delete(id);
@@ -121,14 +70,48 @@ var SafeTimeout = class extends TimerRegistry {
121
70
  }
122
71
  };
123
72
 
124
- // src/utils/template_row.ts
73
+ var KeyedTimers = class {
74
+ #timers = new SafeTimeout();
75
+ #pending = /* @__PURE__ */ new Map();
76
+ set(key, callback, delay) {
77
+ this.clear(key);
78
+ const id = this.#timers.set(() => {
79
+ this.#pending.delete(key);
80
+ callback();
81
+ }, delay);
82
+ this.#pending.set(key, id);
83
+ }
84
+ clear(key) {
85
+ this.#timers.clear(this.#pending.get(key) ?? -1);
86
+ this.#pending.delete(key);
87
+ }
88
+ clearAll() {
89
+ this.#timers.clearAll();
90
+ this.#pending.clear();
91
+ }
92
+ has(key) {
93
+ return this.#pending.has(key);
94
+ }
95
+ };
96
+
97
+ var ListenerSet = class {
98
+ #abort = new AbortController();
99
+ add(target, type, handler, options) {
100
+ target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
101
+ }
102
+ dispose() {
103
+ this.#abort.abort();
104
+ this.#abort = new AbortController();
105
+ }
106
+ };
107
+
125
108
  function cloneTemplateRoot(template) {
126
109
  const root = template.content.firstElementChild;
127
110
  return root instanceof HTMLElement ? root.cloneNode(true) : null;
128
111
  }
129
112
 
130
- // src/controllers/direct_upload_controller.ts
131
113
  var REMOVE_DELAY = 4e3;
114
+ var GENERATED_ATTRIBUTE = "generated";
132
115
  var DirectUploadController = class extends Controller {
133
116
  static targets = ["list", "row"];
134
117
  static values = {
@@ -138,10 +121,9 @@ var DirectUploadController = class extends Controller {
138
121
  scope: { type: String, default: "" }
139
122
  };
140
123
  static events = ["progress", "done", "error", "reconcile"];
141
- #timeouts = new SafeTimeout();
124
+ #removals = new KeyedTimers();
142
125
  #rows = /* @__PURE__ */ new Map();
143
- #beforeCache = new BeforeCacheReset(() => this.#rewindForCache());
144
- /** The validated `scope` selector; a broken declaration falls back to `""`. */
126
+ #connected = false;
145
127
  #scopeSelector = "";
146
128
  #onInitialize = (event) => {
147
129
  if (!this.#inScope(event)) return;
@@ -164,27 +146,46 @@ var DirectUploadController = class extends Controller {
164
146
  const detail = this.#detail(event);
165
147
  this.#complete(this.#key(detail.id), this.#name(detail));
166
148
  };
149
+ #listeners = new ListenerSet();
167
150
  connect() {
168
- document.addEventListener("direct-upload:initialize", this.#onInitialize);
169
- document.addEventListener("direct-upload:progress", this.#onProgress);
170
- document.addEventListener("direct-upload:error", this.#onError);
171
- document.addEventListener("direct-upload:end", this.#onEnd);
172
- this.#beforeCache.activate();
173
- this.#rescheduleRemovals();
151
+ this.#connected = true;
152
+ this.#listeners.add(document, "direct-upload:initialize", this.#onInitialize);
153
+ this.#listeners.add(document, "direct-upload:progress", this.#onProgress);
154
+ this.#listeners.add(document, "direct-upload:error", this.#onError);
155
+ this.#listeners.add(document, "direct-upload:end", this.#onEnd);
156
+ this.#discardInherited();
157
+ this.#syncRemovals();
174
158
  }
175
159
  disconnect() {
176
- document.removeEventListener("direct-upload:initialize", this.#onInitialize);
177
- document.removeEventListener("direct-upload:progress", this.#onProgress);
178
- document.removeEventListener("direct-upload:error", this.#onError);
179
- document.removeEventListener("direct-upload:end", this.#onEnd);
180
- this.#beforeCache.deactivate();
181
- this.#timeouts.clearAll();
182
- }
183
- /** Validates `scope` once so the per-event path never parses or throws. */
160
+ this.#connected = false;
161
+ this.#listeners.dispose();
162
+ this.#removals.clearAll();
163
+ }
164
+ get #generatedAttribute() {
165
+ return `data-${this.identifier}-${GENERATED_ATTRIBUTE}`;
166
+ }
167
+ #discardInherited() {
168
+ if (this.#rows.size > 0 || !this.hasListTarget) return;
169
+ const ids = [];
170
+ for (const row of Array.from(this.listTarget.children)) {
171
+ const id = row.getAttribute(this.#generatedAttribute);
172
+ if (id === null) continue;
173
+ row.remove();
174
+ ids.push(id);
175
+ }
176
+ if (ids.length === 0) return;
177
+ this.#syncAggregate();
178
+ this.dispatch("reconcile", { detail: { ids } });
179
+ }
184
180
  scopeValueChanged() {
185
181
  this.#scopeSelector = validSelector(this.element, this.scopeValue, "");
186
182
  }
187
- /** Updates a row's progress and the aggregate, emitting `progress`. */
183
+ removeOnDoneValueChanged() {
184
+ if (this.#connected) this.#syncRemovals();
185
+ }
186
+ listTargetDisconnected() {
187
+ if (this.#connected) this.#syncAggregate();
188
+ }
188
189
  #updateProgress(id, percent, name) {
189
190
  const row = this.#rowFor(id, name);
190
191
  if (row === null || this.#isSettled(row)) return;
@@ -192,12 +193,6 @@ var DirectUploadController = class extends Controller {
192
193
  this.#syncAggregate();
193
194
  this.dispatch("progress", { detail: { id, percent: clamped } });
194
195
  }
195
- /**
196
- * Marks a not-yet-settled row done at 100%, announces it, and emits `done`.
197
- *
198
- * @stimeoRuntimeOnly `announceDoneText` words the one announcement of this completion and
199
- * `removeOnDone` decides whether it arms the row's removal.
200
- */
201
196
  #complete(id, name) {
202
197
  const row = this.#rowFor(id, name);
203
198
  if (row === null || this.#isSettled(row)) return;
@@ -206,18 +201,8 @@ var DirectUploadController = class extends Controller {
206
201
  this.#syncAggregate();
207
202
  this.#announce(this.announceDoneTextValue, name, row);
208
203
  this.dispatch("done", { detail: { id } });
209
- if (this.removeOnDoneValue) {
210
- this.#timeouts.set(() => this.#removeRow(id), REMOVE_DELAY);
211
- }
204
+ if (this.removeOnDoneValue) this.#scheduleRemoval(id, row);
212
205
  }
213
- /**
214
- * Marks a not-yet-settled row failed, announces it, and emits `error`.
215
- * Returns whether the failure is rendered by this widget (used to decide the
216
- * `direct-upload:error` default), which also holds when the row already
217
- * displays an earlier failure.
218
- *
219
- * @stimeoRuntimeOnly `announceErrorText` words the one announcement of this failure.
220
- */
221
206
  #fail(id, error, name) {
222
207
  const row = this.#rowFor(id, name);
223
208
  if (row === null) return false;
@@ -227,27 +212,25 @@ var DirectUploadController = class extends Controller {
227
212
  this.dispatch("error", { detail: { id, error } });
228
213
  return true;
229
214
  }
230
- /** Whether the row reached a terminal state; settled rows are never rewritten. */
231
215
  #isSettled(row) {
232
216
  const state = row.getAttribute("data-upload-state");
233
217
  return state === "done" || state === "error";
234
218
  }
235
- /**
236
- * Re-arms `removeOnDone` for completed rows after a reconnect.
237
- *
238
- * @stimeoRuntimeOnly `removeOnDone` decides whether reconnecting arms the removal of finished
239
- * rows again.
240
- */
241
- #rescheduleRemovals() {
242
- if (!this.removeOnDoneValue) return;
219
+ #syncRemovals() {
220
+ if (!this.removeOnDoneValue) {
221
+ this.#removals.clearAll();
222
+ return;
223
+ }
243
224
  this.#prune();
244
225
  for (const [id, row] of this.#rows) {
245
- if (row.getAttribute("data-upload-state") === "done") {
246
- this.#timeouts.set(() => this.#removeRow(id), REMOVE_DELAY);
226
+ if (row.getAttribute("data-upload-state") === "done" && !this.#removals.has(id)) {
227
+ this.#scheduleRemoval(id, row);
247
228
  }
248
229
  }
249
230
  }
250
- /** Returns the live row for `id`, creating (and labeling) one on first sight. */
231
+ #scheduleRemoval(id, row) {
232
+ this.#removals.set(id, () => this.#removeRow(row), REMOVE_DELAY);
233
+ }
251
234
  #rowFor(id, name) {
252
235
  const key = this.#key(id);
253
236
  const existing = this.#rows.get(key);
@@ -256,13 +239,13 @@ var DirectUploadController = class extends Controller {
256
239
  this.#applyName(existing, name);
257
240
  return existing;
258
241
  }
259
- existing.remove();
260
- this.#rows.delete(key);
242
+ this.#retire(key, existing);
261
243
  }
262
244
  if (!this.hasRowTarget || !this.hasListTarget) return null;
263
245
  const clone = cloneTemplateRoot(this.rowTarget);
264
246
  if (!clone) return null;
265
247
  this.#applyName(clone, name);
248
+ clone.setAttribute(this.#generatedAttribute, key);
266
249
  clone.setAttribute("data-upload-state", "uploading");
267
250
  this.#applyProgress(clone, 0);
268
251
  this.listTarget.appendChild(clone);
@@ -270,20 +253,12 @@ var DirectUploadController = class extends Controller {
270
253
  this.#syncAggregate();
271
254
  return clone;
272
255
  }
273
- /**
274
- * Writes the event's file name into `[data-field="name"]` and, unless the row
275
- * already carries a non-blank `aria-label` — authored on the template or
276
- * applied by an earlier event — makes it the accessible name too. The visible
277
- * name never depends on the label: an authored label keeps its wording while
278
- * the field still shows which file this row tracks.
279
- */
280
256
  #applyName(row, name) {
281
257
  if (name.length === 0) return;
282
258
  this.#setField(row, "name", name);
283
259
  if ((row.getAttribute("aria-label") ?? "").trim().length > 0) return;
284
260
  row.setAttribute("aria-label", name);
285
261
  }
286
- /** Writes one progress value to every per-row hook; returns the clamped percent. */
287
262
  #applyProgress(row, percent) {
288
263
  const clamped = Math.max(0, Math.min(100, Math.round(percent)));
289
264
  row.setAttribute("aria-valuenow", String(clamped));
@@ -292,17 +267,10 @@ var DirectUploadController = class extends Controller {
292
267
  this.#setField(row, "percent", `${clamped}%`);
293
268
  return clamped;
294
269
  }
295
- #removeRow(id) {
296
- const row = this.#rows.get(id);
297
- if (row === void 0) return;
270
+ #removeRow(row) {
298
271
  row.remove();
299
- this.#rows.delete(id);
300
272
  this.#syncAggregate();
301
273
  }
302
- /**
303
- * Reflects the average progress across live rows on the controller element,
304
- * withdrawing both hooks once no rows remain.
305
- */
306
274
  #syncAggregate() {
307
275
  this.#prune();
308
276
  if (this.#rows.size === 0) {
@@ -318,50 +286,21 @@ var DirectUploadController = class extends Controller {
318
286
  this.element.setAttribute("data-upload-progress", String(overall));
319
287
  this.element.style.setProperty("--stimeo--upload-progress", `${overall}%`);
320
288
  }
321
- /**
322
- * Whether a bookkept row is still this widget's live UI: connected, and — when
323
- * a `list` target is present — inside the *current* one, so re-pointing the
324
- * target attribute at a new element retires rows kept alive in the old list.
325
- */
326
289
  #tracksRow(row) {
327
290
  if (!row.isConnected) return false;
328
291
  return !this.hasListTarget || this.listTarget.contains(row);
329
292
  }
330
- /**
331
- * Retires rows that left the live UI (list swap, external removal). A retired
332
- * clone is removed outright — generated rows only ever live under the current
333
- * `list`, so the before-cache rewind never has an untracked leftover to miss.
334
- */
335
293
  #prune() {
336
294
  for (const [id, row] of this.#rows) {
337
295
  if (this.#tracksRow(row)) continue;
338
- row.remove();
339
- this.#rows.delete(id);
296
+ this.#retire(id, row);
340
297
  }
341
298
  }
342
- /**
343
- * Rewinds for the snapshot and reports what that discarded. An upload in flight
344
- * cannot survive the navigation, so a consumer mirroring the rows would keep a
345
- * progress bar that never resolves.
346
- */
347
- #rewindForCache() {
348
- const ids = [...this.#rows.keys()];
349
- this.#reset();
350
- if (ids.length > 0) this.dispatch("reconcile", { detail: { ids } });
351
- }
352
- #reset() {
353
- for (const row of this.#rows.values()) row.remove();
354
- this.#rows.clear();
355
- this.#timeouts.clearAll();
356
- this.#syncAggregate();
299
+ #retire(id, row) {
300
+ row.remove();
301
+ this.#rows.delete(id);
302
+ this.#removals.clear(id);
357
303
  }
358
- /**
359
- * Sends one consumer-worded message to the page's shared announcer. `{name}`
360
- * resolves to the row's displayed name first — the event that settles an
361
- * upload may omit the file although an earlier event already named the row —
362
- * then the event's own name, then the accessible name (which an authored
363
- * label owns, so it is the last resort, not the primary source).
364
- */
365
304
  #announce(template, name, row) {
366
305
  const stored = this.#field(row, "name")?.textContent ?? "";
367
306
  const label = stored.length > 0 ? stored : name.length > 0 ? name : row.getAttribute("aria-label") ?? "";
@@ -377,17 +316,9 @@ var DirectUploadController = class extends Controller {
377
316
  #detail(event) {
378
317
  return event.detail ?? {};
379
318
  }
380
- /** The event's file name, or `""` when it carries none. */
381
319
  #name(detail) {
382
320
  return detail.file?.name ?? "";
383
321
  }
384
- /**
385
- * Whether an event belongs to this controller. With `scope` set, only events
386
- * whose target (the file input) sits inside an element matching `scope` are
387
- * handled, so several upload widgets on one page do not cross-populate.
388
- * Resolved with `closest()` from the target itself, so the chatty `progress`
389
- * stream never pays a document-wide query. Empty `scope` handles all.
390
- */
391
322
  #inScope(event) {
392
323
  if (this.#scopeSelector.length === 0) return true;
393
324
  const target = event.target;
@@ -399,5 +330,4 @@ var DirectUploadController = class extends Controller {
399
330
  };
400
331
 
401
332
  export { DirectUploadController };
402
- //# sourceMappingURL=direct_upload_controller.js.map
403
333
  //# sourceMappingURL=direct_upload_controller.js.map