@openpresentation/opf-editor 0.24.1 → 0.24.3
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 +64 -1
- package/dist/json-editor.d.ts +2 -0
- package/dist/json-editor.js +34 -5
- package/dist/json-options.d.ts +21 -0
- package/dist/json-options.js +127 -27
- package/dist/presenter.d.ts +102 -0
- package/dist/presenter.js +429 -0
- package/dist/read-deck-file.d.ts +59 -0
- package/dist/read-deck-file.js +142 -0
- package/dist/source-findings.js +27 -0
- package/dist/source-pane.d.ts +2 -0
- package/dist/source-pane.js +28 -23
- package/dist/styles.css +202 -1
- package/package.json +12 -2
package/dist/source-pane.d.ts
CHANGED
|
@@ -59,6 +59,8 @@ export interface SourcePaneOptions {
|
|
|
59
59
|
/** Accessible name of the code editor (default `OPF source`). */
|
|
60
60
|
label?: string;
|
|
61
61
|
catalogs?: JsonCatalogContext;
|
|
62
|
+
/** Live completions while typing JSON: property names and values (enums, booleans, catalog references) at the cursor's JSON path, from the same data as the field menu. YAML and Markdown keep the menu only. Default true. */
|
|
63
|
+
completions?: boolean;
|
|
62
64
|
onError?(error: unknown): void;
|
|
63
65
|
}
|
|
64
66
|
|
package/dist/source-pane.js
CHANGED
|
@@ -4,6 +4,7 @@ import { fromMarkdown, toMarkdown } from "@openpresentation/opf/markdown";
|
|
|
4
4
|
import { mountJsonCodeEditor } from "./json-editor.js";
|
|
5
5
|
import { createSourceMemory, findDuplicateKey, updateJsonSource } from "./exact-source.js";
|
|
6
6
|
import { lineForPath, lineOfOffset, offsetOfLine } from "./source-lines.js";
|
|
7
|
+
import { errorText, normalizeFinding, rejectionFindings as findingsOfError } from "./source-findings.js";
|
|
7
8
|
|
|
8
9
|
// The source pane (RR-98): the OPF document as JSON, YAML or Markdown, with the file name, the format menu, Format, Copy
|
|
9
10
|
// and Download, and the findings under the code. JSON is canonical and keeps its authored bytes (exact-source); YAML and
|
|
@@ -65,20 +66,6 @@ function same(a, b) {
|
|
|
65
66
|
}
|
|
66
67
|
const SEVERITY = { error: 0, warning: 1, info: 2 };
|
|
67
68
|
const plural = (count, word) => `${count} ${word}${count === 1 ? "" : "s"}`;
|
|
68
|
-
const errorText = (error) => error?.issues?.[0]?.message ?? error?.message ?? String(error);
|
|
69
|
-
|
|
70
|
-
/** Normalize one finding: core `Finding` objects, `{ path, message, severity, line? }` objects and plain strings. */
|
|
71
|
-
function normalizeFinding(input, kind) {
|
|
72
|
-
const finding = typeof input === "string" ? { message: input } : input ?? {};
|
|
73
|
-
const severity = finding.severity === "error" || finding.severity === "info" ? finding.severity : finding.severity === "warning" || finding.severity === "warn" ? "warning" : "error";
|
|
74
|
-
const out = { path: String(finding.path ?? ""), message: String(finding.message ?? ""), severity };
|
|
75
|
-
const line = finding.line ?? finding.location?.line;
|
|
76
|
-
if (Number.isInteger(line) && line > 0) out.line = line;
|
|
77
|
-
const own = finding.kind ?? kind;
|
|
78
|
-
if (own) out.kind = own;
|
|
79
|
-
if (finding.ruleId) out.ruleId = finding.ruleId;
|
|
80
|
-
return out;
|
|
81
|
-
}
|
|
82
69
|
|
|
83
70
|
const JSON_ERRORS = { InvalidSymbol: "Invalid symbol", InvalidNumberFormat: "Invalid number", PropertyNameExpected: "Property name expected", ValueExpected: "Value expected", ColonExpected: "Colon expected", CommaExpected: "Comma expected", CloseBraceExpected: "Closing brace expected", CloseBracketExpected: "Closing bracket expected", EndOfFileExpected: "End of file expected", InvalidCommentToken: "Comments are not allowed in JSON", UnexpectedEndOfComment: "Unexpected end of comment", UnexpectedEndOfString: "Unexpected end of string", UnexpectedEndOfNumber: "Unexpected end of number", InvalidUnicode: "Invalid unicode escape", InvalidEscapeCharacter: "Invalid escape character", InvalidCharacter: "Invalid character" };
|
|
84
71
|
|
|
@@ -137,6 +124,8 @@ export function createSourcePane(container, options = {}) {
|
|
|
137
124
|
let collapsed = false;
|
|
138
125
|
let copyTimer = null;
|
|
139
126
|
let renderedKey = "";
|
|
127
|
+
// Whether the findings include an error, and what the editor's `aria-invalid` currently says (null: not yet set).
|
|
128
|
+
let invalid = false, shownInvalid = null;
|
|
140
129
|
const lineCache = { key: "", values: new Map() };
|
|
141
130
|
|
|
142
131
|
// ---- DOM ----------------------------------------------------------------------------------------------------------
|
|
@@ -232,6 +221,7 @@ export function createSourcePane(container, options = {}) {
|
|
|
232
221
|
lineNumbers: true,
|
|
233
222
|
language: formatOf(format).language,
|
|
234
223
|
readOnly,
|
|
224
|
+
completions: options.completions !== false,
|
|
235
225
|
catalogs: options.catalogs ?? editor.catalogs,
|
|
236
226
|
describedBy: `${id}-findings`,
|
|
237
227
|
onChange: () => schedule(),
|
|
@@ -275,7 +265,8 @@ export function createSourcePane(container, options = {}) {
|
|
|
275
265
|
editor.applyPatch([{ op: "replace", path: "", value: read.deck }], { source: "source-pane", format });
|
|
276
266
|
} catch (error) {
|
|
277
267
|
dirty = true;
|
|
278
|
-
|
|
268
|
+
// Every issue of the refusal is its own finding, with its path; a format's own findings stand in when the error names none.
|
|
269
|
+
rejectionFindings = error?.issues?.length || !read.findings.length ? findingsOfError(error) : read.findings.map((finding) => ({ ...finding, kind: "rejected" }));
|
|
279
270
|
applying = false;
|
|
280
271
|
renderFindings();
|
|
281
272
|
return;
|
|
@@ -292,13 +283,16 @@ export function createSourcePane(container, options = {}) {
|
|
|
292
283
|
function refreshNotes() {
|
|
293
284
|
try { noteFindings = markdownNotes(toMarkdown(deck()).report); } catch { noteFindings = []; }
|
|
294
285
|
}
|
|
286
|
+
/** `aria-invalid` follows the findings: set while any finding is an error (syntax, a refused draft, the session's or the host's), cleared with them. */
|
|
295
287
|
function syncAttributes() {
|
|
296
|
-
|
|
288
|
+
shownInvalid = invalid;
|
|
289
|
+
control.update(control.api.getValue(), invalid, null, `${id}-findings`);
|
|
297
290
|
}
|
|
298
291
|
|
|
299
292
|
/** Show `value` as the text of the current format, as an external change. */
|
|
300
293
|
function show(value) {
|
|
301
294
|
baseline = value;
|
|
295
|
+
shownInvalid = false;
|
|
302
296
|
control.update(value, false, null, `${id}-findings`);
|
|
303
297
|
}
|
|
304
298
|
function fromSession(notice) {
|
|
@@ -332,7 +326,7 @@ export function createSourcePane(container, options = {}) {
|
|
|
332
326
|
|
|
333
327
|
const unsubscribe = editor.subscribe((event) => {
|
|
334
328
|
if (destroyed) return;
|
|
335
|
-
if (event.type === "catalogs") { renderFindings(); return; }
|
|
329
|
+
if (event.type === "catalogs") { control.setCatalogs(options.catalogs ?? editor.catalogs); renderFindings(); return; }
|
|
336
330
|
if (applying) return;
|
|
337
331
|
version++;
|
|
338
332
|
fromSession();
|
|
@@ -539,13 +533,19 @@ export function createSourcePane(container, options = {}) {
|
|
|
539
533
|
catch (error) { options.onError?.(error); host = []; }
|
|
540
534
|
} else if (hostFindings) host = hostFindings.map((finding) => normalizeFinding(finding));
|
|
541
535
|
else host = sessionFindings();
|
|
536
|
+
// A finding repeated by an earlier group is dropped; repeats inside one group stay, so a refusal lists every issue the validator found.
|
|
542
537
|
const seen = new Set();
|
|
543
|
-
const all = [
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
538
|
+
const all = [];
|
|
539
|
+
for (const group of [syntaxFindings, rejectionFindings, transientNotes, noteFindings, host]) {
|
|
540
|
+
const keys = [];
|
|
541
|
+
for (const finding of group) {
|
|
542
|
+
const key = `${finding.severity}|${finding.path}|${finding.message}`;
|
|
543
|
+
if (seen.has(key)) continue;
|
|
544
|
+
keys.push(key);
|
|
545
|
+
all.push(finding);
|
|
546
|
+
}
|
|
547
|
+
for (const key of keys) seen.add(key);
|
|
548
|
+
}
|
|
549
549
|
return all.map((finding, index) => ({ finding, index })).sort((a, b) => SEVERITY[a.finding.severity] - SEVERITY[b.finding.severity] || a.index - b.index).map((entry) => entry.finding);
|
|
550
550
|
}
|
|
551
551
|
function lineOf(finding) {
|
|
@@ -558,9 +558,14 @@ export function createSourcePane(container, options = {}) {
|
|
|
558
558
|
return lineCache.values.get(cacheKey) ?? explicit ?? null;
|
|
559
559
|
}
|
|
560
560
|
function renderFindings() {
|
|
561
|
+
paintFindings();
|
|
562
|
+
if (!destroyed && invalid !== shownInvalid) syncAttributes();
|
|
563
|
+
}
|
|
564
|
+
function paintFindings() {
|
|
561
565
|
if (destroyed) return;
|
|
562
566
|
const all = collect();
|
|
563
567
|
const rows = all.map((finding) => ({ finding, line: lineOf(finding) }));
|
|
568
|
+
invalid = rows.some((row) => row.finding.severity === "error");
|
|
564
569
|
const key = JSON.stringify([format, collapsed, rows.map(({ finding, line }) => [finding.severity, finding.path, finding.message, finding.kind, line])]);
|
|
565
570
|
if (key === renderedKey) return;
|
|
566
571
|
renderedKey = key;
|
package/dist/styles.css
CHANGED
|
@@ -2807,6 +2807,49 @@
|
|
|
2807
2807
|
box-shadow: var(--opf-ui-shadow-pop);
|
|
2808
2808
|
}
|
|
2809
2809
|
|
|
2810
|
+
:root :is(.opf-ui, .opf-json, .opf-code) .cm-tooltip.cm-tooltip-autocomplete > ul {
|
|
2811
|
+
font-family: var(--opf-ui-mono);
|
|
2812
|
+
font-size: 12px;
|
|
2813
|
+
}
|
|
2814
|
+
|
|
2815
|
+
:root :is(.opf-ui, .opf-json, .opf-code) .cm-tooltip.cm-tooltip-autocomplete > ul > li {
|
|
2816
|
+
padding: 2px 8px;
|
|
2817
|
+
color: var(--opf-ui-fg);
|
|
2818
|
+
}
|
|
2819
|
+
|
|
2820
|
+
:root :is(.opf-ui, .opf-json, .opf-code) .cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected] {
|
|
2821
|
+
color: var(--opf-ui-accent-fg);
|
|
2822
|
+
background: var(--opf-ui-accent);
|
|
2823
|
+
}
|
|
2824
|
+
|
|
2825
|
+
:root :is(.opf-ui, .opf-json, .opf-code) .cm-tooltip-autocomplete .cm-completionDetail {
|
|
2826
|
+
margin-left: 12px;
|
|
2827
|
+
font-family: var(--opf-ui-font);
|
|
2828
|
+
font-style: normal;
|
|
2829
|
+
color: var(--opf-ui-muted-fg);
|
|
2830
|
+
}
|
|
2831
|
+
|
|
2832
|
+
:root :is(.opf-ui, .opf-json, .opf-code) .cm-tooltip-autocomplete > ul > li[aria-selected] .cm-completionDetail {
|
|
2833
|
+
color: inherit;
|
|
2834
|
+
opacity: 0.85;
|
|
2835
|
+
}
|
|
2836
|
+
|
|
2837
|
+
:root :is(.opf-ui, .opf-json, .opf-code) .cm-tooltip-autocomplete .cm-completionMatchedText {
|
|
2838
|
+
font-weight: 600;
|
|
2839
|
+
text-decoration: none;
|
|
2840
|
+
}
|
|
2841
|
+
|
|
2842
|
+
:root :is(.opf-ui, .opf-json, .opf-code) .cm-tooltip .cm-completionInfo {
|
|
2843
|
+
max-width: 280px;
|
|
2844
|
+
padding: 6px 8px;
|
|
2845
|
+
font: 12px/1.45 var(--opf-ui-font);
|
|
2846
|
+
white-space: pre-wrap;
|
|
2847
|
+
color: var(--opf-ui-fg);
|
|
2848
|
+
background: var(--opf-ui-surface);
|
|
2849
|
+
border: 1px solid var(--opf-ui-border);
|
|
2850
|
+
border-radius: var(--opf-ui-radius-md);
|
|
2851
|
+
}
|
|
2852
|
+
|
|
2810
2853
|
:is(.opf-ui, .opf-json, .opf-code) .cm-diagnostic-error {
|
|
2811
2854
|
border-left-color: var(--opf-ui-danger);
|
|
2812
2855
|
}
|
|
@@ -2938,6 +2981,163 @@
|
|
|
2938
2981
|
}
|
|
2939
2982
|
}
|
|
2940
2983
|
|
|
2984
|
+
/* presenter.css */
|
|
2985
|
+
/* RR-98: the presenter and the Present button (src/presenter.js). Only --opf-ui-* tokens, no color literals (test/styles.mjs). */
|
|
2986
|
+
|
|
2987
|
+
/* ---- the presenter -------------------------------------------------------------------------------------------------------------------- */
|
|
2988
|
+
.opf-presenter,
|
|
2989
|
+
.opf-presenter *,
|
|
2990
|
+
.opf-presenter *::before,
|
|
2991
|
+
.opf-presenter *::after { box-sizing: border-box; }
|
|
2992
|
+
.opf-presenter[hidden] { display: none !important; }
|
|
2993
|
+
|
|
2994
|
+
.opf-presenter {
|
|
2995
|
+
position: fixed;
|
|
2996
|
+
inset: 0;
|
|
2997
|
+
z-index: 2000;
|
|
2998
|
+
display: flex;
|
|
2999
|
+
align-items: center;
|
|
3000
|
+
justify-content: center;
|
|
3001
|
+
overflow: hidden;
|
|
3002
|
+
/* Slides are letterboxed on black in every theme, so the bars never take a token's light or dark value. */
|
|
3003
|
+
background: black;
|
|
3004
|
+
font-family: var(--opf-ui-font);
|
|
3005
|
+
font-size: 13px;
|
|
3006
|
+
line-height: 1.4;
|
|
3007
|
+
color: var(--opf-ui-fg);
|
|
3008
|
+
user-select: none;
|
|
3009
|
+
-webkit-user-select: none;
|
|
3010
|
+
touch-action: none;
|
|
3011
|
+
outline: none;
|
|
3012
|
+
}
|
|
3013
|
+
.opf-presenter[data-chrome="hidden"] { cursor: none; }
|
|
3014
|
+
|
|
3015
|
+
.opf-presenter .opf-presenter-slide {
|
|
3016
|
+
width: 100%;
|
|
3017
|
+
height: 100%;
|
|
3018
|
+
display: flex;
|
|
3019
|
+
align-items: center;
|
|
3020
|
+
justify-content: center;
|
|
3021
|
+
}
|
|
3022
|
+
/* The slide's own width and height attributes give its shape (viewBox); this makes it as large as the screen allows. */
|
|
3023
|
+
.opf-presenter .opf-presenter-slide svg {
|
|
3024
|
+
display: block;
|
|
3025
|
+
width: 100%;
|
|
3026
|
+
height: 100%;
|
|
3027
|
+
max-width: 100%;
|
|
3028
|
+
max-height: 100%;
|
|
3029
|
+
}
|
|
3030
|
+
.opf-presenter .opf-presenter-message {
|
|
3031
|
+
position: absolute;
|
|
3032
|
+
margin: 0;
|
|
3033
|
+
max-width: 40ch;
|
|
3034
|
+
padding: 12px 16px;
|
|
3035
|
+
border: 1px solid var(--opf-ui-border);
|
|
3036
|
+
border-radius: var(--opf-ui-radius-md);
|
|
3037
|
+
background: var(--opf-ui-surface);
|
|
3038
|
+
color: var(--opf-ui-muted-fg);
|
|
3039
|
+
text-align: center;
|
|
3040
|
+
font: 400 13px/1.5 var(--opf-ui-font);
|
|
3041
|
+
}
|
|
3042
|
+
.opf-presenter .opf-presenter-message[hidden] { display: none; }
|
|
3043
|
+
.opf-presenter .opf-presenter-live {
|
|
3044
|
+
position: absolute;
|
|
3045
|
+
width: 1px;
|
|
3046
|
+
height: 1px;
|
|
3047
|
+
margin: -1px;
|
|
3048
|
+
padding: 0;
|
|
3049
|
+
overflow: hidden;
|
|
3050
|
+
clip-path: inset(50%);
|
|
3051
|
+
white-space: nowrap;
|
|
3052
|
+
border: 0;
|
|
3053
|
+
}
|
|
3054
|
+
|
|
3055
|
+
/* ---- the counter and the exit button (they appear on pointer move) ---------------------------------------------------------------------- */
|
|
3056
|
+
.opf-presenter .opf-presenter-counter,
|
|
3057
|
+
.opf-presenter .opf-presenter-close {
|
|
3058
|
+
position: absolute;
|
|
3059
|
+
background: var(--opf-ui-surface);
|
|
3060
|
+
color: var(--opf-ui-muted-fg);
|
|
3061
|
+
border: 1px solid var(--opf-ui-border);
|
|
3062
|
+
opacity: 0;
|
|
3063
|
+
transition: opacity var(--opf-ui-ease), color var(--opf-ui-ease), border-color var(--opf-ui-ease);
|
|
3064
|
+
}
|
|
3065
|
+
.opf-presenter[data-chrome="visible"] .opf-presenter-counter,
|
|
3066
|
+
.opf-presenter[data-chrome="visible"] .opf-presenter-close,
|
|
3067
|
+
.opf-presenter .opf-presenter-close:focus-visible { opacity: 1; }
|
|
3068
|
+
|
|
3069
|
+
.opf-presenter .opf-presenter-counter {
|
|
3070
|
+
bottom: 16px;
|
|
3071
|
+
left: 0;
|
|
3072
|
+
right: 0;
|
|
3073
|
+
width: max-content;
|
|
3074
|
+
margin: 0 auto;
|
|
3075
|
+
padding: 4px 10px;
|
|
3076
|
+
border-radius: var(--opf-ui-radius);
|
|
3077
|
+
font: 500 11.5px/1.4 var(--opf-ui-mono);
|
|
3078
|
+
letter-spacing: 0.04em;
|
|
3079
|
+
pointer-events: none;
|
|
3080
|
+
}
|
|
3081
|
+
.opf-presenter .opf-presenter-close {
|
|
3082
|
+
top: 16px;
|
|
3083
|
+
right: 16px;
|
|
3084
|
+
display: inline-flex;
|
|
3085
|
+
align-items: center;
|
|
3086
|
+
justify-content: center;
|
|
3087
|
+
width: var(--opf-ui-control-h);
|
|
3088
|
+
height: var(--opf-ui-control-h);
|
|
3089
|
+
padding: 0;
|
|
3090
|
+
margin: 0;
|
|
3091
|
+
border-radius: var(--opf-ui-radius);
|
|
3092
|
+
font: inherit;
|
|
3093
|
+
cursor: pointer;
|
|
3094
|
+
}
|
|
3095
|
+
.opf-presenter .opf-presenter-close:hover { color: var(--opf-ui-fg); background: var(--opf-ui-muted); }
|
|
3096
|
+
.opf-presenter .opf-presenter-close:focus-visible {
|
|
3097
|
+
outline: 2px solid var(--opf-ui-ring);
|
|
3098
|
+
outline-offset: 2px;
|
|
3099
|
+
}
|
|
3100
|
+
.opf-presenter .opf-icon { flex: none; }
|
|
3101
|
+
|
|
3102
|
+
/* ---- the Present button (styled like the Export trigger) ------------------------------------------------------------------------------- */
|
|
3103
|
+
.opf-present-button,
|
|
3104
|
+
.opf-present-button *,
|
|
3105
|
+
.opf-present-button *::before,
|
|
3106
|
+
.opf-present-button *::after { box-sizing: border-box; }
|
|
3107
|
+
.opf-present-button {
|
|
3108
|
+
display: inline-flex;
|
|
3109
|
+
align-items: center;
|
|
3110
|
+
justify-content: center;
|
|
3111
|
+
flex: none;
|
|
3112
|
+
width: var(--opf-ui-control-h);
|
|
3113
|
+
height: var(--opf-ui-control-h);
|
|
3114
|
+
margin: 0;
|
|
3115
|
+
padding: 0;
|
|
3116
|
+
border: 1px solid var(--opf-ui-accent);
|
|
3117
|
+
border-radius: var(--opf-ui-radius);
|
|
3118
|
+
background: var(--opf-ui-accent);
|
|
3119
|
+
color: var(--opf-ui-accent-fg);
|
|
3120
|
+
font: inherit;
|
|
3121
|
+
cursor: pointer;
|
|
3122
|
+
transition: opacity var(--opf-ui-ease);
|
|
3123
|
+
}
|
|
3124
|
+
.opf-present-button:hover { opacity: 0.92; }
|
|
3125
|
+
.opf-present-button:focus-visible {
|
|
3126
|
+
outline: 2px solid var(--opf-ui-ring);
|
|
3127
|
+
outline-offset: 2px;
|
|
3128
|
+
}
|
|
3129
|
+
.opf-present-button[aria-disabled="true"] {
|
|
3130
|
+
opacity: 0.5;
|
|
3131
|
+
cursor: not-allowed;
|
|
3132
|
+
}
|
|
3133
|
+
.opf-present-button .opf-icon { flex: none; }
|
|
3134
|
+
|
|
3135
|
+
@media (prefers-reduced-motion: reduce) {
|
|
3136
|
+
.opf-presenter .opf-presenter-counter,
|
|
3137
|
+
.opf-presenter .opf-presenter-close,
|
|
3138
|
+
.opf-present-button { transition: none; }
|
|
3139
|
+
}
|
|
3140
|
+
|
|
2941
3141
|
/* source-pane.css */
|
|
2942
3142
|
/* Source pane (RR-98). Only --opf-ui-* tokens (src/styles/tokens.css). */
|
|
2943
3143
|
.opf-source {
|
|
@@ -3087,7 +3287,8 @@
|
|
|
3087
3287
|
|
|
3088
3288
|
/* Code */
|
|
3089
3289
|
.opf-source-code { position: relative; flex: 1; min-height: 0; overflow: hidden; display: flex; }
|
|
3090
|
-
|
|
3290
|
+
/* The pane frame draws the edge: the editor inside it has no border or radius of its own (panels.css gives a standalone editor both). */
|
|
3291
|
+
.opf-source-code > .cm-editor { flex: 1; min-width: 0; height: 100%; background: transparent; color: var(--opf-ui-fg); border: 0; border-radius: 0; }
|
|
3091
3292
|
.opf-source-code .cm-editor.cm-focused { outline: none; }
|
|
3092
3293
|
.opf-source-code .cm-scroller { overflow: auto; font: 400 13.5px/22px var(--opf-ui-mono); }
|
|
3093
3294
|
.opf-source[data-density="touch"] .opf-source-code .cm-scroller { font-size: 13px; line-height: 21px; }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openpresentation/opf-editor",
|
|
3
|
-
"version": "0.24.
|
|
3
|
+
"version": "0.24.3",
|
|
4
4
|
"description": "Embeddable local OPF editor primitives built on the deterministic renderer.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -230,6 +230,14 @@
|
|
|
230
230
|
"types": "./dist/source-pane.d.ts",
|
|
231
231
|
"default": "./dist/source-pane.js"
|
|
232
232
|
},
|
|
233
|
+
"./presenter": {
|
|
234
|
+
"types": "./dist/presenter.d.ts",
|
|
235
|
+
"default": "./dist/presenter.js"
|
|
236
|
+
},
|
|
237
|
+
"./read-deck-file": {
|
|
238
|
+
"types": "./dist/read-deck-file.d.ts",
|
|
239
|
+
"default": "./dist/read-deck-file.js"
|
|
240
|
+
},
|
|
233
241
|
"./export-menu": {
|
|
234
242
|
"types": "./dist/export-menu.d.ts",
|
|
235
243
|
"default": "./dist/export-menu.js"
|
|
@@ -270,7 +278,7 @@
|
|
|
270
278
|
"check:font-hotlinks": "node --test scripts/check-font-hotlinks.test.mjs && node scripts/check-font-hotlinks.mjs",
|
|
271
279
|
"check:font-hotlinks:built": "node scripts/check-font-hotlinks.mjs --built dist artifacts/playground",
|
|
272
280
|
"build:playground": "node scripts/build-playground.mjs",
|
|
273
|
-
"test:playground": "npm run build:playground && npm run check:font-hotlinks:built && node test/playground-pptx.mjs && node test/playground-script-fonts.mjs artifacts/playground-script-fonts && node test/playground-lazy-fonts.mjs artifacts/playground-lazy-fonts && node test/playground-base-fonts.mjs artifacts/playground-base-fonts && node test/playground-source.mjs && node test/design-controls-browser.mjs && node test/design-gaps-browser.mjs && node test/chart-options-browser.mjs && node test/persistence-browser.mjs && node test/slides-browser.mjs && node test/slide-navigator-browser.mjs && node test/layout-templates-browser.mjs && node test/template-panel-browser.mjs && node test/numbering-panel-browser.mjs && node test/playground-ensure-fonts.mjs artifacts/playground-ensure-fonts && node test/canvas-fonts-browser.mjs artifacts/canvas-fonts && node test/find-replace-browser.mjs && node test/image-crop-browser.mjs && node test/mobile-browser.mjs && node test/review-panel-browser.mjs && node test/review-hook-browser.mjs && node test/source-pane-browser.mjs && node test/playground-download.mjs artifacts/playground-download && node test/export-menu-browser.mjs && node test/agent-handoff-browser.mjs",
|
|
281
|
+
"test:playground": "npm run build:playground && npm run check:font-hotlinks:built && node test/playground-pptx.mjs && node test/playground-script-fonts.mjs artifacts/playground-script-fonts && node test/playground-lazy-fonts.mjs artifacts/playground-lazy-fonts && node test/playground-base-fonts.mjs artifacts/playground-base-fonts && node test/playground-source.mjs && node test/design-controls-browser.mjs && node test/design-gaps-browser.mjs && node test/chart-options-browser.mjs && node test/persistence-browser.mjs && node test/slides-browser.mjs && node test/slide-navigator-browser.mjs && node test/layout-templates-browser.mjs && node test/template-panel-browser.mjs && node test/numbering-panel-browser.mjs && node test/playground-ensure-fonts.mjs artifacts/playground-ensure-fonts && node test/canvas-fonts-browser.mjs artifacts/canvas-fonts && node test/find-replace-browser.mjs && node test/image-crop-browser.mjs && node test/mobile-browser.mjs && node test/review-panel-browser.mjs && node test/review-hook-browser.mjs && node test/source-pane-browser.mjs && node test/playground-download.mjs artifacts/playground-download && node test/export-menu-browser.mjs && node test/agent-handoff-browser.mjs && node test/presenter-browser.mjs && node test/present-button-browser.mjs",
|
|
274
282
|
"test:code-browser": "node test/code-browser.mjs",
|
|
275
283
|
"test:selection-browser": "node test/selection-browser.mjs",
|
|
276
284
|
"test:click-entry-browser": "node test/click-entry-browser.mjs",
|
|
@@ -297,6 +305,8 @@
|
|
|
297
305
|
"test:export-license-browser": "node test/export-license-browser.mjs",
|
|
298
306
|
"test:chart-options-browser": "node test/chart-options-browser.mjs",
|
|
299
307
|
"test:numbering-panel-browser": "node test/numbering-panel-browser.mjs",
|
|
308
|
+
"test:presenter-browser": "node test/presenter-browser.mjs",
|
|
309
|
+
"test:present-button-browser": "node test/present-button-browser.mjs",
|
|
300
310
|
"test:export-menu-browser": "node test/export-menu-browser.mjs",
|
|
301
311
|
"test:agent-handoff-browser": "node test/agent-handoff-browser.mjs"
|
|
302
312
|
},
|