stimeo-ui 0.12.0 → 0.13.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 (133) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/cable/index.d.ts +67 -13
  3. package/dist/cable/index.js +438 -152
  4. package/dist/cable/index.js.map +1 -1
  5. package/dist/controllers/alert_dialog_controller.d.ts +1 -1
  6. package/dist/controllers/alert_dialog_controller.js.map +1 -1
  7. package/dist/controllers/announcer_controller.d.ts +1 -1
  8. package/dist/controllers/announcer_controller.js.map +1 -1
  9. package/dist/controllers/auto_submit_controller.js.map +1 -1
  10. package/dist/controllers/breadcrumb_controller.d.ts +1 -1
  11. package/dist/controllers/breadcrumb_controller.js.map +1 -1
  12. package/dist/controllers/calendar_controller.d.ts +2 -1
  13. package/dist/controllers/calendar_controller.js +10 -2
  14. package/dist/controllers/calendar_controller.js.map +1 -1
  15. package/dist/controllers/carousel_controller.js +1 -1
  16. package/dist/controllers/carousel_controller.js.map +1 -1
  17. package/dist/controllers/character_counter_controller.js.map +1 -1
  18. package/dist/controllers/clipboard_controller.d.ts +1 -1
  19. package/dist/controllers/clipboard_controller.js.map +1 -1
  20. package/dist/controllers/collapsible_controller.js.map +1 -1
  21. package/dist/controllers/color_picker_controller.d.ts +1 -1
  22. package/dist/controllers/color_picker_controller.js.map +1 -1
  23. package/dist/controllers/command_palette_controller.d.ts +3 -3
  24. package/dist/controllers/command_palette_controller.js +2 -2
  25. package/dist/controllers/command_palette_controller.js.map +1 -1
  26. package/dist/controllers/conditional_fields_controller.js.map +1 -1
  27. package/dist/controllers/confirm_controller.d.ts +2 -2
  28. package/dist/controllers/confirm_controller.js.map +1 -1
  29. package/dist/controllers/context_menu_controller.d.ts +1 -1
  30. package/dist/controllers/context_menu_controller.js.map +1 -1
  31. package/dist/controllers/countdown_controller.d.ts +1 -1
  32. package/dist/controllers/countdown_controller.js.map +1 -1
  33. package/dist/controllers/data_grid_controller.d.ts +1 -1
  34. package/dist/controllers/data_grid_controller.js.map +1 -1
  35. package/dist/controllers/date_range_picker_controller.js +10 -10
  36. package/dist/controllers/date_range_picker_controller.js.map +1 -1
  37. package/dist/controllers/dialog_controller.d.ts +1 -1
  38. package/dist/controllers/dialog_controller.js.map +1 -1
  39. package/dist/controllers/direct_upload_controller.js.map +1 -1
  40. package/dist/controllers/dirty_form_controller.js.map +1 -1
  41. package/dist/controllers/dismissible_controller.js.map +1 -1
  42. package/dist/controllers/drawer_controller.d.ts +2 -2
  43. package/dist/controllers/drawer_controller.js +2 -2
  44. package/dist/controllers/drawer_controller.js.map +1 -1
  45. package/dist/controllers/dropdown_controller.d.ts +1 -1
  46. package/dist/controllers/dropdown_controller.js.map +1 -1
  47. package/dist/controllers/file_dropzone_controller.js.map +1 -1
  48. package/dist/controllers/flash_controller.js.map +1 -1
  49. package/dist/controllers/focus_controller.d.ts +2 -2
  50. package/dist/controllers/focus_controller.js.map +1 -1
  51. package/dist/controllers/form_validation_controller.js.map +1 -1
  52. package/dist/controllers/frame_loading_controller.d.ts +3 -3
  53. package/dist/controllers/frame_loading_controller.js.map +1 -1
  54. package/dist/controllers/highlight_controller.js.map +1 -1
  55. package/dist/controllers/hover_card_controller.d.ts +1 -1
  56. package/dist/controllers/hover_card_controller.js.map +1 -1
  57. package/dist/controllers/idle_controller.d.ts +1 -1
  58. package/dist/controllers/idle_controller.js.map +1 -1
  59. package/dist/controllers/input_mask_controller.js.map +1 -1
  60. package/dist/controllers/intersection_controller.js.map +1 -1
  61. package/dist/controllers/lazy_frame_controller.js.map +1 -1
  62. package/dist/controllers/listbox_controller.js.map +1 -1
  63. package/dist/controllers/local_time_controller.d.ts +1 -1
  64. package/dist/controllers/local_time_controller.js.map +1 -1
  65. package/dist/controllers/masonry_controller.d.ts +1 -1
  66. package/dist/controllers/masonry_controller.js.map +1 -1
  67. package/dist/controllers/menu_controller.d.ts +1 -1
  68. package/dist/controllers/menu_controller.js.map +1 -1
  69. package/dist/controllers/menubar_controller.d.ts +2 -2
  70. package/dist/controllers/menubar_controller.js.map +1 -1
  71. package/dist/controllers/navigation_menu_controller.d.ts +1 -1
  72. package/dist/controllers/navigation_menu_controller.js.map +1 -1
  73. package/dist/controllers/nested_form_controller.js.map +1 -1
  74. package/dist/controllers/network_status_controller.js.map +1 -1
  75. package/dist/controllers/number_input_controller.js.map +1 -1
  76. package/dist/controllers/optimistic_controller.d.ts +23 -10
  77. package/dist/controllers/optimistic_controller.js +141 -20
  78. package/dist/controllers/optimistic_controller.js.map +1 -1
  79. package/dist/controllers/overflow_indicator_controller.d.ts +1 -1
  80. package/dist/controllers/overflow_indicator_controller.js.map +1 -1
  81. package/dist/controllers/overflow_menu_controller.js.map +1 -1
  82. package/dist/controllers/pagination_controller.js.map +1 -1
  83. package/dist/controllers/password_reveal_controller.js.map +1 -1
  84. package/dist/controllers/password_strength_controller.d.ts +2 -1
  85. package/dist/controllers/password_strength_controller.js.map +1 -1
  86. package/dist/controllers/persist_controller.js.map +1 -1
  87. package/dist/controllers/popover_controller.d.ts +1 -1
  88. package/dist/controllers/popover_controller.js.map +1 -1
  89. package/dist/controllers/portal_controller.d.ts +2 -2
  90. package/dist/controllers/portal_controller.js.map +1 -1
  91. package/dist/controllers/radio_group_controller.d.ts +1 -1
  92. package/dist/controllers/radio_group_controller.js.map +1 -1
  93. package/dist/controllers/relative_time_controller.d.ts +3 -3
  94. package/dist/controllers/relative_time_controller.js.map +1 -1
  95. package/dist/controllers/roving_controller.d.ts +1 -1
  96. package/dist/controllers/roving_controller.js.map +1 -1
  97. package/dist/controllers/scroll_area_controller.js.map +1 -1
  98. package/dist/controllers/scrollspy_controller.js.map +1 -1
  99. package/dist/controllers/sidebar_controller.d.ts +1 -1
  100. package/dist/controllers/sidebar_controller.js.map +1 -1
  101. package/dist/controllers/skeleton_controller.d.ts +2 -2
  102. package/dist/controllers/skeleton_controller.js.map +1 -1
  103. package/dist/controllers/spinner_controller.d.ts +3 -3
  104. package/dist/controllers/spinner_controller.js.map +1 -1
  105. package/dist/controllers/sticky_observer_controller.js.map +1 -1
  106. package/dist/controllers/submit_once_controller.d.ts +3 -3
  107. package/dist/controllers/submit_once_controller.js.map +1 -1
  108. package/dist/controllers/switch_controller.js.map +1 -1
  109. package/dist/controllers/textarea_autosize_controller.d.ts +1 -1
  110. package/dist/controllers/textarea_autosize_controller.js.map +1 -1
  111. package/dist/controllers/theme_controller.d.ts +3 -2
  112. package/dist/controllers/theme_controller.js.map +1 -1
  113. package/dist/controllers/toast_controller.js +1 -1
  114. package/dist/controllers/toast_controller.js.map +1 -1
  115. package/dist/controllers/toggle_group_controller.js.map +1 -1
  116. package/dist/controllers/toolbar_controller.d.ts +1 -1
  117. package/dist/controllers/toolbar_controller.js.map +1 -1
  118. package/dist/controllers/tooltip_controller.d.ts +1 -1
  119. package/dist/controllers/tooltip_controller.js.map +1 -1
  120. package/dist/controllers/transition_controller.d.ts +1 -1
  121. package/dist/controllers/transition_controller.js.map +1 -1
  122. package/dist/controllers/tree_view_controller.d.ts +4 -3
  123. package/dist/controllers/tree_view_controller.js.map +1 -1
  124. package/dist/index.js +101 -38
  125. package/dist/index.js.map +1 -1
  126. package/dist/inspector/cli.d.ts +1 -1
  127. package/dist/inspector/cli.js +1 -1
  128. package/dist/inspector/cli.js.map +1 -1
  129. package/dist/inspector/cli_bin.js +1 -1
  130. package/dist/inspector/cli_bin.js.map +1 -1
  131. package/dist/inspector/examples.json +1 -1
  132. package/dist/inspector/manifest.json +6 -3
  133. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1886,6 +1886,15 @@ function parseISOMonthString(monthStr) {
1886
1886
  function toISOMonthString(date) {
1887
1887
  return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}`;
1888
1888
  }
1889
+ function monthLabelFormatter(locale) {
1890
+ const options = { month: "long", year: "numeric" };
1891
+ try {
1892
+ return new Intl.DateTimeFormat(locale, options);
1893
+ } catch (error) {
1894
+ if (!(error instanceof RangeError)) throw error;
1895
+ return new Intl.DateTimeFormat("en", options);
1896
+ }
1897
+ }
1889
1898
 
1890
1899
  // src/controllers/calendar_controller.ts
1891
1900
  var OWNED_DISABLED = "data-stimeo--calendar-owns-disabled";
@@ -2070,8 +2079,7 @@ var CalendarController = class extends Controller {
2070
2079
  const month = monthStart.getMonth() + 1;
2071
2080
  if (this.hasLabelTarget) {
2072
2081
  const lang = document.documentElement.lang || "en";
2073
- const formatter = new Intl.DateTimeFormat(lang, { month: "long", year: "numeric" });
2074
- this.labelTarget.textContent = formatter.format(monthStart);
2082
+ this.labelTarget.textContent = monthLabelFormatter(lang).format(monthStart);
2075
2083
  }
2076
2084
  const days = this.#calculateGridDays(year, month);
2077
2085
  const dayElements = this.dayTargets;
@@ -2323,7 +2331,7 @@ var CarouselController = class extends Controller {
2323
2331
  #handledEvents = /* @__PURE__ */ new WeakSet();
2324
2332
  /**
2325
2333
  * Whether `connect()` has run. Scheduling is already inert outside that window
2326
- * ({@link MicrotaskCoalescer}), so this gates the Value callbacks Stimulus
2334
+ * (`MicrotaskCoalescer`), so this gates the Value callbacks Stimulus
2327
2335
  * delivers ahead of `connect()`.
2328
2336
  */
2329
2337
  #connected = false;
@@ -4383,7 +4391,7 @@ var CommandPaletteController = class _CommandPaletteController extends Controlle
4383
4391
  * re-deriving from the declarative `open` Value (which would slam a user-opened
4384
4392
  * palette shut). The `open` Value only seeds the initial state of a genuinely
4385
4393
  * fresh render. We normalize to a clean closed baseline first so {@link open}
4386
- * runs its full setup — the {@link FocusTrap} is a fresh instance after a
4394
+ * runs its full setup — the `FocusTrap` is a fresh instance after a
4387
4395
  * reconnect and must be re-activated.
4388
4396
  */
4389
4397
  connect() {
@@ -4488,7 +4496,7 @@ var CommandPaletteController = class _CommandPaletteController extends Controlle
4488
4496
  }
4489
4497
  /**
4490
4498
  * Combobox navigation keys (arrows / Home / End / Enter), bound to the input.
4491
- * `Tab` (focus trap) and `Escape` (close) are owned by the {@link FocusTrap} at
4499
+ * `Tab` (focus trap) and `Escape` (close) are owned by the shared `FocusTrap` at
4492
4500
  * the document level, so they work no matter which element inside the dialog has
4493
4501
  * focus — not only the input.
4494
4502
  */
@@ -6566,7 +6574,7 @@ var DateRangePickerController = class extends Controller {
6566
6574
  if (this.#previewDate && !this.#isSelectable(this.#previewDate)) this.#previewDate = "";
6567
6575
  if (this.hasMonthLabelTarget) {
6568
6576
  const lang = document.documentElement.lang || "en";
6569
- const formatter = monthFormatter(lang);
6577
+ const formatter = monthLabelFormatter(lang);
6570
6578
  this.monthLabelTarget.textContent = formatter.format(new Date(year, month - 1, 1));
6571
6579
  }
6572
6580
  const [rangeStart, rangeEnd] = this.#visualRange();
@@ -6721,15 +6729,6 @@ function normalizeISO(value) {
6721
6729
  function orderRange(start, end) {
6722
6730
  return start && end && end < start ? [end, start] : [start, end];
6723
6731
  }
6724
- function monthFormatter(locale) {
6725
- const options = { month: "long", year: "numeric" };
6726
- try {
6727
- return new Intl.DateTimeFormat(locale, options);
6728
- } catch (error) {
6729
- if (!(error instanceof RangeError)) throw error;
6730
- return new Intl.DateTimeFormat("en", options);
6731
- }
6732
- }
6733
6732
  function computePreset(name) {
6734
6733
  const today = /* @__PURE__ */ new Date();
6735
6734
  const todayStr = toISODateString(today);
@@ -7411,7 +7410,7 @@ var DrawerController = class extends Controller {
7411
7410
  * rather than being re-derived from the declarative `open` Value (which would
7412
7411
  * close a user-opened drawer). The `open` Value only seeds a genuinely fresh
7413
7412
  * render. We normalize to a clean closed baseline first so {@link open} runs its
7414
- * full reveal + trap activation — the {@link FocusTrap} is inactive after a
7413
+ * full reveal + trap activation — the `FocusTrap` is inactive after a
7415
7414
  * disconnect and must be re-activated.
7416
7415
  */
7417
7416
  connect() {
@@ -7544,7 +7543,7 @@ var DrawerController = class extends Controller {
7544
7543
  * Runs once the close transition has finished: applies `hidden` to the panel
7545
7544
  * and overlay, then reverts the modal side effects (scroll lock, background
7546
7545
  * `inert`, keydown listener) and restores focus to the opener. Deferring the
7547
- * {@link FocusTrap} teardown to here — rather than at {@link close} time — keeps
7546
+ * `FocusTrap` teardown to here — rather than at {@link close} time — keeps
7548
7547
  * the background unreachable and focus trapped for the whole exit animation.
7549
7548
  */
7550
7549
  #applyHidden(panel) {
@@ -14221,32 +14220,58 @@ var NumberInputController = class _NumberInputController extends Controller {
14221
14220
  this.#ariaValueMax.returnAll();
14222
14221
  }
14223
14222
  };
14224
- var TOGGLED_MARKER = "data-optimistic-toggled";
14223
+ var HIDDEN_MARKER = "data-optimistic-toggled";
14224
+ var BUSY_MARKER = "data-optimistic-busy";
14225
+ var AUTHORED_ABSENT = "absent";
14226
+ var AUTHORED_VALUE = "value:";
14227
+ var SYNTHETIC_SUBMISSION = {};
14228
+ function submissionOf(event) {
14229
+ const detail = event.detail;
14230
+ return detail?.formSubmission ?? SYNTHETIC_SUBMISSION;
14231
+ }
14225
14232
  var OptimisticController = class extends Controller {
14226
14233
  static targets = ["show", "hide"];
14227
14234
  static events = ["commit", "rollback"];
14235
+ /** The submission that owns the applied optimistic state, if any. */
14236
+ #pending = null;
14237
+ #gate = new DetachGate();
14238
+ /** True between `connect()` and `disconnect()`, so a repeat connect rewinds nothing. */
14239
+ #connected = false;
14228
14240
  connect() {
14229
- if (this.element.hasAttribute("data-optimistic")) this.#revert();
14241
+ const restored = !this.#connected && !this.#gate.pending;
14242
+ this.#gate.cancel();
14243
+ this.#connected = true;
14244
+ if (restored && this.element.hasAttribute("data-optimistic")) this.#revert();
14230
14245
  this.element.addEventListener("turbo:submit-start", this.#onSubmitStart);
14231
14246
  this.element.addEventListener("turbo:submit-end", this.#onSubmitEnd);
14232
14247
  }
14233
14248
  disconnect() {
14249
+ this.#connected = false;
14234
14250
  this.element.removeEventListener("turbo:submit-start", this.#onSubmitStart);
14235
14251
  this.element.removeEventListener("turbo:submit-end", this.#onSubmitEnd);
14252
+ this.#gate.disconnected(this, () => {
14253
+ this.#pending = null;
14254
+ });
14236
14255
  }
14237
- #onSubmitStart = () => {
14256
+ #onSubmitStart = (event) => {
14257
+ this.#pending = submissionOf(event);
14258
+ if (this.element instanceof HTMLFormElement && !this.element.hasAttribute(BUSY_MARKER)) {
14259
+ this.element.setAttribute(BUSY_MARKER, AUTHORED_ABSENT);
14260
+ }
14261
+ this.#write(this.element, "aria-busy", "true", BUSY_MARKER);
14238
14262
  this.element.setAttribute("data-optimistic", "true");
14239
- this.element.setAttribute("aria-busy", "true");
14240
- for (const target of this.showTargets) this.#toggleHidden(target, false);
14241
- for (const target of this.hideTargets) this.#toggleHidden(target, true);
14263
+ for (const target of this.showTargets) this.#setHidden(target, false);
14264
+ for (const target of this.hideTargets) this.#setHidden(target, true);
14242
14265
  };
14243
14266
  #onSubmitEnd = (event) => {
14267
+ if (submissionOf(event) !== this.#pending) return;
14268
+ this.#pending = null;
14244
14269
  const success = event.detail?.success === true;
14245
- this.element.removeAttribute("aria-busy");
14246
14270
  if (success) {
14247
14271
  this.element.removeAttribute("data-optimistic");
14272
+ this.#restore(this.element, "aria-busy", BUSY_MARKER, "true");
14248
14273
  for (const target of [...this.showTargets, ...this.hideTargets]) {
14249
- target.removeAttribute(TOGGLED_MARKER);
14274
+ target.removeAttribute(HIDDEN_MARKER);
14250
14275
  }
14251
14276
  this.dispatch("commit");
14252
14277
  } else {
@@ -14254,21 +14279,59 @@ var OptimisticController = class extends Controller {
14254
14279
  this.dispatch("rollback");
14255
14280
  }
14256
14281
  };
14257
- /** Sets `hidden` only when it actually changes, marker-tracking the mutation. */
14258
- #toggleHidden(target, hidden) {
14259
- if (target.hidden === hidden) return;
14260
- target.hidden = hidden;
14261
- target.setAttribute(TOGGLED_MARKER, "true");
14282
+ /** Hides or reveals a target, recording the authored `hidden` on first write. */
14283
+ #setHidden(target, hidden) {
14284
+ if (target.hasAttribute("hidden") === hidden) return;
14285
+ this.#write(target, "hidden", hidden ? "" : null, HIDDEN_MARKER);
14286
+ }
14287
+ /** Writes an attribute, recording what it displaced under `marker` once. */
14288
+ #write(element, attribute, value, marker) {
14289
+ if (!element.hasAttribute(marker)) {
14290
+ const authored = element.getAttribute(attribute);
14291
+ element.setAttribute(
14292
+ marker,
14293
+ authored === null ? AUTHORED_ABSENT : `${AUTHORED_VALUE}${authored}`
14294
+ );
14295
+ }
14296
+ if (value === null) element.removeAttribute(attribute);
14297
+ else element.setAttribute(attribute, value);
14262
14298
  }
14263
- /** Reverts exactly the mutations this controller made (marker-owned only). */
14299
+ /**
14300
+ * Puts back the value `marker` recorded and drops the record.
14301
+ *
14302
+ * `written` is what this controller last put in the attribute. Anything else
14303
+ * there now belongs to whoever wrote it — Turbo owns `aria-busy` on a form and
14304
+ * clears it before the terminal arrives, and a consumer may have moved a face
14305
+ * mid-flight — so the record is dropped without touching the attribute. A
14306
+ * marker this build did not write names no authored value, so the attribute
14307
+ * goes back to being absent.
14308
+ */
14309
+ #restore(element, attribute, marker, written) {
14310
+ const recorded = element.getAttribute(marker);
14311
+ if (recorded === null) return;
14312
+ element.removeAttribute(marker);
14313
+ if (element.getAttribute(attribute) !== written) return;
14314
+ if (recorded.startsWith(AUTHORED_VALUE)) {
14315
+ element.setAttribute(attribute, recorded.slice(AUTHORED_VALUE.length));
14316
+ return;
14317
+ }
14318
+ element.removeAttribute(attribute);
14319
+ }
14320
+ /**
14321
+ * Puts back exactly the markup this controller displaced (record-owned only).
14322
+ *
14323
+ * A face can be registered on both sides, and the hide pass runs last, so what
14324
+ * this controller wrote there is `hidden` — matching it against the reveal's
14325
+ * absent value instead would read as someone else's write and leave the face
14326
+ * hidden. Each target is therefore restored once, against the write it last
14327
+ * received.
14328
+ */
14264
14329
  #revert() {
14265
14330
  this.element.removeAttribute("data-optimistic");
14266
- this.element.removeAttribute("aria-busy");
14267
- for (const target of [...this.showTargets, ...this.hideTargets]) {
14268
- if (target.hasAttribute(TOGGLED_MARKER)) {
14269
- target.hidden = !target.hidden;
14270
- target.removeAttribute(TOGGLED_MARKER);
14271
- }
14331
+ this.#restore(this.element, "aria-busy", BUSY_MARKER, "true");
14332
+ const hidden = new Set(this.hideTargets);
14333
+ for (const target of /* @__PURE__ */ new Set([...this.showTargets, ...this.hideTargets])) {
14334
+ this.#restore(target, "hidden", HIDDEN_MARKER, hidden.has(target) ? "" : null);
14272
14335
  }
14273
14336
  }
14274
14337
  };
@@ -23635,7 +23698,7 @@ var ToastController = class extends Controller {
23635
23698
  static events = ["dismiss", "show"];
23636
23699
  /**
23637
23700
  * Registry for every auto-dismiss and transition-finalize timer the controller
23638
- * schedules. {@link SafeTimeout} owns *registration and teardown only*; the
23701
+ * schedules. `SafeTimeout` owns *registration and teardown only*; the
23639
23702
  * pause/resume remaining-time accounting stays in `#activeTimeouts` so the
23640
23703
  * per-widget WCAG 2.2.1 semantics are not flattened into the helper.
23641
23704
  */