@thanh01.pmt/presentation-kit 0.1.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.
@@ -0,0 +1,750 @@
1
+ import { renderSlide, renderMermaidDiagrams } from '../chunk-RCHOTRWI.js';
2
+ export { defineTheme, extractMaxClicks, generateClickCss, postprocessClicks, preprocessClicks, renderSlide, renderSlideAsync, resolveTheme } from '../chunk-RCHOTRWI.js';
3
+ import { useState, useRef, useMemo, useEffect, useCallback } from 'react';
4
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
+
6
+ function useSlideState(options) {
7
+ const {
8
+ markdown,
9
+ initialTheme = "dark",
10
+ initialMode = "presentation",
11
+ containerId,
12
+ enableClicks = false
13
+ } = options;
14
+ const [currentIndex, setCurrentIndex] = useState(0);
15
+ const [mode, setMode] = useState(initialMode);
16
+ const [theme, setTheme] = useState(initialTheme);
17
+ const [currentClick, setCurrentClick] = useState(0);
18
+ const renderCountRef = useRef(0);
19
+ const result = useMemo(() => {
20
+ if (!markdown || !markdown.trim()) return null;
21
+ renderCountRef.current++;
22
+ return renderSlide(markdown, {
23
+ theme,
24
+ enableMermaid: true,
25
+ enableClicks,
26
+ containerId: containerId ?? `slide-container-${renderCountRef.current}`
27
+ });
28
+ }, [markdown, theme, containerId, enableClicks]);
29
+ const slideCount = result?.slideCount ?? 1;
30
+ const maxClicks = result?.maxClicks ?? 0;
31
+ const isReady = result !== null;
32
+ useEffect(() => {
33
+ if (result && currentIndex >= result.slideCount) {
34
+ setCurrentIndex(Math.max(0, result.slideCount - 1));
35
+ }
36
+ }, [result?.slideCount, currentIndex]);
37
+ useEffect(() => {
38
+ setCurrentClick(0);
39
+ }, [currentIndex]);
40
+ useCallback(
41
+ (index) => {
42
+ setCurrentIndex(Math.max(0, Math.min(index, slideCount - 1)));
43
+ },
44
+ [slideCount]
45
+ );
46
+ useCallback(() => {
47
+ setCurrentIndex((prev) => Math.min(prev + 1, slideCount - 1));
48
+ }, [slideCount]);
49
+ useCallback(() => {
50
+ setCurrentIndex((prev) => Math.max(prev - 1, 0));
51
+ }, []);
52
+ const nextClick = useCallback(() => {
53
+ setCurrentClick((prev) => Math.min(prev + 1, maxClicks));
54
+ }, [maxClicks]);
55
+ const prevClick = useCallback(() => {
56
+ setCurrentClick((prev) => Math.max(prev - 1, 0));
57
+ }, []);
58
+ const resetClicks = useCallback(() => {
59
+ setCurrentClick(0);
60
+ }, []);
61
+ const setClickIndex = useCallback(
62
+ (index) => {
63
+ setCurrentClick(Math.max(0, Math.min(index, maxClicks)));
64
+ },
65
+ [maxClicks]
66
+ );
67
+ const goToSlideWithReset = useCallback(
68
+ (index) => {
69
+ setCurrentClick(0);
70
+ setCurrentIndex(Math.max(0, Math.min(index, slideCount - 1)));
71
+ },
72
+ [slideCount]
73
+ );
74
+ const nextWithClick = useCallback(() => {
75
+ if (currentClick < maxClicks) {
76
+ setCurrentClick((prev) => prev + 1);
77
+ } else {
78
+ setCurrentClick(0);
79
+ setCurrentIndex((prev) => Math.min(prev + 1, slideCount - 1));
80
+ }
81
+ }, [currentClick, maxClicks, slideCount]);
82
+ const prevWithClick = useCallback(() => {
83
+ if (currentClick > 0) {
84
+ setCurrentClick((prev) => prev - 1);
85
+ } else {
86
+ setCurrentIndex((prev) => Math.max(prev - 1, 0));
87
+ }
88
+ }, [currentClick]);
89
+ const rerender = useCallback(() => {
90
+ setCurrentIndex((prev) => prev);
91
+ }, []);
92
+ return {
93
+ // Render
94
+ result,
95
+ isReady,
96
+ // Slide
97
+ currentIndex,
98
+ slideCount,
99
+ mode,
100
+ theme,
101
+ // Click
102
+ currentClick,
103
+ maxClicks,
104
+ // Slide actions
105
+ goToSlide: goToSlideWithReset,
106
+ nextSlide: nextWithClick,
107
+ prevSlide: prevWithClick,
108
+ setMode,
109
+ setTheme,
110
+ rerender,
111
+ // Click actions
112
+ nextClick,
113
+ prevClick,
114
+ resetClicks,
115
+ setClickIndex
116
+ };
117
+ }
118
+ var DEFAULT_THEMES = [
119
+ { id: "dark", label: "Dark" },
120
+ { id: "navy", label: "Navy" },
121
+ { id: "light", label: "Light" }
122
+ ];
123
+ function ThemeSwitcher({
124
+ currentTheme,
125
+ onThemeChange,
126
+ themes = DEFAULT_THEMES,
127
+ className
128
+ }) {
129
+ const currentId = typeof currentTheme === "object" && currentTheme !== null && "name" in currentTheme ? currentTheme.name : String(currentTheme);
130
+ return /* @__PURE__ */ jsx(
131
+ "div",
132
+ {
133
+ className,
134
+ style: {
135
+ display: "inline-flex",
136
+ alignItems: "center",
137
+ gap: "2px",
138
+ padding: "2px",
139
+ borderRadius: "8px",
140
+ border: "1px solid rgba(128, 128, 128, 0.2)",
141
+ backgroundColor: "rgba(128, 128, 128, 0.05)"
142
+ },
143
+ children: themes.map((theme) => {
144
+ const isActive = currentId === theme.id;
145
+ return /* @__PURE__ */ jsxs(
146
+ "button",
147
+ {
148
+ type: "button",
149
+ onClick: () => onThemeChange(theme.id),
150
+ title: `Theme: ${theme.label}`,
151
+ style: {
152
+ height: "28px",
153
+ padding: "0 10px",
154
+ borderRadius: "6px",
155
+ fontSize: "12px",
156
+ fontFamily: "inherit",
157
+ fontWeight: isActive ? 600 : 400,
158
+ display: "flex",
159
+ alignItems: "center",
160
+ gap: "5px",
161
+ transition: "all 0.15s ease",
162
+ cursor: "pointer",
163
+ border: "none",
164
+ lineHeight: 1,
165
+ whiteSpace: "nowrap",
166
+ backgroundColor: isActive ? "rgba(128, 128, 128, 0.15)" : "transparent",
167
+ color: isActive ? "currentColor" : "rgba(128, 128, 128, 0.7)"
168
+ },
169
+ children: [
170
+ theme.icon && /* @__PURE__ */ jsx("span", { style: { fontSize: "13px" }, children: theme.icon }),
171
+ /* @__PURE__ */ jsx("span", { children: theme.label })
172
+ ]
173
+ },
174
+ theme.id
175
+ );
176
+ })
177
+ }
178
+ );
179
+ }
180
+ var btnBase = {
181
+ height: "28px",
182
+ borderRadius: "6px",
183
+ fontSize: "12px",
184
+ fontFamily: "inherit",
185
+ display: "flex",
186
+ alignItems: "center",
187
+ justifyContent: "center",
188
+ gap: "5px",
189
+ transition: "all 0.15s ease",
190
+ cursor: "pointer",
191
+ border: "none",
192
+ lineHeight: 1,
193
+ whiteSpace: "nowrap"
194
+ };
195
+ var btnSecondary = {
196
+ ...btnBase,
197
+ padding: "0 10px",
198
+ backgroundColor: "transparent",
199
+ color: "rgba(128, 128, 128, 0.7)"
200
+ };
201
+ var btnActive = {
202
+ ...btnBase,
203
+ padding: "0 10px",
204
+ fontWeight: 600,
205
+ backgroundColor: "rgba(128, 128, 128, 0.15)",
206
+ color: "currentColor"
207
+ };
208
+ var iconBtn = {
209
+ ...btnBase,
210
+ width: "28px",
211
+ padding: 0,
212
+ backgroundColor: "transparent",
213
+ color: "rgba(128, 128, 128, 0.7)"
214
+ };
215
+ var disabledStyle = {
216
+ opacity: 0.3,
217
+ cursor: "not-allowed"
218
+ };
219
+ function NavigationBar({
220
+ currentIndex,
221
+ slideCount,
222
+ onNavigate,
223
+ mode,
224
+ onModeChange,
225
+ className,
226
+ showCopy = true,
227
+ markdown
228
+ }) {
229
+ const [copied, setCopied] = useState(false);
230
+ const handleCopy = useCallback(async () => {
231
+ if (!markdown) return;
232
+ try {
233
+ await navigator.clipboard.writeText(markdown);
234
+ setCopied(true);
235
+ setTimeout(() => setCopied(false), 2e3);
236
+ } catch {
237
+ }
238
+ }, [markdown]);
239
+ const isFirst = currentIndex === 0;
240
+ const isLast = currentIndex >= slideCount - 1;
241
+ return /* @__PURE__ */ jsxs(
242
+ "div",
243
+ {
244
+ className,
245
+ style: {
246
+ display: "flex",
247
+ alignItems: "center",
248
+ justifyContent: "space-between",
249
+ gap: "8px",
250
+ padding: "8px 0",
251
+ borderBottom: "1px solid rgba(128, 128, 128, 0.12)",
252
+ flexWrap: "wrap"
253
+ },
254
+ children: [
255
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "4px" }, children: [
256
+ /* @__PURE__ */ jsx(
257
+ "button",
258
+ {
259
+ type: "button",
260
+ onClick: () => onModeChange("presentation"),
261
+ style: mode === "presentation" ? btnActive : btnSecondary,
262
+ title: "Presentation mode (1 slide)",
263
+ children: "\u25B6 Presentation"
264
+ }
265
+ ),
266
+ /* @__PURE__ */ jsx(
267
+ "button",
268
+ {
269
+ type: "button",
270
+ onClick: () => onModeChange("deck"),
271
+ style: mode === "deck" ? btnActive : btnSecondary,
272
+ title: "Deck mode (all slides)",
273
+ children: "\u2630 Deck"
274
+ }
275
+ )
276
+ ] }),
277
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "4px" }, children: [
278
+ mode === "presentation" && /* @__PURE__ */ jsxs(Fragment, { children: [
279
+ /* @__PURE__ */ jsx(
280
+ "button",
281
+ {
282
+ type: "button",
283
+ onClick: () => onNavigate(currentIndex - 1),
284
+ disabled: isFirst,
285
+ style: { ...iconBtn, ...isFirst ? disabledStyle : {} },
286
+ title: "Previous slide (\u2190)",
287
+ children: "\u2039"
288
+ }
289
+ ),
290
+ /* @__PURE__ */ jsx(
291
+ "select",
292
+ {
293
+ value: currentIndex,
294
+ onChange: (e) => onNavigate(Number(e.target.value)),
295
+ style: {
296
+ height: "28px",
297
+ padding: "0 6px",
298
+ borderRadius: "6px",
299
+ fontSize: "12px",
300
+ fontFamily: "inherit",
301
+ border: "none",
302
+ backgroundColor: "transparent",
303
+ color: "currentColor",
304
+ cursor: "pointer",
305
+ outline: "none"
306
+ },
307
+ title: "Jump to slide",
308
+ children: Array.from({ length: slideCount }, (_, i) => /* @__PURE__ */ jsxs("option", { value: i, children: [
309
+ "Slide ",
310
+ i + 1,
311
+ " / ",
312
+ slideCount
313
+ ] }, i))
314
+ }
315
+ ),
316
+ /* @__PURE__ */ jsx(
317
+ "button",
318
+ {
319
+ type: "button",
320
+ onClick: () => onNavigate(currentIndex + 1),
321
+ disabled: isLast,
322
+ style: { ...iconBtn, ...isLast ? disabledStyle : {} },
323
+ title: "Next slide (\u2192)",
324
+ children: "\u203A"
325
+ }
326
+ )
327
+ ] }),
328
+ mode === "deck" && /* @__PURE__ */ jsxs("span", { style: { fontSize: "12px", color: "rgba(128, 128, 128, 0.6)", padding: "0 8px" }, children: [
329
+ slideCount,
330
+ " slides"
331
+ ] }),
332
+ showCopy && markdown && /* @__PURE__ */ jsx(
333
+ "button",
334
+ {
335
+ type: "button",
336
+ onClick: handleCopy,
337
+ style: btnSecondary,
338
+ title: "Copy markdown source",
339
+ children: copied ? "\u2713 Copied" : "\u29C9 Copy"
340
+ }
341
+ )
342
+ ] })
343
+ ]
344
+ }
345
+ );
346
+ }
347
+ function PresentationView({
348
+ html,
349
+ css,
350
+ themeCss,
351
+ currentIndex,
352
+ slideCount,
353
+ className
354
+ }) {
355
+ const presentationCss = `
356
+ .slide-presentation-host {
357
+ display: flex;
358
+ align-items: center;
359
+ justify-content: center;
360
+ width: 100%;
361
+ }
362
+ .slide-presentation-host > div {
363
+ position: relative;
364
+ display: flex;
365
+ align-items: center;
366
+ justify-content: center;
367
+ width: 100%;
368
+ }
369
+ .slide-presentation-host > div > svg {
370
+ position: absolute;
371
+ visibility: hidden;
372
+ opacity: 0;
373
+ pointer-events: none;
374
+ width: min(100%, calc((100vh - 120px) * (16 / 9)));
375
+ max-width: 1400px;
376
+ height: auto;
377
+ max-height: calc(100vh - 120px);
378
+ aspect-ratio: 16 / 9;
379
+ margin: 0 auto;
380
+ }
381
+ .slide-presentation-host > div > svg:nth-child(${currentIndex + 1}) {
382
+ position: relative;
383
+ visibility: visible;
384
+ opacity: 1;
385
+ pointer-events: auto;
386
+ display: block;
387
+ }
388
+ `;
389
+ return /* @__PURE__ */ jsxs("div", { className, style: { width: "100%" }, children: [
390
+ /* @__PURE__ */ jsx("style", { children: css }),
391
+ /* @__PURE__ */ jsx("style", { children: themeCss }),
392
+ /* @__PURE__ */ jsx("style", { children: presentationCss }),
393
+ /* @__PURE__ */ jsx(
394
+ "div",
395
+ {
396
+ className: "slide-presentation-host",
397
+ style: { padding: "16px 0" },
398
+ dangerouslySetInnerHTML: { __html: html }
399
+ }
400
+ )
401
+ ] });
402
+ }
403
+ function DeckView({
404
+ html,
405
+ css,
406
+ themeCss,
407
+ slideCount,
408
+ className
409
+ }) {
410
+ const deckCss = `
411
+ .slide-deck-host {
412
+ display: flex;
413
+ flex-direction: column;
414
+ align-items: center;
415
+ gap: 24px;
416
+ padding: 16px 0;
417
+ }
418
+ .slide-deck-host > div {
419
+ display: flex;
420
+ flex-direction: column;
421
+ align-items: center;
422
+ gap: 24px;
423
+ }
424
+ .slide-deck-host > div > svg {
425
+ display: block !important;
426
+ width: 100% !important;
427
+ max-width: 960px;
428
+ height: auto !important;
429
+ aspect-ratio: 16 / 9;
430
+ border-radius: 12px;
431
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
432
+ }
433
+ .slide-deck-host > div > svg:hover {
434
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
435
+ }
436
+ `;
437
+ return /* @__PURE__ */ jsxs("div", { className, style: { width: "100%" }, children: [
438
+ /* @__PURE__ */ jsx("style", { children: css }),
439
+ /* @__PURE__ */ jsx("style", { children: themeCss }),
440
+ /* @__PURE__ */ jsx("style", { children: deckCss }),
441
+ /* @__PURE__ */ jsx(
442
+ "div",
443
+ {
444
+ className: "slide-deck-host",
445
+ dangerouslySetInnerHTML: { __html: html }
446
+ }
447
+ )
448
+ ] });
449
+ }
450
+ var DEFAULT_THEME_OPTIONS = [
451
+ { id: "dark", label: "Dark" },
452
+ { id: "navy", label: "Navy" },
453
+ { id: "light", label: "Light" }
454
+ ];
455
+ function SlideViewer({
456
+ markdown,
457
+ initialTheme = "dark",
458
+ initialMode = "presentation",
459
+ className,
460
+ showThemeSwitcher = true,
461
+ showNavigation = true,
462
+ enableKeyboard = true,
463
+ enableClicks = false,
464
+ fullscreen = false,
465
+ themeOptions = DEFAULT_THEME_OPTIONS,
466
+ onThemeChange,
467
+ onSlideChange,
468
+ onModeChange,
469
+ onRenderComplete
470
+ }) {
471
+ const [isFullscreen, setIsFullscreen] = useState(false);
472
+ const state = useSlideState({
473
+ markdown,
474
+ initialTheme,
475
+ initialMode,
476
+ enableClicks
477
+ });
478
+ const {
479
+ currentIndex,
480
+ mode,
481
+ theme,
482
+ result,
483
+ slideCount,
484
+ currentClick,
485
+ maxClicks,
486
+ goToSlide,
487
+ nextSlide,
488
+ prevSlide,
489
+ setMode,
490
+ setTheme,
491
+ nextClick,
492
+ prevClick,
493
+ resetClicks
494
+ } = state;
495
+ useEffect(() => {
496
+ onThemeChange?.(theme);
497
+ }, [theme, onThemeChange]);
498
+ useEffect(() => {
499
+ onSlideChange?.(currentIndex);
500
+ }, [currentIndex, onSlideChange]);
501
+ useEffect(() => {
502
+ onModeChange?.(mode);
503
+ }, [mode, onModeChange]);
504
+ useEffect(() => {
505
+ if (result) onRenderComplete?.(result);
506
+ }, [result, onRenderComplete]);
507
+ useEffect(() => {
508
+ if (!enableKeyboard) return;
509
+ const handleKey = (e) => {
510
+ if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) return;
511
+ if (e.key === "Escape" && fullscreen && isFullscreen) {
512
+ e.preventDefault();
513
+ setIsFullscreen(false);
514
+ return;
515
+ }
516
+ if (mode !== "presentation") return;
517
+ switch (e.key) {
518
+ case "ArrowRight":
519
+ case "PageDown":
520
+ case " ":
521
+ e.preventDefault();
522
+ if (enableClicks && currentClick < maxClicks) {
523
+ nextClick();
524
+ } else {
525
+ nextSlide();
526
+ }
527
+ break;
528
+ case "ArrowLeft":
529
+ case "PageUp":
530
+ e.preventDefault();
531
+ if (enableClicks && currentClick > 0) {
532
+ prevClick();
533
+ } else {
534
+ prevSlide();
535
+ }
536
+ break;
537
+ case "Home":
538
+ e.preventDefault();
539
+ goToSlide(0);
540
+ break;
541
+ case "End":
542
+ e.preventDefault();
543
+ goToSlide(slideCount - 1);
544
+ break;
545
+ case "f":
546
+ case "F":
547
+ if (fullscreen) {
548
+ e.preventDefault();
549
+ setIsFullscreen((prev) => !prev);
550
+ }
551
+ break;
552
+ }
553
+ };
554
+ window.addEventListener("keydown", handleKey);
555
+ return () => window.removeEventListener("keydown", handleKey);
556
+ }, [enableKeyboard, mode, fullscreen, isFullscreen, enableClicks, currentClick, maxClicks, nextClick, prevClick, nextSlide, prevSlide, goToSlide, slideCount]);
557
+ useEffect(() => {
558
+ if (!enableClicks || !result || mode !== "presentation") return;
559
+ const timer = setTimeout(() => {
560
+ const container = document.querySelector(".slide-presentation-host > div");
561
+ if (!container) return;
562
+ container.querySelectorAll("[data-click-group]").forEach((el) => {
563
+ const group = parseInt(el.getAttribute("data-click-group") ?? "0", 10);
564
+ const isVisible = group <= currentClick;
565
+ el.classList.toggle("visible", isVisible);
566
+ });
567
+ }, 50);
568
+ return () => clearTimeout(timer);
569
+ }, [enableClicks, currentClick, result, currentIndex, mode]);
570
+ useEffect(() => {
571
+ if (!result || result.mermaidBlocks.length === 0) return;
572
+ const timer = setTimeout(() => {
573
+ const containers = document.querySelectorAll(".slide-presentation-host > div, .slide-deck-host > div");
574
+ containers.forEach((container) => {
575
+ if (container instanceof HTMLElement) {
576
+ const themeName2 = typeof theme === "string" ? theme : "dark";
577
+ renderMermaidDiagrams(container, themeName2).catch(() => {
578
+ });
579
+ }
580
+ });
581
+ }, 100);
582
+ return () => clearTimeout(timer);
583
+ }, [result, theme, currentIndex, mode]);
584
+ const handleThemeChange = useCallback(
585
+ (themeId) => {
586
+ setTheme(themeId);
587
+ },
588
+ [setTheme]
589
+ );
590
+ const toggleFullscreen = useCallback(() => {
591
+ setIsFullscreen((prev) => !prev);
592
+ }, []);
593
+ if (!result) {
594
+ return /* @__PURE__ */ jsx(
595
+ "div",
596
+ {
597
+ className,
598
+ style: {
599
+ display: "flex",
600
+ alignItems: "center",
601
+ justifyContent: "center",
602
+ padding: "80px 0",
603
+ color: "rgba(128, 128, 128, 0.5)",
604
+ fontSize: "13px",
605
+ fontFamily: "inherit"
606
+ },
607
+ children: "No slide content"
608
+ }
609
+ );
610
+ }
611
+ const themeName = typeof theme === "string" ? theme : theme.name;
612
+ const fullscreenCss = fullscreen ? `
613
+ .slide-viewer-fullscreen {
614
+ position: fixed !important;
615
+ inset: 0 !important;
616
+ z-index: 9999 !important;
617
+ background: #000 !important;
618
+ padding: 24px !important;
619
+ overflow-y: auto !important;
620
+ display: flex !important;
621
+ flex-direction: column !important;
622
+ }
623
+ .slide-viewer-fullscreen .slide-presentation-host {
624
+ flex: 1 !important;
625
+ display: flex !important;
626
+ align-items: center !important;
627
+ justify-content: center !important;
628
+ }
629
+ ` : "";
630
+ return /* @__PURE__ */ jsxs(
631
+ "div",
632
+ {
633
+ className: `${className ?? ""} ${isFullscreen ? "slide-viewer-fullscreen" : ""}`.trim(),
634
+ style: {
635
+ display: "flex",
636
+ flexDirection: "column",
637
+ width: "100%",
638
+ gap: "12px",
639
+ fontFamily: 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
640
+ ...isFullscreen ? { background: "#000", color: "#fff" } : {}
641
+ },
642
+ children: [
643
+ fullscreen && /* @__PURE__ */ jsx("style", { children: fullscreenCss }),
644
+ enableClicks && mode === "presentation" && result.clickCss && /* @__PURE__ */ jsx("style", { children: result.clickCss }),
645
+ (showThemeSwitcher || showNavigation || fullscreen) && /* @__PURE__ */ jsxs("div", { style: {
646
+ display: "flex",
647
+ alignItems: "center",
648
+ justifyContent: "space-between",
649
+ gap: "12px",
650
+ flexWrap: "wrap",
651
+ ...isFullscreen ? { borderBottom: "1px solid rgba(255,255,255,0.1)", paddingBottom: "8px" } : {}
652
+ }, children: [
653
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: showThemeSwitcher && /* @__PURE__ */ jsx(
654
+ ThemeSwitcher,
655
+ {
656
+ currentTheme: themeName,
657
+ onThemeChange: handleThemeChange,
658
+ themes: themeOptions
659
+ }
660
+ ) }),
661
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
662
+ showNavigation && /* @__PURE__ */ jsx(
663
+ NavigationBar,
664
+ {
665
+ currentIndex,
666
+ slideCount,
667
+ onNavigate: goToSlide,
668
+ mode,
669
+ onModeChange: setMode,
670
+ markdown
671
+ }
672
+ ),
673
+ fullscreen && /* @__PURE__ */ jsx(
674
+ "button",
675
+ {
676
+ type: "button",
677
+ onClick: toggleFullscreen,
678
+ style: {
679
+ height: "28px",
680
+ padding: "0 10px",
681
+ borderRadius: "6px",
682
+ fontSize: "12px",
683
+ fontFamily: "inherit",
684
+ display: "flex",
685
+ alignItems: "center",
686
+ gap: "5px",
687
+ border: "none",
688
+ cursor: "pointer",
689
+ backgroundColor: "transparent",
690
+ color: isFullscreen ? "#fff" : "rgba(128,128,128,0.7)",
691
+ transition: "all 0.15s ease"
692
+ },
693
+ title: isFullscreen ? "Exit fullscreen (ESC)" : "Fullscreen (F)",
694
+ children: isFullscreen ? "\u22A1 Exit" : "\u229E Fullscreen"
695
+ }
696
+ )
697
+ ] })
698
+ ] }),
699
+ enableClicks && maxClicks > 0 && mode === "presentation" && /* @__PURE__ */ jsxs("div", { style: {
700
+ display: "flex",
701
+ alignItems: "center",
702
+ gap: "8px",
703
+ fontSize: "11px",
704
+ color: isFullscreen ? "rgba(255,255,255,0.5)" : "rgba(128,128,128,0.5)"
705
+ }, children: [
706
+ /* @__PURE__ */ jsxs("span", { children: [
707
+ "Click ",
708
+ currentClick,
709
+ " / ",
710
+ maxClicks
711
+ ] }),
712
+ /* @__PURE__ */ jsx("div", { style: {
713
+ flex: 1,
714
+ height: "2px",
715
+ borderRadius: "1px",
716
+ backgroundColor: isFullscreen ? "rgba(255,255,255,0.1)" : "rgba(128,128,128,0.1)"
717
+ }, children: /* @__PURE__ */ jsx("div", { style: {
718
+ height: "100%",
719
+ borderRadius: "1px",
720
+ backgroundColor: isFullscreen ? "rgba(255,255,255,0.3)" : "rgba(128,128,128,0.3)",
721
+ width: `${maxClicks > 0 ? currentClick / maxClicks * 100 : 0}%`,
722
+ transition: "width 0.2s ease"
723
+ } }) })
724
+ ] }),
725
+ mode === "presentation" ? /* @__PURE__ */ jsx(
726
+ PresentationView,
727
+ {
728
+ html: result.html,
729
+ css: result.css,
730
+ themeCss: result.themeCss,
731
+ currentIndex,
732
+ slideCount
733
+ }
734
+ ) : /* @__PURE__ */ jsx(
735
+ DeckView,
736
+ {
737
+ html: result.html,
738
+ css: result.css,
739
+ themeCss: result.themeCss,
740
+ slideCount
741
+ }
742
+ )
743
+ ]
744
+ }
745
+ );
746
+ }
747
+
748
+ export { DeckView, NavigationBar, PresentationView, SlideViewer, ThemeSwitcher, useSlideState };
749
+ //# sourceMappingURL=index.js.map
750
+ //# sourceMappingURL=index.js.map