@ckeditor/ckeditor5-dev-manual-server 56.2.0
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/LICENSE.md +16 -0
- package/README.md +17 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +584 -0
- package/dist/manual-test-plugin/collect-pages.d.ts +6 -0
- package/dist/manual-test-plugin/parse-markdown.d.ts +6 -0
- package/dist/manual-test-plugin/plugin.d.ts +7 -0
- package/dist/manual-test-plugin/shell-html.d.ts +13 -0
- package/dist/manual-test-plugin/static-assets.d.ts +10 -0
- package/dist/manual-test-plugin/types.d.ts +18 -0
- package/dist/raw-plugin/plugin.d.ts +6 -0
- package/dist/refresh-plugin/plugin.d.ts +7 -0
- package/dist/utils.d.ts +20 -0
- package/package.json +38 -0
- package/theme/catalog.css +252 -0
- package/theme/catalog.html +57 -0
- package/theme/catalog.ts +162 -0
- package/theme/shell.css +361 -0
- package/theme/shell.html +46 -0
- package/theme/shell.ts +179 -0
package/theme/shell.css
ADDED
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
.manual-test-container {
|
|
2
|
+
min-width: 0;
|
|
3
|
+
box-sizing: border-box;
|
|
4
|
+
padding: calc( var( --shell-height, 44px ) + 8px ) 8px 8px;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
body.shell-enabled {
|
|
8
|
+
box-sizing: border-box;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.shell {
|
|
12
|
+
position: fixed;
|
|
13
|
+
top: 0;
|
|
14
|
+
left: 0;
|
|
15
|
+
right: 0;
|
|
16
|
+
z-index: 99999;
|
|
17
|
+
display: flex;
|
|
18
|
+
align-items: stretch;
|
|
19
|
+
box-sizing: border-box;
|
|
20
|
+
padding: 6px 8px;
|
|
21
|
+
font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
22
|
+
font-size: 12px;
|
|
23
|
+
line-height: 1.25;
|
|
24
|
+
color: #0a0a0a;
|
|
25
|
+
background: rgb(255 255 255 / 85%);
|
|
26
|
+
backdrop-filter: saturate(180%) blur(20px);
|
|
27
|
+
-webkit-backdrop-filter: saturate(180%) blur(20px);
|
|
28
|
+
border-bottom: 1px solid rgb(0 0 0 / 8%);
|
|
29
|
+
box-shadow: 0 1px 2px rgb(0 0 0 / 4%);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.shell__pill {
|
|
33
|
+
display: inline-flex;
|
|
34
|
+
align-items: center;
|
|
35
|
+
padding: 8px 14px;
|
|
36
|
+
border: 0;
|
|
37
|
+
background: transparent;
|
|
38
|
+
border-radius: 999px;
|
|
39
|
+
text-decoration: none;
|
|
40
|
+
color: inherit;
|
|
41
|
+
font: inherit;
|
|
42
|
+
font-weight: 500;
|
|
43
|
+
white-space: nowrap;
|
|
44
|
+
transition: background 0.1s;
|
|
45
|
+
cursor: pointer;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.shell__pill:hover {
|
|
49
|
+
background: rgb(0 0 0 / 5%);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.shell__pill:active {
|
|
53
|
+
background: rgb(0 0 0 / 10%);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.shell__pill:focus-visible {
|
|
57
|
+
outline: 2px solid rgb(0 0 0 / 30%);
|
|
58
|
+
outline-offset: 1px;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.shell__divider {
|
|
62
|
+
flex-shrink: 0;
|
|
63
|
+
align-self: center;
|
|
64
|
+
width: 1px;
|
|
65
|
+
height: 16px;
|
|
66
|
+
background: rgb(0 0 0 / 10%);
|
|
67
|
+
margin: 0 2px;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.shell__label {
|
|
71
|
+
display: inline-flex;
|
|
72
|
+
align-items: center;
|
|
73
|
+
flex: 1 1 auto;
|
|
74
|
+
gap: 10px;
|
|
75
|
+
padding: 8px 14px;
|
|
76
|
+
overflow: hidden;
|
|
77
|
+
min-width: 0;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.shell__label-name {
|
|
81
|
+
font-weight: 600;
|
|
82
|
+
overflow: hidden;
|
|
83
|
+
text-overflow: ellipsis;
|
|
84
|
+
white-space: nowrap;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.shell__label-package {
|
|
88
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
89
|
+
font-weight: 400;
|
|
90
|
+
font-size: 11px;
|
|
91
|
+
opacity: 0.55;
|
|
92
|
+
overflow: hidden;
|
|
93
|
+
text-overflow: ellipsis;
|
|
94
|
+
white-space: nowrap;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.manual-refresh-prompt {
|
|
98
|
+
position: fixed;
|
|
99
|
+
top: calc( var( --shell-height, 44px ) / 1.25 );
|
|
100
|
+
left: 50%;
|
|
101
|
+
z-index: 100000;
|
|
102
|
+
box-sizing: border-box;
|
|
103
|
+
padding: 8px 14px;
|
|
104
|
+
border: 1px solid #bfdbfe;
|
|
105
|
+
border-radius: 999px;
|
|
106
|
+
font: 600 12px/1.25 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
107
|
+
color: #1d4ed8;
|
|
108
|
+
background: #dbeafe;
|
|
109
|
+
cursor: pointer;
|
|
110
|
+
opacity: 0;
|
|
111
|
+
pointer-events: none;
|
|
112
|
+
transform: translate(-50%, calc( -100% - var( --shell-height, 44px ) ) );
|
|
113
|
+
transition: transform 0.18s ease-out, opacity 0.18s ease-out, background 0.1s;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.manual-refresh-prompt--visible {
|
|
117
|
+
opacity: 1;
|
|
118
|
+
pointer-events: auto;
|
|
119
|
+
transform: translate(-50%, -50%);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.manual-refresh-prompt:hover {
|
|
123
|
+
background: #bfdbfe;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.manual-refresh-prompt:active {
|
|
127
|
+
background: #93c5fd;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.manual-refresh-prompt:focus-visible {
|
|
131
|
+
outline: 2px solid #2563eb;
|
|
132
|
+
outline-offset: 1px;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
@media (max-width: 600px) {
|
|
136
|
+
.shell {
|
|
137
|
+
font-size: 11px;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.shell__label-package {
|
|
141
|
+
display: none;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.shell__label-name {
|
|
145
|
+
max-width: 20ch;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.shell-instructions {
|
|
150
|
+
--shell-instructions-width: min(420px, 45vw);
|
|
151
|
+
--shell-instructions-transition-duration: 0.18s;
|
|
152
|
+
|
|
153
|
+
position: fixed;
|
|
154
|
+
top: 44px;
|
|
155
|
+
right: 0;
|
|
156
|
+
bottom: 0;
|
|
157
|
+
z-index: 99998;
|
|
158
|
+
order: 2;
|
|
159
|
+
align-self: start;
|
|
160
|
+
flex: 0 0 0;
|
|
161
|
+
width: 0;
|
|
162
|
+
height: 0;
|
|
163
|
+
min-height: 0;
|
|
164
|
+
padding: 0;
|
|
165
|
+
border: 0;
|
|
166
|
+
background: #fff;
|
|
167
|
+
color: #0a0a0a;
|
|
168
|
+
font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
169
|
+
line-height: 1.6;
|
|
170
|
+
overflow: hidden;
|
|
171
|
+
transition:
|
|
172
|
+
flex-basis var(--shell-instructions-transition-duration) ease-out,
|
|
173
|
+
width var(--shell-instructions-transition-duration) ease-out;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.shell-instructions--open,
|
|
177
|
+
.shell-instructions--closing {
|
|
178
|
+
align-self: stretch;
|
|
179
|
+
height: auto;
|
|
180
|
+
border-left: 1px solid rgb(0 0 0 / 8%);
|
|
181
|
+
box-shadow: -8px 0 24px rgb(0 0 0 / 8%);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.shell-instructions--open {
|
|
185
|
+
flex-basis: var(--shell-instructions-width);
|
|
186
|
+
width: var(--shell-instructions-width);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.shell-instructions__inner {
|
|
190
|
+
display: flex;
|
|
191
|
+
flex-direction: column;
|
|
192
|
+
width: var(--shell-instructions-width);
|
|
193
|
+
height: 100%;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.shell-instructions__header {
|
|
197
|
+
display: flex;
|
|
198
|
+
align-items: flex-start;
|
|
199
|
+
justify-content: space-between;
|
|
200
|
+
gap: 16px;
|
|
201
|
+
padding: 20px 24px;
|
|
202
|
+
border-bottom: 1px solid rgb(0 0 0 / 8%);
|
|
203
|
+
flex-shrink: 0;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.shell-instructions__titles {
|
|
207
|
+
min-width: 0;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.shell-instructions__title {
|
|
211
|
+
margin: 0 0 4px;
|
|
212
|
+
font-size: 18px;
|
|
213
|
+
font-weight: 700;
|
|
214
|
+
letter-spacing: -0.01em;
|
|
215
|
+
line-height: 1.3;
|
|
216
|
+
overflow: hidden;
|
|
217
|
+
text-overflow: ellipsis;
|
|
218
|
+
white-space: nowrap;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.shell-instructions__package {
|
|
222
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
223
|
+
font-size: 12px;
|
|
224
|
+
color: #737373;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.shell-instructions__close {
|
|
228
|
+
flex-shrink: 0;
|
|
229
|
+
display: inline-flex;
|
|
230
|
+
align-items: center;
|
|
231
|
+
justify-content: center;
|
|
232
|
+
width: 32px;
|
|
233
|
+
height: 32px;
|
|
234
|
+
padding: 0;
|
|
235
|
+
border: 0;
|
|
236
|
+
border-radius: 8px;
|
|
237
|
+
background: transparent;
|
|
238
|
+
color: #737373;
|
|
239
|
+
cursor: pointer;
|
|
240
|
+
transition: background 0.1s, color 0.1s;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.shell-instructions__close:hover {
|
|
244
|
+
background: rgb(0 0 0 / 5%);
|
|
245
|
+
color: #0a0a0a;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.shell-instructions__close:focus-visible {
|
|
249
|
+
outline: 2px solid rgb(0 0 0 / 30%);
|
|
250
|
+
outline-offset: 1px;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.shell-instructions__body {
|
|
254
|
+
padding: 20px 24px 28px;
|
|
255
|
+
font-size: 14px;
|
|
256
|
+
overflow-y: auto;
|
|
257
|
+
min-height: 0;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.shell-instructions__body h1,
|
|
261
|
+
.shell-instructions__body h2,
|
|
262
|
+
.shell-instructions__body h3,
|
|
263
|
+
.shell-instructions__body h4,
|
|
264
|
+
.shell-instructions__body h5,
|
|
265
|
+
.shell-instructions__body h6 {
|
|
266
|
+
margin: 24px 0 8px;
|
|
267
|
+
font-weight: 600;
|
|
268
|
+
letter-spacing: -0.01em;
|
|
269
|
+
line-height: 1.3;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
.shell-instructions__body h1 { font-size: 20px; }
|
|
273
|
+
.shell-instructions__body h2 { font-size: 17px; }
|
|
274
|
+
.shell-instructions__body h3 { font-size: 15px; }
|
|
275
|
+
.shell-instructions__body h4,
|
|
276
|
+
.shell-instructions__body h5,
|
|
277
|
+
.shell-instructions__body h6 { font-size: 14px; }
|
|
278
|
+
|
|
279
|
+
.shell-instructions__body > :first-child { margin-top: 0; }
|
|
280
|
+
.shell-instructions__body > :last-child { margin-bottom: 0; }
|
|
281
|
+
|
|
282
|
+
.shell-instructions__body p {
|
|
283
|
+
margin: 8px 0;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.shell-instructions__body ul,
|
|
287
|
+
.shell-instructions__body ol {
|
|
288
|
+
margin: 8px 0;
|
|
289
|
+
padding-left: 24px;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.shell-instructions__body li {
|
|
293
|
+
margin: 3px 0;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.shell-instructions__body code {
|
|
297
|
+
padding: 1px 6px;
|
|
298
|
+
border-radius: 4px;
|
|
299
|
+
background: #f0f0f0;
|
|
300
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
301
|
+
font-size: 0.9em;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.shell-instructions__body pre {
|
|
305
|
+
margin: 12px 0;
|
|
306
|
+
padding: 12px 14px;
|
|
307
|
+
border-radius: 8px;
|
|
308
|
+
background: #f5f5f5;
|
|
309
|
+
overflow-x: auto;
|
|
310
|
+
font-size: 12px;
|
|
311
|
+
line-height: 1.5;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
.shell-instructions__body pre code {
|
|
315
|
+
padding: 0;
|
|
316
|
+
background: transparent;
|
|
317
|
+
font-size: inherit;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.shell-instructions__body a {
|
|
321
|
+
color: #1d4ed8;
|
|
322
|
+
text-decoration: underline;
|
|
323
|
+
text-underline-offset: 2px;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
.shell-instructions__body blockquote {
|
|
327
|
+
margin: 12px 0;
|
|
328
|
+
padding: 4px 14px;
|
|
329
|
+
border-left: 3px solid rgb(0 0 0 / 15%);
|
|
330
|
+
color: #525252;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.shell-instructions__body table {
|
|
334
|
+
margin: 12px 0;
|
|
335
|
+
border-collapse: collapse;
|
|
336
|
+
font-size: 13px;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
.shell-instructions__body th,
|
|
340
|
+
.shell-instructions__body td {
|
|
341
|
+
padding: 6px 10px;
|
|
342
|
+
border: 1px solid rgb(0 0 0 / 10%);
|
|
343
|
+
text-align: left;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.shell-instructions__body th {
|
|
347
|
+
background: #f5f5f5;
|
|
348
|
+
font-weight: 600;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.shell-instructions__body hr {
|
|
352
|
+
margin: 16px 0;
|
|
353
|
+
border: 0;
|
|
354
|
+
border-top: 1px solid rgb(0 0 0 / 10%);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
@media (max-width: 800px) {
|
|
358
|
+
.shell-instructions {
|
|
359
|
+
--shell-instructions-width: min(360px, 70vw);
|
|
360
|
+
}
|
|
361
|
+
}
|
package/theme/shell.html
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<link rel="icon" href="data:image/png;base64,iVBORw0KGgo=">
|
|
7
|
+
<title></title>
|
|
8
|
+
<script type="module" data-manual-shell-script></script>
|
|
9
|
+
<script type="module" data-manual-test-script></script>
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
12
|
+
<template id="manual-shell-template">
|
|
13
|
+
<div class="shell">
|
|
14
|
+
<a class="shell__pill" href="/" title="Back to test index">← All tests</a>
|
|
15
|
+
<span class="shell__divider" aria-hidden="true"></span>
|
|
16
|
+
<span class="shell__label">
|
|
17
|
+
<span class="shell__label-name" data-manual-shell-field="displayName"></span>
|
|
18
|
+
<span class="shell__label-package" data-manual-shell-field="packageName"></span>
|
|
19
|
+
</span>
|
|
20
|
+
<span class="shell__divider" data-manual-shell-section="instructions" aria-hidden="true"></span>
|
|
21
|
+
<button type="button" class="shell__pill" data-manual-shell-section="instructions" data-shell-action="show-instructions" aria-expanded="false">
|
|
22
|
+
Instructions
|
|
23
|
+
</button>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<aside class="shell-instructions" data-manual-shell-section="instructions" aria-hidden="true" inert>
|
|
27
|
+
<div class="shell-instructions__inner">
|
|
28
|
+
<header class="shell-instructions__header">
|
|
29
|
+
<div class="shell-instructions__titles">
|
|
30
|
+
<h1 class="shell-instructions__title" data-manual-shell-field="displayName"></h1>
|
|
31
|
+
<code class="shell-instructions__package" data-manual-shell-field="packageName"></code>
|
|
32
|
+
</div>
|
|
33
|
+
<button type="button" class="shell-instructions__close" data-shell-action="close-instructions" aria-label="Close">
|
|
34
|
+
<svg viewBox="0 0 16 16" width="16" height="16" aria-hidden="true">
|
|
35
|
+
<path fill="currentColor" d="M3.72 3.72a.75.75 0 011.06 0L8 6.94l3.22-3.22a.75.75 0 111.06 1.06L9.06 8l3.22 3.22a.75.75 0 11-1.06 1.06L8 9.06l-3.22 3.22a.75.75 0 01-1.06-1.06L6.94 8 3.72 4.78a.75.75 0 010-1.06z"/>
|
|
36
|
+
</svg>
|
|
37
|
+
</button>
|
|
38
|
+
</header>
|
|
39
|
+
<article class="shell-instructions__body"></article>
|
|
40
|
+
</div>
|
|
41
|
+
</aside>
|
|
42
|
+
</template>
|
|
43
|
+
|
|
44
|
+
<script id="manual-shell-data" type="application/json"></script>
|
|
45
|
+
</body>
|
|
46
|
+
</html>
|
package/theme/shell.ts
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import CKEditorInspector from '@ckeditor/ckeditor5-inspector';
|
|
7
|
+
|
|
8
|
+
import './shell.css';
|
|
9
|
+
|
|
10
|
+
declare const LICENSE_KEY: string;
|
|
11
|
+
|
|
12
|
+
interface ManualData {
|
|
13
|
+
displayName: string;
|
|
14
|
+
instructionsHtml: string;
|
|
15
|
+
packageName: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface ViteHotContextLike {
|
|
19
|
+
on( event: string, callback: () => void ): void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const MANUAL_REFRESH_EVENT_NAME = 'ckeditor5-manual:refresh-available';
|
|
23
|
+
const globalTarget = window as any;
|
|
24
|
+
|
|
25
|
+
renderManual();
|
|
26
|
+
setupManualTestContainerState();
|
|
27
|
+
setupManualRefreshPrompt();
|
|
28
|
+
|
|
29
|
+
// In direct HTML manual tests, `id="editor"` creates `window.editor` as a named DOM property.
|
|
30
|
+
// Reset it so manual tests can safely reuse `window.editor` for the editor instance.
|
|
31
|
+
if ( globalTarget.editor instanceof Element ) {
|
|
32
|
+
globalTarget.editor = null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
globalTarget.CKEditorInspector ||= CKEditorInspector;
|
|
36
|
+
globalTarget.CKEDITOR_GLOBAL_LICENSE_KEY ||= LICENSE_KEY;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Clones the injected Shell template, fills it with current test metadata,
|
|
40
|
+
* and prepends it to the page before the test content is wrapped.
|
|
41
|
+
*/
|
|
42
|
+
function renderManual(): void {
|
|
43
|
+
const template = document.querySelector<HTMLTemplateElement>( '#manual-shell-template' )!;
|
|
44
|
+
const dataElement = document.querySelector<HTMLScriptElement>( '#manual-shell-data' )!;
|
|
45
|
+
const data = JSON.parse( dataElement.textContent! ) as ManualData;
|
|
46
|
+
const fragment = template.content.cloneNode( true ) as DocumentFragment;
|
|
47
|
+
|
|
48
|
+
for ( const element of fragment.querySelectorAll<HTMLElement>( '[data-manual-shell-field="displayName"]' ) ) {
|
|
49
|
+
element.textContent = data.displayName;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
for ( const element of fragment.querySelectorAll<HTMLElement>( '[data-manual-shell-field="packageName"]' ) ) {
|
|
53
|
+
element.textContent = data.packageName;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if ( data.instructionsHtml ) {
|
|
57
|
+
fragment.querySelector<HTMLElement>( '.shell-instructions__body' )!.innerHTML = data.instructionsHtml;
|
|
58
|
+
} else {
|
|
59
|
+
for ( const element of fragment.querySelectorAll<HTMLElement>( '[data-manual-shell-section="instructions"]' ) ) {
|
|
60
|
+
element.remove();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
template.remove();
|
|
65
|
+
dataElement.remove();
|
|
66
|
+
document.body.prepend( fragment );
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Sets up shell-related state for the manual test container injected by the HTML transform.
|
|
71
|
+
*/
|
|
72
|
+
function setupManualTestContainerState(): void {
|
|
73
|
+
document.body.classList.add( 'shell-enabled' );
|
|
74
|
+
|
|
75
|
+
if ( document.querySelector( '.shell-instructions' ) ) {
|
|
76
|
+
document.body.classList.add( 'shell-has-instructions' );
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Shows a manual refresh prompt when the dev server reports source changes.
|
|
82
|
+
*/
|
|
83
|
+
function setupManualRefreshPrompt(): void {
|
|
84
|
+
const hot = ( import.meta as ImportMeta & { hot?: ViteHotContextLike } ).hot;
|
|
85
|
+
|
|
86
|
+
if ( !hot ) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const button = document.createElement( 'button' );
|
|
91
|
+
|
|
92
|
+
button.type = 'button';
|
|
93
|
+
button.className = 'manual-refresh-prompt';
|
|
94
|
+
button.textContent = 'Source changed. Click here to refresh the page.';
|
|
95
|
+
button.tabIndex = -1;
|
|
96
|
+
button.setAttribute( 'aria-hidden', 'true' );
|
|
97
|
+
button.addEventListener( 'click', () => window.location.reload() );
|
|
98
|
+
|
|
99
|
+
document.body.appendChild( button );
|
|
100
|
+
|
|
101
|
+
hot.on( MANUAL_REFRESH_EVENT_NAME, () => {
|
|
102
|
+
button.removeAttribute( 'aria-hidden' );
|
|
103
|
+
button.removeAttribute( 'tabindex' );
|
|
104
|
+
button.classList.add( 'manual-refresh-prompt--visible' );
|
|
105
|
+
} );
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Opens or closes the instructions panel and synchronizes related accessibility state.
|
|
110
|
+
*/
|
|
111
|
+
function toggleInstructions( isOpen: boolean ): void {
|
|
112
|
+
const panel = document.querySelector<HTMLElement>( '.shell-instructions' );
|
|
113
|
+
const trigger = document.querySelector<HTMLElement>( '[data-shell-action="show-instructions"]' );
|
|
114
|
+
|
|
115
|
+
if ( !panel || !trigger ) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
panel.classList.remove( 'shell-instructions--closing' );
|
|
120
|
+
|
|
121
|
+
if ( !isOpen && panel.classList.contains( 'shell-instructions--open' ) ) {
|
|
122
|
+
panel.classList.add( 'shell-instructions--closing' );
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
panel.classList.toggle( 'shell-instructions--open', isOpen );
|
|
126
|
+
panel.setAttribute( 'aria-hidden', String( !isOpen ) );
|
|
127
|
+
panel.toggleAttribute( 'inert', !isOpen );
|
|
128
|
+
trigger.setAttribute( 'aria-expanded', String( isOpen ) );
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Handles clicks on Shell action buttons.
|
|
133
|
+
*/
|
|
134
|
+
document.addEventListener( 'click', event => {
|
|
135
|
+
const target = event.target;
|
|
136
|
+
|
|
137
|
+
if ( !( target instanceof Element ) ) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const trigger = target.closest<HTMLElement>( '[data-shell-action]' );
|
|
142
|
+
|
|
143
|
+
if ( !trigger ) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if ( trigger.dataset.shellAction == 'show-instructions' ) {
|
|
148
|
+
const panel = document.querySelector<HTMLElement>( '.shell-instructions' )!;
|
|
149
|
+
|
|
150
|
+
toggleInstructions( !panel.classList.contains( 'shell-instructions--open' ) );
|
|
151
|
+
} else if ( trigger.dataset.shellAction == 'close-instructions' ) {
|
|
152
|
+
toggleInstructions( false );
|
|
153
|
+
}
|
|
154
|
+
} );
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Cleans up the closing state after the instructions panel transition finishes.
|
|
158
|
+
*/
|
|
159
|
+
document.addEventListener( 'transitionend', event => {
|
|
160
|
+
const target = event.target;
|
|
161
|
+
|
|
162
|
+
if (
|
|
163
|
+
event.propertyName == 'width' &&
|
|
164
|
+
target instanceof Element &&
|
|
165
|
+
target.classList.contains( 'shell-instructions' ) &&
|
|
166
|
+
!target.classList.contains( 'shell-instructions--open' )
|
|
167
|
+
) {
|
|
168
|
+
target.classList.remove( 'shell-instructions--closing' );
|
|
169
|
+
}
|
|
170
|
+
} );
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Allows closing the instructions panel with Escape.
|
|
174
|
+
*/
|
|
175
|
+
document.addEventListener( 'keydown', event => {
|
|
176
|
+
if ( event.key == 'Escape' ) {
|
|
177
|
+
toggleInstructions( false );
|
|
178
|
+
}
|
|
179
|
+
} );
|