stimeo-ui 0.15.0 → 0.17.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 (332) hide show
  1. package/CHANGELOG.md +209 -0
  2. package/README.md +128 -1
  3. package/dist/cable/index.d.ts +79 -23
  4. package/dist/cable/index.js +392 -417
  5. package/dist/cable/index.js.map +1 -1
  6. package/dist/controllers/accordion_controller.d.ts +34 -5
  7. package/dist/controllers/accordion_controller.js +228 -28
  8. package/dist/controllers/accordion_controller.js.map +1 -1
  9. package/dist/controllers/alert_dialog_controller.d.ts +20 -9
  10. package/dist/controllers/alert_dialog_controller.js +862 -221
  11. package/dist/controllers/alert_dialog_controller.js.map +1 -1
  12. package/dist/controllers/announcer_controller.d.ts +38 -7
  13. package/dist/controllers/announcer_controller.js +135 -191
  14. package/dist/controllers/announcer_controller.js.map +1 -1
  15. package/dist/controllers/aspect_ratio_controller.js +0 -10
  16. package/dist/controllers/aspect_ratio_controller.js.map +1 -1
  17. package/dist/controllers/auto_submit_controller.d.ts +30 -6
  18. package/dist/controllers/auto_submit_controller.js +295 -110
  19. package/dist/controllers/auto_submit_controller.js.map +1 -1
  20. package/dist/controllers/avatar_controller.js +172 -106
  21. package/dist/controllers/avatar_controller.js.map +1 -1
  22. package/dist/controllers/breadcrumb_controller.d.ts +10 -7
  23. package/dist/controllers/breadcrumb_controller.js +0 -129
  24. package/dist/controllers/breadcrumb_controller.js.map +1 -1
  25. package/dist/controllers/bulk_select_controller.d.ts +22 -4
  26. package/dist/controllers/bulk_select_controller.js +264 -53
  27. package/dist/controllers/bulk_select_controller.js.map +1 -1
  28. package/dist/controllers/calendar_controller.d.ts +109 -28
  29. package/dist/controllers/calendar_controller.js +346 -180
  30. package/dist/controllers/calendar_controller.js.map +1 -1
  31. package/dist/controllers/carousel_controller.d.ts +99 -27
  32. package/dist/controllers/carousel_controller.js +587 -300
  33. package/dist/controllers/carousel_controller.js.map +1 -1
  34. package/dist/controllers/character_counter_controller.d.ts +18 -2
  35. package/dist/controllers/character_counter_controller.js +271 -143
  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 +77 -75
  39. package/dist/controllers/checkbox_controller.js.map +1 -1
  40. package/dist/controllers/clipboard_controller.d.ts +44 -7
  41. package/dist/controllers/clipboard_controller.js +187 -108
  42. package/dist/controllers/clipboard_controller.js.map +1 -1
  43. package/dist/controllers/collapsible_controller.d.ts +41 -5
  44. package/dist/controllers/collapsible_controller.js +374 -108
  45. package/dist/controllers/collapsible_controller.js.map +1 -1
  46. package/dist/controllers/color_picker_controller.d.ts +47 -14
  47. package/dist/controllers/color_picker_controller.js +183 -127
  48. package/dist/controllers/color_picker_controller.js.map +1 -1
  49. package/dist/controllers/combobox_controller.d.ts +33 -6
  50. package/dist/controllers/combobox_controller.js +426 -109
  51. package/dist/controllers/combobox_controller.js.map +1 -1
  52. package/dist/controllers/command_palette_controller.d.ts +45 -14
  53. package/dist/controllers/command_palette_controller.js +994 -350
  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 +212 -125
  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 +939 -245
  60. package/dist/controllers/confirm_controller.js.map +1 -1
  61. package/dist/controllers/context_menu_controller.d.ts +36 -3
  62. package/dist/controllers/context_menu_controller.js +275 -127
  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 +75 -2
  68. package/dist/controllers/countdown_controller.js +235 -97
  69. package/dist/controllers/countdown_controller.js.map +1 -1
  70. package/dist/controllers/currency_input_controller.d.ts +93 -15
  71. package/dist/controllers/currency_input_controller.js +241 -118
  72. package/dist/controllers/currency_input_controller.js.map +1 -1
  73. package/dist/controllers/data_grid_controller.d.ts +78 -22
  74. package/dist/controllers/data_grid_controller.js +229 -135
  75. package/dist/controllers/data_grid_controller.js.map +1 -1
  76. package/dist/controllers/date_range_picker_controller.d.ts +64 -11
  77. package/dist/controllers/date_range_picker_controller.js +359 -165
  78. package/dist/controllers/date_range_picker_controller.js.map +1 -1
  79. package/dist/controllers/dialog_controller.d.ts +22 -3
  80. package/dist/controllers/dialog_controller.js +887 -225
  81. package/dist/controllers/dialog_controller.js.map +1 -1
  82. package/dist/controllers/direct_upload_controller.d.ts +24 -7
  83. package/dist/controllers/direct_upload_controller.js +80 -142
  84. package/dist/controllers/direct_upload_controller.js.map +1 -1
  85. package/dist/controllers/dirty_form_controller.d.ts +2 -2
  86. package/dist/controllers/dirty_form_controller.js +26 -47
  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 +175 -20
  90. package/dist/controllers/dismissible_controller.js.map +1 -1
  91. package/dist/controllers/drawer_controller.d.ts +52 -16
  92. package/dist/controllers/drawer_controller.js +963 -336
  93. package/dist/controllers/drawer_controller.js.map +1 -1
  94. package/dist/controllers/dropdown_controller.d.ts +39 -3
  95. package/dist/controllers/dropdown_controller.js +342 -85
  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 +182 -58
  99. package/dist/controllers/editable_controller.js.map +1 -1
  100. package/dist/controllers/empty_state_controller.js +67 -53
  101. package/dist/controllers/empty_state_controller.js.map +1 -1
  102. package/dist/controllers/file_dropzone_controller.d.ts +60 -18
  103. package/dist/controllers/file_dropzone_controller.js +426 -229
  104. package/dist/controllers/file_dropzone_controller.js.map +1 -1
  105. package/dist/controllers/filter_controller.d.ts +10 -4
  106. package/dist/controllers/filter_controller.js +78 -36
  107. package/dist/controllers/filter_controller.js.map +1 -1
  108. package/dist/controllers/flash_controller.d.ts +57 -14
  109. package/dist/controllers/flash_controller.js +328 -211
  110. package/dist/controllers/flash_controller.js.map +1 -1
  111. package/dist/controllers/focus_controller.d.ts +12 -3
  112. package/dist/controllers/focus_controller.js +654 -239
  113. package/dist/controllers/focus_controller.js.map +1 -1
  114. package/dist/controllers/form_field_controller.js +153 -136
  115. package/dist/controllers/form_field_controller.js.map +1 -1
  116. package/dist/controllers/form_validation_controller.js +29 -96
  117. package/dist/controllers/form_validation_controller.js.map +1 -1
  118. package/dist/controllers/frame_loading_controller.d.ts +41 -9
  119. package/dist/controllers/frame_loading_controller.js +263 -198
  120. package/dist/controllers/frame_loading_controller.js.map +1 -1
  121. package/dist/controllers/highlight_controller.d.ts +22 -2
  122. package/dist/controllers/highlight_controller.js +119 -70
  123. package/dist/controllers/highlight_controller.js.map +1 -1
  124. package/dist/controllers/hover_card_controller.d.ts +65 -4
  125. package/dist/controllers/hover_card_controller.js +335 -118
  126. package/dist/controllers/hover_card_controller.js.map +1 -1
  127. package/dist/controllers/idle_controller.d.ts +58 -4
  128. package/dist/controllers/idle_controller.js +316 -65
  129. package/dist/controllers/idle_controller.js.map +1 -1
  130. package/dist/controllers/input_mask_controller.d.ts +5 -2
  131. package/dist/controllers/input_mask_controller.js +116 -61
  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 +147 -103
  135. package/dist/controllers/intersection_controller.js.map +1 -1
  136. package/dist/controllers/lazy_frame_controller.d.ts +16 -0
  137. package/dist/controllers/lazy_frame_controller.js +9 -56
  138. package/dist/controllers/lazy_frame_controller.js.map +1 -1
  139. package/dist/controllers/listbox_controller.d.ts +84 -10
  140. package/dist/controllers/listbox_controller.js +413 -153
  141. package/dist/controllers/listbox_controller.js.map +1 -1
  142. package/dist/controllers/local_time_controller.d.ts +1 -1
  143. package/dist/controllers/local_time_controller.js +54 -64
  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 +70 -95
  147. package/dist/controllers/masonry_controller.js.map +1 -1
  148. package/dist/controllers/menu_controller.d.ts +40 -9
  149. package/dist/controllers/menu_controller.js +254 -167
  150. package/dist/controllers/menu_controller.js.map +1 -1
  151. package/dist/controllers/menubar_controller.d.ts +15 -4
  152. package/dist/controllers/menubar_controller.js +206 -331
  153. package/dist/controllers/menubar_controller.js.map +1 -1
  154. package/dist/controllers/meter_controller.d.ts +20 -0
  155. package/dist/controllers/meter_controller.js +159 -71
  156. package/dist/controllers/meter_controller.js.map +1 -1
  157. package/dist/controllers/multi_select_controller.d.ts +50 -7
  158. package/dist/controllers/multi_select_controller.js +797 -388
  159. package/dist/controllers/multi_select_controller.js.map +1 -1
  160. package/dist/controllers/navigation_menu_controller.d.ts +19 -1
  161. package/dist/controllers/navigation_menu_controller.js +156 -231
  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 +373 -174
  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 +241 -45
  168. package/dist/controllers/network_status_controller.js.map +1 -1
  169. package/dist/controllers/number_input_controller.d.ts +62 -10
  170. package/dist/controllers/number_input_controller.js +387 -227
  171. package/dist/controllers/number_input_controller.js.map +1 -1
  172. package/dist/controllers/optimistic_controller.js +28 -75
  173. package/dist/controllers/optimistic_controller.js.map +1 -1
  174. package/dist/controllers/otp_controller.d.ts +38 -7
  175. package/dist/controllers/otp_controller.js +344 -196
  176. package/dist/controllers/otp_controller.js.map +1 -1
  177. package/dist/controllers/overflow_indicator_controller.d.ts +13 -12
  178. package/dist/controllers/overflow_indicator_controller.js +167 -93
  179. package/dist/controllers/overflow_indicator_controller.js.map +1 -1
  180. package/dist/controllers/overflow_menu_controller.d.ts +66 -9
  181. package/dist/controllers/overflow_menu_controller.js +408 -277
  182. package/dist/controllers/overflow_menu_controller.js.map +1 -1
  183. package/dist/controllers/pagination_controller.d.ts +52 -15
  184. package/dist/controllers/pagination_controller.js +342 -120
  185. package/dist/controllers/pagination_controller.js.map +1 -1
  186. package/dist/controllers/password_reveal_controller.d.ts +60 -9
  187. package/dist/controllers/password_reveal_controller.js +424 -99
  188. package/dist/controllers/password_reveal_controller.js.map +1 -1
  189. package/dist/controllers/password_strength_controller.d.ts +14 -5
  190. package/dist/controllers/password_strength_controller.js +99 -153
  191. package/dist/controllers/password_strength_controller.js.map +1 -1
  192. package/dist/controllers/persist_controller.d.ts +11 -4
  193. package/dist/controllers/persist_controller.js +252 -96
  194. package/dist/controllers/persist_controller.js.map +1 -1
  195. package/dist/controllers/pointer_drag_controller.d.ts +19 -7
  196. package/dist/controllers/pointer_drag_controller.js +263 -164
  197. package/dist/controllers/pointer_drag_controller.js.map +1 -1
  198. package/dist/controllers/popover_controller.d.ts +46 -4
  199. package/dist/controllers/popover_controller.js +267 -94
  200. package/dist/controllers/popover_controller.js.map +1 -1
  201. package/dist/controllers/portal_controller.d.ts +44 -4
  202. package/dist/controllers/portal_controller.js +209 -72
  203. package/dist/controllers/portal_controller.js.map +1 -1
  204. package/dist/controllers/preview_guard_controller.d.ts +10 -4
  205. package/dist/controllers/preview_guard_controller.js +243 -112
  206. package/dist/controllers/preview_guard_controller.js.map +1 -1
  207. package/dist/controllers/progress_controller.d.ts +11 -0
  208. package/dist/controllers/progress_controller.js +132 -59
  209. package/dist/controllers/progress_controller.js.map +1 -1
  210. package/dist/controllers/radio_group_controller.d.ts +19 -8
  211. package/dist/controllers/radio_group_controller.js +138 -133
  212. package/dist/controllers/radio_group_controller.js.map +1 -1
  213. package/dist/controllers/range_slider_controller.d.ts +92 -4
  214. package/dist/controllers/range_slider_controller.js +245 -112
  215. package/dist/controllers/range_slider_controller.js.map +1 -1
  216. package/dist/controllers/rating_controller.d.ts +33 -6
  217. package/dist/controllers/rating_controller.js +429 -194
  218. package/dist/controllers/rating_controller.js.map +1 -1
  219. package/dist/controllers/read_more_controller.d.ts +26 -2
  220. package/dist/controllers/read_more_controller.js +185 -47
  221. package/dist/controllers/read_more_controller.js.map +1 -1
  222. package/dist/controllers/reading_progress_controller.d.ts +1 -1
  223. package/dist/controllers/reading_progress_controller.js +147 -135
  224. package/dist/controllers/reading_progress_controller.js.map +1 -1
  225. package/dist/controllers/relative_time_controller.d.ts +18 -4
  226. package/dist/controllers/relative_time_controller.js +145 -110
  227. package/dist/controllers/relative_time_controller.js.map +1 -1
  228. package/dist/controllers/reset_on_restore_controller.d.ts +85 -0
  229. package/dist/controllers/{reset_before_cache_controller.js → reset_on_restore_controller.js} +97 -38
  230. package/dist/controllers/reset_on_restore_controller.js.map +1 -0
  231. package/dist/controllers/resizable_controller.d.ts +44 -4
  232. package/dist/controllers/resizable_controller.js +294 -118
  233. package/dist/controllers/resizable_controller.js.map +1 -1
  234. package/dist/controllers/roving_controller.js +39 -84
  235. package/dist/controllers/roving_controller.js.map +1 -1
  236. package/dist/controllers/scroll_area_controller.d.ts +7 -3
  237. package/dist/controllers/scroll_area_controller.js +428 -221
  238. package/dist/controllers/scroll_area_controller.js.map +1 -1
  239. package/dist/controllers/scroll_restore_controller.js +0 -53
  240. package/dist/controllers/scroll_restore_controller.js.map +1 -1
  241. package/dist/controllers/scroll_visibility_controller.d.ts +28 -12
  242. package/dist/controllers/scroll_visibility_controller.js +395 -146
  243. package/dist/controllers/scroll_visibility_controller.js.map +1 -1
  244. package/dist/controllers/scrollspy_controller.d.ts +9 -3
  245. package/dist/controllers/scrollspy_controller.js +181 -236
  246. package/dist/controllers/scrollspy_controller.js.map +1 -1
  247. package/dist/controllers/separator_controller.d.ts +59 -17
  248. package/dist/controllers/separator_controller.js +288 -132
  249. package/dist/controllers/separator_controller.js.map +1 -1
  250. package/dist/controllers/sidebar_controller.d.ts +81 -7
  251. package/dist/controllers/sidebar_controller.js +1071 -375
  252. package/dist/controllers/sidebar_controller.js.map +1 -1
  253. package/dist/controllers/skeleton_controller.d.ts +23 -0
  254. package/dist/controllers/skeleton_controller.js +248 -92
  255. package/dist/controllers/skeleton_controller.js.map +1 -1
  256. package/dist/controllers/slider_controller.d.ts +72 -8
  257. package/dist/controllers/slider_controller.js +211 -96
  258. package/dist/controllers/slider_controller.js.map +1 -1
  259. package/dist/controllers/smart_sticky_header_controller.d.ts +21 -3
  260. package/dist/controllers/smart_sticky_header_controller.js +163 -54
  261. package/dist/controllers/smart_sticky_header_controller.js.map +1 -1
  262. package/dist/controllers/sortable_controller.js +13 -110
  263. package/dist/controllers/sortable_controller.js.map +1 -1
  264. package/dist/controllers/spinner_controller.d.ts +39 -4
  265. package/dist/controllers/spinner_controller.js +277 -161
  266. package/dist/controllers/spinner_controller.js.map +1 -1
  267. package/dist/controllers/step_indicator_controller.d.ts +24 -17
  268. package/dist/controllers/step_indicator_controller.js +107 -53
  269. package/dist/controllers/step_indicator_controller.js.map +1 -1
  270. package/dist/controllers/stepper_controller.d.ts +43 -9
  271. package/dist/controllers/stepper_controller.js +171 -48
  272. package/dist/controllers/stepper_controller.js.map +1 -1
  273. package/dist/controllers/stick_to_bottom_controller.d.ts +25 -0
  274. package/dist/controllers/stick_to_bottom_controller.js +310 -116
  275. package/dist/controllers/stick_to_bottom_controller.js.map +1 -1
  276. package/dist/controllers/sticky_observer_controller.d.ts +11 -0
  277. package/dist/controllers/sticky_observer_controller.js +214 -49
  278. package/dist/controllers/sticky_observer_controller.js.map +1 -1
  279. package/dist/controllers/submit_once_controller.d.ts +22 -6
  280. package/dist/controllers/submit_once_controller.js +294 -192
  281. package/dist/controllers/submit_once_controller.js.map +1 -1
  282. package/dist/controllers/switch_controller.d.ts +40 -7
  283. package/dist/controllers/switch_controller.js +107 -43
  284. package/dist/controllers/switch_controller.js.map +1 -1
  285. package/dist/controllers/tabs_controller.d.ts +13 -1
  286. package/dist/controllers/tabs_controller.js +50 -25
  287. package/dist/controllers/tabs_controller.js.map +1 -1
  288. package/dist/controllers/tags_input_controller.d.ts +27 -3
  289. package/dist/controllers/tags_input_controller.js +290 -149
  290. package/dist/controllers/tags_input_controller.js.map +1 -1
  291. package/dist/controllers/textarea_autosize_controller.d.ts +10 -0
  292. package/dist/controllers/textarea_autosize_controller.js +71 -58
  293. package/dist/controllers/textarea_autosize_controller.js.map +1 -1
  294. package/dist/controllers/theme_controller.d.ts +37 -8
  295. package/dist/controllers/theme_controller.js +148 -80
  296. package/dist/controllers/theme_controller.js.map +1 -1
  297. package/dist/controllers/time_picker_controller.d.ts +18 -1
  298. package/dist/controllers/time_picker_controller.js +162 -81
  299. package/dist/controllers/time_picker_controller.js.map +1 -1
  300. package/dist/controllers/toast_controller.d.ts +85 -23
  301. package/dist/controllers/toast_controller.js +365 -193
  302. package/dist/controllers/toast_controller.js.map +1 -1
  303. package/dist/controllers/toggle_group_controller.d.ts +60 -9
  304. package/dist/controllers/toggle_group_controller.js +194 -99
  305. package/dist/controllers/toggle_group_controller.js.map +1 -1
  306. package/dist/controllers/toolbar_controller.js +92 -90
  307. package/dist/controllers/toolbar_controller.js.map +1 -1
  308. package/dist/controllers/tooltip_controller.d.ts +52 -2
  309. package/dist/controllers/tooltip_controller.js +185 -125
  310. package/dist/controllers/tooltip_controller.js.map +1 -1
  311. package/dist/controllers/transition_controller.d.ts +22 -4
  312. package/dist/controllers/transition_controller.js +123 -115
  313. package/dist/controllers/transition_controller.js.map +1 -1
  314. package/dist/controllers/tree_view_controller.d.ts +59 -18
  315. package/dist/controllers/tree_view_controller.js +248 -290
  316. package/dist/controllers/tree_view_controller.js.map +1 -1
  317. package/dist/index.d.ts +33 -3
  318. package/dist/index.js +8649 -8572
  319. package/dist/index.js.map +1 -1
  320. package/dist/inspector/cli.d.ts +95 -9
  321. package/dist/inspector/cli.js +343 -77
  322. package/dist/inspector/cli.js.map +1 -1
  323. package/dist/inspector/cli_bin.js +390 -96
  324. package/dist/inspector/cli_bin.js.map +1 -1
  325. package/dist/inspector/examples.json +45 -45
  326. package/dist/inspector/manifest.json +1308 -155
  327. package/dist/positioning/index.d.ts +8 -0
  328. package/dist/positioning/index.js +148 -45
  329. package/dist/positioning/index.js.map +1 -1
  330. package/package.json +7 -7
  331. package/dist/controllers/reset_before_cache_controller.d.ts +0 -76
  332. package/dist/controllers/reset_before_cache_controller.js.map +0 -1
