stimeo-ui 0.16.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 +31 -0
- data/README.md +8 -1
- data/dist/cable/index.js +363 -436
- data/dist/controllers/accordion_controller.js +166 -55
- data/dist/controllers/alert_dialog_controller.js +862 -221
- data/dist/controllers/announcer_controller.js +135 -198
- data/dist/controllers/aspect_ratio_controller.js +0 -10
- data/dist/controllers/auto_submit_controller.js +271 -127
- data/dist/controllers/avatar_controller.js +171 -105
- data/dist/controllers/breadcrumb_controller.js +0 -130
- data/dist/controllers/bulk_select_controller.js +262 -52
- data/dist/controllers/calendar_controller.js +175 -209
- data/dist/controllers/carousel_controller.js +461 -399
- data/dist/controllers/character_counter_controller.js +246 -156
- data/dist/controllers/checkbox_controller.js +32 -74
- data/dist/controllers/clipboard_controller.js +168 -147
- data/dist/controllers/collapsible_controller.js +301 -120
- data/dist/controllers/color_picker_controller.js +149 -139
- data/dist/controllers/combobox_controller.js +360 -133
- data/dist/controllers/command_palette_controller.js +970 -358
- data/dist/controllers/conditional_fields_controller.js +166 -124
- data/dist/controllers/confirm_controller.js +939 -248
- data/dist/controllers/context_menu_controller.js +256 -128
- data/dist/controllers/count_up_controller.js +73 -21
- data/dist/controllers/countdown_controller.js +183 -148
- data/dist/controllers/currency_input_controller.js +134 -158
- data/dist/controllers/data_grid_controller.js +114 -186
- data/dist/controllers/date_range_picker_controller.js +288 -206
- data/dist/controllers/dialog_controller.js +858 -223
- data/dist/controllers/direct_upload_controller.js +73 -153
- data/dist/controllers/dirty_form_controller.js +14 -48
- data/dist/controllers/dismissible_controller.js +175 -21
- data/dist/controllers/drawer_controller.js +933 -341
- data/dist/controllers/dropdown_controller.js +312 -82
- data/dist/controllers/editable_controller.js +158 -68
- data/dist/controllers/empty_state_controller.js +67 -53
- data/dist/controllers/file_dropzone_controller.js +311 -207
- data/dist/controllers/filter_controller.js +67 -39
- data/dist/controllers/flash_controller.js +172 -314
- data/dist/controllers/focus_controller.js +654 -240
- data/dist/controllers/form_field_controller.js +147 -132
- data/dist/controllers/form_validation_controller.js +13 -86
- data/dist/controllers/frame_loading_controller.js +264 -213
- data/dist/controllers/highlight_controller.js +107 -75
- data/dist/controllers/hover_card_controller.js +309 -118
- data/dist/controllers/idle_controller.js +267 -101
- data/dist/controllers/input_mask_controller.js +71 -72
- data/dist/controllers/intersection_controller.js +147 -106
- data/dist/controllers/lazy_frame_controller.js +9 -65
- data/dist/controllers/listbox_controller.js +306 -204
- data/dist/controllers/local_time_controller.js +54 -64
- data/dist/controllers/masonry_controller.js +70 -93
- data/dist/controllers/menu_controller.js +214 -156
- data/dist/controllers/menubar_controller.js +170 -329
- data/dist/controllers/meter_controller.js +151 -67
- data/dist/controllers/multi_select_controller.js +593 -358
- data/dist/controllers/navigation_menu_controller.js +124 -232
- data/dist/controllers/nested_form_controller.js +352 -182
- data/dist/controllers/network_status_controller.js +242 -54
- data/dist/controllers/number_input_controller.js +320 -263
- data/dist/controllers/optimistic_controller.js +16 -76
- data/dist/controllers/otp_controller.js +198 -193
- data/dist/controllers/overflow_indicator_controller.js +116 -113
- data/dist/controllers/overflow_menu_controller.js +343 -283
- data/dist/controllers/pagination_controller.js +295 -119
- data/dist/controllers/password_reveal_controller.js +389 -121
- data/dist/controllers/password_strength_controller.js +99 -153
- data/dist/controllers/persist_controller.js +237 -103
- data/dist/controllers/pointer_drag_controller.js +185 -165
- data/dist/controllers/popover_controller.js +236 -97
- data/dist/controllers/portal_controller.js +209 -76
- data/dist/controllers/preview_guard_controller.js +232 -116
- data/dist/controllers/progress_controller.js +125 -56
- data/dist/controllers/radio_group_controller.js +117 -137
- data/dist/controllers/range_slider_controller.js +192 -105
- data/dist/controllers/rating_controller.js +418 -207
- data/dist/controllers/read_more_controller.js +134 -63
- 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 +255 -139
- data/dist/controllers/roving_controller.js +39 -84
- data/dist/controllers/scroll_area_controller.js +428 -225
- data/dist/controllers/scroll_restore_controller.js +0 -53
- data/dist/controllers/scroll_visibility_controller.js +395 -145
- data/dist/controllers/scrollspy_controller.js +181 -242
- data/dist/controllers/separator_controller.js +267 -140
- data/dist/controllers/sidebar_controller.js +1023 -386
- data/dist/controllers/skeleton_controller.js +248 -97
- data/dist/controllers/slider_controller.js +159 -79
- data/dist/controllers/smart_sticky_header_controller.js +162 -63
- data/dist/controllers/sortable_controller.js +0 -112
- data/dist/controllers/spinner_controller.js +277 -169
- data/dist/controllers/step_indicator_controller.js +99 -46
- data/dist/controllers/stepper_controller.js +114 -73
- data/dist/controllers/stick_to_bottom_controller.js +262 -138
- data/dist/controllers/sticky_observer_controller.js +214 -49
- data/dist/controllers/submit_once_controller.js +294 -205
- data/dist/controllers/switch_controller.js +33 -60
- data/dist/controllers/tabs_controller.js +35 -29
- data/dist/controllers/tags_input_controller.js +136 -145
- data/dist/controllers/textarea_autosize_controller.js +71 -58
- data/dist/controllers/theme_controller.js +130 -112
- data/dist/controllers/time_picker_controller.js +146 -80
- data/dist/controllers/toast_controller.js +186 -297
- data/dist/controllers/toggle_group_controller.js +95 -136
- data/dist/controllers/toolbar_controller.js +68 -98
- data/dist/controllers/tooltip_controller.js +158 -124
- data/dist/controllers/transition_controller.js +123 -119
- data/dist/controllers/tree_view_controller.js +150 -345
- data/dist/index.js +6370 -9346
- data/dist/positioning/index.js +148 -47
- data/lib/stimeo/ui/version.rb +1 -1
- metadata +3 -3
|
@@ -1,8 +1,152 @@
|
|
|
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
|
+
}
|
|
12
|
+
|
|
13
|
+
function isAttributeValue(value) {
|
|
14
|
+
return value === null || typeof value === "string";
|
|
15
|
+
}
|
|
16
|
+
function readLeaseRecord(element, record) {
|
|
17
|
+
try {
|
|
18
|
+
const parsed = JSON.parse(element.getAttribute(record) ?? "null");
|
|
19
|
+
if (!Array.isArray(parsed)) return void 0;
|
|
20
|
+
const [original, written, ...rest] = parsed;
|
|
21
|
+
const linked = rest[0] !== false;
|
|
22
|
+
const beneath = linked ? rest : rest.slice(1);
|
|
23
|
+
if (!beneath.every((under) => typeof under === "string")) return void 0;
|
|
24
|
+
return isAttributeValue(original) && isAttributeValue(written) ? { original, written, linked, beneath } : void 0;
|
|
25
|
+
} catch {
|
|
26
|
+
return void 0;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
var AttributeLease = class _AttributeLease {
|
|
30
|
+
static #registry = sharedRegistry(
|
|
31
|
+
"stimeo-ui.attribute-lease.registry.v1",
|
|
32
|
+
() => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Map() })
|
|
33
|
+
);
|
|
34
|
+
#attribute;
|
|
35
|
+
#record;
|
|
36
|
+
#base;
|
|
37
|
+
#held = /* @__PURE__ */ new Set();
|
|
38
|
+
constructor(attribute, owner, options = {}) {
|
|
39
|
+
this.#attribute = attribute;
|
|
40
|
+
this.#record = `data-${owner}-${attribute}-lease`;
|
|
41
|
+
this.#base = options.base === true;
|
|
42
|
+
const names = _AttributeLease.#registry.names;
|
|
43
|
+
names.set(attribute, (names.get(attribute) ?? /* @__PURE__ */ new Set()).add(this.#record));
|
|
44
|
+
}
|
|
45
|
+
write(element, value) {
|
|
46
|
+
const stack = this.#stack(element);
|
|
47
|
+
const hold = this.#take(stack) ?? this.#acquire(element, stack);
|
|
48
|
+
this.#held.add(element);
|
|
49
|
+
const shows = !this.#covered(element, stack, hold);
|
|
50
|
+
hold.written = value;
|
|
51
|
+
this.#mark(element, stack);
|
|
52
|
+
if (shows) this.#reflect(element, value);
|
|
53
|
+
}
|
|
54
|
+
return(element) {
|
|
55
|
+
const held = this.#held.delete(element);
|
|
56
|
+
const known = _AttributeLease.#registry.stacks.get(element)?.has(this.#attribute);
|
|
57
|
+
const stack = held || known || element.hasAttribute(this.#record) ? this.#stack(element) : [];
|
|
58
|
+
const hold = this.#take(stack);
|
|
59
|
+
if (!hold) return false;
|
|
60
|
+
const carries = element.getAttribute(this.#attribute) === hold.written;
|
|
61
|
+
const owns = carries && !this.#covered(element, stack, hold);
|
|
62
|
+
const index = stack.indexOf(hold);
|
|
63
|
+
stack.splice(index, 1);
|
|
64
|
+
const above = stack[index];
|
|
65
|
+
if (above) above.linked &&= hold.linked;
|
|
66
|
+
this.#mark(element, stack);
|
|
67
|
+
if (!owns) return true;
|
|
68
|
+
const below = hold.linked ? stack[index - 1] : void 0;
|
|
69
|
+
this.#reflect(element, below ? below.written : hold.original);
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
returnAll() {
|
|
73
|
+
for (const element of Array.from(this.#held)) this.return(element);
|
|
74
|
+
}
|
|
75
|
+
#stack(element) {
|
|
76
|
+
const stacks = _AttributeLease.#registry.stacks;
|
|
77
|
+
const byAttribute = stacks.get(element) ?? /* @__PURE__ */ new Map();
|
|
78
|
+
stacks.set(element, byAttribute);
|
|
79
|
+
const stack = byAttribute.get(this.#attribute) ?? this.#seed(element);
|
|
80
|
+
byAttribute.set(this.#attribute, stack);
|
|
81
|
+
return stack;
|
|
82
|
+
}
|
|
83
|
+
#seed(element) {
|
|
84
|
+
const found = [];
|
|
85
|
+
for (const record of _AttributeLease.#registry.names.get(this.#attribute) ?? []) {
|
|
86
|
+
const read = readLeaseRecord(element, record);
|
|
87
|
+
if (read) found.push({ ...read, record });
|
|
88
|
+
}
|
|
89
|
+
const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
|
|
90
|
+
return found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
|
|
91
|
+
lease: null,
|
|
92
|
+
record,
|
|
93
|
+
written,
|
|
94
|
+
original,
|
|
95
|
+
linked: linked && index > 0
|
|
96
|
+
}));
|
|
97
|
+
}
|
|
98
|
+
#take(stack) {
|
|
99
|
+
const hold = stack.find((held) => held.lease === this) ?? stack.find((held) => held.lease === null && held.record === this.#record);
|
|
100
|
+
if (hold) hold.lease = this;
|
|
101
|
+
return hold;
|
|
102
|
+
}
|
|
103
|
+
#acquire(element, stack) {
|
|
104
|
+
const current = element.getAttribute(this.#attribute);
|
|
105
|
+
const top = stack.at(-1);
|
|
106
|
+
const bottom = stack[0];
|
|
107
|
+
const over = top?.written === current ? top : void 0;
|
|
108
|
+
const from = this.#base ? bottom : over;
|
|
109
|
+
const hold = {
|
|
110
|
+
lease: this,
|
|
111
|
+
record: this.#record,
|
|
112
|
+
written: current,
|
|
113
|
+
original: from ? from.original : current,
|
|
114
|
+
linked: !this.#base && over !== void 0
|
|
115
|
+
};
|
|
116
|
+
if (this.#base && bottom) {
|
|
117
|
+
bottom.linked = true;
|
|
118
|
+
stack.unshift(hold);
|
|
119
|
+
} else stack.push(hold);
|
|
120
|
+
return hold;
|
|
121
|
+
}
|
|
122
|
+
#covered(element, stack, hold) {
|
|
123
|
+
const current = element.getAttribute(this.#attribute);
|
|
124
|
+
return stack.slice(stack.indexOf(hold) + 1).some((above) => above.written === current);
|
|
125
|
+
}
|
|
126
|
+
#mark(element, stack) {
|
|
127
|
+
const records = /* @__PURE__ */ new Map([[this.#record, null]]);
|
|
128
|
+
stack.forEach((hold, index) => {
|
|
129
|
+
const names = stack.slice(0, index).map((under) => under.record);
|
|
130
|
+
const beneath = [...new Set(names.reverse())].filter((name) => name !== hold.record);
|
|
131
|
+
const marker = hold.linked || beneath.length === 0 ? [] : [false];
|
|
132
|
+
records.set(
|
|
133
|
+
hold.record,
|
|
134
|
+
hold.written === hold.original && beneath.length === 0 && index === stack.length - 1 ? null : JSON.stringify([hold.original, hold.written, ...marker, ...beneath])
|
|
135
|
+
);
|
|
136
|
+
});
|
|
137
|
+
for (const [name, recorded] of records) {
|
|
138
|
+
if (element.getAttribute(name) === recorded) continue;
|
|
139
|
+
if (recorded === null) element.removeAttribute(name);
|
|
140
|
+
else element.setAttribute(name, recorded);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
#reflect(element, value) {
|
|
144
|
+
if (element.getAttribute(this.#attribute) === value) return;
|
|
145
|
+
if (value === null) element.removeAttribute(this.#attribute);
|
|
146
|
+
else element.setAttribute(this.#attribute, value);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
4
149
|
|
|
5
|
-
// src/utils/declared_value.ts
|
|
6
150
|
function parseDeclared(raw, parse, fallback) {
|
|
7
151
|
try {
|
|
8
152
|
return parse(raw);
|
|
@@ -11,7 +155,6 @@ function parseDeclared(raw, parse, fallback) {
|
|
|
11
155
|
}
|
|
12
156
|
}
|
|
13
157
|
|
|
14
|
-
// src/utils/intersection_watcher.ts
|
|
15
158
|
function isBeforeRootStart(entry) {
|
|
16
159
|
const rect = entry.boundingClientRect;
|
|
17
160
|
if (rect.width === 0 && rect.height === 0) return false;
|
|
@@ -30,30 +173,12 @@ var IntersectionWatcher = class {
|
|
|
30
173
|
constructor(onEntries) {
|
|
31
174
|
this.#onEntries = onEntries;
|
|
32
175
|
}
|
|
33
|
-
/** Whether an observer is live (started, `IntersectionObserver` supported). */
|
|
34
176
|
get active() {
|
|
35
177
|
return this.#active;
|
|
36
178
|
}
|
|
37
|
-
/** Whether the live observer discarded configured options after construction failed. */
|
|
38
179
|
get usingPlatformDefaults() {
|
|
39
180
|
return this.#usingPlatformDefaults;
|
|
40
181
|
}
|
|
41
|
-
/**
|
|
42
|
-
* (Re)creates the observer and observes `targets`. Returns `false` — leaving
|
|
43
|
-
* the watcher inert — without `IntersectionObserver` support (very old
|
|
44
|
-
* browsers; the caller's no-JS fallback stays in charge) or with no targets.
|
|
45
|
-
* If initial construction with the configured options fails, the watcher
|
|
46
|
-
* warns and retries once with the same root and platform defaults. A
|
|
47
|
-
* `rootSelector` that does not parse resolves to the viewport (see
|
|
48
|
-
* {@link IntersectionWatchOptions.rootSelector}), so a typo never fails the
|
|
49
|
-
* call.
|
|
50
|
-
*
|
|
51
|
-
* @throws The fallback constructor error if both construction attempts fail,
|
|
52
|
-
* or whatever the platform throws from `observe()`. The exception is passed
|
|
53
|
-
* through unchanged, but the watcher rolls back first: every target observed
|
|
54
|
-
* so far is released and `active` stays `false`, so a caller that retries
|
|
55
|
-
* starts from a clean slate.
|
|
56
|
-
*/
|
|
57
182
|
start(targets, options = {}) {
|
|
58
183
|
this.stop();
|
|
59
184
|
if (typeof IntersectionObserver === "undefined") return false;
|
|
@@ -91,14 +216,6 @@ var IntersectionWatcher = class {
|
|
|
91
216
|
throw error;
|
|
92
217
|
}
|
|
93
218
|
}
|
|
94
|
-
/**
|
|
95
|
-
* Re-delivers `target`'s CURRENT intersection state: `IntersectionObserver`
|
|
96
|
-
* only reports *changes*, but `observe()` always reports the present state,
|
|
97
|
-
* so unobserve→observe turns "still intersecting" into a fresh callback.
|
|
98
|
-
*
|
|
99
|
-
* @throws Whatever `unobserve()`/`observe()` throws. The watcher is stopped
|
|
100
|
-
* first, so it never stays live with a half-rearmed target.
|
|
101
|
-
*/
|
|
102
219
|
rearm(target) {
|
|
103
220
|
if (!this.#observer) return;
|
|
104
221
|
try {
|
|
@@ -109,7 +226,6 @@ var IntersectionWatcher = class {
|
|
|
109
226
|
throw error;
|
|
110
227
|
}
|
|
111
228
|
}
|
|
112
|
-
/** Severs the observer; late queued callbacks become no-ops via the guard. */
|
|
113
229
|
stop() {
|
|
114
230
|
this.#active = false;
|
|
115
231
|
this.#observer?.disconnect();
|
|
@@ -118,19 +234,64 @@ var IntersectionWatcher = class {
|
|
|
118
234
|
}
|
|
119
235
|
};
|
|
120
236
|
|
|
121
|
-
|
|
122
|
-
|
|
237
|
+
var NUMBER_BOUNDS = {
|
|
238
|
+
finite: { finite: true }};
|
|
239
|
+
function matchesNumberBounds(value, bounds) {
|
|
240
|
+
if (!Number.isFinite(value)) {
|
|
241
|
+
const direction = value === Infinity ? "positive" : value === -Infinity ? "negative" : null;
|
|
242
|
+
if (direction === null) return false;
|
|
243
|
+
if (bounds.allowInfinity !== "both" && bounds.allowInfinity !== direction) return false;
|
|
244
|
+
}
|
|
245
|
+
if (bounds.min !== void 0 && value < bounds.min) return false;
|
|
246
|
+
if (bounds.max !== void 0 && value > bounds.max) return false;
|
|
247
|
+
if (bounds.exclusiveMin !== void 0 && value <= bounds.exclusiveMin) return false;
|
|
248
|
+
if (bounds.integer && !Number.isInteger(value)) return false;
|
|
249
|
+
if (bounds.allowedValues !== void 0 && !bounds.allowedValues.includes(value)) return false;
|
|
250
|
+
return true;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function readNumber(raw, fallback, bounds) {
|
|
254
|
+
return matchesNumberBounds(raw, bounds) ? raw : fallback;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
var NumberValueReader = class {
|
|
258
|
+
#lastRejected = /* @__PURE__ */ new Map();
|
|
259
|
+
read(owner, name, raw, fallback, bounds) {
|
|
260
|
+
const resolved = readNumber(raw, fallback, bounds);
|
|
261
|
+
if (matchesNumberBounds(raw, bounds)) {
|
|
262
|
+
this.#lastRejected.delete(name);
|
|
263
|
+
return resolved;
|
|
264
|
+
}
|
|
265
|
+
const attribute = `data-${owner.identifier}-${name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}-value`;
|
|
266
|
+
const literal = owner.element.getAttribute(attribute);
|
|
267
|
+
if (literal === null) {
|
|
268
|
+
this.#lastRejected.delete(name);
|
|
269
|
+
return resolved;
|
|
270
|
+
}
|
|
271
|
+
if (this.#lastRejected.get(name) !== literal) {
|
|
272
|
+
this.#lastRejected.set(name, literal);
|
|
273
|
+
console.warn(
|
|
274
|
+
`Stimeo UI: "${owner.identifier}" has an invalid number Value "${name}" declaration ${JSON.stringify(literal)}; using ${fallback}.`
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
return resolved;
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
var StickyObserverController = class _StickyObserverController extends Controller {
|
|
282
|
+
#numbers = new NumberValueReader();
|
|
123
283
|
static targets = ["sentinel", "element"];
|
|
124
284
|
static values = {
|
|
125
285
|
rootSelector: { type: String, default: "" },
|
|
126
286
|
offset: { type: Number, default: 0 }
|
|
127
287
|
};
|
|
288
|
+
static valueConstraints = {
|
|
289
|
+
offset: NUMBER_BOUNDS.finite
|
|
290
|
+
};
|
|
128
291
|
static events = ["change"];
|
|
129
|
-
/** Shared IO plumbing (support guard, root resolution, active guard). */
|
|
130
292
|
#watcher = new IntersectionWatcher((entries) => this.#onIntersect(entries));
|
|
131
|
-
|
|
293
|
+
#stuckLease = new AttributeLease("data-stuck", this.identifier);
|
|
132
294
|
#stuck = null;
|
|
133
|
-
/** Target currently owned by the watcher; comparing it avoids duplicate restarts. */
|
|
134
295
|
#observedSentinel = null;
|
|
135
296
|
#connected = false;
|
|
136
297
|
#onIntersect(entries) {
|
|
@@ -150,25 +311,24 @@ var StickyObserverController = class extends Controller {
|
|
|
150
311
|
this.#observedSentinel = null;
|
|
151
312
|
this.#stuck = null;
|
|
152
313
|
}
|
|
153
|
-
/** Starts observation when a sentinel is inserted after connection. */
|
|
154
314
|
sentinelTargetConnected() {
|
|
155
315
|
if (this.#connected) this.#syncObserver();
|
|
156
316
|
}
|
|
157
|
-
/** Stops or transfers observation when the current sentinel is removed. */
|
|
158
317
|
sentinelTargetDisconnected() {
|
|
159
318
|
if (this.#connected) this.#syncObserver();
|
|
160
319
|
}
|
|
161
|
-
/** Reflects the last snapshot onto an element inserted after that snapshot. */
|
|
162
320
|
elementTargetConnected(element) {
|
|
163
|
-
if (this.#stuck !== null)
|
|
164
|
-
|
|
321
|
+
if (this.#stuck !== null) this.#stuckLease.write(element, String(this.#stuck));
|
|
322
|
+
}
|
|
323
|
+
elementTargetDisconnected(element) {
|
|
324
|
+
if (!this.elementTargets.includes(element)) this.#stuckLease.return(element);
|
|
325
|
+
if (this.#connected && this.#stuck !== null && this.hasElementTarget) {
|
|
326
|
+
this.#stuckLease.write(this.elementTarget, String(this.#stuck));
|
|
165
327
|
}
|
|
166
328
|
}
|
|
167
|
-
/** Rebuilds the observer when Turbo morphs the configured root. */
|
|
168
329
|
rootSelectorValueChanged() {
|
|
169
330
|
if (this.#connected) this.#syncObserver(true);
|
|
170
331
|
}
|
|
171
|
-
/** Rebuilds the observer when Turbo morphs the configured top offset. */
|
|
172
332
|
offsetValueChanged() {
|
|
173
333
|
if (this.#connected) this.#syncObserver(true);
|
|
174
334
|
}
|
|
@@ -178,8 +338,8 @@ var StickyObserverController = class extends Controller {
|
|
|
178
338
|
this.#watcher.stop();
|
|
179
339
|
this.#observedSentinel = null;
|
|
180
340
|
if (!sentinel) return;
|
|
181
|
-
const configuredOffset = this
|
|
182
|
-
const offset =
|
|
341
|
+
const configuredOffset = this.#safeOffset;
|
|
342
|
+
const offset = configuredOffset;
|
|
183
343
|
const started = this.#watcher.start(sentinel, {
|
|
184
344
|
rootSelector: this.rootSelectorValue,
|
|
185
345
|
rootMargin: `${-offset}px 0px 0px 0px`,
|
|
@@ -187,17 +347,22 @@ var StickyObserverController = class extends Controller {
|
|
|
187
347
|
});
|
|
188
348
|
if (started) this.#observedSentinel = sentinel;
|
|
189
349
|
}
|
|
190
|
-
/** Reflects the stuck state onto the sticky element and emits `change`. */
|
|
191
350
|
#setStuck(next) {
|
|
192
351
|
if (next === this.#stuck) return;
|
|
193
352
|
this.#stuck = next;
|
|
194
|
-
if (this.hasElementTarget)
|
|
195
|
-
this.elementTarget.setAttribute("data-stuck", next ? "true" : "false");
|
|
196
|
-
}
|
|
353
|
+
if (this.hasElementTarget) this.#stuckLease.write(this.elementTarget, String(next));
|
|
197
354
|
this.dispatch("change", { detail: { stuck: next } });
|
|
198
355
|
}
|
|
356
|
+
get #safeOffset() {
|
|
357
|
+
return this.#numbers.read(
|
|
358
|
+
this,
|
|
359
|
+
"offset",
|
|
360
|
+
this.offsetValue,
|
|
361
|
+
_StickyObserverController.values.offset.default,
|
|
362
|
+
_StickyObserverController.valueConstraints.offset
|
|
363
|
+
);
|
|
364
|
+
}
|
|
199
365
|
};
|
|
200
366
|
|
|
201
367
|
export { StickyObserverController };
|
|
202
|
-
//# sourceMappingURL=sticky_observer_controller.js.map
|
|
203
368
|
//# sourceMappingURL=sticky_observer_controller.js.map
|