stimeo-ui 0.17.0 → 0.18.1

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 (299) hide show
  1. package/CHANGELOG.md +136 -2
  2. package/README.md +19 -10
  3. package/dist/cable/index.d.ts +11 -9
  4. package/dist/cable/index.js +22 -14
  5. package/dist/cable/index.js.map +1 -1
  6. package/dist/coerce-JtZVNG5h.d.ts +20 -0
  7. package/dist/controllers/accordion_controller.js +14 -6
  8. package/dist/controllers/accordion_controller.js.map +1 -1
  9. package/dist/controllers/alert_dialog_controller.js +145 -118
  10. package/dist/controllers/alert_dialog_controller.js.map +1 -1
  11. package/dist/controllers/announcer_controller.d.ts +5 -3
  12. package/dist/controllers/announcer_controller.js +113 -17
  13. package/dist/controllers/announcer_controller.js.map +1 -1
  14. package/dist/controllers/auto_submit_controller.js +185 -60
  15. package/dist/controllers/auto_submit_controller.js.map +1 -1
  16. package/dist/controllers/avatar_controller.js +55 -43
  17. package/dist/controllers/avatar_controller.js.map +1 -1
  18. package/dist/controllers/breadcrumb_controller.js.map +1 -1
  19. package/dist/controllers/bulk_select_controller.d.ts +3 -3
  20. package/dist/controllers/bulk_select_controller.js +64 -50
  21. package/dist/controllers/bulk_select_controller.js.map +1 -1
  22. package/dist/controllers/calendar_controller.d.ts +15 -12
  23. package/dist/controllers/calendar_controller.js +55 -53
  24. package/dist/controllers/calendar_controller.js.map +1 -1
  25. package/dist/controllers/carousel_controller.d.ts +9 -5
  26. package/dist/controllers/carousel_controller.js +124 -86
  27. package/dist/controllers/carousel_controller.js.map +1 -1
  28. package/dist/controllers/character_counter_controller.d.ts +27 -6
  29. package/dist/controllers/character_counter_controller.js +291 -95
  30. package/dist/controllers/character_counter_controller.js.map +1 -1
  31. package/dist/controllers/checkbox_controller.js +6 -0
  32. package/dist/controllers/checkbox_controller.js.map +1 -1
  33. package/dist/controllers/clipboard_controller.js +118 -27
  34. package/dist/controllers/clipboard_controller.js.map +1 -1
  35. package/dist/controllers/collapsible_controller.d.ts +1 -1
  36. package/dist/controllers/collapsible_controller.js +52 -49
  37. package/dist/controllers/collapsible_controller.js.map +1 -1
  38. package/dist/controllers/color_picker_controller.js +29 -7
  39. package/dist/controllers/color_picker_controller.js.map +1 -1
  40. package/dist/controllers/combobox_controller.d.ts +1 -1
  41. package/dist/controllers/combobox_controller.js +210 -71
  42. package/dist/controllers/combobox_controller.js.map +1 -1
  43. package/dist/controllers/command_palette_controller.d.ts +9 -9
  44. package/dist/controllers/command_palette_controller.js +290 -140
  45. package/dist/controllers/command_palette_controller.js.map +1 -1
  46. package/dist/controllers/conditional_fields_controller.js +145 -58
  47. package/dist/controllers/conditional_fields_controller.js.map +1 -1
  48. package/dist/controllers/confirm_controller.js +145 -118
  49. package/dist/controllers/confirm_controller.js.map +1 -1
  50. package/dist/controllers/context_menu_controller.d.ts +49 -14
  51. package/dist/controllers/context_menu_controller.js +138 -73
  52. package/dist/controllers/context_menu_controller.js.map +1 -1
  53. package/dist/controllers/count_up_controller.js.map +1 -1
  54. package/dist/controllers/countdown_controller.d.ts +2 -2
  55. package/dist/controllers/countdown_controller.js +109 -21
  56. package/dist/controllers/countdown_controller.js.map +1 -1
  57. package/dist/controllers/currency_input_controller.d.ts +75 -11
  58. package/dist/controllers/currency_input_controller.js +446 -72
  59. package/dist/controllers/currency_input_controller.js.map +1 -1
  60. package/dist/controllers/data_grid_controller.d.ts +10 -8
  61. package/dist/controllers/data_grid_controller.js +134 -28
  62. package/dist/controllers/data_grid_controller.js.map +1 -1
  63. package/dist/controllers/date_range_picker_controller.d.ts +12 -9
  64. package/dist/controllers/date_range_picker_controller.js +93 -72
  65. package/dist/controllers/date_range_picker_controller.js.map +1 -1
  66. package/dist/controllers/dialog_controller.d.ts +4 -5
  67. package/dist/controllers/dialog_controller.js +145 -118
  68. package/dist/controllers/dialog_controller.js.map +1 -1
  69. package/dist/controllers/direct_upload_controller.d.ts +1 -1
  70. package/dist/controllers/direct_upload_controller.js +24 -14
  71. package/dist/controllers/direct_upload_controller.js.map +1 -1
  72. package/dist/controllers/dirty_form_controller.d.ts +6 -1
  73. package/dist/controllers/dirty_form_controller.js +68 -31
  74. package/dist/controllers/dirty_form_controller.js.map +1 -1
  75. package/dist/controllers/dismissible_controller.js +66 -46
  76. package/dist/controllers/dismissible_controller.js.map +1 -1
  77. package/dist/controllers/drawer_controller.js +145 -118
  78. package/dist/controllers/drawer_controller.js.map +1 -1
  79. package/dist/controllers/dropdown_controller.js +76 -63
  80. package/dist/controllers/dropdown_controller.js.map +1 -1
  81. package/dist/controllers/editable_controller.js +200 -62
  82. package/dist/controllers/editable_controller.js.map +1 -1
  83. package/dist/controllers/empty_state_controller.js +13 -6
  84. package/dist/controllers/empty_state_controller.js.map +1 -1
  85. package/dist/controllers/file_dropzone_controller.d.ts +3 -0
  86. package/dist/controllers/file_dropzone_controller.js +55 -48
  87. package/dist/controllers/file_dropzone_controller.js.map +1 -1
  88. package/dist/controllers/filter_controller.js +9 -2
  89. package/dist/controllers/filter_controller.js.map +1 -1
  90. package/dist/controllers/flash_controller.d.ts +4 -4
  91. package/dist/controllers/flash_controller.js +66 -33
  92. package/dist/controllers/flash_controller.js.map +1 -1
  93. package/dist/controllers/focus_controller.d.ts +3 -3
  94. package/dist/controllers/focus_controller.js +39 -14
  95. package/dist/controllers/focus_controller.js.map +1 -1
  96. package/dist/controllers/form_field_controller.d.ts +2 -1
  97. package/dist/controllers/form_field_controller.js +52 -43
  98. package/dist/controllers/form_field_controller.js.map +1 -1
  99. package/dist/controllers/form_validation_controller.d.ts +3 -3
  100. package/dist/controllers/form_validation_controller.js +18 -11
  101. package/dist/controllers/form_validation_controller.js.map +1 -1
  102. package/dist/controllers/frame_loading_controller.d.ts +13 -12
  103. package/dist/controllers/frame_loading_controller.js +55 -48
  104. package/dist/controllers/frame_loading_controller.js.map +1 -1
  105. package/dist/controllers/highlight_controller.d.ts +5 -4
  106. package/dist/controllers/highlight_controller.js.map +1 -1
  107. package/dist/controllers/hover_card_controller.d.ts +4 -1
  108. package/dist/controllers/hover_card_controller.js +67 -61
  109. package/dist/controllers/hover_card_controller.js.map +1 -1
  110. package/dist/controllers/idle_controller.d.ts +6 -5
  111. package/dist/controllers/idle_controller.js +10 -6
  112. package/dist/controllers/idle_controller.js.map +1 -1
  113. package/dist/controllers/input_mask_controller.d.ts +31 -13
  114. package/dist/controllers/input_mask_controller.js +434 -24
  115. package/dist/controllers/input_mask_controller.js.map +1 -1
  116. package/dist/controllers/intersection_controller.js +3 -0
  117. package/dist/controllers/intersection_controller.js.map +1 -1
  118. package/dist/controllers/lazy_frame_controller.d.ts +3 -2
  119. package/dist/controllers/lazy_frame_controller.js +15 -3
  120. package/dist/controllers/lazy_frame_controller.js.map +1 -1
  121. package/dist/controllers/listbox_controller.d.ts +10 -7
  122. package/dist/controllers/listbox_controller.js +260 -79
  123. package/dist/controllers/listbox_controller.js.map +1 -1
  124. package/dist/controllers/local_time_controller.d.ts +8 -6
  125. package/dist/controllers/local_time_controller.js +48 -13
  126. package/dist/controllers/local_time_controller.js.map +1 -1
  127. package/dist/controllers/masonry_controller.js +11 -4
  128. package/dist/controllers/masonry_controller.js.map +1 -1
  129. package/dist/controllers/menu_controller.d.ts +24 -5
  130. package/dist/controllers/menu_controller.js +138 -82
  131. package/dist/controllers/menu_controller.js.map +1 -1
  132. package/dist/controllers/menubar_controller.d.ts +49 -7
  133. package/dist/controllers/menubar_controller.js +65 -19
  134. package/dist/controllers/menubar_controller.js.map +1 -1
  135. package/dist/controllers/meter_controller.d.ts +13 -20
  136. package/dist/controllers/meter_controller.js +270 -24
  137. package/dist/controllers/meter_controller.js.map +1 -1
  138. package/dist/controllers/multi_select_controller.d.ts +19 -16
  139. package/dist/controllers/multi_select_controller.js +272 -95
  140. package/dist/controllers/multi_select_controller.js.map +1 -1
  141. package/dist/controllers/navigation_menu_controller.d.ts +19 -5
  142. package/dist/controllers/navigation_menu_controller.js +67 -19
  143. package/dist/controllers/navigation_menu_controller.js.map +1 -1
  144. package/dist/controllers/nested_form_controller.js +98 -64
  145. package/dist/controllers/nested_form_controller.js.map +1 -1
  146. package/dist/controllers/network_status_controller.js +70 -52
  147. package/dist/controllers/network_status_controller.js.map +1 -1
  148. package/dist/controllers/number_input_controller.d.ts +24 -6
  149. package/dist/controllers/number_input_controller.js +344 -94
  150. package/dist/controllers/number_input_controller.js.map +1 -1
  151. package/dist/controllers/optimistic_controller.d.ts +8 -5
  152. package/dist/controllers/optimistic_controller.js +29 -11
  153. package/dist/controllers/optimistic_controller.js.map +1 -1
  154. package/dist/controllers/otp_controller.d.ts +35 -4
  155. package/dist/controllers/otp_controller.js +502 -104
  156. package/dist/controllers/otp_controller.js.map +1 -1
  157. package/dist/controllers/overflow_indicator_controller.js +6 -0
  158. package/dist/controllers/overflow_indicator_controller.js.map +1 -1
  159. package/dist/controllers/overflow_menu_controller.d.ts +10 -9
  160. package/dist/controllers/overflow_menu_controller.js +136 -21
  161. package/dist/controllers/overflow_menu_controller.js.map +1 -1
  162. package/dist/controllers/pagination_controller.d.ts +3 -2
  163. package/dist/controllers/pagination_controller.js +47 -14
  164. package/dist/controllers/pagination_controller.js.map +1 -1
  165. package/dist/controllers/password_reveal_controller.d.ts +5 -4
  166. package/dist/controllers/password_reveal_controller.js +52 -49
  167. package/dist/controllers/password_reveal_controller.js.map +1 -1
  168. package/dist/controllers/password_strength_controller.d.ts +1 -1
  169. package/dist/controllers/password_strength_controller.js +13 -6
  170. package/dist/controllers/password_strength_controller.js.map +1 -1
  171. package/dist/controllers/persist_controller.js +48 -128
  172. package/dist/controllers/persist_controller.js.map +1 -1
  173. package/dist/controllers/pointer_drag_controller.d.ts +20 -8
  174. package/dist/controllers/pointer_drag_controller.js +255 -24
  175. package/dist/controllers/pointer_drag_controller.js.map +1 -1
  176. package/dist/controllers/popover_controller.d.ts +9 -5
  177. package/dist/controllers/popover_controller.js +91 -65
  178. package/dist/controllers/popover_controller.js.map +1 -1
  179. package/dist/controllers/portal_controller.js +6 -0
  180. package/dist/controllers/portal_controller.js.map +1 -1
  181. package/dist/controllers/preview_guard_controller.js +14 -3
  182. package/dist/controllers/preview_guard_controller.js.map +1 -1
  183. package/dist/controllers/progress_controller.d.ts +9 -19
  184. package/dist/controllers/progress_controller.js +271 -27
  185. package/dist/controllers/progress_controller.js.map +1 -1
  186. package/dist/controllers/radio_group_controller.d.ts +11 -8
  187. package/dist/controllers/radio_group_controller.js +167 -80
  188. package/dist/controllers/radio_group_controller.js.map +1 -1
  189. package/dist/controllers/range_slider_controller.d.ts +4 -3
  190. package/dist/controllers/range_slider_controller.js +27 -7
  191. package/dist/controllers/range_slider_controller.js.map +1 -1
  192. package/dist/controllers/rating_controller.js +93 -57
  193. package/dist/controllers/rating_controller.js.map +1 -1
  194. package/dist/controllers/read_more_controller.js +10 -6
  195. package/dist/controllers/read_more_controller.js.map +1 -1
  196. package/dist/controllers/reading_progress_controller.js +22 -5
  197. package/dist/controllers/reading_progress_controller.js.map +1 -1
  198. package/dist/controllers/relative_time_controller.d.ts +4 -4
  199. package/dist/controllers/relative_time_controller.js +75 -11
  200. package/dist/controllers/relative_time_controller.js.map +1 -1
  201. package/dist/controllers/reset_on_restore_controller.d.ts +3 -3
  202. package/dist/controllers/reset_on_restore_controller.js +6 -0
  203. package/dist/controllers/reset_on_restore_controller.js.map +1 -1
  204. package/dist/controllers/resizable_controller.d.ts +3 -0
  205. package/dist/controllers/resizable_controller.js +55 -22
  206. package/dist/controllers/resizable_controller.js.map +1 -1
  207. package/dist/controllers/roving_controller.d.ts +3 -3
  208. package/dist/controllers/roving_controller.js +10 -4
  209. package/dist/controllers/roving_controller.js.map +1 -1
  210. package/dist/controllers/scroll_area_controller.js +129 -88
  211. package/dist/controllers/scroll_area_controller.js.map +1 -1
  212. package/dist/controllers/scroll_restore_controller.d.ts +3 -3
  213. package/dist/controllers/scroll_restore_controller.js +14 -2
  214. package/dist/controllers/scroll_restore_controller.js.map +1 -1
  215. package/dist/controllers/scroll_visibility_controller.js +93 -60
  216. package/dist/controllers/scroll_visibility_controller.js.map +1 -1
  217. package/dist/controllers/scrollspy_controller.js +11 -5
  218. package/dist/controllers/scrollspy_controller.js.map +1 -1
  219. package/dist/controllers/separator_controller.d.ts +1 -1
  220. package/dist/controllers/separator_controller.js +59 -43
  221. package/dist/controllers/separator_controller.js.map +1 -1
  222. package/dist/controllers/sidebar_controller.d.ts +1 -1
  223. package/dist/controllers/sidebar_controller.js +150 -122
  224. package/dist/controllers/sidebar_controller.js.map +1 -1
  225. package/dist/controllers/skeleton_controller.js +55 -48
  226. package/dist/controllers/skeleton_controller.js.map +1 -1
  227. package/dist/controllers/slider_controller.d.ts +2 -1
  228. package/dist/controllers/slider_controller.js +27 -6
  229. package/dist/controllers/slider_controller.js.map +1 -1
  230. package/dist/controllers/smart_sticky_header_controller.d.ts +1 -1
  231. package/dist/controllers/smart_sticky_header_controller.js +13 -5
  232. package/dist/controllers/smart_sticky_header_controller.js.map +1 -1
  233. package/dist/controllers/sortable_controller.d.ts +4 -4
  234. package/dist/controllers/sortable_controller.js +27 -14
  235. package/dist/controllers/sortable_controller.js.map +1 -1
  236. package/dist/controllers/spinner_controller.js +55 -48
  237. package/dist/controllers/spinner_controller.js.map +1 -1
  238. package/dist/controllers/step_indicator_controller.d.ts +4 -4
  239. package/dist/controllers/step_indicator_controller.js +6 -0
  240. package/dist/controllers/step_indicator_controller.js.map +1 -1
  241. package/dist/controllers/stepper_controller.d.ts +2 -3
  242. package/dist/controllers/stepper_controller.js +6 -0
  243. package/dist/controllers/stepper_controller.js.map +1 -1
  244. package/dist/controllers/stick_to_bottom_controller.d.ts +3 -1
  245. package/dist/controllers/stick_to_bottom_controller.js +19 -8
  246. package/dist/controllers/stick_to_bottom_controller.js.map +1 -1
  247. package/dist/controllers/sticky_observer_controller.js +49 -43
  248. package/dist/controllers/sticky_observer_controller.js.map +1 -1
  249. package/dist/controllers/submit_once_controller.d.ts +2 -1
  250. package/dist/controllers/submit_once_controller.js +145 -85
  251. package/dist/controllers/submit_once_controller.js.map +1 -1
  252. package/dist/controllers/switch_controller.d.ts +7 -4
  253. package/dist/controllers/switch_controller.js +172 -28
  254. package/dist/controllers/switch_controller.js.map +1 -1
  255. package/dist/controllers/tabs_controller.d.ts +7 -4
  256. package/dist/controllers/tabs_controller.js +6 -1
  257. package/dist/controllers/tabs_controller.js.map +1 -1
  258. package/dist/controllers/tags_input_controller.d.ts +4 -3
  259. package/dist/controllers/tags_input_controller.js +157 -28
  260. package/dist/controllers/tags_input_controller.js.map +1 -1
  261. package/dist/controllers/textarea_autosize_controller.d.ts +1 -1
  262. package/dist/controllers/textarea_autosize_controller.js +40 -19
  263. package/dist/controllers/textarea_autosize_controller.js.map +1 -1
  264. package/dist/controllers/theme_controller.d.ts +3 -2
  265. package/dist/controllers/theme_controller.js +10 -4
  266. package/dist/controllers/theme_controller.js.map +1 -1
  267. package/dist/controllers/time_picker_controller.d.ts +38 -5
  268. package/dist/controllers/time_picker_controller.js +192 -54
  269. package/dist/controllers/time_picker_controller.js.map +1 -1
  270. package/dist/controllers/toast_controller.d.ts +4 -5
  271. package/dist/controllers/toast_controller.js +58 -27
  272. package/dist/controllers/toast_controller.js.map +1 -1
  273. package/dist/controllers/toggle_group_controller.d.ts +2 -3
  274. package/dist/controllers/toggle_group_controller.js +158 -56
  275. package/dist/controllers/toggle_group_controller.js.map +1 -1
  276. package/dist/controllers/toolbar_controller.d.ts +8 -6
  277. package/dist/controllers/toolbar_controller.js +150 -21
  278. package/dist/controllers/toolbar_controller.js.map +1 -1
  279. package/dist/controllers/tooltip_controller.d.ts +4 -1
  280. package/dist/controllers/tooltip_controller.js.map +1 -1
  281. package/dist/controllers/transition_controller.js.map +1 -1
  282. package/dist/controllers/tree_view_controller.d.ts +1 -1
  283. package/dist/controllers/tree_view_controller.js +134 -25
  284. package/dist/controllers/tree_view_controller.js.map +1 -1
  285. package/dist/index.d.ts +4 -1
  286. package/dist/index.js +2515 -1315
  287. package/dist/index.js.map +1 -1
  288. package/dist/inspector/cli.d.ts +25 -12
  289. package/dist/inspector/cli.js +21 -3
  290. package/dist/inspector/cli.js.map +1 -1
  291. package/dist/inspector/cli_bin.d.ts +1 -1
  292. package/dist/inspector/cli_bin.js +62 -8
  293. package/dist/inspector/cli_bin.js.map +1 -1
  294. package/dist/inspector/examples.json +13 -13
  295. package/dist/inspector/manifest.json +19 -5
  296. package/dist/positioning/index.d.ts +9 -8
  297. package/dist/positioning/index.js +6 -0
  298. package/dist/positioning/index.js.map +1 -1
  299. package/package.json +11 -10