@@ -1,8 +1,5 @@
1
1
  import { Controller } from '@hotwired/stimulus';
2
2
 
3
- // src/controllers/character_counter_controller.ts
4
-
5
- // src/utils/announce.ts
6
3
  function announce(message, options = {}) {
7
4
  const text = message.trim();
8
5
  if (text.length === 0) return;
@@ -19,144 +16,246 @@ function fillTemplate(template, values) {
19
16
  });
20
17
  }
21
18
 
22
- // src/utils/attribute_lease.ts
23
- var AttributeLease = class {
19
+ function sharedRegistry(key, create) {
20
+ const symbol = Symbol.for(key);
21
+ const scope = globalThis;
22
+ const existing = scope[symbol];
23
+ if (existing !== void 0) return existing;
24
+ const registry = create();
25
+ Object.defineProperty(globalThis, symbol, { value: registry });
26
+ return registry;
27
+ }
28
+
29
+ function isAttributeValue(value) {
30
+ return value === null || typeof value === "string";
31
+ }
32
+ function readLeaseRecord(element, record) {
33
+ try {
34
+ const parsed = JSON.parse(element.getAttribute(record) ?? "null");
35
+ if (!Array.isArray(parsed)) return void 0;
36
+ const [original, written, ...rest] = parsed;
37
+ const linked = rest[0] !== false;
38
+ const beneath = linked ? rest : rest.slice(1);
39
+ if (!beneath.every((under) => typeof under === "string")) return void 0;
40
+ return isAttributeValue(original) && isAttributeValue(written) ? { original, written, linked, beneath } : void 0;
41
+ } catch {
42
+ return void 0;
43
+ }
44
+ }
45
+ var AttributeLease = class _AttributeLease {
46
+ static #registry = sharedRegistry(
47
+ "stimeo-ui.attribute-lease.registry.v1",
48
+ () => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Map() })
49
+ );
24
50
  #attribute;
