stimeo-ui 0.16.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 (115) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +31 -0
  3. data/README.md +8 -1
  4. data/dist/cable/index.js +363 -436
  5. data/dist/controllers/accordion_controller.js +166 -55
  6. data/dist/controllers/alert_dialog_controller.js +862 -221
  7. data/dist/controllers/announcer_controller.js +135 -198
  8. data/dist/controllers/aspect_ratio_controller.js +0 -10
  9. data/dist/controllers/auto_submit_controller.js +271 -127
  10. data/dist/controllers/avatar_controller.js +171 -105
  11. data/dist/controllers/breadcrumb_controller.js +0 -130
  12. data/dist/controllers/bulk_select_controller.js +262 -52
  13. data/dist/controllers/calendar_controller.js +175 -209
  14. data/dist/controllers/carousel_controller.js +461 -399
  15. data/dist/controllers/character_counter_controller.js +246 -156
  16. data/dist/controllers/checkbox_controller.js +32 -74
  17. data/dist/controllers/clipboard_controller.js +168 -147
  18. data/dist/controllers/collapsible_controller.js +301 -120
  19. data/dist/controllers/color_picker_controller.js +149 -139
  20. data/dist/controllers/combobox_controller.js +360 -133
  21. data/dist/controllers/command_palette_controller.js +970 -358
  22. data/dist/controllers/conditional_fields_controller.js +166 -124
  23. data/dist/controllers/confirm_controller.js +939 -248
  24. data/dist/controllers/context_menu_controller.js +256 -128
  25. data/dist/controllers/count_up_controller.js +73 -21
  26. data/dist/controllers/countdown_controller.js +183 -148
  27. data/dist/controllers/currency_input_controller.js +134 -158
  28. data/dist/controllers/data_grid_controller.js +114 -186
  29. data/dist/controllers/date_range_picker_controller.js +288 -206
  30. data/dist/controllers/dialog_controller.js +858 -223
  31. data/dist/controllers/direct_upload_controller.js +73 -153
  32. data/dist/controllers/dirty_form_controller.js +14 -48
  33. data/dist/controllers/dismissible_controller.js +175 -21
  34. data/dist/controllers/drawer_controller.js +933 -341
  35. data/dist/controllers/dropdown_controller.js +312 -82
  36. data/dist/controllers/editable_controller.js +158 -68
  37. data/dist/controllers/empty_state_controller.js +67 -53
  38. data/dist/controllers/file_dropzone_controller.js +311 -207
  39. data/dist/controllers/filter_controller.js +67 -39
  40. data/dist/controllers/flash_controller.js +172 -314
  41. data/dist/controllers/focus_controller.js +654 -240
  42. data/dist/controllers/form_field_controller.js +147 -132
  43. data/dist/controllers/form_validation_controller.js +13 -86
  44. data/dist/controllers/frame_loading_controller.js +264 -213
  45. data/dist/controllers/highlight_controller.js +107 -75
  46. data/dist/controllers/hover_card_controller.js +309 -118
  47. data/dist/controllers/idle_controller.js +267 -101
  48. data/dist/controllers/input_mask_controller.js +71 -72
  49. data/dist/controllers/intersection_controller.js +147 -106
  50. data/dist/controllers/lazy_frame_controller.js +9 -65
  51. data/dist/controllers/listbox_controller.js +306 -204
  52. data/dist/controllers/local_time_controller.js +54 -64
  53. data/dist/controllers/masonry_controller.js +70 -93
  54. data/dist/controllers/menu_controller.js +214 -156
  55. data/dist/controllers/menubar_controller.js +170 -329
  56. data/dist/controllers/meter_controller.js +151 -67
  57. data/dist/controllers/multi_select_controller.js +593 -358
  58. data/dist/controllers/navigation_menu_controller.js +124 -232
  59. data/dist/controllers/nested_form_controller.js +352 -182
  60. data/dist/controllers/network_status_controller.js +242 -54
  61. data/dist/controllers/number_input_controller.js +320 -263
  62. data/dist/controllers/optimistic_controller.js +16 -76
  63. data/dist/controllers/otp_controller.js +198 -193
  64. data/dist/controllers/overflow_indicator_controller.js +116 -113
  65. data/dist/controllers/overflow_menu_controller.js +343 -283
  66. data/dist/controllers/pagination_controller.js +295 -119
  67. data/dist/controllers/password_reveal_controller.js +389 -121
  68. data/dist/controllers/password_strength_controller.js +99 -153
  69. data/dist/controllers/persist_controller.js +237 -103
  70. data/dist/controllers/pointer_drag_controller.js +185 -165
  71. data/dist/controllers/popover_controller.js +236 -97
  72. data/dist/controllers/portal_controller.js +209 -76
  73. data/dist/controllers/preview_guard_controller.js +232 -116
  74. data/dist/controllers/progress_controller.js +125 -56
  75. data/dist/controllers/radio_group_controller.js +117 -137
  76. data/dist/controllers/range_slider_controller.js +192 -105
  77. data/dist/controllers/rating_controller.js +418 -207
  78. data/dist/controllers/read_more_controller.js +134 -63
  79. data/dist/controllers/reading_progress_controller.js +147 -135
  80. data/dist/controllers/relative_time_controller.js +145 -110
  81. data/dist/controllers/{reset_before_cache_controller.js → reset_on_restore_controller.js} +97 -38
  82. data/dist/controllers/resizable_controller.js +255 -139
  83. data/dist/controllers/roving_controller.js +39 -84
  84. data/dist/controllers/scroll_area_controller.js +428 -225
  85. data/dist/controllers/scroll_restore_controller.js +0 -53
  86. data/dist/controllers/scroll_visibility_controller.js +395 -145
  87. data/dist/controllers/scrollspy_controller.js +181 -242
  88. data/dist/controllers/separator_controller.js +267 -140
  89. data/dist/controllers/sidebar_controller.js +1023 -386
  90. data/dist/controllers/skeleton_controller.js +248 -97
  91. data/dist/controllers/slider_controller.js +159 -79
  92. data/dist/controllers/smart_sticky_header_controller.js +162 -63
  93. data/dist/controllers/sortable_controller.js +0 -112
  94. data/dist/controllers/spinner_controller.js +277 -169
  95. data/dist/controllers/step_indicator_controller.js +99 -46
  96. data/dist/controllers/stepper_controller.js +114 -73
  97. data/dist/controllers/stick_to_bottom_controller.js +262 -138
  98. data/dist/controllers/sticky_observer_controller.js +214 -49
  99. data/dist/controllers/submit_once_controller.js +294 -205
  100. data/dist/controllers/switch_controller.js +33 -60
  101. data/dist/controllers/tabs_controller.js +35 -29
  102. data/dist/controllers/tags_input_controller.js +136 -145
  103. data/dist/controllers/textarea_autosize_controller.js +71 -58
  104. data/dist/controllers/theme_controller.js +130 -112
  105. data/dist/controllers/time_picker_controller.js +146 -80
  106. data/dist/controllers/toast_controller.js +186 -297
  107. data/dist/controllers/toggle_group_controller.js +95 -136
  108. data/dist/controllers/toolbar_controller.js +68 -98
  109. data/dist/controllers/tooltip_controller.js +158 -124
  110. data/dist/controllers/transition_controller.js +123 -119
  111. data/dist/controllers/tree_view_controller.js +150 -345
  112. data/dist/index.js +6370 -9346
  113. data/dist/positioning/index.js +148 -47
  114. data/lib/stimeo/ui/version.rb +1 -1
  115. metadata +3 -3
