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 (111) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +136 -2
  3. data/README.md +19 -10
  4. data/dist/cable/index.js +22 -14
  5. data/dist/controllers/accordion_controller.js +14 -6
  6. data/dist/controllers/alert_dialog_controller.js +145 -118
  7. data/dist/controllers/announcer_controller.js +113 -17
  8. data/dist/controllers/auto_submit_controller.js +185 -60
  9. data/dist/controllers/avatar_controller.js +55 -43
  10. data/dist/controllers/bulk_select_controller.js +64 -50
  11. data/dist/controllers/calendar_controller.js +55 -53
  12. data/dist/controllers/carousel_controller.js +124 -86
  13. data/dist/controllers/character_counter_controller.js +291 -95
  14. data/dist/controllers/checkbox_controller.js +6 -0
  15. data/dist/controllers/clipboard_controller.js +118 -27
  16. data/dist/controllers/collapsible_controller.js +52 -49
  17. data/dist/controllers/color_picker_controller.js +29 -7
  18. data/dist/controllers/combobox_controller.js +210 -71
  19. data/dist/controllers/command_palette_controller.js +290 -140
  20. data/dist/controllers/conditional_fields_controller.js +145 -58
  21. data/dist/controllers/confirm_controller.js +145 -118
  22. data/dist/controllers/context_menu_controller.js +138 -73
  23. data/dist/controllers/countdown_controller.js +109 -21
  24. data/dist/controllers/currency_input_controller.js +446 -72
  25. data/dist/controllers/data_grid_controller.js +134 -28
  26. data/dist/controllers/date_range_picker_controller.js +93 -72
  27. data/dist/controllers/dialog_controller.js +145 -118
  28. data/dist/controllers/direct_upload_controller.js +24 -14
  29. data/dist/controllers/dirty_form_controller.js +68 -31
  30. data/dist/controllers/dismissible_controller.js +66 -46
  31. data/dist/controllers/drawer_controller.js +145 -118
  32. data/dist/controllers/dropdown_controller.js +76 -63
  33. data/dist/controllers/editable_controller.js +200 -62
  34. data/dist/controllers/empty_state_controller.js +13 -6
  35. data/dist/controllers/file_dropzone_controller.js +55 -48
  36. data/dist/controllers/filter_controller.js +9 -2
  37. data/dist/controllers/flash_controller.js +66 -33
  38. data/dist/controllers/focus_controller.js +39 -14
  39. data/dist/controllers/form_field_controller.js +52 -43
  40. data/dist/controllers/form_validation_controller.js +18 -11
  41. data/dist/controllers/frame_loading_controller.js +55 -48
  42. data/dist/controllers/hover_card_controller.js +67 -61
  43. data/dist/controllers/idle_controller.js +10 -6
  44. data/dist/controllers/input_mask_controller.js +434 -24
  45. data/dist/controllers/intersection_controller.js +3 -0
  46. data/dist/controllers/lazy_frame_controller.js +15 -3
  47. data/dist/controllers/listbox_controller.js +260 -79
  48. data/dist/controllers/local_time_controller.js +48 -13
  49. data/dist/controllers/masonry_controller.js +11 -4
  50. data/dist/controllers/menu_controller.js +138 -82
  51. data/dist/controllers/menubar_controller.js +65 -19
  52. data/dist/controllers/meter_controller.js +270 -24
  53. data/dist/controllers/multi_select_controller.js +272 -95
  54. data/dist/controllers/navigation_menu_controller.js +67 -19
  55. data/dist/controllers/nested_form_controller.js +98 -64
  56. data/dist/controllers/network_status_controller.js +70 -52
  57. data/dist/controllers/number_input_controller.js +344 -94
  58. data/dist/controllers/optimistic_controller.js +29 -11
  59. data/dist/controllers/otp_controller.js +502 -104
  60. data/dist/controllers/overflow_indicator_controller.js +6 -0
  61. data/dist/controllers/overflow_menu_controller.js +136 -21
  62. data/dist/controllers/pagination_controller.js +47 -14
  63. data/dist/controllers/password_reveal_controller.js +52 -49
  64. data/dist/controllers/password_strength_controller.js +13 -6
  65. data/dist/controllers/persist_controller.js +48 -128
  66. data/dist/controllers/pointer_drag_controller.js +255 -24
  67. data/dist/controllers/popover_controller.js +91 -65
  68. data/dist/controllers/portal_controller.js +6 -0
  69. data/dist/controllers/preview_guard_controller.js +14 -3
  70. data/dist/controllers/progress_controller.js +271 -27
  71. data/dist/controllers/radio_group_controller.js +167 -80
  72. data/dist/controllers/range_slider_controller.js +27 -7
  73. data/dist/controllers/rating_controller.js +93 -57
  74. data/dist/controllers/read_more_controller.js +10 -6
  75. data/dist/controllers/reading_progress_controller.js +22 -5
  76. data/dist/controllers/relative_time_controller.js +75 -11
  77. data/dist/controllers/reset_on_restore_controller.js +6 -0
  78. data/dist/controllers/resizable_controller.js +55 -22
  79. data/dist/controllers/roving_controller.js +10 -4
  80. data/dist/controllers/scroll_area_controller.js +129 -88
  81. data/dist/controllers/scroll_restore_controller.js +14 -2
  82. data/dist/controllers/scroll_visibility_controller.js +93 -60
  83. data/dist/controllers/scrollspy_controller.js +11 -5
  84. data/dist/controllers/separator_controller.js +59 -43
  85. data/dist/controllers/sidebar_controller.js +150 -122
  86. data/dist/controllers/skeleton_controller.js +55 -48
  87. data/dist/controllers/slider_controller.js +27 -6
  88. data/dist/controllers/smart_sticky_header_controller.js +13 -5
  89. data/dist/controllers/sortable_controller.js +27 -14
  90. data/dist/controllers/spinner_controller.js +55 -48
  91. data/dist/controllers/step_indicator_controller.js +6 -0
  92. data/dist/controllers/stepper_controller.js +6 -0
  93. data/dist/controllers/stick_to_bottom_controller.js +19 -8
  94. data/dist/controllers/sticky_observer_controller.js +49 -43
  95. data/dist/controllers/submit_once_controller.js +145 -85
  96. data/dist/controllers/switch_controller.js +172 -28
  97. data/dist/controllers/tabs_controller.js +6 -1
  98. data/dist/controllers/tags_input_controller.js +157 -28
  99. data/dist/controllers/textarea_autosize_controller.js +40 -19
  100. data/dist/controllers/theme_controller.js +10 -4
  101. data/dist/controllers/time_picker_controller.js +192 -54
  102. data/dist/controllers/toast_controller.js +58 -27
  103. data/dist/controllers/toggle_group_controller.js +158 -56
  104. data/dist/controllers/toolbar_controller.js +150 -21
  105. data/dist/controllers/tree_view_controller.js +134 -25
  106. data/dist/index.js +2515 -1315
  107. data/dist/positioning/index.js +6 -0
  108. data/lib/generators/stimeo/install/install_generator.rb +7 -2
  109. data/lib/generators/stimeo/install/templates/stimeo.js +19 -6
  110. data/lib/stimeo/ui/version.rb +1 -1
  111. metadata +2 -2
