@particle-academy/fancy-slides 0.7.0 → 0.8.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.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode, CSSProperties } from 'react';
3
- import { h as Slide$1, o as Theme, j as SlideElement, D as Deck, d as DeckOp, g as ShapeKind, l as SlideTransition, i as SlideBackground, E as ElementAnimation, m as TextElement, I as ImageElement, S as ShapeElement, k as SlideLayout } from './types-9BbelJX1.cjs';
3
+ import { h as Slide$1, o as Theme, j as SlideElement, D as Deck, d as DeckOp, g as ShapeKind, l as SlideTransition, i as SlideBackground, k as SlideLayout, E as ElementAnimation, m as TextElement, I as ImageElement, S as ShapeElement } from './types-9BbelJX1.cjs';
4
4
  export { A as AnimationEffect, a as AnimationTrigger, C as ChartElement, b as CodeElement, c as DeckActivity, e as ElementBase, f as EmbedElement, T as TableElement, n as TextStyle, p as ThemeColors, q as ThemeFonts, r as TransitionKind } from './types-9BbelJX1.cjs';
5
5
  import { EditorAction } from '@particle-academy/react-fancy';
6
6
 
@@ -323,6 +323,8 @@ interface ElementInspectorProps {
323
323
  onSetTransition?: (transition?: SlideTransition) => void;
324
324
  /** Set the slide's background. */
325
325
  onSetBackground?: (background?: SlideBackground) => void;
326
+ /** Set the slide's layout preset. */
327
+ onSetLayout?: (layout: SlideLayout) => void;
326
328
  /** Set or clear the selected element's entrance build animation. */
327
329
  onSetAnimation?: (animation?: ElementAnimation) => void;
328
330
  /** Set a specific element's build animation by id — used by the slide-level build-order list. */
@@ -334,7 +336,7 @@ interface ElementInspectorProps {
334
336
  * react-fancy `Card`, `Tabs`, `Input`, `Select`, `Slider`, `ColorPicker`,
335
337
  * `Action`.
336
338
  */
337
- declare function ElementInspector({ element, onPatch, onDelete, onLockToggle, slide, onSetTransition, onSetBackground, onSetAnimation, onSetElementAnimation }: ElementInspectorProps): react_jsx_runtime.JSX.Element;
339
+ declare function ElementInspector({ element, onPatch, onDelete, onLockToggle, slide, onSetTransition, onSetBackground, onSetLayout, onSetAnimation, onSetElementAnimation }: ElementInspectorProps): react_jsx_runtime.JSX.Element;
338
340
 
339
341
  interface SpeakerNotesProps {
340
342
  notes?: string;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode, CSSProperties } from 'react';
3
- import { h as Slide$1, o as Theme, j as SlideElement, D as Deck, d as DeckOp, g as ShapeKind, l as SlideTransition, i as SlideBackground, E as ElementAnimation, m as TextElement, I as ImageElement, S as ShapeElement, k as SlideLayout } from './types-9BbelJX1.js';
3
+ import { h as Slide$1, o as Theme, j as SlideElement, D as Deck, d as DeckOp, g as ShapeKind, l as SlideTransition, i as SlideBackground, k as SlideLayout, E as ElementAnimation, m as TextElement, I as ImageElement, S as ShapeElement } from './types-9BbelJX1.js';
4
4
  export { A as AnimationEffect, a as AnimationTrigger, C as ChartElement, b as CodeElement, c as DeckActivity, e as ElementBase, f as EmbedElement, T as TableElement, n as TextStyle, p as ThemeColors, q as ThemeFonts, r as TransitionKind } from './types-9BbelJX1.js';
5
5
  import { EditorAction } from '@particle-academy/react-fancy';
6
6
 
@@ -323,6 +323,8 @@ interface ElementInspectorProps {
323
323
  onSetTransition?: (transition?: SlideTransition) => void;
324
324
  /** Set the slide's background. */
325
325
  onSetBackground?: (background?: SlideBackground) => void;
326
+ /** Set the slide's layout preset. */
327
+ onSetLayout?: (layout: SlideLayout) => void;
326
328
  /** Set or clear the selected element's entrance build animation. */
327
329
  onSetAnimation?: (animation?: ElementAnimation) => void;
328
330
  /** Set a specific element's build animation by id — used by the slide-level build-order list. */
@@ -334,7 +336,7 @@ interface ElementInspectorProps {
334
336
  * react-fancy `Card`, `Tabs`, `Input`, `Select`, `Slider`, `ColorPicker`,
335
337
  * `Action`.
336
338
  */
337
- declare function ElementInspector({ element, onPatch, onDelete, onLockToggle, slide, onSetTransition, onSetBackground, onSetAnimation, onSetElementAnimation }: ElementInspectorProps): react_jsx_runtime.JSX.Element;
339
+ declare function ElementInspector({ element, onPatch, onDelete, onLockToggle, slide, onSetTransition, onSetBackground, onSetLayout, onSetAnimation, onSetElementAnimation }: ElementInspectorProps): react_jsx_runtime.JSX.Element;
338
340
 
339
341
  interface SpeakerNotesProps {
340
342
  notes?: string;
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import { defaultElementRegistry } from './chunk-YEJZYKVB.js';
2
2
  import { isDarkColor, SlideContext } from './chunk-WIUXPQAK.js';
3
3
  export { useIsDarkSlide, useSlideContext, useSlideTheme } from './chunk-WIUXPQAK.js';
4
4
  import { useId, useRef, useState, useEffect, useMemo, useCallback } from 'react';
5
- import { Editor, ContentRenderer, Text, Action, ContextMenu, Separator, Tooltip, Dropdown, Badge, Heading, Tabs, Card, Select, Input, ColorPicker, Slider, Switch, Textarea } from '@particle-academy/react-fancy';
5
+ import { Editor, ContentRenderer, Text, Action, ContextMenu, Separator, Tooltip, Dropdown, Badge, Heading, Tabs, Card, Select, Input, ColorPicker, Textarea, Slider, Switch } from '@particle-academy/react-fancy';
6
6
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
7
7
 
8
8
  // src/theme/default-theme.ts
@@ -1999,10 +1999,10 @@ function EditorToolbar({
1999
1999
  /* @__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" }) }) })
2000
2000
  ] });
2001
2001
  }
2002
- function ElementInspector({ element, onPatch, onDelete, onLockToggle, slide, onSetTransition, onSetBackground, onSetAnimation, onSetElementAnimation }) {
2002
+ function ElementInspector({ element, onPatch, onDelete, onLockToggle, slide, onSetTransition, onSetBackground, onSetLayout, onSetAnimation, onSetElementAnimation }) {
2003
2003
  if (!element) {
2004
2004
  if (slide) {
2005
- return /* @__PURE__ */ jsx(SlideSettings, { slide, onSetTransition, onSetBackground, onSetElementAnimation });
2005
+ return /* @__PURE__ */ jsx(SlideSettings, { slide, onSetTransition, onSetBackground, onSetLayout, onSetElementAnimation });
2006
2006
  }
2007
2007
  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: [
2008
2008
  /* @__PURE__ */ jsx(Heading, { as: "h3", size: "xs", className: "!uppercase !tracking-wider !text-zinc-500", children: "Inspector" }),
@@ -2039,10 +2039,26 @@ function ElementInspector({ element, onPatch, onDelete, onLockToggle, slide, onS
2039
2039
  ] }) })
2040
2040
  ] });
2041
2041
  }