@@ -1,13 +1,31 @@
1
1
  import { Controller } from '@hotwired/stimulus';
2
2
 
3
- // src/controllers/toggle_group_controller.ts
3
+ var FOCUS_EVENTS = /* @__PURE__ */ new Set(["blur", "focus", "focusin", "focusout"]);
4
+ var POINTER_EVENTS = /* @__PURE__ */ new Set(["mouseenter", "mouseleave", "pointerenter", "pointerleave"]);
5
+ function stateReasonFor(event) {
6
+ if (!event) return "api";
7
+ if (FOCUS_EVENTS.has(event.type)) return "focus";
8
+ if (POINTER_EVENTS.has(event.type)) return "pointer";
9
+ return "user";
10
+ }
11
+
12
+ function actionSource(source) {
13
+ if (source instanceof HTMLElement) {
14
+ return { event: null, host: source, origin: source, reason: "api" };
15
+ }
16
+ const event = source ?? null;
17
+ return {
18
+ event,
19
+ host: event?.currentTarget instanceof Element ? event.currentTarget : null,
20
+ origin: event?.target instanceof Element ? event.target : null,
21
+ reason: stateReasonFor(event)
22
+ };
23
+ }
4
24
 
5
- // src/utils/logical_scroll.ts
6
25
  function isRtl(element) {
7
26
  return window.getComputedStyle(element).direction === "rtl";
8
27
  }
