@cardstack/boxel-cli 0.9.0-unstable.5 → 0.9.0-unstable.6

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.
Files changed (86) hide show
  1. package/bundled-test-harness/assets/{ai-module-creation-test-BNiZ9Als.js → ai-module-creation-test-CYdqfeyE.js} +1 -1
  2. package/bundled-test-harness/assets/{app-CP2kZsut.js → app-DEPzUD4Y.js} +1 -1
  3. package/bundled-test-harness/assets/{binary-upload-dedupe-test-c4W0iix2.js → binary-upload-dedupe-test-BIf-AWak.js} +1 -1
  4. package/bundled-test-harness/assets/{can-invoke-test-DyozfCFg.js → can-invoke-test-BjgjfYqo.js} +1 -1
  5. package/bundled-test-harness/assets/{card-chooser-paging-test-BKdBwPQ3.js → card-chooser-paging-test-C2v55yZ3.js} +1 -1
  6. package/bundled-test-harness/assets/{card-chooser-test-DAPWVfJL.js → card-chooser-test-OqnnAsAY.js} +1 -1
  7. package/bundled-test-harness/assets/{card-def-field-def-relationships-test-Dz1qg9ZW.js → card-def-field-def-relationships-test-TNzXYsVI.js} +1 -1
  8. package/bundled-test-harness/assets/{card-delete-test-BmI-DLtn.js → card-delete-test-BVnE3BU6.js} +1 -1
  9. package/bundled-test-harness/assets/{choreo-feature-reel-test-S0XwN4xA.js → choreo-feature-reel-test-DrvZlnG0.js} +1 -1
  10. package/bundled-test-harness/assets/{choreo-gallery-B0nnktwP.js → choreo-gallery-D8__QZCe.js} +11 -11
  11. package/bundled-test-harness/assets/{choreo-gallery-build-order-test-C6q9CDNY.js → choreo-gallery-build-order-test-7TpxKQd2.js} +1 -1
  12. package/bundled-test-harness/assets/{choreo-gallery-compositor-test-C-GwjEUw.js → choreo-gallery-compositor-test-BgMWB-xz.js} +1 -1
  13. package/bundled-test-harness/assets/choreo-gallery-cover-test-uR-CNV8g.js +205 -0
  14. package/bundled-test-harness/assets/{choreo-gallery-crossing-stage-test-B7jRQTAh.js → choreo-gallery-crossing-stage-test-CmGH0E5q.js} +1 -1
  15. package/bundled-test-harness/assets/{choreo-gallery-demos-alive-test-BLqE-zk1.js → choreo-gallery-demos-alive-test-DZ1sPqe8.js} +8 -2
  16. package/bundled-test-harness/assets/{choreo-gallery-drift-test-DOXLQNB9.js → choreo-gallery-drift-test-q7KosXIw.js} +1 -1
  17. package/bundled-test-harness/assets/{choreo-gallery-escort-test-lfBfmp-4.js → choreo-gallery-escort-test-CH_qyw6w.js} +1 -1
  18. package/bundled-test-harness/assets/{choreo-gallery-films-test-M761cc8Q.js → choreo-gallery-films-test-CYmek5qU.js} +1 -1
  19. package/bundled-test-harness/assets/{choreo-gallery-filter-test-BrUWMDaJ.js → choreo-gallery-filter-test-Curg5Fg7.js} +1 -1
  20. package/bundled-test-harness/assets/{choreo-gallery-fold-test-CTtdGSAI.js → choreo-gallery-fold-test-BDTkaH6H.js} +1 -1
  21. package/bundled-test-harness/assets/{choreo-gallery-guides-test-PHmvqxfk.js → choreo-gallery-guides-test-B1vY7Fkx.js} +2 -2
  22. package/bundled-test-harness/assets/{choreo-gallery-hang-test-DP5lQG0y.js → choreo-gallery-hang-test-BJJghTnK.js} +1 -1
  23. package/bundled-test-harness/assets/{choreo-gallery-highlight-test-CLhvRo6X.js → choreo-gallery-highlight-test-DGT0jmDf.js} +2 -2
  24. package/bundled-test-harness/assets/{choreo-gallery-inline-edit-test-jOddqOxH.js → choreo-gallery-inline-edit-test-DwF8ZeCB.js} +1 -1
  25. package/bundled-test-harness/assets/{choreo-gallery-interruption-test-hdQSH8Mi.js → choreo-gallery-interruption-test-DvfkLdWd.js} +1 -1
  26. package/bundled-test-harness/assets/{choreo-gallery-lone-stack-test-AHGiG8yJ.js → choreo-gallery-lone-stack-test-CDwE2xKJ.js} +1 -1
  27. package/bundled-test-harness/assets/{choreo-gallery-navigation-test-BlGmMyFM.js → choreo-gallery-navigation-test-DG6IdX6k.js} +1 -1
  28. package/bundled-test-harness/assets/{choreo-gallery-playhead-transport-test-8aNOk09i.js → choreo-gallery-playhead-transport-test-CITO-DAn.js} +1 -1
  29. package/bundled-test-harness/assets/{choreo-gallery-poplayout-subtree-test-BCJLJdyC.js → choreo-gallery-poplayout-subtree-test-Cs4S9Ky9.js} +1 -1
  30. package/bundled-test-harness/assets/{choreo-gallery-presence-modes-test-CbhdndwS.js → choreo-gallery-presence-modes-test-p8mppXAD.js} +1 -1
  31. package/bundled-test-harness/assets/{choreo-gallery-presentation-test-DDUagg6a.js → choreo-gallery-presentation-test-CT0lZepE.js} +36 -1
  32. package/bundled-test-harness/assets/{choreo-gallery-sheet-standalone-test-BNyhCtW2.js → choreo-gallery-sheet-standalone-test-D-MLCQ6u.js} +1 -1
  33. package/bundled-test-harness/assets/{choreo-gallery-sheet-test-NEe_oYnA.js → choreo-gallery-sheet-test-unHvAt2e.js} +1 -1
  34. package/bundled-test-harness/assets/{choreo-gallery-site-test-hT5mISBG.js → choreo-gallery-site-test-BRHuPInI.js} +1 -1
  35. package/bundled-test-harness/assets/{choreo-gallery-stage-Bmz9m8sP.js → choreo-gallery-stage-DVGS6XI-.js} +1 -1
  36. package/bundled-test-harness/assets/choreo-gallery-stage-keyboard-test-BYpAwZPD.js +102 -0
  37. package/bundled-test-harness/assets/{choreo-gallery-stages-test-DZjVu0Zq.js → choreo-gallery-stages-test-DPFv-GKb.js} +2 -2
  38. package/bundled-test-harness/assets/{choreo-gallery-subdivision-test-DBjnIZ8l.js → choreo-gallery-subdivision-test-C4rwq-DA.js} +1 -1
  39. package/bundled-test-harness/assets/{choreo-gallery-table-plan-test-DTSu2DjF.js → choreo-gallery-table-plan-test-CAQdsCBB.js} +1 -1
  40. package/bundled-test-harness/assets/{choreo-gallery-theater-test-BsLF8HcI.js → choreo-gallery-theater-test-BxvAn-i8.js} +2 -2
  41. package/bundled-test-harness/assets/{choreo-gallery-tuning-test-B1JW701Z.js → choreo-gallery-tuning-test-CvAiiRMn.js} +1 -1
  42. package/bundled-test-harness/assets/{choreo-gallery-widget-room-test-DcEIPub1.js → choreo-gallery-widget-room-test-DLkgh8Ws.js} +2 -2
  43. package/bundled-test-harness/assets/{choreo-gallery-wires-test-6VOc5SF8.js → choreo-gallery-wires-test-DMdHX2zj.js} +1 -1
  44. package/bundled-test-harness/assets/{codeblocks-test-DGtwtURg.js → codeblocks-test-DDMirwuJ.js} +1 -1
  45. package/bundled-test-harness/assets/{compaction-test-CTNozvI6.js → compaction-test-BKQ_668T.js} +1 -1
  46. package/bundled-test-harness/assets/{container-Az9Nq0LL.js → container-BrZklF85.js} +5 -2
  47. package/bundled-test-harness/assets/{create-listing-modal-test-cdE1T_YD.js → create-listing-modal-test-Bsgixn9Z.js} +1 -1
  48. package/bundled-test-harness/assets/{debug-message-test-BfS52C_5.js → debug-message-test-8e9w8xNX.js} +1 -1
  49. package/bundled-test-harness/assets/{fallback-banner-live-delete-test-C6Rl_3oe.js → fallback-banner-live-delete-test-CNsd-0FB.js} +1 -1
  50. package/bundled-test-harness/assets/{fallback-banner-test-CsSGrseR.js → fallback-banner-test-DlT-8Lpv.js} +1 -1
  51. package/bundled-test-harness/assets/{fallback-models-test-D7FBFpyT.js → fallback-models-test-CwG7Ydui.js} +1 -1
  52. package/bundled-test-harness/assets/{file-attachment-test-DtPZTxy4.js → file-attachment-test-Cvs-ulUS.js} +1 -1
  53. package/bundled-test-harness/assets/{general-test-CMH4p9LD.js → general-test-BDjfjhSB.js} +1 -1
  54. package/bundled-test-harness/assets/{main-DQBeCoaR.js → main-BeQF5cZd.js} +1 -1
  55. package/bundled-test-harness/assets/{model-cost-tier-test-DR2G3zVF.js → model-cost-tier-test-FFf8YNd5.js} +1 -1
  56. package/bundled-test-harness/assets/{operator-mode-card-chooser-test-Dtd5macc.js → operator-mode-card-chooser-test-DKo-UoRQ.js} +1 -1
  57. package/bundled-test-harness/assets/{operator-mode-links-test-BW7fJlL7.js → operator-mode-links-test-Dl5g5COc.js} +1 -1
  58. package/bundled-test-harness/assets/{operator-mode-test-OwSg0jux.js → operator-mode-test-Bo8diNLE.js} +1 -1
  59. package/bundled-test-harness/assets/{operator-mode-ui-test-gV3LQASK.js → operator-mode-ui-test-CSc-CYTU.js} +1 -1
  60. package/bundled-test-harness/assets/{overlay-menu-items-test-DhsN6QTO.js → overlay-menu-items-test-Bs1zoaym.js} +1 -1
  61. package/bundled-test-harness/assets/{past-sessions-test-DD6A7KuB.js → past-sessions-test-BGg7ZyON.js} +1 -1
  62. package/bundled-test-harness/assets/{permission-checking-realm-test-bQz4K37U.js → permission-checking-realm-test-Be6jGmyM.js} +1 -1
  63. package/bundled-test-harness/assets/{realm-config-policy-standing-test-Cs9XpWCX.js → realm-config-policy-standing-test-nM6CGX-Q.js} +1 -1
  64. package/bundled-test-harness/assets/{realm-config-routing-rule-edit-test-_D_xuw3p.js → realm-config-routing-rule-edit-test-TIuE2nug.js} +1 -1
  65. package/bundled-test-harness/assets/{realm-config-settings-test-DNqVtlJT.js → realm-config-settings-test-CWqwPMkw.js} +1 -1
  66. package/bundled-test-harness/assets/{reasoning-test-B74P8G_y.js → reasoning-test-CfRBo1ut.js} +1 -1
  67. package/bundled-test-harness/assets/{scrolling-test-EMUFGWKu.js → scrolling-test-DTJ7HVdE.js} +1 -1
  68. package/bundled-test-harness/assets/{sending-test-BIADsBdp.js → sending-test-D6iQh346.js} +1 -1
  69. package/bundled-test-harness/assets/{skills-test-AcW3L6RD.js → skills-test-Ca1EpjMI.js} +1 -1
  70. package/bundled-test-harness/assets/{store-test-CgPJ9v5Z.js → store-test-BS1Ue4Rt.js} +1 -1
  71. package/bundled-test-harness/assets/{tests-QZJXdl8x.js → tests-CPowoOp0.js} +471 -469
  72. package/bundled-test-harness/assets/{text-input-validator-test-DybvZTP3.js → text-input-validator-test-XpZxMbh0.js} +1 -1
  73. package/bundled-test-harness/assets/{to-device-streaming-test-BbgQFsQk.js → to-device-streaming-test-CKu1Ud8R.js} +1 -1
  74. package/bundled-test-harness/assets/{token-usage-test-BkQp1TTc.js → token-usage-test-Cszf7EU8.js} +1 -1
  75. package/bundled-test-harness/assets/{tools-test-DEfT44PZ.js → tools-test-DdlkGAFH.js} +1 -1
  76. package/bundled-test-harness/index.html +4 -4
  77. package/bundled-test-harness/tests/index.html +4 -4
  78. package/bundled-types/host-app/components/host-mode/content.gts +9 -0
  79. package/dist/api.js +166 -165
  80. package/dist/index.js +271 -270
  81. package/package.json +1 -1
  82. package/src/commands/realm-server/data-keys.ts +7 -14
  83. package/src/commands/realm-server/index.ts +2 -0
  84. package/src/commands/realm-server/keys.ts +496 -0
  85. package/src/lib/prompt.ts +45 -12
  86. package/src/lib/seed-auth.ts +63 -3
