stimeo-ui 0.16.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +136 -0
- data/README.md +27 -11
- data/dist/cable/index.js +384 -449
- data/dist/controllers/accordion_controller.js +174 -55
- data/dist/controllers/alert_dialog_controller.js +903 -235
- data/dist/controllers/announcer_controller.js +238 -205
- data/dist/controllers/aspect_ratio_controller.js +0 -10
- data/dist/controllers/auto_submit_controller.js +414 -145
- data/dist/controllers/avatar_controller.js +185 -107
- data/dist/controllers/breadcrumb_controller.js +0 -130
- data/dist/controllers/bulk_select_controller.js +282 -58
- data/dist/controllers/calendar_controller.js +228 -260
- data/dist/controllers/carousel_controller.js +536 -436
- data/dist/controllers/character_counter_controller.js +493 -207
- data/dist/controllers/checkbox_controller.js +38 -74
- data/dist/controllers/clipboard_controller.js +261 -149
- data/dist/controllers/collapsible_controller.js +304 -120
- data/dist/controllers/color_picker_controller.js +178 -146
- data/dist/controllers/combobox_controller.js +522 -156
- data/dist/controllers/command_palette_controller.js +1156 -395
- data/dist/controllers/conditional_fields_controller.js +300 -171
- data/dist/controllers/confirm_controller.js +980 -262
- data/dist/controllers/context_menu_controller.js +346 -153
- data/dist/controllers/count_up_controller.js +73 -21
- data/dist/controllers/countdown_controller.js +281 -158
- data/dist/controllers/currency_input_controller.js +575 -225
- data/dist/controllers/data_grid_controller.js +248 -214
- data/dist/controllers/date_range_picker_controller.js +338 -235
- data/dist/controllers/dialog_controller.js +899 -237
- data/dist/controllers/direct_upload_controller.js +97 -167
- data/dist/controllers/dirty_form_controller.js +72 -69
- data/dist/controllers/dismissible_controller.js +196 -24
- data/dist/controllers/drawer_controller.js +974 -355
- data/dist/controllers/dropdown_controller.js +339 -96
- data/dist/controllers/editable_controller.js +315 -88
- data/dist/controllers/empty_state_controller.js +79 -58
- data/dist/controllers/file_dropzone_controller.js +322 -211
- data/dist/controllers/filter_controller.js +77 -42
- data/dist/controllers/flash_controller.js +238 -347
- data/dist/controllers/focus_controller.js +679 -240
- data/dist/controllers/form_field_controller.js +156 -132
- data/dist/controllers/form_validation_controller.js +31 -97
- data/dist/controllers/frame_loading_controller.js +275 -217
- data/dist/controllers/highlight_controller.js +107 -75
- data/dist/controllers/hover_card_controller.js +327 -130
- data/dist/controllers/idle_controller.js +271 -101
- data/dist/controllers/input_mask_controller.js +483 -97
- data/dist/controllers/intersection_controller.js +150 -106
- data/dist/controllers/lazy_frame_controller.js +24 -68
- data/dist/controllers/listbox_controller.js +523 -240
- data/dist/controllers/local_time_controller.js +102 -77
- data/dist/controllers/masonry_controller.js +80 -96
- data/dist/controllers/menu_controller.js +302 -188
- data/dist/controllers/menubar_controller.js +232 -345
- data/dist/controllers/meter_controller.js +417 -87
- data/dist/controllers/multi_select_controller.js +785 -393
- data/dist/controllers/navigation_menu_controller.js +190 -250
- data/dist/controllers/nested_form_controller.js +396 -192
- data/dist/controllers/network_status_controller.js +268 -62
- data/dist/controllers/number_input_controller.js +610 -303
- data/dist/controllers/optimistic_controller.js +45 -87
- data/dist/controllers/otp_controller.js +658 -255
- data/dist/controllers/overflow_indicator_controller.js +122 -113
- data/dist/controllers/overflow_menu_controller.js +470 -295
- data/dist/controllers/pagination_controller.js +332 -123
- data/dist/controllers/password_reveal_controller.js +392 -121
- data/dist/controllers/password_strength_controller.js +111 -158
- data/dist/controllers/persist_controller.js +165 -111
- data/dist/controllers/pointer_drag_controller.js +434 -188
- data/dist/controllers/popover_controller.js +269 -113
- data/dist/controllers/portal_controller.js +215 -76
- data/dist/controllers/preview_guard_controller.js +243 -116
- data/dist/controllers/progress_controller.js +391 -78
- data/dist/controllers/radio_group_controller.js +278 -211
- data/dist/controllers/range_slider_controller.js +220 -113
- data/dist/controllers/rating_controller.js +458 -211
- data/dist/controllers/read_more_controller.js +138 -63
- data/dist/controllers/reading_progress_controller.js +166 -137
- data/dist/controllers/relative_time_controller.js +211 -112
- data/dist/controllers/{reset_before_cache_controller.js → reset_on_restore_controller.js} +103 -38
- data/dist/controllers/resizable_controller.js +299 -150
- data/dist/controllers/roving_controller.js +49 -88
- data/dist/controllers/scroll_area_controller.js +490 -246
- data/dist/controllers/scroll_restore_controller.js +14 -55
- data/dist/controllers/scroll_visibility_controller.js +432 -149
- data/dist/controllers/scrollspy_controller.js +193 -248
- data/dist/controllers/separator_controller.js +285 -142
- data/dist/controllers/sidebar_controller.js +1069 -404
- data/dist/controllers/skeleton_controller.js +259 -101
- data/dist/controllers/slider_controller.js +187 -86
- data/dist/controllers/smart_sticky_header_controller.js +173 -66
- data/dist/controllers/sortable_controller.js +26 -125
- data/dist/controllers/spinner_controller.js +288 -173
- data/dist/controllers/step_indicator_controller.js +105 -46
- data/dist/controllers/stepper_controller.js +120 -73
- data/dist/controllers/stick_to_bottom_controller.js +275 -140
- data/dist/controllers/sticky_observer_controller.js +220 -49
- data/dist/controllers/submit_once_controller.js +376 -227
- data/dist/controllers/switch_controller.js +201 -84
- data/dist/controllers/tabs_controller.js +41 -30
- data/dist/controllers/tags_input_controller.js +293 -173
- data/dist/controllers/textarea_autosize_controller.js +108 -74
- data/dist/controllers/theme_controller.js +140 -116
- data/dist/controllers/time_picker_controller.js +331 -127
- data/dist/controllers/toast_controller.js +244 -324
- data/dist/controllers/toggle_group_controller.js +252 -191
- data/dist/controllers/toolbar_controller.js +219 -120
- data/dist/controllers/tooltip_controller.js +158 -124
- data/dist/controllers/transition_controller.js +123 -119
- data/dist/controllers/tree_view_controller.js +283 -369
- data/dist/index.js +8573 -10410
- data/dist/positioning/index.js +154 -47
- data/lib/generators/stimeo/install/install_generator.rb +7 -2
- data/lib/generators/stimeo/install/templates/stimeo.js +19 -6
- data/lib/stimeo/ui/version.rb +1 -1
- metadata +3 -3
|
@@ -1,44 +1,7 @@
|
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
|
2
2
|
|
|
3
|
-
// src/controllers/reading_progress_controller.ts
|
|
4
|
-
|
|
5
|
-
// src/utils/before_cache_reset.ts
|
|
6
|
-
var BeforeCacheReset = class _BeforeCacheReset {
|
|
7
|
-
/** Every subscribed instance, iterated by the one shared document listener. */
|
|
8
|
-
static #subscribers = /* @__PURE__ */ new Set();
|
|
9
|
-
/** The shared listener; installed while at least one instance is subscribed. */
|
|
10
|
-
static #onBeforeCache = () => {
|
|
11
|
-
for (const subscriber of _BeforeCacheReset.#subscribers) subscriber.#rewind();
|
|
12
|
-
};
|
|
13
|
-
#rewind;
|
|
14
|
-
/** @param rewind - the pass that returns this controller's state to its initial form. */
|
|
15
|
-
constructor(rewind) {
|
|
16
|
-
this.#rewind = rewind;
|
|
17
|
-
}
|
|
18
|
-
/** Subscribes to `turbo:before-cache`; call from `connect()`. Idempotent. */
|
|
19
|
-
activate() {
|
|
20
|
-
const first = _BeforeCacheReset.#subscribers.size === 0;
|
|
21
|
-
_BeforeCacheReset.#subscribers.add(this);
|
|
22
|
-
if (first) {
|
|
23
|
-
document.addEventListener("turbo:before-cache", _BeforeCacheReset.#onBeforeCache);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
/** Unsubscribes; call from `disconnect()`. Safe when never subscribed. */
|
|
27
|
-
deactivate() {
|
|
28
|
-
_BeforeCacheReset.#subscribers.delete(this);
|
|
29
|
-
if (_BeforeCacheReset.#subscribers.size > 0) return;
|
|
30
|
-
document.removeEventListener("turbo:before-cache", _BeforeCacheReset.#onBeforeCache);
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
// src/utils/frame_coalescer.ts
|
|
35
3
|
var FrameCoalescer = class {
|
|
36
4
|
#frame = null;
|
|
37
|
-
/**
|
|
38
|
-
* Runs `run` on the next frame, unless a frame is already pending — the first
|
|
39
|
-
* request of a burst wins and the rest are dropped. The pending frame is
|
|
40
|
-
* released before `run`, so `run` may request the next one.
|
|
41
|
-
*/
|
|
42
5
|
schedule(run) {
|
|
43
6
|
if (this.#frame !== null) return;
|
|
44
7
|
this.#frame = requestAnimationFrame(() => {
|
|
@@ -46,14 +9,6 @@ var FrameCoalescer = class {
|
|
|
46
9
|
run();
|
|
47
10
|
});
|
|
48
11
|
}
|
|
49
|
-
/**
|
|
50
|
-
* Drops the pending frame, and reaches the platform only when there is one.
|
|
51
|
-
*
|
|
52
|
-
* There is no handle value that stands for "nothing pending":
|
|
53
|
-
* `cancelAnimationFrame` takes an `unsigned long`, so a negative placeholder
|
|
54
|
-
* arrives as a large positive number that the same allocator can hand out, and
|
|
55
|
-
* an idle cancel would then drop a frame belonging to someone else.
|
|
56
|
-
*/
|
|
57
12
|
cancel() {
|
|
58
13
|
if (this.#frame === null) return;
|
|
59
14
|
cancelAnimationFrame(this.#frame);
|
|
@@ -61,18 +16,15 @@ var FrameCoalescer = class {
|
|
|
61
16
|
}
|
|
62
17
|
};
|
|
63
18
|
|
|
64
|
-
// src/utils/layout_observer.ts
|
|
65
19
|
var LayoutObserver = class {
|
|
66
20
|
#callback;
|
|
67
21
|
#resizeObserverFactory;
|
|
68
22
|
#resizeObserver = null;
|
|
69
23
|
#observingViewport = false;
|
|
70
24
|
#loadContainer = null;
|
|
71
|
-
/** Stable bound handler so add/removeEventListener target the same reference. */
|
|
72
25
|
#handleViewportResize = () => {
|
|
73
26
|
this.#callback();
|
|
74
27
|
};
|
|
75
|
-
/** Stable bound handler for the capture-phase `load`; see {@link observeDescendantLoads}. */
|
|
76
28
|
#handleDescendantLoad = () => {
|
|
77
29
|
this.#callback();
|
|
78
30
|
};
|
|
@@ -80,11 +32,6 @@ var LayoutObserver = class {
|
|
|
80
32
|
this.#callback = callback;
|
|
81
33
|
this.#resizeObserverFactory = options.resizeObserverFactory ?? (typeof ResizeObserver === "undefined" ? null : (cb) => new ResizeObserver(cb));
|
|
82
34
|
}
|
|
83
|
-
/**
|
|
84
|
-
* Starts observing an element's size. Repeated calls observe additional
|
|
85
|
-
* elements through the same shared observer. No-ops when no
|
|
86
|
-
* `ResizeObserver` implementation is available.
|
|
87
|
-
*/
|
|
88
35
|
observe(element) {
|
|
89
36
|
if (!this.#resizeObserverFactory) return;
|
|
90
37
|
if (!this.#resizeObserver) {
|
|
@@ -94,47 +41,28 @@ var LayoutObserver = class {
|
|
|
94
41
|
}
|
|
95
42
|
this.#resizeObserver.observe(element);
|
|
96
43
|
}
|
|
97
|
-
/** Stops observing a single element while leaving any others in place. */
|
|
98
44
|
unobserve(element) {
|
|
99
45
|
this.#resizeObserver?.unobserve(element);
|
|
100
46
|
}
|
|
101
|
-
/** Starts observing viewport resizes. Idempotent: the listener is added once. */
|
|
102
47
|
observeViewport() {
|
|
103
48
|
if (this.#observingViewport) return;
|
|
104
49
|
this.#observingViewport = true;
|
|
105
50
|
window.addEventListener("resize", this.#handleViewportResize);
|
|
106
51
|
}
|
|
107
|
-
/** Stops observing viewport resizes without affecting element observation. */
|
|
108
52
|
unobserveViewport() {
|
|
109
53
|
if (!this.#observingViewport) return;
|
|
110
54
|
this.#observingViewport = false;
|
|
111
55
|
window.removeEventListener("resize", this.#handleViewportResize);
|
|
112
56
|
}
|
|
113
|
-
/**
|
|
114
|
-
* Starts reporting a `load` from anywhere inside `container` — an image or a
|
|
115
|
-
* frame settling changes the box it sits in, and it measures as zero high until
|
|
116
|
-
* then. `load` does not bubble, so the subscription is a capture-phase listener
|
|
117
|
-
* on the container itself and nothing the caller spells.
|
|
118
|
-
*
|
|
119
|
-
* **One container at a time.** A further call moves the observation, so a widget
|
|
120
|
-
* whose content element is swapped at runtime releases the element it let go by
|
|
121
|
-
* naming the new one — there is no second place for the release to drift from.
|
|
122
|
-
*/
|
|
123
57
|
observeDescendantLoads(container) {
|
|
124
58
|
this.unobserveDescendantLoads();
|
|
125
59
|
this.#loadContainer = container;
|
|
126
60
|
container.addEventListener("load", this.#handleDescendantLoad, true);
|
|
127
61
|
}
|
|
128
|
-
/** Stops reporting descendant loads without affecting element or viewport observation. */
|
|
129
62
|
unobserveDescendantLoads() {
|
|
130
63
|
this.#loadContainer?.removeEventListener("load", this.#handleDescendantLoad, true);
|
|
131
64
|
this.#loadContainer = null;
|
|
132
65
|
}
|
|
133
|
-
/**
|
|
134
|
-
* Releases every observation: disconnects the {@link ResizeObserver} and removes
|
|
135
|
-
* the viewport and descendant-load listeners. Safe to call multiple times. Call
|
|
136
|
-
* this from a controller's `disconnect()`.
|
|
137
|
-
*/
|
|
138
66
|
disconnect() {
|
|
139
67
|
this.#resizeObserver?.disconnect();
|
|
140
68
|
this.#resizeObserver = null;
|
|
@@ -143,81 +71,196 @@ var LayoutObserver = class {
|
|
|
143
71
|
}
|
|
144
72
|
};
|
|
145
73
|
|
|
146
|
-
|
|
147
|
-
|
|
74
|
+
var ListenerSet = class {
|
|
75
|
+
#abort = new AbortController();
|
|
76
|
+
add(target, type, handler, options) {
|
|
77
|
+
target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
|
|
78
|
+
}
|
|
79
|
+
dispose() {
|
|
80
|
+
this.#abort.abort();
|
|
81
|
+
this.#abort = new AbortController();
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
function setAttributeIfChanged(element, name, value, beforeWrite) {
|
|
86
|
+
if (element.getAttribute(name) === value) return false;
|
|
87
|
+
if (value === null) element.removeAttribute(name);
|
|
88
|
+
else element.setAttribute(name, value);
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function sharedRegistry(key, create) {
|
|
93
|
+
const symbol = Symbol.for(key);
|
|
94
|
+
const scope = globalThis;
|
|
95
|
+
const existing = scope[symbol];
|
|
96
|
+
if (existing !== void 0) return existing;
|
|
97
|
+
const registry = create();
|
|
98
|
+
Object.defineProperty(globalThis, symbol, { value: registry });
|
|
99
|
+
return registry;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
var StylePropertyLease = class _StylePropertyLease {
|
|
103
|
+
static #registry = sharedRegistry(
|
|
104
|
+
"stimeo-ui.style-property-lease.registry.v1",
|
|
105
|
+
() => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Map() })
|
|
106
|
+
);
|
|
148
107
|
#property;
|
|
149
|
-
#
|
|
150
|
-
|
|
151
|
-
constructor(property) {
|
|
108
|
+
#record;
|
|
109
|
+
#held = /* @__PURE__ */ new Set();
|
|
110
|
+
constructor(property, owner) {
|
|
152
111
|
this.#property = property;
|
|
112
|
+
this.#record = `data-${owner}-style-${property}-lease`;
|
|
113
|
+
const names = _StylePropertyLease.#registry.names;
|
|
114
|
+
names.set(property, (names.get(property) ?? /* @__PURE__ */ new Set()).add(this.#record));
|
|
153
115
|
}
|
|
154
|
-
/** Writes or removes the leased declaration while preserving its authored value. */
|
|
155
116
|
write(element, value, priority = "") {
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
writtenValue: value,
|
|
165
|
-
writtenPriority: value === null ? "" : priority
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
this.#reflect(element, value, priority);
|
|
117
|
+
const stack = this.#stack(element);
|
|
118
|
+
const hold = this.#take(stack) ?? this.#acquire(element, stack);
|
|
119
|
+
this.#held.add(element);
|
|
120
|
+
const shows = !this.#covered(element, stack, hold);
|
|
121
|
+
hold.writtenValue = value;
|
|
122
|
+
hold.writtenPriority = value === null ? "" : priority;
|
|
123
|
+
this.#mark(element, stack);
|
|
124
|
+
if (shows) this.#show(element, value, hold.writtenPriority);
|
|
169
125
|
}
|
|
170
|
-
/** Returns one lease without overwriting a later consumer declaration. */
|
|
171
126
|
return(element) {
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
this.#
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
127
|
+
const held = this.#held.delete(element);
|
|
128
|
+
const known = _StylePropertyLease.#registry.stacks.get(element)?.has(this.#property);
|
|
129
|
+
const stack = held || known || element.hasAttribute(this.#record) ? this.#stack(element) : [];
|
|
130
|
+
const hold = this.#take(stack);
|
|
131
|
+
if (!hold) return;
|
|
132
|
+
const owns = this.#carries(element, hold) && !this.#covered(element, stack, hold);
|
|
133
|
+
const index = stack.indexOf(hold);
|
|
134
|
+
stack.splice(index, 1);
|
|
135
|
+
const above = stack[index];
|
|
136
|
+
if (above) above.linked &&= hold.linked;
|
|
137
|
+
this.#mark(element, stack);
|
|
138
|
+
if (!owns) return;
|
|
139
|
+
const below = hold.linked ? stack[index - 1] : void 0;
|
|
140
|
+
if (below) this.#show(element, below.writtenValue, below.writtenPriority);
|
|
141
|
+
else this.#show(element, hold.originalValue, hold.originalPriority);
|
|
180
142
|
}
|
|
181
|
-
/** Returns every outstanding declaration lease. */
|
|
182
143
|
returnAll() {
|
|
183
|
-
for (const element of Array.from(this.#
|
|
144
|
+
for (const element of Array.from(this.#held)) this.return(element);
|
|
145
|
+
}
|
|
146
|
+
#recorded(element, name) {
|
|
147
|
+
try {
|
|
148
|
+
const parsed = JSON.parse(element.getAttribute(name) ?? "null");
|
|
149
|
+
if (!Array.isArray(parsed)) return null;
|
|
150
|
+
const [originalValue, originalPriority, writtenValue, writtenPriority, ...rest] = parsed;
|
|
151
|
+
if (typeof originalValue !== "string" || typeof originalPriority !== "string") return null;
|
|
152
|
+
if (typeof writtenValue !== "string" && writtenValue !== null) return null;
|
|
153
|
+
if (typeof writtenPriority !== "string") return null;
|
|
154
|
+
const linked = rest[0] !== false;
|
|
155
|
+
const beneath = linked ? rest : rest.slice(1);
|
|
156
|
+
if (!beneath.every((under) => typeof under === "string")) return null;
|
|
157
|
+
return { originalValue, originalPriority, writtenValue, writtenPriority, linked, beneath };
|
|
158
|
+
} catch {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
184
161
|
}
|
|
185
|
-
|
|
186
|
-
|
|
162
|
+
#stack(element) {
|
|
163
|
+
const stacks = _StylePropertyLease.#registry.stacks;
|
|
164
|
+
const byProperty = stacks.get(element) ?? /* @__PURE__ */ new Map();
|
|
165
|
+
stacks.set(element, byProperty);
|
|
166
|
+
const stack = byProperty.get(this.#property) ?? this.#seed(element);
|
|
167
|
+
byProperty.set(this.#property, stack);
|
|
168
|
+
return stack;
|
|
169
|
+
}
|
|
170
|
+
#seed(element) {
|
|
171
|
+
const found = [];
|
|
172
|
+
for (const record of _StylePropertyLease.#registry.names.get(this.#property) ?? []) {
|
|
173
|
+
const read = this.#recorded(element, record);
|
|
174
|
+
if (read) found.push({ ...read, record });
|
|
175
|
+
}
|
|
176
|
+
const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
|
|
177
|
+
return found.sort((one, other) => depth(one) - depth(other)).map((entry, index) => ({
|
|
178
|
+
lease: null,
|
|
179
|
+
record: entry.record,
|
|
180
|
+
writtenValue: entry.writtenValue,
|
|
181
|
+
writtenPriority: entry.writtenPriority,
|
|
182
|
+
originalValue: entry.originalValue,
|
|
183
|
+
originalPriority: entry.originalPriority,
|
|
184
|
+
linked: entry.linked && index > 0
|
|
185
|
+
}));
|
|
186
|
+
}
|
|
187
|
+
#take(stack) {
|
|
188
|
+
const hold = stack.find((held) => held.lease === this) ?? stack.find((held) => held.lease === null && held.record === this.#record);
|
|
189
|
+
if (hold) hold.lease = this;
|
|
190
|
+
return hold;
|
|
191
|
+
}
|
|
192
|
+
#acquire(element, stack) {
|
|
193
|
+
const top = stack.at(-1);
|
|
194
|
+
const over = top && this.#carries(element, top) ? top : void 0;
|
|
187
195
|
const style = element.style;
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
196
|
+
const hold = {
|
|
197
|
+
lease: this,
|
|
198
|
+
record: this.#record,
|
|
199
|
+
writtenValue: null,
|
|
200
|
+
writtenPriority: "",
|
|
201
|
+
originalValue: over ? over.originalValue : style.getPropertyValue(this.#property),
|
|
202
|
+
originalPriority: over ? over.originalPriority : style.getPropertyPriority(this.#property),
|
|
203
|
+
linked: over !== void 0
|
|
204
|
+
};
|
|
205
|
+
stack.push(hold);
|
|
206
|
+
return hold;
|
|
207
|
+
}
|
|
208
|
+
#covered(element, stack, hold) {
|
|
209
|
+
return stack.slice(stack.indexOf(hold) + 1).some((above) => this.#carries(element, above));
|
|
210
|
+
}
|
|
211
|
+
#mark(element, stack) {
|
|
212
|
+
const records = /* @__PURE__ */ new Map([[this.#record, null]]);
|
|
213
|
+
stack.forEach((hold, index) => {
|
|
214
|
+
const names = stack.slice(0, index).map((under) => under.record);
|
|
215
|
+
const beneath = [...new Set(names.reverse())].filter((name) => name !== hold.record);
|
|
216
|
+
const marker = hold.linked || beneath.length === 0 ? [] : [false];
|
|
217
|
+
const { originalValue, originalPriority, writtenValue, writtenPriority } = hold;
|
|
218
|
+
records.set(
|
|
219
|
+
hold.record,
|
|
220
|
+
(writtenValue ?? "") === originalValue && writtenPriority === originalPriority && beneath.length === 0 && index === stack.length - 1 ? null : JSON.stringify([
|
|
221
|
+
originalValue,
|
|
222
|
+
originalPriority,
|
|
223
|
+
writtenValue,
|
|
224
|
+
writtenPriority,
|
|
225
|
+
...marker,
|
|
226
|
+
...beneath
|
|
227
|
+
])
|
|
228
|
+
);
|
|
229
|
+
});
|
|
230
|
+
for (const [name, recorded] of records) {
|
|
231
|
+
setAttributeIfChanged(element, name, recorded);
|
|
192
232
|
}
|
|
193
|
-
|
|
194
|
-
|
|
233
|
+
}
|
|
234
|
+
#carries(element, hold) {
|
|
235
|
+
return this.#holds(element, hold.writtenValue ?? "", hold.writtenPriority);
|
|
236
|
+
}
|
|
237
|
+
#holds(element, value, priority) {
|
|
238
|
+
const style = element.style;
|
|
239
|
+
return style.getPropertyValue(this.#property) === value && style.getPropertyPriority(this.#property) === priority;
|
|
240
|
+
}
|
|
241
|
+
#show(element, value, priority) {
|
|
242
|
+
if (this.#holds(element, value ?? "", priority)) return;
|
|
243
|
+
if (value === null) element.style.removeProperty(this.#property);
|
|
244
|
+
else element.style.setProperty(this.#property, value, priority);
|
|
195
245
|
}
|
|
196
246
|
};
|
|
197
247
|
|
|
198
|
-
// src/controllers/reading_progress_controller.ts
|
|
199
248
|
var PROGRESS_PROPERTY = "--stimeo--reading-progress";
|
|
200
249
|
var ReadingProgressController = class extends Controller {
|
|
201
250
|
static events = ["change", "complete"];
|
|
202
|
-
|
|
203
|
-
#lease = new StylePropertyLease(PROGRESS_PROPERTY);
|
|
204
|
-
/** The article's own box and the viewport: either changes the span. */
|
|
251
|
+
#lease = new StylePropertyLease(PROGRESS_PROPERTY, this.identifier);
|
|
205
252
|
#layout = new LayoutObserver(() => this.#onScroll());
|
|
206
|
-
#beforeCache = new BeforeCacheReset(() => this.#rewindForCache());
|
|
207
|
-
/** Coalesces scroll bursts, and the connect baseline, into one frame. */
|
|
208
253
|
#frames = new FrameCoalescer();
|
|
209
|
-
/** Last published progress, so `change`/`complete` fire only on movement. */
|
|
210
254
|
#progress = -1;
|
|
211
|
-
/** False until the connect frame has run: `complete` needs real reading. */
|
|
212
255
|
#baselined = false;
|
|
213
256
|
#onScroll = () => this.#frames.schedule(() => this.#measure());
|
|
257
|
+
#listeners = new ListenerSet();
|
|
214
258
|
connect() {
|
|
215
259
|
this.#progress = -1;
|
|
216
260
|
this.#baselined = false;
|
|
217
|
-
|
|
261
|
+
this.#listeners.add(window, "scroll", this.#onScroll, { passive: true, capture: true });
|
|
218
262
|
this.#layout.observe(this.element);
|
|
219
263
|
this.#layout.observeViewport();
|
|
220
|
-
this.#beforeCache.activate();
|
|
221
264
|
this.#measure();
|
|
222
265
|
this.#frames.schedule(() => {
|
|
223
266
|
this.#measure();
|
|
@@ -225,25 +268,12 @@ var ReadingProgressController = class extends Controller {
|
|
|
225
268
|
});
|
|
226
269
|
}
|
|
227
270
|
disconnect() {
|
|
228
|
-
|
|
271
|
+
this.#listeners.dispose();
|
|
229
272
|
this.#layout.disconnect();
|
|
230
|
-
this.#beforeCache.deactivate();
|
|
231
|
-
this.#frames.cancel();
|
|
232
|
-
this.#lease.returnAll();
|
|
233
|
-
}
|
|
234
|
-
/**
|
|
235
|
-
* Hands both declarations back before the page is snapshotted, so a restored
|
|
236
|
-
* page starts from the authored DOM rather than from someone else's progress.
|
|
237
|
-
* The baseline goes back with them: a cancelled visit leaves this page on
|
|
238
|
-
* screen, and the next measurement has to publish afresh rather than match a
|
|
239
|
-
* value that has already been handed back.
|
|
240
|
-
*/
|
|
241
|
-
#rewindForCache() {
|
|
242
273
|
this.#frames.cancel();
|
|
243
|
-
this.#lease.
|
|
244
|
-
this.#
|
|
274
|
+
this.#lease.return(this.element);
|
|
275
|
+
this.#lease.return(document.documentElement);
|
|
245
276
|
}
|
|
246
|
-
/** Computes and publishes the progress; emits on movement only. */
|
|
247
277
|
#measure() {
|
|
248
278
|
const rect = this.element.getBoundingClientRect();
|
|
249
279
|
if (rect.width === 0 && rect.height === 0) return;
|
|
@@ -262,5 +292,4 @@ var ReadingProgressController = class extends Controller {
|
|
|
262
292
|
};
|
|
263
293
|
|
|
264
294
|
export { ReadingProgressController };
|
|
265
|
-
//# sourceMappingURL=reading_progress_controller.js.map
|
|
266
295
|
//# sourceMappingURL=reading_progress_controller.js.map
|