@lark-apaas/coding-registry-buildless 0.1.17 → 0.1.18-beta.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.
- package/package.json +1 -1
- package/scripts/deck-stage.js +80 -14
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lark-apaas/coding-registry-buildless",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.18-beta.0",
|
|
4
4
|
"description": "Miaoda registry (buildless runtime) — shadcn-style copy-in SDKs (globals + CDN-pinned, browser Babel) for buildless static HTML stacks",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
package/scripts/deck-stage.js
CHANGED
|
@@ -130,6 +130,28 @@
|
|
|
130
130
|
// Slide-authored controls that should keep a tap instead of it navigating.
|
|
131
131
|
const INTERACTIVE_SEL = 'a[href], button, input, select, textarea, summary, label, video[controls], audio[controls], [role="button"], [onclick], [tabindex]:not([tabindex^="-"]), [contenteditable]:not([contenteditable="false" i])';
|
|
132
132
|
|
|
133
|
+
/* Custom element families whose thumbnail clones keep their tag instead of
|
|
134
|
+
* being neutered (see _materialize).
|
|
135
|
+
*
|
|
136
|
+
* A whitelist rather than repairing the replacement <div>: rewriting the tag
|
|
137
|
+
* drops every selector keyed on it at once — the type selector plus any
|
|
138
|
+
* combinator naming it, and cd-elements styles its elements exactly that way
|
|
139
|
+
* (`cd-image{display:contents}`) — so copying declarations back onto the div
|
|
140
|
+
* is unbounded and only ever partially right. Restoring `display` alone leaves
|
|
141
|
+
* `my-cols{display:grid;grid-template-columns:1fr 1fr}` a one-column grid.
|
|
142
|
+
*
|
|
143
|
+
* Admission needs both, since a whitelisted clone mounts once per thumbnail:
|
|
144
|
+
* 1. rendered content sits in the element's own light DOM, so cloneNode
|
|
145
|
+
* already captured it and re-mounting adds nothing;
|
|
146
|
+
* 2. mounting is idempotent and side-effect-free.
|
|
147
|
+
* cd-* qualifies: <cd-image> inlines a real <img> carrying the computed
|
|
148
|
+
* src/srcset, and render() is an idempotent attribute pass over an <img> it
|
|
149
|
+
* reuses. It costs one thing — render() also resets that img's `sizes`,
|
|
150
|
+
* discarding the rail-width hint _materialize sets; the URL still matches the
|
|
151
|
+
* slide's, so the thumb reuses the slide's decoded bitmap. */
|
|
152
|
+
const KEEP_LIVE_PREFIXES = ['cd-'];
|
|
153
|
+
const keepsCloneLive = (el) => KEEP_LIVE_PREFIXES.some((p) => el.localName.startsWith(p));
|
|
154
|
+
|
|
133
155
|
// Mirrors the host platform's isMobile() (UA regex + iPad maxTouchPoints);
|
|
134
156
|
// the product iframe is cross-origin, so the shared helper can't be
|
|
135
157
|
// imported. Deliberately NOT viewport-based: the desktop workbench renders
|
|
@@ -865,16 +887,22 @@
|
|
|
865
887
|
}
|
|
866
888
|
});
|
|
867
889
|
}, { root: this._rail, rootMargin: '400px 0px' });
|
|
868
|
-
//
|
|
869
|
-
//
|
|
870
|
-
//
|
|
871
|
-
//
|
|
872
|
-
//
|
|
873
|
-
//
|
|
874
|
-
//
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
890
|
+
// Whenever author CSS changes anywhere outside the slides, the thumbnail
|
|
891
|
+
// clones need it re-snapshotted: they read author styles through a
|
|
892
|
+
// separate constructable sheet, not through the document. _liveObserver
|
|
893
|
+
// only watches the slides, so it never sees a rule written on <html>,
|
|
894
|
+
// <body>, a wrapper div, or a <style>/<link> in head. Re-snapshot (the
|
|
895
|
+
// sheet is shared by reference, so one replaceSync updates every thumb
|
|
896
|
+
// shadow root), then re-sync each thumb host's attrs + custom properties
|
|
897
|
+
// — a freshly arrived sheet can define vars the mirrored values predate.
|
|
898
|
+
// In-slide DOM mutations stay _liveObserver's job.
|
|
899
|
+
//
|
|
900
|
+
// Every trigger shares this one debounce timer on purpose: two triggers
|
|
901
|
+
// landing together must collapse into ONE resync, or it costs two
|
|
902
|
+
// replaceSyncs plus two full passes of var mirroring across every thumb.
|
|
903
|
+
this._resyncAuthorCss = () => {
|
|
904
|
+
clearTimeout(this._authorCssTimer);
|
|
905
|
+
this._authorCssTimer = setTimeout(() => {
|
|
878
906
|
this._snapshotAuthorCss();
|
|
879
907
|
// One getComputedStyle for the whole batch — each
|
|
880
908
|
// getPropertyValue read below reuses the same computed style
|
|
@@ -885,7 +913,42 @@
|
|
|
885
913
|
});
|
|
886
914
|
}, 120);
|
|
887
915
|
};
|
|
916
|
+
// Trigger: the TweaksPanel's sliders/toggles, which write CSS vars
|
|
917
|
+
// outside <deck-stage>. Debouncing is what keeps a slider drag from
|
|
918
|
+
// thrashing the resync.
|
|
919
|
+
this._onTweakChange = () => this._resyncAuthorCss();
|
|
888
920
|
window.addEventListener('tweakchange', this._onTweakChange);
|
|
921
|
+
// A <style>/<link> reaching document.head after the snapshot below has to
|
|
922
|
+
// re-enter it. That snapshot runs while <deck-stage> upgrades, which can
|
|
923
|
+
// precede a deferred or CDN-hosted SDK script injecting a rule the clones
|
|
924
|
+
// need — otherwise whichever <script src> won the race decides whether
|
|
925
|
+
// thumbnails are faithful. cd-elements is the live case: the first
|
|
926
|
+
// <cd-image>'s connectedCallback is what puts `cd-image{display:contents}`
|
|
927
|
+
// in head, and a KEEP_LIVE_PREFIXES clone that misses it renders as an
|
|
928
|
+
// unstyled `display:inline` element.
|
|
929
|
+
// Trigger: a sheet joining or leaving head. Same resync as any other
|
|
930
|
+
// author-CSS change, so it goes through the shared path above — no
|
|
931
|
+
// re-clone needed, and a tweak arriving alongside it collapses into one.
|
|
932
|
+
const restyling = (nodes) => {
|
|
933
|
+
for (const n of nodes) {
|
|
934
|
+
// The print-freeze <style> is head churn this component causes itself,
|
|
935
|
+
// carrying nothing a thumbnail needs.
|
|
936
|
+
if (n === this._freezeStyle) continue;
|
|
937
|
+
if (n.tagName === 'STYLE' || n.tagName === 'LINK') return true;
|
|
938
|
+
}
|
|
939
|
+
return false;
|
|
940
|
+
};
|
|
941
|
+
this._headObserver = new MutationObserver((records) => {
|
|
942
|
+
// Removals matter too: a theme switcher swapping one <link> for another
|
|
943
|
+
// would otherwise leave the dropped sheet's rules in the snapshot.
|
|
944
|
+
for (const r of records) {
|
|
945
|
+
if (restyling(r.addedNodes) || restyling(r.removedNodes)) {
|
|
946
|
+
this._resyncAuthorCss();
|
|
947
|
+
return;
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
});
|
|
951
|
+
this._headObserver.observe(document.head, { childList: true });
|
|
889
952
|
this._snapshotAuthorCss();
|
|
890
953
|
// Build the rail now that it's enabled — slotchange already fired,
|
|
891
954
|
// so _renderRail's early-return skipped the initial build.
|
|
@@ -1081,7 +1144,7 @@
|
|
|
1081
1144
|
if (this._dragGhost) { this._dragGhost.remove(); this._dragGhost = null; }
|
|
1082
1145
|
this.removeEventListener('click', this._onTap);
|
|
1083
1146
|
if (this._liveTimer) clearTimeout(this._liveTimer);
|
|
1084
|
-
if (this.
|
|
1147
|
+
if (this._authorCssTimer) clearTimeout(this._authorCssTimer);
|
|
1085
1148
|
if (this._railAnimTimer) clearTimeout(this._railAnimTimer);
|
|
1086
1149
|
if (this._notesPersistTimer) clearTimeout(this._notesPersistTimer);
|
|
1087
1150
|
clearTimeout(this._mobUiTimer);
|
|
@@ -1090,6 +1153,7 @@
|
|
|
1090
1153
|
if (this._scaleRaf) cancelAnimationFrame(this._scaleRaf);
|
|
1091
1154
|
if (this._liveObserver) this._liveObserver.disconnect();
|
|
1092
1155
|
if (this._railObserver) this._railObserver.disconnect();
|
|
1156
|
+
if (this._headObserver) this._headObserver.disconnect();
|
|
1093
1157
|
(this._thumbs || []).forEach((t) => clearTimeout(t._canvasRecapTimer));
|
|
1094
1158
|
if (this._onTweakChange) window.removeEventListener('tweakchange', this._onTweakChange);
|
|
1095
1159
|
}
|
|
@@ -2377,7 +2441,8 @@
|
|
|
2377
2441
|
});
|
|
2378
2442
|
// Custom elements inside the slide would have their
|
|
2379
2443
|
// connectedCallback fire when the clone is appended. Replace them
|
|
2380
|
-
// with inert boxes
|
|
2444
|
+
// with inert boxes — except the KEEP_LIVE_PREFIXES families — so a
|
|
2445
|
+
// component-heavy deck doesn't run N copies
|
|
2381
2446
|
// of each component's mount logic in the rail. Children are
|
|
2382
2447
|
// preserved so layout-wrapper elements (<my-column><h2>…</h2>)
|
|
2383
2448
|
// still show their authored content; the querySelectorAll NodeList
|
|
@@ -2400,12 +2465,13 @@
|
|
|
2400
2465
|
while (el.firstChild) box.appendChild(el.firstChild);
|
|
2401
2466
|
return box;
|
|
2402
2467
|
};
|
|
2468
|
+
const needsNeuter = (el) => el.localName.includes('-') && !keepsCloneLive(el);
|
|
2403
2469
|
// querySelectorAll('*') returns descendants only — a custom-element
|
|
2404
2470
|
// slide root (<my-slide>…</my-slide>) would slip through and upgrade
|
|
2405
2471
|
// on append. Swap the root first.
|
|
2406
|
-
if (clone
|
|
2472
|
+
if (needsNeuter(clone)) clone = neuter(clone);
|
|
2407
2473
|
clone.querySelectorAll('*').forEach((el) => {
|
|
2408
|
-
if (el
|
|
2474
|
+
if (needsNeuter(el)) el.replaceWith(neuter(el));
|
|
2409
2475
|
});
|
|
2410
2476
|
clone.style.cssText += ';position:absolute;top:0;left:0;transform-origin:0 0;' +
|
|
2411
2477
|
'pointer-events:none;width:' + dw + 'px;height:' + dh + 'px;' +
|