@@ -14,7 +14,7 @@ import "./src-DKlevVIu.js";
14
14
  import { t as MotionModifier } from "./motion-CU0yC2Ky.js";
15
15
  import { t as Presence } from "./presence-BYtEBpVa.js";
16
16
  import { t as require_qunit } from "./qunit-C-Foo4Nd.js";
17
- import { a as setupChoreoGalleryTest, r as frames, s as sleep } from "./choreo-gallery-stage-Bmz9m8sP.js";
17
+ import { a as setupChoreoGalleryTest, r as frames, s as sleep } from "./choreo-gallery-stage-DVGS6XI-.js";
18
18
  //#region tests/integration/choreo-gallery-build-order-test.gts
19
19
  /**
20
20
  * The Build Order demo: as a popLayout leaver, beside a noisy neighbour, and
@@ -1,6 +1,6 @@
1
1
  import { s as __toESM } from "./chunk-Rp0pCe6z.js";
2
2
  import { t as require_qunit } from "./qunit-C-Foo4Nd.js";
3
- import { a as setupChoreoGalleryTest } from "./choreo-gallery-stage-Bmz9m8sP.js";
3
+ import { a as setupChoreoGalleryTest } from "./choreo-gallery-stage-DVGS6XI-.js";
4
4
  //#region tests/integration/choreo-gallery-compositor-test.ts
5
5
  var import_qunit = /* @__PURE__ */ __toESM(require_qunit());
