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,117 +1,98 @@
1
1
  import { Controller } from '@hotwired/stimulus';
2
2
 
3
- // src/controllers/optimistic_controller.ts
4
-
5
- // src/utils/detach_gate.ts
6
3
  var DetachGate = class _DetachGate {
7
- /** Set while a probe is queued, waiting for a reconnect to cancel it. */
8
4
  #pending = false;
9
- /**
10
- * True while a probe is queued — the last disconnect was ambiguous and no
11
- * reconnect has cancelled it yet. Read it from `connect()` to tell the
12
- * reconnect half of an in-page move from a first connect: a controller whose
13
- * initialisation restarts a measurement (a min-duration floor, an elapsed
14
- * counter) must skip it for the move, where nothing actually restarted.
15
- */
16
5
  get pending() {
17
6
  return this.#pending;
18
7
  }
19
- /**
20
- * True when the disconnect is definitely a real detach — the element left
21
- * the document, or `data-controller` no longer lists the identifier. False
22
- * means ambiguous (in-page move or observed-root exit), NOT "alive".
23
- */
24
8
  static isDetached(host) {
25
- if (!host.element.isConnected) return true;
26
- const tokens = (host.element.getAttribute("data-controller") ?? "").split(/\s+/);
27
- return !tokens.includes(host.identifier);
28
- }
29
- /**
30
- * Call from `disconnect()`: runs `teardown` synchronously on a definite
31
- * detach (fast path), otherwise defers it one microtask — a reconnect
32
- * ({@link cancel} from `connect()`) keeps the state, no reconnect runs it.
33
- * One microtask is the whole probe window: Stimulus reconnects a moved
34
- * element within the same mutation batch, before the checkpoint drains.
35
- */
9
+ return !host.element.isConnected || !_DetachGate.#listed(host);
10
+ }
36
11
  disconnected(host, teardown) {
37
- if (_DetachGate.isDetached(host)) {
12
+ const carried = _DetachGate.#carried(host);
13
+ if (!carried && _DetachGate.isDetached(host)) {
38
14
  this.#pending = false;
39
15
  teardown();
40
16
  return;
41
17
  }
42
18
  this.#pending = true;
43
- queueMicrotask(() => {
19
+ const probe = () => {
44
20
  if (!this.#pending) return;
45
21
  this.#pending = false;
46
22
  teardown();
47
- });
23
+ };
24
+ if (carried) setTimeout(probe, 0);
25
+ else queueMicrotask(probe);
26
+ }
27
+ static #carried(host) {
28
+ const element = host.element;
29
+ return !element.isConnected && element.closest("[data-turbo-permanent]") !== null && _DetachGate.#listed(host);
30
+ }
31
+ static #listed(host) {
32
+ const tokens = (host.element.getAttribute("data-controller") ?? "").split(/\s+/);
33
+ return tokens.includes(host.identifier);
48
34
  }
49
- /**
50
- * Disarms a pending probe. Call from `connect()` (the reconnect that proves
51
- * an in-page move) and from the head of any teardown path not routed through
52
- * {@link disconnected} (disabled-toggle, Escape), so an orphaned probe can
53
- * never run the teardown a second time.
54
- */
55
35
  cancel() {
56
36
  this.#pending = false;
57
37
  }
58
38
  };
59
39
 
60
- // src/utils/listener_set.ts
61
40
  var ListenerSet = class {
62
- /** The generation every `add` joins until the next `dispose()`. */
63
41
  #abort = new AbortController();
64
- /**
65
- * Attaches `handler` to the open generation, exactly as the caller spelled it.
66
- *
67
- * The set supplies the signal, so `options` carries everything else the DOM
68
- * accepts — `capture` included, which has to match at release time and no
69
- * longer has a second place to drift from.
70
- */
71
42
  add(target, type, handler, options) {
72
43
  target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
73
44
  }
74
- /**
75
- * Releases every listener of the open generation, synchronously, and opens the
76
- * next one. Idempotent, and safe before anything has been added.
77
- */
78
45
  dispose() {
79
46
  this.#abort.abort();
80
47
  this.#abort = new AbortController();
81
48
  }
82
49
  };
83
50
 
