rikiki-deck 0.4.0 → 0.6.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/.claude/skills/rikiki-debug/SKILL.md +55 -0
- package/.claude/skills/rikiki-deck/SKILL.md +81 -0
- package/.claude/skills/rikiki-theme/SKILL.md +70 -0
- package/LICENSE +1 -1
- package/README.md +66 -1
- package/bin/rikiki.mjs +35 -2
- package/dist/atoms/deck-code-highlighter.d.ts +6 -0
- package/dist/atoms/deck-code.d.ts +14 -0
- package/dist/click-stages.js +1 -1
- package/dist/color.js +1 -0
- package/dist/deck-code-highlighter.js +1 -0
- package/dist/deck-code.js +2 -2
- package/dist/deck-overview.js +6 -6
- package/dist/deck-presenter.js +53 -13
- package/dist/deck-root.js +5 -5
- package/dist/deck-transition.js +2 -2
- package/dist/index.d.ts +3 -0
- package/dist/index.js +28 -28
- package/dist/livereload.js +1 -1
- package/dist/plugins/click-stages.d.ts +5 -0
- package/dist/runtime/color.d.ts +8 -0
- package/dist/runtime/deck-root.d.ts +153 -11
- package/dist/shiki.js +1 -1
- package/dist/standalone.js +119 -79
- package/docs/llms/rikiki-reference.md +139 -17
- package/llms.txt +5 -3
- package/package.json +15 -4
- package/themes/rikiki.css +10 -13
- package/themes/siliceum.css +10 -12
|
@@ -1,4 +1,39 @@
|
|
|
1
|
-
import { LitElement } from 'lit';
|
|
1
|
+
import { LitElement, type PropertyValues } from 'lit';
|
|
2
|
+
type Slide = HTMLElement & {
|
|
3
|
+
applyStep?: (step: number) => void;
|
|
4
|
+
render?: () => unknown;
|
|
5
|
+
};
|
|
6
|
+
/** The stable surface a plugin may touch · deliberately small so plugins never
|
|
7
|
+
* reach into the engine's private internals (the old approach monkey-patched
|
|
8
|
+
* the prototype's private methods, which broke silently on any rename). */
|
|
9
|
+
export interface DeckContext {
|
|
10
|
+
/** The deck-root element · for ad-hoc first-party coordination markers. */
|
|
11
|
+
readonly host: DeckRoot;
|
|
12
|
+
readonly current: number;
|
|
13
|
+
readonly step: number;
|
|
14
|
+
readonly slides: readonly Slide[];
|
|
15
|
+
requestUpdate(): void;
|
|
16
|
+
}
|
|
17
|
+
/** A deck-root extension. Register one with `deckRoot.use(plugin)` · the engine
|
|
18
|
+
* calls the optional hooks at the matching points. All hooks are optional so a
|
|
19
|
+
* plugin implements only what it needs. */
|
|
20
|
+
export interface DeckPlugin {
|
|
21
|
+
/** Unique name · registration is idempotent by this. */
|
|
22
|
+
name: string;
|
|
23
|
+
/** Run once on registration · may return a teardown run on unregister. */
|
|
24
|
+
setup?(ctx: DeckContext): void | (() => void);
|
|
25
|
+
/** Contribute to the active slide's step count · combined with the engine's
|
|
26
|
+
* own count (and other plugins') as a maximum. Must not call back into the
|
|
27
|
+
* engine's step count. */
|
|
28
|
+
steps?(slide: Slide, ctx: DeckContext): number;
|
|
29
|
+
/** React after the engine applied a step to the active slide. */
|
|
30
|
+
applyStep?(step: number, slide: Slide, ctx: DeckContext): void;
|
|
31
|
+
/** Around-advice for navigation · call `proceed()` to run the real navigation
|
|
32
|
+
* (optionally wrapped, e.g. inside a View Transition). Return a truthy value
|
|
33
|
+
* when handled · otherwise the engine navigates normally. Only the first
|
|
34
|
+
* registered plugin with a `navigate` hook owns navigation. */
|
|
35
|
+
navigate?(to: number, ctx: DeckContext, proceed: () => void): boolean | void;
|
|
36
|
+
}
|
|
2
37
|
export declare class DeckRoot extends LitElement {
|
|
3
38
|
static styles: import("lit").CSSResult;
|
|
4
39
|
current: number;
|
|
@@ -6,20 +41,35 @@ export declare class DeckRoot extends LitElement {
|
|
|
6
41
|
/** When non-null, a full-screen overlay covers the deck (clicker B/./W/,
|
|
7
42
|
* keys). Pressing any key dismisses it · same convention as PowerPoint. */
|
|
8
43
|
blank: 'black' | 'white' | null;
|
|
44
|
+
/** Set by the presenter plugin while the speaker popup is open. The main
|
|
45
|
+
* window is then the projected one, so its key-hint chips and nav arrows are
|
|
46
|
+
* noise · hide them until the popup closes (issue #6). */
|
|
47
|
+
presenterActive: boolean;
|
|
9
48
|
overview: boolean;
|
|
10
|
-
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
*
|
|
49
|
+
/** Fluid rendering · the deck fills its box and reflows like a web page
|
|
50
|
+
* (no logical canvas, no zoom-to-fit scale, no letterbox). Opt-in · the
|
|
51
|
+
* default stays the uniform zoom-to-fit canvas. Toggleable at runtime ·
|
|
52
|
+
* flipping it re-applies the canvas vars, scale and letterbox both ways. */
|
|
53
|
+
fluid: boolean;
|
|
54
|
+
/** Logical canvas size · defaults to 1920 × 1080 (16:9). Only the ratio and
|
|
55
|
+
* the rem baseline depend on these · the canvas is then scaled uniformly to
|
|
56
|
+
* fill the window (see _applyScale). */
|
|
17
57
|
width: number;
|
|
18
58
|
height: number;
|
|
19
59
|
/** Hide the bottom-left keyboard-hint chip (the ←/→ · O · P · ? row). */
|
|
20
60
|
noHint: boolean;
|
|
21
61
|
/** Hide the bottom-right on-screen previous/next navigation arrows. */
|
|
22
62
|
noArrows: boolean;
|
|
63
|
+
/** Hide the bottom-right slide counter (`n / total`) · used by the presenter
|
|
64
|
+
* preview, which already shows the count in its own chrome. */
|
|
65
|
+
noCounter: boolean;
|
|
66
|
+
/** Passive-render mode · the deck still scales/letterboxes but wires NO
|
|
67
|
+
* keyboard, mouse, autoplay or presenter handlers. Used by the presenter
|
|
68
|
+
* preview iframes, which must not hijack keys or open a nested presenter on
|
|
69
|
+
* the shared BroadcastChannel · the speaker drives the real deck instead. */
|
|
70
|
+
preview: boolean;
|
|
71
|
+
/** Disable slide zoom (Ctrl/⌘+wheel, pinch, +/-/0) · on by default. */
|
|
72
|
+
noZoom: boolean;
|
|
23
73
|
/** Optional slide transition · "slide" | "fade" | "zoom". When set, the
|
|
24
74
|
* deck-transition.js plugin is fetched on first navigation. Per-slide
|
|
25
75
|
* override available via `data-transition` on the slide host. */
|
|
@@ -54,7 +104,30 @@ export declare class DeckRoot extends LitElement {
|
|
|
54
104
|
private _navDownY;
|
|
55
105
|
private _wheelAccum;
|
|
56
106
|
private _wheelLockUntil;
|
|
107
|
+
private _zoom;
|
|
108
|
+
private _panX;
|
|
109
|
+
private _panY;
|
|
110
|
+
private static readonly ZOOM_MAX;
|
|
111
|
+
private static readonly ZOOM_STEP;
|
|
112
|
+
private static readonly ZOOM_WHEEL_SENSITIVITY;
|
|
113
|
+
private _plugins;
|
|
114
|
+
private _ctx;
|
|
115
|
+
/** Build (once) the stable context object plugins receive · live getters so a
|
|
116
|
+
* plugin always sees the engine's current position (the object itself is
|
|
117
|
+
* cached, not frozen). */
|
|
118
|
+
private _context;
|
|
119
|
+
/** Register a plugin · idempotent by name. Returns an unregister function that
|
|
120
|
+
* runs the plugin's teardown and detaches its hooks. A freshly registered
|
|
121
|
+
* plugin may change step counts or element visibility, so the active slide is
|
|
122
|
+
* re-applied immediately (this also covers plugins attached after the deck
|
|
123
|
+
* has already rendered). */
|
|
124
|
+
use(plugin: DeckPlugin): () => void;
|
|
57
125
|
firstUpdated(): void;
|
|
126
|
+
/** Canvas vars, scale and every listener the deck needs while connected.
|
|
127
|
+
* Mirror of the disconnectedCallback teardown · runs from firstUpdated on
|
|
128
|
+
* the initial connect, and again from connectedCallback on a re-attach
|
|
129
|
+
* (firstUpdated only ever runs once per element). */
|
|
130
|
+
private _installRuntime;
|
|
58
131
|
/** Confine author `<style scoped>` blocks to their own slide. A light-DOM
|
|
59
132
|
* <style> is a global stylesheet by default, so a per-slide tweak would
|
|
60
133
|
* bleed across the whole deck. Wrapping its body in a native @scope rule
|
|
@@ -62,9 +135,68 @@ export declare class DeckRoot extends LitElement {
|
|
|
62
135
|
* with no selector rewriting · plain CSS inside keeps working unchanged. */
|
|
63
136
|
private _scopeSlideStyles;
|
|
64
137
|
/** Publish the logical canvas size on the document root so both the
|
|
65
|
-
* `html:has(deck-root
|
|
66
|
-
*
|
|
138
|
+
* `html:has(deck-root)` rem-baseline rule and the shadow `#stage` (via
|
|
139
|
+
* custom-property inheritance) size against the same numbers. */
|
|
140
|
+
/** True when the whole deck is fluid, or the active slide opts out of the
|
|
141
|
+
* fixed canvas via its own `fluid` attribute · a per-slide viewport escape
|
|
142
|
+
* (issue #4). It drives the canvas vars, scale and letterbox exactly like
|
|
143
|
+
* the deck-wide `fluid` flag, just for that one slide. */
|
|
144
|
+
private _effectiveFluid;
|
|
145
|
+
/** Reflect the active slide's per-slide fluid escape on the host · the
|
|
146
|
+
* `unfixed` marker that the stage CSS and the injected rem baseline key on ·
|
|
147
|
+
* then re-apply the canvas vars and scale for the new effective mode. Called
|
|
148
|
+
* on every slide change · a no-op for a deck that never uses per-slide fluid. */
|
|
149
|
+
private _applySlideFluid;
|
|
67
150
|
private _applyCanvasVars;
|
|
151
|
+
/** Uniform zoom-to-fit · scale the fixed logical canvas to the largest size
|
|
152
|
+
* that still fits the host's own box (the viewport for a full-window deck,
|
|
153
|
+
* the container for an embedded one). Driven by a ResizeObserver. */
|
|
154
|
+
private _applyScale;
|
|
155
|
+
private _resizeObserver;
|
|
156
|
+
/** Zoom is live only in the fixed canvas and outside overlays. */
|
|
157
|
+
private _zoomEnabled;
|
|
158
|
+
/** Publish zoom + pan as custom props the #stage transform reads. */
|
|
159
|
+
private _applyZoom;
|
|
160
|
+
/** Keep the pan within bounds so the magnified stage always covers the
|
|
161
|
+
* viewport (no gaps); at fit (zoom 1) it forces re-centring. */
|
|
162
|
+
private _clampPan;
|
|
163
|
+
/** Zoom by a factor, keeping the point at viewport (cx, cy) fixed. */
|
|
164
|
+
private _zoomAt;
|
|
165
|
+
private _resetZoom;
|
|
166
|
+
private _panBy;
|
|
167
|
+
private _panning;
|
|
168
|
+
private _panLastX;
|
|
169
|
+
private _panLastY;
|
|
170
|
+
private _onPanDown;
|
|
171
|
+
private _onPanMove;
|
|
172
|
+
private _onPanUp;
|
|
173
|
+
/** Make the letterbox bands match the active slide's background, so a scaled
|
|
174
|
+
* deck blends seamlessly into the bands instead of sitting on a contrasting
|
|
175
|
+
* frame. A slide with no background of its own (transparent) shows the page
|
|
176
|
+
* surface · removing the override lets the bands fall back to that same
|
|
177
|
+
* surface, which stays seamless too. */
|
|
178
|
+
private _applyLetterbox;
|
|
179
|
+
/** The scaling baseline is a framework concern, not a theme one: inject it
|
|
180
|
+
* globally so any theme (or none) gets it. The rem unit tracks the logical
|
|
181
|
+
* canvas height · the #stage transform does the responsive scaling · and the
|
|
182
|
+
* page never scrolls (so the letterbox is the only thing outside a slide).
|
|
183
|
+
* Guarded by the element id (not a static) so separately-bundled copies of
|
|
184
|
+
* this class on one page share the same once-per-document semantics.
|
|
185
|
+
*
|
|
186
|
+
* Every rule is scoped with `:has(> body > deck-root)`, so it is inert
|
|
187
|
+
* unless a deck is a direct <body> child · i.e. a full-page deck. An
|
|
188
|
+
* embedded deck (sitting in some container) never matches, so it leaves the
|
|
189
|
+
* host page's scroll and rem baseline alone.
|
|
190
|
+
*
|
|
191
|
+
* The `:not([fluid])` rule carries the zoom-to-fit canvas baseline; the
|
|
192
|
+
* `[fluid]` rule gives a fluid deck the viewport-relative rem baseline
|
|
193
|
+
* instead. The `[unfixed]` rule (set while the active slide opts out via its
|
|
194
|
+
* own `fluid` attribute) borrows that same viewport baseline for that one
|
|
195
|
+
* slide · it comes last so it wins the equal-specificity tie with the
|
|
196
|
+
* `:not([fluid])` rule. The `height:100%` pair backs the 100% `:host`
|
|
197
|
+
* sizing. */
|
|
198
|
+
private static _injectGlobals;
|
|
199
|
+
connectedCallback(): void;
|
|
68
200
|
disconnectedCallback(): void;
|
|
69
201
|
private _startAutoplay;
|
|
70
202
|
private _stopAutoplay;
|
|
@@ -111,14 +243,23 @@ export declare class DeckRoot extends LitElement {
|
|
|
111
243
|
/** Lazy-import the overview module the first time the user opens it. */
|
|
112
244
|
private _renderOverviewIfActive;
|
|
113
245
|
private _maxSteps;
|
|
246
|
+
/** The engine's own step count for the active slide · `steps`/`data-steps`
|
|
247
|
+
* attribute, or a `deck-code[step-groups]` group count. Plugins extend this
|
|
248
|
+
* through their `steps` hook (see _maxSteps). */
|
|
249
|
+
private _baseMaxSteps;
|
|
114
250
|
private _advance;
|
|
115
251
|
private _back;
|
|
116
252
|
private _goTo;
|
|
253
|
+
private _goToNow;
|
|
117
254
|
private _goToCoords;
|
|
118
255
|
private _applyActive;
|
|
119
256
|
private _applyStep;
|
|
257
|
+
/** The bottom-right slide counter is noise in modes where it shouldn't show:
|
|
258
|
+
* the overview grid, a black/white blanked screen, and the cover slide (the
|
|
259
|
+
* title slide has no business carrying a page number). */
|
|
260
|
+
private _counterHidden;
|
|
120
261
|
private _updateUI;
|
|
121
|
-
updated(): void;
|
|
262
|
+
updated(changed: PropertyValues<this>): void;
|
|
122
263
|
private _navArrows;
|
|
123
264
|
render(): unknown;
|
|
124
265
|
}
|
|
@@ -127,3 +268,4 @@ declare global {
|
|
|
127
268
|
'deck-root': DeckRoot;
|
|
128
269
|
}
|
|
129
270
|
}
|
|
271
|
+
export {};
|
package/dist/shiki.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
function n(e){let i=customElements.get("deck-code");if(!i){console.warn("[rikiki/deck-code] <deck-code> is not defined yet \xB7 import rikiki first");return}i.highlighter=e,i.rehighlightAll()}var t=null,l="one-dark-pro";async function s(e){return t||(t=await(globalThis.__rikikiShiki??(await import(new URL("./vendor/shiki.js",import.meta.url).href)).createHighlighter)({themes:[e.theme],langs:e.langs}),t)}async function d(e={}){let i={theme:e.theme??"one-dark-pro",langs:e.langs??["ts","js","html","css","json"]};l=i.theme;let r=await s(i);n((o,h)=>{try{return r.codeToHtml(o,{lang:h||"txt",theme:l}).replace(/^<pre[^>]*><code[^>]*>/,"").replace(/<\/code><\/pre>$/,"")}catch{return null}})}export{d as installShiki};
|