@reslide-dev/core 0.1.0 → 0.2.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/dist/index.d.mts +21 -2
- package/dist/index.mjs +601 -120
- package/package.json +12 -12
package/dist/index.d.mts
CHANGED
|
@@ -123,6 +123,8 @@ interface PresenterViewProps {
|
|
|
123
123
|
/**
|
|
124
124
|
* Presenter view that syncs with the main presentation window.
|
|
125
125
|
* Shows: current slide, next slide preview, notes, and timer.
|
|
126
|
+
* Supports bidirectional control — navigate from this window to
|
|
127
|
+
* drive the main presentation.
|
|
126
128
|
*/
|
|
127
129
|
declare function PresenterView({
|
|
128
130
|
children,
|
|
@@ -143,6 +145,8 @@ declare function isPresenterView(): boolean;
|
|
|
143
145
|
interface DrawingLayerProps {
|
|
144
146
|
/** Whether drawing mode is active */
|
|
145
147
|
active: boolean;
|
|
148
|
+
/** Current slide index — drawings are stored per slide */
|
|
149
|
+
currentSlide: number;
|
|
146
150
|
/** Pen color */
|
|
147
151
|
color?: string;
|
|
148
152
|
/** Pen width */
|
|
@@ -150,10 +154,12 @@ interface DrawingLayerProps {
|
|
|
150
154
|
}
|
|
151
155
|
/**
|
|
152
156
|
* Canvas-based freehand drawing overlay for presentations.
|
|
153
|
-
*
|
|
157
|
+
* Drawings are stored per slide and persist across navigation.
|
|
158
|
+
* Toggle with `d` key, clear current slide with `c` key.
|
|
154
159
|
*/
|
|
155
160
|
declare function DrawingLayer({
|
|
156
161
|
active,
|
|
162
|
+
currentSlide,
|
|
157
163
|
color,
|
|
158
164
|
width
|
|
159
165
|
}: DrawingLayerProps): react_jsx_runtime0.JSX.Element;
|
|
@@ -314,6 +320,19 @@ declare function ClickNavigation({
|
|
|
314
320
|
disabled
|
|
315
321
|
}: ClickNavigationProps): react_jsx_runtime0.JSX.Element | null;
|
|
316
322
|
//#endregion
|
|
323
|
+
//#region src/NavigationBar.d.ts
|
|
324
|
+
/**
|
|
325
|
+
* Slidev-style navigation bar that appears on hover at the bottom of the presentation.
|
|
326
|
+
* Provides buttons for prev/next, overview, fullscreen, presenter, and drawing modes.
|
|
327
|
+
*/
|
|
328
|
+
declare function NavigationBar({
|
|
329
|
+
isDrawing,
|
|
330
|
+
onToggleDrawing
|
|
331
|
+
}: {
|
|
332
|
+
isDrawing: boolean;
|
|
333
|
+
onToggleDrawing: () => void;
|
|
334
|
+
}): react_jsx_runtime0.JSX.Element;
|
|
335
|
+
//#endregion
|
|
317
336
|
//#region src/ProgressBar.d.ts
|
|
318
337
|
declare function ProgressBar(): react_jsx_runtime0.JSX.Element;
|
|
319
338
|
//#endregion
|
|
@@ -391,4 +410,4 @@ declare function useDeck(): DeckContextValue;
|
|
|
391
410
|
declare const SlideIndexContext: react.Context<number | null>;
|
|
392
411
|
declare function useSlideIndex(): number;
|
|
393
412
|
//#endregion
|
|
394
|
-
export { Click, ClickNavigation, type ClickProps, ClickSteps, CodeEditor, type CodeEditorProps, Deck, type DeckActions, DeckContext, type DeckContextValue, type DeckProps, type DeckState, Draggable, type DraggableProps, DrawingLayer, type DrawingLayerProps, GlobalLayer, type GlobalLayerProps, Mark, type MarkProps, Mermaid, type MermaidProps, Notes, type NotesProps, PresenterView, type PresenterViewProps, PrintView, ProgressBar, ReslideEmbed, type ReslideEmbedProps, Slide, SlideIndexContext, type SlideProps, SlotRight, Toc, type TocProps, type TransitionType, isPresenterView, openPresenterWindow, useDeck, useSlideIndex };
|
|
413
|
+
export { Click, ClickNavigation, type ClickProps, ClickSteps, CodeEditor, type CodeEditorProps, Deck, type DeckActions, DeckContext, type DeckContextValue, type DeckProps, type DeckState, Draggable, type DraggableProps, DrawingLayer, type DrawingLayerProps, GlobalLayer, type GlobalLayerProps, Mark, type MarkProps, Mermaid, type MermaidProps, NavigationBar, Notes, type NotesProps, PresenterView, type PresenterViewProps, PrintView, ProgressBar, ReslideEmbed, type ReslideEmbedProps, Slide, SlideIndexContext, type SlideProps, SlotRight, Toc, type TocProps, type TransitionType, isPresenterView, openPresenterWindow, useDeck, useSlideIndex };
|
package/dist/index.mjs
CHANGED
|
@@ -78,12 +78,56 @@ function useDeck() {
|
|
|
78
78
|
//#region src/DrawingLayer.tsx
|
|
79
79
|
/**
|
|
80
80
|
* Canvas-based freehand drawing overlay for presentations.
|
|
81
|
-
*
|
|
81
|
+
* Drawings are stored per slide and persist across navigation.
|
|
82
|
+
* Toggle with `d` key, clear current slide with `c` key.
|
|
82
83
|
*/
|
|
83
|
-
function DrawingLayer({ active, color = "#ef4444", width = 3 }) {
|
|
84
|
+
function DrawingLayer({ active, currentSlide, color = "#ef4444", width = 3 }) {
|
|
84
85
|
const canvasRef = useRef(null);
|
|
85
86
|
const [isDrawing, setIsDrawing] = useState(false);
|
|
86
87
|
const lastPoint = useRef(null);
|
|
88
|
+
const drawingsRef = useRef(/* @__PURE__ */ new Map());
|
|
89
|
+
const prevSlideRef = useRef(currentSlide);
|
|
90
|
+
const getCanvasSize = useCallback(() => {
|
|
91
|
+
const canvas = canvasRef.current;
|
|
92
|
+
if (!canvas) return {
|
|
93
|
+
w: 0,
|
|
94
|
+
h: 0
|
|
95
|
+
};
|
|
96
|
+
return {
|
|
97
|
+
w: canvas.width,
|
|
98
|
+
h: canvas.height
|
|
99
|
+
};
|
|
100
|
+
}, []);
|
|
101
|
+
const saveCurrentSlide = useCallback((slideIndex) => {
|
|
102
|
+
const canvas = canvasRef.current;
|
|
103
|
+
const ctx = canvas?.getContext("2d");
|
|
104
|
+
if (!ctx || !canvas) return;
|
|
105
|
+
const { w, h } = getCanvasSize();
|
|
106
|
+
if (w === 0 || h === 0) return;
|
|
107
|
+
const imageData = ctx.getImageData(0, 0, w, h);
|
|
108
|
+
if (imageData.data.some((_, i) => i % 4 === 3 && imageData.data[i] > 0)) drawingsRef.current.set(slideIndex, imageData);
|
|
109
|
+
else drawingsRef.current.delete(slideIndex);
|
|
110
|
+
}, [getCanvasSize]);
|
|
111
|
+
const restoreSlide = useCallback((slideIndex) => {
|
|
112
|
+
const canvas = canvasRef.current;
|
|
113
|
+
const ctx = canvas?.getContext("2d");
|
|
114
|
+
if (!ctx || !canvas) return;
|
|
115
|
+
const { w, h } = getCanvasSize();
|
|
116
|
+
ctx.clearRect(0, 0, w, h);
|
|
117
|
+
const saved = drawingsRef.current.get(slideIndex);
|
|
118
|
+
if (saved && saved.width === w && saved.height === h) ctx.putImageData(saved, 0, 0);
|
|
119
|
+
}, [getCanvasSize]);
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
if (prevSlideRef.current !== currentSlide) {
|
|
122
|
+
saveCurrentSlide(prevSlideRef.current);
|
|
123
|
+
restoreSlide(currentSlide);
|
|
124
|
+
prevSlideRef.current = currentSlide;
|
|
125
|
+
}
|
|
126
|
+
}, [
|
|
127
|
+
currentSlide,
|
|
128
|
+
saveCurrentSlide,
|
|
129
|
+
restoreSlide
|
|
130
|
+
]);
|
|
87
131
|
const getPoint = useCallback((e) => {
|
|
88
132
|
const canvas = canvasRef.current;
|
|
89
133
|
const rect = canvas.getBoundingClientRect();
|
|
@@ -127,26 +171,35 @@ function DrawingLayer({ active, color = "#ef4444", width = 3 }) {
|
|
|
127
171
|
if (!canvas) return;
|
|
128
172
|
const resize = () => {
|
|
129
173
|
const rect = canvas.parentElement?.getBoundingClientRect();
|
|
130
|
-
if (rect)
|
|
131
|
-
|
|
132
|
-
|
|
174
|
+
if (!rect) return;
|
|
175
|
+
const newWidth = rect.width * window.devicePixelRatio;
|
|
176
|
+
const newHeight = rect.height * window.devicePixelRatio;
|
|
177
|
+
if (canvas.width !== newWidth || canvas.height !== newHeight) {
|
|
178
|
+
saveCurrentSlide(currentSlide);
|
|
179
|
+
drawingsRef.current.clear();
|
|
180
|
+
canvas.width = newWidth;
|
|
181
|
+
canvas.height = newHeight;
|
|
133
182
|
}
|
|
134
183
|
};
|
|
135
184
|
resize();
|
|
136
185
|
window.addEventListener("resize", resize);
|
|
137
186
|
return () => window.removeEventListener("resize", resize);
|
|
138
|
-
}, []);
|
|
187
|
+
}, [currentSlide, saveCurrentSlide]);
|
|
139
188
|
useEffect(() => {
|
|
140
189
|
if (!active) return;
|
|
141
190
|
function handleKey(e) {
|
|
142
191
|
if (e.key === "c") {
|
|
143
|
-
const
|
|
144
|
-
|
|
192
|
+
const canvas = canvasRef.current;
|
|
193
|
+
const ctx = canvas?.getContext("2d");
|
|
194
|
+
if (ctx && canvas) {
|
|
195
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
196
|
+
drawingsRef.current.delete(currentSlide);
|
|
197
|
+
}
|
|
145
198
|
}
|
|
146
199
|
}
|
|
147
200
|
window.addEventListener("keydown", handleKey);
|
|
148
201
|
return () => window.removeEventListener("keydown", handleKey);
|
|
149
|
-
}, [active]);
|
|
202
|
+
}, [active, currentSlide]);
|
|
150
203
|
return /* @__PURE__ */ jsx("canvas", {
|
|
151
204
|
ref: canvasRef,
|
|
152
205
|
onMouseDown: startDraw,
|
|
@@ -165,6 +218,412 @@ function DrawingLayer({ active, color = "#ef4444", width = 3 }) {
|
|
|
165
218
|
});
|
|
166
219
|
}
|
|
167
220
|
//#endregion
|
|
221
|
+
//#region src/use-presenter.ts
|
|
222
|
+
const CHANNEL_NAME = "reslide-presenter";
|
|
223
|
+
/**
|
|
224
|
+
* Hook for syncing presentation state across windows via BroadcastChannel.
|
|
225
|
+
* The main presentation window broadcasts state changes and listens for
|
|
226
|
+
* navigation commands from the presenter window.
|
|
227
|
+
*/
|
|
228
|
+
function usePresenterSync(currentSlide, clickStep, handlers) {
|
|
229
|
+
const channelRef = useRef(null);
|
|
230
|
+
useEffect(() => {
|
|
231
|
+
if (typeof BroadcastChannel === "undefined") return;
|
|
232
|
+
const channel = new BroadcastChannel(CHANNEL_NAME);
|
|
233
|
+
channelRef.current = channel;
|
|
234
|
+
if (handlers) channel.onmessage = (e) => {
|
|
235
|
+
if (e.data.type === "navigate") switch (e.data.action) {
|
|
236
|
+
case "next":
|
|
237
|
+
handlers.next();
|
|
238
|
+
break;
|
|
239
|
+
case "prev":
|
|
240
|
+
handlers.prev();
|
|
241
|
+
break;
|
|
242
|
+
case "goTo":
|
|
243
|
+
if (e.data.slideIndex != null) handlers.goTo(e.data.slideIndex);
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
return () => {
|
|
248
|
+
channel.close();
|
|
249
|
+
channelRef.current = null;
|
|
250
|
+
};
|
|
251
|
+
}, [handlers]);
|
|
252
|
+
useEffect(() => {
|
|
253
|
+
channelRef.current?.postMessage({
|
|
254
|
+
type: "sync",
|
|
255
|
+
currentSlide,
|
|
256
|
+
clickStep
|
|
257
|
+
});
|
|
258
|
+
}, [currentSlide, clickStep]);
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Hook for the presenter window to listen for sync messages and send
|
|
262
|
+
* navigation commands back to the main window.
|
|
263
|
+
*/
|
|
264
|
+
function usePresenterChannel(onSync) {
|
|
265
|
+
const channelRef = useRef(null);
|
|
266
|
+
const onSyncRef = useRef(onSync);
|
|
267
|
+
onSyncRef.current = onSync;
|
|
268
|
+
useEffect(() => {
|
|
269
|
+
if (typeof BroadcastChannel === "undefined") return;
|
|
270
|
+
const channel = new BroadcastChannel(CHANNEL_NAME);
|
|
271
|
+
channelRef.current = channel;
|
|
272
|
+
channel.onmessage = (e) => {
|
|
273
|
+
if (e.data.type === "sync") onSyncRef.current(e.data);
|
|
274
|
+
};
|
|
275
|
+
return () => {
|
|
276
|
+
channel.close();
|
|
277
|
+
channelRef.current = null;
|
|
278
|
+
};
|
|
279
|
+
}, []);
|
|
280
|
+
return {
|
|
281
|
+
next: useCallback(() => {
|
|
282
|
+
channelRef.current?.postMessage({
|
|
283
|
+
type: "navigate",
|
|
284
|
+
action: "next"
|
|
285
|
+
});
|
|
286
|
+
}, []),
|
|
287
|
+
prev: useCallback(() => {
|
|
288
|
+
channelRef.current?.postMessage({
|
|
289
|
+
type: "navigate",
|
|
290
|
+
action: "prev"
|
|
291
|
+
});
|
|
292
|
+
}, []),
|
|
293
|
+
goTo: useCallback((index) => {
|
|
294
|
+
channelRef.current?.postMessage({
|
|
295
|
+
type: "navigate",
|
|
296
|
+
action: "goTo",
|
|
297
|
+
slideIndex: index
|
|
298
|
+
});
|
|
299
|
+
}, [])
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Opens the presenter window at the /presenter route.
|
|
304
|
+
*/
|
|
305
|
+
function openPresenterWindow() {
|
|
306
|
+
const url = new URL(window.location.href);
|
|
307
|
+
url.searchParams.set("presenter", "true");
|
|
308
|
+
window.open(url.toString(), "reslide-presenter", "width=1024,height=768,menubar=no,toolbar=no");
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Check if the current window is the presenter view.
|
|
312
|
+
*/
|
|
313
|
+
function isPresenterView() {
|
|
314
|
+
if (typeof window === "undefined") return false;
|
|
315
|
+
return new URLSearchParams(window.location.search).get("presenter") === "true";
|
|
316
|
+
}
|
|
317
|
+
//#endregion
|
|
318
|
+
//#region src/NavigationBar.tsx
|
|
319
|
+
/**
|
|
320
|
+
* Slidev-style navigation bar that appears on hover at the bottom of the presentation.
|
|
321
|
+
* Provides buttons for prev/next, overview, fullscreen, presenter, and drawing modes.
|
|
322
|
+
*/
|
|
323
|
+
function NavigationBar({ isDrawing, onToggleDrawing }) {
|
|
324
|
+
const { currentSlide, totalSlides, clickStep, totalClickSteps, isOverview, isFullscreen, next, prev, toggleOverview, toggleFullscreen } = useDeck();
|
|
325
|
+
const [visible, setVisible] = useState(false);
|
|
326
|
+
const timerRef = useRef(null);
|
|
327
|
+
const barRef = useRef(null);
|
|
328
|
+
const showBar = useCallback(() => {
|
|
329
|
+
setVisible(true);
|
|
330
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
331
|
+
timerRef.current = setTimeout(() => setVisible(false), 3e3);
|
|
332
|
+
}, []);
|
|
333
|
+
useEffect(() => {
|
|
334
|
+
function handleMouseMove(e) {
|
|
335
|
+
const threshold = window.innerHeight - 80;
|
|
336
|
+
if (e.clientY > threshold) showBar();
|
|
337
|
+
}
|
|
338
|
+
window.addEventListener("mousemove", handleMouseMove);
|
|
339
|
+
return () => window.removeEventListener("mousemove", handleMouseMove);
|
|
340
|
+
}, [showBar]);
|
|
341
|
+
const handleMouseEnter = () => {
|
|
342
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
343
|
+
setVisible(true);
|
|
344
|
+
};
|
|
345
|
+
const handleMouseLeave = () => {
|
|
346
|
+
timerRef.current = setTimeout(() => setVisible(false), 1500);
|
|
347
|
+
};
|
|
348
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
349
|
+
ref: barRef,
|
|
350
|
+
className: "reslide-navbar",
|
|
351
|
+
onMouseEnter: handleMouseEnter,
|
|
352
|
+
onMouseLeave: handleMouseLeave,
|
|
353
|
+
style: {
|
|
354
|
+
position: "absolute",
|
|
355
|
+
bottom: 0,
|
|
356
|
+
left: "50%",
|
|
357
|
+
transform: `translateX(-50%) translateY(${visible ? "0" : "100%"})`,
|
|
358
|
+
display: "flex",
|
|
359
|
+
alignItems: "center",
|
|
360
|
+
gap: "0.25rem",
|
|
361
|
+
padding: "0.375rem 0.75rem",
|
|
362
|
+
backgroundColor: "rgba(0, 0, 0, 0.7)",
|
|
363
|
+
backdropFilter: "blur(8px)",
|
|
364
|
+
borderRadius: "0.5rem 0.5rem 0 0",
|
|
365
|
+
transition: "transform 0.25s ease, opacity 0.25s ease",
|
|
366
|
+
opacity: visible ? 1 : 0,
|
|
367
|
+
zIndex: 200,
|
|
368
|
+
color: "#e2e8f0",
|
|
369
|
+
fontSize: "0.8125rem",
|
|
370
|
+
fontFamily: "system-ui, sans-serif",
|
|
371
|
+
fontVariantNumeric: "tabular-nums",
|
|
372
|
+
pointerEvents: visible ? "auto" : "none"
|
|
373
|
+
},
|
|
374
|
+
children: [
|
|
375
|
+
/* @__PURE__ */ jsx(NavButton, {
|
|
376
|
+
onClick: prev,
|
|
377
|
+
title: "Previous (←)",
|
|
378
|
+
disabled: isOverview,
|
|
379
|
+
children: /* @__PURE__ */ jsx(ArrowIcon, { direction: "left" })
|
|
380
|
+
}),
|
|
381
|
+
/* @__PURE__ */ jsxs("span", {
|
|
382
|
+
style: {
|
|
383
|
+
padding: "0 0.5rem",
|
|
384
|
+
userSelect: "none",
|
|
385
|
+
whiteSpace: "nowrap"
|
|
386
|
+
},
|
|
387
|
+
children: [
|
|
388
|
+
currentSlide + 1,
|
|
389
|
+
" / ",
|
|
390
|
+
totalSlides,
|
|
391
|
+
clickStep > 0 && totalClickSteps > 0 && /* @__PURE__ */ jsxs("span", {
|
|
392
|
+
style: {
|
|
393
|
+
opacity: .6,
|
|
394
|
+
marginLeft: "0.25rem"
|
|
395
|
+
},
|
|
396
|
+
children: [
|
|
397
|
+
"(",
|
|
398
|
+
clickStep,
|
|
399
|
+
"/",
|
|
400
|
+
totalClickSteps,
|
|
401
|
+
")"
|
|
402
|
+
]
|
|
403
|
+
})
|
|
404
|
+
]
|
|
405
|
+
}),
|
|
406
|
+
/* @__PURE__ */ jsx(NavButton, {
|
|
407
|
+
onClick: next,
|
|
408
|
+
title: "Next (→ / Space)",
|
|
409
|
+
disabled: isOverview,
|
|
410
|
+
children: /* @__PURE__ */ jsx(ArrowIcon, { direction: "right" })
|
|
411
|
+
}),
|
|
412
|
+
/* @__PURE__ */ jsx(Divider, {}),
|
|
413
|
+
/* @__PURE__ */ jsx(NavButton, {
|
|
414
|
+
onClick: toggleOverview,
|
|
415
|
+
title: "Overview (Esc)",
|
|
416
|
+
active: isOverview,
|
|
417
|
+
children: /* @__PURE__ */ jsx(GridIcon, {})
|
|
418
|
+
}),
|
|
419
|
+
/* @__PURE__ */ jsx(NavButton, {
|
|
420
|
+
onClick: toggleFullscreen,
|
|
421
|
+
title: "Fullscreen (f)",
|
|
422
|
+
active: isFullscreen,
|
|
423
|
+
children: /* @__PURE__ */ jsx(FullscreenIcon, { expanded: isFullscreen })
|
|
424
|
+
}),
|
|
425
|
+
/* @__PURE__ */ jsx(NavButton, {
|
|
426
|
+
onClick: openPresenterWindow,
|
|
427
|
+
title: "Presenter (p)",
|
|
428
|
+
children: /* @__PURE__ */ jsx(PresenterIcon, {})
|
|
429
|
+
}),
|
|
430
|
+
/* @__PURE__ */ jsx(NavButton, {
|
|
431
|
+
onClick: onToggleDrawing,
|
|
432
|
+
title: "Drawing (d)",
|
|
433
|
+
active: isDrawing,
|
|
434
|
+
children: /* @__PURE__ */ jsx(PenIcon, {})
|
|
435
|
+
})
|
|
436
|
+
]
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
function NavButton({ children, onClick, title, active, disabled }) {
|
|
440
|
+
return /* @__PURE__ */ jsx("button", {
|
|
441
|
+
type: "button",
|
|
442
|
+
onClick,
|
|
443
|
+
title,
|
|
444
|
+
disabled,
|
|
445
|
+
style: {
|
|
446
|
+
display: "flex",
|
|
447
|
+
alignItems: "center",
|
|
448
|
+
justifyContent: "center",
|
|
449
|
+
width: "2rem",
|
|
450
|
+
height: "2rem",
|
|
451
|
+
background: active ? "rgba(255,255,255,0.2)" : "none",
|
|
452
|
+
border: "none",
|
|
453
|
+
borderRadius: "0.25rem",
|
|
454
|
+
cursor: disabled ? "default" : "pointer",
|
|
455
|
+
color: active ? "#fff" : "#cbd5e1",
|
|
456
|
+
opacity: disabled ? .4 : 1,
|
|
457
|
+
transition: "background 0.15s, color 0.15s",
|
|
458
|
+
padding: 0
|
|
459
|
+
},
|
|
460
|
+
onMouseEnter: (e) => {
|
|
461
|
+
if (!disabled) e.currentTarget.style.background = "rgba(255,255,255,0.15)";
|
|
462
|
+
},
|
|
463
|
+
onMouseLeave: (e) => {
|
|
464
|
+
e.currentTarget.style.background = active ? "rgba(255,255,255,0.2)" : "none";
|
|
465
|
+
},
|
|
466
|
+
children
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
function Divider() {
|
|
470
|
+
return /* @__PURE__ */ jsx("div", { style: {
|
|
471
|
+
width: 1,
|
|
472
|
+
height: "1.25rem",
|
|
473
|
+
backgroundColor: "rgba(255,255,255,0.2)",
|
|
474
|
+
margin: "0 0.25rem"
|
|
475
|
+
} });
|
|
476
|
+
}
|
|
477
|
+
function ArrowIcon({ direction }) {
|
|
478
|
+
return /* @__PURE__ */ jsx("svg", {
|
|
479
|
+
width: "16",
|
|
480
|
+
height: "16",
|
|
481
|
+
viewBox: "0 0 24 24",
|
|
482
|
+
fill: "none",
|
|
483
|
+
stroke: "currentColor",
|
|
484
|
+
strokeWidth: "2",
|
|
485
|
+
strokeLinecap: "round",
|
|
486
|
+
strokeLinejoin: "round",
|
|
487
|
+
children: direction === "left" ? /* @__PURE__ */ jsx("polyline", { points: "15 18 9 12 15 6" }) : /* @__PURE__ */ jsx("polyline", { points: "9 6 15 12 9 18" })
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
function GridIcon() {
|
|
491
|
+
return /* @__PURE__ */ jsxs("svg", {
|
|
492
|
+
width: "16",
|
|
493
|
+
height: "16",
|
|
494
|
+
viewBox: "0 0 24 24",
|
|
495
|
+
fill: "none",
|
|
496
|
+
stroke: "currentColor",
|
|
497
|
+
strokeWidth: "2",
|
|
498
|
+
strokeLinecap: "round",
|
|
499
|
+
strokeLinejoin: "round",
|
|
500
|
+
children: [
|
|
501
|
+
/* @__PURE__ */ jsx("rect", {
|
|
502
|
+
x: "3",
|
|
503
|
+
y: "3",
|
|
504
|
+
width: "7",
|
|
505
|
+
height: "7"
|
|
506
|
+
}),
|
|
507
|
+
/* @__PURE__ */ jsx("rect", {
|
|
508
|
+
x: "14",
|
|
509
|
+
y: "3",
|
|
510
|
+
width: "7",
|
|
511
|
+
height: "7"
|
|
512
|
+
}),
|
|
513
|
+
/* @__PURE__ */ jsx("rect", {
|
|
514
|
+
x: "3",
|
|
515
|
+
y: "14",
|
|
516
|
+
width: "7",
|
|
517
|
+
height: "7"
|
|
518
|
+
}),
|
|
519
|
+
/* @__PURE__ */ jsx("rect", {
|
|
520
|
+
x: "14",
|
|
521
|
+
y: "14",
|
|
522
|
+
width: "7",
|
|
523
|
+
height: "7"
|
|
524
|
+
})
|
|
525
|
+
]
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
function FullscreenIcon({ expanded }) {
|
|
529
|
+
return /* @__PURE__ */ jsx("svg", {
|
|
530
|
+
width: "16",
|
|
531
|
+
height: "16",
|
|
532
|
+
viewBox: "0 0 24 24",
|
|
533
|
+
fill: "none",
|
|
534
|
+
stroke: "currentColor",
|
|
535
|
+
strokeWidth: "2",
|
|
536
|
+
strokeLinecap: "round",
|
|
537
|
+
strokeLinejoin: "round",
|
|
538
|
+
children: expanded ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
539
|
+
/* @__PURE__ */ jsx("polyline", { points: "4 14 10 14 10 20" }),
|
|
540
|
+
/* @__PURE__ */ jsx("polyline", { points: "20 10 14 10 14 4" }),
|
|
541
|
+
/* @__PURE__ */ jsx("line", {
|
|
542
|
+
x1: "14",
|
|
543
|
+
y1: "10",
|
|
544
|
+
x2: "21",
|
|
545
|
+
y2: "3"
|
|
546
|
+
}),
|
|
547
|
+
/* @__PURE__ */ jsx("line", {
|
|
548
|
+
x1: "3",
|
|
549
|
+
y1: "21",
|
|
550
|
+
x2: "10",
|
|
551
|
+
y2: "14"
|
|
552
|
+
})
|
|
553
|
+
] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
554
|
+
/* @__PURE__ */ jsx("polyline", { points: "15 3 21 3 21 9" }),
|
|
555
|
+
/* @__PURE__ */ jsx("polyline", { points: "9 21 3 21 3 15" }),
|
|
556
|
+
/* @__PURE__ */ jsx("line", {
|
|
557
|
+
x1: "21",
|
|
558
|
+
y1: "3",
|
|
559
|
+
x2: "14",
|
|
560
|
+
y2: "10"
|
|
561
|
+
}),
|
|
562
|
+
/* @__PURE__ */ jsx("line", {
|
|
563
|
+
x1: "3",
|
|
564
|
+
y1: "21",
|
|
565
|
+
x2: "10",
|
|
566
|
+
y2: "14"
|
|
567
|
+
})
|
|
568
|
+
] })
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
function PresenterIcon() {
|
|
572
|
+
return /* @__PURE__ */ jsxs("svg", {
|
|
573
|
+
width: "16",
|
|
574
|
+
height: "16",
|
|
575
|
+
viewBox: "0 0 24 24",
|
|
576
|
+
fill: "none",
|
|
577
|
+
stroke: "currentColor",
|
|
578
|
+
strokeWidth: "2",
|
|
579
|
+
strokeLinecap: "round",
|
|
580
|
+
strokeLinejoin: "round",
|
|
581
|
+
children: [
|
|
582
|
+
/* @__PURE__ */ jsx("rect", {
|
|
583
|
+
x: "2",
|
|
584
|
+
y: "3",
|
|
585
|
+
width: "20",
|
|
586
|
+
height: "14",
|
|
587
|
+
rx: "2"
|
|
588
|
+
}),
|
|
589
|
+
/* @__PURE__ */ jsx("line", {
|
|
590
|
+
x1: "8",
|
|
591
|
+
y1: "21",
|
|
592
|
+
x2: "16",
|
|
593
|
+
y2: "21"
|
|
594
|
+
}),
|
|
595
|
+
/* @__PURE__ */ jsx("line", {
|
|
596
|
+
x1: "12",
|
|
597
|
+
y1: "17",
|
|
598
|
+
x2: "12",
|
|
599
|
+
y2: "21"
|
|
600
|
+
})
|
|
601
|
+
]
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
function PenIcon() {
|
|
605
|
+
return /* @__PURE__ */ jsxs("svg", {
|
|
606
|
+
width: "16",
|
|
607
|
+
height: "16",
|
|
608
|
+
viewBox: "0 0 24 24",
|
|
609
|
+
fill: "none",
|
|
610
|
+
stroke: "currentColor",
|
|
611
|
+
strokeWidth: "2",
|
|
612
|
+
strokeLinecap: "round",
|
|
613
|
+
strokeLinejoin: "round",
|
|
614
|
+
children: [
|
|
615
|
+
/* @__PURE__ */ jsx("path", { d: "M12 19l7-7 3 3-7 7-3-3z" }),
|
|
616
|
+
/* @__PURE__ */ jsx("path", { d: "M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z" }),
|
|
617
|
+
/* @__PURE__ */ jsx("path", { d: "M2 2l7.586 7.586" }),
|
|
618
|
+
/* @__PURE__ */ jsx("circle", {
|
|
619
|
+
cx: "11",
|
|
620
|
+
cy: "11",
|
|
621
|
+
r: "2"
|
|
622
|
+
})
|
|
623
|
+
]
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
//#endregion
|
|
168
627
|
//#region src/slide-context.ts
|
|
169
628
|
const SlideIndexContext = createContext(null);
|
|
170
629
|
function useSlideIndex() {
|
|
@@ -248,7 +707,6 @@ function SlideTransition({ children, currentSlide, transition }) {
|
|
|
248
707
|
value: displaySlide,
|
|
249
708
|
children: /* @__PURE__ */ jsx("div", {
|
|
250
709
|
className: "reslide-transition-slide",
|
|
251
|
-
style: { position: "relative" },
|
|
252
710
|
children: slides[displaySlide]
|
|
253
711
|
})
|
|
254
712
|
})
|
|
@@ -298,50 +756,6 @@ function useFullscreen(ref) {
|
|
|
298
756
|
};
|
|
299
757
|
}
|
|
300
758
|
//#endregion
|
|
301
|
-
//#region src/use-presenter.ts
|
|
302
|
-
const CHANNEL_NAME = "reslide-presenter";
|
|
303
|
-
/**
|
|
304
|
-
* Hook for syncing presentation state across windows via BroadcastChannel.
|
|
305
|
-
* The main presentation window broadcasts state changes.
|
|
306
|
-
*/
|
|
307
|
-
function usePresenterSync(currentSlide, clickStep, onReceive) {
|
|
308
|
-
const channelRef = useRef(null);
|
|
309
|
-
useEffect(() => {
|
|
310
|
-
if (typeof BroadcastChannel === "undefined") return;
|
|
311
|
-
const channel = new BroadcastChannel(CHANNEL_NAME);
|
|
312
|
-
channelRef.current = channel;
|
|
313
|
-
if (onReceive) channel.onmessage = (e) => {
|
|
314
|
-
onReceive(e.data);
|
|
315
|
-
};
|
|
316
|
-
return () => {
|
|
317
|
-
channel.close();
|
|
318
|
-
channelRef.current = null;
|
|
319
|
-
};
|
|
320
|
-
}, [onReceive]);
|
|
321
|
-
useEffect(() => {
|
|
322
|
-
channelRef.current?.postMessage({
|
|
323
|
-
type: "sync",
|
|
324
|
-
currentSlide,
|
|
325
|
-
clickStep
|
|
326
|
-
});
|
|
327
|
-
}, [currentSlide, clickStep]);
|
|
328
|
-
}
|
|
329
|
-
/**
|
|
330
|
-
* Opens the presenter window at the /presenter route.
|
|
331
|
-
*/
|
|
332
|
-
function openPresenterWindow() {
|
|
333
|
-
const url = new URL(window.location.href);
|
|
334
|
-
url.searchParams.set("presenter", "true");
|
|
335
|
-
window.open(url.toString(), "reslide-presenter", "width=1024,height=768,menubar=no,toolbar=no");
|
|
336
|
-
}
|
|
337
|
-
/**
|
|
338
|
-
* Check if the current window is the presenter view.
|
|
339
|
-
*/
|
|
340
|
-
function isPresenterView() {
|
|
341
|
-
if (typeof window === "undefined") return false;
|
|
342
|
-
return new URLSearchParams(window.location.search).get("presenter") === "true";
|
|
343
|
-
}
|
|
344
|
-
//#endregion
|
|
345
759
|
//#region src/Deck.tsx
|
|
346
760
|
function Deck({ children, transition = "none" }) {
|
|
347
761
|
const containerRef = useRef(null);
|
|
@@ -352,7 +766,6 @@ function Deck({ children, transition = "none" }) {
|
|
|
352
766
|
const [isPrinting, setIsPrinting] = useState(false);
|
|
353
767
|
const [clickStepsMap, setClickStepsMap] = useState({});
|
|
354
768
|
const { isFullscreen, toggleFullscreen } = useFullscreen(containerRef);
|
|
355
|
-
usePresenterSync(currentSlide, clickStep);
|
|
356
769
|
const totalSlides = Children.count(children);
|
|
357
770
|
const totalClickSteps = clickStepsMap[currentSlide] ?? 0;
|
|
358
771
|
const registerClickSteps = useCallback((slideIndex, count) => {
|
|
@@ -399,6 +812,15 @@ function Deck({ children, transition = "none" }) {
|
|
|
399
812
|
if (isOverview) setIsOverview(false);
|
|
400
813
|
}
|
|
401
814
|
}, [totalSlides, isOverview]);
|
|
815
|
+
usePresenterSync(currentSlide, clickStep, useMemo(() => ({
|
|
816
|
+
next,
|
|
817
|
+
prev,
|
|
818
|
+
goTo
|
|
819
|
+
}), [
|
|
820
|
+
next,
|
|
821
|
+
prev,
|
|
822
|
+
goTo
|
|
823
|
+
]));
|
|
402
824
|
const toggleOverview = useCallback(() => {
|
|
403
825
|
setIsOverview((v) => !v);
|
|
404
826
|
}, []);
|
|
@@ -512,12 +934,15 @@ function Deck({ children, transition = "none" }) {
|
|
|
512
934
|
onNext: next,
|
|
513
935
|
disabled: isDrawing
|
|
514
936
|
}),
|
|
515
|
-
!isOverview && !isPrinting && /* @__PURE__ */ jsx(SlideNumber, {
|
|
516
|
-
current: currentSlide + 1,
|
|
517
|
-
total: totalSlides
|
|
518
|
-
}),
|
|
519
937
|
!isOverview && !isPrinting && /* @__PURE__ */ jsx(ProgressBar, {}),
|
|
520
|
-
!isOverview && !isPrinting && /* @__PURE__ */ jsx(DrawingLayer, {
|
|
938
|
+
!isOverview && !isPrinting && /* @__PURE__ */ jsx(DrawingLayer, {
|
|
939
|
+
active: isDrawing,
|
|
940
|
+
currentSlide
|
|
941
|
+
}),
|
|
942
|
+
!isPrinting && /* @__PURE__ */ jsx(NavigationBar, {
|
|
943
|
+
isDrawing,
|
|
944
|
+
onToggleDrawing: () => setIsDrawing((v) => !v)
|
|
945
|
+
})
|
|
521
946
|
]
|
|
522
947
|
})
|
|
523
948
|
});
|
|
@@ -564,24 +989,6 @@ function OverviewGrid({ children, totalSlides, goTo }) {
|
|
|
564
989
|
}, i))
|
|
565
990
|
});
|
|
566
991
|
}
|
|
567
|
-
function SlideNumber({ current, total }) {
|
|
568
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
569
|
-
className: "reslide-slide-number",
|
|
570
|
-
style: {
|
|
571
|
-
position: "absolute",
|
|
572
|
-
bottom: "1rem",
|
|
573
|
-
right: "1rem",
|
|
574
|
-
fontSize: "0.875rem",
|
|
575
|
-
opacity: .6,
|
|
576
|
-
fontVariantNumeric: "tabular-nums"
|
|
577
|
-
},
|
|
578
|
-
children: [
|
|
579
|
-
current,
|
|
580
|
-
" / ",
|
|
581
|
-
total
|
|
582
|
-
]
|
|
583
|
-
});
|
|
584
|
-
}
|
|
585
992
|
//#endregion
|
|
586
993
|
//#region src/Slide.tsx
|
|
587
994
|
const baseStyle = {
|
|
@@ -851,6 +1258,8 @@ SlotRight.__reslideSlot = "right";
|
|
|
851
1258
|
/**
|
|
852
1259
|
* Presenter view that syncs with the main presentation window.
|
|
853
1260
|
* Shows: current slide, next slide preview, notes, and timer.
|
|
1261
|
+
* Supports bidirectional control — navigate from this window to
|
|
1262
|
+
* drive the main presentation.
|
|
854
1263
|
*/
|
|
855
1264
|
function PresenterView({ children, notes }) {
|
|
856
1265
|
const [currentSlide, setCurrentSlide] = useState(0);
|
|
@@ -858,17 +1267,28 @@ function PresenterView({ children, notes }) {
|
|
|
858
1267
|
const [elapsed, setElapsed] = useState(0);
|
|
859
1268
|
const slides = Children.toArray(children);
|
|
860
1269
|
const totalSlides = slides.length;
|
|
1270
|
+
const { next, prev, goTo } = usePresenterChannel((msg) => {
|
|
1271
|
+
setCurrentSlide(msg.currentSlide);
|
|
1272
|
+
setClickStep(msg.clickStep);
|
|
1273
|
+
});
|
|
861
1274
|
useEffect(() => {
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
1275
|
+
function handleKeyDown(e) {
|
|
1276
|
+
if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) return;
|
|
1277
|
+
switch (e.key) {
|
|
1278
|
+
case "ArrowRight":
|
|
1279
|
+
case " ":
|
|
1280
|
+
e.preventDefault();
|
|
1281
|
+
next();
|
|
1282
|
+
break;
|
|
1283
|
+
case "ArrowLeft":
|
|
1284
|
+
e.preventDefault();
|
|
1285
|
+
prev();
|
|
1286
|
+
break;
|
|
868
1287
|
}
|
|
869
|
-
}
|
|
870
|
-
|
|
871
|
-
|
|
1288
|
+
}
|
|
1289
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
1290
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
1291
|
+
}, [next, prev]);
|
|
872
1292
|
useEffect(() => {
|
|
873
1293
|
const start = Date.now();
|
|
874
1294
|
const interval = setInterval(() => {
|
|
@@ -881,21 +1301,31 @@ function PresenterView({ children, notes }) {
|
|
|
881
1301
|
const s = seconds % 60;
|
|
882
1302
|
return `${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
|
|
883
1303
|
};
|
|
1304
|
+
const noopReg = useCallback((_i, _c) => {}, []);
|
|
884
1305
|
const noop = useCallback(() => {}, []);
|
|
885
|
-
const contextValue = {
|
|
1306
|
+
const contextValue = useMemo(() => ({
|
|
886
1307
|
currentSlide,
|
|
887
1308
|
totalSlides,
|
|
888
1309
|
clickStep,
|
|
889
1310
|
totalClickSteps: 0,
|
|
890
1311
|
isOverview: false,
|
|
891
1312
|
isFullscreen: false,
|
|
892
|
-
next
|
|
893
|
-
prev
|
|
894
|
-
goTo
|
|
1313
|
+
next,
|
|
1314
|
+
prev,
|
|
1315
|
+
goTo,
|
|
895
1316
|
toggleOverview: noop,
|
|
896
1317
|
toggleFullscreen: noop,
|
|
897
|
-
registerClickSteps:
|
|
898
|
-
}
|
|
1318
|
+
registerClickSteps: noopReg
|
|
1319
|
+
}), [
|
|
1320
|
+
currentSlide,
|
|
1321
|
+
totalSlides,
|
|
1322
|
+
clickStep,
|
|
1323
|
+
next,
|
|
1324
|
+
prev,
|
|
1325
|
+
goTo,
|
|
1326
|
+
noop,
|
|
1327
|
+
noopReg
|
|
1328
|
+
]);
|
|
899
1329
|
return /* @__PURE__ */ jsx(DeckContext.Provider, {
|
|
900
1330
|
value: contextValue,
|
|
901
1331
|
children: /* @__PURE__ */ jsxs("div", {
|
|
@@ -989,37 +1419,88 @@ function PresenterView({ children, notes }) {
|
|
|
989
1419
|
backgroundColor: "#0f172a",
|
|
990
1420
|
borderRadius: "0.5rem"
|
|
991
1421
|
},
|
|
992
|
-
children: [
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1422
|
+
children: [
|
|
1423
|
+
/* @__PURE__ */ jsx("div", {
|
|
1424
|
+
style: {
|
|
1425
|
+
fontSize: "1.5rem",
|
|
1426
|
+
fontVariantNumeric: "tabular-nums",
|
|
1427
|
+
fontWeight: 700
|
|
1428
|
+
},
|
|
1429
|
+
children: formatTime(elapsed)
|
|
1430
|
+
}),
|
|
1431
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1432
|
+
style: {
|
|
1433
|
+
display: "flex",
|
|
1434
|
+
alignItems: "center",
|
|
1435
|
+
gap: "0.5rem"
|
|
1436
|
+
},
|
|
1437
|
+
children: [
|
|
1438
|
+
/* @__PURE__ */ jsx(PresenterNavButton, {
|
|
1439
|
+
onClick: prev,
|
|
1440
|
+
title: "Previous (←)",
|
|
1441
|
+
children: "◀"
|
|
1442
|
+
}),
|
|
1443
|
+
/* @__PURE__ */ jsxs("span", {
|
|
1444
|
+
style: {
|
|
1445
|
+
fontSize: "1.125rem",
|
|
1446
|
+
fontVariantNumeric: "tabular-nums"
|
|
1447
|
+
},
|
|
1448
|
+
children: [
|
|
1449
|
+
currentSlide + 1,
|
|
1450
|
+
" / ",
|
|
1451
|
+
totalSlides,
|
|
1452
|
+
clickStep > 0 && /* @__PURE__ */ jsxs("span", {
|
|
1453
|
+
style: { color: "#94a3b8" },
|
|
1454
|
+
children: [
|
|
1455
|
+
" (click ",
|
|
1456
|
+
clickStep,
|
|
1457
|
+
")"
|
|
1458
|
+
]
|
|
1459
|
+
})
|
|
1460
|
+
]
|
|
1461
|
+
}),
|
|
1462
|
+
/* @__PURE__ */ jsx(PresenterNavButton, {
|
|
1463
|
+
onClick: next,
|
|
1464
|
+
title: "Next (→ / Space)",
|
|
1465
|
+
children: "▶"
|
|
1466
|
+
})
|
|
1467
|
+
]
|
|
1468
|
+
}),
|
|
1469
|
+
/* @__PURE__ */ jsx("div", { style: { width: "5rem" } })
|
|
1470
|
+
]
|
|
1018
1471
|
})
|
|
1019
1472
|
]
|
|
1020
1473
|
})
|
|
1021
1474
|
});
|
|
1022
1475
|
}
|
|
1476
|
+
function PresenterNavButton({ children, onClick, title }) {
|
|
1477
|
+
return /* @__PURE__ */ jsx("button", {
|
|
1478
|
+
type: "button",
|
|
1479
|
+
onClick,
|
|
1480
|
+
title,
|
|
1481
|
+
style: {
|
|
1482
|
+
display: "flex",
|
|
1483
|
+
alignItems: "center",
|
|
1484
|
+
justifyContent: "center",
|
|
1485
|
+
width: "2.25rem",
|
|
1486
|
+
height: "2.25rem",
|
|
1487
|
+
background: "rgba(255,255,255,0.1)",
|
|
1488
|
+
border: "1px solid rgba(255,255,255,0.15)",
|
|
1489
|
+
borderRadius: "0.375rem",
|
|
1490
|
+
cursor: "pointer",
|
|
1491
|
+
color: "#e2e8f0",
|
|
1492
|
+
fontSize: "0.875rem",
|
|
1493
|
+
transition: "background 0.15s"
|
|
1494
|
+
},
|
|
1495
|
+
onMouseEnter: (e) => {
|
|
1496
|
+
e.currentTarget.style.background = "rgba(255,255,255,0.2)";
|
|
1497
|
+
},
|
|
1498
|
+
onMouseLeave: (e) => {
|
|
1499
|
+
e.currentTarget.style.background = "rgba(255,255,255,0.1)";
|
|
1500
|
+
},
|
|
1501
|
+
children
|
|
1502
|
+
});
|
|
1503
|
+
}
|
|
1023
1504
|
//#endregion
|
|
1024
1505
|
//#region src/CodeEditor.tsx
|
|
1025
1506
|
/**
|
|
@@ -1441,4 +1922,4 @@ function ReslideEmbed({ code, transition, components: userComponents, className,
|
|
|
1441
1922
|
});
|
|
1442
1923
|
}
|
|
1443
1924
|
//#endregion
|
|
1444
|
-
export { Click, ClickNavigation, ClickSteps, CodeEditor, Deck, DeckContext, Draggable, DrawingLayer, GlobalLayer, Mark, Mermaid, Notes, PresenterView, PrintView, ProgressBar, ReslideEmbed, Slide, SlideIndexContext, SlotRight, Toc, isPresenterView, openPresenterWindow, useDeck, useSlideIndex };
|
|
1925
|
+
export { Click, ClickNavigation, ClickSteps, CodeEditor, Deck, DeckContext, Draggable, DrawingLayer, GlobalLayer, Mark, Mermaid, NavigationBar, Notes, PresenterView, PrintView, ProgressBar, ReslideEmbed, Slide, SlideIndexContext, SlotRight, Toc, isPresenterView, openPresenterWindow, useDeck, useSlideIndex };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reslide-dev/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Framework-agnostic React presentation components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
],
|
|
10
10
|
"type": "module",
|
|
11
11
|
"exports": {
|
|
12
|
-
".": "./
|
|
12
|
+
".": "./src/index.ts",
|
|
13
13
|
"./mdx-components": "./src/mdx-components.ts",
|
|
14
14
|
"./themes/default.css": "./src/themes/default.css",
|
|
15
15
|
"./themes/dark.css": "./src/themes/dark.css",
|
|
@@ -21,22 +21,22 @@
|
|
|
21
21
|
"access": "public"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@mdx-js/mdx": "
|
|
24
|
+
"@mdx-js/mdx": "3.1.1"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@testing-library/dom": "
|
|
28
|
-
"@testing-library/react": "
|
|
29
|
-
"@types/react": "
|
|
30
|
-
"@types/react-dom": "
|
|
31
|
-
"jsdom": "
|
|
32
|
-
"react": "
|
|
33
|
-
"react-dom": "
|
|
27
|
+
"@testing-library/dom": "10.4.1",
|
|
28
|
+
"@testing-library/react": "16.3.2",
|
|
29
|
+
"@types/react": "19.2.14",
|
|
30
|
+
"@types/react-dom": "19.2.3",
|
|
31
|
+
"jsdom": "29.0.1",
|
|
32
|
+
"react": "19.2.4",
|
|
33
|
+
"react-dom": "19.2.4",
|
|
34
34
|
"vite-plus": "latest",
|
|
35
35
|
"vitest": "npm:@voidzero-dev/vite-plus-test@latest"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
|
-
"react": "
|
|
39
|
-
"react-dom": "
|
|
38
|
+
"react": ">=19.0.0",
|
|
39
|
+
"react-dom": ">=19.0.0"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
42
|
"build": "vp pack",
|