stimeo-ui 0.16.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +136 -0
  3. data/README.md +27 -11
  4. data/dist/cable/index.js +384 -449
  5. data/dist/controllers/accordion_controller.js +174 -55
  6. data/dist/controllers/alert_dialog_controller.js +903 -235
  7. data/dist/controllers/announcer_controller.js +238 -205
  8. data/dist/controllers/aspect_ratio_controller.js +0 -10
  9. data/dist/controllers/auto_submit_controller.js +414 -145
  10. data/dist/controllers/avatar_controller.js +185 -107
  11. data/dist/controllers/breadcrumb_controller.js +0 -130
  12. data/dist/controllers/bulk_select_controller.js +282 -58
  13. data/dist/controllers/calendar_controller.js +228 -260
  14. data/dist/controllers/carousel_controller.js +536 -436
  15. data/dist/controllers/character_counter_controller.js +493 -207
  16. data/dist/controllers/checkbox_controller.js +38 -74
  17. data/dist/controllers/clipboard_controller.js +261 -149
  18. data/dist/controllers/collapsible_controller.js +304 -120
  19. data/dist/controllers/color_picker_controller.js +178 -146
  20. data/dist/controllers/combobox_controller.js +522 -156
  21. data/dist/controllers/command_palette_controller.js +1156 -395
  22. data/dist/controllers/conditional_fields_controller.js +300 -171
  23. data/dist/controllers/confirm_controller.js +980 -262
  24. data/dist/controllers/context_menu_controller.js +346 -153
  25. data/dist/controllers/count_up_controller.js +73 -21
  26. data/dist/controllers/countdown_controller.js +281 -158
  27. data/dist/controllers/currency_input_controller.js +575 -225
  28. data/dist/controllers/data_grid_controller.js +248 -214
  29. data/dist/controllers/date_range_picker_controller.js +338 -235
  30. data/dist/controllers/dialog_controller.js +899 -237
  31. data/dist/controllers/direct_upload_controller.js +97 -167
  32. data/dist/controllers/dirty_form_controller.js +72 -69
  33. data/dist/controllers/dismissible_controller.js +196 -24
  34. data/dist/controllers/drawer_controller.js +974 -355
  35. data/dist/controllers/dropdown_controller.js +339 -96
  36. data/dist/controllers/editable_controller.js +315 -88
  37. data/dist/controllers/empty_state_controller.js +79 -58
  38. data/dist/controllers/file_dropzone_controller.js +322 -211
  39. data/dist/controllers/filter_controller.js +77 -42
  40. data/dist/controllers/flash_controller.js +238 -347
  41. data/dist/controllers/focus_controller.js +679 -240
  42. data/dist/controllers/form_field_controller.js +156 -132
  43. data/dist/controllers/form_validation_controller.js +31 -97
  44. data/dist/controllers/frame_loading_controller.js +275 -217
  45. data/dist/controllers/highlight_controller.js +107 -75
  46. data/dist/controllers/hover_card_controller.js +327 -130
  47. data/dist/controllers/idle_controller.js +271 -101
  48. data/dist/controllers/input_mask_controller.js +483 -97
  49. data/dist/controllers/intersection_controller.js +150 -106
  50. data/dist/controllers/lazy_frame_controller.js +24 -68
  51. data/dist/controllers/listbox_controller.js +523 -240
  52. data/dist/controllers/local_time_controller.js +102 -77
  53. data/dist/controllers/masonry_controller.js +80 -96
  54. data/dist/controllers/menu_controller.js +302 -188
  55. data/dist/controllers/menubar_controller.js +232 -345
  56. data/dist/controllers/meter_controller.js +417 -87
  57. data/dist/controllers/multi_select_controller.js +785 -393
  58. data/dist/controllers/navigation_menu_controller.js +190 -250
  59. data/dist/controllers/nested_form_controller.js +396 -192
  60. data/dist/controllers/network_status_controller.js +268 -62
  61. data/dist/controllers/number_input_controller.js +610 -303
  62. data/dist/controllers/optimistic_controller.js +45 -87
  63. data/dist/controllers/otp_controller.js +658 -255
  64. data/dist/controllers/overflow_indicator_controller.js +122 -113
  65. data/dist/controllers/overflow_menu_controller.js +470 -295
  66. data/dist/controllers/pagination_controller.js +332 -123
  67. data/dist/controllers/password_reveal_controller.js +392 -121
  68. data/dist/controllers/password_strength_controller.js +111 -158
  69. data/dist/controllers/persist_controller.js +165 -111
  70. data/dist/controllers/pointer_drag_controller.js +434 -188
  71. data/dist/controllers/popover_controller.js +269 -113
  72. data/dist/controllers/portal_controller.js +215 -76
  73. data/dist/controllers/preview_guard_controller.js +243 -116
  74. data/dist/controllers/progress_controller.js +391 -78
  75. data/dist/controllers/radio_group_controller.js +278 -211
  76. data/dist/controllers/range_slider_controller.js +220 -113
  77. data/dist/controllers/rating_controller.js +458 -211
  78. data/dist/controllers/read_more_controller.js +138 -63
  79. data/dist/controllers/reading_progress_controller.js +166 -137
  80. data/dist/controllers/relative_time_controller.js +211 -112
  81. data/dist/controllers/{reset_before_cache_controller.js → reset_on_restore_controller.js} +103 -38
  82. data/dist/controllers/resizable_controller.js +299 -150
  83. data/dist/controllers/roving_controller.js +49 -88
  84. data/dist/controllers/scroll_area_controller.js +490 -246
  85. data/dist/controllers/scroll_restore_controller.js +14 -55
  86. data/dist/controllers/scroll_visibility_controller.js +432 -149
  87. data/dist/controllers/scrollspy_controller.js +193 -248
  88. data/dist/controllers/separator_controller.js +285 -142
  89. data/dist/controllers/sidebar_controller.js +1069 -404
  90. data/dist/controllers/skeleton_controller.js +259 -101
  91. data/dist/controllers/slider_controller.js +187 -86
  92. data/dist/controllers/smart_sticky_header_controller.js +173 -66
  93. data/dist/controllers/sortable_controller.js +26 -125
  94. data/dist/controllers/spinner_controller.js +288 -173
  95. data/dist/controllers/step_indicator_controller.js +105 -46
  96. data/dist/controllers/stepper_controller.js +120 -73
  97. data/dist/controllers/stick_to_bottom_controller.js +275 -140
  98. data/dist/controllers/sticky_observer_controller.js +220 -49
  99. data/dist/controllers/submit_once_controller.js +376 -227
  100. data/dist/controllers/switch_controller.js +201 -84
  101. data/dist/controllers/tabs_controller.js +41 -30
  102. data/dist/controllers/tags_input_controller.js +293 -173
  103. data/dist/controllers/textarea_autosize_controller.js +108 -74
  104. data/dist/controllers/theme_controller.js +140 -116
  105. data/dist/controllers/time_picker_controller.js +331 -127
  106. data/dist/controllers/toast_controller.js +244 -324
  107. data/dist/controllers/toggle_group_controller.js +252 -191
  108. data/dist/controllers/toolbar_controller.js +219 -120
  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 +283 -369
  112. data/dist/index.js +8573 -10410
  113. data/dist/positioning/index.js +154 -47
  114. data/lib/generators/stimeo/install/install_generator.rb +7 -2
  115. data/lib/generators/stimeo/install/templates/stimeo.js +19 -6
  116. data/lib/stimeo/ui/version.rb +1 -1
  117. metadata +3 -3
