@lark-apaas/coding-registry-buildless 0.1.22 → 0.1.23

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/coding-registry-buildless",
3
- "version": "0.1.22",
3
+ "version": "0.1.23",
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": [
@@ -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 rotated fullscreen
39
- * presenting mode. This needs NO authoring changes: never hand-roll
40
- * mobile/responsive slide layouts. Desktop behaviour is unchanged.
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
@@ -615,11 +616,13 @@
615
616
  Rotate only while the device is physically portrait. Once the user
616
617
  turns the phone (system auto-rotate) the viewport itself is landscape,
617
618
  and stacking another 90° would render slides sideways — so landscape
618
- falls back to a plain full-bleed fit. _fitMobilePresent and
619
- _mobPresentZone branch on the same orientation test. */
619
+ falls back to a plain full-bleed fit. data-present-portrait is the
620
+ host asking for an upright presentation, which suppresses the rotation
621
+ on a portrait device too. This selector is the third copy of the
622
+ predicate in _presentRotated — keep all three in phase. */
620
623
  :host([data-mobile-present]) .stage { background: #000; }
621
624
  @media (orientation: portrait) {
622
- :host([data-mobile-present]) .stage {
625
+ :host([data-mobile-present]:not([data-present-portrait])) .stage {
623
626
  inset: auto;
624
627
  left: 50%;
625
628
  top: 50%;
@@ -890,6 +893,10 @@
890
893
  this._snthumb = /[?&](_snthumb|thumbnail)=/.test(location.search);
891
894
  this._preflight = /[?&]preflight=/.test(location.search);
892
895
  this._mobile = isMobileUA();
896
+ // Orientation the host asked presenting to enter in. Sticky: only a
897
+ // message that actually carries `orientation` moves it, so replays and
898
+ // any other bare {on} message leave the current orientation alone.
899
+ this._presentPortrait = false;
893
900
  // Layout-driven size signal. window.resize is unreliable inside
894
901
  // prerendered/reframed iOS WebViews and host-managed iframes — the
895
902
  // frame can change size without any resize event, leaving a layout
@@ -1904,7 +1911,17 @@
1904
1911
  _syncMobileMode() {
1905
1912
  const eligible = (this._mobile || this._preflight) && !this.hasAttribute('noscale') && !this._snthumb;
1906
1913
  this.toggleAttribute('data-mobile-list', eligible && !this._presenting);
1907
- this.toggleAttribute('data-mobile-present', eligible && !!this._presenting && !this._preflight);
1914
+ const present = eligible && !!this._presenting && !this._preflight;
1915
+ this.toggleAttribute('data-mobile-present', present);
1916
+ this.toggleAttribute('data-present-portrait', present && this._presentPortrait);
1917
+ }
1918
+
1919
+ // Single source of truth for "is the presenting stage CSS-rotated?".
1920
+ // Read by the fit and the tap zones; the @media (orientation: portrait)
1921
+ // rule above is the same predicate spelled in CSS, reached through the
1922
+ // data-present-portrait attribute _syncMobileMode derives from this state.
1923
+ _presentRotated() {
1924
+ return !this._presentPortrait && window.innerHeight >= window.innerWidth;
1908
1925
  }
1909
1926
 
1910
1927
  _fitMobileList() {
@@ -2045,12 +2062,12 @@
2045
2062
  this.removeAttribute('data-windowed');
2046
2063
  this._canvas.style.width = this.designWidth + 'px';
2047
2064
  this._canvas.style.height = this.designHeight + 'px';
2048
- // Portrait: the stage is CSS-rotated, so its logical size is the
2049
- // swapped viewport. Landscape (user physically rotated): no rotation,
2050
- // plain fit. The CSS branches on the same orientation query.
2051
- const portrait = window.innerHeight >= window.innerWidth;
2052
- const lw = portrait ? window.innerHeight : window.innerWidth;
2053
- const lh = portrait ? window.innerWidth : window.innerHeight;
2065
+ // Rotated: the stage is CSS-rotated, so its logical size is the swapped
2066
+ // viewport. Otherwise (device already landscape, or the host asked for
2067
+ // an upright presentation) it is a plain fit into the viewport.
2068
+ const rotated = this._presentRotated();
2069
+ const lw = rotated ? window.innerHeight : window.innerWidth;
2070
+ const lh = rotated ? window.innerWidth : window.innerHeight;
2054
2071
  const s = Math.min(lw / this.designWidth, lh / this.designHeight);
2055
2072
  this._canvas.style.transform = 'scale(' + s + ')';
2056
2073
  }
@@ -2129,13 +2146,25 @@
2129
2146
  _onMessage(e) {
2130
2147
  const d = e.data;
2131
2148
  if (d && d.type === 'miaoda:deck:presenting' && typeof d.on === 'boolean') {
2149
+ // orientation is optional and sticky — the host owns it end to end, and
2150
+ // a message that omits it (a mirror replay, or a host that predates the
2151
+ // field) means "unchanged", never "back to landscape". Absent field on
2152
+ // a fresh deck therefore keeps the historical rotate-on-portrait
2153
+ // behaviour, which is what the default has to be.
2154
+ const portrait = d.orientation === 'portrait';
2155
+ const flipped = d.orientation != null && portrait !== this._presentPortrait;
2156
+ if (d.orientation != null) this._presentPortrait = portrait;
2132
2157
  // Same-value messages (incl. mirror replays routed back through here)
2133
2158
  // must not re-run the layout work or re-emit. _presenting starts
2134
- // undefined, so the first message always lands.
2135
- if (d.on === this._presenting) return;
2159
+ // undefined, so the first message always lands. The one same-value
2160
+ // case that still has to land is an orientation flip while presenting:
2161
+ // it carries the same `on` but needs the relayout.
2162
+ if (d.on === this._presenting && !(flipped && d.on)) return;
2136
2163
  this._presenting = d.on;
2137
2164
  this._syncMobileMode();
2138
- if (!d.on) this._toggleMobUi(false);
2165
+ // Leaving presenting, or flipping to upright (which has no control
2166
+ // layer at all), both have to take an open one down with them.
2167
+ if (!d.on || this._presentPortrait) this._toggleMobUi(false);
2139
2168
  this._syncRailHidden();
2140
2169
  this._syncNotesHidden();
2141
2170
  this._closeMenu();
@@ -2229,8 +2258,12 @@
2229
2258
  e.preventDefault();
2230
2259
  if (this.hasAttribute('data-mobile-present')) {
2231
2260
  const zone = this._mobPresentZone(e);
2232
- if (zone === 'menu') this._toggleMobUi();
2233
- else {
2261
+ if (zone === 'menu') {
2262
+ // Upright presenting ships no control layer: the host owns the exit
2263
+ // chrome and the page navigation there, so the middle third stays
2264
+ // inert rather than offering a second, conflicting way in.
2265
+ if (!this._presentPortrait) this._toggleMobUi();
2266
+ } else {
2234
2267
  this._advance(zone === 'prev' ? -1 : 1, 'tap');
2235
2268
  if (this.hasAttribute('data-mob-ui')) this._toggleMobUi(true);
2236
2269
  }
@@ -2246,10 +2279,9 @@
2246
2279
  // these comparisons — single point of change).
2247
2280
  _mobPresentZone(e) {
2248
2281
  const rect = this._stage.getBoundingClientRect();
2249
- // Portrait = stage is rotated, visual x comes from viewport y;
2250
- // landscape = no rotation, viewport x directly. Same branch as the fit.
2251
- const portrait = window.innerHeight >= window.innerWidth;
2252
- const x = portrait
2282
+ // Rotated stage = the visual x axis comes from viewport y; unrotated =
2283
+ // viewport x directly. Same predicate as the fit.
2284
+ const x = this._presentRotated()
2253
2285
  ? (e.clientY - rect.top) / Math.max(1, rect.height)
2254
2286
  : (e.clientX - rect.left) / Math.max(1, rect.width);
2255
2287
  return x < 1 / 3 ? 'prev' : x > 2 / 3 ? 'next' : 'menu';