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,354 @@
1
1
  import { Controller } from '@hotwired/stimulus';
2
2
 
3
- // src/controllers/editable_controller.ts
3
+ function setAttributeIfChanged(element, name, value, beforeWrite) {
4
+ if (element.getAttribute(name) === value) return false;
5
+ if (value === null) element.removeAttribute(name);
6
+ else element.setAttribute(name, value);
7
+ return true;
8
+ }
9
+
10
+ function sharedRegistry(key, create) {
11
+ const symbol = Symbol.for(key);
12
+ const scope = globalThis;
13
+ const existing = scope[symbol];
14
+ if (existing !== void 0) return existing;
15
+ const registry2 = create();
16
+ Object.defineProperty(globalThis, symbol, { value: registry2 });
17
+ return registry2;
18
+ }
19
+
20
+ var registry = sharedRegistry(
21
+ "stimeo-ui.attribute-lease.registry.v1",
22
+ () => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Map() })
23
+ );
24
+ function isAttributeValue(value) {
25
+ return value === null || typeof value === "string";
26
+ }
27
+ function readLeaseRecord(element, record) {
28
+ try {
29
+ const parsed = JSON.parse(element.getAttribute(record) ?? "null");
30
+ if (!Array.isArray(parsed)) return void 0;
31
+ const [original, written, ...rest] = parsed;
32
+ const linked = rest[0] !== false;
33
+ const beneath = linked ? rest : rest.slice(1);
34
+ if (!beneath.every((under) => typeof under === "string")) return void 0;
35
+ return isAttributeValue(original) && isAttributeValue(written) ? { original, written, linked, beneath } : void 0;
36
+ } catch {
37
+ return void 0;
38
+ }
39
+ }
40
+ function attributeStack(element, attribute) {
41
+ const byAttribute = registry.stacks.get(element) ?? /* @__PURE__ */ new Map();
42
+ registry.stacks.set(element, byAttribute);
43
+ const known = byAttribute.get(attribute);
44
+ if (known) return known;
45
+ const found = [];
46
+ for (const record of registry.names.get(attribute) ?? []) {
47
+ const read = readLeaseRecord(element, record);
48
+ if (read) found.push({ ...read, record });
49
+ }
50
+ const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
51
+ const stack = found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
52
+ lease: null,
53
+ record,
54
+ written,
55
+ original,
56
+ linked: linked && index > 0
57
+ }));
58
+ byAttribute.set(attribute, stack);
59
+ return stack;
60
+ }
61
+ function findHold(stack, lease, record) {
62
+ return stack.find((held) => held.lease === lease) ?? stack.find((held) => held.lease === null && held.record === record);
63
+ }
64
+ var AttributeLease = class {
65
+ #attribute;
66
+ #record;
67
+ #base;
68
+ #preserveAuthor;
69
+ #held = /* @__PURE__ */ new Set();
70
+ constructor(attribute, owner, options = {}) {
71
+ this.#attribute = attribute;
72
+ this.#record = `data-${owner}-${attribute}-lease`;
73
+ this.#base = options.base === true;
74
+ this.#preserveAuthor = options.preserveAuthor === true;
75
+ const names = registry.names;
76
+ names.set(attribute, (names.get(attribute) ?? /* @__PURE__ */ new Set()).add(this.#record));
77
+ }
78
+ write(element, value) {
79
+ const stack = attributeStack(element, this.#attribute);
80
+ const hold = this.#take(stack) ?? this.#acquire(element, stack);
81
+ this.#held.add(element);
82
+ const shows = !this.#covered(element, stack, hold);
83
+ hold.written = value;
84
+ this.#mark(element, stack);
85
+ if (shows) this.#reflect(element, value);
86
+ }
87
+ return(element) {
88
+ const held = this.#held.delete(element);
89
+ const known = registry.stacks.get(element)?.has(this.#attribute);
90
+ const stack = held || known || element.hasAttribute(this.#record) ? attributeStack(element, this.#attribute) : [];
91
+ const hold = this.#take(stack);
92
+ if (!hold) return false;
93
+ const carries = element.getAttribute(this.#attribute) === hold.written;
94
+ const owns = carries && !this.#covered(element, stack, hold);
95
+ const index = stack.indexOf(hold);
96
+ stack.splice(index, 1);
97
+ const above = stack[index];
98
+ if (above) above.linked &&= hold.linked;
99
+ this.#mark(element, stack);
100
+ if (!owns) return true;
101
+ const below = hold.linked ? stack[index - 1] : void 0;
102
+ this.#reflect(element, below ? below.written : hold.original);
103
+ return true;
104
+ }
105
+ returnAll() {
106
+ for (const element of Array.from(this.#held)) this.return(element);
107
+ }
108
+ #take(stack) {
109
+ const hold = findHold(stack, this, this.#record);
110
+ if (hold) hold.lease = this;
111
+ return hold;
112
+ }
113
+ #acquire(element, stack) {
114
+ const current = element.getAttribute(this.#attribute);
115
+ const top = stack.at(-1);
116
+ const bottom = stack[0];
117
+ const over = top?.written === current ? top : void 0;
118
+ const from = this.#base ? this.#preserveAuthor && !stack.some((held) => held.written === current) ? void 0 : bottom : over;
119
+ const hold = {
120
+ lease: this,
121
+ record: this.#record,
122
+ written: current,
123
+ original: from ? from.original : current,
124
+ linked: !this.#base && over !== void 0
125
+ };
126
+ if (this.#base && bottom) {
127
+ bottom.linked = true;
128
+ stack.unshift(hold);
129
+ } else stack.push(hold);
130
+ return hold;
131
+ }
132
+ #covered(element, stack, hold) {
133
+ const current = element.getAttribute(this.#attribute);
134
+ return stack.slice(stack.indexOf(hold) + 1).some((above) => above.written === current);
135
+ }
136
+ #mark(element, stack) {
137
+ const records = /* @__PURE__ */ new Map([[this.#record, null]]);
138
+ stack.forEach((hold, index) => {
139
+ const names = stack.slice(0, index).map((under) => under.record);
140
+ const beneath = [...new Set(names.reverse())].filter((name) => name !== hold.record);
141
+ const marker = hold.linked || beneath.length === 0 ? [] : [false];
142
+ records.set(
143
+ hold.record,
144
+ hold.written === hold.original && beneath.length === 0 && index === stack.length - 1 ? null : JSON.stringify([hold.original, hold.written, ...marker, ...beneath])
145
+ );
146
+ });
147
+ for (const [name, recorded] of records) {
148
+ setAttributeIfChanged(element, name, recorded);
149
+ }
150
+ }
151
+ #reflect(element, value) {
152
+ setAttributeIfChanged(element, this.#attribute, value);
153
+ }
154
+ };
4
155
 
5
- // src/utils/composition_tracker.ts
6
156
  var COMPOSITION_INPUT_TYPES = /* @__PURE__ */ new Set([
7
157
  "insertCompositionText",
8
158
  "insertFromComposition",
9
159
  "deleteCompositionText",
10
160
  "deleteByComposition"
11
161
  ]);
162
+ function isCompositionInputType(inputType) {
163
+ return inputType !== void 0 && COMPOSITION_INPUT_TYPES.has(inputType);
164
+ }
165
+ var BEFORE_MORPH_ATTRIBUTE = "turbo:before-morph-attribute";
166
+ var textOf = (element) => element.value;
167
+ var holdsFocus = (element) => element instanceof Node && element.getRootNode().activeElement === element;
12
168
  var CompositionTracker = class {
13
169
  #observedTargets = /* @__PURE__ */ new Set();
14
- #activeTargets = /* @__PURE__ */ new Set();
170
+ #composition = null;
15
171
  #onStart;
16
172
  #onEnd;
17
- /** The field whose confirming `input` is still owed, while the window is open. */
173
+ #onAbandon;
18
174
  #confirmedTarget = null;
175
+ #keyComposing = false;
176
+ #connected = false;
177
+ #abandoned = null;
19
178
  constructor(options = {}) {
20
179
  this.#onStart = options.onStart;
21
180
  this.#onEnd = options.onEnd;
181
+ this.#onAbandon = options.onAbandon;
22
182
  }
23
- /** Starts lifecycle tracking for `target`; repeated calls are idempotent. */
24
183
  observe(target) {
184
+ this.#connected = true;
25
185
  if (this.#observedTargets.has(target)) return;
26
186
  target.addEventListener("compositionstart", this.#handleStart);
27
187
  target.addEventListener("compositionend", this.#handleEnd);
28
- target.addEventListener("keydown", this.#handleKeydown);
188
+ target.addEventListener("keydown", this.#handleKeydown, true);
189
+ target.addEventListener("beforeinput", this.#handleBeforeInput, true);
190
+ target.addEventListener("input", this.#handleInput, true);
191
+ target.addEventListener("blur", this.#handleBlur, true);
192
+ target.addEventListener(BEFORE_MORPH_ATTRIBUTE, this.#handleBeforeMorphAttribute);
29
193
  this.#observedTargets.add(target);
30
194
  }
31
- /** Stops tracking one target and clears any active composition it owned. */
32
195
  unobserve(target) {
33
196
  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);
197
+ this.#release(target);
198
+ if (this.#composition?.target === target) this.#letGo();
38
199
  if (this.#confirmedTarget === target) this.#confirmedTarget = null;
39
200
  }
40
- /** Releases every listener and clears state so reconnect starts cleanly. */
41
201
  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
- }
202
+ this.#connected = false;
203
+ for (const target of this.#observedTargets) this.#release(target);
47
204
  this.#observedTargets.clear();
48
- this.#activeTargets.clear();
205
+ this.#letGo();
49
206
  this.#confirmedTarget = null;
207
+ this.#keyComposing = false;
208
+ this.#abandoned = null;
50
209
  }
51
- /** True when lifecycle tracking or the current event reports composition. */
52
210
  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
- */
211
+ this.#settle();
212
+ return event?.isComposing === true || this.#composition !== null;
213
+ }
214
+ composingElement() {
215
+ this.#settle();
216
+ return this.#composition?.element ?? null;
217
+ }
218
+ owns(event) {
219
+ const element = this.composingElement();
220
+ return event.isComposing === true || element !== null && element === event.target;
221
+ }
61
222
  consumesConfirmedInput(event) {
62
223
  const confirmed = this.#confirmedTarget;
63
224
  this.#confirmedTarget = null;
64
225
  if (confirmed === null || confirmed !== event.target) return false;
65
226
  const inputType = event.inputType;
66
- return !inputType || COMPOSITION_INPUT_TYPES.has(inputType);
227
+ return !inputType || isCompositionInputType(inputType);
67
228
  }
229
+ #release(target) {
230
+ target.removeEventListener("compositionstart", this.#handleStart);
231
+ target.removeEventListener("compositionend", this.#handleEnd);
232
+ target.removeEventListener("keydown", this.#handleKeydown, true);
233
+ target.removeEventListener("beforeinput", this.#handleBeforeInput, true);
234
+ target.removeEventListener("input", this.#handleInput, true);
235
+ target.removeEventListener("blur", this.#handleBlur, true);
236
+ target.removeEventListener(BEFORE_MORPH_ATTRIBUTE, this.#handleBeforeMorphAttribute);
237
+ }
238
+ #letGo() {
239
+ const composition = this.#composition;
240
+ if (composition === null) return;
241
+ if (!holdsFocus(composition.element)) {
242
+ this.#composition = null;
243
+ return;
244
+ }
245
+ queueMicrotask(() => {
246
+ if (this.#composition !== composition || this.#observedTargets.has(composition.target)) {
247
+ return;
248
+ }
249
+ this.#composition = null;
250
+ if (!this.#connected) return;
251
+ this.#abandoned = { element: composition.element, inPlace: true };
252
+ this.#runAbandon();
253
+ });
254
+ }
255
+ #settle() {
256
+ const composition = this.#composition;
257
+ if (composition === null) return;
258
+ const { target, element, text } = composition;
259
+ if (target instanceof Node && element instanceof Node && !target.contains(element)) {
260
+ this.#composition = null;
261
+ } else if (textOf(element) !== text) {
262
+ this.#abandon(false);
263
+ }
264
+ }
265
+ #abandon(inPlace) {
266
+ this.#owe(inPlace);
267
+ this.#composition = null;
268
+ queueMicrotask(this.#runAbandon);
269
+ }
270
+ #owe(inPlace) {
271
+ const composition = this.#composition;
272
+ if (composition !== null) this.#abandoned = { element: composition.element, inPlace };
273
+ }
274
+ #runAbandon = () => {
275
+ const abandoned = this.#abandoned;
276
+ if (abandoned === null) return;
277
+ this.#abandoned = null;
278
+ this.#onAbandon?.(abandoned.element, abandoned.inPlace);
279
+ };
68
280
  #handleStart = (event) => {
69
281
  this.#confirmedTarget = null;
70
- if (event.currentTarget) this.#activeTargets.add(event.currentTarget);
282
+ this.#settle();
283
+ this.#owe(true);
284
+ const target = event.currentTarget;
285
+ const element = event.target;
286
+ this.#composition = { target, element, text: textOf(element) };
287
+ this.#runAbandon();
71
288
  this.#onStart?.(event);
72
289
  };
73
290
  #handleEnd = (event) => {
74
- if (event.currentTarget) this.#activeTargets.delete(event.currentTarget);
291
+ this.#runAbandon();
292
+ if (this.#composition?.target === event.currentTarget) this.#composition = null;
75
293
  this.#confirmedTarget = event.target;
76
294
  this.#onEnd?.(event);
77
295
  };
78
- /** A key on an observed field opens an edit of its own, so no echo is owed. */
79
- #handleKeydown = () => {
296
+ #handleKeydown = (event) => {
297
+ this.#settle();
298
+ this.#runAbandon();
80
299
  this.#confirmedTarget = null;
300
+ this.#keyComposing = event.isComposing === true;
301
+ };
302
+ #handleBeforeInput = (event) => {
303
+ const keyComposing = this.#keyComposing;
304
+ this.#keyComposing = false;
305
+ this.#settle();
306
+ const { isComposing, inputType } = event;
307
+ if (this.#composition !== null && !keyComposing && !isComposing && inputType && !isCompositionInputType(inputType)) {
308
+ this.#abandon(true);
309
+ }
310
+ this.#runAbandon();
311
+ };
312
+ #handleInput = (event) => {
313
+ const composition = this.#composition;
314
+ const { isTrusted, isComposing, inputType } = event;
315
+ if (composition !== null && event.target === composition.element && (isTrusted || isComposing || isCompositionInputType(inputType))) {
316
+ composition.text = textOf(composition.element);
317
+ } else {
318
+ this.#settle();
319
+ }
320
+ this.#runAbandon();
321
+ };
322
+ #handleBlur = (event) => {
323
+ this.#settle();
324
+ this.#runAbandon();
325
+ const composition = this.#composition;
326
+ if (composition === null || composition.target === composition.element) return;
327
+ const { element } = composition;
328
+ if (!(element instanceof Node) || event.target !== element) return;
329
+ const root = element.getRootNode();
330
+ if (root.activeElement !== element) this.#composition = null;
331
+ };
332
+ #handleBeforeMorphAttribute = (event) => {
333
+ this.#settle();
334
+ const composition = this.#composition;
335
+ if (composition?.target !== event.currentTarget || event.target !== composition.element) return;
336
+ const detail = event.detail;
337
+ if (detail?.attributeName === "value") event.preventDefault();
81
338
  };
82
339
  };
83
340
 
84
- // src/controllers/editable_controller.ts
341
+ var ListenerSet = class {
342
+ #abort = new AbortController();
343
+ add(target, type, handler, options) {
344
+ target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
345
+ }
346
+ dispose() {
347
+ this.#abort.abort();
348
+ this.#abort = new AbortController();
349
+ }
350
+ };
351
+
85
352
  var EditableController = class extends Controller {
86
353
  static targets = ["display", "input"];
87
354
  static values = {
@@ -89,31 +356,11 @@ var EditableController = class extends Controller {
89
356
  };
90
357
  static actions = ["cancel", "edit", "onDisplayKeydown", "onKeydown", "revert", "save"];
91
358
  static events = ["cancel", "change"];
92
- /** The value captured when edit mode began, used to detect real changes. */
93
359
  #previousValue = "";
94
- /**
95
- * The value the last save replaced, or `null` when there is nothing to undo.
96
- * Cleared on connect: a value from before a page restore is unrecoverable, so
97
- * `revert()` must not resurrect one.
98
- */
99
360
  #revertValue = null;
100
- /**
101
- * Owns IME lifecycle state for the edit surface, so a keydown that belongs to
102
- * a composition (cancel or confirm) is never treated as an edit command.
103
- */
104
361
  #composition = new CompositionTracker();
105
- /**
106
- * Watches focus leaving the editor from wherever it currently sits.
107
- *
108
- * `focusout` bubbles where `blur` does not, so one listener on the root sees
109
- * every departure — including one from a Save or Cancel button the consumer
110
- * placed beside the input. Binding the input alone would make the promise
111
- * "saves wherever focus moved" true only for focus that leaves the input
112
- * itself, and tabbing straight past an inner button would strand the editor
113
- * open.
114
- *
115
- * @stimeoRuntimeOnly `submitOnBlur` decides whether this one blur commits the edit.
116
- */
362
+ #hidden = new AttributeLease("hidden", this.identifier);
363
+ #connected = false;
117
364
  #onFocusOut = (event) => {
118
365
  const from = event.target;
119
366
  if (this.hasDisplayTarget && from instanceof Node && this.displayTarget.contains(from)) return;
@@ -121,32 +368,35 @@ var EditableController = class extends Controller {
121
368
  if (next instanceof Node && this.element.contains(next)) return;
122
369
  if (this.submitOnBlurValue) this.#commit(false);
123
370
  };
124
- /** Establishes the initial display mode (display shown, input hidden). */
371
+ #listeners = new ListenerSet();
125
372
  connect() {
373
+ this.#connected = true;
126
374
  if (this.hasInputTarget) this.#composition.observe(this.inputTarget);
127
- this.element.addEventListener("focusout", this.#onFocusOut);
375
+ this.#listeners.add(this.element, "focusout", this.#onFocusOut);
128
376
  this.#revertValue = null;
129
377
  this.#setMode("display");
130
378
  }
131
- /** Releases the composition and focus listeners so nothing outlives the element. */
132
379
  disconnect() {
380
+ this.#connected = false;
133
381
  this.#composition.disconnect();
134
- this.element.removeEventListener("focusout", this.#onFocusOut);
382
+ this.#listeners.dispose();
135
383
  }
136
- /** Tracks an input added initially or after connect (e.g. a Turbo swap). */
137
384
  inputTargetConnected(input) {
138
385
  this.#composition.observe(input);
139
386
  this.#applyMode();
140
387
  }
141
- /** Removes composition listeners when the active input is replaced or removed. */
142
388
  inputTargetDisconnected(input) {
143
389
  this.#composition.unobserve(input);
390
+ if (!this.inputTargets.includes(input)) this.#hidden.return(input);
391
+ if (this.#connected) this.#applyMode();
144
392
  }
145
- /** Re-hides or re-shows a display element that arrived after the mode was set. */
146
393
  displayTargetConnected() {
147
394
  this.#applyMode();
148
395
  }
149
- /** Enters edit mode: seeds the input from the declared value, focuses, selects. */
396
+ displayTargetDisconnected(display) {
397
+ if (!this.displayTargets.includes(display)) this.#hidden.return(display);
398
+ if (this.#connected) this.#applyMode();
399
+ }
150
400
  edit() {
151
401
  if (this.#isEditing || !this.hasInputTarget || !this.hasDisplayTarget) return;
152
402
  this.#previousValue = this.#currentValue;
@@ -155,35 +405,26 @@ var EditableController = class extends Controller {
155
405
  this.inputTarget.focus();
156
406
  this.inputTarget.select();
157
407
  }
158
- /** Commits the edit and returns focus to the display element. */
159
408
  save() {
160
409
  this.#commit(true);
161
410
  }
162
- /** Discards edits, returns to display mode, and dispatches `cancel`. */
163
411
  cancel() {
164
412
  if (!this.#isEditing) return;
165
413
  this.#setMode("display");
166
414
  if (this.hasDisplayTarget) this.displayTarget.focus();
167
415
  this.dispatch("cancel", { detail: {} });
168
416
  }
169
- /**
170
- * Puts back the value the last save replaced — for a consumer whose server
171
- * rejected it. Silent by design: a `change` here would re-enter the same
172
- * handler that asked for the undo. One save, one undo.
173
- */
174
417
  revert() {
175
418
  if (this.#revertValue === null || this.#isEditing) return;
176
419
  this.#writeValue(this.#revertValue);
177
420
  this.#revertValue = null;
178
421
  }
179
- /** Adds `F2` as an editing entry point alongside the button's native activation. */
180
422
  onDisplayKeydown(event) {
181
423
  if (event.key === "F2") {
182
424
  event.preventDefault();
183
425
  this.edit();
184
426
  }
185
427
  }
186
- /** Commits on `Enter` (or `Ctrl+Enter` when multiline) and cancels on `Escape`. */
187
428
  onKeydown(event) {
188
429
  if (this.#composition.isComposing(event)) return;
189
430
  if (event.key === "Escape") {
@@ -199,13 +440,6 @@ var EditableController = class extends Controller {
199
440
  this.#commit(true);
200
441
  }
201
442
  }
202
- /**
203
- * Returns to display mode, storing the input's value and dispatching `change`
204
- * when it differs from where editing began.
205
- *
206
- * @param restoreFocus - Move focus back to the display element (explicit
207
- * commit) rather than honoring the user's new focus target (blur).
208
- */
209
443
  #commit(restoreFocus) {
210
444
  if (!this.#isEditing || !this.hasInputTarget) return;
211
445
  const value = this.inputTarget.value.trim();
@@ -218,39 +452,32 @@ var EditableController = class extends Controller {
218
452
  this.dispatch("change", { detail: { value, previous } });
219
453
  }
220
454
  }
221
- /** Stores `value` wherever the display element declares it. */
222
455
  #writeValue(value) {
223
456
  if (!this.hasDisplayTarget) return;
224
457
  const display = this.displayTarget;
225
458
  if (display.hasAttribute("data-value")) display.dataset.value = value;
226
459
  else display.textContent = value;
227
460
  }
228
- /** Derives both elements' visibility from the mode currently in the DOM. */
229
461
  #applyMode() {
230
462
  const editing = this.#isEditing;
231
- if (this.hasDisplayTarget) this.displayTarget.hidden = editing;
232
- if (this.hasInputTarget) this.inputTarget.hidden = !editing;
463
+ if (this.hasDisplayTarget) this.#hidden.write(this.displayTarget, editing ? "" : null);
464
+ if (this.hasInputTarget) this.#hidden.write(this.inputTarget, editing ? null : "");
233
465
  }
234
- /** Records the mode, then brings both elements in line with it. */
235
466
  #setMode(mode) {
236
467
  this.element.dataset.mode = mode;
237
468
  this.#applyMode();
238
469
  }
239
- /** The value the display element declares, trimmed. */
240
470
  get #currentValue() {
241
471
  const display = this.displayTarget;
242
472
  return (display.dataset.value ?? display.textContent ?? "").trim();
243
473
  }
244
- /** Whether the editing control is a multi-line `<textarea>`. */
245
474
  get #isMultiline() {
246
475
  return this.inputTarget.tagName === "TEXTAREA";
247
476
  }
248
- /** Whether the controller is currently in edit mode. */
249
477
  get #isEditing() {
250
478
  return this.element.dataset.mode === "editing";
251
479
  }
252
480
  };
253
481
 
254
482
  export { EditableController };
255
- //# sourceMappingURL=editable_controller.js.map
256
483
  //# sourceMappingURL=editable_controller.js.map