6
6
  /** A run that records the transport ops the host performs on it. */
@@ -0,0 +1,205 @@
1
+ import { s as __toESM } from "./chunk-Rp0pCe6z.js";
2
+ import { Lr as testRealmURL, Pr as testHostModeRealmURL } from "./runtime-common-0-Tvgtf6.js";
3
+ import { t as getOwner } from "./owner-BT6cj890.js";
4
+ import { t as HostModeService } from "./host-mode-service-CtK92ze8.js";
5
+ import { M as waitUntil, a as find, d as click, i as findAll, k as visit, l as triggerEvent, o as waitFor } from "./dist-BGqriEf8.js";
6
+ import { t as require_qunit } from "./qunit-C-Foo4Nd.js";
7
+ import { F as setupLocalIndexing, I as setupOnSave, ct as setupApplicationTest, j as setupAcceptanceTestRealm, pt as setupAuthEndpoints, st as visitOperatorMode, t as setupMockMatrix, z as setupUserSubscription } from "./mock-matrix-CJaQa5Mm.js";
8
+ import { r as choreoGalleryRealmOf } from "./choreo-gallery-D8__QZCe.js";
9
+ //#region tests/acceptance/choreo-gallery-cover-test.gts
10
+ /**
11
+ * A demo card opened from the Choreo gallery covers the gallery without
12
+ * unmounting it: the stack item below in interact mode, the primary card
13
+ * under the stack on a published site. The grid's stages rest while they
14
+ * are covered — no loop runs, no endless animation plays — and carry on
15
+ * from where they were when the demo closes.
16
+ */ var import_qunit = /* @__PURE__ */ __toESM(require_qunit());
17
+ /**
18
+ * Crossing first, so its tile is in view: its tape scrolls itself in a frame
19
+ * loop for as long as the stage is on. Circle loop's score and Keyframes'
20
+ * morph repeat forever, one as Web Animations a Choreo pass starts by script,
21
+ * the other written by Motion frame by frame. Wires' tethers stand for as long
22
+ * as its board does, so its run ticks and its rest wires are redrawn every
23
+ * frame until resting pauses both.
24
+ */
25
+ var DEMOS = [
26
+ "crossing",
27
+ "circle-loop",
28
+ "keyframes",
29
+ "wires",
30
+ "enter"
31
+ ];
32
+ /** the module that runs the tape's loop */
33
+ var TAPE = "/lib/xstress-live";
34
+ var stageOf = (slug) => `[data-gallery-tile="${slug}"] .tile-stage`;
35
+ var resting = (stage) => stage.classList.contains("is-resting");
36
+ /** animations playing in any tile's stage */
37
+ var runningInStages = () => findAll(".tile-stage").flatMap((stage) => stage.getAnimations({ subtree: true })).filter((animation) => animation.playState === "running").length;
38
+ /**
39
+ * Waits for every tile's stage to stop playing. A resting stage pauses what
40
+ * it finds at once, and looks again within a second for effects a score
41
+ * starts by script, so a tile whose score passes as the page opens over it
42
+ * rests a moment later than the rest.
43
+ */
44
+ var stagesSettled = () => waitUntil(() => runningInStages() === 0, { timeout: 2500 }).catch(() => void 0);
45
+ /**
46
+ * A click on a tile's title as a pointer makes it. The `click` helper also
47
+ * focuses the link first, and focusing a link scrolls it into view, which in
48
+ * the test's small container scrolls the tile being watched out of it.
49
+ */
50
+ var openTile = (scope, slug) => triggerEvent(`${scope}[data-gallery-tile="${slug}"] .tile-title`, "click");
51
+ var frames = (count) => new Promise((resolve) => {
52
+ let left = count;
53
+ let step = () => --left <= 0 ? resolve() : requestAnimationFrame(step);
54
+ requestAnimationFrame(step);
55
+ });
56
+ /**
57
+ * How many frames a module's code asks for over a run of painted frames. A
58
+ * running loop asks for every one; a stopped loop asks for none. (The tape's
59
+ * own position is no measure: it moves under a pixel a frame, and at a device
60
+ * pixel ratio of 1 the browser rounds that back to where it was.)
61
+ */
62
+ async function framesAskedBy(module, count = 10) {
63
+ let asked = 0;
64
+ let original = window.requestAnimationFrame;
65
+ window.requestAnimationFrame = (callback) => {
66
+ if ((/* @__PURE__ */ new Error()).stack?.includes(module)) asked++;
67
+ return original.call(window, callback);
68
+ };
69
+ try {
70
+ await frames(count);
71
+ } finally {
72
+ window.requestAnimationFrame = original;
73
+ }
74
+ return asked;
75
+ }
76
+ /**
77
+ * How many changes the tiles' DOM takes over a run of painted frames. A loop
78
+ * Motion or Choreo runs by script writes styles and paths every frame; a grid
79
+ * at rest writes nothing.
80
+ */
81
+ async function tileWrites(count = 10) {
82
+ let writes = 0;
83
+ let observer = new MutationObserver((records) => {
84
+ writes += records.length;
85
+ });
86
+ for (let tile of findAll("[data-gallery-tile]")) observer.observe(tile, {
87
+ attributes: true,
88
+ characterData: true,
89
+ childList: true,
90
+ subtree: true
91
+ });
92
+ try {
93
+ await frames(count);
94
+ } finally {
95
+ observer.disconnect();
96
+ }
97
+ return writes;
98
+ }
99
+ (0, import_qunit.module)("Acceptance | Choreo gallery | covered by a demo", function() {
100
+ (0, import_qunit.module)("in interact mode", function(hooks) {
101
+ setupApplicationTest(hooks);
102
+ setupLocalIndexing(hooks);
103
+ setupOnSave(hooks);
104
+ let mockMatrixUtils = setupMockMatrix(hooks, {
105
+ loggedInAs: "@testuser:localhost",
106
+ activeRealms: [testRealmURL]
107
+ });
108
+ hooks.beforeEach(async function() {
109
+ mockMatrixUtils.createAndJoinRoom({
110
+ sender: "@testuser:localhost",
111
+ name: "room-test"
112
+ });
113
+ setupUserSubscription();
114
+ setupAuthEndpoints();
115
+ await setupAcceptanceTestRealm({
116
+ mockMatrixUtils,
117
+ contents: choreoGalleryRealmOf(DEMOS)
118
+ });
119
+ });
120
+ const gallery = `${testRealmURL}index`;
121
+ const demo = (slug) => `${testRealmURL}demos/${slug}`;
122
+ const stackCard = (index) => `[data-test-operator-mode-stack="0"] [data-test-stack-card-index="${index}"]`;
123
+ (0, import_qunit.test)("the grid’s stages rest under the demo, mounted, and wake when it closes", async function(assert) {
124
+ await visitOperatorMode({ stacks: [[{
125
+ id: gallery,
126
+ format: "isolated"
127
+ }]] });
128
+ await waitFor(`${stackCard(0)} ${stageOf("crossing")}`);
129
+ let stage = find(`${stackCard(0)} ${stageOf("crossing")}`);
130
+ await waitUntil(() => !resting(stage));
131
+ assert.true(await framesAskedBy(TAPE) > 0, "the tape runs in view");
132
+ await openTile(`${stackCard(0)} `, "enter");
133
+ await waitFor(`${stackCard(1)}[data-test-stack-card="${demo("enter")}"] .demo-head h1`);
134
+ await waitUntil(() => resting(stage));
135
+ assert.strictEqual(find(`${stackCard(0)} ${stageOf("crossing")}`), stage, "the covered stage is the one that was running, still mounted");
136
+ await stagesSettled();
137
+ assert.strictEqual(runningInStages(), 0, "nothing in any tile’s stage plays");
138
+ assert.strictEqual(await framesAskedBy(TAPE), 0, "and its own loop asks for no frames");
139
+ assert.strictEqual(await tileWrites(), 0, "and nothing in the grid is written to, frame after frame");
140
+ await click(`${stackCard(1)} [data-test-close-button]`);
141
+ await waitFor(stackCard(1), { count: 0 });
142
+ await waitUntil(() => !resting(stage));
143
+ assert.strictEqual(find(`${stackCard(0)} ${stageOf("crossing")}`), stage, "the same stage wakes, rather than a new one starting over");
144
+ assert.true(await framesAskedBy(TAPE) > 0, "its tape runs again");
145
+ });
146
+ });
147
+ class StubHostModeService extends HostModeService {
148
+ get isActive() {
149
+ return true;
150
+ }
151
+ get hostModeOrigin() {
152
+ return testHostModeRealmURL.replace(/\/test\/?$/, "");
153
+ }
154
+ }
155
+ (0, import_qunit.module)("on a published site", function(hooks) {
156
+ setupApplicationTest(hooks);
157
+ setupLocalIndexing(hooks);
158
+ setupOnSave(hooks);
159
+ let mockMatrixUtils = setupMockMatrix(hooks, {
160
+ loggedInAs: "@testuser:localhost",
161
+ activeRealms: [testHostModeRealmURL]
162
+ });
163
+ hooks.beforeEach(async function() {
164
+ let owner = getOwner(this);
165
+ owner.unregister?.("service:host-mode-service");
166
+ owner.register("service:host-mode-service", StubHostModeService);
167
+ mockMatrixUtils.createAndJoinRoom({
168
+ sender: "@testuser:localhost",
169
+ name: "room-test"
170
+ });
171
+ setupUserSubscription();
172
+ setupAuthEndpoints();
173
+ await setupAcceptanceTestRealm({
174
+ realmURL: testHostModeRealmURL,
175
+ mockMatrixUtils,
176
+ permissions: { "*": ["read"] },
177
+ contents: choreoGalleryRealmOf(DEMOS)
178
+ });
179
+ mockMatrixUtils.setActiveRealms([testHostModeRealmURL]);
180
+ });
181
+ const stackItem = (slug) => `[data-test-host-mode-stack-item="${testHostModeRealmURL}demos/${slug}"]`;
182
+ (0, import_qunit.test)("the grid’s stages rest under the stack, and carry on when it closes", async function(assert) {
183
+ await visit("/test");
184
+ await waitFor(stageOf("crossing"));
185
+ let stage = find(stageOf("crossing"));
186
+ await waitUntil(() => !resting(stage));
187
+ assert.true(await framesAskedBy(TAPE) > 0, "the tape runs in view");
188
+ await openTile("", "enter");
189
+ await waitFor(`${stackItem("enter")} .demo-head h1`);
190
+ assert.dom(".current-card").hasAttribute("inert", "", "the gallery under the stack is inert");
191
+ await waitUntil(() => resting(stage));
192
+ await stagesSettled();
193
+ assert.strictEqual(runningInStages(), 0, "nothing in any tile’s stage plays");
194
+ assert.strictEqual(await framesAskedBy(TAPE), 0, "and its own loop asks for no frames");
195
+ assert.strictEqual(await tileWrites(), 0, "and nothing in the grid is written to, frame after frame");
196
+ await click("[data-test-host-stack-item-close-button]");
197
+ await waitFor(stackItem("enter"), { count: 0 });
198
+ assert.dom(".current-card").doesNotHaveAttribute("inert", "the gallery is live again");
199
+ await waitUntil(() => !resting(stage));
200
+ assert.strictEqual(find(stageOf("crossing")), stage, "the same stage carries on");
201
+ assert.true(await framesAskedBy(TAPE) > 0, "its tape runs again");
202
+ });
203
+ });
204
+ });
205
+ //#endregion
@@ -3,7 +3,7 @@ import { T as settled, a as find } from "./dist-BGqriEf8.js";
3
3
  import { t as require_qunit } from "./qunit-C-Foo4Nd.js";