@@ -22,6 +22,13 @@ function actionSource(source) {
22
22
  };
23
23
  }
24
24
 
25
+ function fillTemplate(template, values) {
26
+ return template.replace(/\{([a-zA-Z][a-zA-Z0-9]*)\}/g, (match, name) => {
27
+ const replacement = Object.hasOwn(values, name) ? values[name] : void 0;
28
+ return replacement === void 0 ? match : String(replacement);
29
+ });
30
+ }
31
+
25
32
  function announce(message, options = {}) {
26
33
  const text = message.trim();
27
34
  if (text.length === 0) return;
@@ -31,21 +38,15 @@ function announce(message, options = {}) {
31
38
  })
32
39
  );
33
40
  }
34
- function fillTemplate(template, values) {
35
- return template.replace(/\{([a-zA-Z][a-zA-Z0-9]*)\}/g, (match, name) => {
36
- const replacement = values[name];
37
- return replacement === void 0 ? match : String(replacement);
38
- });
39
- }
40
41
 
41
42
  function sharedRegistry(key, create) {
42
43
  const symbol = Symbol.for(key);
43
44
  const scope = globalThis;
44
45
  const existing = scope[symbol];
45
46
  if (existing !== void 0) return existing;
46
- const registry = create();
47
- Object.defineProperty(globalThis, symbol, { value: registry });
48
- return registry;
47
+ const registry2 = create();
48
+ Object.defineProperty(globalThis, symbol, { value: registry2 });
49
+ return registry2;
49
50
  }
