stimeo-ui 0.18.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +31 -2
- data/dist/controllers/command_palette_controller.js +1 -0
- data/dist/controllers/dismissible_controller.js +2 -0
- data/dist/controllers/editable_controller.js +1 -0
- data/dist/controllers/input_mask_controller.js +23 -0
- data/dist/controllers/multi_select_controller.js +21 -1
- data/dist/controllers/pointer_drag_controller.js +6 -1
- data/dist/controllers/popover_controller.js +9 -0
- data/dist/index.js +63 -2
- data/lib/stimeo/ui/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 54a0ca530097c890ee9b7292939afa617a822905abb0c8b93ee841c9bbc196b8
|
|
4
|
+
data.tar.gz: 7ffbb49e1e7c617aadd557a774d0d88fd4d79361d56aa3ea3b7e656d492e2adf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5b1c8cde31c41ff03270c5f8e5d94cfe75b453eaf89d0bd6dcbca1bf095a360b7669e2012860812c5b7b4fa0e363cba5c6dbb156419f971ba042af8c46dff4d7
|
|
7
|
+
data.tar.gz: 1ced263a41d46a475685c30b0e636b14fe6307aa310ce7d80ec5fd645662c6eb16d1af05c6dc1a3d006cb1da0d5506af14072e1706d2ddff932e82a2b6260847
|
data/CHANGELOG.md
CHANGED
|
@@ -7,7 +7,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
While the version is `0.x`, the public API (the `stimeo--*` data attributes) may
|
|
8
8
|
change between releases.
|
|
9
9
|
|
|
10
|
-
## [
|
|
10
|
+
## [0.18.1] - 2026-10-31
|
|
11
|
+
|
|
12
|
+
Patch release focused on keyboard ownership, focus handoff, masked selections,
|
|
13
|
+
and Inspector compatibility.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Inspector host contracts can admit the `<input>` types a controller composes
|
|
18
|
+
with instead of replacing (`inputTypes`); any other `<input>` on such a host is
|
|
19
|
+
still reported as `invalid-host`. The manifest carries this as `schemaVersion`
|
|
20
|
+
17. Update Inspector engines and the VS Code extension together with their
|
|
21
|
+
manifest; an older engine reading it may report an admitted input as
|
|
22
|
+
`invalid-host`.
|
|
23
|
+
- Refresh pinned build and test tooling: Biome 2.6.3, happy-dom 21.0.4,
|
|
24
|
+
tsup 9.0.0, and Rollup 4.66.0.
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- command-palette and editable: respect keyboard events already handled by another
|
|
29
|
+
listener, including global shortcuts and F2.
|
|
30
|
+
- multi-select: close on Tab from a chip and keep the list closed when that Tab
|
|
31
|
+
reaches the input.
|
|
32
|
+
- popover: close when focus reaches an unrelated control after first falling to
|
|
33
|
+
the document body, while preserving the destination focus.
|
|
34
|
+
- dismissible: release focus from hidden content when no fallback can receive
|
|
35
|
+
focus.
|
|
36
|
+
- input-mask: preserve selected text when a single invalid typed character would
|
|
37
|
+
replace it.
|
|
38
|
+
- pointer-drag: cancel active sessions when a handle loses its target declaration
|
|
39
|
+
and restore the fallback handle when no declared handles remain.
|
|
11
40
|
|
|
12
41
|
## [0.18.0] - 2026-10-22
|
|
13
42
|
|
|
@@ -1411,7 +1440,7 @@ Initial public alpha: 101 behavior-only, accessible Stimulus controllers driven
|
|
|
1411
1440
|
by `data-*` attributes, shipping no CSS. Published to npm (with provenance) and
|
|
1412
1441
|
RubyGems.
|
|
1413
1442
|
|
|
1414
|
-
[
|
|
1443
|
+
[0.18.1]: https://github.com/taiyaky/stimeo-ui/releases/tag/v0.18.1
|
|
1415
1444
|
[0.18.0]: https://github.com/taiyaky/stimeo-ui/releases/tag/v0.18.0
|
|
1416
1445
|
[0.17.0]: https://github.com/taiyaky/stimeo-ui/releases/tag/v0.17.0
|
|
1417
1446
|
[0.16.0]: https://github.com/taiyaky/stimeo-ui/releases/tag/v0.16.0
|
|
@@ -1629,6 +1629,7 @@ var CommandPaletteController = class _CommandPaletteController extends Controlle
|
|
|
1629
1629
|
return this.hasDialogTarget && !this.dialogTarget.hidden;
|
|
1630
1630
|
}
|
|
1631
1631
|
#onGlobalKeydown = (event) => {
|
|
1632
|
+
if (event.defaultPrevented) return;
|
|
1632
1633
|
if (this.#composition.isComposing(event) || !this.#matchesHotkey(event)) return;
|
|
1633
1634
|
event.preventDefault();
|
|
1634
1635
|
this.toggle();
|
|
@@ -323,6 +323,8 @@ var DismissibleController = class extends Controller {
|
|
|
323
323
|
if (document.activeElement === candidate) return;
|
|
324
324
|
}
|
|
325
325
|
document.body.focus();
|
|
326
|
+
const remaining = document.activeElement;
|
|
327
|
+
if (remaining instanceof HTMLElement && root.contains(remaining)) remaining.blur();
|
|
326
328
|
}
|
|
327
329
|
*#focusFallbacks(root) {
|
|
328
330
|
const explicitFallback = this.hasFallbackTarget ? this.fallbackTarget : null;
|
|
@@ -590,6 +590,27 @@ var InputMaskController = class extends Controller {
|
|
|
590
590
|
#textBeforeComposition = "";
|
|
591
591
|
#formatted = null;
|
|
592
592
|
#shown = { result: null, empty: true };
|
|
593
|
+
#edits = new ListenerSet();
|
|
594
|
+
#onBeforeInput = (event) => {
|
|
595
|
+
const data = event.data;
|
|
596
|
+
if (event.defaultPrevented || !event.cancelable || event.inputType !== "insertText" || data === null || Array.from(data).length !== 1 || !this.#started || this.#composition.isComposing(event))
|
|
597
|
+
return;
|
|
598
|
+
const input = this.element;
|
|
599
|
+
const start = input.selectionStart;
|
|
600
|
+
const end = input.selectionEnd;
|
|
601
|
+
if (start === null || end === null || start === end || input.readOnly || input.disabled || inheritsFieldsetDisabled(input) || !input.isConnected || !this.application.element.contains(input) || !(input.getAttribute("data-controller") ?? "").split(/\s+/).includes(this.identifier) || this.patternValue === "" || this.#formatted !== this.#declared || input.value !== this.#lastValue)
|
|
602
|
+
return;
|
|
603
|
+
const prefix = applyMask(input.value.slice(0, start), this.patternValue, this.#tokens);
|
|
604
|
+
for (const character of Array.from(this.patternValue).slice(prefix.tokenFlags.length)) {
|
|
605
|
+
const token = this.#tokens.get(character);
|
|
606
|
+
if (token) {
|
|
607
|
+
if (acceptedForm(token, data) === null) event.preventDefault();
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
if (halfWidthChar(data) === halfWidthChar(character)) return;
|
|
611
|
+
}
|
|
612
|
+
event.preventDefault();
|
|
613
|
+
};
|
|
593
614
|
#composition = new CompositionTracker({
|
|
594
615
|
onStart: () => {
|
|
595
616
|
this.#textBeforeComposition = this.element.value;
|
|
@@ -625,6 +646,7 @@ var InputMaskController = class extends Controller {
|
|
|
625
646
|
this.#morph.observe(this.element);
|
|
626
647
|
this.#started = true;
|
|
627
648
|
this.#composition.observe(this.element);
|
|
649
|
+
this.#edits.add(this.element, "beforeinput", this.#onBeforeInput);
|
|
628
650
|
if (!this.unmaskToHiddenValue) this.#withdraw();
|
|
629
651
|
if (this.#composition.isComposing()) {
|
|
630
652
|
this.#reformat("reconcile");
|
|
@@ -639,6 +661,7 @@ var InputMaskController = class extends Controller {
|
|
|
639
661
|
disconnect() {
|
|
640
662
|
this.#morph.disconnect();
|
|
641
663
|
this.#started = false;
|
|
664
|
+
this.#edits.dispose();
|
|
642
665
|
this.#composition.disconnect();
|
|
643
666
|
this.#adoption.clearAll();
|
|
644
667
|
this.#gate.disconnected(this, () => this.#retractRaw());
|
|
@@ -1118,7 +1118,9 @@ var MultiSelectController = class _MultiSelectController extends Controller {
|
|
|
1118
1118
|
focusAfterEnd: () => this.#focusInput()
|
|
1119
1119
|
});
|
|
1120
1120
|
#listeners = new ListenerSet();
|
|
1121
|
+
#tab = null;
|
|
1121
1122
|
connect() {
|
|
1123
|
+
this.#tab = null;
|
|
1122
1124
|
this.#tabindex.reclaim(this.element);
|
|
1123
1125
|
this.#rows.connect();
|
|
1124
1126
|
this.#normalizeSelection([]);
|
|
@@ -1130,6 +1132,9 @@ var MultiSelectController = class _MultiSelectController extends Controller {
|
|
|
1130
1132
|
this.#selectionValues = this.#values;
|
|
1131
1133
|
this.#syncFields();
|
|
1132
1134
|
this.#listeners.add(document, "click", this.#onOutsideClick, { capture: true });
|
|
1135
|
+
this.#listeners.add(this.element, "keydown", this.#onTab);
|
|
1136
|
+
for (const type of ["focus", "keydown", "keyup", "pointerdown"])
|
|
1137
|
+
this.#listeners.add(document, type, this.#trackTab, { capture: true });
|
|
1133
1138
|
this.#connected = true;
|
|
1134
1139
|
this.#reconcile.observe(this.element);
|
|
1135
1140
|
}
|
|
@@ -1151,6 +1156,7 @@ var MultiSelectController = class _MultiSelectController extends Controller {
|
|
|
1151
1156
|
this.#composition.disconnect();
|
|
1152
1157
|
this.#chipRow.disconnect();
|
|
1153
1158
|
this.#listeners.dispose();
|
|
1159
|
+
this.#tab = null;
|
|
1154
1160
|
this.#releaseTabindex();
|
|
1155
1161
|
}
|
|
1156
1162
|
optionTargetConnected() {
|
|
@@ -1320,7 +1326,11 @@ var MultiSelectController = class _MultiSelectController extends Controller {
|
|
|
1320
1326
|
this.#setActive(visible[0] ?? null);
|
|
1321
1327
|
this.dispatch("filter", { detail: { query } });
|
|
1322
1328
|
}
|
|
1323
|
-
open() {
|
|
1329
|
+
open(event) {
|
|
1330
|
+
if (event instanceof FocusEvent && event === this.#tab) {
|
|
1331
|
+
this.#tab = null;
|
|
1332
|
+
return;
|
|
1333
|
+
}
|
|
1324
1334
|
if (!this.hasListTarget || !this.hasInputTarget) {
|
|
1325
1335
|
this.#reflectEmpty();
|
|
1326
1336
|
return;
|
|
@@ -1407,6 +1417,16 @@ var MultiSelectController = class _MultiSelectController extends Controller {
|
|
|
1407
1417
|
break;
|
|
1408
1418
|
}
|
|
1409
1419
|
}
|
|
1420
|
+
#onTab = (event) => {
|
|
1421
|
+
if (event.key !== "Tab" || event.defaultPrevented || event.isComposing || !this.hasTagsTarget || !this.tagsTarget.contains(event.target))
|
|
1422
|
+
return;
|
|
1423
|
+
this.#tab = event;
|
|
1424
|
+
this.close();
|
|
1425
|
+
};
|
|
1426
|
+
#trackTab = (event) => {
|
|
1427
|
+
const key = this.#tab;
|
|
1428
|
+
this.#tab = event.type === "focus" && key instanceof KeyboardEvent && !key.defaultPrevented && event.target === this.inputTargets[0] ? event : null;
|
|
1429
|
+
};
|
|
1410
1430
|
toggleOption(source) {
|
|
1411
1431
|
const { event, host, origin, reason } = actionSource(source);
|
|
1412
1432
|
if (origin && origin.closest(`[data-controller~="${this.identifier}"]`) !== this.element)
|
|
@@ -408,6 +408,7 @@ var PointerDragController = class _PointerDragController extends Controller {
|
|
|
408
408
|
#tabindex = new TabindexLoan("0", this.identifier, { preserveFocus: true });
|
|
409
409
|
#pointer = null;
|
|
410
410
|
#keyboard = null;
|
|
411
|
+
#connected = false;
|
|
411
412
|
#keyboardFocusSession = null;
|
|
412
413
|
#listeners = new ListenerSet();
|
|
413
414
|
#shadowFocus = new ListenerSet();
|
|
@@ -421,6 +422,7 @@ var PointerDragController = class _PointerDragController extends Controller {
|
|
|
421
422
|
this.#reflectSession();
|
|
422
423
|
});
|
|
423
424
|
connect() {
|
|
425
|
+
this.#connected = true;
|
|
424
426
|
this.#morphRender.observe(this.element);
|
|
425
427
|
if (!this.#pointer && !this.#keyboard) this.#followOutput = null;
|
|
426
428
|
this.#gate.cancel();
|
|
@@ -438,6 +440,7 @@ var PointerDragController = class _PointerDragController extends Controller {
|
|
|
438
440
|
}
|
|
439
441
|
}
|
|
440
442
|
disconnect() {
|
|
443
|
+
this.#connected = false;
|
|
441
444
|
this.#morphRender.disconnect();
|
|
442
445
|
this.#listeners.dispose();
|
|
443
446
|
this.#shadowFocus.dispose();
|
|
@@ -464,7 +467,9 @@ var PointerDragController = class _PointerDragController extends Controller {
|
|
|
464
467
|
}
|
|
465
468
|
handleTargetDisconnected(handle) {
|
|
466
469
|
this.#restoreHandle(handle);
|
|
467
|
-
if (this
|
|
470
|
+
if (!this.#connected) return;
|
|
471
|
+
if (this.element.contains(handle) && (this.handleTargets.includes(handle) || DetachGate.isDetached(this)))
|
|
472
|
+
return;
|
|
468
473
|
const interrupted = this.#pointer?.handle === handle && this.#pointer.started ? this.#pointer.pointerType : this.#keyboard?.handle === handle ? "keyboard" : null;
|
|
469
474
|
if (this.#pointer?.handle === handle) this.#endPointerSession();
|
|
470
475
|
if (this.#keyboard?.handle === handle) this.#clearKeyboardSession();
|
|
@@ -369,6 +369,7 @@ var PopoverController = class extends Controller {
|
|
|
369
369
|
this.#close("api");
|
|
370
370
|
this.#listeners.add(document, "click", this.#onOutsideClick, { capture: true });
|
|
371
371
|
this.#listeners.add(this.element, "focusout", this.#onFocusOut);
|
|
372
|
+
this.#listeners.add(document, "focusin", this.#onDocumentFocusIn, { capture: true });
|
|
372
373
|
this.#connected = true;
|
|
373
374
|
this.#reporting = true;
|
|
374
375
|
}
|
|
@@ -475,6 +476,14 @@ var PopoverController = class extends Controller {
|
|
|
475
476
|
if (!(next instanceof Node) || this.element.contains(next)) return;
|
|
476
477
|
this.#close("focus");
|
|
477
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
|
+
};
|
|
478
487
|
get #isOpen() {
|
|
479
488
|
return this.hasPanelTarget && !this.panelTarget.hidden;
|
|
480
489
|
}
|
data/dist/index.js
CHANGED
|
@@ -5735,6 +5735,7 @@ var CommandPaletteController = class _CommandPaletteController extends Controlle
|
|
|
5735
5735
|
return this.hasDialogTarget && !this.dialogTarget.hidden;
|
|
5736
5736
|
}
|
|
5737
5737
|
#onGlobalKeydown = (event) => {
|
|
5738
|
+
if (event.defaultPrevented) return;
|
|
5738
5739
|
if (this.#composition.isComposing(event) || !this.#matchesHotkey(event)) return;
|
|
5739
5740
|
event.preventDefault();
|
|
5740
5741
|
this.toggle();
|
|
@@ -9037,6 +9038,8 @@ var DismissibleController = class extends Controller {
|
|
|
9037
9038
|
if (document.activeElement === candidate) return;
|
|
9038
9039
|
}
|
|
9039
9040
|
document.body.focus();
|
|
9041
|
+
const remaining = document.activeElement;
|
|
9042
|
+
if (remaining instanceof HTMLElement && root.contains(remaining)) remaining.blur();
|
|
9040
9043
|
}
|
|
9041
9044
|
*#focusFallbacks(root) {
|
|
9042
9045
|
const explicitFallback = this.hasFallbackTarget ? this.fallbackTarget : null;
|
|
@@ -9482,6 +9485,7 @@ var EditableController = class extends Controller {
|
|
|
9482
9485
|
this.#revertValue = null;
|
|
9483
9486
|
}
|
|
9484
9487
|
onDisplayKeydown(event) {
|
|
9488
|
+
if (event.defaultPrevented) return;
|
|
9485
9489
|
if (event.key === "F2") {
|
|
9486
9490
|
event.preventDefault();
|
|
9487
9491
|
this.edit();
|
|
@@ -11666,6 +11670,27 @@ var InputMaskController = class extends Controller {
|
|
|
11666
11670
|
#textBeforeComposition = "";
|
|
11667
11671
|
#formatted = null;
|
|
11668
11672
|
#shown = { result: null, empty: true };
|
|
11673
|
+
#edits = new ListenerSet();
|
|
11674
|
+
#onBeforeInput = (event) => {
|
|
11675
|
+
const data = event.data;
|
|
11676
|
+
if (event.defaultPrevented || !event.cancelable || event.inputType !== "insertText" || data === null || Array.from(data).length !== 1 || !this.#started || this.#composition.isComposing(event))
|
|
11677
|
+
return;
|
|
11678
|
+
const input = this.element;
|
|
11679
|
+
const start = input.selectionStart;
|
|
11680
|
+
const end = input.selectionEnd;
|
|
11681
|
+
if (start === null || end === null || start === end || input.readOnly || input.disabled || inheritsFieldsetDisabled(input) || !input.isConnected || !this.application.element.contains(input) || !(input.getAttribute("data-controller") ?? "").split(/\s+/).includes(this.identifier) || this.patternValue === "" || this.#formatted !== this.#declared || input.value !== this.#lastValue)
|
|
11682
|
+
return;
|
|
11683
|
+
const prefix = applyMask(input.value.slice(0, start), this.patternValue, this.#tokens);
|
|
11684
|
+
for (const character of Array.from(this.patternValue).slice(prefix.tokenFlags.length)) {
|
|
11685
|
+
const token = this.#tokens.get(character);
|
|
11686
|
+
if (token) {
|
|
11687
|
+
if (acceptedForm(token, data) === null) event.preventDefault();
|
|
11688
|
+
return;
|
|
11689
|
+
}
|
|
11690
|
+
if (halfWidthChar(data) === halfWidthChar(character)) return;
|
|
11691
|
+
}
|
|
11692
|
+
event.preventDefault();
|
|
11693
|
+
};
|
|
11669
11694
|
#composition = new CompositionTracker({
|
|
11670
11695
|
onStart: () => {
|
|
11671
11696
|
this.#textBeforeComposition = this.element.value;
|
|
@@ -11701,6 +11726,7 @@ var InputMaskController = class extends Controller {
|
|
|
11701
11726
|
this.#morph.observe(this.element);
|
|
11702
11727
|
this.#started = true;
|
|
11703
11728
|
this.#composition.observe(this.element);
|
|
11729
|
+
this.#edits.add(this.element, "beforeinput", this.#onBeforeInput);
|
|
11704
11730
|
if (!this.unmaskToHiddenValue) this.#withdraw();
|
|
11705
11731
|
if (this.#composition.isComposing()) {
|
|
11706
11732
|
this.#reformat("reconcile");
|
|
@@ -11715,6 +11741,7 @@ var InputMaskController = class extends Controller {
|
|
|
11715
11741
|
disconnect() {
|
|
11716
11742
|
this.#morph.disconnect();
|
|
11717
11743
|
this.#started = false;
|
|
11744
|
+
this.#edits.dispose();
|
|
11718
11745
|
this.#composition.disconnect();
|
|
11719
11746
|
this.#adoption.clearAll();
|
|
11720
11747
|
this.#gate.disconnected(this, () => this.#retractRaw());
|
|
@@ -13885,7 +13912,9 @@ var MultiSelectController = class _MultiSelectController extends Controller {
|
|
|
13885
13912
|
focusAfterEnd: () => this.#focusInput()
|
|
13886
13913
|
});
|
|
13887
13914
|
#listeners = new ListenerSet();
|
|
13915
|
+
#tab = null;
|
|
13888
13916
|
connect() {
|
|
13917
|
+
this.#tab = null;
|
|
13889
13918
|
this.#tabindex.reclaim(this.element);
|
|
13890
13919
|
this.#rows.connect();
|
|
13891
13920
|
this.#normalizeSelection([]);
|
|
@@ -13897,6 +13926,9 @@ var MultiSelectController = class _MultiSelectController extends Controller {
|
|
|
13897
13926
|
this.#selectionValues = this.#values;
|
|
13898
13927
|
this.#syncFields();
|
|
13899
13928
|
this.#listeners.add(document, "click", this.#onOutsideClick, { capture: true });
|
|
13929
|
+
this.#listeners.add(this.element, "keydown", this.#onTab);
|
|
13930
|
+
for (const type of ["focus", "keydown", "keyup", "pointerdown"])
|
|
13931
|
+
this.#listeners.add(document, type, this.#trackTab, { capture: true });
|
|
13900
13932
|
this.#connected = true;
|
|
13901
13933
|
this.#reconcile.observe(this.element);
|
|
13902
13934
|
}
|
|
@@ -13918,6 +13950,7 @@ var MultiSelectController = class _MultiSelectController extends Controller {
|
|
|
13918
13950
|
this.#composition.disconnect();
|
|
13919
13951
|
this.#chipRow.disconnect();
|
|
13920
13952
|
this.#listeners.dispose();
|
|
13953
|
+
this.#tab = null;
|
|
13921
13954
|
this.#releaseTabindex();
|
|
13922
13955
|
}
|
|
13923
13956
|
optionTargetConnected() {
|
|
@@ -14087,7 +14120,11 @@ var MultiSelectController = class _MultiSelectController extends Controller {
|
|
|
14087
14120
|
this.#setActive(visible[0] ?? null);
|
|
14088
14121
|
this.dispatch("filter", { detail: { query } });
|
|
14089
14122
|
}
|
|
14090
|
-
open() {
|
|
14123
|
+
open(event) {
|
|
14124
|
+
if (event instanceof FocusEvent && event === this.#tab) {
|
|
14125
|
+
this.#tab = null;
|
|
14126
|
+
return;
|
|
14127
|
+
}
|
|
14091
14128
|
if (!this.hasListTarget || !this.hasInputTarget) {
|
|
14092
14129
|
this.#reflectEmpty();
|
|
14093
14130
|
return;
|
|
@@ -14174,6 +14211,16 @@ var MultiSelectController = class _MultiSelectController extends Controller {
|
|
|
14174
14211
|
break;
|
|
14175
14212
|
}
|
|
14176
14213
|
}
|
|
14214
|
+
#onTab = (event) => {
|
|
14215
|
+
if (event.key !== "Tab" || event.defaultPrevented || event.isComposing || !this.hasTagsTarget || !this.tagsTarget.contains(event.target))
|
|
14216
|
+
return;
|
|
14217
|
+
this.#tab = event;
|
|
14218
|
+
this.close();
|
|
14219
|
+
};
|
|
14220
|
+
#trackTab = (event) => {
|
|
14221
|
+
const key = this.#tab;
|
|
14222
|
+
this.#tab = event.type === "focus" && key instanceof KeyboardEvent && !key.defaultPrevented && event.target === this.inputTargets[0] ? event : null;
|
|
14223
|
+
};
|
|
14177
14224
|
toggleOption(source) {
|
|
14178
14225
|
const { event, host, origin, reason } = actionSource(source);
|
|
14179
14226
|
if (origin && origin.closest(`[data-controller~="${this.identifier}"]`) !== this.element)
|
|
@@ -17986,6 +18033,7 @@ var PointerDragController = class _PointerDragController extends Controller {
|
|
|
17986
18033
|
#tabindex = new TabindexLoan("0", this.identifier, { preserveFocus: true });
|
|
17987
18034
|
#pointer = null;
|
|
17988
18035
|
#keyboard = null;
|
|
18036
|
+
#connected = false;
|
|
17989
18037
|
#keyboardFocusSession = null;
|
|
17990
18038
|
#listeners = new ListenerSet();
|
|
17991
18039
|
#shadowFocus = new ListenerSet();
|
|
@@ -17999,6 +18047,7 @@ var PointerDragController = class _PointerDragController extends Controller {
|
|
|
17999
18047
|
this.#reflectSession();
|
|
18000
18048
|
});
|
|
18001
18049
|
connect() {
|
|
18050
|
+
this.#connected = true;
|
|
18002
18051
|
this.#morphRender.observe(this.element);
|
|
18003
18052
|
if (!this.#pointer && !this.#keyboard) this.#followOutput = null;
|
|
18004
18053
|
this.#gate.cancel();
|
|
@@ -18016,6 +18065,7 @@ var PointerDragController = class _PointerDragController extends Controller {
|
|
|
18016
18065
|
}
|
|
18017
18066
|
}
|
|
18018
18067
|
disconnect() {
|
|
18068
|
+
this.#connected = false;
|
|
18019
18069
|
this.#morphRender.disconnect();
|
|
18020
18070
|
this.#listeners.dispose();
|
|
18021
18071
|
this.#shadowFocus.dispose();
|
|
@@ -18042,7 +18092,9 @@ var PointerDragController = class _PointerDragController extends Controller {
|
|
|
18042
18092
|
}
|
|
18043
18093
|
handleTargetDisconnected(handle) {
|
|
18044
18094
|
this.#restoreHandle(handle);
|
|
18045
|
-
if (this
|
|
18095
|
+
if (!this.#connected) return;
|
|
18096
|
+
if (this.element.contains(handle) && (this.handleTargets.includes(handle) || DetachGate.isDetached(this)))
|
|
18097
|
+
return;
|
|
18046
18098
|
const interrupted = this.#pointer?.handle === handle && this.#pointer.started ? this.#pointer.pointerType : this.#keyboard?.handle === handle ? "keyboard" : null;
|
|
18047
18099
|
if (this.#pointer?.handle === handle) this.#endPointerSession();
|
|
18048
18100
|
if (this.#keyboard?.handle === handle) this.#clearKeyboardSession();
|
|
@@ -18397,6 +18449,7 @@ var PopoverController = class extends Controller {
|
|
|
18397
18449
|
this.#close("api");
|
|
18398
18450
|
this.#listeners.add(document, "click", this.#onOutsideClick, { capture: true });
|
|
18399
18451
|
this.#listeners.add(this.element, "focusout", this.#onFocusOut);
|
|
18452
|
+
this.#listeners.add(document, "focusin", this.#onDocumentFocusIn, { capture: true });
|
|
18400
18453
|
this.#connected = true;
|
|
18401
18454
|
this.#reporting = true;
|
|
18402
18455
|
}
|
|
@@ -18503,6 +18556,14 @@ var PopoverController = class extends Controller {
|
|
|
18503
18556
|
if (!(next instanceof Node) || this.element.contains(next)) return;
|
|
18504
18557
|
this.#close("focus");
|
|
18505
18558
|
};
|
|
18559
|
+
#onDocumentFocusIn = (event) => {
|
|
18560
|
+
if (!this.#closable) return;
|
|
18561
|
+
const target = event.target;
|
|
18562
|
+
if (!(target instanceof Node) || target === document.body || this.element.contains(target)) {
|
|
18563
|
+
return;
|
|
18564
|
+
}
|
|
18565
|
+
this.#close("focus");
|
|
18566
|
+
};
|
|
18506
18567
|
get #isOpen() {
|
|
18507
18568
|
return this.hasPanelTarget && !this.panelTarget.hidden;
|
|
18508
18569
|
}
|
data/lib/stimeo/ui/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: stimeo-ui
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.18.
|
|
4
|
+
version: 0.18.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Stimeo Labs
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-31 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: railties
|