dsh-remote-plugin 0.6.13 → 0.6.15

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.
@@ -0,0 +1,206 @@
1
+ import { a as buildPlan, c as interpPolar, n as Spring, o as allocOutputs, r as resampleIcon, t as SPRING_PRESETS } from "./spring-CFHloqPP.js";
2
+ import { i as serialize, n as iconToCubics, r as cubicsToPathD } from "./normalize-CYnN3Npw.js";
3
+ //#region src/dom/index.ts
4
+ const tickers = /* @__PURE__ */ new Set();
5
+ let rafId = 0;
6
+ let last = -1;
7
+ function loop(ts) {
8
+ const dt = last < 0 ? 0 : Math.min(Math.max((ts - last) / 1e3, 0), .1);
9
+ last = ts;
10
+ for (const tick of [...tickers]) tick(dt);
11
+ if (tickers.size > 0) rafId = requestAnimationFrame(loop);
12
+ else {
13
+ rafId = 0;
14
+ last = -1;
15
+ }
16
+ }
17
+ function addTicker(tick) {
18
+ tickers.add(tick);
19
+ if (rafId === 0) {
20
+ last = -1;
21
+ rafId = requestAnimationFrame(loop);
22
+ }
23
+ }
24
+ function removeTicker(tick) {
25
+ tickers.delete(tick);
26
+ if (tickers.size === 0 && rafId !== 0) {
27
+ cancelAnimationFrame(rafId);
28
+ rafId = 0;
29
+ last = -1;
30
+ }
31
+ }
32
+ const samples = /* @__PURE__ */ new WeakMap();
33
+ const canon = /* @__PURE__ */ new WeakMap();
34
+ const plans = /* @__PURE__ */ new WeakMap();
35
+ function sampledOf(icon) {
36
+ if (typeof icon === "string") return resampleIcon(icon);
37
+ let s = samples.get(icon);
38
+ if (!s) {
39
+ s = resampleIcon(icon);
40
+ samples.set(icon, s);
41
+ }
42
+ return s;
43
+ }
44
+ /** Canonical `d` of an icon: the input string verbatim, or the real cubics
45
+ * quantized to 4 decimals (the at-rest snap; engine-stable bytes so SSR
46
+ * hydration matches, see fmtCanon in core/serialize). Exported because it
47
+ * is what a binding renders at SSR/rest before any runtime exists. */
48
+ function canonicalD(icon) {
49
+ if (typeof icon === "string") return icon;
50
+ let d = canon.get(icon);
51
+ if (!d) {
52
+ d = cubicsToPathD(iconToCubics(icon));
53
+ canon.set(icon, d);
54
+ }
55
+ return d;
56
+ }
57
+ function planBetween(src, dst) {
58
+ if (typeof src === "string" || typeof dst === "string") return buildPlan(sampledOf(src), sampledOf(dst));
59
+ let inner = plans.get(src);
60
+ if (!inner) {
61
+ inner = /* @__PURE__ */ new WeakMap();
62
+ plans.set(src, inner);
63
+ }
64
+ let p = inner.get(dst);
65
+ if (!p) {
66
+ p = buildPlan(sampledOf(src), sampledOf(dst));
67
+ inner.set(dst, p);
68
+ }
69
+ return p;
70
+ }
71
+ function resolveSpring(s) {
72
+ if (typeof s === "string") return SPRING_PRESETS[s];
73
+ const d = SPRING_PRESETS.snappy;
74
+ return {
75
+ k: s?.stiffness ?? d.k,
76
+ c: s?.damping ?? d.c
77
+ };
78
+ }
79
+ /** Creates the morph instance over a `<path>` and paints the initial icon. */
80
+ function createMorph(el, icon, options) {
81
+ const spring = new Spring();
82
+ let reducedMotion = options?.reducedMotion ?? "never";
83
+ let target = icon;
84
+ let rest = true;
85
+ let plan = null;
86
+ let out = null;
87
+ let closed = null;
88
+ let t = 1;
89
+ let flying = false;
90
+ let dead = false;
91
+ el.setAttribute("d", canonicalD(icon));
92
+ const render = (tt) => {
93
+ const p = plan;
94
+ const o = out;
95
+ const cl = closed;
96
+ if (!p || !o || !cl) return;
97
+ t = tt;
98
+ interpPolar(p, tt, o);
99
+ el.setAttribute("d", serialize(o, cl));
100
+ };
101
+ const stop = () => {
102
+ if (!flying) return;
103
+ flying = false;
104
+ removeTicker(tick);
105
+ };
106
+ const tick = (dt) => {
107
+ const settled = spring.step(dt);
108
+ render(spring.x);
109
+ if (settled) {
110
+ stop();
111
+ settle();
112
+ }
113
+ };
114
+ const settle = () => {
115
+ rest = true;
116
+ plan = null;
117
+ out = null;
118
+ closed = null;
119
+ t = 1;
120
+ spring.x = 1;
121
+ spring.v = 0;
122
+ el.setAttribute("d", canonicalD(target));
123
+ };
124
+ /** The current shape as plan source: the at-rest icon, or the rendered
125
+ * buffers (already N points per subpath). */
126
+ const snapshot = () => {
127
+ const p = plan;
128
+ const o = out;
129
+ if (rest || !p || !o) return sampledOf(target);
130
+ return o.map((buf, k) => ({
131
+ pts: Float64Array.from(buf),
132
+ closed: p.items[k].closed
133
+ }));
134
+ };
135
+ const retarget = (icon) => {
136
+ plan = rest ? planBetween(target, icon) : buildPlan(snapshot(), sampledOf(icon));
137
+ out = allocOutputs(plan);
138
+ closed = plan.items.map((it) => it.closed);
139
+ target = icon;
140
+ rest = false;
141
+ };
142
+ const setNow = (icon) => {
143
+ stop();
144
+ target = icon;
145
+ settle();
146
+ };
147
+ /** True when the policy says this morphTo must jump instead of flying. */
148
+ const motionOff = () => {
149
+ if (reducedMotion === "always") return true;
150
+ if (reducedMotion !== "user") return false;
151
+ if (typeof matchMedia === "undefined") return false;
152
+ return matchMedia?.("(prefers-reduced-motion: reduce)").matches ?? false;
153
+ };
154
+ const seek = (icon, tt) => {
155
+ if (dead) return;
156
+ const reuse = !rest && plan !== null && icon === target;
157
+ stop();
158
+ spring.v = 0;
159
+ if (!reuse) retarget(icon);
160
+ render(tt);
161
+ };
162
+ return {
163
+ morphTo(icon, sp) {
164
+ if (dead) return;
165
+ if (icon === target && (rest || flying)) return;
166
+ if (motionOff()) {
167
+ setNow(icon);
168
+ return;
169
+ }
170
+ const { k, c } = resolveSpring(sp);
171
+ spring.config(k, c);
172
+ retarget(icon);
173
+ spring.start();
174
+ if (!flying) {
175
+ flying = true;
176
+ addTicker(tick);
177
+ }
178
+ },
179
+ set(icon) {
180
+ if (dead) return;
181
+ setNow(icon);
182
+ },
183
+ seek,
184
+ get progress() {
185
+ return rest ? 1 : t;
186
+ },
187
+ set progress(v) {
188
+ if (!dead) seek(target, v);
189
+ },
190
+ get reducedMotion() {
191
+ return reducedMotion;
192
+ },
193
+ set reducedMotion(v) {
194
+ reducedMotion = v;
195
+ },
196
+ destroy() {
197
+ stop();
198
+ dead = true;
199
+ plan = null;
200
+ out = null;
201
+ closed = null;
202
+ }
203
+ };
204
+ }
205
+ //#endregion
206
+ export { canonicalD, createMorph };
@@ -0,0 +1,261 @@
1
+ import { n as createController, t as computeInitialD } from "./controller-CXZuwJ_M.js";
2
+ //#region src/element/index.ts
3
+ const SVG_NS = "http://www.w3.org/2000/svg";
4
+ const REACTIVE = [
5
+ "icon",
6
+ "from",
7
+ "to",
8
+ "progress",
9
+ "spring",
10
+ "reducedMotion"
11
+ ];
12
+ const PRESENTATION = /* @__PURE__ */ new Set([
13
+ "size",
14
+ "color",
15
+ "stroke-width",
16
+ "absolute-stroke-width",
17
+ "label"
18
+ ]);
19
+ const Base = typeof HTMLElement === "undefined" ? class {} : HTMLElement;
20
+ var MorphIconElement = class extends Base {
21
+ static observedAttributes = [
22
+ "icon",
23
+ "from",
24
+ "to",
25
+ "progress",
26
+ "spring",
27
+ "reduced-motion",
28
+ "size",
29
+ "color",
30
+ "stroke-width",
31
+ "absolute-stroke-width",
32
+ "label"
33
+ ];
34
+ #props = {};
35
+ #ctrl = null;
36
+ #path = null;
37
+ #adopted = false;
38
+ #preConnectDirty = false;
39
+ #size = "24";
40
+ #color = "currentColor";
41
+ #strokeWidth = "2";
42
+ #absoluteStrokeWidth = false;
43
+ #label = null;
44
+ get icon() {
45
+ return this.#props.icon;
46
+ }
47
+ set icon(v) {
48
+ this.#props.icon = v;
49
+ this.#watch();
50
+ }
51
+ get from() {
52
+ return this.#props.from;
53
+ }
54
+ set from(v) {
55
+ this.#props.from = v;
56
+ this.#watch();
57
+ }
58
+ get to() {
59
+ return this.#props.to;
60
+ }
61
+ set to(v) {
62
+ this.#props.to = v;
63
+ this.#watch();
64
+ }
65
+ get progress() {
66
+ return this.#props.progress;
67
+ }
68
+ set progress(v) {
69
+ this.#props.progress = v;
70
+ this.#watch();
71
+ }
72
+ get spring() {
73
+ return this.#props.spring;
74
+ }
75
+ set spring(v) {
76
+ this.#props.spring = v;
77
+ this.#watch();
78
+ }
79
+ get reducedMotion() {
80
+ return this.#props.reducedMotion;
81
+ }
82
+ set reducedMotion(v) {
83
+ this.#props.reducedMotion = v;
84
+ this.#watch();
85
+ }
86
+ morphTo(icon, spring) {
87
+ const ctrl = this.#ctrl;
88
+ if (!ctrl) {
89
+ this.#imperativeBeforeDriver(icon);
90
+ return;
91
+ }
92
+ ctrl.morphTo(icon, spring ?? this.#props.spring);
93
+ }
94
+ set(icon) {
95
+ const ctrl = this.#ctrl;
96
+ if (!ctrl) {
97
+ this.#imperativeBeforeDriver(icon);
98
+ return;
99
+ }
100
+ ctrl.set(icon);
101
+ }
102
+ connectedCallback() {
103
+ for (const key of REACTIVE) this.#upgradeProperty(key);
104
+ if (!this.#path) this.#adoptOrRender();
105
+ if (this.style.display === "") this.style.display = "contents";
106
+ if (this.#path && !this.#ctrl) {
107
+ const path = this.#path;
108
+ const gate = this.#adopted && !this.#preConnectDirty;
109
+ this.#adopted = false;
110
+ this.#ctrl = createController(this.#props);
111
+ if (gate) {
112
+ let armed = false;
113
+ const gated = { setAttribute(name, value) {
114
+ if (armed) path.setAttribute(name, value);
115
+ } };
116
+ try {
117
+ this.#ctrl.mount(gated, this.#props);
118
+ } finally {
119
+ armed = true;
120
+ }
121
+ } else this.#ctrl.mount(path, this.#props);
122
+ }
123
+ }
124
+ disconnectedCallback() {
125
+ this.#ctrl?.destroy();
126
+ this.#ctrl = null;
127
+ }
128
+ attributeChangedCallback(name, _old, value) {
129
+ switch (name) {
130
+ case "icon":
131
+ this.#props.icon = value ?? void 0;
132
+ break;
133
+ case "from":
134
+ this.#props.from = value ?? void 0;
135
+ break;
136
+ case "to":
137
+ this.#props.to = value ?? void 0;
138
+ break;
139
+ case "progress": {
140
+ const n = value === null ? NaN : Number(value);
141
+ this.#props.progress = Number.isFinite(n) ? n : void 0;
142
+ break;
143
+ }
144
+ case "spring":
145
+ this.#props.spring = value ?? void 0;
146
+ break;
147
+ case "reduced-motion":
148
+ this.#props.reducedMotion = value ?? void 0;
149
+ break;
150
+ case "size":
151
+ this.#size = value ?? "24";
152
+ break;
153
+ case "color":
154
+ this.#color = value ?? "currentColor";
155
+ break;
156
+ case "stroke-width":
157
+ this.#strokeWidth = value ?? "2";
158
+ break;
159
+ case "absolute-stroke-width":
160
+ this.#absoluteStrokeWidth = value !== null;
161
+ break;
162
+ case "label": this.#label = value;
163
+ }
164
+ if (!this.#path) return;
165
+ if (PRESENTATION.has(name)) {
166
+ const svg = this.querySelector("svg");
167
+ if (svg) this.#applyPresentation(svg);
168
+ return;
169
+ }
170
+ this.#watch();
171
+ }
172
+ /** A property assigned before the element was defined lands as an own
173
+ * value that shadows the accessor; re-route it through the setter. */
174
+ #upgradeProperty(key) {
175
+ if (Object.hasOwn(this, key)) {
176
+ const self = this;
177
+ const v = self[key];
178
+ delete self[key];
179
+ self[key] = v;
180
+ }
181
+ }
182
+ #watch() {
183
+ const ctrl = this.#ctrl;
184
+ if (!ctrl) {
185
+ this.#preConnectDirty = true;
186
+ return;
187
+ }
188
+ ctrl.watch(this.#props);
189
+ }
190
+ /** Imperative call before the controller exists: adopt the icon as the
191
+ * mount state AND exit controlled mode — "every imperative call
192
+ * invalidates the frozen pair" must hold pre-connect too, or a pending
193
+ * pair would win the mount and silently discard this call. */
194
+ #imperativeBeforeDriver(icon) {
195
+ this.#props.icon = icon;
196
+ this.#props.from = void 0;
197
+ this.#props.to = void 0;
198
+ this.#preConnectDirty = true;
199
+ }
200
+ /** SSR markup is adopted verbatim (the element never rewrites server bytes
201
+ * at rest); without it, the element renders its own <svg> like the
202
+ * framework shells do. */
203
+ #adoptOrRender() {
204
+ const existing = this.querySelector("path");
205
+ if (existing) {
206
+ this.#path = existing;
207
+ this.#adopted = true;
208
+ const p = this.#props;
209
+ if (p.icon === void 0 && p.from === void 0 && p.to === void 0) {
210
+ const d = existing.getAttribute("d");
211
+ if (d) p.icon = d;
212
+ }
213
+ return;
214
+ }
215
+ const doc = this.ownerDocument;
216
+ const svg = doc.createElementNS(SVG_NS, "svg");
217
+ svg.setAttribute("xmlns", SVG_NS);
218
+ svg.setAttribute("viewBox", "0 0 24 24");
219
+ svg.setAttribute("fill", "none");
220
+ svg.setAttribute("stroke-linecap", "round");
221
+ svg.setAttribute("stroke-linejoin", "round");
222
+ this.#applyPresentation(svg);
223
+ const path = doc.createElementNS(SVG_NS, "path");
224
+ path.setAttribute("d", computeInitialD(this.#props));
225
+ svg.appendChild(path);
226
+ this.appendChild(svg);
227
+ this.#path = path;
228
+ }
229
+ #applyPresentation(svg) {
230
+ svg.setAttribute("width", this.#size);
231
+ svg.setAttribute("height", this.#size);
232
+ svg.setAttribute("stroke", this.#color);
233
+ const sw = this.#absoluteStrokeWidth ? String(Number(this.#strokeWidth) * 24 / Number(this.#size)) : this.#strokeWidth;
234
+ svg.setAttribute("stroke-width", sw);
235
+ const label = this.#label;
236
+ let title = svg.querySelector("title");
237
+ if (label) {
238
+ svg.setAttribute("role", "img");
239
+ svg.removeAttribute("aria-hidden");
240
+ if (!title) {
241
+ title = this.ownerDocument.createElementNS(SVG_NS, "title");
242
+ svg.insertBefore(title, svg.firstChild);
243
+ }
244
+ title.textContent = label;
245
+ } else {
246
+ svg.removeAttribute("role");
247
+ svg.setAttribute("aria-hidden", "true");
248
+ title?.remove();
249
+ }
250
+ }
251
+ };
252
+ let registered = false;
253
+ /** Defines `<morph-icon>` (or a custom tag). Idempotent per tag; a no-op
254
+ * without a DOM (safe to call from code that also runs during SSR). */
255
+ function defineMorphIcon(tag = "morph-icon") {
256
+ if (typeof customElements === "undefined" || customElements.get(tag)) return;
257
+ customElements.define(tag, registered ? class extends MorphIconElement {} : MorphIconElement);
258
+ registered = true;
259
+ }
260
+ //#endregion
261
+ export { MorphIconElement, computeInitialD, defineMorphIcon };