9
28
 
10
- // src/utils/arrow_step.ts
11
29
  function logicalArrowStep(key, element) {
12
30
  if (key === "ArrowDown") return 1;
13
31
  if (key === "ArrowUp") return -1;
@@ -20,7 +38,6 @@ function isReservedArrowChord(event, allow = []) {
20
38
  return event.altKey && !allow.includes("alt") || event.ctrlKey && !allow.includes("ctrl") || event.metaKey && !allow.includes("meta") || event.shiftKey && !allow.includes("shift");
21
39
  }
22
40
 
23
- // src/utils/event_owner.ts
24
41
  function ownerIndex(candidates, node) {
25
42
  if (!(node instanceof Node)) return -1;
26
43
  return candidates.findIndex((candidate) => candidate.contains(node));
@@ -29,7 +46,6 @@ function ownerOf(candidates, node) {
29
46
  return candidates[ownerIndex(candidates, node)] ?? null;
30
47
  }
31
48
 
32
- // src/utils/field_mirror.ts
33
49
  function writeFields(container, values, { name, form = "" }) {
34
50
  const current = [...container.children];
35
51
  const submits = current.length === values.length && current.every(
@@ -52,7 +68,6 @@ function commitField(target) {
52
68
  target.dispatchEvent(new Event("change", { bubbles: true }));
53
69
  }
54
70
 
55
- // src/utils/focus_candidate.ts
56
71
  function inheritsFieldsetDisabled(control) {
57
72
  let fieldset = control.closest("fieldset[disabled]");
58
73
  while (fieldset) {
@@ -63,7 +78,6 @@ function inheritsFieldsetDisabled(control) {
63
78
  return false;
64
79
  }
65
80
 
66
- // src/utils/interactive_host.ts
67
81
  var INTERACTIVE_HOST_SELECTOR = "button, input, select, textarea, label, a[href], area[href], summary, details, audio[controls], video[controls], iframe, object, embed";
68
82
  function isInteractiveHost(element) {
69
83
  if (element.matches(INTERACTIVE_HOST_SELECTOR)) return true;
@@ -80,27 +94,33 @@ function isInteractiveHost(element) {
80
94
  return false;
81
95
  }
82
96
 
83
- // src/utils/microtask_coalescer.ts
97
+ var ListenerSet = class {
98
+ #abort = new AbortController();
99
+ add(target, type, handler, options) {
100
+ target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
101
+ }
102
+ dispose() {
103
+ this.#abort.abort();
104
+ this.#abort = new AbortController();
105
+ }
106
+ };
107
+
84
108
  var MicrotaskCoalescer = class {
85
109
  #run;
86
110
  #queued = false;
87
111
  #active = false;
88
112
  #generation = 0;
89
- /** @param run - the single reconciliation pass, invoked at most once per batch. */
90
113
  constructor(run) {
91
114
  this.#run = run;
92
115
  }
93
- /** Opens the window in which {@link schedule} is honoured; call from `connect()`. */
94
116
  activate() {
95
117
  this.#active = true;
96
118
  }
97
- /** Closes the window and drops any pending pass; call from `disconnect()`. */
98
119
  cancel() {
99
120
  this.#active = false;
100
121
  this.#queued = false;
101
122
  this.#generation += 1;
102
123
  }
103
- /** Requests one pass after the batch settles. Idempotent; inert outside the window. */
104
124
  schedule() {
105
125
  if (!this.#active || this.#queued) return;
106
126
  this.#queued = true;
@@ -113,31 +133,50 @@ var MicrotaskCoalescer = class {
113
133
  }
114
134
  };
115
135
 
116
- // src/utils/roving_tabindex.ts
136
+ var MorphRenderWatcher = class {
137
+ #listeners = new ListenerSet();
138
+ #pass;
139
+ #element = null;
140
+ #onMorph = () => this.#pass.schedule();
141
+ constructor(run) {
142
+ this.#pass = new MicrotaskCoalescer(run);
143
+ }
144
+ observe(element) {
145
+ if (this.#element === element) return;
146
+ this.disconnect();
147
+ this.#element = element;
148
+ this.#pass.activate();
149
+ this.#listeners.add(element, "turbo:morph-element", this.#onMorph);
150
+ }
151
+ schedule() {
152
+ this.#pass.schedule();
153
+ }
154
+ disconnect() {
155
+ this.#listeners.dispose();
156
+ this.#pass.cancel();
157
+ this.#element = null;
158
+ }
159
+ };
160
+
161
+ var MoveCounter = class {
162
+ #sequence = 0;
163
+ record() {
164
+ this.#sequence += 1;
165
+ return this.#sequence;
166
+ }
167
+ isLatest(token) {
168
+ return token === this.#sequence;
169
+ }
170
+ };
171
+
117
172
  var RovingTabindex = class {
118
- /** Returns the current ordered item elements; called on every operation. */
119
173
  #getItems;
120
- /**
121
- * @param getItems - Returns the current ordered item elements. Called on every
122
- * operation so the live target list is always used.
123
- */
124
174
  constructor(getItems) {
125
175
  this.#getItems = getItems;
126
176
  }
127
- /** Index of the currently tabbable item (`tabindex="0"`), or `-1` if none. */
128
177
  get activeIndex() {
129
178
  return this.#getItems().findIndex((item) => item.tabIndex === 0);
130
179
  }
131
- /**
132
- * Makes exactly the item at `index` tabbable (`tabindex="0"`) and removes every
133
- * other item from the Tab sequence (`tabindex="-1"`). An out-of-range `index`
134
- * (e.g. `-1`) leaves all items at `-1`, which a controller can use to express
135
- * "nothing is currently tabbable".
136
- *
137
- * @param index - Position of the item to make tabbable.
138
- * @param options - Pass `{ focus: true }` to also move DOM focus to that item,
139
- * and `items` to reuse an event-scoped collection snapshot.
140
- */
141
180
  setActive(index, options = {}) {
142
181
  const { focus = false } = options;
143
182
  const items = options.items ?? this.#getItems();
@@ -153,7 +192,10 @@ function rovingMove(current, length, delta, wrap) {
153
192
  return (next + length) % length;
154
193
  }
155
194
 
156
- // src/controllers/toggle_group_controller.ts
195
+ function targetSelector(identifier, name) {
196
+ return `[data-${identifier}-target~="${name}"]`;
197
+ }
198
+
157
199
  var ITEM_ATTRIBUTES = [
158
200
  "aria-pressed",
159
201
  "data-value",
@@ -166,6 +208,7 @@ var ITEM_ATTRIBUTES = [
166
208
  ];
167
209
  var hasModifier = (event) => event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
168
210
  var ToggleGroupController = class extends Controller {
211
+ #moves = new MoveCounter();
169
212
  static targets = ["item", "fields"];
170
213
  static values = {
171
214
  mode: { type: String, default: "multiple" },
@@ -177,27 +220,13 @@ var ToggleGroupController = class extends Controller {
177
220
  #roving = new RovingTabindex(() => this.#managedTargets);
178
221
  #handledEvents = /* @__PURE__ */ new WeakSet();
179
222
  #managedItems = /* @__PURE__ */ new Set();
180
- #originalTabindex = /* @__PURE__ */ new Map();
223
+ #originalTabindex = /* @__PURE__ */ new WeakMap();
181
224
  #ownedPressed = /* @__PURE__ */ new Set();
182
225
  #internalPressedValues = /* @__PURE__ */ new Map();
183
- /** One pass per batch of item, Value, and retained-element changes. */
184
- #pass = new MicrotaskCoalescer(() => this.#reconcileDom());
226
+ #pass = new MorphRenderWatcher(() => this.#reconcileDom());
185
227
  #observer = null;
186
228
  #connected = false;
187
- /** The pressed set last published: read on connect, then committed or reported. */
188
229
  #committedValues = [];
189
- /**
190
- * How many presses the user has committed, so a press whose reports are still
191
- * going out can tell that a listener has committed a newer one meanwhile.
192
- */
193
- #presses = 0;
194
- /**
195
- * Normalizes state and establishes one roving entry point. A single authored
196
- * `tabindex="0"` survives reconnect; otherwise the first pressed, navigable
197
- * item wins, falling back to the first navigable item. The pressed set it
198
- * settles on is the one a later move is measured from; connecting reports
199
- * nothing.
200
- */
201
230
  connect() {
202
231
  const currentItems = new Set(this.itemTargets);
203
232
  for (const item of this.#managedItems) {
@@ -219,16 +248,12 @@ var ToggleGroupController = class extends Controller {
219
248
  this.element.addEventListener("focusin", this.#onFocusin);
220
249
  this.#connected = true;
221
250
  this.#internalPressedValues.clear();
222
- this.#pass.activate();
251
+ this.#pass.observe(this.element);
223
252
  this.#observeMutations();
224
253
  }
225
- /**
226
- * Releases every listener, the observer, and a pass still queued, while
227
- * retaining DOM state for Turbo cache/reconnect.
228
- */
229
254
  disconnect() {
230
255
  this.#connected = false;
231
- this.#pass.cancel();
256
+ this.#pass.disconnect();
232
257
  this.element.removeEventListener("click", this.#onClickCapture, true);
233
258
  this.element.removeEventListener("keydown", this.#onKeydownCapture, true);
234
259
  this.element.removeEventListener("click", this.#onClick);
@@ -236,60 +261,47 @@ var ToggleGroupController = class extends Controller {
236
261
  this.element.removeEventListener("focusin", this.#onFocusin);
237
262
  this.#observer?.disconnect();
238
263
  this.#observer = null;
239
- this.#internalPressedValues.clear();
240
264
  }
241
- /** Drops a newly connected item from the Tab sequence before the batch is reconciled. */
242
265
  itemTargetConnected(item) {
243
266
  if (!this.#connected) return;
244
267
  this.#reconcileHost(item, true);
245
268
  this.#pass.schedule();
246
269
  }
247
- /** Restores attributes owned only while an element is an item, then reconciles the batch. */
248
270
  itemTargetDisconnected(item) {
249
271
  if (!this.#connected) return;
250
272
  this.#releaseItem(item);
251
273
  this.#pass.schedule();
252
274
  }
253
- /** Reconciles the single-selection invariant when the Stimulus Value changes. */
254
275
  modeValueChanged() {
255
276
  this.#pass.schedule();
256
277
  }
257
- /** Rebuilds the submitted fields when the public name changes at runtime. */
258
278
  nameValueChanged() {
259
279
  this.#pass.schedule();
260
280
  }
261
- /** Repoints the submitted fields when the owning form changes at runtime. */
262
281
  formValueChanged() {
263
282
  this.#pass.schedule();
264
283
  }
265
- /**
266
- * Toggles the action's item. Per-item action wiring is optional because click
267
- * is also delegated from the group.
268
- */
269
- toggle(event) {
270
- if (event.defaultPrevented) return;
271
- const item = event.currentTarget;
284
+ toggle(source) {
285
+ const { event, host, origin, reason } = actionSource(source);
286
+ const item = host?.closest(targetSelector(this.identifier, "item"));
272
287
  if (!item || !this.itemTargets.includes(item)) return;
273
- this.#handledEvents.add(event);
274
- this.#toggleItem(item);
288
+ if (origin && origin.closest(`[data-controller~="${this.identifier}"]`) !== this.element)
289
+ return;
290
+ if (event?.defaultPrevented) return;
291
+ if (event) this.#handledEvents.add(event);
292
+ this.#toggleItem(item, reason);
275
293
  }
276
- /**
277
- * Moves focus or activates the action's item. Per-item action wiring is
278
- * optional because keydown is also delegated from the group.
279
- */
280
294
  onKeydown(event) {
281
295
  const item = event.currentTarget;
282
296
  if (!item || !this.itemTargets.includes(item)) return;
283
297
  this.#handleKeydown(event, item);
284
298
  }
285
- /** Blocks disabled activation before per-item or consumer event handlers run. */
286
299
  #onClickCapture = (event) => {
287
300
  const item = this.#itemForEventTarget(event.target);
288
301
  if (!item || !this.#isSupportedHost(item) || !this.#isActivationDisabled(item)) return;
289
302
  event.preventDefault();
290
303
  event.stopImmediatePropagation();
291
304
  };
292
- /** Blocks disabled keyboard activation while leaving navigation keys available. */
293
305
  #onKeydownCapture = (event) => {
294
306
  if (event.key !== " " && event.key !== "Enter") return;
295
307
  const item = this.#itemForEventTarget(event.target);
@@ -297,24 +309,20 @@ var ToggleGroupController = class extends Controller {
297
309
  event.preventDefault();
298
310
  event.stopImmediatePropagation();
299
311
  };
300
- /** Delegated click path for static and runtime-added items without actions. */
301
312
  #onClick = (event) => {
302
313
  if (this.#handledEvents.delete(event) || event.defaultPrevented) return;
303
314
  const item = this.#itemForEventTarget(event.target);
304
315
  if (item) this.#toggleItem(item);
305
316
  };
306
- /** Delegated keydown path for static and runtime-added items without actions. */
307
317
  #onKeydown = (event) => {
308
318
  const item = this.#itemForEventTarget(event.target);
309
319
  if (item) this.#handleKeydown(event, item);
310
320
  };
311
- /** Keeps programmatic and pointer focus as the group's next Tab entry point. */
312
321
  #onFocusin = (event) => {
313
322
  const item = this.#itemForEventTarget(event.target);
314
323
  if (!item || !this.#isNavigable(item)) return;
315
324
  this.#setActive(item);
316
325
  };
317
- /** Applies the APG navigation and activation key map to one supported item. */
318
326
  #handleKeydown(event, item) {
319
327
  if (event.defaultPrevented || !this.#isSupportedHost(item)) return;
320
328
  if (event.isComposing) return;
@@ -353,18 +361,7 @@ var ToggleGroupController = class extends Controller {
353
361
  event.preventDefault();
354
362
  if (destination) this.#setActive(destination, true);
355
363
  }
356
- /**
357
- * Applies one user toggle and dispatches the documented change detail. The set
358
- * it leaves is taken as published before either report goes out, so a
359
- * listener that presses again or writes `aria-pressed` is measured from it. A
360
- * listener of the native `change` that presses again has had that newer press
361
- * reported, so this press's `change` would describe a set that is gone and is
362
- * not dispatched.
363
- *
364
- * @stimeoRuntimeOnly `mode` is the rule this one press follows; the lasting single-press
365
- * normalisation is a render root of its own.
366
- */
367
- #toggleItem(item) {
364
+ #toggleItem(item, reason = "user") {
368
365
  if (!this.#isSupportedHost(item) || this.#isActivationDisabled(item)) return;
369
366
  if (!this.#managedItems.has(item)) this.#reconcileHost(item, true);
370
367
  const willPress = !this.#isPressed(item);
@@ -376,20 +373,20 @@ var ToggleGroupController = class extends Controller {
376
373
  }
377
374
  this.#setActive(item);
378
375
  const values = this.#pressedValues();
376
+ const previous = this.#committedValues;
377
+ const changed = values.length !== previous.length || values.some((value, index) => value !== previous[index]);
379
378
  this.#committedValues = values;
380
- this.#presses += 1;
381
- const press = this.#presses;
379
+ if (!changed) {
380
+ this.#mirrorFields(false);
381
+ return;
382
+ }
383
+ const token = this.#moves.record();
382
384
  this.#mirrorFields(true);
383
- if (press !== this.#presses) return;
385
+ if (!this.#moves.isLatest(token)) return;
384
386
  this.dispatch("change", {
385
- detail: { value: this.#itemValue(item), pressed: willPress, values: [...values] }
387
+ detail: { value: this.#itemValue(item), pressed: willPress, values: [...values], reason }
386
388
  });
387
389
  }
388
- /**
389
- * Mirrors the pressed values into the optional fields container.
390
- *
391
- * @stimeoRenderRoot
392
- */
393
390
  #mirrorFields(notify) {
394
391
  if (!this.hasFieldsTarget) return;
395
392
  const options = { name: this.nameValue, form: this.formValue };
@@ -397,13 +394,6 @@ var ToggleGroupController = class extends Controller {
397
394
  commitField(this.fieldsTarget);
398
395
  }
399
396
  }
400
- /**
401
- * Reconciles supported hosts, pressed state, the roving invariant, and the
402
- * fields after the page changed the group, then reports a pressed set that
403
- * moved. Records still queued are read first, so an author's write is not lost
404
- * when observation is suspended for this pass's own writes; observation resumes
405
- * before the report, so an edit a listener makes is seen by the next pass.
406
- */
407
397
  #reconcileDom() {
408
398
  const observer = this.#observer;
409
399
  if (observer) {
@@ -418,7 +408,6 @@ var ToggleGroupController = class extends Controller {
418
408
  if (observer) this.#observeWith(observer);
419
409
  this.#reportMove();
420
410
  }
421
- /** Reports a pressed set that moved since the one this group last published. */
422
411
  #reportMove() {
423
412
  const values = this.#pressedValues();
424
413
  const previous = this.#committedValues;
@@ -428,7 +417,6 @@ var ToggleGroupController = class extends Controller {
428
417
  this.#committedValues = values;
429
418
  this.dispatch("reconcile", { detail: { values: [...values] } });
430
419
  }
431
- /** Begins or ends ownership according to the item's current host semantics. */
432
420
  #reconcileHost(item, dropFromTabSequence) {
433
421
  if (!this.#isSupportedHost(item)) {
434
422
  this.#releaseItem(item);
@@ -441,17 +429,13 @@ var ToggleGroupController = class extends Controller {
441
429
  }
442
430
  this.#normalizePressed(item);
443
431
  }
444
- /** Restores only defaults owned because an element belonged to this group. */
445
432
  #releaseItem(item) {
446
433
  if (!this.#managedItems.delete(item)) return;
447
434
  const original = this.#originalTabindex.get(item);
448
435
  if (original === null) item.removeAttribute("tabindex");
449
436
  else if (original !== void 0) item.setAttribute("tabindex", original);
450
- this.#originalTabindex.delete(item);
451
437
  if (this.#ownedPressed.delete(item)) item.removeAttribute("aria-pressed");
452
- this.#internalPressedValues.delete(item);
453
438
  }
454
- /** Supplies a missing pressed state and normalizes invalid ARIA tokens. */
455
439
  #normalizePressed(item) {
456
440
  const value = item.getAttribute("aria-pressed");
457
441
  if (value === null) {
@@ -462,13 +446,7 @@ var ToggleGroupController = class extends Controller {
462
446
  item.setAttribute("aria-pressed", "false");
463
447
  }
464
448
  }
465
- /**
466
- * Makes the first DOM-ordered pressed item the sole pressed item in single mode.
467
- *
468
- * @stimeoRenderRoot
469
- */
470
449
  #normalizeSelection() {
471
- for (const item of this.#managedTargets) this.#normalizePressed(item);
472
450
  if (this.modeValue !== "single") return;
473
451
  let found = false;
474
452
  for (const item of this.#managedTargets) {
@@ -477,7 +455,6 @@ var ToggleGroupController = class extends Controller {
477
455
  else this.#setPressed(item, false);
478
456
  }
479
457
  }
480
- /** Keeps one navigable Tab stop, preferring current DOM state after initial connect. */
481
458
  #ensureTabStop(initialPreference) {
482
459
  const navigable = this.#navigableItems;
483
460
  let active;
@@ -493,7 +470,6 @@ var ToggleGroupController = class extends Controller {
493
470
  active ??= navigable[0];
494
471
  this.#setActive(active ?? null);
495
472
  }
496
- /** Moves through the full item order until a navigable destination is found. */
497
473
  #nextNavigable(fromIndex, delta) {
498
474
  const items = this.#managedTargets;
499
475
  let index = fromIndex;
@@ -504,31 +480,25 @@ var ToggleGroupController = class extends Controller {
504
480
  }
505
481
  return void 0;
506
482
  }
507
- /** Assigns the single roving Tab stop and optionally moves DOM focus. */
508
483
  #setActive(item, focus = false) {
509
484
  this.#roving.setActive(this.#managedTargets.indexOf(item), { focus });
510
485
  }
511
- /** Finds this group's item containing an event target, excluding nested groups. */
512
486
  #itemForEventTarget(target) {
513
487
  if (!this.#ownsEventTarget(target)) return null;
514
488
  return ownerOf(this.itemTargets, target);
515
489
  }
516
- /** Whether the closest Toggle Group scope around a target is this instance. */
517
490
  #ownsEventTarget(target) {
518
491
  return target instanceof Element && target.closest(`[data-controller~="${this.identifier}"]`) === this.element;
519
492
  }
520
- /** Hosts whose activation model can be owned without conflicting native behavior. */
521
493
  #isSupportedHost(item) {
522
494
  if (item instanceof HTMLButtonElement) return item.type === "button";
523
495
  return !isInteractiveHost(item);
524
496
  }
525
- /** Items eligible for roving focus (ARIA-disabled deliberately remains eligible). */
526
497
  #isNavigable(item) {
527
498
  if (!this.#isSupportedHost(item) || this.#isHidden(item)) return false;
528
499
  if (!(item instanceof HTMLButtonElement)) return true;
529
500
  return !item.disabled && !inheritsFieldsetDisabled(item);
530
501
  }
531
- /** Whether hidden applies on the path from an item up to the group root. */
532
502
  #isHidden(item) {
533
503
  let current = item;
534
504
  while (current && current !== this.element) {
@@ -537,7 +507,6 @@ var ToggleGroupController = class extends Controller {
537
507
  }
538
508
  return false;
539
509
  }
540
- /** Whether ARIA, visibility, or native HTML semantics suppress activation. */
541
510
  #isActivationDisabled(item) {
542
511
  if (!this.#isNavigable(item)) return true;
543
512
  let current = item;
@@ -547,7 +516,6 @@ var ToggleGroupController = class extends Controller {
547
516
  }
548
517
  return false;
549
518
  }
550
- /** Releases default ownership when a Turbo morph authors `aria-pressed`. */
551
519
  #releaseAuthoredPressed(records) {
552
520
  for (const record of records) {
553
521
  if (record.attributeName !== "aria-pressed") continue;
@@ -559,7 +527,6 @@ var ToggleGroupController = class extends Controller {
559
527
  }
560
528
  this.#internalPressedValues.clear();
561
529
  }
562
- /** Watches target membership, retained item hosts/state, and inherited host/fieldset state. */
563
530
  #observeMutations() {
564
531
  const observer = new MutationObserver((records) => {
565
532
  this.#releaseAuthoredPressed(records);
@@ -568,7 +535,6 @@ var ToggleGroupController = class extends Controller {
568
535
  this.#observer = observer;
569
536
  this.#observeWith(observer);
570
537
  }
571
- /** Registers every root and ancestor observation on one observer instance. */
572
538
  #observeWith(observer) {
573
539
  observer.observe(this.element, {
574
540
  subtree: true,
@@ -585,34 +551,27 @@ var ToggleGroupController = class extends Controller {
585
551
  ancestor = ancestor.parentElement;
586
552
  }
587
553
  }
588
- /** Supported targets currently managed by the roving primitive. */
589
554
  get #managedTargets() {
590
555
  return this.itemTargets.filter((item) => this.#managedItems.has(item));
591
556
  }
592
- /** Managed items eligible for the roving Tab stop. */
593
557
  get #navigableItems() {
594
558
  return this.#managedTargets.filter((item) => this.#isNavigable(item));
595
559
  }
596
- /** Whether an item is currently pressed. */
597
560
  #isPressed(item) {
598
561
  return item.getAttribute("aria-pressed") === "true";
599
562
  }
600
- /** Reflects pressed state while distinguishing controller writes from authored morphs. */
601
563
  #setPressed(item, pressed) {
602
564
  const value = pressed ? "true" : "false";
603
565
  this.#internalPressedValues.set(item, value);
604
566
  item.setAttribute("aria-pressed", value);
605
567
  }
606
- /** The DOM-ordered values of every currently pressed managed item. */
607
568
  #pressedValues() {
608
569
  return this.#managedTargets.filter((item) => this.#isPressed(item)).map((item) => this.#itemValue(item));
609
570
  }
610
- /** An item's value (`data-value`, defaulting to empty). */
611
571
  #itemValue(item) {
612
572
  return item.getAttribute("data-value") ?? "";
613
573
  }
614
574
  };
615
575
 
616
576
  export { ToggleGroupController };
617
- //# sourceMappingURL=toggle_group_controller.js.map
618
577
  //# sourceMappingURL=toggle_group_controller.js.map