@particle-academy/fancy-slides 0.1.7 → 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 +12 -5
- package/dist/index.d.ts +12 -5
- package/dist/index.js +157 -4
- package/dist/index.js.map +1 -1
- package/dist/registry.d.cts +1 -1
- package/dist/registry.d.ts +1 -1
- package/dist/{types-Bc-psiRF.d.cts → types-B2ecrEAz.d.cts} +4 -0
- package/dist/{types-Bc-psiRF.d.ts → types-B2ecrEAz.d.ts} +4 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -653,6 +653,11 @@ function SlideViewer({
|
|
|
653
653
|
);
|
|
654
654
|
const [blanked, setBlanked] = react.useState(false);
|
|
655
655
|
const containerRef = react.useRef(null);
|
|
656
|
+
const prevIndexRef = react.useRef(index);
|
|
657
|
+
const forward = index >= prevIndexRef.current;
|
|
658
|
+
react.useEffect(() => {
|
|
659
|
+
prevIndexRef.current = index;
|
|
660
|
+
}, [index]);
|
|
656
661
|
useSlideKeyboard({
|
|
657
662
|
total: deck.slides.length,
|
|
658
663
|
index,
|
|
@@ -676,6 +681,8 @@ function SlideViewer({
|
|
|
676
681
|
const slide = deck.slides[index];
|
|
677
682
|
const theme = resolveTheme(deck.theme);
|
|
678
683
|
const aspectRatio = theme.aspectRatio ?? 16 / 9;
|
|
684
|
+
const transition = slide?.transition ?? theme.defaultTransition;
|
|
685
|
+
const enterStyle = transitionEnterStyle(transition, forward);
|
|
679
686
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
680
687
|
"div",
|
|
681
688
|
{
|
|
@@ -694,6 +701,7 @@ function SlideViewer({
|
|
|
694
701
|
tabIndex: 0,
|
|
695
702
|
"data-fancy-slides-viewer": deck.id,
|
|
696
703
|
children: [
|
|
704
|
+
/* @__PURE__ */ jsxRuntime.jsx("style", { children: TRANSITION_KEYFRAMES }),
|
|
697
705
|
!blanked && slide && /* @__PURE__ */ jsxRuntime.jsx(
|
|
698
706
|
"div",
|
|
699
707
|
{
|
|
@@ -705,7 +713,7 @@ function SlideViewer({
|
|
|
705
713
|
["--fs-ratio"]: aspectRatio.toString(),
|
|
706
714
|
boxShadow: "0 8px 30px rgba(0,0,0,0.35)"
|
|
707
715
|
},
|
|
708
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(Slide, { slide, theme, renderElement })
|
|
716
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "fs-slide-enter", style: enterStyle, children: /* @__PURE__ */ jsxRuntime.jsx(Slide, { slide, theme, renderElement }) }, index)
|
|
709
717
|
}
|
|
710
718
|
),
|
|
711
719
|
!hideChrome && !blanked && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -735,6 +743,68 @@ function SlideViewer({
|
|
|
735
743
|
}
|
|
736
744
|
);
|
|
737
745
|
}
|
|
746
|
+
var DEFAULT_DURATION = 400;
|
|
747
|
+
var EASE = "cubic-bezier(0.16, 1, 0.3, 1)";
|
|
748
|
+
function transitionEnterStyle(transition, forward) {
|
|
749
|
+
const kind = transition?.kind ?? "none";
|
|
750
|
+
if (kind === "none") return { width: "100%", height: "100%" };
|
|
751
|
+
const duration = transition?.duration ?? DEFAULT_DURATION;
|
|
752
|
+
let name;
|
|
753
|
+
switch (kind) {
|
|
754
|
+
case "fade":
|
|
755
|
+
name = "fs-fade-in";
|
|
756
|
+
break;
|
|
757
|
+
case "zoom":
|
|
758
|
+
name = "fs-zoom-in";
|
|
759
|
+
break;
|
|
760
|
+
case "slide": {
|
|
761
|
+
const dir = transition?.direction ?? (forward ? "right" : "left");
|
|
762
|
+
name = `fs-slide-in-${dir}`;
|
|
763
|
+
break;
|
|
764
|
+
}
|
|
765
|
+
default:
|
|
766
|
+
return { width: "100%", height: "100%" };
|
|
767
|
+
}
|
|
768
|
+
return {
|
|
769
|
+
width: "100%",
|
|
770
|
+
height: "100%",
|
|
771
|
+
animationName: name,
|
|
772
|
+
animationDuration: `${duration}ms`,
|
|
773
|
+
animationTimingFunction: EASE,
|
|
774
|
+
animationFillMode: "both"
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
var TRANSITION_KEYFRAMES = `
|
|
778
|
+
@media (prefers-reduced-motion: reduce) {
|
|
779
|
+
.fs-slide-enter { animation: none !important; }
|
|
780
|
+
}
|
|
781
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
782
|
+
@keyframes fs-fade-in {
|
|
783
|
+
from { opacity: 0; }
|
|
784
|
+
to { opacity: 1; }
|
|
785
|
+
}
|
|
786
|
+
@keyframes fs-zoom-in {
|
|
787
|
+
from { opacity: 0; transform: scale(0.92); }
|
|
788
|
+
to { opacity: 1; transform: scale(1); }
|
|
789
|
+
}
|
|
790
|
+
@keyframes fs-slide-in-right {
|
|
791
|
+
from { opacity: 0; transform: translateX(8%); }
|
|
792
|
+
to { opacity: 1; transform: translateX(0); }
|
|
793
|
+
}
|
|
794
|
+
@keyframes fs-slide-in-left {
|
|
795
|
+
from { opacity: 0; transform: translateX(-8%); }
|
|
796
|
+
to { opacity: 1; transform: translateX(0); }
|
|
797
|
+
}
|
|
798
|
+
@keyframes fs-slide-in-up {
|
|
799
|
+
from { opacity: 0; transform: translateY(8%); }
|
|
800
|
+
to { opacity: 1; transform: translateY(0); }
|
|
801
|
+
}
|
|
802
|
+
@keyframes fs-slide-in-down {
|
|
803
|
+
from { opacity: 0; transform: translateY(-8%); }
|
|
804
|
+
to { opacity: 1; transform: translateY(0); }
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
`;
|
|
738
808
|
function PresenterView({
|
|
739
809
|
deck,
|
|
740
810
|
index: controlledIndex,
|
|
@@ -1088,6 +1158,7 @@ function useDeckState({ value, onChange, onOp }) {
|
|
|
1088
1158
|
setLayout: (id, layout) => apply({ kind: "slide_set_layout", id, layout }),
|
|
1089
1159
|
setNotes: (id, notes) => apply({ kind: "slide_set_notes", id, notes }),
|
|
1090
1160
|
setBackground: (id, background) => apply({ kind: "slide_set_background", id, background }),
|
|
1161
|
+
setTransition: (id, transition) => apply({ kind: "slide_set_transition", id, transition }),
|
|
1091
1162
|
addElement: (slideId2, element) => {
|
|
1092
1163
|
const id = element.id ?? elementId();
|
|
1093
1164
|
apply({ kind: "element_add", slideId: slideId2, element: { ...element, id } });
|
|
@@ -1129,6 +1200,8 @@ function reduce(deck, op) {
|
|
|
1129
1200
|
return { ...deck, slides: deck.slides.map((s) => s.id === op.id ? { ...s, notes: op.notes } : s) };
|
|
1130
1201
|
case "slide_set_background":
|
|
1131
1202
|
return { ...deck, slides: deck.slides.map((s) => s.id === op.id ? { ...s, background: op.background } : s) };
|
|
1203
|
+
case "slide_set_transition":
|
|
1204
|
+
return { ...deck, slides: deck.slides.map((s) => s.id === op.id ? { ...s, transition: op.transition } : s) };
|
|
1132
1205
|
case "element_add":
|
|
1133
1206
|
return {
|
|
1134
1207
|
...deck,
|
|
@@ -1396,8 +1469,11 @@ function EditorToolbar({
|
|
|
1396
1469
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-auto flex items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsx(reactFancy.Tooltip, { content: "Present (F)", children: /* @__PURE__ */ jsxRuntime.jsx(reactFancy.Action, { color: "violet", size: "sm", icon: "play", onClick: onPresent, children: "Present" }) }) })
|
|
1397
1470
|
] });
|
|
1398
1471
|
}
|
|
1399
|
-
function ElementInspector({ element, onPatch, onDelete, onLockToggle }) {
|
|
1472
|
+
function ElementInspector({ element, onPatch, onDelete, onLockToggle, slide, onSetTransition, onSetBackground }) {
|
|
1400
1473
|
if (!element) {
|
|
1474
|
+
if (slide) {
|
|
1475
|
+
return /* @__PURE__ */ jsxRuntime.jsx(SlideSettings, { slide, onSetTransition, onSetBackground });
|
|
1476
|
+
}
|
|
1401
1477
|
return /* @__PURE__ */ jsxRuntime.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: [
|
|
1402
1478
|
/* @__PURE__ */ jsxRuntime.jsx(reactFancy.Heading, { as: "h3", size: "xs", className: "!uppercase !tracking-wider !text-zinc-500", children: "Inspector" }),
|
|
1403
1479
|
/* @__PURE__ */ jsxRuntime.jsx(reactFancy.Text, { size: "sm", className: "mt-2 !text-zinc-500", children: "Select an element to edit its properties." })
|
|
@@ -1431,6 +1507,80 @@ function ElementInspector({ element, onPatch, onDelete, onLockToggle }) {
|
|
|
1431
1507
|
] }) })
|
|
1432
1508
|
] });
|
|
1433
1509
|
}
|
|
1510
|
+
function SlideSettings({
|
|
1511
|
+
slide,
|
|
1512
|
+
onSetTransition,
|
|
1513
|
+
onSetBackground
|
|
1514
|
+
}) {
|
|
1515
|
+
const transition = slide.transition;
|
|
1516
|
+
const kind = transition?.kind ?? "none";
|
|
1517
|
+
const setTransition = (next) => {
|
|
1518
|
+
const merged = { kind, duration: transition?.duration, direction: transition?.direction, ...next };
|
|
1519
|
+
onSetTransition?.(merged.kind === "none" ? { kind: "none" } : merged);
|
|
1520
|
+
};
|
|
1521
|
+
return /* @__PURE__ */ jsxRuntime.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: [
|
|
1522
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between border-b border-zinc-200 px-3 py-2 dark:border-zinc-800", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1523
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactFancy.Heading, { as: "h3", size: "xs", className: "!font-mono !uppercase !tracking-wider !text-zinc-500", children: "slide" }),
|
|
1524
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactFancy.Text, { size: "xs", className: "!font-mono !text-zinc-400", children: [
|
|
1525
|
+
"#",
|
|
1526
|
+
slide.id.slice(-6)
|
|
1527
|
+
] })
|
|
1528
|
+
] }) }),
|
|
1529
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto p-3", children: [
|
|
1530
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactFancy.Card, { padding: "md", className: "!bg-white dark:!bg-zinc-950", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
|
|
1531
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactFancy.Heading, { as: "h4", size: "xs", className: "!uppercase !tracking-wider !text-zinc-500", children: "Transition" }),
|
|
1532
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1533
|
+
reactFancy.Select,
|
|
1534
|
+
{
|
|
1535
|
+
label: "Kind",
|
|
1536
|
+
list: [
|
|
1537
|
+
{ value: "none", label: "None" },
|
|
1538
|
+
{ value: "fade", label: "Fade" },
|
|
1539
|
+
{ value: "slide", label: "Slide" },
|
|
1540
|
+
{ value: "zoom", label: "Zoom" }
|
|
1541
|
+
],
|
|
1542
|
+
value: kind,
|
|
1543
|
+
onValueChange: (v) => setTransition({ kind: v })
|
|
1544
|
+
}
|
|
1545
|
+
),
|
|
1546
|
+
kind === "slide" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1547
|
+
reactFancy.Select,
|
|
1548
|
+
{
|
|
1549
|
+
label: "Direction",
|
|
1550
|
+
list: [
|
|
1551
|
+
{ value: "left", label: "From left" },
|
|
1552
|
+
{ value: "right", label: "From right" },
|
|
1553
|
+
{ value: "up", label: "From bottom" },
|
|
1554
|
+
{ value: "down", label: "From top" }
|
|
1555
|
+
],
|
|
1556
|
+
value: transition?.direction ?? "right",
|
|
1557
|
+
onValueChange: (v) => setTransition({ direction: v })
|
|
1558
|
+
}
|
|
1559
|
+
),
|
|
1560
|
+
kind !== "none" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1561
|
+
reactFancy.Input,
|
|
1562
|
+
{
|
|
1563
|
+
label: "Duration (ms)",
|
|
1564
|
+
type: "number",
|
|
1565
|
+
value: String(transition?.duration ?? 400),
|
|
1566
|
+
onChange: (e) => setTransition({ duration: parseInt(e.target.value, 10) || 400 })
|
|
1567
|
+
}
|
|
1568
|
+
),
|
|
1569
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactFancy.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." })
|
|
1570
|
+
] }) }),
|
|
1571
|
+
onSetBackground && /* @__PURE__ */ jsxRuntime.jsx(reactFancy.Card, { padding: "md", className: "mt-3 !bg-white dark:!bg-zinc-950", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
|
|
1572
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactFancy.Heading, { as: "h4", size: "xs", className: "!uppercase !tracking-wider !text-zinc-500", children: "Background" }),
|
|
1573
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldLabel, { label: "Color", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1574
|
+
reactFancy.ColorPicker,
|
|
1575
|
+
{
|
|
1576
|
+
value: slide.background?.color ?? "#ffffff",
|
|
1577
|
+
onChange: (c) => onSetBackground({ ...slide.background, color: c })
|
|
1578
|
+
}
|
|
1579
|
+
) })
|
|
1580
|
+
] }) })
|
|
1581
|
+
] })
|
|
1582
|
+
] });
|
|
1583
|
+
}
|
|
1434
1584
|
function LayoutSection({ element, onPatch }) {
|
|
1435
1585
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
|
|
1436
1586
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
@@ -1880,13 +2030,16 @@ function DeckEditor({
|
|
|
1880
2030
|
ElementInspector,
|
|
1881
2031
|
{
|
|
1882
2032
|
element: selectedElement,
|
|
2033
|
+
slide: slide ?? null,
|
|
1883
2034
|
onPatch: (patch) => slide && elementIdSelected && ops.updateElement(slide.id, elementIdSelected, patch),
|
|
1884
2035
|
onDelete: () => {
|
|
1885
2036
|
if (!slide || !elementIdSelected) return;
|
|
1886
2037
|
ops.removeElement(slide.id, elementIdSelected);
|
|
1887
2038
|
setElementIdSelected(null);
|
|
1888
2039
|
},
|
|
1889
|
-
onLockToggle: (locked) => slide && elementIdSelected && ops.updateElement(slide.id, elementIdSelected, { locked })
|
|
2040
|
+
onLockToggle: (locked) => slide && elementIdSelected && ops.updateElement(slide.id, elementIdSelected, { locked }),
|
|
2041
|
+
onSetTransition: (transition) => slide && ops.setTransition(slide.id, transition),
|
|
2042
|
+
onSetBackground: (background) => slide && ops.setBackground(slide.id, background)
|
|
1890
2043
|
}
|
|
1891
2044
|
) })
|
|
1892
2045
|
] }),
|