25
- #records = /* @__PURE__ */ new Map();
26
- /** @param attribute - The attribute whose temporary values this lease owns. */
27
- constructor(attribute) {
51
+ #record;
52
+ #base;
53
+ #held = /* @__PURE__ */ new Set();
54
+ constructor(attribute, owner, options = {}) {
28
55
  this.#attribute = attribute;
56
+ this.#record = `data-${owner}-${attribute}-lease`;
57
+ this.#base = options.base === true;
58
+ const names = _AttributeLease.#registry.names;
59
+ names.set(attribute, (names.get(attribute) ?? /* @__PURE__ */ new Set()).add(this.#record));
29
60
  }
30
- /** Writes or removes the leased attribute while preserving its authored value. */
31
61
  write(element, value) {
32
- const existing = this.#records.get(element);
33
- if (existing) {
34
- existing.written = value;
35
- } else {
36
- this.#records.set(element, {
37
- original: element.getAttribute(this.#attribute),
38
- written: value
39
- });
40
- }
41
- this.#reflect(element, value);
62
+ const stack = this.#stack(element);
63
+ const hold = this.#take(stack) ?? this.#acquire(element, stack);
64
+ this.#held.add(element);
65
+ const shows = !this.#covered(element, stack, hold);
66
+ hold.written = value;
67
+ this.#mark(element, stack);
68
+ if (shows) this.#reflect(element, value);
42
69
  }
43
- /** Returns one lease without overwriting a value subsequently authored by a consumer. */
44
70
  return(element) {
45
- const record = this.#records.get(element);
46
- if (!record) return;
47
- this.#records.delete(element);
48
- const stillOwned = element.getAttribute(this.#attribute) === record.written;
49
- if (stillOwned) this.#reflect(element, record.original);
71
+ const held = this.#held.delete(element);
72
+ const known = _AttributeLease.#registry.stacks.get(element)?.has(this.#attribute);
73
+ const stack = held || known || element.hasAttribute(this.#record) ? this.#stack(element) : [];
74
+ const hold = this.#take(stack);
75
+ if (!hold) return false;
76
+ const carries = element.getAttribute(this.#attribute) === hold.written;
77
+ const owns = carries && !this.#covered(element, stack, hold);
78
+ const index = stack.indexOf(hold);
79
+ stack.splice(index, 1);
80
+ const above = stack[index];
81
+ if (above) above.linked &&= hold.linked;
82
+ this.#mark(element, stack);
83
+ if (!owns) return true;
84
+ const below = hold.linked ? stack[index - 1] : void 0;
85
+ this.#reflect(element, below ? below.written : hold.original);
86
+ return true;
87
+ }
88
+ returnAll() {
89
+ for (const element of Array.from(this.#held)) this.return(element);
90
+ }
91
+ #stack(element) {
92
+ const stacks = _AttributeLease.#registry.stacks;
93
+ const byAttribute = stacks.get(element) ?? /* @__PURE__ */ new Map();
94
+ stacks.set(element, byAttribute);
95
+ const stack = byAttribute.get(this.#attribute) ?? this.#seed(element);
96
+ byAttribute.set(this.#attribute, stack);
97
+ return stack;
98
+ }
99
+ #seed(element) {
100
+ const found = [];
101
+ for (const record of _AttributeLease.#registry.names.get(this.#attribute) ?? []) {
102
+ const read = readLeaseRecord(element, record);
103
+ if (read) found.push({ ...read, record });
104
+ }
105
+ const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
106
+ return found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
107
+ lease: null,
108
+ record,
109
+ written,
110
+ original,
111
+ linked: linked && index > 0
112
+ }));
113
+ }
114
+ #take(stack) {
115
+ const hold = stack.find((held) => held.lease === this) ?? stack.find((held) => held.lease === null && held.record === this.#record);
116
+ if (hold) hold.lease = this;
117
+ return hold;
118
+ }
119
+ #acquire(element, stack) {
120
+ const current = element.getAttribute(this.#attribute);
121
+ const top = stack.at(-1);
122
+ const bottom = stack[0];
123
+ const over = top?.written === current ? top : void 0;
124
+ const from = this.#base ? bottom : over;
125
+ const hold = {
126
+ lease: this,
127
+ record: this.#record,
128
+ written: current,
129
+ original: from ? from.original : current,
130
+ linked: !this.#base && over !== void 0
131
+ };
132
+ if (this.#base && bottom) {
133
+ bottom.linked = true;
134
+ stack.unshift(hold);
135
+ } else stack.push(hold);
136
+ return hold;
137
+ }
138
+ #covered(element, stack, hold) {
139
+ const current = element.getAttribute(this.#attribute);
140
+ return stack.slice(stack.indexOf(hold) + 1).some((above) => above.written === current);
141
+ }
142
+ #mark(element, stack) {
143
+ const records = /* @__PURE__ */ new Map([[this.#record, null]]);
144
+ stack.forEach((hold, index) => {
145
+ const names = stack.slice(0, index).map((under) => under.record);
146
+ const beneath = [...new Set(names.reverse())].filter((name) => name !== hold.record);
147
+ const marker = hold.linked || beneath.length === 0 ? [] : [false];
148
+ records.set(
149
+ hold.record,
150
+ hold.written === hold.original && beneath.length === 0 && index === stack.length - 1 ? null : JSON.stringify([hold.original, hold.written, ...marker, ...beneath])
151
+ );
152
+ });
153
+ for (const [name, recorded] of records) {
154
+ if (element.getAttribute(name) === recorded) continue;
155
+ if (recorded === null) element.removeAttribute(name);
156
+ else element.setAttribute(name, recorded);
157
+ }
50
158
  }
51
- /** Reflects only a real value transition, avoiding self-triggered mutation work. */
52
159
  #reflect(element, value) {
53
160
  if (element.getAttribute(this.#attribute) === value) return;
54
161
  if (value === null) element.removeAttribute(this.#attribute);
55
162
  else element.setAttribute(this.#attribute, value);
56
163
  }
57
- /** Returns every outstanding lease using the same ownership check as {@link return}. */
58
- returnAll() {
59
- for (const element of Array.from(this.#records.keys())) this.return(element);
60
- }
61
- };
62
-
63
- // src/utils/before_cache_reset.ts
64
- var BeforeCacheReset = class _BeforeCacheReset {
65
- /** Every subscribed instance, iterated by the one shared document listener. */
66
- static #subscribers = /* @__PURE__ */ new Set();
67
- /** The shared listener; installed while at least one instance is subscribed. */
68
- static #onBeforeCache = () => {
69
- for (const subscriber of _BeforeCacheReset.#subscribers) subscriber.#rewind();
70
- };
71
- #rewind;
72
- /** @param rewind - the pass that returns this controller's state to its initial form. */
73
- constructor(rewind) {
74
- this.#rewind = rewind;
75
- }
76
- /** Subscribes to `turbo:before-cache`; call from `connect()`. Idempotent. */
77
- activate() {
78
- const first = _BeforeCacheReset.#subscribers.size === 0;
79
- _BeforeCacheReset.#subscribers.add(this);
80
- if (first) {
81
- document.addEventListener("turbo:before-cache", _BeforeCacheReset.#onBeforeCache);
82
- }
83
- }
84
- /** Unsubscribes; call from `disconnect()`. Safe when never subscribed. */
85
- deactivate() {
86
- _BeforeCacheReset.#subscribers.delete(this);
87
- if (_BeforeCacheReset.#subscribers.size > 0) return;
88
- document.removeEventListener("turbo:before-cache", _BeforeCacheReset.#onBeforeCache);
89
- }
90
164
  };
91
165
 
92
- // src/utils/composition_tracker.ts
166
+ var COMPOSITION_INPUT_TYPES = /* @__PURE__ */ new Set([
167
+ "insertCompositionText",
168
+ "insertFromComposition",
169
+ "deleteCompositionText",
170
+ "deleteByComposition"
171
+ ]);
93
172
  var CompositionTracker = class {
94
173
  #observedTargets = /* @__PURE__ */ new Set();
95
174
  #activeTargets = /* @__PURE__ */ new Set();
96
175
  #onStart;
97
176
  #onEnd;
177
+ #confirmedTarget = null;
98
178
  constructor(options = {}) {
99
179
  this.#onStart = options.onStart;
100
180
  this.#onEnd = options.onEnd;
101
181
  }
102
- /** Starts lifecycle tracking for `target`; repeated calls are idempotent. */
103
182
  observe(target) {
104
183
  if (this.#observedTargets.has(target)) return;
105
184
  target.addEventListener("compositionstart", this.#handleStart);
106
185
  target.addEventListener("compositionend", this.#handleEnd);
186
+ target.addEventListener("keydown", this.#handleKeydown);
107
187
  this.#observedTargets.add(target);
108
188
  }
109
- /** Stops tracking one target and clears any active composition it owned. */
110
189
  unobserve(target) {
111
190
  if (!this.#observedTargets.delete(target)) return;
112
191
  target.removeEventListener("compositionstart", this.#handleStart);
113
192
  target.removeEventListener("compositionend", this.#handleEnd);
193
+ target.removeEventListener("keydown", this.#handleKeydown);
114
194
  this.#activeTargets.delete(target);
195
+ if (this.#confirmedTarget === target) this.#confirmedTarget = null;
115
196
  }
116
- /** Releases every listener and clears state so reconnect starts cleanly. */
117
197
  disconnect() {
118
198
  for (const target of this.#observedTargets) {
119
199
  target.removeEventListener("compositionstart", this.#handleStart);
120
200
  target.removeEventListener("compositionend", this.#handleEnd);
201
+ target.removeEventListener("keydown", this.#handleKeydown);
121
202
  }
122
203
  this.#observedTargets.clear();
123
204
  this.#activeTargets.clear();
205
+ this.#confirmedTarget = null;
124
206
  }
125
- /** True when lifecycle tracking or the current event reports composition. */
126
207
  isComposing(event) {
127
208
  return this.#activeTargets.size > 0 || event?.isComposing === true;
128
209
  }
210
+ consumesConfirmedInput(event) {
211
+ const confirmed = this.#confirmedTarget;
212
+ this.#confirmedTarget = null;
213
+ if (confirmed === null || confirmed !== event.target) return false;
214
+ const inputType = event.inputType;
215
+ return !inputType || COMPOSITION_INPUT_TYPES.has(inputType);
216
+ }
129
217
  #handleStart = (event) => {
218
+ this.#confirmedTarget = null;
130
219
  if (event.currentTarget) this.#activeTargets.add(event.currentTarget);
131
220
  this.#onStart?.(event);
132
221
  };
133
222
  #handleEnd = (event) => {
134
223
  if (event.currentTarget) this.#activeTargets.delete(event.currentTarget);
224
+ this.#confirmedTarget = event.target;
135
225
  this.#onEnd?.(event);
136
226
  };
227
+ #handleKeydown = () => {
228
+ this.#confirmedTarget = null;
229
+ };
230
+ };
231
+
232
+ var ListenerSet = class {
233
+ #abort = new AbortController();
234
+ add(target, type, handler, options) {
235
+ target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
236
+ }
237
+ dispose() {
238
+ this.#abort.abort();
239
+ this.#abort = new AbortController();
240
+ }
137
241
  };
138
242
 
139
- // src/utils/microtask_coalescer.ts
140
243
  var MicrotaskCoalescer = class {
141
244
  #run;
142
245
  #queued = false;
143
246
  #active = false;
144
247
  #generation = 0;
145
- /** @param run - the single reconciliation pass, invoked at most once per batch. */
146
248
  constructor(run) {
147
249
  this.#run = run;
148
250
  }
149
- /** Opens the window in which {@link schedule} is honoured; call from `connect()`. */
150
251
  activate() {
151
252
  this.#active = true;
152
253
  }
153
- /** Closes the window and drops any pending pass; call from `disconnect()`. */
154
254
  cancel() {
155
255
  this.#active = false;
156
256
  this.#queued = false;
157
257
  this.#generation += 1;
158
258
  }
159
- /** Requests one pass after the batch settles. Idempotent; inert outside the window. */
160
259
  schedule() {
161
260
  if (!this.#active || this.#queued) return;
162
261
  this.#queued = true;
@@ -169,43 +268,93 @@ var MicrotaskCoalescer = class {
169
268
  }
170
269
  };
171
270
 
172
- // src/utils/safe_timeout.ts
271
+ var MorphRenderWatcher = class {
272
+ #listeners = new ListenerSet();
273
+ #pass;
274
+ #element = null;
275
+ #onMorph = () => this.#pass.schedule();
276
+ constructor(run) {
277
+ this.#pass = new MicrotaskCoalescer(run);
278
+ }
279
+ observe(element) {
280
+ if (this.#element === element) return;
281
+ this.disconnect();
282
+ this.#element = element;
283
+ this.#pass.activate();
284
+ this.#listeners.add(element, "turbo:morph-element", this.#onMorph);
285
+ }
286
+ schedule() {
287
+ this.#pass.schedule();
288
+ }
289
+ disconnect() {
290
+ this.#listeners.dispose();
291
+ this.#pass.cancel();
292
+ this.#element = null;
293
+ }
294
+ };
295
+
296
+ var NUMBER_BOUNDS = {
297
+ nonNegative: { finite: true, min: 0 }};
298
+ function matchesNumberBounds(value, bounds) {
299
+ if (!Number.isFinite(value)) {
300
+ const direction = value === Infinity ? "positive" : value === -Infinity ? "negative" : null;
301
+ if (direction === null) return false;
302
+ if (bounds.allowInfinity !== "both" && bounds.allowInfinity !== direction) return false;
303
+ }
304
+ if (bounds.min !== void 0 && value < bounds.min) return false;
305
+ if (bounds.max !== void 0 && value > bounds.max) return false;
306
+ if (bounds.exclusiveMin !== void 0 && value <= bounds.exclusiveMin) return false;
307
+ if (bounds.integer && !Number.isInteger(value)) return false;
308
+ if (bounds.allowedValues !== void 0 && !bounds.allowedValues.includes(value)) return false;
309
+ return true;
310
+ }
311
+
312
+ function readNumber(raw, fallback, bounds) {
313
+ return matchesNumberBounds(raw, bounds) ? raw : fallback;
314
+ }
315
+
316
+ var NumberValueReader = class {
317
+ #lastRejected = /* @__PURE__ */ new Map();
318
+ read(owner, name, raw, fallback, bounds) {
319
+ const resolved = readNumber(raw, fallback, bounds);
320
+ if (matchesNumberBounds(raw, bounds)) {
321
+ this.#lastRejected.delete(name);
322
+ return resolved;
323
+ }
324
+ const attribute = `data-${owner.identifier}-${name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}-value`;
325
+ const literal = owner.element.getAttribute(attribute);
326
+ if (literal === null) {
327
+ this.#lastRejected.delete(name);
328
+ return resolved;
329
+ }
330
+ if (this.#lastRejected.get(name) !== literal) {
331
+ this.#lastRejected.set(name, literal);
332
+ console.warn(
333
+ `Stimeo UI: "${owner.identifier}" has an invalid number Value "${name}" declaration ${JSON.stringify(literal)}; using ${fallback}.`
334
+ );
335
+ }
336
+ return resolved;
337
+ }
338
+ };
339
+
173
340
  var TimerRegistry = class {
174
- /** Live timer ids that have not yet been cleared (or, for timeouts, fired). */
175
341
  ids = /* @__PURE__ */ new Set();
176
- /**
177
- * Cancels a single tracked timer.
178
- *
179
- * No-ops if the id is unknown (already cleared, fired, or never owned by this
180
- * registry), so callers can clear defensively without guarding.
181
- */
182
342
  clear(id) {
183
343
  if (this.ids.delete(id)) {
184
344
  this.cancel(id);
185
345
  }
186
346
  }
187
- /**
188
- * Cancels every tracked timer. Call this from a controller's `disconnect()`
189
- * to guarantee no timer outlives the element.
190
- */
191
347
  clearAll() {
192
348
  for (const id of this.ids) {
193
349
  this.cancel(id);
194
350
  }
195
351
  this.ids.clear();
196
352
  }
197
- /** Number of timers currently tracked (pending). */
198
353
  get size() {
199
354
  return this.ids.size;
200
355
  }
201
356
  };
202
357
  var SafeTimeout = class extends TimerRegistry {
203
- /**
204
- * Schedules `callback` after `delay` ms and returns the timer id.
205
- *
206
- * The id is removed from the registry automatically when the timeout fires,
207
- * so {@link TimerRegistry.size | size} reflects only still-pending timers.
208
- */
209
358
  set(callback, delay) {
210
359
  const id = this.schedule(() => {
211
360
  this.ids.delete(id);
@@ -222,8 +371,8 @@ var SafeTimeout = class extends TimerRegistry {
222
371
  }
223
372
  };
224
373
 
225
- // src/controllers/character_counter_controller.ts
226
374
  var CharacterCounterController = class _CharacterCounterController extends Controller {
375
+ #numbers = new NumberValueReader();
227
376
  static targets = ["input", "output"];
228
377
  static values = {
229
378
  max: { type: Number, default: 0 },
@@ -231,13 +380,18 @@ var CharacterCounterController = class _CharacterCounterController extends Contr
231
380
  mode: { type: String, default: "remaining" },
232
381
  announceText: { type: String, default: "" }
233
382
  };
383
+ static valueConstraints = {
384
+ max: NUMBER_BOUNDS.nonNegative,
385
+ warnAt: NUMBER_BOUNDS.nonNegative
386
+ };
234
387
  static events = ["change", "reconcile"];
235
- /** Delay (ms) before one settled count is sent to the shared announcer. */
236
388
  static #announceDelay = 200;
237
389
  #timeouts = new SafeTimeout();
238
- #ariaInvalid = new AttributeLease("aria-invalid");
239
- #beforeCache = new BeforeCacheReset(() => this.#rewindForCache());
240
- #repaint = new MicrotaskCoalescer(() => this.#reconcile(true));
390
+ #ariaInvalid = new AttributeLease(
391
+ "aria-invalid",
392
+ this.identifier
393
+ );
394
+ #repaint = new MorphRenderWatcher(() => this.#reconcile(true));
241
395
  #composition = new CompositionTracker({
242
396
  onEnd: (event) => this.#commitFrom(event.currentTarget)
243
397
  });
@@ -249,59 +403,46 @@ var CharacterCounterController = class _CharacterCounterController extends Contr
249
403
  #onInput = (event) => {
250
404
  const field = this.#boundField;
251
405
  if (!field || event.currentTarget !== field || this.#field !== field) return;
406
+ if (this.#composition.consumesConfirmedInput(event)) return;
252
407
  if (this.#composition.isComposing(event)) return;
253
408
  this.#commit(field);
254
409
  };
255
- /** Reflects the current DOM state and opens the mutation-reconciliation window. */
256
410
  connect() {
257
- this.#repaint.activate();
258
- this.#beforeCache.activate();
411
+ this.#repaint.observe(this.element);
259
412
  this.#reconcile(false);
260
413
  }
261
- /** Releases listeners, timers, borrowed ARIA, and controller-owned state hooks. */
262
414
  disconnect() {
263
- this.#repaint.cancel();
264
- this.#beforeCache.deactivate();
415
+ this.#repaint.disconnect();
265
416
  this.#cancelAnnouncement();
266
417
  this.#bindField(null);
267
- this.#composition.disconnect();
268
418
  this.#clearStateHooks();
269
419
  this.#lastLength = null;
270
420
  this.#lastDetail = null;
271
421
  }
272
- /** Rebinds and repaints after an input target is added or replaced at runtime. */
273
422
  inputTargetConnected() {
274
423
  this.#repaint.schedule();
275
424
  }
276
- /** Releases and repaints after an input target is removed or replaced at runtime. */
277
425
  inputTargetDisconnected() {
278
426
  this.#repaint.schedule();
279
427
  }
280
- /** Initializes a display target inserted after the controller connected. */
281
428
  outputTargetConnected() {
282
429
  this.#repaint.schedule();
283
430
  }
284
- /** Reconciles the optional display target set after a removal or replacement. */
285
431
  outputTargetDisconnected() {
286
432
  this.#repaint.schedule();
287
433
  }
288
- /** Repaints when application code or a Turbo morph changes `max`. */
289
434
  maxValueChanged() {
290
435
  this.#repaint.schedule();
291
436
  }
292
- /** Repaints when application code or a Turbo morph changes `warnAt`. */
293
437
  warnAtValueChanged() {
294
438
  this.#repaint.schedule();
295
439
  }
296
- /** Repaints when application code or a Turbo morph changes `mode`. */
297
440
  modeValueChanged() {
298
441
  this.#repaint.schedule();
299
442
  }
300
- /** Cancels a pending old message when its consumer-authored template changes. */
301
443
  announceTextValueChanged() {
302
444
  this.#repaint.schedule();
303
445
  }
304
- /** Rebinds one mutation batch and reports a changed controller-derived state. */
305
446
  #reconcile(report) {
306
447
  const previous = this.#lastDetail;
307
448
  const owedField = this.#announceId === null ? null : this.#boundField;
@@ -324,13 +465,11 @@ var CharacterCounterController = class _CharacterCounterController extends Contr
324
465
  this.dispatch("reconcile", { detail });
325
466
  }
326
467
  }
327
- /** Commits a composition only when it came from the field still owned here. */
328
468
  #commitFrom(target) {
329
469
  const field = this.#boundField;
330
470
  if (!field || target !== field || this.#field !== field) return;
331
471
  this.#commit(field);
332
472
  }
333
- /** Reflects one confirmed user input and reports only a real length transition. */
334
473
  #commit(field) {
335
474
  const reading = this.#render(field);
336
475
  const previousLength = this.#lastLength;
@@ -347,7 +486,6 @@ var CharacterCounterController = class _CharacterCounterController extends Contr
347
486
  this.dispatch("change", { detail });
348
487
  this.#scheduleAnnouncement(reading);
349
488
  }
350
- /** Selects the public event state from the richer internal reading. */
351
489
  #detail(reading) {
352
490
  return {
353
491
  length: reading.length,
@@ -355,19 +493,13 @@ var CharacterCounterController = class _CharacterCounterController extends Contr
355
493
  over: reading.over
356
494
  };
357
495
  }
358
- /** Compares exactly the state carried by `change` and `reconcile`. */
359
496
  #detailsDiffer(left, right) {
360
497
  return left.length !== right.length || left.remaining !== right.remaining || left.over !== right.over;
361
498
  }
362
- /**
363
- * Synchronizes visible count, state hooks, and temporary validation ARIA.
364
- *
365
- * @stimeoRenderRoot
366
- */
367
499
  #render(field) {
368
500
  const length = field.value.length;
369
- const max = this.#normalizeCount(this.maxValue);
370
- const warnAt = this.#normalizeCount(this.warnAtValue);
501
+ const max = this.#normalizeCount(this.#safeMax);
502
+ const warnAt = this.#normalizeCount(this.#safeWarnAt);
371
503
  const remaining = max > 0 ? max - length : null;
372
504
  const over = remaining !== null && remaining < 0;
373
505
  const near = remaining !== null && warnAt > 0 && !over && remaining <= warnAt;
@@ -378,14 +510,11 @@ var CharacterCounterController = class _CharacterCounterController extends Contr
378
510
  this.#writeOutput(text);
379
511
  return { length, remaining, over, max, text };
380
512
  }
381
- /** Clears derived output when the declarative input set has no usable field. */
382
513
  #renderEmpty() {
383
- this.#ariaInvalid.returnAll();
384
514
  this.#reflectedOver = null;
385
515
  this.#clearStateHooks();
386
516
  this.#writeOutput("");
387
517
  }
388
- /** Replaces the observed field symmetrically, returning state from the old one. */
389
518
  #bindField(field) {
390
519
  if (field === this.#boundField) return;
391
520
  const previous = this.#boundField;
@@ -401,14 +530,12 @@ var CharacterCounterController = class _CharacterCounterController extends Contr
401
530
  field.addEventListener("input", this.#onInput);
402
531
  this.#composition.observe(field);
403
532
  }
404
- /** Leases `aria-invalid` only on the edge into over-limit, then returns it. */
405
533
  #reflectInvalid(field, over) {
406
- if (this.#reflectedOver === over) return;
534
+ if (this.#reflectedOver === over && (!over || field.hasAttribute("aria-invalid"))) return;
407
535
  this.#reflectedOver = over;
408
536
  if (over) this.#ariaInvalid.write(field, "true");
409
537
  else this.#ariaInvalid.return(field);
410
538
  }
411
- /** Builds the visible count for the normalized display mode. */
412
539
  #format(length, remaining, max) {
413
540
  if (remaining === null) return String(length);
414
541
  switch (this.#mode) {
@@ -420,7 +547,6 @@ var CharacterCounterController = class _CharacterCounterController extends Contr
420
547
  return String(remaining);
421
548
  }
422
549
  }
423
- /** Debounces one i18n-neutral message into the shared polite announcer. */
424
550
  #scheduleAnnouncement(reading) {
425
551
  this.#cancelAnnouncement();
426
552
  const message = fillTemplate(this.announceTextValue, {
@@ -436,17 +562,14 @@ var CharacterCounterController = class _CharacterCounterController extends Contr
436
562
  this.#announceId = null;
437
563
  }, _CharacterCounterController.#announceDelay);
438
564
  }
439
- /** Cancels the one outstanding announcement without touching visible output. */
440
565
  #cancelAnnouncement() {
441
566
  if (this.#announceId !== null) this.#timeouts.clear(this.#announceId);
442
567
  this.#announceId = null;
443
568
  }
444
- /** Writes the optional display only when its text actually changed. */
445
569
  #writeOutput(text) {
446
570
  if (!this.hasOutputTarget || this.outputTarget.textContent === text) return;
447
571
  this.outputTarget.textContent = text;
448
572
  }
449
- /** Reflects a presence-style state hook without redundant attribute writes. */
450
573
  #toggle(name, on) {
451
574
  if (on) {
452
575
  if (this.element.getAttribute(name) !== "true") this.element.setAttribute(name, "true");
@@ -454,29 +577,17 @@ var CharacterCounterController = class _CharacterCounterController extends Contr
454
577
  this.element.removeAttribute(name);
455
578
  }
456
579
  }
457
- /** Removes both state hooks owned by this controller. */
458
580
  #clearStateHooks() {
459
581
  this.#toggle("data-over-limit", false);
460
582
  this.#toggle("data-near-limit", false);
461
583
  }
462
- /** Returns borrowed ARIA and transient hooks before Turbo snapshots the page. */
463
- #rewindForCache() {
464
- this.#cancelAnnouncement();
465
- this.#ariaInvalid.returnAll();
466
- this.#reflectedOver = null;
467
- this.#clearStateHooks();
468
- }
469
- /** Converts a public count Value into a finite non-negative integer. */
470
584
  #normalizeCount(raw) {
471
- if (!Number.isFinite(raw)) return 0;
472
585
  return Math.max(0, Math.trunc(raw));
473
586
  }
474
- /** Falls back to `remaining` when an authored display mode is unknown. */
475
587
  get #mode() {
476
588
  if (this.modeValue === "used" || this.modeValue === "both") return this.modeValue;
477
589
  return "remaining";
478
590
  }
479
- /** The watched field: the first target, or a directly controlled form field. */
480
591
  get #field() {
481
592
  if (this.hasInputTarget) return this.inputTarget;
482
593
  const element = this.element;
@@ -484,8 +595,25 @@ var CharacterCounterController = class _CharacterCounterController extends Contr
484
595
  return element;
485
596
  return null;
486
597
  }
598
+ get #safeMax() {
599
+ return this.#numbers.read(
600
+ this,
601
+ "max",
602
+ this.maxValue,
603
+ _CharacterCounterController.values.max.default,
604
+ _CharacterCounterController.valueConstraints.max
605
+ );
606
+ }
607
+ get #safeWarnAt() {
608
+ return this.#numbers.read(
609
+ this,
610
+ "warnAt",
611
+ this.warnAtValue,
612
+ _CharacterCounterController.values.warnAt.default,
613
+ _CharacterCounterController.valueConstraints.warnAt
614
+ );
615
+ }
487
616
  };
488
617
 
489
618
  export { CharacterCounterController };
490
- //# sourceMappingURL=character_counter_controller.js.map
491
619
  //# sourceMappingURL=character_counter_controller.js.map