@lark-apaas/coding-registry-buildless 0.1.7 → 0.1.8-alpha.20260720141429
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/components/tweaks-panel.jsx +12 -8
- package/package.json +1 -1
- package/scripts/deck-stage.js +52 -16
|
@@ -63,9 +63,9 @@
|
|
|
63
63
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
64
64
|
|
|
65
65
|
const __TWEAKS_STYLE = `
|
|
66
|
-
.twk-panel{position:fixed;right:16px;
|
|
66
|
+
.twk-panel{position:fixed;right:16px;top:16px;z-index:2147483646;width:280px;
|
|
67
67
|
max-height:calc(100vh - 32px);display:flex;flex-direction:column;
|
|
68
|
-
transform:scale(var(--dc-inv-zoom,1));transform-origin:
|
|
68
|
+
transform:scale(var(--dc-inv-zoom,1));transform-origin:top right;
|
|
69
69
|
background:rgba(250,249,247,.78);color:#29261b;
|
|
70
70
|
-webkit-backdrop-filter:blur(24px) saturate(160%);backdrop-filter:blur(24px) saturate(160%);
|
|
71
71
|
border:.5px solid rgba(255,255,255,.6);border-radius:14px;
|
|
@@ -202,6 +202,10 @@ function useTweaks(defaults) {
|
|
|
202
202
|
function TweaksPanel({ title = 'Tweaks', children }) {
|
|
203
203
|
const [open, setOpen] = React.useState(false);
|
|
204
204
|
const dragRef = React.useRef(null);
|
|
205
|
+
// x = distance from the viewport's right edge, y = distance from its TOP.
|
|
206
|
+
// The panel anchors top-right (right/top in CSS) so it clears the host's
|
|
207
|
+
// bottom toolbar; both axes still grow inward, so clamp/drag math is
|
|
208
|
+
// symmetric with the old bottom-right anchor.
|
|
205
209
|
const offsetRef = React.useRef({ x: 16, y: 16 });
|
|
206
210
|
const PAD = 16;
|
|
207
211
|
|
|
@@ -210,13 +214,13 @@ function TweaksPanel({ title = 'Tweaks', children }) {
|
|
|
210
214
|
if (!panel) return;
|
|
211
215
|
const w = panel.offsetWidth, h = panel.offsetHeight;
|
|
212
216
|
const maxRight = Math.max(PAD, window.innerWidth - w - PAD);
|
|
213
|
-
const
|
|
217
|
+
const maxTop = Math.max(PAD, window.innerHeight - h - PAD);
|
|
214
218
|
offsetRef.current = {
|
|
215
219
|
x: Math.min(maxRight, Math.max(PAD, offsetRef.current.x)),
|
|
216
|
-
y: Math.min(
|
|
220
|
+
y: Math.min(maxTop, Math.max(PAD, offsetRef.current.y)),
|
|
217
221
|
};
|
|
218
222
|
panel.style.right = offsetRef.current.x + 'px';
|
|
219
|
-
panel.style.
|
|
223
|
+
panel.style.top = offsetRef.current.y + 'px';
|
|
220
224
|
}, []);
|
|
221
225
|
|
|
222
226
|
React.useEffect(() => {
|
|
@@ -253,11 +257,11 @@ function TweaksPanel({ title = 'Tweaks', children }) {
|
|
|
253
257
|
const r = panel.getBoundingClientRect();
|
|
254
258
|
const sx = e.clientX, sy = e.clientY;
|
|
255
259
|
const startRight = window.innerWidth - r.right;
|
|
256
|
-
const
|
|
260
|
+
const startTop = r.top;
|
|
257
261
|
const move = (ev) => {
|
|
258
262
|
offsetRef.current = {
|
|
259
263
|
x: startRight - (ev.clientX - sx),
|
|
260
|
-
y:
|
|
264
|
+
y: startTop + (ev.clientY - sy),
|
|
261
265
|
};
|
|
262
266
|
clampToViewport();
|
|
263
267
|
};
|
|
@@ -274,7 +278,7 @@ function TweaksPanel({ title = 'Tweaks', children }) {
|
|
|
274
278
|
<>
|
|
275
279
|
<style>{__TWEAKS_STYLE}</style>
|
|
276
280
|
<div ref={dragRef} className="twk-panel" data-miaoda-chrome=""
|
|
277
|
-
style={{ right: offsetRef.current.x,
|
|
281
|
+
style={{ right: offsetRef.current.x, top: offsetRef.current.y }}>
|
|
278
282
|
<div className="twk-hd" onMouseDown={onDragStart}>
|
|
279
283
|
<b>{title}</b>
|
|
280
284
|
<button className="twk-x" aria-label="Close tweaks"
|
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.8-alpha.20260720141429",
|
|
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
|
@@ -38,10 +38,11 @@
|
|
|
38
38
|
* a scrollable vertical card list (browse) and a rotated fullscreen
|
|
39
39
|
* presenting mode. This needs NO authoring changes: never hand-roll
|
|
40
40
|
* mobile/responsive slide layouts. Desktop behaviour is unchanged.
|
|
41
|
-
* Browse mode renders
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
41
|
+
* Browse mode renders each slide's static base state and never fires
|
|
42
|
+
* entrance animations — exactly like the thumbnail rail and print
|
|
43
|
+
* (presenting keeps animations). One more surface that requires the
|
|
44
|
+
* visible end-state to be the base style (see Entrance animations
|
|
45
|
+
* below).
|
|
45
46
|
*
|
|
46
47
|
* Slides are HIDDEN, not unmounted. Non-active slides stay in the DOM with
|
|
47
48
|
* `visibility: hidden` + `opacity: 0`, so their state (videos, iframes,
|
|
@@ -139,6 +140,7 @@
|
|
|
139
140
|
const MOB_RADIUS = 8; // card corner radius
|
|
140
141
|
const MOB_BADGE_IDLE_MS = 2000; // scroll idle before the page badge fades
|
|
141
142
|
const MOB_UI_HIDE_MS = 3000; // presenting controls auto-hide
|
|
143
|
+
const CANVAS_RECAP_MS = 1200; // re-snapshot canvas thumbs once chart entrance animations settle
|
|
142
144
|
|
|
143
145
|
const pad2 = (n) => String(n).padStart(2, '0');
|
|
144
146
|
|
|
@@ -1037,6 +1039,7 @@
|
|
|
1037
1039
|
if (this._scaleRaf) cancelAnimationFrame(this._scaleRaf);
|
|
1038
1040
|
if (this._liveObserver) this._liveObserver.disconnect();
|
|
1039
1041
|
if (this._railObserver) this._railObserver.disconnect();
|
|
1042
|
+
(this._thumbs || []).forEach((t) => clearTimeout(t._canvasRecapTimer));
|
|
1040
1043
|
if (this._onTweakChange) window.removeEventListener('tweakchange', this._onTweakChange);
|
|
1041
1044
|
}
|
|
1042
1045
|
|
|
@@ -1364,26 +1367,38 @@
|
|
|
1364
1367
|
'animation-play-state: running !important; transition-duration: 0s !important; } }';
|
|
1365
1368
|
}
|
|
1366
1369
|
|
|
1367
|
-
/** Mobile browse (data-mobile-list)
|
|
1368
|
-
*
|
|
1369
|
-
*
|
|
1370
|
-
*
|
|
1371
|
-
*
|
|
1372
|
-
*
|
|
1373
|
-
*
|
|
1374
|
-
*
|
|
1375
|
-
*
|
|
1376
|
-
*
|
|
1370
|
+
/** Mobile browse (data-mobile-list) renders each card's static BASE
|
|
1371
|
+
* state — the same semantic as the thumbnail rail, print and
|
|
1372
|
+
* reduced-motion. The USAGE authoring contract makes the base style the
|
|
1373
|
+
* visible end-state (hidden lives only inside keyframes' `from`, gated
|
|
1374
|
+
* on [data-deck-active]), so animation-name:none shows exactly the
|
|
1375
|
+
* intended slide. Freezing at the END state instead would key visible
|
|
1376
|
+
* styling to a flag that MOVES during scroll: keyframe properties
|
|
1377
|
+
* (transform especially — it replaces the base value outright) snap on
|
|
1378
|
+
* and off as [data-deck-active] arrives at and leaves each card,
|
|
1379
|
+
* jolting layout. The timing longhands stay as a backstop: an authored
|
|
1380
|
+
* `animation … !important` that out-cascades our name:none still
|
|
1381
|
+
* collapses to an instant run. The attribute selector is repeated to
|
|
1382
|
+
* out-rank authored !important rules — important-vs-important resolves
|
|
1383
|
+
* by specificity, and the common `[data-deck-active] .x` gate is only
|
|
1384
|
+
* (0,2,0). Document-level like the print rule: author animations style
|
|
1385
|
+
* light-DOM slide content that shadow CSS can't reach, and <deck-stage>
|
|
1386
|
+
* is a light-DOM element document CSS can key on. Presenting/desktop
|
|
1387
|
+
* keep their animations — the rule is keyed on the host attribute, no
|
|
1388
|
+
* JS toggling needed. */
|
|
1377
1389
|
_syncMobFreezeRule() {
|
|
1378
1390
|
const id = 'deck-stage-mob-freeze';
|
|
1379
1391
|
if (document.getElementById(id)) return;
|
|
1392
|
+
const sel = 'deck-stage[data-mobile-list][data-mobile-list][data-mobile-list]';
|
|
1380
1393
|
const tag = document.createElement('style');
|
|
1381
1394
|
tag.id = id;
|
|
1382
1395
|
tag.textContent =
|
|
1383
|
-
'
|
|
1396
|
+
sel + ' *, ' + sel + ' *::before, ' + sel + ' *::after {' +
|
|
1397
|
+
' animation-name: none !important;' +
|
|
1384
1398
|
' animation-delay: -99s !important; animation-duration: .001s !important;' +
|
|
1385
1399
|
' animation-iteration-count: 1 !important; animation-fill-mode: both !important;' +
|
|
1386
|
-
' animation-play-state: running !important;
|
|
1400
|
+
' animation-play-state: running !important;' +
|
|
1401
|
+
' transition-duration: 0s !important; transition-delay: 0s !important; }';
|
|
1387
1402
|
document.head.appendChild(tag);
|
|
1388
1403
|
}
|
|
1389
1404
|
|
|
@@ -2063,6 +2078,7 @@
|
|
|
2063
2078
|
// Orphans — slides removed since last render.
|
|
2064
2079
|
bySlide.forEach((t) => {
|
|
2065
2080
|
if (this._railObserver) this._railObserver.unobserve(t.frame);
|
|
2081
|
+
clearTimeout(t._canvasRecapTimer);
|
|
2066
2082
|
t.thumb.remove();
|
|
2067
2083
|
});
|
|
2068
2084
|
// Put thumbs into document order to match _slides. insertBefore on
|
|
@@ -2276,6 +2292,7 @@
|
|
|
2276
2292
|
// drawings appear in the thumbnail instead of a blank rectangle.
|
|
2277
2293
|
const origCanvases = entry.slide.querySelectorAll('canvas');
|
|
2278
2294
|
const cloneCanvases = clone.querySelectorAll('canvas');
|
|
2295
|
+
const canvasImgs = []; // {orig, img} pairs kept for the delayed re-snapshot below
|
|
2279
2296
|
cloneCanvases.forEach((el, ci) => {
|
|
2280
2297
|
const orig = origCanvases[ci];
|
|
2281
2298
|
if (!orig || !orig.width || !orig.height) return;
|
|
@@ -2287,6 +2304,7 @@
|
|
|
2287
2304
|
';width:' + orig.offsetWidth + 'px;height:' + orig.offsetHeight + 'px;';
|
|
2288
2305
|
img.className = el.className;
|
|
2289
2306
|
el.replaceWith(img);
|
|
2307
|
+
canvasImgs.push({ orig, img });
|
|
2290
2308
|
} catch (e) {}
|
|
2291
2309
|
});
|
|
2292
2310
|
// Images: defer decode and let the browser pick the smallest
|
|
@@ -2351,6 +2369,23 @@
|
|
|
2351
2369
|
// Once materialized the IO callback is a no-op early-return —
|
|
2352
2370
|
// unobserve so scroll doesn't keep firing it.
|
|
2353
2371
|
if (this._railObserver) this._railObserver.unobserve(entry.frame);
|
|
2372
|
+
// Chart libraries (ECharts/Chart.js) animate their entrance over ~1s and
|
|
2373
|
+
// draw straight to the canvas bitmap — no DOM mutation, so _liveObserver
|
|
2374
|
+
// never sees the finished frame and the toDataURL snapshot above may have
|
|
2375
|
+
// caught a blank or mid-animation canvas. Re-snapshot once after the
|
|
2376
|
+
// animation settles and overwrite each <img>. Guarded so a thumb that was
|
|
2377
|
+
// refreshed (host swapped) or removed (img detached) since is left alone.
|
|
2378
|
+
if (canvasImgs.length) {
|
|
2379
|
+
clearTimeout(entry._canvasRecapTimer);
|
|
2380
|
+
entry._canvasRecapTimer = setTimeout(() => {
|
|
2381
|
+
entry._canvasRecapTimer = null;
|
|
2382
|
+
if (entry.host !== host) return;
|
|
2383
|
+
canvasImgs.forEach(({ orig, img }) => {
|
|
2384
|
+
if (!img.isConnected || !orig.width || !orig.height) return;
|
|
2385
|
+
try { img.src = orig.toDataURL(); } catch (e) {}
|
|
2386
|
+
});
|
|
2387
|
+
}, CANVAS_RECAP_MS);
|
|
2388
|
+
}
|
|
2354
2389
|
}
|
|
2355
2390
|
|
|
2356
2391
|
/** Re-clone a single thumb (live-update path). No-op if the thumb
|
|
@@ -2359,6 +2394,7 @@
|
|
|
2359
2394
|
_refreshThumb(slide) {
|
|
2360
2395
|
const entry = (this._thumbs || []).find((t) => t.slide === slide);
|
|
2361
2396
|
if (!entry || !entry.host) return;
|
|
2397
|
+
clearTimeout(entry._canvasRecapTimer);
|
|
2362
2398
|
entry.host.remove();
|
|
2363
2399
|
entry.host = entry.clone = null;
|
|
2364
2400
|
this._materialize(entry);
|