50
51
 
51
52
  var ids = sharedRegistry("stimeo-ui.aria-ids.registry.v1", () => ({ counter: 0 }));
@@ -77,7 +78,21 @@ function isReservedArrowChord(event, allow = []) {
77
78
  if (!event.key.startsWith("Arrow")) return false;
78
79
  return event.altKey && !allow.includes("alt") || event.ctrlKey && !allow.includes("ctrl") || event.metaKey && !allow.includes("meta") || event.shiftKey && !allow.includes("shift");
79
80
  }
81
+ function hasModifierChord(event) {
82
+ return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
83
+ }
84
+
85
+ function setAttributeIfChanged(element, name, value, beforeWrite) {
86
+ if (element.getAttribute(name) === value) return false;
87
+ if (value === null) element.removeAttribute(name);
88
+ else element.setAttribute(name, value);
89
+ return true;
90
+ }
80
91
 
92
+ var registry = sharedRegistry(
93
+ "stimeo-ui.attribute-lease.registry.v1",
94
+ () => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Map() })
95
+ );
81
96
  function isAttributeValue(value) {
82
97
  return value === null || typeof value === "string";
83
98
  }
@@ -94,24 +109,46 @@ function readLeaseRecord(element, record) {
94
109
  return void 0;
95
110
  }