4
4
  import { t as animationsSettled } from "./test-support-foMaafLc.js";
5
5
  import { i as orphanCount, s as strandedTransforms } from "./test-support-BLXHZ-sH.js";
6
- import { a as setupChoreoGalleryTest, o as setupStageViewport, r as frames, t as $ } from "./choreo-gallery-stage-Bmz9m8sP.js";
6
+ import { a as setupChoreoGalleryTest, o as setupStageViewport, r as frames, t as $ } from "./choreo-gallery-stage-DVGS6XI-.js";
7
7
  //#region tests/integration/choreo-gallery-crossing-stage-test.gts
8
8
  /**
9
9
  * Crossing: three looping slides, a cut at any phase, and the matching tile
@@ -1,6 +1,6 @@
1
1
  import { s as __toESM } from "./chunk-Rp0pCe6z.js";
2
2
  import { t as require_qunit } from "./qunit-C-Foo4Nd.js";
3
- import { a as setupChoreoGalleryTest } from "./choreo-gallery-stage-Bmz9m8sP.js";
3
+ import { a as setupChoreoGalleryTest } from "./choreo-gallery-stage-DVGS6XI-.js";
4
4
  //#region tests/integration/choreo-gallery-demos-alive-test.gts
5
5
  var import_qunit = /* @__PURE__ */ __toESM(require_qunit());
