stimeo-ui 0.15.0 → 0.17.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +209 -0
- data/README.md +128 -1
- data/dist/cable/index.js +392 -417
- data/dist/controllers/accordion_controller.js +228 -28
- data/dist/controllers/alert_dialog_controller.js +862 -221
- data/dist/controllers/announcer_controller.js +135 -191
- data/dist/controllers/aspect_ratio_controller.js +0 -10
- data/dist/controllers/auto_submit_controller.js +295 -110
- data/dist/controllers/avatar_controller.js +172 -106
- data/dist/controllers/breadcrumb_controller.js +0 -129
- data/dist/controllers/bulk_select_controller.js +264 -53
- data/dist/controllers/calendar_controller.js +346 -180
- data/dist/controllers/carousel_controller.js +587 -300
- data/dist/controllers/character_counter_controller.js +271 -143
- data/dist/controllers/checkbox_controller.js +77 -75
- data/dist/controllers/clipboard_controller.js +187 -108
- data/dist/controllers/collapsible_controller.js +374 -108
- data/dist/controllers/color_picker_controller.js +183 -127
- data/dist/controllers/combobox_controller.js +426 -109
- data/dist/controllers/command_palette_controller.js +994 -350
- data/dist/controllers/conditional_fields_controller.js +212 -125
- data/dist/controllers/confirm_controller.js +939 -245
- data/dist/controllers/context_menu_controller.js +275 -127
- data/dist/controllers/count_up_controller.js +73 -21
- data/dist/controllers/countdown_controller.js +235 -97
- data/dist/controllers/currency_input_controller.js +241 -118
- data/dist/controllers/data_grid_controller.js +229 -135
- data/dist/controllers/date_range_picker_controller.js +359 -165
- data/dist/controllers/dialog_controller.js +887 -225
- data/dist/controllers/direct_upload_controller.js +80 -142
- data/dist/controllers/dirty_form_controller.js +26 -47
- data/dist/controllers/dismissible_controller.js +175 -20
- data/dist/controllers/drawer_controller.js +963 -336
- data/dist/controllers/dropdown_controller.js +342 -85
- data/dist/controllers/editable_controller.js +182 -58
- data/dist/controllers/empty_state_controller.js +67 -53
- data/dist/controllers/file_dropzone_controller.js +426 -229
- data/dist/controllers/filter_controller.js +78 -36
- data/dist/controllers/flash_controller.js +328 -211
- data/dist/controllers/focus_controller.js +654 -239
- data/dist/controllers/form_field_controller.js +153 -136
- data/dist/controllers/form_validation_controller.js +29 -96
- data/dist/controllers/frame_loading_controller.js +263 -198
- data/dist/controllers/highlight_controller.js +119 -70
- data/dist/controllers/hover_card_controller.js +335 -118
- data/dist/controllers/idle_controller.js +316 -65
- data/dist/controllers/input_mask_controller.js +116 -61
- data/dist/controllers/intersection_controller.js +147 -103
- data/dist/controllers/lazy_frame_controller.js +9 -56
- data/dist/controllers/listbox_controller.js +413 -153
- data/dist/controllers/local_time_controller.js +54 -64
- data/dist/controllers/masonry_controller.js +70 -95
- data/dist/controllers/menu_controller.js +254 -167
- data/dist/controllers/menubar_controller.js +206 -331
- data/dist/controllers/meter_controller.js +159 -71
- data/dist/controllers/multi_select_controller.js +797 -388
- data/dist/controllers/navigation_menu_controller.js +156 -231
- data/dist/controllers/nested_form_controller.js +373 -174
- data/dist/controllers/network_status_controller.js +241 -45
- data/dist/controllers/number_input_controller.js +387 -227
- data/dist/controllers/optimistic_controller.js +28 -75
- data/dist/controllers/otp_controller.js +344 -196
- data/dist/controllers/overflow_indicator_controller.js +167 -93
- data/dist/controllers/overflow_menu_controller.js +408 -277
- data/dist/controllers/pagination_controller.js +342 -120
- data/dist/controllers/password_reveal_controller.js +424 -99
- data/dist/controllers/password_strength_controller.js +99 -153
- data/dist/controllers/persist_controller.js +252 -96
- data/dist/controllers/pointer_drag_controller.js +263 -164
- data/dist/controllers/popover_controller.js +267 -94
- data/dist/controllers/portal_controller.js +209 -72
- data/dist/controllers/preview_guard_controller.js +243 -112
- data/dist/controllers/progress_controller.js +132 -59
- data/dist/controllers/radio_group_controller.js +138 -133
- data/dist/controllers/range_slider_controller.js +245 -112
- data/dist/controllers/rating_controller.js +429 -194
- data/dist/controllers/read_more_controller.js +185 -47
- data/dist/controllers/reading_progress_controller.js +147 -135
- data/dist/controllers/relative_time_controller.js +145 -110
- data/dist/controllers/{reset_before_cache_controller.js → reset_on_restore_controller.js} +97 -38
- data/dist/controllers/resizable_controller.js +294 -118
- data/dist/controllers/roving_controller.js +39 -84
- data/dist/controllers/scroll_area_controller.js +428 -221
- data/dist/controllers/scroll_restore_controller.js +0 -53
- data/dist/controllers/scroll_visibility_controller.js +395 -146
- data/dist/controllers/scrollspy_controller.js +181 -236
- data/dist/controllers/separator_controller.js +288 -132
- data/dist/controllers/sidebar_controller.js +1071 -375
- data/dist/controllers/skeleton_controller.js +248 -92
- data/dist/controllers/slider_controller.js +211 -96
- data/dist/controllers/smart_sticky_header_controller.js +163 -54
- data/dist/controllers/sortable_controller.js +13 -110
- data/dist/controllers/spinner_controller.js +277 -161
- data/dist/controllers/step_indicator_controller.js +107 -53
- data/dist/controllers/stepper_controller.js +171 -48
- data/dist/controllers/stick_to_bottom_controller.js +310 -116
- data/dist/controllers/sticky_observer_controller.js +214 -49
- data/dist/controllers/submit_once_controller.js +294 -192
- data/dist/controllers/switch_controller.js +107 -43
- data/dist/controllers/tabs_controller.js +50 -25
- data/dist/controllers/tags_input_controller.js +290 -149
- data/dist/controllers/textarea_autosize_controller.js +71 -58
- data/dist/controllers/theme_controller.js +148 -80
- data/dist/controllers/time_picker_controller.js +162 -81
- data/dist/controllers/toast_controller.js +365 -193
- data/dist/controllers/toggle_group_controller.js +194 -99
- data/dist/controllers/toolbar_controller.js +92 -90
- data/dist/controllers/tooltip_controller.js +185 -125
- data/dist/controllers/transition_controller.js +123 -115
- data/dist/controllers/tree_view_controller.js +248 -290
- data/dist/index.js +8649 -8572
- data/dist/positioning/index.js +148 -45
- data/lib/stimeo/ui/version.rb +1 -1
- metadata +3 -3
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
function sharedRegistry(key, create) {
|
|
4
|
+
const symbol = Symbol.for(key);
|
|
5
|
+
const scope = globalThis;
|
|
6
|
+
const existing = scope[symbol];
|
|
7
|
+
if (existing !== void 0) return existing;
|
|
8
|
+
const registry = create();
|
|
9
|
+
Object.defineProperty(globalThis, symbol, { value: registry });
|
|
10
|
+
return registry;
|
|
11
|
+
}
|
|
4
12
|
|
|
5
|
-
// src/utils/escape_layer.ts
|
|
6
13
|
var EscapeLayer = class _EscapeLayer {
|
|
7
|
-
static #registries =
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
#claims = null;
|
|
13
|
-
/**
|
|
14
|
-
* Activates this layer at the top of its document's Escape stack, installing
|
|
15
|
-
* the document's shared resolver listener if this is its first layer.
|
|
16
|
-
* Re-activating an already-active layer moves it to the top.
|
|
17
|
-
*/
|
|
14
|
+
static #registries = sharedRegistry(
|
|
15
|
+
"stimeo-ui.escape-layer.registry.v1",
|
|
16
|
+
() => /* @__PURE__ */ new WeakMap()
|
|
17
|
+
);
|
|
18
|
+
#active = null;
|
|
18
19
|
activate(ownerDocument = document, options) {
|
|
19
20
|
this.deactivate();
|
|
20
21
|
let registry = _EscapeLayer.#registries.get(ownerDocument);
|
|
@@ -23,44 +24,31 @@ var EscapeLayer = class _EscapeLayer {
|
|
|
23
24
|
_EscapeLayer.#registries.set(ownerDocument, registry);
|
|
24
25
|
ownerDocument.addEventListener("keydown", registry.onKeydown);
|
|
25
26
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
this.#
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Removes this layer from its document's Escape stack, uninstalling the
|
|
33
|
-
* shared listener when the stack empties. Safe to call when inactive.
|
|
34
|
-
*/
|
|
27
|
+
const entry = { onDismiss: options.onDismiss, claims: options.claims ?? null };
|
|
28
|
+
registry.stack.push(entry);
|
|
29
|
+
this.#active = { document: ownerDocument, entry };
|
|
30
|
+
}
|
|
35
31
|
deactivate() {
|
|
36
|
-
const
|
|
37
|
-
if (!
|
|
38
|
-
const registry = _EscapeLayer.#registries.get(
|
|
32
|
+
const active = this.#active;
|
|
33
|
+
if (!active) return;
|
|
34
|
+
const registry = _EscapeLayer.#registries.get(active.document);
|
|
39
35
|
if (registry) {
|
|
40
|
-
const index = registry.stack.lastIndexOf(
|
|
36
|
+
const index = registry.stack.lastIndexOf(active.entry);
|
|
41
37
|
if (index >= 0) registry.stack.splice(index, 1);
|
|
42
38
|
if (registry.stack.length === 0) {
|
|
43
|
-
|
|
44
|
-
_EscapeLayer.#registries.delete(
|
|
39
|
+
active.document.removeEventListener("keydown", registry.onKeydown);
|
|
40
|
+
_EscapeLayer.#registries.delete(active.document);
|
|
45
41
|
}
|
|
46
42
|
}
|
|
47
|
-
this.#
|
|
48
|
-
|
|
49
|
-
this.#claims = null;
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Whether this active layer would own a press right now: it is the topmost
|
|
53
|
-
* layer whose {@link EscapeLayerOptions.claims} passes. Exposed for tests
|
|
54
|
-
* and diagnostics — production dismissal goes through the shared listener.
|
|
55
|
-
*/
|
|
43
|
+
this.#active = null;
|
|
44
|
+
}
|
|
56
45
|
get ownsEscape() {
|
|
57
|
-
const
|
|
58
|
-
if (!
|
|
59
|
-
const registry = _EscapeLayer.#registries.get(
|
|
46
|
+
const active = this.#active;
|
|
47
|
+
if (!active) return false;
|
|
48
|
+
const registry = _EscapeLayer.#registries.get(active.document);
|
|
60
49
|
if (!registry) return false;
|
|
61
|
-
return _EscapeLayer.#resolveOwner(registry.stack) ===
|
|
50
|
+
return _EscapeLayer.#resolveOwner(registry.stack) === active.entry;
|
|
62
51
|
}
|
|
63
|
-
/** Builds a document's registry with its shared resolver listener. */
|
|
64
52
|
static #createRegistry() {
|
|
65
53
|
const registry = {
|
|
66
54
|
stack: [],
|
|
@@ -69,60 +57,86 @@ var EscapeLayer = class _EscapeLayer {
|
|
|
69
57
|
const owner = _EscapeLayer.#resolveOwner(registry.stack);
|
|
70
58
|
if (!owner) return;
|
|
71
59
|
event.preventDefault();
|
|
72
|
-
owner
|
|
60
|
+
owner.onDismiss();
|
|
73
61
|
}
|
|
74
62
|
};
|
|
75
63
|
return registry;
|
|
76
64
|
}
|
|
77
|
-
/** The topmost stack layer whose claims predicate passes, or `null`. */
|
|
78
65
|
static #resolveOwner(stack) {
|
|
79
66
|
for (let index = stack.length - 1; index >= 0; index--) {
|
|
80
67
|
const layer = stack[index];
|
|
81
68
|
if (!layer) continue;
|
|
82
|
-
if (layer
|
|
69
|
+
if (layer.claims && !layer.claims()) continue;
|
|
83
70
|
return layer;
|
|
84
71
|
}
|
|
85
72
|
return null;
|
|
86
73
|
}
|
|
87
74
|
};
|
|
88
75
|
|
|
89
|
-
|
|
76
|
+
var MAX_TIMER_DELAY_MS = 2147483647;
|
|
77
|
+
|
|
78
|
+
var NUMBER_BOUNDS = {
|
|
79
|
+
timer: { finite: true, min: 0, max: MAX_TIMER_DELAY_MS }};
|
|
80
|
+
function matchesNumberBounds(value, bounds) {
|
|
81
|
+
if (!Number.isFinite(value)) {
|
|
82
|
+
const direction = value === Infinity ? "positive" : value === -Infinity ? "negative" : null;
|
|
83
|
+
if (direction === null) return false;
|
|
84
|
+
if (bounds.allowInfinity !== "both" && bounds.allowInfinity !== direction) return false;
|
|
85
|
+
}
|
|
86
|
+
if (bounds.min !== void 0 && value < bounds.min) return false;
|
|
87
|
+
if (bounds.max !== void 0 && value > bounds.max) return false;
|
|
88
|
+
if (bounds.exclusiveMin !== void 0 && value <= bounds.exclusiveMin) return false;
|
|
89
|
+
if (bounds.integer && !Number.isInteger(value)) return false;
|
|
90
|
+
if (bounds.allowedValues !== void 0 && !bounds.allowedValues.includes(value)) return false;
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function readNumber(raw, fallback, bounds) {
|
|
95
|
+
return matchesNumberBounds(raw, bounds) ? raw : fallback;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
var NumberValueReader = class {
|
|
99
|
+
#lastRejected = /* @__PURE__ */ new Map();
|
|
100
|
+
read(owner, name, raw, fallback, bounds) {
|
|
101
|
+
const resolved = readNumber(raw, fallback, bounds);
|
|
102
|
+
if (matchesNumberBounds(raw, bounds)) {
|
|
103
|
+
this.#lastRejected.delete(name);
|
|
104
|
+
return resolved;
|
|
105
|
+
}
|
|
106
|
+
const attribute = `data-${owner.identifier}-${name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}-value`;
|
|
107
|
+
const literal = owner.element.getAttribute(attribute);
|
|
108
|
+
if (literal === null) {
|
|
109
|
+
this.#lastRejected.delete(name);
|
|
110
|
+
return resolved;
|
|
111
|
+
}
|
|
112
|
+
if (this.#lastRejected.get(name) !== literal) {
|
|
113
|
+
this.#lastRejected.set(name, literal);
|
|
114
|
+
console.warn(
|
|
115
|
+
`Stimeo UI: "${owner.identifier}" has an invalid number Value "${name}" declaration ${JSON.stringify(literal)}; using ${fallback}.`
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
return resolved;
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
90
122
|
var TimerRegistry = class {
|
|
91
|
-
/** Live timer ids that have not yet been cleared (or, for timeouts, fired). */
|
|
92
123
|
ids = /* @__PURE__ */ new Set();
|
|
93
|
-
/**
|
|
94
|
-
* Cancels a single tracked timer.
|
|
95
|
-
*
|
|
96
|
-
* No-ops if the id is unknown (already cleared, fired, or never owned by this
|
|
97
|
-
* registry), so callers can clear defensively without guarding.
|
|
98
|
-
*/
|
|
99
124
|
clear(id) {
|
|
100
125
|
if (this.ids.delete(id)) {
|
|
101
126
|
this.cancel(id);
|
|
102
127
|
}
|
|
103
128
|
}
|
|
104
|
-
/**
|
|
105
|
-
* Cancels every tracked timer. Call this from a controller's `disconnect()`
|
|
106
|
-
* to guarantee no timer outlives the element.
|
|
107
|
-
*/
|
|
108
129
|
clearAll() {
|
|
109
130
|
for (const id of this.ids) {
|
|
110
131
|
this.cancel(id);
|
|
111
132
|
}
|
|
112
133
|
this.ids.clear();
|
|
113
134
|
}
|
|
114
|
-
/** Number of timers currently tracked (pending). */
|
|
115
135
|
get size() {
|
|
116
136
|
return this.ids.size;
|
|
117
137
|
}
|
|
118
138
|
};
|
|
119
139
|
var SafeTimeout = class extends TimerRegistry {
|
|
120
|
-
/**
|
|
121
|
-
* Schedules `callback` after `delay` ms and returns the timer id.
|
|
122
|
-
*
|
|
123
|
-
* The id is removed from the registry automatically when the timeout fires,
|
|
124
|
-
* so {@link TimerRegistry.size | size} reflects only still-pending timers.
|
|
125
|
-
*/
|
|
126
140
|
set(callback, delay) {
|
|
127
141
|
const id = this.schedule(() => {
|
|
128
142
|
this.ids.delete(id);
|
|
@@ -139,7 +153,6 @@ var SafeTimeout = class extends TimerRegistry {
|
|
|
139
153
|
}
|
|
140
154
|
};
|
|
141
155
|
|
|
142
|
-
// src/utils/scroll_dismiss.ts
|
|
143
156
|
function observeScrollDismiss(element, onScroll) {
|
|
144
157
|
const targets = [...scrollParents(element), window];
|
|
145
158
|
const handler = () => onScroll();
|
|
@@ -164,107 +177,135 @@ function isScrollable(element) {
|
|
|
164
177
|
return /auto|scroll|overlay/.test(style.overflow + style.overflowX + style.overflowY);
|
|
165
178
|
}
|
|
166
179
|
|
|
167
|
-
|
|
168
|
-
var
|
|
180
|
+
var FOCUS_EVENTS = /* @__PURE__ */ new Set(["blur", "focus", "focusin", "focusout"]);
|
|
181
|
+
var POINTER_EVENTS = /* @__PURE__ */ new Set(["mouseenter", "mouseleave", "pointerenter", "pointerleave"]);
|
|
182
|
+
function stateReasonFor(event) {
|
|
183
|
+
if (!event) return "api";
|
|
184
|
+
if (FOCUS_EVENTS.has(event.type)) return "focus";
|
|
185
|
+
if (POINTER_EVENTS.has(event.type)) return "pointer";
|
|
186
|
+
return "user";
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
var TooltipController = class _TooltipController extends Controller {
|
|
190
|
+
#numbers = new NumberValueReader();
|
|
169
191
|
static targets = ["trigger", "content"];
|
|
170
192
|
static values = {
|
|
171
193
|
showDelay: { type: Number, default: 0 },
|
|
172
194
|
hideDelay: { type: Number, default: 0 },
|
|
173
195
|
closeOnScroll: { type: Boolean, default: false }
|
|
174
196
|
};
|
|
197
|
+
static valueConstraints = {
|
|
198
|
+
showDelay: NUMBER_BOUNDS.timer,
|
|
199
|
+
hideDelay: NUMBER_BOUNDS.timer
|
|
200
|
+
};
|
|
175
201
|
static actions = ["hide", "show"];
|
|
176
|
-
|
|
202
|
+
static events = ["close", "open"];
|
|
177
203
|
#timers = new SafeTimeout();
|
|
178
|
-
/** Escape-stack membership while shown; the shared resolver dismisses via it. */
|
|
179
204
|
#escapeLayer = new EscapeLayer();
|
|
180
|
-
/** The id of the currently pending show timer, if any. */
|
|
181
205
|
#pendingShow = null;
|
|
182
|
-
/** The id of the currently pending hide timer, if any. */
|
|
183
206
|
#pendingHide = null;
|
|
184
|
-
/** Whether focus or the pointer currently requires the tooltip to persist. */
|
|
185
207
|
#focusActive = false;
|
|
186
208
|
#pointerActive = false;
|
|
187
|
-
/** Cleanup for the dismiss-on-scroll listeners while shown, or `null`. */
|
|
188
209
|
#stopScrollDismiss = null;
|
|
189
|
-
|
|
210
|
+
#shownContent = null;
|
|
211
|
+
#reporting = false;
|
|
190
212
|
connect() {
|
|
191
|
-
this.#
|
|
192
|
-
this.#cancelHide();
|
|
213
|
+
this.#cancelTimers();
|
|
193
214
|
this.#resetInteractionState();
|
|
194
|
-
this.#conceal();
|
|
215
|
+
this.#conceal("api");
|
|
216
|
+
this.#reporting = true;
|
|
195
217
|
}
|
|
196
|
-
/** Clears timers, the Escape-stack membership, and scroll listeners so nothing outlives the element. */
|
|
197
218
|
disconnect() {
|
|
198
|
-
this.#
|
|
199
|
-
this.#
|
|
200
|
-
this.#
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
this.#
|
|
219
|
+
this.#reporting = false;
|
|
220
|
+
this.#cancelTimers();
|
|
221
|
+
this.#release();
|
|
222
|
+
}
|
|
223
|
+
closeOnScrollValueChanged() {
|
|
224
|
+
if (this.#shownContent) this.#syncScrollDismiss();
|
|
225
|
+
}
|
|
226
|
+
contentTargetDisconnected(content) {
|
|
227
|
+
if (content !== this.#shownContent) return;
|
|
228
|
+
if (this.contentTargets.includes(content)) return;
|
|
229
|
+
this.#cancelTimers();
|
|
230
|
+
this.#release();
|
|
231
|
+
content.hidden = true;
|
|
232
|
+
content.setAttribute("data-state", "closed");
|
|
233
|
+
this.#reflectHidden();
|
|
204
234
|
}
|
|
205
|
-
/** Shows after `showDelay`, recording the focus/pointer reason supplied by an action event. */
|
|
206
235
|
show(event) {
|
|
236
|
+
const reason = stateReasonFor(event);
|
|
207
237
|
this.#activateInteraction(event);
|
|
208
238
|
this.#cancelHide();
|
|
209
239
|
if (this.#isVisible || this.#pendingShow !== null) return;
|
|
210
|
-
if (this
|
|
211
|
-
this.#reveal();
|
|
240
|
+
if (this.#safeShowDelay <= 0) {
|
|
241
|
+
this.#reveal(reason);
|
|
212
242
|
return;
|
|
213
243
|
}
|
|
214
244
|
this.#pendingShow = this.#timers.set(() => {
|
|
215
245
|
this.#pendingShow = null;
|
|
216
|
-
this.#reveal();
|
|
217
|
-
}, this
|
|
246
|
+
this.#reveal(reason);
|
|
247
|
+
}, this.#safeShowDelay);
|
|
218
248
|
}
|
|
219
|
-
/** Hides after `hideDelay` once no focus/pointer reason remains; eventless calls are explicit. */
|
|
220
249
|
hide(event) {
|
|
250
|
+
const reason = stateReasonFor(event);
|
|
221
251
|
const interactionEnded = this.#deactivateInteraction(event);
|
|
222
|
-
if (interactionEnded && this.#hasActiveInteraction)
|
|
223
|
-
this.#cancelHide();
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
252
|
+
if (interactionEnded && this.#hasActiveInteraction) return;
|
|
226
253
|
this.#cancelShow();
|
|
227
|
-
if (!this.#
|
|
228
|
-
if (this
|
|
229
|
-
this.#conceal();
|
|
254
|
+
if (!this.#hidable || this.#pendingHide !== null) return;
|
|
255
|
+
if (this.#safeHideDelay <= 0) {
|
|
256
|
+
this.#conceal(reason);
|
|
230
257
|
return;
|
|
231
258
|
}
|
|
232
259
|
this.#pendingHide = this.#timers.set(() => {
|
|
233
260
|
this.#pendingHide = null;
|
|
234
|
-
this.#conceal();
|
|
235
|
-
}, this
|
|
261
|
+
this.#conceal(reason);
|
|
262
|
+
}, this.#safeHideDelay);
|
|
236
263
|
}
|
|
237
|
-
|
|
238
|
-
#reveal() {
|
|
264
|
+
#reveal(reason) {
|
|
239
265
|
if (!this.hasContentTarget) return;
|
|
240
|
-
this.contentTarget
|
|
241
|
-
this
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
}
|
|
266
|
+
const content = this.contentTarget;
|
|
267
|
+
const was = this.#isVisible;
|
|
268
|
+
content.hidden = false;
|
|
269
|
+
content.setAttribute("data-state", "open");
|
|
270
|
+
this.#shownContent = content;
|
|
271
|
+
if (!was && this.#reporting) this.dispatch("open", { detail: { reason }, cancelable: false });
|
|
272
|
+
if (this.#shownContent !== content) return;
|
|
273
|
+
this.#escapeLayer.activate(document, { onDismiss: () => this.#dismiss("escape") });
|
|
274
|
+
this.#syncScrollDismiss();
|
|
246
275
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
this.#
|
|
250
|
-
this.#
|
|
251
|
-
this.#
|
|
276
|
+
#conceal(reason) {
|
|
277
|
+
const was = this.#isVisible;
|
|
278
|
+
this.#release();
|
|
279
|
+
this.#reflectHidden();
|
|
280
|
+
if (was && this.#reporting) this.dispatch("close", { detail: { reason }, cancelable: false });
|
|
281
|
+
}
|
|
282
|
+
#reflectHidden() {
|
|
252
283
|
if (!this.hasContentTarget) return;
|
|
253
284
|
this.contentTarget.hidden = true;
|
|
254
285
|
this.contentTarget.setAttribute("data-state", "closed");
|
|
255
286
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
this.#
|
|
259
|
-
this.#
|
|
260
|
-
this.#
|
|
287
|
+
#release() {
|
|
288
|
+
this.#shownContent = null;
|
|
289
|
+
this.#escapeLayer.deactivate();
|
|
290
|
+
this.#stopScrollDismiss?.();
|
|
291
|
+
this.#stopScrollDismiss = null;
|
|
292
|
+
}
|
|
293
|
+
#syncScrollDismiss() {
|
|
294
|
+
if (this.closeOnScrollValue) {
|
|
295
|
+
this.#stopScrollDismiss ??= observeScrollDismiss(this.element, () => this.#dismiss("scroll"));
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
this.#stopScrollDismiss?.();
|
|
299
|
+
this.#stopScrollDismiss = null;
|
|
300
|
+
}
|
|
301
|
+
#dismiss(reason) {
|
|
302
|
+
this.#cancelTimers();
|
|
303
|
+
this.#conceal(reason);
|
|
261
304
|
}
|
|
262
|
-
/** Records the modality whose enter/focus event requires the tooltip to stay visible. */
|
|
263
305
|
#activateInteraction(event) {
|
|
264
306
|
if (event?.type === "mouseenter") this.#pointerActive = true;
|
|
265
307
|
if (event?.type === "focusin") this.#focusActive = true;
|
|
266
308
|
}
|
|
267
|
-
/** Clears a modality on leave/blur and reports whether the event represented such a change. */
|
|
268
309
|
#deactivateInteraction(event) {
|
|
269
310
|
if (event?.type === "mouseleave") {
|
|
270
311
|
this.#pointerActive = false;
|
|
@@ -276,35 +317,54 @@ var TooltipController = class extends Controller {
|
|
|
276
317
|
}
|
|
277
318
|
return false;
|
|
278
319
|
}
|
|
279
|
-
/** Discards interaction reasons at a lifecycle boundary. */
|
|
280
320
|
#resetInteractionState() {
|
|
281
321
|
this.#focusActive = false;
|
|
282
322
|
this.#pointerActive = false;
|
|
283
323
|
}
|
|
284
|
-
/** Whether focus or pointer presence still requires a persistent tooltip. */
|
|
285
324
|
get #hasActiveInteraction() {
|
|
286
325
|
return this.#focusActive || this.#pointerActive;
|
|
287
326
|
}
|
|
288
|
-
|
|
327
|
+
#cancelTimers() {
|
|
328
|
+
this.#cancelShow();
|
|
329
|
+
this.#cancelHide();
|
|
330
|
+
}
|
|
289
331
|
#cancelShow() {
|
|
290
332
|
if (this.#pendingShow !== null) {
|
|
291
333
|
this.#timers.clear(this.#pendingShow);
|
|
292
334
|
this.#pendingShow = null;
|
|
293
335
|
}
|
|
294
336
|
}
|
|
295
|
-
/** Cancels any pending hide timer. */
|
|
296
337
|
#cancelHide() {
|
|
297
338
|
if (this.#pendingHide !== null) {
|
|
298
339
|
this.#timers.clear(this.#pendingHide);
|
|
299
340
|
this.#pendingHide = null;
|
|
300
341
|
}
|
|
301
342
|
}
|
|
302
|
-
/** Whether the tooltip is currently shown. */
|
|
303
343
|
get #isVisible() {
|
|
304
344
|
return this.hasContentTarget && !this.contentTarget.hidden;
|
|
305
345
|
}
|
|
346
|
+
get #hidable() {
|
|
347
|
+
return this.#isVisible || this.#shownContent !== null;
|
|
348
|
+
}
|
|
349
|
+
get #safeShowDelay() {
|
|
350
|
+
return this.#numbers.read(
|
|
351
|
+
this,
|
|
352
|
+
"showDelay",
|
|
353
|
+
this.showDelayValue,
|
|
354
|
+
_TooltipController.values.showDelay.default,
|
|
355
|
+
_TooltipController.valueConstraints.showDelay
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
get #safeHideDelay() {
|
|
359
|
+
return this.#numbers.read(
|
|
360
|
+
this,
|
|
361
|
+
"hideDelay",
|
|
362
|
+
this.hideDelayValue,
|
|
363
|
+
_TooltipController.values.hideDelay.default,
|
|
364
|
+
_TooltipController.valueConstraints.hideDelay
|
|
365
|
+
);
|
|
366
|
+
}
|
|
306
367
|
};
|
|
307
368
|
|
|
308
369
|
export { TooltipController };
|
|
309
|
-
//# sourceMappingURL=tooltip_controller.js.map
|
|
310
370
|
//# sourceMappingURL=tooltip_controller.js.map
|