@ox-content/code-play 3.0.0-alpha.8 → 3.0.0-beta.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/README.md +35 -6
- package/dist/browser.mjs +587 -68
- package/dist/client.mjs +192 -28
- package/dist/client.mjs.map +1 -1
- package/dist/config.d.mts +47 -2
- package/dist/config.d.mts.map +1 -1
- package/dist/hydrate.d.mts +3 -1
- package/dist/hydrate.d.mts.map +1 -1
- package/dist/hydrate2.mjs +395 -43
- package/dist/hydrate2.mjs.map +1 -1
- package/dist/index.d.mts +49 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +4 -4
- package/dist/payload.mjs +5 -1
- package/dist/payload.mjs.map +1 -1
- package/dist/plugin.d.mts.map +1 -1
- package/dist/plugin2.mjs +712 -162
- package/dist/plugin2.mjs.map +1 -1
- package/package.json +1 -1
package/dist/hydrate2.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as errorResult, i as errorMessage, n as createCodePlay, o as JS_SANDBOX_FLAGS, u as selectStream } from "./client.mjs";
|
|
2
|
-
import { a as escapeHtml,
|
|
2
|
+
import { a as escapeHtml, h as resolveLanguage, i as escapeAttribute, t as decodePayload } from "./payload.mjs";
|
|
3
3
|
//#region src/hydrate-action.ts
|
|
4
4
|
function readPlayPayload(encoded) {
|
|
5
5
|
try {
|
|
@@ -18,62 +18,221 @@ async function runPlayAction(input) {
|
|
|
18
18
|
input.setBusy(false);
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
|
+
function idleRunActionState() {
|
|
22
|
+
return { phase: "idle" };
|
|
23
|
+
}
|
|
24
|
+
function runningRunActionState(action, startedAtMs = Date.now()) {
|
|
25
|
+
return {
|
|
26
|
+
phase: "running",
|
|
27
|
+
action,
|
|
28
|
+
startedAtMs
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function resultRunActionState(action, result, finishedAtMs = Date.now()) {
|
|
32
|
+
return {
|
|
33
|
+
phase: result.status === "offline" ? "offline" : result.status === "ok" || result.status === "cancelled" ? "result" : "error",
|
|
34
|
+
action,
|
|
35
|
+
result,
|
|
36
|
+
message: result.diagnostics[0]?.message,
|
|
37
|
+
finishedAtMs
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function errorRunActionState(action, error, finishedAtMs = Date.now()) {
|
|
41
|
+
return {
|
|
42
|
+
phase: "error",
|
|
43
|
+
action,
|
|
44
|
+
message: errorMessage(error),
|
|
45
|
+
finishedAtMs
|
|
46
|
+
};
|
|
47
|
+
}
|
|
21
48
|
//#endregion
|
|
22
49
|
//#region src/styles.ts
|
|
23
50
|
const CODE_PLAY_STYLES = `
|
|
24
51
|
.ox-code-play {
|
|
25
52
|
border: 1px solid var(--octc-color-border, color-mix(in srgb, currentColor 16%, transparent));
|
|
26
|
-
border-radius:
|
|
27
|
-
background: var(--octc-color-bg
|
|
53
|
+
border-radius: 6px;
|
|
54
|
+
background: var(--octc-color-bg, Canvas);
|
|
28
55
|
color: var(--octc-color-text, CanvasText);
|
|
29
56
|
overflow: hidden;
|
|
30
|
-
margin:
|
|
57
|
+
margin: 1rem 0;
|
|
31
58
|
}
|
|
32
59
|
.ox-code-play__toolbar {
|
|
33
60
|
display: flex;
|
|
34
61
|
flex-wrap: wrap;
|
|
35
|
-
gap: 0.
|
|
62
|
+
gap: 0.4rem;
|
|
36
63
|
align-items: center;
|
|
37
|
-
padding: 0.
|
|
64
|
+
padding: 0.45rem 0.6rem;
|
|
38
65
|
border-bottom: 1px solid var(--octc-color-border, color-mix(in srgb, currentColor 12%, transparent));
|
|
66
|
+
background: color-mix(in srgb, var(--octc-color-bg-alt, var(--octc-color-bg, Canvas)) 64%, transparent);
|
|
67
|
+
}
|
|
68
|
+
.ox-code-play__summary {
|
|
69
|
+
display: inline-flex;
|
|
70
|
+
flex: 1 1 12rem;
|
|
71
|
+
min-width: 9rem;
|
|
72
|
+
gap: 0.45rem;
|
|
73
|
+
align-items: baseline;
|
|
39
74
|
}
|
|
40
75
|
.ox-code-play__lang {
|
|
41
76
|
font: 600 0.8rem/1.2 ui-sans-serif, system-ui, sans-serif;
|
|
42
|
-
margin-right: auto;
|
|
43
77
|
color: var(--octc-color-text, CanvasText);
|
|
44
78
|
}
|
|
79
|
+
.ox-code-play__title {
|
|
80
|
+
min-width: 0;
|
|
81
|
+
overflow-wrap: anywhere;
|
|
82
|
+
font: 500 0.78rem/1.25 ui-sans-serif, system-ui, sans-serif;
|
|
83
|
+
opacity: 0.72;
|
|
84
|
+
}
|
|
85
|
+
.ox-code-play__status {
|
|
86
|
+
min-width: 4.6rem;
|
|
87
|
+
text-align: center;
|
|
88
|
+
border: 1px solid var(--octc-color-border, color-mix(in srgb, currentColor 16%, transparent));
|
|
89
|
+
border-radius: 999px;
|
|
90
|
+
padding: 0.12rem 0.45rem;
|
|
91
|
+
font: 650 0.68rem/1.25 ui-sans-serif, system-ui, sans-serif;
|
|
92
|
+
color: var(--octc-color-text, CanvasText);
|
|
93
|
+
background: var(--octc-color-bg, Canvas);
|
|
94
|
+
}
|
|
95
|
+
.ox-code-play[data-ox-run-state="running"] .ox-code-play__status {
|
|
96
|
+
color: var(--octc-color-primary, var(--octc-accent, #4f46e5));
|
|
97
|
+
}
|
|
98
|
+
.ox-code-play[data-ox-run-state="error"] .ox-code-play__status,
|
|
99
|
+
.ox-code-play[data-ox-run-state="offline"] .ox-code-play__status {
|
|
100
|
+
color: var(--octc-danger, #b42318);
|
|
101
|
+
}
|
|
45
102
|
.ox-code-play__toolbar button {
|
|
46
103
|
appearance: none;
|
|
47
104
|
border: 1px solid var(--octc-color-border, color-mix(in srgb, currentColor 20%, transparent));
|
|
48
105
|
background: color-mix(in srgb, var(--octc-color-text, CanvasText) 8%, transparent);
|
|
49
106
|
color: var(--octc-color-text, CanvasText);
|
|
50
|
-
border-radius:
|
|
51
|
-
|
|
107
|
+
border-radius: 6px;
|
|
108
|
+
min-height: 1.9rem;
|
|
109
|
+
padding: 0.18rem 0.62rem;
|
|
52
110
|
font: 600 0.75rem/1.4 ui-sans-serif, system-ui, sans-serif;
|
|
53
111
|
cursor: pointer;
|
|
54
112
|
}
|
|
55
113
|
.ox-code-play__toolbar button:disabled { opacity: 0.55; cursor: progress; }
|
|
114
|
+
.ox-code-play__toolbar button:focus-visible,
|
|
115
|
+
.ox-code-play__tabs button:focus-visible,
|
|
116
|
+
.ox-code-play__field input:focus-visible,
|
|
117
|
+
.ox-code-play__field select:focus-visible,
|
|
118
|
+
.ox-code-play__panel:focus-visible {
|
|
119
|
+
outline: 2px solid var(--octc-color-primary, var(--octc-accent, #4f46e5));
|
|
120
|
+
outline-offset: 2px;
|
|
121
|
+
}
|
|
122
|
+
.ox-code-play__runtime {
|
|
123
|
+
display: flex;
|
|
124
|
+
flex-wrap: wrap;
|
|
125
|
+
gap: 0.4rem 0.7rem;
|
|
126
|
+
align-items: center;
|
|
127
|
+
padding: 0.38rem 0.6rem;
|
|
128
|
+
border-bottom: 1px solid var(--octc-color-border, color-mix(in srgb, currentColor 10%, transparent));
|
|
129
|
+
background: color-mix(in srgb, var(--octc-color-bg-alt, var(--octc-color-bg, Canvas)) 56%, transparent);
|
|
130
|
+
}
|
|
131
|
+
.ox-code-play__runtime-chip {
|
|
132
|
+
display: inline-flex;
|
|
133
|
+
gap: 0.3rem;
|
|
134
|
+
align-items: baseline;
|
|
135
|
+
min-width: 0;
|
|
136
|
+
padding: 0;
|
|
137
|
+
border: 0;
|
|
138
|
+
background: transparent;
|
|
139
|
+
}
|
|
140
|
+
.ox-code-play__runtime-chip span {
|
|
141
|
+
font: 650 0.62rem/1.1 ui-sans-serif, system-ui, sans-serif;
|
|
142
|
+
text-transform: uppercase;
|
|
143
|
+
letter-spacing: 0.03em;
|
|
144
|
+
opacity: 0.62;
|
|
145
|
+
}
|
|
146
|
+
.ox-code-play__runtime-chip strong {
|
|
147
|
+
font: 650 0.72rem/1.2 ui-sans-serif, system-ui, sans-serif;
|
|
148
|
+
}
|
|
149
|
+
.ox-code-play__runtime-chip--ok strong { color: var(--octc-color-primary, var(--octc-accent, #4f46e5)); }
|
|
150
|
+
.ox-code-play__runtime-chip--warn strong { color: var(--octc-warning, #b54708); }
|
|
151
|
+
.ox-code-play__runtime-chip--muted strong { opacity: 0.72; }
|
|
152
|
+
.ox-code-play__project {
|
|
153
|
+
display: inline-flex;
|
|
154
|
+
flex: 1 1 18rem;
|
|
155
|
+
min-width: min(100%, 16rem);
|
|
156
|
+
gap: 0.45rem;
|
|
157
|
+
align-items: center;
|
|
158
|
+
flex-wrap: wrap;
|
|
159
|
+
margin-left: auto;
|
|
160
|
+
padding: 0.28rem 0.42rem;
|
|
161
|
+
border: 1px solid var(--octc-color-border, color-mix(in srgb, currentColor 14%, transparent));
|
|
162
|
+
border-radius: 6px;
|
|
163
|
+
background: var(--octc-color-bg, Canvas);
|
|
164
|
+
}
|
|
165
|
+
.ox-code-play__project-main,
|
|
166
|
+
.ox-code-play__project-entry {
|
|
167
|
+
display: inline-grid;
|
|
168
|
+
gap: 0.1rem;
|
|
169
|
+
min-width: 0;
|
|
170
|
+
}
|
|
171
|
+
.ox-code-play__project-main { flex: 1 1 8.5rem; }
|
|
172
|
+
.ox-code-play__project-entry { flex: 999 1 9rem; }
|
|
173
|
+
.ox-code-play__project-main span,
|
|
174
|
+
.ox-code-play__project-entry span {
|
|
175
|
+
font: 600 0.62rem/1.1 ui-sans-serif, system-ui, sans-serif;
|
|
176
|
+
text-transform: uppercase;
|
|
177
|
+
letter-spacing: 0.04em;
|
|
178
|
+
opacity: 0.62;
|
|
179
|
+
}
|
|
180
|
+
.ox-code-play__project-main strong,
|
|
181
|
+
.ox-code-play__project-entry strong {
|
|
182
|
+
min-width: 0;
|
|
183
|
+
overflow-wrap: anywhere;
|
|
184
|
+
font: 650 0.78rem/1.2 ui-sans-serif, system-ui, sans-serif;
|
|
185
|
+
}
|
|
186
|
+
.ox-code-play__project-files,
|
|
187
|
+
.ox-code-play__project-warning,
|
|
188
|
+
.ox-code-play__project-link {
|
|
189
|
+
flex: 0 0 auto;
|
|
190
|
+
border-radius: 6px;
|
|
191
|
+
padding: 0.18rem 0.45rem;
|
|
192
|
+
font: 650 0.68rem/1.25 ui-sans-serif, system-ui, sans-serif;
|
|
193
|
+
}
|
|
194
|
+
.ox-code-play__project-files {
|
|
195
|
+
background: color-mix(in srgb, var(--octc-color-text, CanvasText) 8%, transparent);
|
|
196
|
+
}
|
|
197
|
+
.ox-code-play__project-warning {
|
|
198
|
+
color: var(--octc-warning, #b54708);
|
|
199
|
+
background: color-mix(in srgb, var(--octc-warning, #b54708) 12%, transparent);
|
|
200
|
+
}
|
|
201
|
+
.ox-code-play__project-link {
|
|
202
|
+
color: var(--octc-color-primary, var(--octc-accent, #4f46e5));
|
|
203
|
+
background: color-mix(in srgb, var(--octc-color-primary, var(--octc-accent, #4f46e5)) 12%, transparent);
|
|
204
|
+
text-decoration: none;
|
|
205
|
+
}
|
|
206
|
+
.ox-code-play__project-link:focus-visible {
|
|
207
|
+
outline: 2px solid var(--octc-color-primary, var(--octc-accent, #4f46e5));
|
|
208
|
+
outline-offset: 2px;
|
|
209
|
+
}
|
|
56
210
|
.ox-code-play .ox-code { margin: 0; }
|
|
57
|
-
.ox-code-play__source pre {
|
|
211
|
+
.ox-code-play__source pre {
|
|
212
|
+
margin: 0;
|
|
213
|
+
border: 0;
|
|
214
|
+
border-radius: 0;
|
|
215
|
+
padding: 0.75rem 0.8rem;
|
|
216
|
+
}
|
|
58
217
|
.ox-code-play__tabs {
|
|
59
218
|
display: flex;
|
|
60
|
-
gap: 0.
|
|
61
|
-
padding: 0.
|
|
219
|
+
gap: 0.15rem;
|
|
220
|
+
padding: 0.35rem 0.55rem 0;
|
|
62
221
|
}
|
|
63
222
|
.ox-code-play__tabs button {
|
|
64
223
|
appearance: none;
|
|
65
224
|
border: 0;
|
|
66
225
|
background: transparent;
|
|
67
226
|
color: var(--octc-color-text, CanvasText);
|
|
68
|
-
padding: 0.
|
|
69
|
-
border-radius:
|
|
227
|
+
padding: 0.28rem 0.48rem;
|
|
228
|
+
border-radius: 5px 5px 0 0;
|
|
70
229
|
font: 600 0.75rem/1.2 ui-sans-serif, system-ui, sans-serif;
|
|
71
230
|
cursor: pointer;
|
|
72
231
|
}
|
|
73
232
|
.ox-code-play__tabs button[aria-selected="true"] {
|
|
74
233
|
background: color-mix(in srgb, var(--octc-color-text, CanvasText) 10%, transparent);
|
|
75
234
|
}
|
|
76
|
-
.ox-code-play__panel { padding: 0.
|
|
235
|
+
.ox-code-play__panel { padding: 0.55rem 0.65rem 0.7rem; color: var(--octc-color-text, CanvasText); }
|
|
77
236
|
.ox-code-play__panel pre {
|
|
78
237
|
background: transparent !important;
|
|
79
238
|
color: inherit !important;
|
|
@@ -84,7 +243,7 @@ const CODE_PLAY_STYLES = `
|
|
|
84
243
|
}
|
|
85
244
|
.ox-code-play__empty { margin: 0; opacity: 0.7; font-size: 0.85rem; }
|
|
86
245
|
.ox-code-play__stdio { font: 12px/1.45 ui-monospace, SFMono-Regular, monospace; }
|
|
87
|
-
.ox-code-play__stdio-line { display: grid; grid-template-columns:
|
|
246
|
+
.ox-code-play__stdio-line { display: grid; grid-template-columns: 5.4rem 1fr; gap: 0.55rem; white-space: pre-wrap; }
|
|
88
247
|
.ox-code-play__stdio-line--stderr { color: var(--octc-danger, #b42318); }
|
|
89
248
|
.ox-code-play__stdio-line--stdin { opacity: 0.75; }
|
|
90
249
|
.ox-code-play__stdio-meta { opacity: 0.6; }
|
|
@@ -93,7 +252,7 @@ const CODE_PLAY_STYLES = `
|
|
|
93
252
|
.ox-code-play__field input, .ox-code-play__field select {
|
|
94
253
|
font: inherit;
|
|
95
254
|
padding: 0.3rem 0.45rem;
|
|
96
|
-
border-radius:
|
|
255
|
+
border-radius: 6px;
|
|
97
256
|
border: 1px solid var(--octc-color-border, color-mix(in srgb, currentColor 18%, transparent));
|
|
98
257
|
background: var(--octc-color-bg, Canvas);
|
|
99
258
|
color: var(--octc-color-text, CanvasText);
|
|
@@ -115,6 +274,20 @@ const CODE_PLAY_STYLES = `
|
|
|
115
274
|
.ox-code-play__diag--warning { color: var(--octc-warning, #b54708); }
|
|
116
275
|
.ox-code-play--compact .ox-code-play__tabs { display: none; }
|
|
117
276
|
.ox-code-play--compact .ox-code-play__panel[data-panel]:not([data-panel="stdio"]):not([data-panel="stderr"]) { display: none; }
|
|
277
|
+
@media (max-width: 640px) {
|
|
278
|
+
.ox-code-play__toolbar {
|
|
279
|
+
align-items: flex-start;
|
|
280
|
+
}
|
|
281
|
+
.ox-code-play__runtime,
|
|
282
|
+
.ox-code-play__tabs,
|
|
283
|
+
.ox-code-play__panel {
|
|
284
|
+
padding-inline: 0.55rem;
|
|
285
|
+
}
|
|
286
|
+
.ox-code-play__stdio-line {
|
|
287
|
+
grid-template-columns: 1fr;
|
|
288
|
+
gap: 0.15rem;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
118
291
|
`;
|
|
119
292
|
//#endregion
|
|
120
293
|
//#region src/viewers.ts
|
|
@@ -188,42 +361,141 @@ function renderPlayUi(state) {
|
|
|
188
361
|
if (preset === "headless") return "";
|
|
189
362
|
const panel = state.panel ?? "stdio";
|
|
190
363
|
const canTypecheck = state.payload.capabilities.typecheck;
|
|
364
|
+
const runState = state.runState ?? (state.busy ? {
|
|
365
|
+
phase: "running",
|
|
366
|
+
action: "execute"
|
|
367
|
+
} : idleRunActionState());
|
|
368
|
+
const isBusy = Boolean(state.busy) || runState.phase === "running";
|
|
191
369
|
const tabs = renderTabs(state, panel);
|
|
192
370
|
const viewers = state.payload.viewers;
|
|
193
|
-
|
|
371
|
+
const label = widgetLabel(state.payload, definition);
|
|
372
|
+
return `<div class="ox-code-play ox-code-play--${preset}" data-ox-code-play-ui data-ox-run-state="${runState.phase}" role="region" aria-label="${escapeHtml(label)}" aria-busy="${isBusy ? "true" : "false"}">
|
|
194
373
|
<div class="ox-code-play__toolbar">
|
|
195
|
-
<span class="ox-code-play__lang">${escapeHtml(definition?.name ?? state.payload.language)}</span>
|
|
196
|
-
<
|
|
197
|
-
|
|
198
|
-
|
|
374
|
+
<span class="ox-code-play__summary"><span class="ox-code-play__lang">${escapeHtml(definition?.name ?? state.payload.language)}</span>${state.payload.title ? `<span class="ox-code-play__title">${escapeHtml(state.payload.title)}</span>` : ""}</span>
|
|
375
|
+
<span class="ox-code-play__status" data-ox-status role="status" aria-live="polite">${renderRunStatusText(runState)}</span>
|
|
376
|
+
<button type="button" data-ox-action="run" aria-label="${escapeHtml(`Run ${label}`)}"${actionButtonAttrs("run", Boolean(state.busy))}>Run</button>
|
|
377
|
+
${canTypecheck ? `<button type="button" data-ox-action="typecheck" aria-label="${escapeHtml(`Typecheck ${label}`)}"${actionButtonAttrs("typecheck", Boolean(state.busy))}>Typecheck</button>` : ""}
|
|
378
|
+
<button type="button" data-ox-action="cancel" aria-label="${escapeHtml(`Cancel ${label}`)}"${actionButtonAttrs("cancel", Boolean(state.busy))}>Cancel</button>
|
|
199
379
|
</div>
|
|
380
|
+
${renderRuntimeStrip(state.payload, definition)}
|
|
200
381
|
<div class="ox-code-play__source"></div>
|
|
201
382
|
${tabs}
|
|
202
|
-
${viewers.stdio ?
|
|
203
|
-
${viewers.stderr ?
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
383
|
+
${viewers.stdio ? renderPanel("stdio", "Stdio", panel, preset, `${renderDiagnosticsHtml(state.result)}${renderStdioHtml(state.result?.stdio ?? [])}`) : ""}
|
|
384
|
+
${viewers.stderr ? renderPanel("stderr", "Stderr", panel, preset, renderStderrHtml(state.result)) : ""}
|
|
385
|
+
${viewers.config ? renderPanel("config", "Config", panel, preset, renderConfigHtml(definition?.configSchema ?? [], state.payload.config)) : ""}
|
|
386
|
+
${viewers.provenance ? renderPanel("provenance", "Provenance", panel, preset, renderProvenanceHtml(state.result?.provenance)) : ""}
|
|
387
|
+
${viewers.timing ? renderPanel("timing", "Timing", panel, preset, renderTimingHtml(state.result?.timing)) : ""}
|
|
207
388
|
</div>`;
|
|
208
389
|
}
|
|
390
|
+
function renderRunStatusText(state) {
|
|
391
|
+
if (state.phase === "running") return state.action === "typecheck" ? "Typechecking" : "Running";
|
|
392
|
+
if (state.phase === "offline") return "Offline";
|
|
393
|
+
if (state.phase === "error") {
|
|
394
|
+
if (state.result?.status === "timeout") return "Timed out";
|
|
395
|
+
if (state.result?.status === "unsupported") return "Unsupported";
|
|
396
|
+
return "Error";
|
|
397
|
+
}
|
|
398
|
+
if (state.phase === "result") {
|
|
399
|
+
if (state.result?.status === "cancelled") return "Cancelled";
|
|
400
|
+
return "Done";
|
|
401
|
+
}
|
|
402
|
+
return "Ready";
|
|
403
|
+
}
|
|
404
|
+
function renderRuntimeStrip(payload, definition) {
|
|
405
|
+
const runtime = runtimeLabel(payload, definition);
|
|
406
|
+
const executor = executorLabel(payload, definition);
|
|
407
|
+
const checks = payload.capabilities.typecheck ? "Typecheck ready" : "Run only";
|
|
408
|
+
return `<div class="ox-code-play__runtime" aria-label="Code Play runtime">${[
|
|
409
|
+
runtimeChip("Runtime", runtime.label, runtime.kind),
|
|
410
|
+
runtimeChip("Executor", executor.label, executor.kind),
|
|
411
|
+
runtimeChip("Checks", checks, payload.capabilities.typecheck ? "ok" : "muted")
|
|
412
|
+
].join("")}${renderProjectSandboxHtml(payload.project)}</div>`;
|
|
413
|
+
}
|
|
414
|
+
function runtimeLabel(payload, definition) {
|
|
415
|
+
switch (definition?.backend) {
|
|
416
|
+
case "javascript": return {
|
|
417
|
+
label: "Browser sandbox",
|
|
418
|
+
kind: "ok"
|
|
419
|
+
};
|
|
420
|
+
case "typescript": return {
|
|
421
|
+
label: "TypeScript sandbox",
|
|
422
|
+
kind: "ok"
|
|
423
|
+
};
|
|
424
|
+
case "framework": return {
|
|
425
|
+
label: `${definition.name} iframe preview`,
|
|
426
|
+
kind: "ok"
|
|
427
|
+
};
|
|
428
|
+
case "rust-playground": return {
|
|
429
|
+
label: "Rust Playground",
|
|
430
|
+
kind: payload.endpoints?.rust ? "ok" : "warn"
|
|
431
|
+
};
|
|
432
|
+
case "go-playground": return {
|
|
433
|
+
label: "Go Playground",
|
|
434
|
+
kind: payload.endpoints?.go ? "ok" : "warn"
|
|
435
|
+
};
|
|
436
|
+
case "remote": return payload.endpoint ? {
|
|
437
|
+
label: "Piston-compatible",
|
|
438
|
+
kind: "ok"
|
|
439
|
+
} : {
|
|
440
|
+
label: "Endpoint missing",
|
|
441
|
+
kind: "warn"
|
|
442
|
+
};
|
|
443
|
+
default: return {
|
|
444
|
+
label: definition?.name ?? payload.language,
|
|
445
|
+
kind: "muted"
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
function executorLabel(payload, definition) {
|
|
450
|
+
if (!payload.capabilities.execute) return {
|
|
451
|
+
label: "Disabled",
|
|
452
|
+
kind: "warn"
|
|
453
|
+
};
|
|
454
|
+
if (definition?.backend === "remote" && !payload.endpoint) return {
|
|
455
|
+
label: "Configure endpoint",
|
|
456
|
+
kind: "warn"
|
|
457
|
+
};
|
|
458
|
+
return {
|
|
459
|
+
label: "On demand",
|
|
460
|
+
kind: "ok"
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
function runtimeChip(label, value, kind) {
|
|
464
|
+
return `<span class="ox-code-play__runtime-chip ox-code-play__runtime-chip--${kind}"><span>${escapeHtml(label)}</span><strong>${escapeHtml(value)}</strong></span>`;
|
|
465
|
+
}
|
|
466
|
+
function renderProjectSandboxHtml(project) {
|
|
467
|
+
if (!project) return "";
|
|
468
|
+
const fileCount = `${project.files.length} ${project.files.length === 1 ? "file" : "files"}`;
|
|
469
|
+
const target = project.target === "browser" ? "Browser project" : project.target === "node" ? "Node-like project" : "External project";
|
|
470
|
+
const url = project.openUrl ?? project.fallbackUrl;
|
|
471
|
+
const warnings = project.warnings?.length ? `<span class="ox-code-play__project-warning" title="${escapeAttribute(project.warnings.join("\n"))}">Warnings</span>` : "";
|
|
472
|
+
const link = url ? `<a class="ox-code-play__project-link" href="${escapeAttribute(url)}" target="_blank" rel="noopener noreferrer">Open</a>` : "";
|
|
473
|
+
return `<span class="ox-code-play__project" data-ox-project-provider="${escapeAttribute(project.provider)}">
|
|
474
|
+
<span class="ox-code-play__project-main"><span>${escapeHtml(project.label)}</span><strong>${escapeHtml(target)}</strong></span>
|
|
475
|
+
${project.entry ? `<span class="ox-code-play__project-entry"><span>Entry</span><strong>${escapeHtml(project.entry)}</strong></span>` : ""}
|
|
476
|
+
<span class="ox-code-play__project-files">${escapeHtml(fileCount)}</span>
|
|
477
|
+
${warnings}${link}
|
|
478
|
+
</span>`;
|
|
479
|
+
}
|
|
209
480
|
function renderTabs(state, panel) {
|
|
210
481
|
if (state.payload.ui === "compact") return "";
|
|
211
482
|
const viewers = state.payload.viewers;
|
|
212
483
|
const buttons = [
|
|
213
|
-
viewers.stdio ? tab("stdio", "
|
|
214
|
-
viewers.stderr ? tab("stderr", "
|
|
215
|
-
viewers.config ? tab("config", "
|
|
216
|
-
viewers.provenance ? tab("provenance", "
|
|
217
|
-
viewers.timing ? tab("timing", "
|
|
484
|
+
viewers.stdio ? tab("stdio", "Stdio", panel) : "",
|
|
485
|
+
viewers.stderr ? tab("stderr", "Stderr", panel) : "",
|
|
486
|
+
viewers.config ? tab("config", "Config", panel) : "",
|
|
487
|
+
viewers.provenance ? tab("provenance", "Provenance", panel) : "",
|
|
488
|
+
viewers.timing ? tab("timing", "Timing", panel) : ""
|
|
218
489
|
].filter(Boolean).join("");
|
|
219
490
|
return buttons ? `<div class="ox-code-play__tabs" role="tablist">${buttons}</div>` : "";
|
|
220
491
|
}
|
|
221
492
|
function tab(id, label, selected) {
|
|
222
|
-
|
|
493
|
+
const isSelected = selected === id;
|
|
494
|
+
return `<button type="button" role="tab" data-ox-panel="${id}" aria-selected="${isSelected ? "true" : "false"}" tabindex="${isSelected ? "0" : "-1"}">${label}</button>`;
|
|
223
495
|
}
|
|
224
496
|
function actionButtonAttrs(action, busy) {
|
|
225
497
|
const state = actionBusyState(action, busy);
|
|
226
|
-
return `${state.disabled ? " disabled" : ""}${state.hidden ? " hidden" : ""}`;
|
|
498
|
+
return `${state.disabled ? " disabled aria-disabled=\"true\"" : ""}${state.hidden ? " hidden" : ""}`;
|
|
227
499
|
}
|
|
228
500
|
function actionBusyState(action, busy) {
|
|
229
501
|
if (action === "cancel") return {
|
|
@@ -240,15 +512,30 @@ function applyActionBusy(root, busy) {
|
|
|
240
512
|
const state = actionBusyState(button.dataset.oxAction ?? "", busy);
|
|
241
513
|
button.disabled = state.disabled;
|
|
242
514
|
button.hidden = state.hidden;
|
|
515
|
+
button.setAttribute("aria-disabled", state.disabled ? "true" : "false");
|
|
243
516
|
}
|
|
517
|
+
for (const widget of queryPlayWidgets(root)) widget.setAttribute("aria-busy", busy ? "true" : "false");
|
|
518
|
+
}
|
|
519
|
+
function renderPanel(id, label, current, preset, html) {
|
|
520
|
+
return `<div class="ox-code-play__panel" role="tabpanel" tabindex="0" aria-label="${escapeHtml(label)}" data-panel="${id}"${hidden(current, id, preset)}>${html}</div>`;
|
|
244
521
|
}
|
|
245
522
|
function hidden(current, id, preset) {
|
|
246
523
|
if (preset === "compact" && (id === "stdio" || id === "stderr")) return "";
|
|
247
524
|
return current === id ? "" : " hidden";
|
|
248
525
|
}
|
|
526
|
+
function widgetLabel(payload, definition) {
|
|
527
|
+
const language = definition?.name ?? payload.language;
|
|
528
|
+
return payload.title ? `${payload.title} (${language})` : `${language} Code Play`;
|
|
529
|
+
}
|
|
530
|
+
function queryPlayWidgets(root) {
|
|
531
|
+
const widgets = [...root.querySelectorAll(".ox-code-play")];
|
|
532
|
+
if (typeof HTMLElement !== "undefined" && root instanceof HTMLElement && root.matches(".ox-code-play")) widgets.unshift(root);
|
|
533
|
+
return widgets;
|
|
534
|
+
}
|
|
249
535
|
//#endregion
|
|
250
536
|
//#region src/hydrate.ts
|
|
251
537
|
const STYLE_ID = "ox-code-play-styles";
|
|
538
|
+
let widgetId = 0;
|
|
252
539
|
function hydrateCodePlay(root = defaultRoot(), options = {}) {
|
|
253
540
|
ensureStyles();
|
|
254
541
|
const client = options.client ?? createCodePlayFromPayloads(root);
|
|
@@ -261,7 +548,7 @@ function mountCodePlay(element, options = {}) {
|
|
|
261
548
|
const payload = readPlayPayload(element.getAttribute("data-ox-code-play") ?? "");
|
|
262
549
|
if (!payload || payload.ui === "headless") return;
|
|
263
550
|
const client = options.client ?? createCodePlay({
|
|
264
|
-
languages: { [payload.language]:
|
|
551
|
+
languages: { [payload.language]: languageEnableFromPayload(payload) },
|
|
265
552
|
endpoints: payload.endpoints
|
|
266
553
|
});
|
|
267
554
|
const source = element.innerHTML;
|
|
@@ -273,14 +560,17 @@ function mountCodePlay(element, options = {}) {
|
|
|
273
560
|
if (sourceSlot) sourceSlot.innerHTML = source;
|
|
274
561
|
element.replaceChildren(widget);
|
|
275
562
|
element.dataset.oxCodePlayMounted = "true";
|
|
563
|
+
element.removeAttribute("inert");
|
|
276
564
|
bindWidget(element, payload, client);
|
|
565
|
+
prepareA11y(element);
|
|
277
566
|
}
|
|
278
567
|
function bindWidget(element, payload, client) {
|
|
279
568
|
let current = payload;
|
|
280
569
|
const session = client.createSession({
|
|
281
570
|
language: payload.language,
|
|
282
571
|
code: payload.code,
|
|
283
|
-
config: payload.config
|
|
572
|
+
config: payload.config,
|
|
573
|
+
project: payload.project
|
|
284
574
|
});
|
|
285
575
|
const runButton = element.querySelector("[data-ox-action=\"run\"]");
|
|
286
576
|
const checkButton = element.querySelector("[data-ox-action=\"typecheck\"]");
|
|
@@ -288,6 +578,9 @@ function bindWidget(element, payload, client) {
|
|
|
288
578
|
runButton?.addEventListener("click", () => void run("execute"));
|
|
289
579
|
checkButton?.addEventListener("click", () => void run("typecheck"));
|
|
290
580
|
cancelButton?.addEventListener("click", () => session.cancel());
|
|
581
|
+
element.addEventListener("keydown", (event) => {
|
|
582
|
+
if (event.target instanceof HTMLElement && event.target.matches("[role=\"tab\"]")) handleTabKeydown(element, event);
|
|
583
|
+
});
|
|
291
584
|
element.addEventListener("click", (event) => {
|
|
292
585
|
const target = event.target;
|
|
293
586
|
if (!(target instanceof HTMLElement)) return;
|
|
@@ -306,13 +599,20 @@ function bindWidget(element, payload, client) {
|
|
|
306
599
|
async function run(action) {
|
|
307
600
|
await runPlayAction({
|
|
308
601
|
action: () => action === "typecheck" ? session.typecheck() : session.run(),
|
|
309
|
-
setBusy: (busy) =>
|
|
310
|
-
|
|
311
|
-
|
|
602
|
+
setBusy: (busy) => {
|
|
603
|
+
applyActionBusy(element, busy);
|
|
604
|
+
if (busy) paintRunState(element, runningRunActionState(action));
|
|
605
|
+
},
|
|
606
|
+
onResult: (result) => paintResult(element, current, result, action),
|
|
607
|
+
onError: (error) => {
|
|
608
|
+
paintRunState(element, errorRunActionState(action, error));
|
|
609
|
+
paintResult(element, current, errorResult(errorMessage(error)), action);
|
|
610
|
+
}
|
|
312
611
|
});
|
|
313
612
|
}
|
|
314
613
|
}
|
|
315
|
-
function paintResult(element, _payload, result) {
|
|
614
|
+
function paintResult(element, _payload, result, action) {
|
|
615
|
+
paintRunState(element, resultRunActionState(action, result));
|
|
316
616
|
const stdio = element.querySelector("[data-panel=\"stdio\"]");
|
|
317
617
|
if (stdio) {
|
|
318
618
|
stdio.innerHTML = `${renderDiagnosticsHtml(result)}${renderStdioHtml(result.stdio)}`;
|
|
@@ -335,6 +635,13 @@ function paintResult(element, _payload, result) {
|
|
|
335
635
|
if (stderr) stderr.innerHTML = renderStderrHtml(result);
|
|
336
636
|
showPanel(element, resultPanelToShow(result, Boolean(stderr)));
|
|
337
637
|
}
|
|
638
|
+
function paintRunState(element, state) {
|
|
639
|
+
const widget = element.querySelector(".ox-code-play");
|
|
640
|
+
widget?.setAttribute("data-ox-run-state", state.phase);
|
|
641
|
+
widget?.setAttribute("aria-busy", state.phase === "running" ? "true" : "false");
|
|
642
|
+
const status = element.querySelector("[data-ox-status]");
|
|
643
|
+
if (status) status.textContent = renderRunStatusText(state);
|
|
644
|
+
}
|
|
338
645
|
function resultPanelToShow(result, hasStderrPanel) {
|
|
339
646
|
if (!hasStderrPanel) return "stdio";
|
|
340
647
|
if (result.diagnostics.some((diagnostic) => diagnostic.severity === "error") || result.status !== "ok" && Boolean(result.stderr)) return "stderr";
|
|
@@ -342,7 +649,11 @@ function resultPanelToShow(result, hasStderrPanel) {
|
|
|
342
649
|
}
|
|
343
650
|
function showPanel(element, panel) {
|
|
344
651
|
const compact = Boolean(element.querySelector(".ox-code-play--compact"));
|
|
345
|
-
for (const tab of element.querySelectorAll("[data-ox-panel]"))
|
|
652
|
+
for (const tab of element.querySelectorAll("[data-ox-panel]")) {
|
|
653
|
+
const selected = tab.getAttribute("data-ox-panel") === panel;
|
|
654
|
+
tab.setAttribute("aria-selected", selected ? "true" : "false");
|
|
655
|
+
tab.tabIndex = selected ? 0 : -1;
|
|
656
|
+
}
|
|
346
657
|
for (const node of element.querySelectorAll(".ox-code-play__panel")) {
|
|
347
658
|
const id = node.dataset.panel;
|
|
348
659
|
if (compact && (id === "stdio" || id === "stderr")) {
|
|
@@ -352,6 +663,38 @@ function showPanel(element, panel) {
|
|
|
352
663
|
node.hidden = id !== panel;
|
|
353
664
|
}
|
|
354
665
|
}
|
|
666
|
+
function handleTabKeydown(element, event) {
|
|
667
|
+
if (![
|
|
668
|
+
"ArrowLeft",
|
|
669
|
+
"ArrowRight",
|
|
670
|
+
"Home",
|
|
671
|
+
"End"
|
|
672
|
+
].includes(event.key)) return;
|
|
673
|
+
const tabs = [...element.querySelectorAll("[data-ox-panel]")];
|
|
674
|
+
const current = tabs.indexOf(event.target);
|
|
675
|
+
if (current === -1) return;
|
|
676
|
+
event.preventDefault();
|
|
677
|
+
const next = tabs[event.key === "Home" ? 0 : event.key === "End" ? tabs.length - 1 : event.key === "ArrowRight" ? (current + 1) % tabs.length : (current - 1 + tabs.length) % tabs.length];
|
|
678
|
+
const panel = next?.dataset.oxPanel;
|
|
679
|
+
if (!next || !panel) return;
|
|
680
|
+
showPanel(element, panel);
|
|
681
|
+
next.focus();
|
|
682
|
+
}
|
|
683
|
+
function prepareA11y(element) {
|
|
684
|
+
const widget = element.querySelector(".ox-code-play");
|
|
685
|
+
if (!widget) return;
|
|
686
|
+
if (!widget.id) widget.id = `ox-code-play-${++widgetId}`;
|
|
687
|
+
for (const tab of element.querySelectorAll("[data-ox-panel]")) {
|
|
688
|
+
const panelName = tab.dataset.oxPanel;
|
|
689
|
+
const panel = panelName ? element.querySelector(`[data-panel="${panelName}"]`) : null;
|
|
690
|
+
if (!panelName || !panel) continue;
|
|
691
|
+
tab.id ||= `${widget.id}-${panelName}-tab`;
|
|
692
|
+
panel.id ||= `${widget.id}-${panelName}-panel`;
|
|
693
|
+
tab.setAttribute("aria-controls", panel.id);
|
|
694
|
+
panel.setAttribute("aria-labelledby", tab.id);
|
|
695
|
+
panel.removeAttribute("aria-label");
|
|
696
|
+
}
|
|
697
|
+
}
|
|
355
698
|
function readForm(form) {
|
|
356
699
|
const data = new FormData(form);
|
|
357
700
|
const config = {};
|
|
@@ -364,7 +707,7 @@ function createCodePlayFromPayloads(root) {
|
|
|
364
707
|
let endpoints;
|
|
365
708
|
for (const element of queryWidgets(root)) try {
|
|
366
709
|
const payload = decodePayload(element.getAttribute("data-ox-code-play") ?? "");
|
|
367
|
-
languages[payload.language] =
|
|
710
|
+
languages[payload.language] = languageEnableFromPayload(payload);
|
|
368
711
|
endpoints = payload.endpoints ?? endpoints;
|
|
369
712
|
} catch {}
|
|
370
713
|
return createCodePlay({
|
|
@@ -372,6 +715,15 @@ function createCodePlayFromPayloads(root) {
|
|
|
372
715
|
endpoints
|
|
373
716
|
});
|
|
374
717
|
}
|
|
718
|
+
function languageEnableFromPayload(payload) {
|
|
719
|
+
const enable = {
|
|
720
|
+
execute: payload.capabilities.execute,
|
|
721
|
+
typecheck: payload.capabilities.typecheck,
|
|
722
|
+
config: payload.config
|
|
723
|
+
};
|
|
724
|
+
if (payload.endpoint) enable.endpoint = payload.endpoint;
|
|
725
|
+
return enable;
|
|
726
|
+
}
|
|
375
727
|
function queryWidgets(root) {
|
|
376
728
|
return [...root.querySelectorAll("[data-ox-code-play]")];
|
|
377
729
|
}
|
|
@@ -387,6 +739,6 @@ function defaultRoot() {
|
|
|
387
739
|
return document;
|
|
388
740
|
}
|
|
389
741
|
//#endregion
|
|
390
|
-
export {
|
|
742
|
+
export { resultRunActionState as _, renderProjectSandboxHtml as a, renderDiagnosticsHtml as c, renderStdioHtml as d, renderTimingHtml as f, readPlayPayload as g, idleRunActionState as h, renderPlayUi as i, renderProvenanceHtml as l, errorRunActionState as m, mountCodePlay as n, renderRunStatusText as o, CODE_PLAY_STYLES as p, resultPanelToShow as r, renderConfigHtml as s, hydrateCodePlay as t, renderStderrHtml as u, runPlayAction as v, runningRunActionState as y };
|
|
391
743
|
|
|
392
744
|
//# sourceMappingURL=hydrate2.mjs.map
|