@@ -1,15 +1,26 @@
1
1
  import { Controller } from '@hotwired/stimulus';
2
2
 
3
+ function setAttributeIfChanged(element, name, value, beforeWrite) {
4
+ if (element.getAttribute(name) === value) return false;
5
+ if (value === null) element.removeAttribute(name);
6
+ else element.setAttribute(name, value);
7
+ return true;
8
+ }
9
+
3
10
  function sharedRegistry(key, create) {
4
11
  const symbol = Symbol.for(key);
5
12
  const scope = globalThis;
6
13
  const existing = scope[symbol];
7
14
  if (existing !== void 0) return existing;
8
- const registry = create();
9
- Object.defineProperty(globalThis, symbol, { value: registry });
10
- return registry;
15
+ const registry2 = create();
16
+ Object.defineProperty(globalThis, symbol, { value: registry2 });
17
+ return registry2;
11
18
  }
12
19
 
20
+ var registry = sharedRegistry(
21
+ "stimeo-ui.attribute-lease.registry.v1",
22
+ () => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Map() })
23
+ );
13
24
  function isAttributeValue(value) {
14
25
  return value === null || typeof value === "string";
15
26
  }
@@ -26,24 +37,46 @@ function readLeaseRecord(element, record) {
26
37
  return void 0;
27
38
  }
28
39
  }
