@openpresentation/opf-editor 0.29.1 → 0.30.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.
@@ -12,8 +12,22 @@ import type { ReviewFinding, ReviewHook } from "./review.js";
12
12
  import type { ReviewPanel, ReviewPanelOptions } from "./review-panel.js";
13
13
  import type { SlideManager } from "./slide-manager.js";
14
14
  import type { SourceCursor, SourceFormat, SourceFile, SourcePane, SourcePaneOptions } from "./source-pane.js";
15
+ import type { Toolbar, ToolbarItemName, ToolbarItemSpec } from "./toolbar.js";
16
+ import type { DeckTitle } from "./deck-title.js";
17
+ import type { OpfIcons } from "./icons.js";
18
+ import type { DesignMenu, DesignMenuLabels } from "./design-menu.js";
19
+ import type { ReviewPill, ReviewPillCounts, ReviewPillLabels } from "./review-pill.js";
20
+ import type { HelpButton, HelpButtonLabels, HelpShortcut } from "./shortcuts-sheet.js";
21
+ import type { ToolbarAction, ToolbarActions, ToolbarActionsLabels } from "./toolbar-actions.js";
15
22
 
16
- export type OpfEditorLayout = "full" | "canvas" | "source" | "studio" | "playground";
23
+ /** CE-28: `"embed"` is the slide alone under a compact toolbar (title, history, counter, expand, Present), for a page that shows a deck. */
24
+ export type OpfEditorLayout = "full" | "canvas" | "embed" | "viewer" | "source" | "studio" | "playground";
25
+ export type { ToolbarAction, HelpShortcut };
26
+ /** CE-28: a toolbar item by name, or `{ id, priority, collapsible }` (see `toolbar.d.ts`). */
27
+ export type OpfToolbarItem = ToolbarItemSpec;
28
+ /** CE-29: the names of the `icons` option. */
29
+ export type OpfEditorIconName = "more" | "expand" | "collapse" | "valid" | "error" | "warning" | "info" | "checking" | "unavailable" | "help" | "close" | "trigger" | "check" | "previous" | "next" | "add" | "present";
30
+ export type { Toolbar, ToolbarItemName };
17
31
  export type OpfEditorView = "slide" | "sorter" | "outline" | "layouts";
18
32
  export type OpfEditorDensity = "comfortable" | "touch";
19
33
 
@@ -48,6 +62,17 @@ export declare const THEME_TOKENS: Readonly<{
48
62
  controlHeight: "--opf-ui-control-h";
49
63
  shadow: "--opf-ui-shadow-pop";
50
64
  motion: "--opf-ui-ease";
65
+ barBackground: "--opf-ui-bar-bg";
66
+ barText: "--opf-ui-bar-fg";
67
+ barBorder: "--opf-ui-bar-border";
68
+ barGap: "--opf-ui-bar-gap";
69
+ barPadding: "--opf-ui-bar-padding";
70
+ barHeight: "--opf-ui-bar-height";
71
+ titleFont: "--opf-ui-title-font";
72
+ titleSize: "--opf-ui-title-size";
73
+ titleWeight: "--opf-ui-title-weight";
74
+ titleText: "--opf-ui-title-fg";
75
+ overlayZ: "--opf-ui-z-overlay";
51
76
  }>;
52
77
  export type ThemeTokenName = keyof typeof THEME_TOKENS;
53
78
  /** Token values by short name or by full custom-property name: `{ accent: "#0a7", "--opf-ui-border": "#ddd" }`. */
@@ -145,6 +170,23 @@ export interface OpfEditorSlots {
145
170
  overlay?: HTMLElement;
146
171
  /** CE-20, the Studio: an element of the host placed at the end of the Studio's bar (Share, avatars). */
147
172
  topbarEnd?: HTMLElement;
173
+ /**
174
+ * CE-28, the toolbar's items in the host's own elements (mode B): the deck title, the Undo and Redo buttons, the slide counter (a second
175
+ * navigator on the one slide index), the view switch and the expand button. An item given here is left out of the bar. Slots that name only
176
+ * these (and `toolbar`) keep the built layout; `export`, `present` and `autosave` above are their items' slots too.
177
+ */
178
+ title?: HTMLElement;
179
+ history?: HTMLElement;
180
+ counter?: HTMLElement;
181
+ views?: HTMLElement;
182
+ expand?: HTMLElement;
183
+ /** CE-28 wave 2: the Design quick menu (the `design` item; `design` is the side panel's slot), the review pill (`review` item), the help button and the host's actions. */
184
+ designMenu?: HTMLElement;
185
+ reviewPill?: HTMLElement;
186
+ help?: HTMLElement;
187
+ actions?: HTMLElement;
188
+ /** CE-28: the element the toolbar is built in, instead of the default layout's bar (with your own `slots` arrangement, the only place it goes). */
189
+ toolbar?: HTMLElement;
148
190
  }
