@particle-academy/fancy-slides 0.1.6 → 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.cjs +156 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +491 -0
- package/dist/index.d.ts +491 -0
- package/dist/index.js +157 -4
- package/dist/index.js.map +1 -1
- package/dist/registry.d.cts +11 -0
- package/dist/registry.d.ts +11 -0
- package/dist/styles.d.cts +2 -0
- package/dist/styles.d.ts +2 -0
- package/dist/types-B2ecrEAz.d.cts +294 -0
- package/dist/types-B2ecrEAz.d.ts +294 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isDarkColor, SlideContext } from './chunk-WIUXPQAK.js';
|
|
2
2
|
export { useIsDarkSlide, useSlideContext, useSlideTheme } from './chunk-WIUXPQAK.js';
|
|
3
3
|
import { useId, useRef, useState, useEffect, useMemo, useCallback } from 'react';
|
|
4
|
-
import { ContentRenderer, Text, Action, ContextMenu, Separator, Tooltip, Dropdown, Badge, Heading, Tabs, Card,
|
|
4
|
+
import { ContentRenderer, Text, Action, ContextMenu, Separator, Tooltip, Dropdown, Badge, Heading, Tabs, Card, Select, Input, ColorPicker, Slider, Textarea } from '@particle-academy/react-fancy';
|
|
5
5
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
6
6
|
|
|
7
7
|
// src/theme/default-theme.ts
|
|
@@ -611,6 +611,11 @@ function SlideViewer({
|
|
|
611
611
|
);
|
|
612
612
|
const [blanked, setBlanked] = useState(false);
|
|
613
613
|
const containerRef = useRef(null);
|
|
614
|
+
const prevIndexRef = useRef(index);
|
|
615
|
+
const forward = index >= prevIndexRef.current;
|
|
616
|
+
useEffect(() => {
|
|
617
|
+
prevIndexRef.current = index;
|
|
618
|
+
}, [index]);
|
|
614
619
|
useSlideKeyboard({
|
|
615
620
|
total: deck.slides.length,
|
|
616
621
|
index,
|
|
@@ -634,6 +639,8 @@ function SlideViewer({
|
|
|
634
639
|
const slide = deck.slides[index];
|
|
635
640
|
const theme = resolveTheme(deck.theme);
|
|
636
641
|
const aspectRatio = theme.aspectRatio ?? 16 / 9;
|
|
642
|
+
const transition = slide?.transition ?? theme.defaultTransition;
|
|
643
|
+
const enterStyle = transitionEnterStyle(transition, forward);
|
|
637
644
|
return /* @__PURE__ */ jsxs(
|
|
638
645
|
"div",
|
|
639
646
|
{
|
|
@@ -652,6 +659,7 @@ function SlideViewer({
|
|
|
652
659
|
tabIndex: 0,
|
|
653
660
|
"data-fancy-slides-viewer": deck.id,
|
|
654
661
|
children: [
|
|
662
|
+
/* @__PURE__ */ jsx("style", { children: TRANSITION_KEYFRAMES }),
|
|
655
663
|
!blanked && slide && /* @__PURE__ */ jsx(
|
|
656
664
|
"div",
|
|
657
665
|
{
|
|
@@ -663,7 +671,7 @@ function SlideViewer({
|
|
|
663
671
|
["--fs-ratio"]: aspectRatio.toString(),
|
|
664
672
|
boxShadow: "0 8px 30px rgba(0,0,0,0.35)"
|
|
665
673
|
},
|
|
666
|
-
children: /* @__PURE__ */ jsx(Slide, { slide, theme, renderElement })
|
|
674
|
+
children: /* @__PURE__ */ jsx("div", { className: "fs-slide-enter", style: enterStyle, children: /* @__PURE__ */ jsx(Slide, { slide, theme, renderElement }) }, index)
|
|
667
675
|
}
|
|
668
676
|
),
|
|
669
677
|
!hideChrome && !blanked && /* @__PURE__ */ jsxs(
|
|
@@ -693,6 +701,68 @@ function SlideViewer({
|
|
|
693
701
|
}
|
|
694
702
|
);
|
|
695
703
|
}
|
|
704
|
+
var DEFAULT_DURATION = 400;
|
|
705
|
+
var EASE = "cubic-bezier(0.16, 1, 0.3, 1)";
|
|
706
|
+
function transitionEnterStyle(transition, forward) {
|
|
707
|
+
const kind = transition?.kind ?? "none";
|
|
708
|
+
if (kind === "none") return { width: "100%", height: "100%" };
|
|
709
|
+
const duration = transition?.duration ?? DEFAULT_DURATION;
|
|
710
|
+
let name;
|
|
711
|
+
switch (kind) {
|
|
712
|
+
case "fade":
|
|
713
|
+
name = "fs-fade-in";
|
|
714
|
+
break;
|
|
715
|
+
case "zoom":
|
|
716
|
+
name = "fs-zoom-in";
|
|
717
|
+
break;
|
|
718
|
+
case "slide": {
|
|
719
|
+
const dir = transition?.direction ?? (forward ? "right" : "left");
|
|
720
|
+
name = `fs-slide-in-${dir}`;
|
|
721
|
+
break;
|
|
722
|
+
}
|
|
723
|
+
default:
|
|
724
|
+
return { width: "100%", height: "100%" };
|
|
725
|
+
}
|
|
726
|
+
return {
|
|
727
|
+
width: "100%",
|
|
728
|
+
height: "100%",
|
|
729
|
+
animationName: name,
|
|
730
|
+
animationDuration: `${duration}ms`,
|
|
731
|
+
animationTimingFunction: EASE,
|
|
732
|
+
animationFillMode: "both"
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
var TRANSITION_KEYFRAMES = `
|
|
736
|
+
@media (prefers-reduced-motion: reduce) {
|
|
737
|
+
.fs-slide-enter { animation: none !important; }
|
|
738
|
+
}
|
|
739
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
740
|
+
@keyframes fs-fade-in {
|
|
741
|
+
from { opacity: 0; }
|
|
742
|
+
to { opacity: 1; }
|
|
743
|
+
}
|
|
744
|
+
@keyframes fs-zoom-in {
|
|
745
|
+
from { opacity: 0; transform: scale(0.92); }
|
|
746
|
+
to { opacity: 1; transform: scale(1); }
|
|
747
|
+
}
|
|
748
|
+
@keyframes fs-slide-in-right {
|
|
749
|
+
from { opacity: 0; transform: translateX(8%); }
|
|
750
|
+
to { opacity: 1; transform: translateX(0); }
|
|
751
|
+
}
|
|
752
|
+
@keyframes fs-slide-in-left {
|
|
753
|
+
from { opacity: 0; transform: translateX(-8%); }
|
|
754
|
+
to { opacity: 1; transform: translateX(0); }
|
|
755
|
+
}
|
|
756
|
+
@keyframes fs-slide-in-up {
|
|
757
|
+
from { opacity: 0; transform: translateY(8%); }
|
|
758
|
+
to { opacity: 1; transform: translateY(0); }
|
|
759
|
+
}
|
|
760
|
+
@keyframes fs-slide-in-down {
|
|
761
|
+
from { opacity: 0; transform: translateY(-8%); }
|
|
762
|
+
to { opacity: 1; transform: translateY(0); }
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
`;
|
|
696
766
|
function PresenterView({
|
|
697
767
|
deck,
|
|
698
768
|
index: controlledIndex,
|
|
@@ -1046,6 +1116,7 @@ function useDeckState({ value, onChange, onOp }) {
|
|
|
1046
1116
|
setLayout: (id, layout) => apply({ kind: "slide_set_layout", id, layout }),
|
|
1047
1117
|
setNotes: (id, notes) => apply({ kind: "slide_set_notes", id, notes }),
|
|
1048
1118
|
setBackground: (id, background) => apply({ kind: "slide_set_background", id, background }),
|
|
1119
|
+
setTransition: (id, transition) => apply({ kind: "slide_set_transition", id, transition }),
|
|
1049
1120
|
addElement: (slideId2, element) => {
|
|
1050
1121
|
const id = element.id ?? elementId();
|
|
1051
1122
|
apply({ kind: "element_add", slideId: slideId2, element: { ...element, id } });
|
|
@@ -1087,6 +1158,8 @@ function reduce(deck, op) {
|
|
|
1087
1158
|
return { ...deck, slides: deck.slides.map((s) => s.id === op.id ? { ...s, notes: op.notes } : s) };
|
|
1088
1159
|
case "slide_set_background":
|
|
1089
1160
|
return { ...deck, slides: deck.slides.map((s) => s.id === op.id ? { ...s, background: op.background } : s) };
|
|
1161
|
+
case "slide_set_transition":
|
|
1162
|
+
return { ...deck, slides: deck.slides.map((s) => s.id === op.id ? { ...s, transition: op.transition } : s) };
|
|
1090
1163
|
case "element_add":
|
|
1091
1164
|
return {
|
|
1092
1165
|
...deck,
|
|
@@ -1354,8 +1427,11 @@ function EditorToolbar({
|
|
|
1354
1427
|
/* @__PURE__ */ jsx("div", { className: "ml-auto flex items-center gap-2", children: /* @__PURE__ */ jsx(Tooltip, { content: "Present (F)", children: /* @__PURE__ */ jsx(Action, { color: "violet", size: "sm", icon: "play", onClick: onPresent, children: "Present" }) }) })
|
|
1355
1428
|
] });
|
|
1356
1429
|
}
|
|
1357
|
-
function ElementInspector({ element, onPatch, onDelete, onLockToggle }) {
|
|
1430
|
+
function ElementInspector({ element, onPatch, onDelete, onLockToggle, slide, onSetTransition, onSetBackground }) {
|
|
1358
1431
|
if (!element) {
|
|
1432
|
+
if (slide) {
|
|
1433
|
+
return /* @__PURE__ */ jsx(SlideSettings, { slide, onSetTransition, onSetBackground });
|
|
1434
|
+
}
|
|
1359
1435
|
return /* @__PURE__ */ jsxs("div", { className: "fs-inspector flex h-full flex-col border-l border-zinc-200 bg-zinc-50 p-4 dark:border-zinc-800 dark:bg-zinc-900", children: [
|
|
1360
1436
|
/* @__PURE__ */ jsx(Heading, { as: "h3", size: "xs", className: "!uppercase !tracking-wider !text-zinc-500", children: "Inspector" }),
|
|
1361
1437
|
/* @__PURE__ */ jsx(Text, { size: "sm", className: "mt-2 !text-zinc-500", children: "Select an element to edit its properties." })
|
|
@@ -1389,6 +1465,80 @@ function ElementInspector({ element, onPatch, onDelete, onLockToggle }) {
|
|
|
1389
1465
|
] }) })
|
|
1390
1466
|
] });
|
|
1391
1467
|
}
|
|
1468
|
+
function SlideSettings({
|
|
1469
|
+
slide,
|
|
1470
|
+
onSetTransition,
|
|
1471
|
+
onSetBackground
|
|
1472
|
+
}) {
|
|
1473
|
+
const transition = slide.transition;
|
|
1474
|
+
const kind = transition?.kind ?? "none";
|
|
1475
|
+
const setTransition = (next) => {
|
|
1476
|
+
const merged = { kind, duration: transition?.duration, direction: transition?.direction, ...next };
|
|
1477
|
+
onSetTransition?.(merged.kind === "none" ? { kind: "none" } : merged);
|
|
1478
|
+
};
|
|
1479
|
+
return /* @__PURE__ */ jsxs("div", { className: "fs-inspector flex h-full w-full flex-col border-l border-zinc-200 bg-zinc-50 dark:border-zinc-800 dark:bg-zinc-900", children: [
|
|
1480
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-between border-b border-zinc-200 px-3 py-2 dark:border-zinc-800", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1481
|
+
/* @__PURE__ */ jsx(Heading, { as: "h3", size: "xs", className: "!font-mono !uppercase !tracking-wider !text-zinc-500", children: "slide" }),
|
|
1482
|
+
/* @__PURE__ */ jsxs(Text, { size: "xs", className: "!font-mono !text-zinc-400", children: [
|
|
1483
|
+
"#",
|
|
1484
|
+
slide.id.slice(-6)
|
|
1485
|
+
] })
|
|
1486
|
+
] }) }),
|
|
1487
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto p-3", children: [
|
|
1488
|
+
/* @__PURE__ */ jsx(Card, { padding: "md", className: "!bg-white dark:!bg-zinc-950", children: /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
1489
|
+
/* @__PURE__ */ jsx(Heading, { as: "h4", size: "xs", className: "!uppercase !tracking-wider !text-zinc-500", children: "Transition" }),
|
|
1490
|
+
/* @__PURE__ */ jsx(
|
|
1491
|
+
Select,
|
|
1492
|
+
{
|
|
1493
|
+
label: "Kind",
|
|
1494
|
+
list: [
|
|
1495
|
+
{ value: "none", label: "None" },
|
|
1496
|
+
{ value: "fade", label: "Fade" },
|
|
1497
|
+
{ value: "slide", label: "Slide" },
|
|
1498
|
+
{ value: "zoom", label: "Zoom" }
|
|
1499
|
+
],
|
|
1500
|
+
value: kind,
|
|
1501
|
+
onValueChange: (v) => setTransition({ kind: v })
|
|
1502
|
+
}
|
|
1503
|
+
),
|
|
1504
|
+
kind === "slide" && /* @__PURE__ */ jsx(
|
|
1505
|
+
Select,
|
|
1506
|
+
{
|
|
1507
|
+
label: "Direction",
|
|
1508
|
+
list: [
|
|
1509
|
+
{ value: "left", label: "From left" },
|
|
1510
|
+
{ value: "right", label: "From right" },
|
|
1511
|
+
{ value: "up", label: "From bottom" },
|
|
1512
|
+
{ value: "down", label: "From top" }
|
|
1513
|
+
],
|
|
1514
|
+
value: transition?.direction ?? "right",
|
|
1515
|
+
onValueChange: (v) => setTransition({ direction: v })
|
|
1516
|
+
}
|
|
1517
|
+
),
|
|
1518
|
+
kind !== "none" && /* @__PURE__ */ jsx(
|
|
1519
|
+
Input,
|
|
1520
|
+
{
|
|
1521
|
+
label: "Duration (ms)",
|
|
1522
|
+
type: "number",
|
|
1523
|
+
value: String(transition?.duration ?? 400),
|
|
1524
|
+
onChange: (e) => setTransition({ duration: parseInt(e.target.value, 10) || 400 })
|
|
1525
|
+
}
|
|
1526
|
+
),
|
|
1527
|
+
/* @__PURE__ */ jsx(Text, { size: "xs", className: "!text-zinc-500", children: "Entrance animation played when this slide appears in the viewer. Falls back to the theme default. Honors prefers-reduced-motion." })
|
|
1528
|
+
] }) }),
|
|
1529
|
+
onSetBackground && /* @__PURE__ */ jsx(Card, { padding: "md", className: "mt-3 !bg-white dark:!bg-zinc-950", children: /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
1530
|
+
/* @__PURE__ */ jsx(Heading, { as: "h4", size: "xs", className: "!uppercase !tracking-wider !text-zinc-500", children: "Background" }),
|
|
1531
|
+
/* @__PURE__ */ jsx(FieldLabel, { label: "Color", children: /* @__PURE__ */ jsx(
|
|
1532
|
+
ColorPicker,
|
|
1533
|
+
{
|
|
1534
|
+
value: slide.background?.color ?? "#ffffff",
|
|
1535
|
+
onChange: (c) => onSetBackground({ ...slide.background, color: c })
|
|
1536
|
+
}
|
|
1537
|
+
) })
|
|
1538
|
+
] }) })
|
|
1539
|
+
] })
|
|
1540
|
+
] });
|
|
1541
|
+
}
|
|
1392
1542
|
function LayoutSection({ element, onPatch }) {
|
|
1393
1543
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
1394
1544
|
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
@@ -1838,13 +1988,16 @@ function DeckEditor({
|
|
|
1838
1988
|
ElementInspector,
|
|
1839
1989
|
{
|
|
1840
1990
|
element: selectedElement,
|
|
1991
|
+
slide: slide ?? null,
|
|
1841
1992
|
onPatch: (patch) => slide && elementIdSelected && ops.updateElement(slide.id, elementIdSelected, patch),
|
|
1842
1993
|
onDelete: () => {
|
|
1843
1994
|
if (!slide || !elementIdSelected) return;
|
|
1844
1995
|
ops.removeElement(slide.id, elementIdSelected);
|
|
1845
1996
|
setElementIdSelected(null);
|
|
1846
1997
|
},
|
|
1847
|
-
onLockToggle: (locked) => slide && elementIdSelected && ops.updateElement(slide.id, elementIdSelected, { locked })
|
|
1998
|
+
onLockToggle: (locked) => slide && elementIdSelected && ops.updateElement(slide.id, elementIdSelected, { locked }),
|
|
1999
|
+
onSetTransition: (transition) => slide && ops.setTransition(slide.id, transition),
|
|
2000
|
+
onSetBackground: (background) => slide && ops.setBackground(slide.id, background)
|
|
1848
2001
|
}
|
|
1849
2002
|
) })
|
|
1850
2003
|
] }),
|