6
6
  function rest() {
@@ -12,6 +12,10 @@ function rest() {
12
12
  * too. In a gallery whose cards are whole demos that means the demos mount
13
13
  * already finished: rows that should wait for the scroll arrive in place, and
14
14
  * a looping keyframe animation is seeded at its last frame instead of running.
15
+ *
16
+ * The whileInView rows are what catch that: they animate from mount. A looping
17
+ * stage starts its loop when its stage first comes on, after mount, so the
18
+ * keyframes test asks only that the loop runs where it can be seen.
15
19
  */
16
20
  (0, import_qunit.module)("Integration | Choreo gallery | gallery demos stay alive", function(hooks) {
17
21
  let gallery = setupChoreoGalleryTest(hooks);
@@ -23,11 +27,13 @@ function rest() {
23
27
  const waiting = rows.filter((row) => Number(getComputedStyle(row).opacity) < .5);
24
28
  assert.ok(waiting.length > 0, `rows below the fold are still waiting: ${rows.map((r) => getComputedStyle(r).opacity).join(",")}`);
25
29
  });
26
- (0, import_qunit.test)("a looping keyframe animation is running", async function(assert) {
30
+ (0, import_qunit.test)("a looping keyframe animation runs once its tile is on stage", async function(assert) {
27
31
  await gallery.renderGallery();
28
32
  await rest();
29
33
  const morph = document.querySelector(".morph");
30
34
  assert.ok(morph, "the keyframes demo rendered");
35
+ morph.scrollIntoView({ block: "center" });
36
+ await rest();
31
37
  const running = morph.getAnimations().concat([...morph.parentElement?.getAnimations() ?? []]);
32
38
  const animating = running.length > 0 || Number(getComputedStyle(morph).opacity) < 1;
33
39
  assert.ok(animating, `something is animating on it: ${running.length}`);
@@ -1,6 +1,6 @@
1
1
  import { s as __toESM } from "./chunk-Rp0pCe6z.js";
2
2
  import { t as require_qunit } from "./qunit-C-Foo4Nd.js";
3
- import { a as setupChoreoGalleryTest } from "./choreo-gallery-stage-Bmz9m8sP.js";
3
+ import { a as setupChoreoGalleryTest } from "./choreo-gallery-stage-DVGS6XI-.js";
4
4
  //#region tests/integration/choreo-gallery-drift-test.ts
5
5
  var import_qunit = /* @__PURE__ */ __toESM(require_qunit());
6
6
  var applied;
@@ -1,7 +1,7 @@
1
1
  import { s as __toESM } from "./chunk-Rp0pCe6z.js";
2
2
  import { a as find, d as click } from "./dist-BGqriEf8.js";
3
3
  import { t as require_qunit } from "./qunit-C-Foo4Nd.js";
4
- import { a as setupChoreoGalleryTest, o as setupStageViewport, r as frames } from "./choreo-gallery-stage-Bmz9m8sP.js";
4
+ import { a as setupChoreoGalleryTest, o as setupStageViewport, r as frames } from "./choreo-gallery-stage-DVGS6XI-.js";
5
5
  //#region tests/integration/choreo-gallery-escort-test.gts
6
6
  /**
7
7
  * Escort — the acceptance page for the opened step vocabulary
@@ -6,7 +6,7 @@ import { F as setupLocalIndexing, M as setupCardLogs, P as setupIntegrationTestR
6
6
  import { r as getService } from "./dist-BE9MasZr.js";
7
7
  import { o as setupChoreo } from "./test-support-BLXHZ-sH.js";
8
8
  import { vt as setupBaseRealm } from "./base-realm-DMaIwpS6.js";
9
- import { t as choreoGalleryContents } from "./choreo-gallery-B0nnktwP.js";
9
+ import { t as choreoGalleryContents } from "./choreo-gallery-D8__QZCe.js";
10
10
  import { t as renderCard } from "./render-component-PtY1yFne.js";
11
11
  //#region tests/integration/choreo-gallery-films-test.gts
12
12
  var import_qunit = /* @__PURE__ */ __toESM(require_qunit());
@@ -1,7 +1,7 @@
1
1
  import { s as __toESM } from "./chunk-Rp0pCe6z.js";
2
2
  import { d as click } from "./dist-BGqriEf8.js";
3
3
  import { t as require_qunit } from "./qunit-C-Foo4Nd.js";
4
- import { a as setupChoreoGalleryTest, i as galleryInstance, n as GALLERY_DEMOS } from "./choreo-gallery-stage-Bmz9m8sP.js";
4
+ import { a as setupChoreoGalleryTest, i as galleryInstance, n as GALLERY_DEMOS } from "./choreo-gallery-stage-DVGS6XI-.js";
5
5
  //#region tests/integration/choreo-gallery-filter-test.gts
6
6
  var import_qunit = /* @__PURE__ */ __toESM(require_qunit());
7
7
  /** the catalog: every linked demo, with the group it files under */
@@ -2,7 +2,7 @@ import { s as __toESM } from "./chunk-Rp0pCe6z.js";
2
2
  import { T as settled } from "./dist-BGqriEf8.js";
3
3
  import { t as require_qunit } from "./qunit-C-Foo4Nd.js";
4
4
  import { t as animationsSettled } from "./test-support-foMaafLc.js";
5
- import { a as setupChoreoGalleryTest, o as setupStageViewport, r as frames } from "./choreo-gallery-stage-Bmz9m8sP.js";
5
+ import { a as setupChoreoGalleryTest, o as setupStageViewport, r as frames } from "./choreo-gallery-stage-DVGS6XI-.js";
6
6
  //#region tests/integration/choreo-gallery-fold-test.gts
7
7
  /**
8
8
  * The Fold demo's argument, asserted.
@@ -14,8 +14,8 @@ import { M as waitUntil, d as click, h as render, o as waitFor } from "./dist-BG
14
14
  import { t as require_qunit } from "./qunit-C-Foo4Nd.js";
15
15
  import "./mock-matrix-CJaQa5Mm.js";
16
16
  import { n as live, r as liveAll } from "./test-support-BLXHZ-sH.js";
17
- import { n as choreoGalleryGuides } from "./choreo-gallery-B0nnktwP.js";
18
- import { a as setupChoreoGalleryTest, i as galleryInstance, n as GALLERY_DEMOS } from "./choreo-gallery-stage-Bmz9m8sP.js";
17
+ import { n as choreoGalleryGuides } from "./choreo-gallery-D8__QZCe.js";
18
+ import { a as setupChoreoGalleryTest, i as galleryInstance, n as GALLERY_DEMOS } from "./choreo-gallery-stage-DVGS6XI-.js";
19
19
  //#region tests/integration/choreo-gallery-guides-test.gts
20
20
  /**
21
21
  * The guides, their links and the lab: a guide renders from the realm with
@@ -2,7 +2,7 @@ import { s as __toESM } from "./chunk-Rp0pCe6z.js";
2
2
  import { T as settled } from "./dist-BGqriEf8.js";
3
3
  import { t as require_qunit } from "./qunit-C-Foo4Nd.js";
4
4
  import { t as animationsSettled } from "./test-support-foMaafLc.js";
5
- import { a as setupChoreoGalleryTest, l as trigger, o as setupStageViewport, r as frames, s as sleep, t as $ } from "./choreo-gallery-stage-Bmz9m8sP.js";
5
+ import { a as setupChoreoGalleryTest, l as trigger, o as setupStageViewport, r as frames, s as sleep, t as $ } from "./choreo-gallery-stage-DVGS6XI-.js";
6
6
  //#region tests/integration/choreo-gallery-hang-test.gts
7
7
  /**
8
8
  * Hang's argument, asserted: a throw is READ, and the reading is what puts
@@ -1,7 +1,7 @@
1
1
  import { s as __toESM } from "./chunk-Rp0pCe6z.js";
2
2
  import { t as require_qunit } from "./qunit-C-Foo4Nd.js";
3
- import { t as choreoGalleryContents } from "./choreo-gallery-B0nnktwP.js";
4
- import { a as setupChoreoGalleryTest } from "./choreo-gallery-stage-Bmz9m8sP.js";
3
+ import { t as choreoGalleryContents } from "./choreo-gallery-D8__QZCe.js";
4
+ import { a as setupChoreoGalleryTest } from "./choreo-gallery-stage-DVGS6XI-.js";
5
5
  //#region tests/integration/choreo-gallery-highlight-test.ts
6
6
  var import_qunit = /* @__PURE__ */ __toESM(require_qunit());
7
7
  var highlightSample;
@@ -2,7 +2,7 @@ import { s as __toESM } from "./chunk-Rp0pCe6z.js";
2
2
  import { a as find, d as click, s as fillIn } from "./dist-BGqriEf8.js";
3
3
  import { t as require_qunit } from "./qunit-C-Foo4Nd.js";
4
4
  import { t as animationsSettled } from "./test-support-foMaafLc.js";
5
- import { a as setupChoreoGalleryTest, o as setupStageViewport, r as frames } from "./choreo-gallery-stage-Bmz9m8sP.js";
5
+ import { a as setupChoreoGalleryTest, o as setupStageViewport, r as frames } from "./choreo-gallery-stage-DVGS6XI-.js";
6
6
  //#region tests/integration/choreo-gallery-inline-edit-test.gts
7
7
  /**
8
8
  * The Inline Edit demo: a record read, then written.
@@ -5,7 +5,7 @@ import { i as setMotionSpeed } from "./speed-bIo0tyrM.js";
5
5
  import { t as require_qunit } from "./qunit-C-Foo4Nd.js";
6
6
  import { t as animationsSettled } from "./test-support-foMaafLc.js";
7
7
  import { i as orphanCount, s as strandedTransforms } from "./test-support-BLXHZ-sH.js";
8
- import { a as setupChoreoGalleryTest, o as setupStageViewport, s as sleep } from "./choreo-gallery-stage-Bmz9m8sP.js";
8
+ import { a as setupChoreoGalleryTest, o as setupStageViewport, s as sleep } from "./choreo-gallery-stage-DVGS6XI-.js";
9
9
  //#region tests/integration/choreo-gallery-interruption-test.gts
10
10
  /**
11
11
  * Rapid interruption, across every stage in the gallery.
@@ -13,7 +13,7 @@ import { t as LayoutGroup } from "./layout-group-Btk-S82w.js";
13
13
  import { t as MotionModifier } from "./motion-CU0yC2Ky.js";
14
14
  import { t as Presence } from "./presence-BYtEBpVa.js";
15
15
  import { t as require_qunit } from "./qunit-C-Foo4Nd.js";
16
- import { a as setupChoreoGalleryTest } from "./choreo-gallery-stage-Bmz9m8sP.js";
16
+ import { a as setupChoreoGalleryTest } from "./choreo-gallery-stage-DVGS6XI-.js";
17
17
  //#region tests/integration/choreo-gallery-lone-stack-test.gts
18
18
  var import_qunit = /* @__PURE__ */ __toESM(require_qunit());
19
19
  var keyOf = (item) => item.id;
@@ -5,7 +5,7 @@ import { t as HostModeService } from "./host-mode-service-CtK92ze8.js";
5
5
  import { T as settled, d as click, k as visit, o as waitFor, y as currentURL } from "./dist-BGqriEf8.js";
6
6
  import { t as require_qunit } from "./qunit-C-Foo4Nd.js";
7
7
  import { F as setupLocalIndexing, I as setupOnSave, ct as setupApplicationTest, j as setupAcceptanceTestRealm, pt as setupAuthEndpoints, st as visitOperatorMode, t as setupMockMatrix, z as setupUserSubscription } from "./mock-matrix-CJaQa5Mm.js";
8
- import { r as choreoGalleryRealmOf } from "./choreo-gallery-B0nnktwP.js";
8
+ import { r as choreoGalleryRealmOf } from "./choreo-gallery-D8__QZCe.js";
9
9
  //#region tests/acceptance/choreo-gallery-navigation-test.gts
10
10
  /**
11
11
  * Moving around the Choreo gallery is the host's: each tile is the demo
@@ -1,7 +1,7 @@
1
1
  import { s as __toESM } from "./chunk-Rp0pCe6z.js";
2
2
  import { M as waitUntil, T as settled } from "./dist-BGqriEf8.js";
3
3
  import { t as require_qunit } from "./qunit-C-Foo4Nd.js";
4
- import { a as setupChoreoGalleryTest, r as frames } from "./choreo-gallery-stage-Bmz9m8sP.js";
4
+ import { a as setupChoreoGalleryTest, r as frames } from "./choreo-gallery-stage-DVGS6XI-.js";
5
5
  //#region tests/integration/choreo-gallery-playhead-transport-test.gts
6
6
  /**
7
7
  * The Playhead demo on `c.run` — the score is a <c.Sequence>, the presses
@@ -16,7 +16,7 @@ import { t as MotionModifier } from "./motion-CU0yC2Ky.js";
16
16
  import { t as Presence } from "./presence-BYtEBpVa.js";
17
17
  import { t as require_qunit } from "./qunit-C-Foo4Nd.js";
18
18
  import "./test-support-foMaafLc.js";
19
- import { a as setupChoreoGalleryTest, c as stageWellStyle, o as setupStageViewport, s as sleep } from "./choreo-gallery-stage-Bmz9m8sP.js";
19
+ import { a as setupChoreoGalleryTest, c as stageWellStyle, o as setupStageViewport, s as sleep } from "./choreo-gallery-stage-DVGS6XI-.js";
20
20
  //#region tests/integration/choreo-gallery-poplayout-subtree-test.gts
21
21
  var import_qunit = /* @__PURE__ */ __toESM(require_qunit());
22
22
  var keyOf = (demo) => demo.slug;
@@ -2,7 +2,7 @@ import { s as __toESM } from "./chunk-Rp0pCe6z.js";
2
2
  import { a as find, d as click } from "./dist-BGqriEf8.js";
3
3
  import { t as require_qunit } from "./qunit-C-Foo4Nd.js";
4
4
  import { n as bounds, t as animationsSettled } from "./test-support-foMaafLc.js";
5
- import { a as setupChoreoGalleryTest } from "./choreo-gallery-stage-Bmz9m8sP.js";
5
+ import { a as setupChoreoGalleryTest } from "./choreo-gallery-stage-DVGS6XI-.js";
6
6
  //#region tests/integration/choreo-gallery-presence-modes-test.gts
7
7
  /**
8
8
  * What `sync` actually does to the layout — asserted, because it reads as a
@@ -2,7 +2,7 @@ import { s as __toESM } from "./chunk-Rp0pCe6z.js";
2
2
  import { M as waitUntil, c as triggerKeyEvent, d as click, f as focus } from "./dist-BGqriEf8.js";
3
3
  import { t as require_qunit } from "./qunit-C-Foo4Nd.js";
4
4
  import { t as animationsSettled } from "./test-support-foMaafLc.js";
5
- import { a as setupChoreoGalleryTest, r as frames } from "./choreo-gallery-stage-Bmz9m8sP.js";
5
+ import { a as setupChoreoGalleryTest, r as frames } from "./choreo-gallery-stage-DVGS6XI-.js";
6
6
  //#region tests/integration/choreo-gallery-presentation-test.gts
7
7
  /**
8
8
  * Presentation — gates as presenter mode (packages/choreo-gallery/realm/docs/choreo-constructs.md §8.1).
@@ -15,6 +15,8 @@ function run() {
15
15
  return host()?.presentation?.c?.run ?? null;
16
16
  }
17
17
  var opacityOf = (sel) => parseFloat(getComputedStyle(document.querySelector(sel)).opacity);
18
+ /** the deck's key cue: the Space / ‹ › hint shows only while it is lit */
19
+ var keyCueShows = () => getComputedStyle(document.querySelector(".pres-keys")).visibility === "visible";
18
20
  (0, import_qunit.module)("Integration | Choreo gallery | presentation", function(hooks) {
19
21
  let gallery = setupChoreoGalleryTest(hooks);
20
22
  let Presentation;
@@ -118,5 +120,38 @@ var opacityOf = (sel) => parseFloat(getComputedStyle(document.querySelector(sel)
118
120
  assert.strictEqual(title?.getAttribute("data-arrive"), "back");
119
121
  assert.ok(opacityOf(".pres-title") > .9, "back shows the title slide already built");
120
122
  });
123
+ (0, import_qunit.test)("the bar takes Tab, and a key on a bar control is that control's own", async function(assert) {
124
+ await gallery.renderStage(Presentation);
125
+ await waitUntil(() => {
126
+ const r = run();
127
+ return Boolean(r?.parked && r.segment === 1);
128
+ }, { timeout: 4e3 });
129
+ const deck = document.querySelector("[data-test-pres]");
130
+ const controls = [
131
+ "[data-test-pres-seg=\"0\"]",
132
+ "[data-test-pres-xfade]",
133
+ "[data-test-pres-restart]",
134
+ "[data-test-pres-back]",
135
+ "[data-test-pres-fwd]"
136
+ ].map((selector) => document.querySelector(selector));
137
+ for (const control of controls) assert.strictEqual(control.tabIndex, 0, "a bar control is a tab stop");
138
+ const restart = document.querySelector("[data-test-pres-restart]");
139
+ await focus(restart);
140
+ assert.false(keyCueShows(), "focus on a bar control leaves the cue dark");
141
+ await triggerKeyEvent(restart, "keydown", " ");
142
+ await triggerKeyEvent(restart, "keydown", "ArrowRight");
143
+ await frames(1);
144
+ assert.true(run().parked, "the deck did not take the keys");
145
+ assert.strictEqual(run().segment, 1, "no build moved");
146
+ const fwd = document.querySelector("[data-test-pres-fwd]");
147
+ await click(fwd);
148
+ assert.strictEqual(document.activeElement, fwd, "a keyboard press leaves focus on the control");
149
+ assert.false(keyCueShows(), "a keyboard press leaves the cue dark");
150
+ await animationsSettled();
151
+ await click(fwd, { detail: 1 });
152
+ assert.strictEqual(document.activeElement, deck, "a pointer press hands focus to the deck");
153
+ assert.true(keyCueShows(), "the deck that takes the keys lights the cue");
154
+ await animationsSettled();
155
+ });
121
156
  });
122
157
  //#endregion
@@ -8,7 +8,7 @@ import { d as click } from "./dist-BGqriEf8.js";
8
8
  import "./src-DKlevVIu.js";
9
9
  import { t as LayoutGroup } from "./layout-group-Btk-S82w.js";
10
10
  import { t as require_qunit } from "./qunit-C-Foo4Nd.js";
11
- import { a as setupChoreoGalleryTest, r as frames } from "./choreo-gallery-stage-Bmz9m8sP.js";
11
+ import { a as setupChoreoGalleryTest, r as frames } from "./choreo-gallery-stage-DVGS6XI-.js";
12
12
  //#region tests/integration/choreo-gallery-sheet-standalone-test.gts
13
13
  /**
14
14
  * Every distinct reading over a wall-clock window.
@@ -2,7 +2,7 @@ import { s as __toESM } from "./chunk-Rp0pCe6z.js";
2
2
  import { d as click } from "./dist-BGqriEf8.js";
3
3
  import { t as require_qunit } from "./qunit-C-Foo4Nd.js";
4
4
  import { t as animationsSettled } from "./test-support-foMaafLc.js";
5
- import { a as setupChoreoGalleryTest } from "./choreo-gallery-stage-Bmz9m8sP.js";
5
+ import { a as setupChoreoGalleryTest } from "./choreo-gallery-stage-DVGS6XI-.js";
6
6
  //#region tests/integration/choreo-gallery-sheet-test.gts
7
7
  var import_qunit = /* @__PURE__ */ __toESM(require_qunit());
8
8
  /** the sheet's own y, read off the element rather than off the props */ function offset(el) {
@@ -12,7 +12,7 @@ import { d as click, h as render, o as waitFor } from "./dist-BGqriEf8.js";
12
12
  import { t as require_qunit } from "./qunit-C-Foo4Nd.js";
13
13
  import { nt as provide } from "./mock-matrix-CJaQa5Mm.js";
14
14
  import { n as live, r as liveAll } from "./test-support-BLXHZ-sH.js";
15
- import { a as setupChoreoGalleryTest, n as GALLERY_DEMOS } from "./choreo-gallery-stage-Bmz9m8sP.js";
15
+ import { a as setupChoreoGalleryTest, n as GALLERY_DEMOS } from "./choreo-gallery-stage-DVGS6XI-.js";
16
16
  //#region tests/integration/choreo-gallery-site-test.gts
17
17
  /**
18
18
  * The gallery site, whole: the gallery card as the realm serves it — every
@@ -12,7 +12,7 @@ import { F as setupLocalIndexing, M as setupCardLogs, P as setupIntegrationTestR
12
12
  import { r as getService } from "./dist-BE9MasZr.js";
13
13
  import { o as setupChoreo } from "./test-support-BLXHZ-sH.js";
14
14
  import { vt as setupBaseRealm } from "./base-realm-DMaIwpS6.js";
15
- import { t as choreoGalleryContents } from "./choreo-gallery-B0nnktwP.js";
15
+ import { t as choreoGalleryContents } from "./choreo-gallery-D8__QZCe.js";
16
16
  import { t as renderCard } from "./render-component-PtY1yFne.js";
17
17
  //#region tests/helpers/choreo-gallery-stage.gts
18
18
  /** a card instance document in the gallery realm, as much as the tests read */
@@ -0,0 +1,102 @@
1
+ import { s as __toESM } from "./chunk-Rp0pCe6z.js";
2
+ import { M as waitUntil, c as triggerKeyEvent, d as click, f as focus } from "./dist-BGqriEf8.js";
3
+ import { t as require_qunit } from "./qunit-C-Foo4Nd.js";
4
+ import { t as animationsSettled } from "./test-support-foMaafLc.js";
5
+ import { a as setupChoreoGalleryTest } from "./choreo-gallery-stage-DVGS6XI-.js";
6
+ //#region tests/integration/choreo-gallery-stage-keyboard-test.gts
7
+ /**
8
+ * The stages' keyboard paths: every focusable part of a stage shows the
9
+ * site's focus ring, and what a pointer does on a stage's open surface a
10
+ * key can do too.
11
+ */ var import_qunit = /* @__PURE__ */ __toESM(require_qunit());
12
+ /** the focus ring the browser draws on `el` once it has keyboard focus */
13
+ async function ringOn(el) {
14
+ await focus(el);
15
+ let style = getComputedStyle(el);
16
+ return {
17
+ focusVisible: el.matches(":focus-visible"),
18
+ outline: style.outlineStyle,
19
+ color: style.outlineColor
20
+ };
21
+ }
22
+ /** the theme's focus color, `--ring`, as it resolves where `el` sits */
23
+ function themeRing(el) {
24
+ let probe = document.createElement("i");
25
+ probe.style.color = "var(--ring)";
26
+ el.parentElement.append(probe);
27
+ let color = getComputedStyle(probe).color;
28
+ probe.remove();
29
+ return color;
30
+ }
31
+ /** the keydown that reaches the document, if a stage lets it through */
32
+ async function keyAtDocument(el, key) {
33
+ let seen;
34
+ let listen = (event) => seen = event;
35
+ document.addEventListener("keydown", listen);
36
+ try {
37
+ await triggerKeyEvent(el, "keydown", key);
38
+ } finally {
39
+ document.removeEventListener("keydown", listen);
40
+ }
41
+ return seen;
42
+ }
43
+ (0, import_qunit.module)("Integration | Choreo gallery | stage keyboard", function(hooks) {
44
+ let gallery = setupChoreoGalleryTest(hooks);
45
+ (0, import_qunit.test)("a camera print shows the focus ring", async function(assert) {
46
+ await gallery.renderStage(await gallery.stage("camera", "Camera"));
47
+ let print = document.querySelector("[data-test-cam-print]");
48
+ let ring = await ringOn(print);
49
+ assert.true(ring.focusVisible, "the print has keyboard focus");
50
+ assert.notStrictEqual(ring.outline, "none", "the print draws a ring");
51
+ assert.strictEqual(ring.color, themeRing(print), "the ring is drawn in the theme's --ring");
52
+ });
53
+ (0, import_qunit.test)("Escape backs out of a camera dive and returns focus to the print", async function(assert) {
54
+ await gallery.renderStage(await gallery.stage("camera", "Camera"));
55
+ let print = document.querySelector("[data-test-cam-print]");
56
+ assert.strictEqual(print.getAttribute("aria-pressed"), "false");
57
+ await focus(print);
58
+ await click(print);
59
+ await waitUntil(() => document.querySelector("[data-test-cam-love]"));
60
+ assert.strictEqual(print.getAttribute("aria-pressed"), "true", "the open print reads as pressed");
61
+ let love = document.querySelector("[data-test-cam-love]");
62
+ await focus(love);
63
+ let reached = await keyAtDocument(love, "Escape");
64
+ await animationsSettled();
65
+ assert.strictEqual(reached, void 0, "the stage kept the key");
66
+ assert.dom("[data-test-cam-love]").doesNotExist("the dive closed");
67
+ assert.strictEqual(print.getAttribute("aria-pressed"), "false");
68
+ assert.strictEqual(document.activeElement, print, "focus is back on the print that was open");
69
+ });
70
+ (0, import_qunit.test)("a pointer dive leaves focus on the print, so Escape backs out of it", async function(assert) {
71
+ await gallery.renderStage(await gallery.stage("camera", "Camera"));
72
+ let print = document.querySelector("[data-test-cam-print]");
73
+ print.dispatchEvent(new MouseEvent("click", {
74
+ bubbles: true,
75
+ detail: 1
76
+ }));
77
+ await waitUntil(() => document.querySelector("[data-test-cam-love]"));
78
+ assert.strictEqual(document.activeElement, print, "the open print has focus");
79
+ assert.false(print.matches(":focus-visible"), "a pointer dive draws no focus ring");
80
+ let reached = await keyAtDocument(print, "Escape");
81
+ await animationsSettled();
82
+ assert.strictEqual(reached, void 0, "the stage kept the key");
83
+ assert.dom("[data-test-cam-love]").doesNotExist("the dive closed");
84
+ });
85
+ (0, import_qunit.test)("Escape with no dive open is left for the host", async function(assert) {
86
+ await gallery.renderStage(await gallery.stage("camera", "Camera"));
87
+ let print = document.querySelector("[data-test-cam-print]");
88
+ await focus(print);
89
+ let reached = await keyAtDocument(print, "Escape");
90
+ assert.ok(reached, "the key reaches the host");
91
+ assert.false(reached.defaultPrevented, "the stage left it alone");
92
+ });
93
+ (0, import_qunit.test)("a wires mark and comment show the focus ring", async function(assert) {
94
+ await gallery.renderStage(await gallery.stage("wires", "Wires"));
95
+ for (let selector of ["[data-test-wires-mark]", "[data-test-wires-note]"]) {
96
+ let ring = await ringOn(document.querySelector(selector));
97
+ assert.true(ring.focusVisible, `${selector} has keyboard focus`);
98
+ assert.notStrictEqual(ring.outline, "none", `${selector} draws a ring`);
99
+ }
100
+ });
101
+ });
102
+ //#endregion