@lark-apaas/coding-registry-buildless 0.1.22 → 0.1.24-alpha.20260902135158
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 +68 -30
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.24-alpha.20260902135158",
|
|
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
|
@@ -35,9 +35,10 @@
|
|
|
35
35
|
* a `deckchange`
|
|
36
36
|
* CustomEvent on the element: detail = {action, from, to, slide}.
|
|
37
37
|
* (g) mobile — on mobile devices the same deck automatically renders as
|
|
38
|
-
* a scrollable vertical card list (browse) and a
|
|
39
|
-
*
|
|
40
|
-
* mobile/responsive slide layouts.
|
|
38
|
+
* a scrollable vertical card list (browse) and a fullscreen presenting
|
|
39
|
+
* mode, pseudo-landscape or upright as the host asks. This needs NO
|
|
40
|
+
* authoring changes: never hand-roll mobile/responsive slide layouts.
|
|
41
|
+
* Desktop behaviour is unchanged.
|
|
41
42
|
* Browse mode renders each slide's static base state and never fires
|
|
42
43
|
* entrance animations — exactly like the thumbnail rail and print
|
|
43
44
|
* (presenting keeps animations). One more surface that requires the
|
|
@@ -100,16 +101,22 @@
|
|
|
100
101
|
* content genuinely needs interactive behaviour static HTML can't express.
|
|
101
102
|
* - Do NOT set position/inset/width/height on the slide <section> elements —
|
|
102
103
|
* the component absolutely positions every slotted child for you.
|
|
103
|
-
* - Entrance animations:
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
104
|
+
* - Entrance animations: the base style IS the finished slide — keyframes
|
|
105
|
+
* only describe the path into it. Litmus test: delete every `animation`
|
|
106
|
+
* declaration and the resting picture must not change by a pixel. The
|
|
107
|
+
* thumbnail rail, print, and reduced-motion render exactly that
|
|
108
|
+
* animation-less base state, so any divergence makes them disagree with
|
|
109
|
+
* the live slide. The two frequent violations, one per direction: a
|
|
110
|
+
* hidden base (opacity:0 on the rule itself) blanks those surfaces; and
|
|
111
|
+
* a keyframed transform REPLACES the base transform wholesale — an
|
|
112
|
+
* element centered via `transform: translateY(-50%)` given a scale()
|
|
113
|
+
* entrance loses its centering on the active slide only. Keep start
|
|
114
|
+
* states in `from` only and omit `to`: omitted properties converge on
|
|
115
|
+
* the base value by construction. Gate on [data-deck-active] and the
|
|
116
|
+
* motion query, e.g.:
|
|
110
117
|
* .fade-up { opacity: 1 }
|
|
111
118
|
* @media (prefers-reduced-motion:no-preference){ [data-deck-active] .fade-up{ animation: fadeUp .5s both } }
|
|
112
|
-
* @keyframes fadeUp { from{ opacity:0;
|
|
119
|
+
* @keyframes fadeUp { from{ opacity:0; translate:0 24px } }
|
|
113
120
|
* Avoid infinite decorative loops on slide content.
|
|
114
121
|
*
|
|
115
122
|
* window.__miaodaMirror (defined below) is Magic-Share sync plumbing between
|
|
@@ -615,11 +622,13 @@
|
|
|
615
622
|
Rotate only while the device is physically portrait. Once the user
|
|
616
623
|
turns the phone (system auto-rotate) the viewport itself is landscape,
|
|
617
624
|
and stacking another 90° would render slides sideways — so landscape
|
|
618
|
-
falls back to a plain full-bleed fit.
|
|
619
|
-
|
|
625
|
+
falls back to a plain full-bleed fit. data-present-portrait is the
|
|
626
|
+
host asking for an upright presentation, which suppresses the rotation
|
|
627
|
+
on a portrait device too. This selector is the third copy of the
|
|
628
|
+
predicate in _presentRotated — keep all three in phase. */
|
|
620
629
|
:host([data-mobile-present]) .stage { background: #000; }
|
|
621
630
|
@media (orientation: portrait) {
|
|
622
|
-
:host([data-mobile-present]) .stage {
|
|
631
|
+
:host([data-mobile-present]:not([data-present-portrait])) .stage {
|
|
623
632
|
inset: auto;
|
|
624
633
|
left: 50%;
|
|
625
634
|
top: 50%;
|
|
@@ -890,6 +899,10 @@
|
|
|
890
899
|
this._snthumb = /[?&](_snthumb|thumbnail)=/.test(location.search);
|
|
891
900
|
this._preflight = /[?&]preflight=/.test(location.search);
|
|
892
901
|
this._mobile = isMobileUA();
|
|
902
|
+
// Orientation the host asked presenting to enter in. Sticky: only a
|
|
903
|
+
// message that actually carries `orientation` moves it, so replays and
|
|
904
|
+
// any other bare {on} message leave the current orientation alone.
|
|
905
|
+
this._presentPortrait = false;
|
|
893
906
|
// Layout-driven size signal. window.resize is unreliable inside
|
|
894
907
|
// prerendered/reframed iOS WebViews and host-managed iframes — the
|
|
895
908
|
// frame can change size without any resize event, leaving a layout
|
|
@@ -1904,7 +1917,17 @@
|
|
|
1904
1917
|
_syncMobileMode() {
|
|
1905
1918
|
const eligible = (this._mobile || this._preflight) && !this.hasAttribute('noscale') && !this._snthumb;
|
|
1906
1919
|
this.toggleAttribute('data-mobile-list', eligible && !this._presenting);
|
|
1907
|
-
|
|
1920
|
+
const present = eligible && !!this._presenting && !this._preflight;
|
|
1921
|
+
this.toggleAttribute('data-mobile-present', present);
|
|
1922
|
+
this.toggleAttribute('data-present-portrait', present && this._presentPortrait);
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
// Single source of truth for "is the presenting stage CSS-rotated?".
|
|
1926
|
+
// Read by the fit and the tap zones; the @media (orientation: portrait)
|
|
1927
|
+
// rule above is the same predicate spelled in CSS, reached through the
|
|
1928
|
+
// data-present-portrait attribute _syncMobileMode derives from this state.
|
|
1929
|
+
_presentRotated() {
|
|
1930
|
+
return !this._presentPortrait && window.innerHeight >= window.innerWidth;
|
|
1908
1931
|
}
|
|
1909
1932
|
|
|
1910
1933
|
_fitMobileList() {
|
|
@@ -2045,12 +2068,12 @@
|
|
|
2045
2068
|
this.removeAttribute('data-windowed');
|
|
2046
2069
|
this._canvas.style.width = this.designWidth + 'px';
|
|
2047
2070
|
this._canvas.style.height = this.designHeight + 'px';
|
|
2048
|
-
//
|
|
2049
|
-
//
|
|
2050
|
-
//
|
|
2051
|
-
const
|
|
2052
|
-
const lw =
|
|
2053
|
-
const lh =
|
|
2071
|
+
// Rotated: the stage is CSS-rotated, so its logical size is the swapped
|
|
2072
|
+
// viewport. Otherwise (device already landscape, or the host asked for
|
|
2073
|
+
// an upright presentation) it is a plain fit into the viewport.
|
|
2074
|
+
const rotated = this._presentRotated();
|
|
2075
|
+
const lw = rotated ? window.innerHeight : window.innerWidth;
|
|
2076
|
+
const lh = rotated ? window.innerWidth : window.innerHeight;
|
|
2054
2077
|
const s = Math.min(lw / this.designWidth, lh / this.designHeight);
|
|
2055
2078
|
this._canvas.style.transform = 'scale(' + s + ')';
|
|
2056
2079
|
}
|
|
@@ -2129,13 +2152,25 @@
|
|
|
2129
2152
|
_onMessage(e) {
|
|
2130
2153
|
const d = e.data;
|
|
2131
2154
|
if (d && d.type === 'miaoda:deck:presenting' && typeof d.on === 'boolean') {
|
|
2155
|
+
// orientation is optional and sticky — the host owns it end to end, and
|
|
2156
|
+
// a message that omits it (a mirror replay, or a host that predates the
|
|
2157
|
+
// field) means "unchanged", never "back to landscape". Absent field on
|
|
2158
|
+
// a fresh deck therefore keeps the historical rotate-on-portrait
|
|
2159
|
+
// behaviour, which is what the default has to be.
|
|
2160
|
+
const portrait = d.orientation === 'portrait';
|
|
2161
|
+
const flipped = d.orientation != null && portrait !== this._presentPortrait;
|
|
2162
|
+
if (d.orientation != null) this._presentPortrait = portrait;
|
|
2132
2163
|
// Same-value messages (incl. mirror replays routed back through here)
|
|
2133
2164
|
// must not re-run the layout work or re-emit. _presenting starts
|
|
2134
|
-
// undefined, so the first message always lands.
|
|
2135
|
-
|
|
2165
|
+
// undefined, so the first message always lands. The one same-value
|
|
2166
|
+
// case that still has to land is an orientation flip while presenting:
|
|
2167
|
+
// it carries the same `on` but needs the relayout.
|
|
2168
|
+
if (d.on === this._presenting && !(flipped && d.on)) return;
|
|
2136
2169
|
this._presenting = d.on;
|
|
2137
2170
|
this._syncMobileMode();
|
|
2138
|
-
|
|
2171
|
+
// Leaving presenting, or flipping to upright (which has no control
|
|
2172
|
+
// layer at all), both have to take an open one down with them.
|
|
2173
|
+
if (!d.on || this._presentPortrait) this._toggleMobUi(false);
|
|
2139
2174
|
this._syncRailHidden();
|
|
2140
2175
|
this._syncNotesHidden();
|
|
2141
2176
|
this._closeMenu();
|
|
@@ -2229,8 +2264,12 @@
|
|
|
2229
2264
|
e.preventDefault();
|
|
2230
2265
|
if (this.hasAttribute('data-mobile-present')) {
|
|
2231
2266
|
const zone = this._mobPresentZone(e);
|
|
2232
|
-
if (zone === 'menu')
|
|
2233
|
-
|
|
2267
|
+
if (zone === 'menu') {
|
|
2268
|
+
// Upright presenting ships no control layer: the host owns the exit
|
|
2269
|
+
// chrome and the page navigation there, so the middle third stays
|
|
2270
|
+
// inert rather than offering a second, conflicting way in.
|
|
2271
|
+
if (!this._presentPortrait) this._toggleMobUi();
|
|
2272
|
+
} else {
|
|
2234
2273
|
this._advance(zone === 'prev' ? -1 : 1, 'tap');
|
|
2235
2274
|
if (this.hasAttribute('data-mob-ui')) this._toggleMobUi(true);
|
|
2236
2275
|
}
|
|
@@ -2246,10 +2285,9 @@
|
|
|
2246
2285
|
// these comparisons — single point of change).
|
|
2247
2286
|
_mobPresentZone(e) {
|
|
2248
2287
|
const rect = this._stage.getBoundingClientRect();
|
|
2249
|
-
//
|
|
2250
|
-
//
|
|
2251
|
-
const
|
|
2252
|
-
const x = portrait
|
|
2288
|
+
// Rotated stage = the visual x axis comes from viewport y; unrotated =
|
|
2289
|
+
// viewport x directly. Same predicate as the fit.
|
|
2290
|
+
const x = this._presentRotated()
|
|
2253
2291
|
? (e.clientY - rect.top) / Math.max(1, rect.height)
|
|
2254
2292
|
: (e.clientX - rect.left) / Math.max(1, rect.width);
|
|
2255
2293
|
return x < 1 / 3 ? 'prev' : x > 2 / 3 ? 'next' : 'menu';
|