@@ -1,44 +1,25 @@
1
1
  import { Controller } from '@hotwired/stimulus';
2
2
 
3
- // src/controllers/highlight_controller.ts
3
+ var MAX_TIMER_DELAY_MS = 2147483647;
4
4
 
5
- // src/utils/safe_timeout.ts
6
5
  var TimerRegistry = class {
7
- /** Live timer ids that have not yet been cleared (or, for timeouts, fired). */
8
6
  ids = /* @__PURE__ */ new Set();
9
- /**
10
- * Cancels a single tracked timer.
11
- *
12
- * No-ops if the id is unknown (already cleared, fired, or never owned by this
13
- * registry), so callers can clear defensively without guarding.
14
- */
15
7
  clear(id) {
16
8
  if (this.ids.delete(id)) {
17
9
  this.cancel(id);
18
10
  }
19
11
  }
20
- /**
21
- * Cancels every tracked timer. Call this from a controller's `disconnect()`
22
- * to guarantee no timer outlives the element.
23
- */
24
12
  clearAll() {
25
13
  for (const id of this.ids) {
26
14
  this.cancel(id);
27
15
  }
28
16
  this.ids.clear();
29
17
  }
30
- /** Number of timers currently tracked (pending). */
31
18
  get size() {
32
19
  return this.ids.size;
33
20
  }
34
21
  };