2042
+ var SLIDE_LAYOUTS = [
2043
+ { value: "blank", label: "Blank" },
2044
+ { value: "title", label: "Title" },
2045
+ { value: "title-content", label: "Title + content" },
2046
+ { value: "two-column", label: "Two column" },
2047
+ { value: "section-divider", label: "Section divider" },
2048
+ { value: "image-text", label: "Image + text" },
2049
+ { value: "text-image", label: "Text + image" },
2050
+ { value: "quote", label: "Quote" }
2051
+ ];
2052
+ function backgroundMode(bg) {
2053
+ if (bg?.gradient) return "gradient";
2054
+ if (bg?.image) return "image";
2055
+ return "color";
2056
+ }
2042
2057
  function SlideSettings({
2043
2058
  slide,
2044
2059
  onSetTransition,
2045
2060
  onSetBackground,
2061
+ onSetLayout,
2046
2062
  onSetElementAnimation
2047
2063
  }) {
2048
2064
  const transition = slide.transition;
@@ -2051,6 +2067,7 @@ function SlideSettings({
2051
2067
  const merged = { kind, duration: transition?.duration, direction: transition?.direction, ...next };
2052
2068
  onSetTransition?.(merged.kind === "none" ? { kind: "none" } : merged);
2053
2069
  };
2070
+ const bgMode = backgroundMode(slide.background);
2054
2071
  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: [
2055
2072
  /* @__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: [
2056
2073
  /* @__PURE__ */ jsx(Heading, { as: "h3", size: "xs", className: "!font-mono !uppercase !tracking-wider !text-zinc-500", children: "slide" }),
@@ -2060,6 +2077,19 @@ function SlideSettings({
2060
2077
  ] })
2061
2078
  ] }) }),
2062
2079
  /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto p-3", children: [