84
- // src/utils/transient_hooks.ts
51
+ var SubmissionOwner = class {
52
+ #synthetic = /* @__PURE__ */ Symbol("synthetic submission");
53
+ #active = null;
54
+ begin(event) {
55
+ this.#active = { source: event.target, token: this.#tokenOf(event) };
56
+ }
57
+ resolve(event) {
58
+ if (this.#active === null || this.#active.source !== event.target || this.#active.token !== this.#tokenOf(event)) {
59
+ return null;
60
+ }
61
+ this.clear();
62
+ return this.#detailOf(event)?.success === true;
63
+ }
64
+ clear() {
65
+ this.#active = null;
66
+ }
67
+ #tokenOf(event) {
68
+ return this.#detailOf(event)?.formSubmission ?? this.#synthetic;
69
+ }
70
+ #detailOf(event) {
71
+ return event.detail;
72
+ }
73
+ };
74
+
85
75
  var TransientHooks = class {
86
76
  #attributes;
87
77
  constructor(options) {
88
78
  this.#attributes = options.attributes;
89
79
  }
90
- /** Drops the declared hooks from `element`; what it carries besides stays. */
91
80
  reset(element) {
92
81
  for (const attribute of this.#attributes) element.removeAttribute(attribute);
93
82
  }
94
83
  };
95
84
 
96
- // src/controllers/optimistic_controller.ts
97
85
  var TRANSIENT = new TransientHooks({ attributes: ["data-optimistic"] });
98
86
  var HIDDEN_MARKER = "data-optimistic-toggled";
99
87
  var BUSY_MARKER = "data-optimistic-busy";
100
88
  var AUTHORED_ABSENT = "absent";
101
89
  var AUTHORED_VALUE = "value:";
102
- var SYNTHETIC_SUBMISSION = {};
103
- function submissionOf(event) {
104
- const detail = event.detail;
105
- return detail?.formSubmission ?? SYNTHETIC_SUBMISSION;
106
- }
107
90
  var OptimisticController = class extends Controller {
108
91
  static targets = ["show", "hide"];
109
92
  static events = ["commit", "rollback"];
110
- /** The submission that owns the applied optimistic state, if any. */
111
- #pending = null;
93
+ #submission = new SubmissionOwner();
112
94
  #gate = new DetachGate();
113
95
  #listeners = new ListenerSet();
114
- /** True between `connect()` and `disconnect()`, so a repeat connect rewinds nothing. */
115
96
  #connected = false;
116
97
  connect() {
117
98
  const restored = !this.#connected && !this.#gate.pending;
@@ -125,11 +106,11 @@ var OptimisticController = class extends Controller {
125
106
  this.#connected = false;
126
107
  this.#listeners.dispose();
127
108
  this.#gate.disconnected(this, () => {
128
- this.#pending = null;
109
+ this.#submission.clear();
129
110
  });
130
111
  }
131
112
  #onSubmitStart = (event) => {
132
- this.#pending = submissionOf(event);
113
+ this.#submission.begin(event);
133
114
  if (this.element instanceof HTMLFormElement && !this.element.hasAttribute(BUSY_MARKER)) {
134
115
  this.element.setAttribute(BUSY_MARKER, AUTHORED_ABSENT);
135
116
  }
@@ -139,9 +120,8 @@ var OptimisticController = class extends Controller {
139
120
  for (const target of this.hideTargets) this.#setHidden(target, true);
140
121
  };
141
122
  #onSubmitEnd = (event) => {
142
- if (submissionOf(event) !== this.#pending) return;
143
- this.#pending = null;
144
- const success = event.detail?.success === true;
123
+ const success = this.#submission.resolve(event);
124
+ if (success === null) return;
145
125
  if (success) {
146
126
  this.element.removeAttribute("data-optimistic");
147
127
  this.#restore(this.element, "aria-busy", BUSY_MARKER, "true");
@@ -154,12 +134,10 @@ var OptimisticController = class extends Controller {
154
134
  this.dispatch("rollback");
155
135
  }
156
136
  };
157
- /** Hides or reveals a target, recording the authored `hidden` on first write. */
158
137
  #setHidden(target, hidden) {
159
138
  if (target.hasAttribute("hidden") === hidden) return;
160
139
  this.#write(target, "hidden", hidden ? "" : null, HIDDEN_MARKER);
161
140
  }
162
- /** Writes an attribute, recording what it displaced under `marker` once. */
163
141
  #write(element, attribute, value, marker) {
164
142
  if (!element.hasAttribute(marker)) {
165
143
  const authored = element.getAttribute(attribute);
@@ -171,16 +149,6 @@ var OptimisticController = class extends Controller {
171
149
  if (value === null) element.removeAttribute(attribute);
172
150
  else element.setAttribute(attribute, value);
173
151
  }
174
- /**
175
- * Puts back the value `marker` recorded and drops the record.
176
- *
177
- * `written` is what this controller last put in the attribute. Anything else
178
- * there now belongs to whoever wrote it — Turbo owns `aria-busy` on a form and
179
- * clears it before the terminal arrives, and a consumer may have moved a face
180
- * mid-flight — so the record is dropped without touching the attribute. A
181
- * marker this build did not write names no authored value, so the attribute
182
- * goes back to being absent.
183
- */
184
152
  #restore(element, attribute, marker, written) {
185
153
  const recorded = element.getAttribute(marker);
186
154
  if (recorded === null) return;
@@ -192,15 +160,6 @@ var OptimisticController = class extends Controller {
192
160
  }
193
161
  element.removeAttribute(attribute);
194
162
  }
195
- /**
196
- * Puts back exactly the markup this controller displaced (record-owned only).
197
- *
198
- * A face can be registered on both sides, and the hide pass runs last, so what
199
- * this controller wrote there is `hidden` — matching it against the reveal's
200
- * absent value instead would read as someone else's write and leave the face
201
- * hidden. Each target is therefore restored once, against the write it last
202
- * received.
203
- */
204
163
  #revert() {
205
164
  TRANSIENT.reset(this.element);
206
165
  this.#restore(this.element, "aria-busy", BUSY_MARKER, "true");
@@ -212,5 +171,4 @@ var OptimisticController = class extends Controller {
212
171
  };
213
172
 
214
173
  export { OptimisticController };
215
- //# sourceMappingURL=optimistic_controller.js.map
216
174
  //# sourceMappingURL=optimistic_controller.js.map