35
22
  var SafeTimeout = class extends TimerRegistry {
36
- /**
37
- * Schedules `callback` after `delay` ms and returns the timer id.
38
- *
39
- * The id is removed from the registry automatically when the timeout fires,
40
- * so {@link TimerRegistry.size | size} reflects only still-pending timers.
41
- */
42
23
  set(callback, delay) {
43
24
  const id = this.schedule(() => {
44
25
  this.ids.delete(id);
@@ -55,16 +36,9 @@ var SafeTimeout = class extends TimerRegistry {
55
36
  }
56
37
  };
57
38
 
58
- // src/utils/keyed_timers.ts
59
39
  var KeyedTimers = class {
60
40
  #timers = new SafeTimeout();
61
- /** The pending timer of each key; an entry lives exactly as long as its timer. */
62
41
  #pending = /* @__PURE__ */ new Map();
63
- /**
64
- * Arms `callback` after `delay` ms for `key`, cancelling the timer `key` had
65
- * pending. The entry is dropped before the callback runs, so the callback sees
66
- * the key unarmed and may arm it again for the next round.
67
- */
68
42
  set(key, callback, delay) {
69
43
  this.clear(key);
70
44
  const id = this.#timers.set(() => {
@@ -73,86 +47,145 @@ var KeyedTimers = class {
73
47
  }, delay);
74
48
  this.#pending.set(key, id);
75
49
  }
76
- /**
77
- * Cancels `key`'s pending timer, if it has one.
78
- *
79
- * A timer id is a positive integer, so `-1` stands for "nothing pending" and
80
- * the registry ignores an id it does not own — the unarmed case needs no
81
- * branch of its own, and no other key's timer can be reached from here.
82
- */
83
50
  clear(key) {
84
51
  this.#timers.clear(this.#pending.get(key) ?? -1);
85
52
  this.#pending.delete(key);
86
53
  }
87
- /**
88
- * Cancels every pending timer and forgets every key. Call this from a
89
- * controller's `disconnect()` so no timer, and no entry, outlives the element.
90
- */
91
54
  clearAll() {
92
55
  this.#timers.clearAll();
93
56
  this.#pending.clear();
94
57
  }
95
- /** Whether `key` has a timer pending. */
96
58
  has(key) {
97
59
  return this.#pending.has(key);
98
60
  }
99
61
  };
100
62
 
101
- // src/utils/reduced_motion.ts
63
+ var NUMBER_BOUNDS = {
64
+ timer: { finite: true, min: 0, max: MAX_TIMER_DELAY_MS }};
65
+ function matchesNumberBounds(value, bounds) {
66
+ if (!Number.isFinite(value)) {
67
+ const direction = value === Infinity ? "positive" : value === -Infinity ? "negative" : null;
68
+ if (direction === null) return false;
69
+ if (bounds.allowInfinity !== "both" && bounds.allowInfinity !== direction) return false;
70
+ }
71
+ if (bounds.min !== void 0 && value < bounds.min) return false;
72
+ if (bounds.max !== void 0 && value > bounds.max) return false;
73
+ if (bounds.exclusiveMin !== void 0 && value <= bounds.exclusiveMin) return false;
74
+ if (bounds.integer && !Number.isInteger(value)) return false;
75
+ if (bounds.allowedValues !== void 0 && !bounds.allowedValues.includes(value)) return false;
76
+ return true;
77
+ }
78
+
79
+ function readNumber(raw, fallback, bounds) {
80
+ return matchesNumberBounds(raw, bounds) ? raw : fallback;
81
+ }
82
+
83
+ var NumberValueReader = class {
84
+ #lastRejected = /* @__PURE__ */ new Map();
85
+ read(owner, name, raw, fallback, bounds) {
86
+ const resolved = readNumber(raw, fallback, bounds);
87
+ if (matchesNumberBounds(raw, bounds)) {
88
+ this.#lastRejected.delete(name);
89
+ return resolved;
90
+ }
91
+ const attribute = `data-${owner.identifier}-${name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}-value`;
92
+ const literal = owner.element.getAttribute(attribute);
93
+ if (literal === null) {
94
+ this.#lastRejected.delete(name);
95
+ return resolved;
96
+ }
97
+ if (this.#lastRejected.get(name) !== literal) {
98
+ this.#lastRejected.set(name, literal);
99
+ console.warn(
100
+ `Stimeo UI: "${owner.identifier}" has an invalid number Value "${name}" declaration ${JSON.stringify(literal)}; using ${fallback}.`
101
+ );
102
+ }
103
+ return resolved;
104
+ }
105
+ };
106
+
102
107
  function prefersReducedMotion() {
103
108
  return typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
104
109
  }
105
110
 
106
- // src/utils/transient_hooks.ts
111
+ function sharedRegistry(key, create) {
112
+ const symbol = Symbol.for(key);
113
+ const scope = globalThis;
114
+ const existing = scope[symbol];
115
+ if (existing !== void 0) return existing;
116
+ const registry = create();
117
+ Object.defineProperty(globalThis, symbol, { value: registry });
118
+ return registry;
119
+ }
120
+
107
121
  var TransientHooks = class {
108
122
  #attributes;
109
123
  constructor(options) {
110
124
  this.#attributes = options.attributes;
111
125
  }
112
- /** Drops the declared hooks from `element`; what it carries besides stays. */
113
126
  reset(element) {
114
127
  for (const attribute of this.#attributes) element.removeAttribute(attribute);
115
128
  }
116
129
  };
117
130
 
118
- // src/controllers/highlight_controller.ts
119
131
  var TRANSIENT = new TransientHooks({ attributes: ["data-highlight"] });
120
- var hookOwners = /* @__PURE__ */ new WeakMap();
121
- var HighlightController = class extends Controller {
132
+ var hookOwners = sharedRegistry(
133
+ "stimeo-ui.highlight.registry.v1",
134
+ () => /* @__PURE__ */ new WeakMap()
135
+ );
136
+ var HighlightController = class _HighlightController extends Controller {
137
+ #numbers = new NumberValueReader();
122
138
  static values = {
123
139
  duration: { type: Number, default: 1500 },
124
140
  observe: { type: Boolean, default: false }
125
141
  };
142
+ static valueConstraints = {
143
+ duration: NUMBER_BOUNDS.timer
144
+ };
126
145
  static events = ["start", "end"];
127
- /**
128
- * The removal timer this connection has outstanding for each element. Which
129
- * connection owns an element's hook is answered by the shared owner registry above.
130
- */
131
146
  #removal = new KeyedTimers();
132
147
  #observer = null;
148
+ #watching = false;
149
+ #connected = false;
133
150
  connect() {
134
151
  this.#clearArrivedHook(this.element);
152
+ this.#connected = true;
135
153
  if (this.observeValue) {
136
- for (const child of this.element.children) this.#clearArrivedHook(child);
137
- if (typeof MutationObserver !== "undefined") {
138
- this.#observer = new MutationObserver((mutations) => this.#onMutations(mutations));
139
- this.#observer.observe(this.element, { childList: true });
140
- }
154
+ this.#watchChildren();
141
155
  return;
142
156
  }
143
157
  this.#highlight(this.element);
144
158
  }
145
159
  disconnect() {
160
+ this.#connected = false;
161
+ this.#stopWatching();
162
+ this.#removal.clearAll();
163
+ }
164
+ observeValueChanged() {
165
+ if (!this.#connected || this.observeValue === this.#watching) return;
166
+ if (this.#watching) this.#stopWatching();
167
+ else this.#watchChildren();
168
+ }
169
+ #watchChildren() {
170
+ this.#watching = true;
171
+ for (const child of this.element.children) {
172
+ const owner = hookOwners.get(child);
173
+ if (owner === void 0 || !owner.pending()) this.#clearArrivedHook(child);
174
+ }
175
+ if (typeof MutationObserver !== "undefined") {
176
+ this.#observer = new MutationObserver((mutations) => this.#onMutations(mutations));
177
+ this.#observer.observe(this.element, { childList: true });
178
+ }
179
+ }
180
+ #stopWatching() {
181
+ this.#watching = false;
146
182
  this.#observer?.disconnect();
147
183
  this.#observer = null;
148
- this.#removal.clearAll();
149
184
  }
150
- /** Drops a hook that arrived with the DOM, along with this connection's claim on it. */
151
185
  #clearArrivedHook(el) {
152
- if (hookOwners.get(el) === this) hookOwners.delete(el);
186
+ if (hookOwners.get(el)?.owner === this) hookOwners.delete(el);
153
187
  TRANSIENT.reset(el);
154
188
  }
155
- /** Highlights every element child added by a childList mutation. */
156
189
  #onMutations(mutations) {
157
190
  for (const mutation of mutations) {
158
191
  for (const node of mutation.addedNodes) {
@@ -160,11 +193,6 @@ var HighlightController = class extends Controller {
160
193
  }
161
194
  }
162
195
  }
163
- /**
164
- * Flags `el` with `data-highlight` and schedules its removal (unless reduced-motion).
165
- *
166
- * @stimeoRuntimeOnly `duration` is the length of the one emphasis this call arms.
167
- */
168
196
  #highlight(el) {
169
197
  if (prefersReducedMotion()) return;
170
198
  this.#releasePending(el);
@@ -177,27 +205,31 @@ var HighlightController = class extends Controller {
177
205
  el.removeAttribute("data-highlight");
178
206
  this.dispatch("end", { target: el, detail: { element: el } });
179
207
  },
180
- this.durationValue
208
+ this.#safeDuration
181
209
  );
182
- hookOwners.set(el, this);
210
+ hookOwners.set(el, {
211
+ owner: this,
212
+ pending: () => this.#removal.has(el),
213
+ cancel: () => this.#cancelPending(el)
214
+ });
183
215
  }
184
- /**
185
- * Releases whichever removal timer holds `el`'s hook. The row may have been
186
- * highlighted inside a different watched container before it moved here, and that
187
- * container's timer is reachable only through the shared owner registry.
188
- */
189
216
  #releasePending(el) {
190
217
  const owner = hookOwners.get(el);
191
- if (owner !== void 0 && owner !== this) owner.#cancelPending(el);
192
- this.#cancelPending(el);
218
+ if (owner !== void 0 && owner.owner !== this) owner.cancel();
193
219
  }
194
- /** Releases `el`'s pending removal timer, if it has one, and this connection's claim. */
195
220
  #cancelPending(el) {
196
221
  this.#removal.clear(el);
197
- hookOwners.delete(el);
222
+ }
223
+ get #safeDuration() {
224
+ return this.#numbers.read(
225
+ this,
226
+ "duration",
227
+ this.durationValue,
228
+ _HighlightController.values.duration.default,
229
+ _HighlightController.valueConstraints.duration
230
+ );
198
231
  }
199
232
  };
200
233
 
201
234
  export { HighlightController };
202
- //# sourceMappingURL=highlight_controller.js.map
203
235
  //# sourceMappingURL=highlight_controller.js.map