96
111
  }
97
- var AttributeLease = class _AttributeLease {
98
- static #registry = sharedRegistry(
99
- "stimeo-ui.attribute-lease.registry.v1",
100
- () => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Map() })
101
- );
112
+ function attributeStack(element, attribute) {
113
+ const byAttribute = registry.stacks.get(element) ?? /* @__PURE__ */ new Map();
114
+ registry.stacks.set(element, byAttribute);
115
+ const known = byAttribute.get(attribute);
116
+ if (known) return known;
117
+ const found = [];
118
+ for (const record of registry.names.get(attribute) ?? []) {
119
+ const read = readLeaseRecord(element, record);
120
+ if (read) found.push({ ...read, record });
121
+ }
122
+ const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
123
+ const stack = found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
124
+ lease: null,
125
+ record,
126
+ written,
127
+ original,
128
+ linked: linked && index > 0
129
+ }));
130
+ byAttribute.set(attribute, stack);
131
+ return stack;
132
+ }
133
+ function findHold(stack, lease, record) {
134
+ return stack.find((held) => held.lease === lease) ?? stack.find((held) => held.lease === null && held.record === record);
135
+ }
136
+ var AttributeLease = class {
102
137
  #attribute;
103
138
  #record;
104
139
  #base;
140
+ #preserveAuthor;
105
141
  #held = /* @__PURE__ */ new Set();
106
142
  constructor(attribute, owner, options = {}) {
107
143
  this.#attribute = attribute;
108
144
  this.#record = `data-${owner}-${attribute}-lease`;
109
145
  this.#base = options.base === true;
110
- const names = _AttributeLease.#registry.names;
146
+ this.#preserveAuthor = options.preserveAuthor === true;
147
+ const names = registry.names;
111
148
  names.set(attribute, (names.get(attribute) ?? /* @__PURE__ */ new Set()).add(this.#record));
112
149
  }
113
150
  write(element, value) {
114
- const stack = this.#stack(element);
151
+ const stack = attributeStack(element, this.#attribute);
115
152
  const hold = this.#take(stack) ?? this.#acquire(element, stack);
116
153
  this.#held.add(element);
117
154
  const shows = !this.#covered(element, stack, hold);
@@ -121,8 +158,8 @@ var AttributeLease = class _AttributeLease {
121
158
  }
122
159
  return(element) {
123
160
  const held = this.#held.delete(element);
124
- const known = _AttributeLease.#registry.stacks.get(element)?.has(this.#attribute);
125
- const stack = held || known || element.hasAttribute(this.#record) ? this.#stack(element) : [];
161
+ const known = registry.stacks.get(element)?.has(this.#attribute);
162
+ const stack = held || known || element.hasAttribute(this.#record) ? attributeStack(element, this.#attribute) : [];
126
163
  const hold = this.#take(stack);
127
164
  if (!hold) return false;
128
165
  const carries = element.getAttribute(this.#attribute) === hold.written;
@@ -140,31 +177,8 @@ var AttributeLease = class _AttributeLease {
140
177
  returnAll() {
141
178
  for (const element of Array.from(this.#held)) this.return(element);
142
179
  }
143
- #stack(element) {
144
- const stacks = _AttributeLease.#registry.stacks;
145
- const byAttribute = stacks.get(element) ?? /* @__PURE__ */ new Map();
146
- stacks.set(element, byAttribute);
147
- const stack = byAttribute.get(this.#attribute) ?? this.#seed(element);
148
- byAttribute.set(this.#attribute, stack);
149
- return stack;
150
- }
151
- #seed(element) {
152
- const found = [];
153
- for (const record of _AttributeLease.#registry.names.get(this.#attribute) ?? []) {
154
- const read = readLeaseRecord(element, record);
155
- if (read) found.push({ ...read, record });
156
- }
157
- const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
158
- return found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
159
- lease: null,
160
- record,
161
- written,
162
- original,
163
- linked: linked && index > 0
164
- }));
165
- }
166
180
  #take(stack) {
167
- const hold = stack.find((held) => held.lease === this) ?? stack.find((held) => held.lease === null && held.record === this.#record);
181
+ const hold = findHold(stack, this, this.#record);
168
182
  if (hold) hold.lease = this;
169
183
  return hold;
170
184
  }
@@ -173,7 +187,7 @@ var AttributeLease = class _AttributeLease {
173
187
  const top = stack.at(-1);
174
188
  const bottom = stack[0];
175
189
  const over = top?.written === current ? top : void 0;
176
- const from = this.#base ? bottom : over;
190
+ const from = this.#base ? this.#preserveAuthor && !stack.some((held) => held.written === current) ? void 0 : bottom : over;
177
191
  const hold = {
178
192
  lease: this,
179
193
  record: this.#record,
@@ -203,15 +217,11 @@ var AttributeLease = class _AttributeLease {
203
217
  );
204
218
  });
205
219
  for (const [name, recorded] of records) {
206
- if (element.getAttribute(name) === recorded) continue;
207
- if (recorded === null) element.removeAttribute(name);
208
- else element.setAttribute(name, recorded);
220
+ setAttributeIfChanged(element, name, recorded);
209
221
  }
210
222
  }
211
223
  #reflect(element, value) {
212
- if (element.getAttribute(this.#attribute) === value) return;
213
- if (value === null) element.removeAttribute(this.#attribute);
214
- else element.setAttribute(this.#attribute, value);
224
+ setAttributeIfChanged(element, this.#attribute, value);
215
225
  }
216
226
  };
217
227
 
@@ -260,7 +270,7 @@ var RovingTabindex = class {
260
270
  };
261
271
 
262
272
  var ChipRow = class {
263
- #directionElement;
273
+ #getDirectionElement;
264
274
  #getItems;
265
275
  #getButton;
266
276
  #onRemove;
@@ -268,7 +278,7 @@ var ChipRow = class {
268
278
  #roving = new RovingTabindex(() => this.buttons);
269
279
  #container = null;
270
280
  constructor(options) {
271
- this.#directionElement = options.directionElement;
281
+ this.#getDirectionElement = options.getDirectionElement;
272
282
  this.#getItems = options.getItems;
273
283
  this.#getButton = options.getButton ?? ((item) => matchingPart(item, "button"));
274
284
  this.#onRemove = options.onRemove;
@@ -349,7 +359,7 @@ var ChipRow = class {
349
359
  if (!entry) return;
350
360
  const buttons = entry.buttons;
351
361
  const index = entry.buttonIndex;
352
- switch (logicalArrowKey(event.key, this.#directionElement)) {
362
+ switch (logicalArrowKey(event.key, this.#getDirectionElement())) {
353
363
  case "ArrowLeft":
354
364
  if (index > 0) {
355
365
  event.preventDefault();
@@ -379,63 +389,182 @@ var COMPOSITION_INPUT_TYPES = /* @__PURE__ */ new Set([
379
389
  "deleteCompositionText",
380
390
  "deleteByComposition"
381
391
  ]);
392
+ function isCompositionInputType(inputType) {
393
+ return inputType !== void 0 && COMPOSITION_INPUT_TYPES.has(inputType);
394
+ }
395
+ var BEFORE_MORPH_ATTRIBUTE = "turbo:before-morph-attribute";
396
+ var textOf = (element) => element.value;
397
+ var holdsFocus = (element) => element instanceof Node && element.getRootNode().activeElement === element;
382
398
  var CompositionTracker = class {
383
399
  #observedTargets = /* @__PURE__ */ new Set();
384
- #activeTargets = /* @__PURE__ */ new Set();
400
+ #composition = null;
385
401
  #onStart;
386
402
  #onEnd;
403
+ #onAbandon;
387
404
  #confirmedTarget = null;
405
+ #keyComposing = false;
406
+ #connected = false;
407
+ #abandoned = null;
388
408
  constructor(options = {}) {
389
409
  this.#onStart = options.onStart;
390
410
  this.#onEnd = options.onEnd;
411
+ this.#onAbandon = options.onAbandon;
391
412
  }
392
413
  observe(target) {
414
+ this.#connected = true;
393
415
  if (this.#observedTargets.has(target)) return;
394
416
  target.addEventListener("compositionstart", this.#handleStart);
395
417
  target.addEventListener("compositionend", this.#handleEnd);
396
- target.addEventListener("keydown", this.#handleKeydown);
418
+ target.addEventListener("keydown", this.#handleKeydown, true);
419
+ target.addEventListener("beforeinput", this.#handleBeforeInput, true);
420
+ target.addEventListener("input", this.#handleInput, true);
421
+ target.addEventListener("blur", this.#handleBlur, true);
422
+ target.addEventListener(BEFORE_MORPH_ATTRIBUTE, this.#handleBeforeMorphAttribute);
397
423
  this.#observedTargets.add(target);
398
424
  }
399
425
  unobserve(target) {
400
426
  if (!this.#observedTargets.delete(target)) return;
401
- target.removeEventListener("compositionstart", this.#handleStart);
402
- target.removeEventListener("compositionend", this.#handleEnd);
403
- target.removeEventListener("keydown", this.#handleKeydown);
404
- this.#activeTargets.delete(target);
427
+ this.#release(target);
428
+ if (this.#composition?.target === target) this.#letGo();
405
429
  if (this.#confirmedTarget === target) this.#confirmedTarget = null;
406
430
  }
407
431
  disconnect() {
408
- for (const target of this.#observedTargets) {
409
- target.removeEventListener("compositionstart", this.#handleStart);
410
- target.removeEventListener("compositionend", this.#handleEnd);
411
- target.removeEventListener("keydown", this.#handleKeydown);
412
- }
432
+ this.#connected = false;
433
+ for (const target of this.#observedTargets) this.#release(target);
413
434
  this.#observedTargets.clear();
414
- this.#activeTargets.clear();
435
+ this.#letGo();
415
436
  this.#confirmedTarget = null;
437
+ this.#keyComposing = false;
438
+ this.#abandoned = null;
416
439
  }
417
440
  isComposing(event) {
418
- return this.#activeTargets.size > 0 || event?.isComposing === true;
441
+ this.#settle();
442
+ return event?.isComposing === true || this.#composition !== null;
443
+ }
444
+ composingElement() {
445
+ this.#settle();
446
+ return this.#composition?.element ?? null;
447
+ }
448
+ owns(event) {
449
+ const element = this.composingElement();
450
+ return event.isComposing === true || element !== null && element === event.target;
419
451
  }
420
452
  consumesConfirmedInput(event) {
421
453
  const confirmed = this.#confirmedTarget;
422
454
  this.#confirmedTarget = null;
423
455
  if (confirmed === null || confirmed !== event.target) return false;
424
456
  const inputType = event.inputType;
425
- return !inputType || COMPOSITION_INPUT_TYPES.has(inputType);
457
+ return !inputType || isCompositionInputType(inputType);
426
458
  }
459
+ #release(target) {
460
+ target.removeEventListener("compositionstart", this.#handleStart);
461
+ target.removeEventListener("compositionend", this.#handleEnd);
462
+ target.removeEventListener("keydown", this.#handleKeydown, true);
463
+ target.removeEventListener("beforeinput", this.#handleBeforeInput, true);
464
+ target.removeEventListener("input", this.#handleInput, true);
465
+ target.removeEventListener("blur", this.#handleBlur, true);
466
+ target.removeEventListener(BEFORE_MORPH_ATTRIBUTE, this.#handleBeforeMorphAttribute);
467
+ }
468
+ #letGo() {
469
+ const composition = this.#composition;
470
+ if (composition === null) return;
471
+ if (!holdsFocus(composition.element)) {
472
+ this.#composition = null;
473
+ return;
474
+ }
475
+ queueMicrotask(() => {
476
+ if (this.#composition !== composition || this.#observedTargets.has(composition.target)) {
477
+ return;
478
+ }
479
+ this.#composition = null;
480
+ if (!this.#connected) return;
481
+ this.#abandoned = { element: composition.element, inPlace: true };
482
+ this.#runAbandon();
483
+ });
484
+ }
485
+ #settle() {
486
+ const composition = this.#composition;
487
+ if (composition === null) return;
488
+ const { target, element, text } = composition;
489
+ if (target instanceof Node && element instanceof Node && !target.contains(element)) {
490
+ this.#composition = null;
491
+ } else if (textOf(element) !== text) {
492
+ this.#abandon(false);
493
+ }
494
+ }
495
+ #abandon(inPlace) {
496
+ this.#owe(inPlace);
497
+ this.#composition = null;
498
+ queueMicrotask(this.#runAbandon);
499
+ }
500
+ #owe(inPlace) {
501
+ const composition = this.#composition;
502
+ if (composition !== null) this.#abandoned = { element: composition.element, inPlace };
503
+ }
504
+ #runAbandon = () => {
505
+ const abandoned = this.#abandoned;
506
+ if (abandoned === null) return;
507
+ this.#abandoned = null;
508
+ this.#onAbandon?.(abandoned.element, abandoned.inPlace);
509
+ };
427
510
  #handleStart = (event) => {
428
511
  this.#confirmedTarget = null;
429
- if (event.currentTarget) this.#activeTargets.add(event.currentTarget);
512
+ this.#settle();
513
+ this.#owe(true);
514
+ const target = event.currentTarget;
515
+ const element = event.target;
516
+ this.#composition = { target, element, text: textOf(element) };
517
+ this.#runAbandon();
430
518
  this.#onStart?.(event);
431
519
  };
432
520
  #handleEnd = (event) => {
433
- if (event.currentTarget) this.#activeTargets.delete(event.currentTarget);
521
+ this.#runAbandon();
522
+ if (this.#composition?.target === event.currentTarget) this.#composition = null;
434
523
  this.#confirmedTarget = event.target;
435
524
  this.#onEnd?.(event);
436
525
  };
437
- #handleKeydown = () => {
526
+ #handleKeydown = (event) => {
527
+ this.#settle();
528
+ this.#runAbandon();
438
529
  this.#confirmedTarget = null;
530
+ this.#keyComposing = event.isComposing === true;
531
+ };
532
+ #handleBeforeInput = (event) => {
533
+ const keyComposing = this.#keyComposing;
534
+ this.#keyComposing = false;
535
+ this.#settle();
536
+ const { isComposing, inputType } = event;
537
+ if (this.#composition !== null && !keyComposing && !isComposing && inputType && !isCompositionInputType(inputType)) {
538
+ this.#abandon(true);
539
+ }
540
+ this.#runAbandon();
541
+ };
542
+ #handleInput = (event) => {
543
+ const composition = this.#composition;
544
+ const { isTrusted, isComposing, inputType } = event;
545
+ if (composition !== null && event.target === composition.element && (isTrusted || isComposing || isCompositionInputType(inputType))) {
546
+ composition.text = textOf(composition.element);
547
+ } else {
548
+ this.#settle();
549
+ }
550
+ this.#runAbandon();
551
+ };
552
+ #handleBlur = (event) => {
553
+ this.#settle();
554
+ this.#runAbandon();
555
+ const composition = this.#composition;
556
+ if (composition === null || composition.target === composition.element) return;
557
+ const { element } = composition;
558
+ if (!(element instanceof Node) || event.target !== element) return;
559
+ const root = element.getRootNode();
560
+ if (root.activeElement !== element) this.#composition = null;
561
+ };
562
+ #handleBeforeMorphAttribute = (event) => {
563
+ this.#settle();
564
+ const composition = this.#composition;
565
+ if (composition?.target !== event.currentTarget || event.target !== composition.element) return;
566
+ const detail = event.detail;
567
+ if (detail?.attributeName === "value") event.preventDefault();
439
568
  };
440
569
  };
441
570
 
@@ -488,6 +617,9 @@ var MicrotaskCoalescer = class {
488
617
  this.#queued = false;
489
618
  this.#generation += 1;
490
619
  }
620
+ get pending() {
621
+ return this.#queued;
622
+ }
491
623
  schedule() {
492
624
  if (!this.#active || this.#queued) return;
493
625
  this.#queued = true;
@@ -518,6 +650,9 @@ var MorphRenderWatcher = class {
518
650
  schedule() {
519
651
  this.#pass.schedule();
520
652
  }
653
+ get pending() {
654
+ return this.#pass.pending;
655
+ }
521
656
  disconnect() {
522
657
  this.#listeners.dispose();
523
658
  this.#pass.cancel();
@@ -635,9 +770,8 @@ var StateRegions = class _StateRegions {
635
770
  const below = hold.linked ? stack[index - 1] : void 0;
636
771
  if (below) {
637
772
  if (region.hidden !== below.written) region.hidden = below.written;
638
- } else if (region.getAttribute("hidden") !== hold.authored) {
639
- if (hold.authored === null) region.removeAttribute("hidden");
640
- else region.setAttribute("hidden", hold.authored);
773
+ } else {
774
+ setAttributeIfChanged(region, "hidden", hold.authored);
641
775
  }
642
776
  }
643
777
  this.#mark(region, stack);
@@ -712,9 +846,7 @@ var StateRegions = class _StateRegions {
712
846
  );
713
847
  });
714
848
  for (const [name, recorded] of records) {
715
- if (region.getAttribute(name) === recorded) continue;
716
- if (recorded === null) region.removeAttribute(name);
717
- else region.setAttribute(name, recorded);
849
+ setAttributeIfChanged(region, name, recorded);
718
850
  }
719
851
  }
720
852
  #recorded(region, name) {
@@ -735,6 +867,11 @@ var StateRegions = class _StateRegions {
735
867
  return regions.filter((region) => host.contains(region));
736
868
  }
737
869
  };
870
+ function deepActiveElement(ownerDocument) {
871
+ let active = ownerDocument.activeElement;
872
+ while (active?.shadowRoot?.activeElement) active = active.shadowRoot.activeElement;
873
+ return active;
874
+ }
738
875
 
739
876
  function queryOpenDescendants(root, selector) {
740
877
  const matches = [];
@@ -752,6 +889,9 @@ function queryOpenDescendants(root, selector) {
752
889
  return matches;
753
890
  }
754
891
 
892
+ function holdsFocus2(element) {
893
+ return element.matches(":focus") || deepActiveElement(element.ownerDocument) === element;
894
+ }
755
895
  var TabindexLoan = class _TabindexLoan {
756
896
  static #registry = sharedRegistry(
757
897
  "stimeo-ui.tabindex-loan.registry.v1",
@@ -759,19 +899,22 @@ var TabindexLoan = class _TabindexLoan {
759
899
  );
760
900
  #value;
761
901
  #record;
902
+ #preserveFocus;
762
903
  #lent = /* @__PURE__ */ new Set();
763
- constructor(value, owner) {
904
+ constructor(value, owner, options = {}) {
764
905
  this.#value = value;
765
906
  this.#record = `data-${owner}-tabindex-loan`;
907
+ this.#preserveFocus = options.preserveFocus === true;
766
908
  _TabindexLoan.#registry.names.add(this.#record);
767
909
  }
768
- lend(element) {
910
+ lend(element, options = {}) {
769
911
  const stack = this.#stack(element);
770
912
  const current = element.getAttribute("tabindex");
771
913
  const held = stack.find((hold) => hold.loan === this) ?? stack.find(
772
914
  (hold) => hold.loan === null && hold.record === this.#record && hold.value === this.#value
773
915
  );
774
916
  const linked = stack.at(-1)?.value === current;
917
+ if (!held && options.onlyIfUnfocusable && (current !== null || element.tabIndex >= 0)) return;
775
918
  if (!held && current !== null && !linked) return;
776
919
  this.#lent.add(element);
777
920
  if (held) held.loan = this;
@@ -781,19 +924,28 @@ var TabindexLoan = class _TabindexLoan {
781
924
  element.setAttribute("tabindex", this.#value);
782
925
  }
783
926
  }
784
- returnAll() {
785
- for (const element of this.#lent) {
786
- const stack = this.#stack(element);
787
- const hold = stack.find((held) => held.loan === this);
788
- if (hold) this.#release(element, stack, hold);
927
+ return(element) {
928
+ const stack = this.#stack(element);
929
+ const hold = stack.find((held) => held.loan === this) ?? stack.find(
930
+ (held) => held.loan === null && held.record === this.#record && held.value === this.#value
931
+ );
932
+ if (!hold) return false;
933
+ if (!this.#release(element, stack, hold, this.#preserveFocus)) {
934
+ hold.loan = this;
935
+ this.#lent.add(element);
936
+ return false;
789
937
  }
790
- this.#lent.clear();
938
+ this.#lent.delete(element);
939
+ return true;
940
+ }
941
+ returnAll() {
942
+ for (const element of Array.from(this.#lent)) this.return(element);
791
943
  }
792
944
  reclaim(element) {
793
945
  if (element.getAttribute(this.#record) !== this.#value) return;
794
946
  const stack = this.#stack(element);
795
947
  const hold = stack.find((held) => held.loan === null && held.record === this.#record);
796
- if (hold && !element.matches(":focus")) this.#release(element, stack, hold);
948
+ if (hold && !holdsFocus2(element)) this.#release(element, stack, hold);
797
949
  }
798
950
  reclaimWithin(root) {
799
951
  for (const element of queryOpenDescendants(root, `[${this.#record}]`)) {
@@ -817,26 +969,26 @@ var TabindexLoan = class _TabindexLoan {
817
969
  for (const [index, hold] of holds.entries()) hold.linked = index > 0;
818
970
  return holds;
819
971
  }
820
- #release(element, stack, hold) {
972
+ #release(element, stack, hold, preserveFocus = false) {
821
973
  const current = element.getAttribute("tabindex");
822
974
  const index = stack.indexOf(hold);
823
975
  const owns = current === hold.value && !stack.slice(index + 1).some((above2) => above2.value === current);
976
+ if (owns && preserveFocus && holdsFocus2(element)) return false;
824
977
  stack.splice(index, 1);
825
978
  const above = stack[index];
826
979
  if (above) above.linked &&= hold.linked;
827
980
  this.#mark(element, stack);
828
- if (!owns) return;
981
+ if (!owns) return true;
829
982
  const below = hold.linked ? stack[index - 1] : void 0;
830
983
  if (!below) element.removeAttribute("tabindex");
831
984
  else if (below.value !== current) element.setAttribute("tabindex", below.value);
985
+ return true;
832
986
  }
833
987
  #mark(element, stack) {
834
988
  const records = /* @__PURE__ */ new Map([[this.#record, null]]);
835
989
  for (const hold of stack) records.set(hold.record, hold.value);
836
990
  for (const [name, recorded] of records) {
837
- if (element.getAttribute(name) === recorded) continue;
838
- if (recorded === null) element.removeAttribute(name);
839
- else element.setAttribute(name, recorded);
991
+ setAttributeIfChanged(element, name, recorded);
840
992
  }
841
993
  }
842
994
  };
@@ -959,13 +1111,16 @@ var MultiSelectController = class _MultiSelectController extends Controller {
959
1111
  noun: "chip template"
960
1112
  });
961
1113
  #chipRow = new ChipRow({
962
- directionElement: this.element,
1114
+ getDirectionElement: () => this.#chipDirectionElement,
963
1115
  getItems: () => this.tagTargets,
964
1116
  getButton: (tag) => matchingPart(tag, `button${this.#rows.selector("remove")}`),
965
1117
  onRemove: (index) => this.#removeTagAt(index),
966
1118
  focusAfterEnd: () => this.#focusInput()
967
1119
  });
1120
+ #listeners = new ListenerSet();
1121
+ #tab = null;
968
1122
  connect() {
1123
+ this.#tab = null;
969
1124
  this.#tabindex.reclaim(this.element);
970
1125
  this.#rows.connect();
971
1126
  this.#normalizeSelection([]);
@@ -976,7 +1131,10 @@ var MultiSelectController = class _MultiSelectController extends Controller {
976
1131
  }
977
1132
  this.#selectionValues = this.#values;
978
1133
  this.#syncFields();
979
- document.addEventListener("click", this.#onOutsideClick, true);
1134
+ this.#listeners.add(document, "click", this.#onOutsideClick, { capture: true });
1135
+ this.#listeners.add(this.element, "keydown", this.#onTab);
1136
+ for (const type of ["focus", "keydown", "keyup", "pointerdown"])
1137
+ this.#listeners.add(document, type, this.#trackTab, { capture: true });
980
1138
  this.#connected = true;
981
1139
  this.#reconcile.observe(this.element);
982
1140
  }
@@ -997,7 +1155,8 @@ var MultiSelectController = class _MultiSelectController extends Controller {
997
1155
  this.#reconcile.disconnect();
998
1156
  this.#composition.disconnect();
999
1157
  this.#chipRow.disconnect();
1000
- document.removeEventListener("click", this.#onOutsideClick, true);
1158
+ this.#listeners.dispose();
1159
+ this.#tab = null;
1001
1160
  this.#releaseTabindex();
1002
1161
  }
1003
1162
  optionTargetConnected() {
@@ -1167,7 +1326,11 @@ var MultiSelectController = class _MultiSelectController extends Controller {
1167
1326
  this.#setActive(visible[0] ?? null);
1168
1327
  this.dispatch("filter", { detail: { query } });
1169
1328
  }
1170
- open() {
1329
+ open(event) {
1330
+ if (event instanceof FocusEvent && event === this.#tab) {
1331
+ this.#tab = null;
1332
+ return;
1333
+ }
1171
1334
  if (!this.hasListTarget || !this.hasInputTarget) {
1172
1335
  this.#reflectEmpty();
1173
1336
  return;
@@ -1192,10 +1355,11 @@ var MultiSelectController = class _MultiSelectController extends Controller {
1192
1355
  onKeydown(event) {
1193
1356
  if (event.defaultPrevented) return;
1194
1357
  if (isReservedArrowChord(event)) return;
1358
+ if ((event.key === "Home" || event.key === "End") && hasModifierChord(event)) return;
1195
1359
  if (!this.hasInputTarget) return;
1196
1360
  if (this.#composition.isComposing(event)) return;
1197
1361
  this.#reconcileActiveForInteraction();
1198
- switch (logicalArrowKey(event.key, this.element)) {
1362
+ switch (logicalArrowKey(event.key, this.#chipDirectionElement)) {
1199
1363
  case "ArrowDown":
1200
1364
  event.preventDefault();
1201
1365
  if (this.#isClosed) this.open();
@@ -1253,6 +1417,16 @@ var MultiSelectController = class _MultiSelectController extends Controller {
1253
1417
  break;
1254
1418
  }
1255
1419
  }
1420
+ #onTab = (event) => {
1421
+ if (event.key !== "Tab" || event.defaultPrevented || event.isComposing || !this.hasTagsTarget || !this.tagsTarget.contains(event.target))
1422
+ return;
1423
+ this.#tab = event;
1424
+ this.close();
1425
+ };
1426
+ #trackTab = (event) => {
1427
+ const key = this.#tab;
1428
+ this.#tab = event.type === "focus" && key instanceof KeyboardEvent && !key.defaultPrevented && event.target === this.inputTargets[0] ? event : null;
1429
+ };
1256
1430
  toggleOption(source) {
1257
1431
  const { event, host, origin, reason } = actionSource(source);
1258
1432
  if (origin && origin.closest(`[data-controller~="${this.identifier}"]`) !== this.element)
@@ -1264,6 +1438,9 @@ var MultiSelectController = class _MultiSelectController extends Controller {
1264
1438
  if (focus && (event !== null || this.element.contains(document.activeElement)))
1265
1439
  this.#focusInput();
1266
1440
  }
1441
+ get #chipDirectionElement() {
1442
+ return this.hasTagsTarget ? this.tagsTarget : this.element;
1443
+ }
1267
1444
  #focusInput() {
1268
1445
  if (this.hasInputTarget) this.inputTarget.focus();
1269
1446
  }
@@ -1322,7 +1499,7 @@ var MultiSelectController = class _MultiSelectController extends Controller {
1322
1499
  const name = this.#removeName(text, this.#optionValue(option));
1323
1500
  if (!label || !button || !name) continue;
1324
1501
  if (readLabel(label) !== text) writeLabel(label, text);
1325
- if (button.getAttribute("aria-label") !== name) button.setAttribute("aria-label", name);
1502
+ setAttributeIfChanged(button, "aria-label", name);
1326
1503
  }
1327
1504
  }
1328
1505
  #appendTag(option) {