149
191
 
150
192
  /** CE-20: one item of the Studio's selection. `key` is the scene key (the id path, `/slides/@intro/blocks/@kpi`; a layout region `<slide key>#<name>`). */
@@ -251,7 +293,8 @@ export interface OpfEditorOptions {
251
293
  variables?: "authored" | "resolved";
252
294
 
253
295
  /**
254
- * `"full"` (default), `"canvas"` or `"source"`: the editor builds the arrangement (ignored when `slots` is given). CE-20: `"studio"` is the
296
+ * `"full"` (default), `"canvas"`, `"embed"` (CE-28) or `"source"`: the editor builds the arrangement (ignored when `slots` names a part; slots for the
297
+ * toolbar's items alone keep it). CE-20: `"studio"` is the
255
298
  * Presentation and Slide Studio and `"playground"` its first-contact preset (a host's `slots` then add parts, such as `topbarEnd`).
256
299
  */
257
300
  layout?: OpfEditorLayout;
@@ -269,6 +312,35 @@ export interface OpfEditorOptions {
269
312
  slideIndex?: number;
270
313
  /** `"contain"` sizes the slide to fit its frame (default in the built layouts); `false` leaves the size to the host. */
271
314
  fit?: "contain" | false;
315
+ /**
316
+ * CE-28: the toolbar's items in order (names, or `{ id, priority, collapsible }`); `false` builds no bar (items given in `slots` still mount).
317
+ * Default: the layout's preset (`full`: title, history, find, views, spacer, autosave, export, present, expand, more; `canvas`: title, history,
318
+ * spacer, expand, more; `embed`: title, history, counter, spacer, expand, present, more; none for `source` and `slots`). Items this editor has
319
+ * nothing for (Export without Export, the views with one view) are left out; `zoom`, `design`, `review`, `actions` and `help` are reserved and
320
+ * left out until their parts ship. The Studio has its own bar and ignores this.
321
+ */
322
+ toolbar?: false | readonly OpfToolbarItem[];
323
+ /**
324
+ * CE-28: the expanded editor (the `expand` item and `editor.expand()`). `target` is the element that fills the window (default the mount
325
+ * element; give a wrapper when your own header with the toolbar items sits outside it), `fullscreen` also asks the browser for full screen.
326
+ * `false` turns it off.
327
+ */
328
+ expand?: false | { target?: HTMLElement; fullscreen?: boolean };
329
+ /**
330
+ * CE-29: the icons of the chrome's parts, by name, in one flat map (see docs/styling.md): `more` (the ⋯ button), `expand` and `collapse`,
331
+ * `valid`, `error`, `warning`, `info`, `checking` and `unavailable` (the review pill), `help` and `close` (the help sheet; `close` is also
332
+ * the Design menu's), `trigger` and `check` (the Design menu), `previous` and `next` (both slide navigators), `add` (the strip's "+"), `present`.
333
+ * An icon is an SVG element, a function returning one, or 24x24 path data; an unknown name throws.
334
+ */
335
+ icons?: OpfIcons<OpfEditorIconName>;
336
+ /** CE-28 wave 2: the host's own buttons in the toolbar (the `actions` item); `editor.setActions` replaces them. Each `enabled()` and `pressed()` is read again after every change, selection and read-only switch. */
337
+ actions?: ToolbarAction[];
338
+ /** CE-28 wave 2: the Design quick menu (the `design` item). `onOpenPanel` adds its "More design options…" row for your own Design panel; the editor's own Design panel wins when it has one. */
339
+ designMenu?: { onOpenPanel?: () => void };
340
+ /** CE-28 wave 2: "+" and the context menu on the thumbnail strip (default true in `full` and `embed`, false elsewhere). */
341
+ slideActions?: boolean;
342
+ /** CE-28 wave 2: the browser asks before the page closes while the editor is `dirty` (`true`), or while the function says so (default false). */
343
+ guardUnload?: boolean | ((editor: OpfEditor) => boolean);
272
344
 
273
345
  source?: OpfEditorSourceOptions;
274
346
  canvas?: Omit<CanvasEditorOptions, "editor" | "fonts" | "renderOptions" | "slideIndex" | "presentation" | "catalogs" | "propertiesContainer">;
@@ -288,9 +360,18 @@ export interface OpfEditorOptions {
288
360
  theme?: OpfEditorTheme;
289
361
  /**
290
362
  * Text for the default layouts (`review`, `design`, `find`, `undo`, `redo`, `slideView`, `inspector`) and the accessible names of the slide row's
291
- * two landmarks (`navigator`, default "Slide navigation"; `thumbnails`, default "Slides").
363
+ * two landmarks (`navigator`, default "Slide navigation"; `thumbnails`, default "Slides"). CE-28, the toolbar: `title` (the name of the deck
364
+ * title field, default "Presentation name"), `untitled` (its placeholder, default "Untitled presentation"), `expand` and `collapse` (the expand
365
+ * button, default "Expand editor" and "Exit expanded editor"), `more` (the ⋯ button, default "More"), `moreMenu` (its menu, default "More
366
+ * actions") and `counter` (the toolbar counter's landmark, default "Slide navigation").
292
367
  */
293
- labels?: Partial<Record<"review" | "design" | "find" | "undo" | "redo" | "slideView" | "inspector" | "navigator" | "thumbnails", string>>;
368
+ labels?: Partial<Record<"review" | "design" | "find" | "undo" | "redo" | "slideView" | "inspector" | "navigator" | "thumbnails" | OpfEditorChromeLabel, string>> & {
369
+ /** CE-28 wave 2: the labels of the Design quick menu, the review pill, the help sheet and the actions group. */
370
+ designMenu?: DesignMenuLabels;
371
+ reviewPill?: ReviewPillLabels;
372
+ help?: HelpButtonLabels;
373
+ actions?: ToolbarActionsLabels;
374
+ };
294
375
  /**
295
376
  * Which slide stays on show when the document changes outside the canvas: `"id"` (default) follows the slide by its id (a reorder in the source
296
377
  * pane keeps it), `"position"` keeps the position and clamps it to the deck.
@@ -309,6 +390,9 @@ export interface OpfEditorOptions {
309
390
  on?: { [Name in keyof OpfEditorEvents]?: (detail: OpfEditorEvents[Name]) => void };
310
391
  }
311
392
 
393
+ /** CE-28: the labels of the toolbar's parts. */
394
+ export type OpfEditorChromeLabel = "title" | "untitled" | "expand" | "collapse" | "more" | "moreMenu" | "counter" | "exportItem";
395
+
312
396
  export interface OpfEditorSourceState {
313
397
  /** `valid`, `invalid` (the document has errors) or `syntax` (the text does not read as a document in `format`). */
314
398
  status: { kind: "valid"; warnings: number } | { kind: "invalid"; errors: number; warnings: number } | { kind: "syntax"; format: SourceFormat; message: string };
@@ -369,6 +453,16 @@ export interface OpfEditorEvents {
369
453
  "review-goto": { finding: ReviewFinding; target: unknown };
370
454
  "review-focus": { fix: unknown; target: unknown };
371
455
  panel: { panel: "review" | "design" };
456
+ /** CE-28: the document's `name` changed, from any source (the title field, the source pane, undo, the host). `""` is no name. */
457
+ deckName: { name: string; previous: string };
458
+ /** CE-28: the editor was expanded to fill the window, or returned (the button, `expand()`, Escape, the browser leaving full screen). */
459
+ expand: { expanded: boolean };
460
+ /** CE-28 wave 2: the document, or a source draft, now differs from what was last loaded or saved (`true`), or no longer does. */
461
+ dirty: { dirty: boolean };
462
+ /** CE-28 wave 2: Ctrl/Cmd+S inside the editor (or `editor.save()`): save this. `text` is the source pane's text, a draft too (`draft`). Call `markSaved()` once saved. */
463
+ save: { document: unknown; text: string; format: SourceFormat; draft: boolean };
464
+ /** CE-28 wave 2: the review pill was pressed in a layout without a Review panel (the embed): show the findings your own way. */
465
+ "review-open": { counts: ReviewPillCounts | null; findings: ReviewFinding[] };
372
466
  destroy: Record<string, never>;
373
467
  }
374
468
 
@@ -387,7 +481,7 @@ export interface OpfEditorSetDocumentOptions {
387
481
  * The handle of a mounted editor. It is returned at once, before the parts have mounted (they wait for the fonts and, in a layout that shows
388
482
  * slides, for the slide chunk), and every method works from the first moment: a setting (`setDensity`, `setExportMode`, `setView`, `setSlide`,
389
483
  * `setReadOnly`, `setTheme`, `setName`) is kept and read when the parts mount, and a call that acts on a part (`select`, `goTo`, `showPanel`,
390
- * `focus`, `openFind`, `present`, and the Studio's `setLayout`, `setZoom`, `fit`, `openLayout` and `commands.register`) is queued and runs, in
484
+ * `focus`, `openFind`, `present`, CE-28's `setDeckName` and `expand`, and the Studio's `setLayout`, `setZoom`, `fit`, `openLayout` and `commands.register`) is queued and runs, in
391
485
  * order, as soon as the editor is mounted, before `mounted` is emitted; a later call to the same method replaces an earlier one. A queued call
392
486
  * returns `true` (accepted) or, where it needs a part the editor does not have, `false`. Only `setDocument` and `setSourceText`, whose result
393
487
  * depends on the document, throw before `ready`.
@@ -417,6 +511,35 @@ export interface OpfEditor {
417
511
  readonly selection: { path: string; value: unknown } | OpfStudioSelectionItem[] | null;
418
512
  /** CE-20: the arrangement; `setLayout` switches the Studio between "studio" and "playground". */
419
513
  readonly layout: OpfEditorLayout | "slots";
514
+ /** CE-28: the toolbar the editor built (undefined without one: `toolbar: false`, `source`, `slots` without `slots.toolbar`, the Studio). */
515
+ readonly toolbar: Toolbar | undefined;
516
+ /** CE-28: the deck title part (the `title` item), once mounted. */
517
+ readonly deckTitle: DeckTitle | undefined;
518
+ /** CE-28 wave 2: the toolbar's other parts once mounted. A host that runs its own Review (the playground) feeds `reviewPill.update(counts)`. */
519
+ readonly designMenu: DesignMenu | undefined;
520
+ readonly reviewPill: ReviewPill | undefined;
521
+ readonly helpButton: HelpButton | undefined;
522
+ readonly toolbarActions: ToolbarActions | undefined;
523
+ /** CE-28: the deck's `name` (`""` without one). Not the source pane's file name (`getName`). */
524
+ getDeckName(): string;
525
+ /**
526
+ * CE-28: rename the deck: one undoable, validated edit through the session (the text is trimmed; an empty name removes `name`). An open canvas
527
+ * edit is committed first. False while read-only, while the source text is not a valid deck, or when the edit was refused; queued (true) before mount.
528
+ */
529
+ setDeckName(name: string): boolean;
530
+ /** CE-28: expand the editor to fill the window (`false` returns it). Returns the resulting state; queued (true) before mount; false with `expand: false` and in the Studio. */
531
+ expand(on?: boolean): boolean;
532
+ readonly expanded: boolean;
533
+ /** CE-28 wave 2: the document, or a source draft that is not a valid deck, differs from what was last loaded (`setDocument`, `setSourceText`) or saved. */
534
+ readonly dirty: boolean;
535
+ /** CE-28 wave 2: the host saved the document: it becomes the baseline of `dirty` (and autosave records it, with `persistence`). */
536
+ markSaved(): boolean;
537
+ /** CE-28 wave 2: emit `save` now, as Ctrl/Cmd+S does. False before mount. */
538
+ save(): boolean;
539
+ /** CE-28 wave 2: replace the host's toolbar actions. */
540
+ setActions(actions: ToolbarAction[]): void;
541
+ /** CE-28 wave 2: the keyboard shortcuts this editor binds now (what the help sheet lists; in the Studio, its commands and the chrome's keys). */
542
+ shortcuts(): HelpShortcut[];
420
543
  setLayout(layout: "studio" | "playground"): boolean;
421
544
  /** CE-20: the Studio's zoom (1 is the slide fitted), `setZoom` and `fit` ("slide" or "width"). */
422
545
  readonly zoom: number;