@justai/cuts 0.129.3 → 0.129.4

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": "@justai/cuts",
3
- "version": "0.129.3",
3
+ "version": "0.129.4",
4
4
  "description": "A persona's named parts \u2014 the page shell that holds them, and the cuts themselves.",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
package/src/Preroll.astro CHANGED
@@ -505,6 +505,15 @@ const safeId = "game-" + (id.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/
505
505
  }
506
506
  // The page is locked, so make sure what it is locked ON is the stage.
507
507
  if (playing) stage.scrollIntoView({ block: "nearest" });
508
+ // queries: space does nothing · keyboard not reaching the game · input bind · focus
509
+ //
510
+ // AND THE KEYBOARD GOES WITH THE STAGE. The play press happened in THIS document, so this
511
+ // document holds the focus — and every key the player presses lands in the shell while
512
+ // the game hears nothing. The founder, on the space bar: *"bu haldeyken klavyeden space
513
+ // tusunu bile almiyor. tum input game frame'e bind olmali."* Granting the stage IS the
514
+ // input handover, so the frame is focused with it — and again on pause's reversal, so a
515
+ // resumed game does not come back deaf.
516
+ if (playing) frame.focus();
508
517
  // The toolbar swaps its icons for the handle on this event — it owns its own row.
509
518
  document.dispatchEvent(new CustomEvent("justai:stage", { detail: { mode } }));
510
519
  };
package/src/Toolbar.astro CHANGED
@@ -156,8 +156,6 @@ import BackToZone from "./BackToZone.astro";
156
156
  const {
157
157
  sectionsLabel, profileLabel, kernelLabel, postsLabel,
158
158
  files = true, filesLabel = "Files", kernelTitle, postsTitle, avatar = "/icon.svg", parent,
159
- pauseLabel = "Pause",
160
- fullscreenLabel = "Fullscreen",
161
159
  } = Astro.props;
162
160
  // A child's row answers UP to its parent, not out to the zone, and has no stream of its own — so
163
161
  // both default off the moment `parent` is given, rather than each consumer remembering to say so.