2080
+ onSetLayout && /* @__PURE__ */ jsx(Card, { padding: "md", className: "mb-3 !bg-white dark:!bg-zinc-950", children: /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
2081
+ /* @__PURE__ */ jsx(Heading, { as: "h4", size: "xs", className: "!uppercase !tracking-wider !text-zinc-500", children: "Layout" }),
2082
+ /* @__PURE__ */ jsx(
2083
+ Select,
2084
+ {
2085
+ label: "Preset",
2086
+ list: SLIDE_LAYOUTS,
2087
+ value: slide.layout ?? "blank",
2088
+ onValueChange: (v) => onSetLayout(v)
2089
+ }
2090
+ ),
2091
+ /* @__PURE__ */ jsx(Text, { size: "xs", className: "!text-zinc-500", children: "The layout hint the deck commits to \u2014 carried through to the pptx export's slide layout." })
2092
+ ] }) }),
2063
2093
  /* @__PURE__ */ jsx(Card, { padding: "md", className: "!bg-white dark:!bg-zinc-950", children: /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
2064
2094
  /* @__PURE__ */ jsx(Heading, { as: "h4", size: "xs", className: "!uppercase !tracking-wider !text-zinc-500", children: "Transition" }),
2065
2095
  /* @__PURE__ */ jsx(
@@ -2103,13 +2133,63 @@ function SlideSettings({
2103
2133
  ] }) }),
2104
2134
  onSetBackground && /* @__PURE__ */ jsx(Card, { padding: "md", className: "mt-3 !bg-white dark:!bg-zinc-950", children: /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
2105
2135
  /* @__PURE__ */ jsx(Heading, { as: "h4", size: "xs", className: "!uppercase !tracking-wider !text-zinc-500", children: "Background" }),
2106
- /* @__PURE__ */ jsx(FieldLabel, { label: "Color", children: /* @__PURE__ */ jsx(
2136
+ /* @__PURE__ */ jsx(
2137
+ Select,
2138
+ {
2139
+ label: "Type",
2140
+ list: [
2141
+ { value: "color", label: "Solid color" },
2142
+ { value: "gradient", label: "Gradient" },
2143
+ { value: "image", label: "Image" }
2144
+ ],
2145
+ value: bgMode,
2146
+ onValueChange: (v) => {
2147
+ if (v === "color") onSetBackground({ color: slide.background?.color ?? "#ffffff" });
2148
+ else if (v === "gradient") onSetBackground({ gradient: slide.background?.gradient ?? "linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)" });
2149
+ else onSetBackground({ image: slide.background?.image ?? "", imageFit: slide.background?.imageFit ?? "cover", color: slide.background?.color });
2150
+ }
2151
+ }
2152
+ ),
2153
+ bgMode === "color" && /* @__PURE__ */ jsx(FieldLabel, { label: "Color", children: /* @__PURE__ */ jsx(
2107
2154
  ColorPicker,
2108
2155
  {
2109
2156
  value: slide.background?.color ?? "#ffffff",
2110
- onChange: (c) => onSetBackground({ ...slide.background, color: c })
2157
+ onChange: (c) => onSetBackground({ color: c })
2111
2158
  }
2112
- ) })
2159
+ ) }),
2160
+ bgMode === "gradient" && /* @__PURE__ */ jsx(
2161
+ Textarea,
2162
+ {
2163
+ label: "CSS gradient",
2164
+ value: slide.background?.gradient ?? "",
2165
+ onValueChange: (v) => onSetBackground({ gradient: v }),
2166
+ rows: 2
2167
+ }
2168
+ ),
2169
+ bgMode === "image" && /* @__PURE__ */ jsxs(Fragment, { children: [
2170
+ /* @__PURE__ */ jsx(
2171
+ Textarea,
2172
+ {
2173
+ label: "Image URL",
2174
+ value: slide.background?.image ?? "",
2175
+ onValueChange: (v) => onSetBackground({ ...slide.background, image: v }),
2176
+ rows: 2
2177
+ }
2178
+ ),
2179
+ /* @__PURE__ */ jsx(
2180
+ Select,
2181
+ {
2182
+ label: "Fit",
2183
+ list: [
2184
+ { value: "cover", label: "Cover" },
2185
+ { value: "contain", label: "Contain" },
2186
+ { value: "fill", label: "Fill (stretch)" }
2187
+ ],
2188
+ value: slide.background?.imageFit ?? "cover",
2189
+ onValueChange: (v) => onSetBackground({ ...slide.background, imageFit: v })
2190
+ }
2191
+ )
2192
+ ] })
2113
2193
  ] }) }),