29
- var AttributeLease = class _AttributeLease {
30
- static #registry = sharedRegistry(
31
- "stimeo-ui.attribute-lease.registry.v1",
32
- () => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Map() })
33
- );
40
+ function attributeStack(element, attribute) {
41
+ const byAttribute = registry.stacks.get(element) ?? /* @__PURE__ */ new Map();
42
+ registry.stacks.set(element, byAttribute);
43
+ const known = byAttribute.get(attribute);
44
+ if (known) return known;
45
+ const found = [];
46
+ for (const record of registry.names.get(attribute) ?? []) {
47
+ const read = readLeaseRecord(element, record);
48
+ if (read) found.push({ ...read, record });
49
+ }
50
+ const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
51
+ const stack = found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
52
+ lease: null,
53
+ record,
54
+ written,
55
+ original,
56
+ linked: linked && index > 0
57
+ }));
58
+ byAttribute.set(attribute, stack);
59
+ return stack;
60
+ }
61
+ function findHold(stack, lease, record) {
62
+ return stack.find((held) => held.lease === lease) ?? stack.find((held) => held.lease === null && held.record === record);
63
+ }
64
+ var AttributeLease = class {
34
65
  #attribute;
35
66
  #record;
36
67
  #base;
68
+ #preserveAuthor;
37
69
  #held = /* @__PURE__ */ new Set();
38
70
  constructor(attribute, owner, options = {}) {
39
71
  this.#attribute = attribute;
40
72
  this.#record = `data-${owner}-${attribute}-lease`;
41
73
  this.#base = options.base === true;
42
- const names = _AttributeLease.#registry.names;
74
+ this.#preserveAuthor = options.preserveAuthor === true;
75
+ const names = registry.names;
43
76
  names.set(attribute, (names.get(attribute) ?? /* @__PURE__ */ new Set()).add(this.#record));
44
77
  }
45
78
  write(element, value) {
46
- const stack = this.#stack(element);
79
+ const stack = attributeStack(element, this.#attribute);
47
80
  const hold = this.#take(stack) ?? this.#acquire(element, stack);
48
81
  this.#held.add(element);
49
82
  const shows = !this.#covered(element, stack, hold);
@@ -53,8 +86,8 @@ var AttributeLease = class _AttributeLease {
53
86
  }
54
87
  return(element) {
55
88
  const held = this.#held.delete(element);
56
- const known = _AttributeLease.#registry.stacks.get(element)?.has(this.#attribute);
57
- const stack = held || known || element.hasAttribute(this.#record) ? this.#stack(element) : [];
89
+ const known = registry.stacks.get(element)?.has(this.#attribute);
90
+ const stack = held || known || element.hasAttribute(this.#record) ? attributeStack(element, this.#attribute) : [];
58
91
  const hold = this.#take(stack);
59
92
  if (!hold) return false;
60
93
  const carries = element.getAttribute(this.#attribute) === hold.written;
@@ -72,31 +105,8 @@ var AttributeLease = class _AttributeLease {
72
105
  returnAll() {
73
106
  for (const element of Array.from(this.#held)) this.return(element);
74
107
  }
75
- #stack(element) {
76
- const stacks = _AttributeLease.#registry.stacks;
77
- const byAttribute = stacks.get(element) ?? /* @__PURE__ */ new Map();
78
- stacks.set(element, byAttribute);
79
- const stack = byAttribute.get(this.#attribute) ?? this.#seed(element);
80
- byAttribute.set(this.#attribute, stack);
81
- return stack;
82
- }
83
- #seed(element) {
84
- const found = [];
85
- for (const record of _AttributeLease.#registry.names.get(this.#attribute) ?? []) {
86
- const read = readLeaseRecord(element, record);
87
- if (read) found.push({ ...read, record });
88
- }
89
- const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
90
- return found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
91
- lease: null,
92
- record,
93
- written,
94
- original,
95
- linked: linked && index > 0
96
- }));
97
- }
98
108
  #take(stack) {
99
- const hold = stack.find((held) => held.lease === this) ?? stack.find((held) => held.lease === null && held.record === this.#record);
109
+ const hold = findHold(stack, this, this.#record);
100
110
  if (hold) hold.lease = this;
101
111
  return hold;
102
112
  }
@@ -105,7 +115,7 @@ var AttributeLease = class _AttributeLease {
105
115
  const top = stack.at(-1);
106
116
  const bottom = stack[0];
107
117
  const over = top?.written === current ? top : void 0;
108
- const from = this.#base ? bottom : over;
118
+ const from = this.#base ? this.#preserveAuthor && !stack.some((held) => held.written === current) ? void 0 : bottom : over;
109
119
  const hold = {
110
120
  lease: this,
111
121
  record: this.#record,
@@ -135,15 +145,11 @@ var AttributeLease = class _AttributeLease {
135
145
  );
136
146
  });
137
147
  for (const [name, recorded] of records) {
138
- if (element.getAttribute(name) === recorded) continue;
139
- if (recorded === null) element.removeAttribute(name);
140
- else element.setAttribute(name, recorded);
148
+ setAttributeIfChanged(element, name, recorded);
141
149
  }
142
150
  }
143
151
  #reflect(element, value) {
144
- if (element.getAttribute(this.#attribute) === value) return;
145
- if (value === null) element.removeAttribute(this.#attribute);
146
- else element.setAttribute(this.#attribute, value);
152
+ setAttributeIfChanged(element, this.#attribute, value);
147
153
  }
148
154
  };
149
155
 
@@ -161,25 +167,25 @@ var EscapeLayer = class _EscapeLayer {
161
167
  #active = null;
162
168
  activate(ownerDocument = document, options) {
163
169
  this.deactivate();
164
- let registry = _EscapeLayer.#registries.get(ownerDocument);
165
- if (!registry) {
166
- registry = _EscapeLayer.#createRegistry();
167
- _EscapeLayer.#registries.set(ownerDocument, registry);
168
- ownerDocument.addEventListener("keydown", registry.onKeydown);
170
+ let registry2 = _EscapeLayer.#registries.get(ownerDocument);
171
+ if (!registry2) {
172
+ registry2 = _EscapeLayer.#createRegistry();
173
+ _EscapeLayer.#registries.set(ownerDocument, registry2);
174
+ ownerDocument.addEventListener("keydown", registry2.onKeydown);
169
175
  }
170
176
  const entry = { onDismiss: options.onDismiss, claims: options.claims ?? null };
171
- registry.stack.push(entry);
177
+ registry2.stack.push(entry);
172
178
  this.#active = { document: ownerDocument, entry };
173
179
  }
174
180
  deactivate() {
175
181
  const active = this.#active;
176
182
  if (!active) return;
177
- const registry = _EscapeLayer.#registries.get(active.document);
178
- if (registry) {
179
- const index = registry.stack.lastIndexOf(active.entry);
180
- if (index >= 0) registry.stack.splice(index, 1);
181
- if (registry.stack.length === 0) {
182
- active.document.removeEventListener("keydown", registry.onKeydown);
183
+ const registry2 = _EscapeLayer.#registries.get(active.document);
184
+ if (registry2) {
185
+ const index = registry2.stack.lastIndexOf(active.entry);
186
+ if (index >= 0) registry2.stack.splice(index, 1);
187
+ if (registry2.stack.length === 0) {
188
+ active.document.removeEventListener("keydown", registry2.onKeydown);
183
189
  _EscapeLayer.#registries.delete(active.document);
184
190
  }
185
191
  }
@@ -188,22 +194,22 @@ var EscapeLayer = class _EscapeLayer {
188
194
  get ownsEscape() {
189
195
  const active = this.#active;
190
196
  if (!active) return false;
191
- const registry = _EscapeLayer.#registries.get(active.document);
192
- if (!registry) return false;
193
- return _EscapeLayer.#resolveOwner(registry.stack) === active.entry;
197
+ const registry2 = _EscapeLayer.#registries.get(active.document);
198
+ if (!registry2) return false;
199
+ return _EscapeLayer.#resolveOwner(registry2.stack) === active.entry;
194
200
  }
195
201
  static #createRegistry() {
196
- const registry = {
202
+ const registry2 = {
197
203
  stack: [],
198
204
  onKeydown: (event) => {
199
205
  if (event.key !== "Escape" || event.defaultPrevented || event.isComposing) return;
200
- const owner = _EscapeLayer.#resolveOwner(registry.stack);
206
+ const owner = _EscapeLayer.#resolveOwner(registry2.stack);
201
207
  if (!owner) return;
202
208
  event.preventDefault();
203
209
  owner.onDismiss();
204
210
  }
205
211
  };
206
- return registry;
212
+ return registry2;
207
213
  }
208
214
  static #resolveOwner(stack) {
209
215
  for (let index = stack.length - 1; index >= 0; index--) {
@@ -301,6 +307,17 @@ function firstTabStop(root) {
301
307
  return null;
302
308
  }
303
309
 
310
+ var ListenerSet = class {
311
+ #abort = new AbortController();
312
+ add(target, type, handler, options) {
313
+ target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
314
+ }
315
+ dispose() {
316
+ this.#abort.abort();
317
+ this.#abort = new AbortController();
318
+ }
319
+ };
320
+
304
321
  function observeScrollDismiss(element, onScroll) {
305
322
  const targets = [...scrollParents(element), window];
306
323
  const handler = () => onScroll();
@@ -347,10 +364,12 @@ var PopoverController = class extends Controller {
347
364
  #shownPanel = null;
348
365
  #connected = false;
349
366
  #reporting = false;
367
+ #listeners = new ListenerSet();
350
368
  connect() {
351
369
  this.#close("api");
352
- document.addEventListener("click", this.#onOutsideClick, true);
353
- this.element.addEventListener("focusout", this.#onFocusOut);
370
+ this.#listeners.add(document, "click", this.#onOutsideClick, { capture: true });
371
+ this.#listeners.add(this.element, "focusout", this.#onFocusOut);
372
+ this.#listeners.add(document, "focusin", this.#onDocumentFocusIn, { capture: true });
354
373
  this.#connected = true;
355
374
  this.#reporting = true;
356
375
  }
@@ -358,8 +377,7 @@ var PopoverController = class extends Controller {
358
377
  this.#connected = false;
359
378
  this.#reporting = false;
360
379
  this.#release();
361
- document.removeEventListener("click", this.#onOutsideClick, true);
362
- this.element.removeEventListener("focusout", this.#onFocusOut);
380
+ this.#listeners.dispose();
363
381
  }
364
382
  closeOnScrollValueChanged() {
365
383
  if (this.#shownPanel) this.#syncScrollDismiss();
@@ -458,6 +476,14 @@ var PopoverController = class extends Controller {
458
476
  if (!(next instanceof Node) || this.element.contains(next)) return;
459
477
  this.#close("focus");
460
478
  };
479
+ #onDocumentFocusIn = (event) => {
480
+ if (!this.#closable) return;
481
+ const target = event.target;
482
+ if (!(target instanceof Node) || target === document.body || this.element.contains(target)) {
483
+ return;
484
+ }
485
+ this.#close("focus");
486
+ };
461
487
  get #isOpen() {
462
488
  return this.hasPanelTarget && !this.panelTarget.hidden;
463
489
  }
@@ -83,6 +83,9 @@ var MicrotaskCoalescer = class {
83
83
  this.#queued = false;
84
84
  this.#generation += 1;
85
85
  }
86
+ get pending() {
87
+ return this.#queued;
88
+ }
86
89
  schedule() {
87
90
  if (!this.#active || this.#queued) return;
88
91
  this.#queued = true;
@@ -113,6 +116,9 @@ var MorphRenderWatcher = class {
113
116
  schedule() {
114
117
  this.#pass.schedule();
115
118
  }
119
+ get pending() {
120
+ return this.#pass.pending;
121
+ }
116
122
  disconnect() {
117
123
  this.#listeners.dispose();
118
124
  this.#pass.cancel();
@@ -27,6 +27,9 @@ var MicrotaskCoalescer = class {
27
27
  this.#queued = false;
28
28
  this.#generation += 1;
29
29
  }
30
+ get pending() {
31
+ return this.#queued;
32
+ }
30
33
  schedule() {
31
34
  if (!this.#active || this.#queued) return;
32
35
  this.#queued = true;
@@ -57,6 +60,9 @@ var MorphRenderWatcher = class {
57
60
  schedule() {
58
61
  this.#pass.schedule();
59
62
  }
63
+ get pending() {
64
+ return this.#pass.pending;
65
+ }
60
66
  disconnect() {
61
67
  this.#listeners.dispose();
62
68
  this.#pass.cancel();
@@ -64,6 +70,13 @@ var MorphRenderWatcher = class {
64
70
  }
65
71
  };
66
72
 
73
+ function setAttributeIfChanged(element, name, value, beforeWrite) {
74
+ if (element.getAttribute(name) === value) return false;
75
+ if (value === null) element.removeAttribute(name);
76
+ else element.setAttribute(name, value);
77
+ return true;
78
+ }
79
+
67
80
  function sharedRegistry(key, create) {
68
81
  const symbol = Symbol.for(key);
69
82
  const scope = globalThis;
@@ -203,9 +216,7 @@ var StylePropertyLease = class _StylePropertyLease {
203
216
  );
204
217
  });
205
218
  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);
219
+ setAttributeIfChanged(element, name, recorded);
209
220
  }
210
221
  }
211
222
  #carries(element, hold) {