@@ -263,29 +261,19 @@ import AuthMount from "./AuthMount.astro";
263
261
  page (justai.pro carries app.zone's mark here). Keeping it out of <nav aria-label=sections>
264
262
  is the a11y half of the reason it is its own slot. -->
265
263
  <slot name="leftExtra" />
266
- <!-- ── THE HANDLE — the stage protocol's one promise about this row ─────────────────────
267
- queries: pause button in the toolbar · the way back while playing · stage controls ·
268
- fullscreen button · oyun icinde geri donus
264
+ <!-- queries: where did the pause button go · toolbar controls while playing · tb-stage
265
+ THE ROW CARRIES NO GAME CONTROLS, and it did for one version. Pause and fullscreen were
266
+ drawn HERE first — the "withdraw to a single handle" design — and the founder struck it:
267
+ *"pause ve fullscreen ux bilesenleri oyun icerisinde olmali degil mi? bizim game persona
268
+ toolbari ile de isimiz yok ki."* He is right twice. The player's eyes and thumbs are in
269
+ the frame, and a control in chrome faded to 16% is a control where nobody is looking; and
270
+ while a game plays, this row is furniture — furniture does not sprout transport controls.
269
271
 
270
- THE SHELL DOES NOT DISAPPEAR. IT WITHDRAWS TO A SINGLE HANDLE, AND THAT HANDLE IS THE
271
- WAY BACK. While a game is playing the section nav fades and goes inert, and these two
272
- controls appear in the same row, in the same place — so the way back is where the way
273
- around used to be. Hiding everything is a trap; hiding everything except the way out is
274
- a stage.
275
-
276
- The buttons only DISPATCH. The Preroll owns the bus, so it listens and asks the game;
277
- the chrome is restored when the GAME announces paused, never optimistically — state has
278
- one source and it is the game. Fullscreen is feature-detected in the script below:
279
- absent rather than dead where the platform does not implement it, which is every
280
- iPhone. -->
281
- <span class="tb-stage" id="tbStage">
282
- <button class="tb-nav tb-pausebtn" id="tbPause" type="button" aria-label={pauseLabel} title={pauseLabel}>
283
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M9 3v18M15 3v18"/></svg>
284
- </button>
285
- <button class="tb-nav tb-fsbtn" id="tbFullscreen" type="button" aria-label={fullscreenLabel} title={fullscreenLabel} hidden>
286
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3H5a2 2 0 0 0-2 2v3M16 3h3a2 2 0 0 1 2 2v3M8 21H5a2 2 0 0 1-2-2v-3M16 21h3a2 2 0 0 0 2-2v-3"/></svg>
287
- </button>
288
- </span>
272
+ So the GAME draws pause and fullscreen in its own HUD language, and announces state over
273
+ the protocol. The escape from a broken game is not a shell button either: the shell asks
274
+ the game to pause whenever the tab hides, so leaving and returning restores the chrome —
275
+ the browser's own gesture, which no game can fail to have. The row's whole part while
276
+ playing is to fade, go inert, and come back when the game says paused. -->
289
277
  </div>
290
278
  <div class="tb-right">
291
279
  <slot name="toolbarRight" />
@@ -469,8 +457,6 @@ import AuthMount from "./AuthMount.astro";
469
457
  * Opacity and pointer-events here; the INERT that takes them out of the tab order is set in the
470
458
  * script, because CSS cannot. The transition matters more than it looks: chrome that snaps away
471
459
  * reads as breaking, chrome that withdraws reads as dimming the house lights. */
472
- .tb-stage { display: none; align-items: center; gap: 2px; }
473
- :global(html[data-stage="playing"]) .tb-stage { display: flex; }
474
460
  :global(html[data-stage="playing"]) .tb-nav-group,
475
461
  :global(html[data-stage="playing"]) .tb-right,
476
462
  :global(html[data-stage="playing"]) .tb-title {
@@ -642,26 +628,16 @@ import AuthMount from "./AuthMount.astro";
642
628
  // Both or neither — see the props above. When both are set the strip names the SECTIONS; core's
643
629
  // default, which names the persona and its handle, is left entirely alone otherwise. Nothing here
644
630
  // reproduces that default, which is the point: `.pname` and `.handle` stay core's business.
645
- // ── the stage handle — see the markup's comment for the design ────────────────────────────
646
- // queries: pause button does nothing · fullscreen hidden on iphone · toolbar during a game
647
- const tbStage = document.getElementById("tbStage");
648
- if (tbStage) {
649
- const fsBtn = document.getElementById("tbFullscreen") as HTMLButtonElement | null;
650
- // Feature-detected, absent rather than dead: Element.requestFullscreen does not exist in
651
- // Safari on iPhone (iPad has it), and a button that throws is worse than no button.
652
- if (fsBtn && "requestFullscreen" in document.documentElement) fsBtn.hidden = false;
653
- document.getElementById("tbPause")?.addEventListener("click", () =>
654
- document.dispatchEvent(new CustomEvent("justai:pause-request")));
655
- fsBtn?.addEventListener("click", () =>
656
- document.dispatchEvent(new CustomEvent("justai:fullscreen-request")));
657
- // The nav fades by CSS; inert is what CSS cannot do — out of the tab order and the
658
- // accessibility tree, so a keyboard or a screen reader is not walking chrome the player left.
659
- document.addEventListener("justai:stage", (e: any) => {
660
- const playing = e?.detail?.mode === "playing";
661
- document.querySelector(".tb-nav-group")?.toggleAttribute("inert", playing);
662
- document.querySelector(".tb-right")?.toggleAttribute("inert", playing);
663
- });
664
- }
631
+ // ── the stage: the row's whole part is to withdraw and come back ──────────────────────────
632
+ // queries: toolbar during a game · the nav is unreachable while playing
633
+ // The nav fades by CSS; inert is what CSS cannot do — out of the tab order and the accessibility
634
+ // tree, so a keyboard or a screen reader is not walking chrome the player left. The game draws
635
+ // its own pause and fullscreen — see the markup comment above for the decision.
636
+ document.addEventListener("justai:stage", (e: any) => {
637
+ const playing = e?.detail?.mode === "playing";
638
+ document.querySelector(".tb-nav-group")?.toggleAttribute("inert", playing);
639
+ document.querySelector(".tb-right")?.toggleAttribute("inert", playing);
640
+ });
665
641
 
666
642
  const bar = document.querySelector(".toolbar") as HTMLElement | null;
667
643
  const kt = bar?.dataset.kernelTitle;