2114
2194
  onSetElementAnimation && /* @__PURE__ */ jsx(Card, { padding: "md", className: "mt-3 !bg-white dark:!bg-zinc-950", children: /* @__PURE__ */ jsx(BuildOrderList, { slide, onSetElementAnimation }) })
2115
2195
  ] })
@@ -2350,6 +2430,24 @@ function TextStyleControls({ element, onPatch }) {
2350
2430
  onValueChange: (v) => setStyle({ align: v })
2351
2431
  }
2352
2432
  ),
2433
+ /* @__PURE__ */ jsx(
2434
+ Select,
2435
+ {
2436
+ label: "Vertical align",
2437
+ list: [
2438
+ { value: "top", label: "Top" },
2439
+ { value: "middle", label: "Middle" },
2440
+ { value: "bottom", label: "Bottom" }
2441
+ ],
2442
+ value: s.verticalAlign ?? "top",
2443
+ onValueChange: (v) => setStyle({ verticalAlign: v })
2444
+ }
2445
+ ),
2446
+ /* @__PURE__ */ jsx(Input, { label: "Line height", type: "number", value: String(s.lineHeight ?? 1.4), onChange: (e) => setStyle({ lineHeight: parseFloat(e.target.value) || 1.4 }) }),
2447
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
2448
+ /* @__PURE__ */ jsx(Switch, { label: "Italic", checked: !!s.italic, onCheckedChange: (v) => setStyle({ italic: v }) }),
2449
+ /* @__PURE__ */ jsx(Switch, { label: "Underline", checked: !!s.underline, onCheckedChange: (v) => setStyle({ underline: v }) })
2450
+ ] }),
2353
2451
  /* @__PURE__ */ jsx(FieldLabel, { label: "Color", children: /* @__PURE__ */ jsx(ColorPicker, { value: s.color ?? "#0f172a", onChange: (c) => setStyle({ color: c }) }) })
2354
2452
  ] });
2355
2453
  }
@@ -2432,6 +2530,7 @@ function ShapeStyleControls({ element, onPatch }) {
2432
2530
  /* @__PURE__ */ jsx(FieldLabel, { label: "Fill", children: /* @__PURE__ */ jsx(ColorPicker, { value: element.fill ?? "#ffffff", onChange: (c) => onPatch({ fill: c }) }) }),
2433
2531
  /* @__PURE__ */ jsx(FieldLabel, { label: "Stroke", children: /* @__PURE__ */ jsx(ColorPicker, { value: element.stroke ?? "#0f172a", onChange: (c) => onPatch({ stroke: c }) }) }),
2434
2532
  /* @__PURE__ */ jsx(Slider, { label: "Stroke width", value: element.strokeWidth ?? 2, onValueChange: (v) => onPatch({ strokeWidth: Number(v) }), min: 0, max: 20, step: 0.5 }),
2533
+ /* @__PURE__ */ jsx(Switch, { label: "Dashed stroke", checked: !!element.dashed, onCheckedChange: (v) => onPatch({ dashed: v }) }),
2435
2534
  (element.shape === "rounded-rect" || element.shape === "rect") && /* @__PURE__ */ jsx(Slider, { label: "Corner radius", value: element.radius ?? 0, onValueChange: (v) => onPatch({ radius: Number(v) }), min: 0, max: 40 })
2436
2535
  ] });
2437
2536
  }
@@ -2451,7 +2550,8 @@ function CodeStyleControls({ element, onPatch }) {
2451
2550
  value: element.codeTheme ?? "auto",
2452
2551
  onValueChange: (v) => onPatch({ codeTheme: v })
2453
2552
  }
2454
- )
2553
+ ),
2554
+ /* @__PURE__ */ jsx(Switch, { label: "Line numbers", checked: element.lineNumbers ?? true, onCheckedChange: (v) => onPatch({ lineNumbers: v }) })
2455
2555
  ] });
2456
2556
  }
2457
2557
  function ChartStyleControls({ element, onPatch }) {
@@ -2958,6 +3058,7 @@ function DeckEditor({
2958
3058
  onLockToggle: (locked) => slide && elementIdSelected && ops.updateElement(slide.id, elementIdSelected, { locked }),
2959
3059
  onSetTransition: (transition) => slide && ops.setTransition(slide.id, transition),
2960
3060
  onSetBackground: (background) => slide && ops.setBackground(slide.id, background),
3061
+ onSetLayout: (layout) => slide && ops.setLayout(slide.id, layout),
2961
3062
  onSetAnimation: (animation) => slide && elementIdSelected && ops.setAnimation(slide.id, elementIdSelected, animation),
2962
3063
  onSetElementAnimation: (eid, animation) => slide && ops.setAnimation(slide.id, eid, animation)
2963
3064
  }