@texuli/deck 0.0.0-stage → 0.5.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 +21 -0
- package/README.md +183 -2
- package/dist/authoring/builder.d.ts +351 -0
- package/dist/authoring/builder.js +64 -0
- package/dist/authoring/index.d.ts +6 -0
- package/dist/authoring/index.js +6 -0
- package/dist/authoring/lint.d.ts +36 -0
- package/dist/authoring/lint.js +325 -0
- package/dist/authoring/outlines.d.ts +34 -0
- package/dist/authoring/outlines.js +255 -0
- package/dist/authoring/patch.d.ts +23 -0
- package/dist/authoring/patch.js +166 -0
- package/dist/authoring/select-layouts.d.ts +19 -0
- package/dist/authoring/select-layouts.js +90 -0
- package/dist/engine/auto-slide.d.ts +32 -0
- package/dist/engine/auto-slide.js +67 -0
- package/dist/engine/canvas.d.ts +56 -0
- package/dist/engine/canvas.js +48 -0
- package/dist/engine/controller.d.ts +126 -0
- package/dist/engine/controller.js +248 -0
- package/dist/engine/controls.d.ts +128 -0
- package/dist/engine/controls.js +460 -0
- package/dist/engine/hash.d.ts +42 -0
- package/dist/engine/hash.js +86 -0
- package/dist/engine/index.d.ts +88 -0
- package/dist/engine/index.js +88 -0
- package/dist/engine/messages.d.ts +138 -0
- package/dist/engine/messages.js +140 -0
- package/dist/engine/motion.d.ts +64 -0
- package/dist/engine/motion.js +112 -0
- package/dist/engine/navigation.d.ts +87 -0
- package/dist/engine/navigation.js +156 -0
- package/dist/engine/presenter.d.ts +58 -0
- package/dist/engine/presenter.js +157 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +9 -0
- package/dist/markdown/attributes.d.ts +24 -0
- package/dist/markdown/attributes.js +94 -0
- package/dist/markdown/attrs-closed.d.ts +52 -0
- package/dist/markdown/attrs-closed.js +520 -0
- package/dist/markdown/blocks.d.ts +112 -0
- package/dist/markdown/blocks.js +766 -0
- package/dist/markdown/frontmatter.d.ts +30 -0
- package/dist/markdown/frontmatter.js +165 -0
- package/dist/markdown/index.d.ts +29 -0
- package/dist/markdown/index.js +29 -0
- package/dist/markdown/issues.d.ts +68 -0
- package/dist/markdown/issues.js +83 -0
- package/dist/markdown/json.d.ts +21 -0
- package/dist/markdown/json.js +236 -0
- package/dist/markdown/limits.d.ts +32 -0
- package/dist/markdown/limits.js +32 -0
- package/dist/markdown/parse.d.ts +31 -0
- package/dist/markdown/parse.js +283 -0
- package/dist/markdown/scan.d.ts +26 -0
- package/dist/markdown/scan.js +138 -0
- package/dist/markdown/slides.d.ts +32 -0
- package/dist/markdown/slides.js +854 -0
- package/dist/markdown/text.d.ts +76 -0
- package/dist/markdown/text.js +447 -0
- package/dist/markdown/twin.d.ts +41 -0
- package/dist/markdown/twin.js +374 -0
- package/dist/markdown/write.d.ts +17 -0
- package/dist/markdown/write.js +688 -0
- package/dist/math/index.d.ts +14 -0
- package/dist/math/index.js +14 -0
- package/dist/math/parse.d.ts +9 -0
- package/dist/math/parse.js +648 -0
- package/dist/math/symbols.d.ts +44 -0
- package/dist/math/symbols.js +333 -0
- package/dist/math/types.d.ts +59 -0
- package/dist/math/types.js +69 -0
- package/dist/model/backgrounds/contrast.d.ts +77 -0
- package/dist/model/backgrounds/contrast.js +186 -0
- package/dist/model/backgrounds/index.d.ts +7 -0
- package/dist/model/backgrounds/index.js +7 -0
- package/dist/model/backgrounds/resolve.d.ts +86 -0
- package/dist/model/backgrounds/resolve.js +215 -0
- package/dist/model/backgrounds/schema.d.ts +178 -0
- package/dist/model/backgrounds/schema.js +203 -0
- package/dist/model/codes.d.ts +73 -0
- package/dist/model/codes.js +67 -0
- package/dist/model/deck.d.ts +392 -0
- package/dist/model/deck.js +338 -0
- package/dist/model/index.d.ts +19 -0
- package/dist/model/index.js +19 -0
- package/dist/model/layouts/catalog.d.ts +433 -0
- package/dist/model/layouts/catalog.js +495 -0
- package/dist/model/layouts/index.d.ts +5 -0
- package/dist/model/layouts/index.js +5 -0
- package/dist/model/layouts/props.d.ts +302 -0
- package/dist/model/layouts/props.js +272 -0
- package/dist/model/loader.d.ts +37 -0
- package/dist/model/loader.js +317 -0
- package/dist/model/migrate.d.ts +34 -0
- package/dist/model/migrate.js +453 -0
- package/dist/model/motion/index.d.ts +6 -0
- package/dist/model/motion/index.js +6 -0
- package/dist/model/motion/transition.d.ts +96 -0
- package/dist/model/motion/transition.js +127 -0
- package/dist/model/parse.d.ts +57 -0
- package/dist/model/parse.js +307 -0
- package/dist/model/plain.d.ts +40 -0
- package/dist/model/plain.js +275 -0
- package/dist/model/shared.d.ts +63 -0
- package/dist/model/shared.js +86 -0
- package/dist/model/steps/index.d.ts +7 -0
- package/dist/model/steps/index.js +7 -0
- package/dist/model/steps/phase.d.ts +34 -0
- package/dist/model/steps/phase.js +50 -0
- package/dist/model/steps/slide-steps.d.ts +129 -0
- package/dist/model/steps/slide-steps.js +256 -0
- package/dist/model/style/index.d.ts +8 -0
- package/dist/model/style/index.js +8 -0
- package/dist/model/style/resolve.d.ts +87 -0
- package/dist/model/style/resolve.js +174 -0
- package/dist/model/style/schema.d.ts +85 -0
- package/dist/model/style/schema.js +53 -0
- package/dist/model/style/theme.d.ts +69 -0
- package/dist/model/style/theme.js +84 -0
- package/dist/schema/builders.d.ts +146 -0
- package/dist/schema/builders.js +285 -0
- package/dist/schema/diagnostics.d.ts +78 -0
- package/dist/schema/diagnostics.js +81 -0
- package/dist/schema/index.d.ts +15 -0
- package/dist/schema/index.js +14 -0
- package/dist/schema/internal.d.ts +40 -0
- package/dist/schema/internal.js +209 -0
- package/dist/schema/json-schema.d.ts +12 -0
- package/dist/schema/json-schema.js +213 -0
- package/dist/schema/types.d.ts +166 -0
- package/dist/schema/types.js +1 -0
- package/dist/schema/validate.d.ts +51 -0
- package/dist/schema/validate.js +765 -0
- package/dist/templates/index.d.ts +2 -0
- package/dist/templates/index.js +2 -0
- package/dist/templates/templates.d.ts +11 -0
- package/dist/templates/templates.js +47 -0
- package/package.json +60 -4
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@texuli/deck/engine` — framework-free presentation runtime (ADR-009).
|
|
3
|
+
*
|
|
4
|
+
* ## Public API
|
|
5
|
+
*
|
|
6
|
+
* ### Navigation (`navigation.ts`)
|
|
7
|
+
* - `createDeckNavigator(deck, options?)` → `DeckNavigator`
|
|
8
|
+
* - `next` / `prev` / `first` / `last` / `goTo(id | visibleIndex | location, step?)`
|
|
9
|
+
* - `goToVertical(sectionId, verticalIndex, step?)`
|
|
10
|
+
* - `getLocation()` → `DeckLocation` (`slideIndex`, `slideId`, `step`,
|
|
11
|
+
* `stepCount` = max step index / advances, optional `sectionId` /
|
|
12
|
+
* `verticalIndex` for stacked outline sections)
|
|
13
|
+
* - `visibleSlides()`, `stepCountFor(slideId)`
|
|
14
|
+
* - `modelSlideStepCount(slide)` — default advance count from blocks/props/labels
|
|
15
|
+
* - Types: `EngineDeck`, `EngineSlide`, `EngineSection`, `DeckLocation`,
|
|
16
|
+
* `NavigatorOptions`, `DeckNavigator`
|
|
17
|
+
*
|
|
18
|
+
* ### Hash routing (`hash.ts`)
|
|
19
|
+
* - `parseDeckHash(raw)` / `formatDeckHash(slideId, step)` — `#/<id>/<step>`
|
|
20
|
+
* Rejects traversal (`..`), uppercase ids, percent-encoding, `?`/`#`/`\` inside.
|
|
21
|
+
* - `parseDeckRoute(hash, search?)` / `formatDeckRoute(location, flags?)` —
|
|
22
|
+
* `?print=1¬es=1` flags
|
|
23
|
+
* - Constants: `DECK_HASH_ID_MAX` (64), `DECK_HASH_STEP_MAX` (32)
|
|
24
|
+
*
|
|
25
|
+
* ### Controls + input (`controls.ts`)
|
|
26
|
+
* - `DECK_CONTROLS` registry (single source for help/toolbar/docs)
|
|
27
|
+
* - `decideDeckInput(event, state?)` → `DeckAction | null`
|
|
28
|
+
* Keys: →↓PageDown Space Enter / ←↑PageUp Shift+Space Backspace, Home/End,
|
|
29
|
+
* O, F, S|P, B|., L, ?, Ctrl/⌘+P, D, Esc stack (debug→help→overview→
|
|
30
|
+
* blackout→laser→fullscreen-exit). Swipe ≥50 px, 1.5× dominance, <800 ms.
|
|
31
|
+
* Guards: fields/IME/modifiers/interactive targets/`data-tx-deck-*`.
|
|
32
|
+
* - `inputPathFrom(nodes, stopAt?)`, `deckControlFor`, `availableDeckControls`,
|
|
33
|
+
* `deckKeyBindings`, `DECK_KEY_BINDINGS`, `DECK_ESCAPE_ORDER`
|
|
34
|
+
* - Swipe constants, `DECK_INTERACTIVE_ATTRIBUTE`, `DECK_CHROME_ATTRIBUTE`
|
|
35
|
+
*
|
|
36
|
+
* ### Canvas fit (`canvas.ts`)
|
|
37
|
+
* - `DECK_CANVAS` / `deckCanvasSize(aspect)` / `fitDeckCanvas(w, h, aspect?, fit?)`
|
|
38
|
+
* Aspects 16:9, 4:3, 9:16, 1:1. Fit: `contain` | `cover` | `container`
|
|
39
|
+
* (`container` ≡ letterboxed contain for embedded decks).
|
|
40
|
+
*
|
|
41
|
+
* ### Motion (`motion.ts`)
|
|
42
|
+
* - `resolveDeckTransition({ slide, style, motion, reducedMotion })`
|
|
43
|
+
* - `effectiveMotion`, `morphPairsFor`, `TRANSITION_MS`, `MAX_MOTION_MS`
|
|
44
|
+
*
|
|
45
|
+
* ### Auto-slide (`auto-slide.ts`)
|
|
46
|
+
* - `createAutoSlideScheduler({ intervalMs, onAdvance, clock?, startPaused? })`
|
|
47
|
+
* Injectable clock; `input()` pauses; clamp 1s…600s.
|
|
48
|
+
*
|
|
49
|
+
* ### Presenter protocol v1 (`presenter.ts`)
|
|
50
|
+
* - Closed messages `{ type: 'hello'|'sync'|'request', slideId, step }`
|
|
51
|
+
* - Namespace `texuli-deck-presenter/1:<ns>` via `presenterChannelName`
|
|
52
|
+
* - `parsePresenterMessage` / `presenterMessage` / `isPresenterMessage`
|
|
53
|
+
* - Transports (no globals at import): `createPresenterTransport(channel)`,
|
|
54
|
+
* `createMemoryPresenterTransport(ns?)`,
|
|
55
|
+
* `createBroadcastPresenterTransport(ns, factory?)`
|
|
56
|
+
*
|
|
57
|
+
* ### Controller (`controller.ts`)
|
|
58
|
+
* - `createDeckController(deck, options?)` → `DeckController`
|
|
59
|
+
* - Navigation: `goTo` / `next` / `prev` / `first` / `last` / `getState`
|
|
60
|
+
* - `subscribe(listener)` or `subscribe(event, listener)` —
|
|
61
|
+
* events: `slidechange` | `stepchange` | `statechange` | `overview` |
|
|
62
|
+
* `blackout` | `pause` | `action` | `destroy`
|
|
63
|
+
* - `setOverview` / `setBlackout` / `pause` / `resume` / `handleInput` /
|
|
64
|
+
* `destroy`
|
|
65
|
+
* - Plugins (ordered): `setup`, `beforeNavigate`, `afterNavigate`,
|
|
66
|
+
* `beforeRender` (read-only slide/context), `afterRender`, `onAction`,
|
|
67
|
+
* `onDestroy`. Stage calls `controller.beforeRender()` / `afterRender()`
|
|
68
|
+
* around a paint; hooks observe only (no HTML injection).
|
|
69
|
+
*
|
|
70
|
+
* ### Messages (`messages.ts`)
|
|
71
|
+
* - `DECK_MESSAGES` English defaults; `formatMessage(key, values?, overrides?)`
|
|
72
|
+
* - `resolveDeckLocale(deck?, override?)` → `{ locale, dir }`
|
|
73
|
+
*
|
|
74
|
+
* ## Constraints
|
|
75
|
+
* - Framework-free and DOM-free at import (no `window`/`document` access).
|
|
76
|
+
* - Imports stay inside `packages/deck/src/` (the engine uses the package's own model;
|
|
77
|
+
* import-guard enforced), and nothing touches window, document or navigator at load.
|
|
78
|
+
* - Zero third-party runtime dependencies; erasable TypeScript only.
|
|
79
|
+
*/
|
|
80
|
+
export { createAutoSlideScheduler, } from "./auto-slide.js";
|
|
81
|
+
export { DECK_ASPECTS, DECK_CANVAS, DEFAULT_DECK_ASPECT, deckCanvasSize, fitDeckCanvas, isDeckAspect, } from "./canvas.js";
|
|
82
|
+
export { createDeckController, } from "./controller.js";
|
|
83
|
+
export { availableDeckControls, DECK_CHROME_ATTRIBUTE, DECK_CONTROL_CAPABILITIES, DECK_CONTROL_GROUPS, DECK_CONTROLS, DECK_ESCAPE_ORDER, DECK_INPUT_ACTIONS, DECK_INTERACTIVE_ATTRIBUTE, DECK_KEY_BINDINGS, DECK_SWIPE_AXIS_RATIO, DECK_SWIPE_MAX_DURATION_MS, DECK_SWIPE_MIN_DISTANCE, DEFAULT_DECK_CONTROL_ENVIRONMENT, decideDeckInput, deckControlFor, deckKeyBindings, inputPathFrom, } from "./controls.js";
|
|
84
|
+
export { DECK_HASH_ID_MAX, DECK_HASH_STEP_MAX, formatDeckHash, formatDeckRoute, parseDeckHash, parseDeckRoute, } from "./hash.js";
|
|
85
|
+
export { DECK_MESSAGES, formatMessage, resolveDeckLocale, } from "./messages.js";
|
|
86
|
+
export { DECK_TRANSITIONS, DEFAULT_MOTION, DEFAULT_TRANSITION, effectiveMotion, isDeckTransition, isMotionLevel, MAX_MOTION_MS, MOTION_LEVELS, morphPairsFor, REDUCED_FADE_MS, resolveDeckTransition, SUBTLE_SCALE, TRANSITION_MS, } from "./motion.js";
|
|
87
|
+
export { createDeckNavigator, modelSlideStepCount, } from "./navigation.js";
|
|
88
|
+
export { createBroadcastPresenterTransport, createMemoryPresenterTransport, createPresenterTransport, isPresenterMessage, PRESENTER_MESSAGE_TYPES, PRESENTER_PROTOCOL_PREFIX, PRESENTER_PROTOCOL_VERSION, parsePresenterMessage, presenterChannelName, presenterMessage, sanitizePresenterNamespace, } from "./presenter.js";
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* English defaults for every stage chrome string, plus `formatMessage`.
|
|
3
|
+
*
|
|
4
|
+
* Consumers pass per-key overrides; `meta.locale` / `meta.dir` flow through
|
|
5
|
+
* {@link resolveDeckLocale}. Placeholders use `{name}` syntax.
|
|
6
|
+
*/
|
|
7
|
+
export declare const DECK_MESSAGES: Readonly<{
|
|
8
|
+
readonly 'controls.previous': "Previous step or slide";
|
|
9
|
+
readonly 'controls.previousDescription': "Goes back one step, or to the previous slide.";
|
|
10
|
+
readonly 'controls.chooseSlide': "Choose a slide";
|
|
11
|
+
readonly 'controls.chooseSlideDescription': "Opens the slide list so you can jump directly to a slide.";
|
|
12
|
+
readonly 'controls.next': "Next step or slide";
|
|
13
|
+
readonly 'controls.nextDescription': "Shows the next step, or advances to the next slide.";
|
|
14
|
+
readonly 'controls.first': "First slide";
|
|
15
|
+
readonly 'controls.firstDescription': "Jumps to the first slide.";
|
|
16
|
+
readonly 'controls.last': "Last slide";
|
|
17
|
+
readonly 'controls.lastDescription': "Jumps to the last slide.";
|
|
18
|
+
readonly 'controls.overview': "Overview of all slides";
|
|
19
|
+
readonly 'controls.overviewDescription': "Shows every slide as a grid.";
|
|
20
|
+
readonly 'controls.fullscreen': "Full screen";
|
|
21
|
+
readonly 'controls.fullscreenDescription': "Fills the screen with the slides.";
|
|
22
|
+
readonly 'controls.leaveFullscreen': "Leave full screen";
|
|
23
|
+
readonly 'controls.leaveFullscreenDescription': "Returns the deck to its normal place.";
|
|
24
|
+
readonly 'controls.presenter': "Presenter view";
|
|
25
|
+
readonly 'controls.presenterDescription': "Shows notes, the next slide and timers.";
|
|
26
|
+
readonly 'controls.blackout': "Black out the screen";
|
|
27
|
+
readonly 'controls.blackoutDescription': "Turns the screen black.";
|
|
28
|
+
readonly 'controls.laser': "Laser pointer";
|
|
29
|
+
readonly 'controls.laserDescription': "Turns the pointer into a bright dot.";
|
|
30
|
+
readonly 'controls.copyLink': "Copy link to this slide";
|
|
31
|
+
readonly 'controls.copyLinkDescription': "Copies a link to this slide and step.";
|
|
32
|
+
readonly 'controls.print': "Print, one slide per page";
|
|
33
|
+
readonly 'controls.printDescription': "Prints the deck or saves it as a PDF.";
|
|
34
|
+
readonly 'controls.help': "Controls and shortcuts";
|
|
35
|
+
readonly 'controls.helpDescription': "Lists every control and its keys.";
|
|
36
|
+
readonly 'controls.debug': "Debug for agents";
|
|
37
|
+
readonly 'controls.debugDescription': "Shows this slide source, checks and reference.";
|
|
38
|
+
readonly 'chrome.toolbar': "Deck controls";
|
|
39
|
+
readonly 'chrome.navigate': "Navigate";
|
|
40
|
+
readonly 'chrome.more': "More presentation controls";
|
|
41
|
+
readonly 'chrome.fullscreenControls': "Full screen controls";
|
|
42
|
+
readonly 'chrome.blackoutHint': "Screen blacked out. Press B or select to show the slide.";
|
|
43
|
+
readonly 'chrome.hintMove': "Use {key} to move,";
|
|
44
|
+
readonly 'chrome.hintFullscreen': "{key} for full screen,";
|
|
45
|
+
readonly 'chrome.hintHelp': "{key} for every control.";
|
|
46
|
+
readonly 'chrome.buttonOnly': "Button only";
|
|
47
|
+
readonly 'chrome.copied': "Copied";
|
|
48
|
+
readonly 'chrome.copyFailed': "Could not copy";
|
|
49
|
+
readonly 'chrome.slideProgress': "Deck progress";
|
|
50
|
+
readonly 'chrome.chooseSlide': "Choose a slide";
|
|
51
|
+
readonly 'chrome.laserOn': "Laser on";
|
|
52
|
+
readonly 'chrome.close': "Close";
|
|
53
|
+
readonly 'overview.title': "Slide overview";
|
|
54
|
+
readonly 'overview.loading': "Loading overview…";
|
|
55
|
+
readonly 'overview.loadError': "The overview could not be loaded.";
|
|
56
|
+
readonly 'overview.slideNumber': "Slide {current}";
|
|
57
|
+
readonly 'overview.selectSlide': "Go to slide {current}: {title}";
|
|
58
|
+
readonly 'presenter.title': "Presenter";
|
|
59
|
+
readonly 'presenter.viewLabel': "Presenter view";
|
|
60
|
+
readonly 'presenter.elapsed': "Elapsed";
|
|
61
|
+
readonly 'presenter.slideTime': "Slide";
|
|
62
|
+
readonly 'presenter.now': "Now";
|
|
63
|
+
readonly 'presenter.next': "Next";
|
|
64
|
+
readonly 'presenter.currentSlide': "Current slide";
|
|
65
|
+
readonly 'presenter.nextSlide': "Next slide";
|
|
66
|
+
readonly 'presenter.endOfDeck': "End of deck";
|
|
67
|
+
readonly 'presenter.previous': "Previous";
|
|
68
|
+
readonly 'presenter.advance': "Next";
|
|
69
|
+
readonly 'presenter.notes': "Speaker notes";
|
|
70
|
+
readonly 'presenter.upNext': "Up next";
|
|
71
|
+
readonly 'presenter.noNotes': "No notes for this slide.";
|
|
72
|
+
readonly 'presenter.popupBlocked': "Presenter window could not be opened.";
|
|
73
|
+
readonly 'presenter.loading': "Loading presenter…";
|
|
74
|
+
readonly 'presenter.pause': "Pause presentation";
|
|
75
|
+
readonly 'presenter.resume': "Resume presentation";
|
|
76
|
+
readonly 'print.button': "Print";
|
|
77
|
+
readonly 'print.noSlides': "This deck has no slides to print.";
|
|
78
|
+
readonly 'print.notes': "Speaker notes";
|
|
79
|
+
readonly 'print.notesAppendix': "Notes";
|
|
80
|
+
readonly 'print.noNotes': "No notes for this slide.";
|
|
81
|
+
readonly 'debug.title': "Debug for agents";
|
|
82
|
+
readonly 'debug.close': "Close";
|
|
83
|
+
readonly 'debug.thisSlide': "This slide";
|
|
84
|
+
readonly 'debug.slide': "Slide";
|
|
85
|
+
readonly 'debug.position': "Position";
|
|
86
|
+
readonly 'debug.layout': "Layout";
|
|
87
|
+
readonly 'debug.pointer': "Pointer";
|
|
88
|
+
readonly 'debug.props': "Props";
|
|
89
|
+
readonly 'debug.deck': "Deck";
|
|
90
|
+
readonly 'debug.notes': "Notes";
|
|
91
|
+
readonly 'debug.actions': "Actions";
|
|
92
|
+
readonly 'debug.copyReference': "Copy agent reference";
|
|
93
|
+
readonly 'debug.copyPrompt': "Copy as agent prompt";
|
|
94
|
+
readonly 'debug.copySlideJson': "Copy slide JSON";
|
|
95
|
+
readonly 'debug.downloadJson': "Download deck JSON";
|
|
96
|
+
readonly 'debug.copyOutline': "Copy outline";
|
|
97
|
+
readonly 'debug.checks': "Checks on this slide";
|
|
98
|
+
readonly 'debug.noFindings': "No findings on this slide.";
|
|
99
|
+
readonly 'debug.otherFindings': "Other slides with findings";
|
|
100
|
+
readonly 'debug.blocks': "Blocks";
|
|
101
|
+
readonly 'debug.slideText': "Slide text";
|
|
102
|
+
readonly 'debug.noText': "(no text)";
|
|
103
|
+
readonly 'debug.loading': "Loading the debug panel…";
|
|
104
|
+
readonly 'debug.loadError': "The debug panel could not be loaded.";
|
|
105
|
+
readonly 'debug.unnamedDeck': "unnamed";
|
|
106
|
+
readonly 'layout.contentUnavailable': "This part of the slide could not be shown.";
|
|
107
|
+
readonly 'layout.emptySlide': "This slide has no content yet.";
|
|
108
|
+
readonly 'layout.contentLoadError': "Slide content could not be loaded.";
|
|
109
|
+
readonly 'layout.contentLoading': "Loading slide content…";
|
|
110
|
+
readonly 'stage.controls': "Presentation controls";
|
|
111
|
+
readonly 'stage.elapsedTime': "Elapsed time";
|
|
112
|
+
readonly 'stage.notes': "Speaker notes";
|
|
113
|
+
readonly 'stage.upNext': "Up next";
|
|
114
|
+
readonly 'stage.slides': "Slides";
|
|
115
|
+
readonly 'stage.emptyNotes': "No notes for this slide.";
|
|
116
|
+
readonly 'stage.emptyContent': "This slide has no content yet.";
|
|
117
|
+
readonly 'stage.loadingOverview': "Loading overview…";
|
|
118
|
+
readonly 'stage.overviewError': "The overview could not be loaded.";
|
|
119
|
+
readonly 'stage.loadingPresenter': "Loading presenter…";
|
|
120
|
+
readonly 'stage.loadingDebug': "Loading the debug panel…";
|
|
121
|
+
readonly 'stage.debugError': "The debug panel could not be loaded.";
|
|
122
|
+
readonly 'stage.slideOf': "Slide {current} of {total}";
|
|
123
|
+
readonly 'stage.stepOf': "Step {current} of {total}";
|
|
124
|
+
}>;
|
|
125
|
+
export type DeckMessageKey = keyof typeof DECK_MESSAGES;
|
|
126
|
+
export type DeckMessages = Partial<Record<DeckMessageKey, string>>;
|
|
127
|
+
export type MessageValues = Readonly<Record<string, string | number>>;
|
|
128
|
+
export interface DeckLocale {
|
|
129
|
+
locale?: string;
|
|
130
|
+
dir?: 'ltr' | 'rtl' | 'auto';
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Resolve a message key with optional overrides and `{name}` placeholders.
|
|
134
|
+
* Unknown placeholders are left intact.
|
|
135
|
+
*/
|
|
136
|
+
export declare function formatMessage(key: DeckMessageKey, values?: MessageValues, overrides?: DeckMessages): string;
|
|
137
|
+
/** Merge deck meta and host overrides into a concrete locale. */
|
|
138
|
+
export declare function resolveDeckLocale(deck?: DeckLocale | null, override?: DeckLocale | null): Required<DeckLocale>;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* English defaults for every stage chrome string, plus `formatMessage`.
|
|
3
|
+
*
|
|
4
|
+
* Consumers pass per-key overrides; `meta.locale` / `meta.dir` flow through
|
|
5
|
+
* {@link resolveDeckLocale}. Placeholders use `{name}` syntax.
|
|
6
|
+
*/
|
|
7
|
+
export const DECK_MESSAGES = Object.freeze({
|
|
8
|
+
'controls.previous': 'Previous step or slide',
|
|
9
|
+
'controls.previousDescription': 'Goes back one step, or to the previous slide.',
|
|
10
|
+
'controls.chooseSlide': 'Choose a slide',
|
|
11
|
+
'controls.chooseSlideDescription': 'Opens the slide list so you can jump directly to a slide.',
|
|
12
|
+
'controls.next': 'Next step or slide',
|
|
13
|
+
'controls.nextDescription': 'Shows the next step, or advances to the next slide.',
|
|
14
|
+
'controls.first': 'First slide',
|
|
15
|
+
'controls.firstDescription': 'Jumps to the first slide.',
|
|
16
|
+
'controls.last': 'Last slide',
|
|
17
|
+
'controls.lastDescription': 'Jumps to the last slide.',
|
|
18
|
+
'controls.overview': 'Overview of all slides',
|
|
19
|
+
'controls.overviewDescription': 'Shows every slide as a grid.',
|
|
20
|
+
'controls.fullscreen': 'Full screen',
|
|
21
|
+
'controls.fullscreenDescription': 'Fills the screen with the slides.',
|
|
22
|
+
'controls.leaveFullscreen': 'Leave full screen',
|
|
23
|
+
'controls.leaveFullscreenDescription': 'Returns the deck to its normal place.',
|
|
24
|
+
'controls.presenter': 'Presenter view',
|
|
25
|
+
'controls.presenterDescription': 'Shows notes, the next slide and timers.',
|
|
26
|
+
'controls.blackout': 'Black out the screen',
|
|
27
|
+
'controls.blackoutDescription': 'Turns the screen black.',
|
|
28
|
+
'controls.laser': 'Laser pointer',
|
|
29
|
+
'controls.laserDescription': 'Turns the pointer into a bright dot.',
|
|
30
|
+
'controls.copyLink': 'Copy link to this slide',
|
|
31
|
+
'controls.copyLinkDescription': 'Copies a link to this slide and step.',
|
|
32
|
+
'controls.print': 'Print, one slide per page',
|
|
33
|
+
'controls.printDescription': 'Prints the deck or saves it as a PDF.',
|
|
34
|
+
'controls.help': 'Controls and shortcuts',
|
|
35
|
+
'controls.helpDescription': 'Lists every control and its keys.',
|
|
36
|
+
'controls.debug': 'Debug for agents',
|
|
37
|
+
'controls.debugDescription': 'Shows this slide source, checks and reference.',
|
|
38
|
+
'chrome.toolbar': 'Deck controls',
|
|
39
|
+
'chrome.navigate': 'Navigate',
|
|
40
|
+
'chrome.more': 'More presentation controls',
|
|
41
|
+
'chrome.fullscreenControls': 'Full screen controls',
|
|
42
|
+
'chrome.blackoutHint': 'Screen blacked out. Press B or select to show the slide.',
|
|
43
|
+
'chrome.hintMove': 'Use {key} to move,',
|
|
44
|
+
'chrome.hintFullscreen': '{key} for full screen,',
|
|
45
|
+
'chrome.hintHelp': '{key} for every control.',
|
|
46
|
+
'chrome.buttonOnly': 'Button only',
|
|
47
|
+
'chrome.copied': 'Copied',
|
|
48
|
+
'chrome.copyFailed': 'Could not copy',
|
|
49
|
+
'chrome.slideProgress': 'Deck progress',
|
|
50
|
+
'chrome.chooseSlide': 'Choose a slide',
|
|
51
|
+
'chrome.laserOn': 'Laser on',
|
|
52
|
+
'chrome.close': 'Close',
|
|
53
|
+
'overview.title': 'Slide overview',
|
|
54
|
+
'overview.loading': 'Loading overview…',
|
|
55
|
+
'overview.loadError': 'The overview could not be loaded.',
|
|
56
|
+
'overview.slideNumber': 'Slide {current}',
|
|
57
|
+
'overview.selectSlide': 'Go to slide {current}: {title}',
|
|
58
|
+
'presenter.title': 'Presenter',
|
|
59
|
+
'presenter.viewLabel': 'Presenter view',
|
|
60
|
+
'presenter.elapsed': 'Elapsed',
|
|
61
|
+
'presenter.slideTime': 'Slide',
|
|
62
|
+
'presenter.now': 'Now',
|
|
63
|
+
'presenter.next': 'Next',
|
|
64
|
+
'presenter.currentSlide': 'Current slide',
|
|
65
|
+
'presenter.nextSlide': 'Next slide',
|
|
66
|
+
'presenter.endOfDeck': 'End of deck',
|
|
67
|
+
'presenter.previous': 'Previous',
|
|
68
|
+
'presenter.advance': 'Next',
|
|
69
|
+
'presenter.notes': 'Speaker notes',
|
|
70
|
+
'presenter.upNext': 'Up next',
|
|
71
|
+
'presenter.noNotes': 'No notes for this slide.',
|
|
72
|
+
'presenter.popupBlocked': 'Presenter window could not be opened.',
|
|
73
|
+
'presenter.loading': 'Loading presenter…',
|
|
74
|
+
'presenter.pause': 'Pause presentation',
|
|
75
|
+
'presenter.resume': 'Resume presentation',
|
|
76
|
+
'print.button': 'Print',
|
|
77
|
+
'print.noSlides': 'This deck has no slides to print.',
|
|
78
|
+
'print.notes': 'Speaker notes',
|
|
79
|
+
'print.notesAppendix': 'Notes',
|
|
80
|
+
'print.noNotes': 'No notes for this slide.',
|
|
81
|
+
'debug.title': 'Debug for agents',
|
|
82
|
+
'debug.close': 'Close',
|
|
83
|
+
'debug.thisSlide': 'This slide',
|
|
84
|
+
'debug.slide': 'Slide',
|
|
85
|
+
'debug.position': 'Position',
|
|
86
|
+
'debug.layout': 'Layout',
|
|
87
|
+
'debug.pointer': 'Pointer',
|
|
88
|
+
'debug.props': 'Props',
|
|
89
|
+
'debug.deck': 'Deck',
|
|
90
|
+
'debug.notes': 'Notes',
|
|
91
|
+
'debug.actions': 'Actions',
|
|
92
|
+
'debug.copyReference': 'Copy agent reference',
|
|
93
|
+
'debug.copyPrompt': 'Copy as agent prompt',
|
|
94
|
+
'debug.copySlideJson': 'Copy slide JSON',
|
|
95
|
+
'debug.downloadJson': 'Download deck JSON',
|
|
96
|
+
'debug.copyOutline': 'Copy outline',
|
|
97
|
+
'debug.checks': 'Checks on this slide',
|
|
98
|
+
'debug.noFindings': 'No findings on this slide.',
|
|
99
|
+
'debug.otherFindings': 'Other slides with findings',
|
|
100
|
+
'debug.blocks': 'Blocks',
|
|
101
|
+
'debug.slideText': 'Slide text',
|
|
102
|
+
'debug.noText': '(no text)',
|
|
103
|
+
'debug.loading': 'Loading the debug panel…',
|
|
104
|
+
'debug.loadError': 'The debug panel could not be loaded.',
|
|
105
|
+
'debug.unnamedDeck': 'unnamed',
|
|
106
|
+
'layout.contentUnavailable': 'This part of the slide could not be shown.',
|
|
107
|
+
'layout.emptySlide': 'This slide has no content yet.',
|
|
108
|
+
'layout.contentLoadError': 'Slide content could not be loaded.',
|
|
109
|
+
'layout.contentLoading': 'Loading slide content…',
|
|
110
|
+
'stage.controls': 'Presentation controls',
|
|
111
|
+
'stage.elapsedTime': 'Elapsed time',
|
|
112
|
+
'stage.notes': 'Speaker notes',
|
|
113
|
+
'stage.upNext': 'Up next',
|
|
114
|
+
'stage.slides': 'Slides',
|
|
115
|
+
'stage.emptyNotes': 'No notes for this slide.',
|
|
116
|
+
'stage.emptyContent': 'This slide has no content yet.',
|
|
117
|
+
'stage.loadingOverview': 'Loading overview…',
|
|
118
|
+
'stage.overviewError': 'The overview could not be loaded.',
|
|
119
|
+
'stage.loadingPresenter': 'Loading presenter…',
|
|
120
|
+
'stage.loadingDebug': 'Loading the debug panel…',
|
|
121
|
+
'stage.debugError': 'The debug panel could not be loaded.',
|
|
122
|
+
'stage.slideOf': 'Slide {current} of {total}',
|
|
123
|
+
'stage.stepOf': 'Step {current} of {total}',
|
|
124
|
+
});
|
|
125
|
+
const PLACEHOLDER = /\{([a-zA-Z][a-zA-Z0-9_]*)\}/g;
|
|
126
|
+
/**
|
|
127
|
+
* Resolve a message key with optional overrides and `{name}` placeholders.
|
|
128
|
+
* Unknown placeholders are left intact.
|
|
129
|
+
*/
|
|
130
|
+
export function formatMessage(key, values = {}, overrides = {}) {
|
|
131
|
+
const template = overrides[key] ?? DECK_MESSAGES[key];
|
|
132
|
+
return template.replace(PLACEHOLDER, (match, name) => Object.hasOwn(values, name) ? String(values[name]) : match);
|
|
133
|
+
}
|
|
134
|
+
/** Merge deck meta and host overrides into a concrete locale. */
|
|
135
|
+
export function resolveDeckLocale(deck, override) {
|
|
136
|
+
return {
|
|
137
|
+
locale: override?.locale ?? deck?.locale ?? 'en',
|
|
138
|
+
dir: override?.dir ?? deck?.dir ?? 'auto',
|
|
139
|
+
};
|
|
140
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure transition resolution metadata. Rendering is owned by the stage.
|
|
3
|
+
*
|
|
4
|
+
* Precedence: slide override → deck style → `fade`. The motion ceiling
|
|
5
|
+
* (`full` | `subtle` | `none`) shortens or drops motion; the viewer's
|
|
6
|
+
* reduced-motion preference only lowers it. Durations never exceed 400 ms.
|
|
7
|
+
*
|
|
8
|
+
* Self-contained: does not import `@texuli/deck/model` (import-guard).
|
|
9
|
+
*/
|
|
10
|
+
export declare const DECK_TRANSITIONS: readonly ["none", "fade", "fade-up", "slide", "zoom", "morph"];
|
|
11
|
+
export type DeckTransition = (typeof DECK_TRANSITIONS)[number];
|
|
12
|
+
export declare const MOTION_LEVELS: readonly ["full", "subtle", "none"];
|
|
13
|
+
export type DeckMotion = (typeof MOTION_LEVELS)[number];
|
|
14
|
+
export declare const MAX_MOTION_MS = 400;
|
|
15
|
+
export declare const REDUCED_FADE_MS = 150;
|
|
16
|
+
export declare const SUBTLE_SCALE = 0.6;
|
|
17
|
+
export declare const DEFAULT_TRANSITION: DeckTransition;
|
|
18
|
+
export declare const DEFAULT_MOTION: DeckMotion;
|
|
19
|
+
export declare const TRANSITION_MS: Readonly<Record<DeckTransition, number>>;
|
|
20
|
+
export type TransitionReason = 'motion-none' | 'reduced-motion' | 'subtle' | 'slide-override' | 'deck-default' | 'engine-default';
|
|
21
|
+
export interface ResolvedTransition {
|
|
22
|
+
name: DeckTransition;
|
|
23
|
+
requested: DeckTransition;
|
|
24
|
+
durationMs: number;
|
|
25
|
+
motion: DeckMotion;
|
|
26
|
+
reason: TransitionReason;
|
|
27
|
+
}
|
|
28
|
+
export interface ResolveTransitionInput {
|
|
29
|
+
slide?: {
|
|
30
|
+
transition?: unknown;
|
|
31
|
+
id?: unknown;
|
|
32
|
+
} | null;
|
|
33
|
+
style?: {
|
|
34
|
+
transition?: unknown;
|
|
35
|
+
motion?: unknown;
|
|
36
|
+
} | null;
|
|
37
|
+
/** Ceiling; defaults to `style.motion`, then `full`. */
|
|
38
|
+
motion?: DeckMotion;
|
|
39
|
+
reducedMotion?: boolean;
|
|
40
|
+
}
|
|
41
|
+
export declare function isDeckTransition(value: unknown): value is DeckTransition;
|
|
42
|
+
export declare function isMotionLevel(value: unknown): value is DeckMotion;
|
|
43
|
+
/** Effective motion ceiling, lowered (never raised) by reduced motion. */
|
|
44
|
+
export declare function effectiveMotion(input?: ResolveTransitionInput): DeckMotion;
|
|
45
|
+
/**
|
|
46
|
+
* Resolve the transition into a slide from the slide override, the deck
|
|
47
|
+
* default and the motion level.
|
|
48
|
+
*/
|
|
49
|
+
export declare function resolveDeckTransition(input?: ResolveTransitionInput): ResolvedTransition;
|
|
50
|
+
/**
|
|
51
|
+
* Morph/auto-animate pairing metadata for the stage: pairs of slide ids that
|
|
52
|
+
* share a `morph` transition on the destination. The stage matches elements
|
|
53
|
+
* by `data-tx-deck-morph-id` (or equivalent); this only reports the pair.
|
|
54
|
+
*/
|
|
55
|
+
export interface MorphPair {
|
|
56
|
+
fromSlideId: string;
|
|
57
|
+
toSlideId: string;
|
|
58
|
+
}
|
|
59
|
+
export declare function morphPairsFor(slides: readonly {
|
|
60
|
+
id: string;
|
|
61
|
+
transition?: unknown;
|
|
62
|
+
}[], style?: {
|
|
63
|
+
transition?: unknown;
|
|
64
|
+
} | null): readonly MorphPair[];
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure transition resolution metadata. Rendering is owned by the stage.
|
|
3
|
+
*
|
|
4
|
+
* Precedence: slide override → deck style → `fade`. The motion ceiling
|
|
5
|
+
* (`full` | `subtle` | `none`) shortens or drops motion; the viewer's
|
|
6
|
+
* reduced-motion preference only lowers it. Durations never exceed 400 ms.
|
|
7
|
+
*
|
|
8
|
+
* Self-contained: does not import `@texuli/deck/model` (import-guard).
|
|
9
|
+
*/
|
|
10
|
+
export const DECK_TRANSITIONS = ['none', 'fade', 'fade-up', 'slide', 'zoom', 'morph'];
|
|
11
|
+
export const MOTION_LEVELS = ['full', 'subtle', 'none'];
|
|
12
|
+
export const MAX_MOTION_MS = 400;
|
|
13
|
+
export const REDUCED_FADE_MS = 150;
|
|
14
|
+
export const SUBTLE_SCALE = 0.6;
|
|
15
|
+
export const DEFAULT_TRANSITION = 'fade';
|
|
16
|
+
export const DEFAULT_MOTION = 'full';
|
|
17
|
+
export const TRANSITION_MS = Object.freeze({
|
|
18
|
+
none: 0,
|
|
19
|
+
fade: 300,
|
|
20
|
+
'fade-up': 300,
|
|
21
|
+
slide: 400,
|
|
22
|
+
zoom: 350,
|
|
23
|
+
morph: 400,
|
|
24
|
+
});
|
|
25
|
+
export function isDeckTransition(value) {
|
|
26
|
+
return typeof value === 'string' && DECK_TRANSITIONS.includes(value);
|
|
27
|
+
}
|
|
28
|
+
export function isMotionLevel(value) {
|
|
29
|
+
return typeof value === 'string' && MOTION_LEVELS.includes(value);
|
|
30
|
+
}
|
|
31
|
+
function clampMs(ms) {
|
|
32
|
+
return Math.max(0, Math.min(MAX_MOTION_MS, Math.round(ms)));
|
|
33
|
+
}
|
|
34
|
+
/** Effective motion ceiling, lowered (never raised) by reduced motion. */
|
|
35
|
+
export function effectiveMotion(input = {}) {
|
|
36
|
+
const level = isMotionLevel(input.motion)
|
|
37
|
+
? input.motion
|
|
38
|
+
: isMotionLevel(input.style?.motion)
|
|
39
|
+
? input.style.motion
|
|
40
|
+
: DEFAULT_MOTION;
|
|
41
|
+
if (level === 'none')
|
|
42
|
+
return 'none';
|
|
43
|
+
return input.reducedMotion ? 'subtle' : level;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Resolve the transition into a slide from the slide override, the deck
|
|
47
|
+
* default and the motion level.
|
|
48
|
+
*/
|
|
49
|
+
export function resolveDeckTransition(input = {}) {
|
|
50
|
+
const own = input.slide?.transition;
|
|
51
|
+
const deckTransition = input.style?.transition;
|
|
52
|
+
const requested = isDeckTransition(own)
|
|
53
|
+
? own
|
|
54
|
+
: isDeckTransition(deckTransition)
|
|
55
|
+
? deckTransition
|
|
56
|
+
: DEFAULT_TRANSITION;
|
|
57
|
+
const source = isDeckTransition(own)
|
|
58
|
+
? 'slide-override'
|
|
59
|
+
: isDeckTransition(deckTransition)
|
|
60
|
+
? 'deck-default'
|
|
61
|
+
: 'engine-default';
|
|
62
|
+
const motion = effectiveMotion(input);
|
|
63
|
+
if (motion === 'none' || requested === 'none') {
|
|
64
|
+
return {
|
|
65
|
+
name: 'none',
|
|
66
|
+
requested,
|
|
67
|
+
durationMs: 0,
|
|
68
|
+
motion,
|
|
69
|
+
reason: motion === 'none' ? 'motion-none' : source,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
if (input.reducedMotion) {
|
|
73
|
+
return {
|
|
74
|
+
name: 'fade',
|
|
75
|
+
requested,
|
|
76
|
+
durationMs: REDUCED_FADE_MS,
|
|
77
|
+
motion,
|
|
78
|
+
reason: 'reduced-motion',
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
if (motion === 'subtle') {
|
|
82
|
+
const name = requested === 'zoom' ? 'fade' : requested;
|
|
83
|
+
return {
|
|
84
|
+
name,
|
|
85
|
+
requested,
|
|
86
|
+
durationMs: clampMs(TRANSITION_MS[name] * SUBTLE_SCALE),
|
|
87
|
+
motion,
|
|
88
|
+
reason: 'subtle',
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
name: requested,
|
|
93
|
+
requested,
|
|
94
|
+
durationMs: clampMs(TRANSITION_MS[requested]),
|
|
95
|
+
motion,
|
|
96
|
+
reason: source,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
export function morphPairsFor(slides, style) {
|
|
100
|
+
const pairs = [];
|
|
101
|
+
for (let i = 1; i < slides.length; i += 1) {
|
|
102
|
+
const to = slides[i];
|
|
103
|
+
const from = slides[i - 1];
|
|
104
|
+
if (!to || !from)
|
|
105
|
+
continue;
|
|
106
|
+
const resolved = resolveDeckTransition({ slide: to, style });
|
|
107
|
+
if (resolved.name === 'morph') {
|
|
108
|
+
pairs.push({ fromSlideId: from.id, toSlideId: to.id });
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return pairs;
|
|
112
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
export interface EngineSlide {
|
|
2
|
+
id: string;
|
|
3
|
+
hidden?: boolean;
|
|
4
|
+
/** Step labels: `steps[i]` names step `i + 1`. */
|
|
5
|
+
steps?: readonly string[];
|
|
6
|
+
blocks?: readonly unknown[];
|
|
7
|
+
props?: unknown;
|
|
8
|
+
layout?: string;
|
|
9
|
+
transition?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface EngineSection {
|
|
12
|
+
id: string;
|
|
13
|
+
slideIds: readonly string[];
|
|
14
|
+
/** When true, the section is a vertical stack (Reveal-style). */
|
|
15
|
+
stack?: boolean;
|
|
16
|
+
}
|
|
17
|
+
export interface EngineDeck {
|
|
18
|
+
slides: readonly EngineSlide[];
|
|
19
|
+
outline?: {
|
|
20
|
+
sections?: readonly EngineSection[];
|
|
21
|
+
};
|
|
22
|
+
navigation?: {
|
|
23
|
+
start?: string;
|
|
24
|
+
loop?: boolean;
|
|
25
|
+
autoSlideMs?: number;
|
|
26
|
+
};
|
|
27
|
+
style?: {
|
|
28
|
+
transition?: string;
|
|
29
|
+
motion?: string;
|
|
30
|
+
aspect?: string;
|
|
31
|
+
progress?: string;
|
|
32
|
+
};
|
|
33
|
+
meta?: {
|
|
34
|
+
locale?: string;
|
|
35
|
+
dir?: 'ltr' | 'rtl' | 'auto';
|
|
36
|
+
title?: string;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/** Current place in the deck (immutable snapshot). */
|
|
40
|
+
export interface DeckLocation {
|
|
41
|
+
/** Index into the full `deck.slides` array. */
|
|
42
|
+
slideIndex: number;
|
|
43
|
+
slideId: string;
|
|
44
|
+
/** 0-based step on the current slide. */
|
|
45
|
+
step: number;
|
|
46
|
+
/** Maximum step index (number of advances). Navigable range is 0…stepCount. */
|
|
47
|
+
stepCount: number;
|
|
48
|
+
/** Set when the slide belongs to a stacked outline section. */
|
|
49
|
+
sectionId?: string;
|
|
50
|
+
/** 0-based index inside the stacked section. */
|
|
51
|
+
verticalIndex?: number;
|
|
52
|
+
}
|
|
53
|
+
export interface NavigatorOptions {
|
|
54
|
+
initialSlideId?: string;
|
|
55
|
+
initialStep?: number;
|
|
56
|
+
/**
|
|
57
|
+
* How many advances each slide has (max step index). Defaults to
|
|
58
|
+
* {@link modelSlideStepCount}.
|
|
59
|
+
*/
|
|
60
|
+
stepCount?: (slide: EngineSlide) => number;
|
|
61
|
+
}
|
|
62
|
+
export interface DeckNavigator {
|
|
63
|
+
getLocation(): DeckLocation;
|
|
64
|
+
visibleSlides(): readonly EngineSlide[];
|
|
65
|
+
next(): DeckLocation;
|
|
66
|
+
prev(): DeckLocation;
|
|
67
|
+
first(): DeckLocation;
|
|
68
|
+
last(): DeckLocation;
|
|
69
|
+
/**
|
|
70
|
+
* Jump by slide id, by visible index (number), or by a full location.
|
|
71
|
+
* Unknown or hidden ids fall back to the first visible slide.
|
|
72
|
+
*/
|
|
73
|
+
goTo(slide: string | number | DeckLocation, step?: number): DeckLocation;
|
|
74
|
+
goToVertical(sectionId: string, verticalIndex: number, step?: number): DeckLocation;
|
|
75
|
+
stepCountFor(slideId: string): number;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Count distinct positive model-v2 step markers plus explicit step labels.
|
|
79
|
+
* Never throws; unknown shapes contribute nothing. The result is the maximum
|
|
80
|
+
* step index (0 when the slide has no advances).
|
|
81
|
+
*/
|
|
82
|
+
export declare function modelSlideStepCount(slide: EngineSlide): number;
|
|
83
|
+
/**
|
|
84
|
+
* Create a pure navigator over a deck-shaped object. The deck is read once;
|
|
85
|
+
* later mutations of the input are ignored.
|
|
86
|
+
*/
|
|
87
|
+
export declare function createDeckNavigator(deck: EngineDeck, options?: NavigatorOptions): DeckNavigator;
|