@particle-academy/fancy-cms-ui 0.0.1-dev.13 → 0.0.1-dev.14

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/editor.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { ReactElement, ReactNode } from 'react';
2
2
  import { P as PageDoc, i as NodeId, N as Node, m as StyleProps, L as LayoutMode } from './types-CpfPEq3V.cjs';
3
- import { a as ElementRegistry } from './registry-Bk7GN1rA.cjs';
3
+ import { a as ElementRegistry, D as DataContext } from './registry-ni9y0dSw.cjs';
4
4
  import { P as PageOp } from './ops-CdBZarAT.cjs';
5
5
 
6
6
  interface EditorProps {
@@ -28,6 +28,8 @@ interface NodeTransform {
28
28
  interface EditablePageProps {
29
29
  doc: PageDoc;
30
30
  registry?: ElementRegistry;
31
+ /** Data context for `{ $bind }` props + repeaters (server props, etc.). */
32
+ data?: DataContext;
31
33
  /** Slot for the fancy-motion timeline dock (rendered at the bottom in EditMode). */
32
34
  timelineDock?: ReactNode;
33
35
  /** Per-node transforms applied to the page (e.g. the sampled keyframe snapshot). */
@@ -54,7 +56,7 @@ interface EditablePageProps {
54
56
  * toolbar styles it, and the selection can be **dragged to move** / **resized**
55
57
  * — committed as transforms the host captures into a timeline keyframe.
56
58
  */
57
- declare function EditablePage({ doc, registry, timelineDock, transforms, onNodeTransform, onSelect, frames, onProgress, pinned, }: EditablePageProps): ReactElement;
59
+ declare function EditablePage({ doc, registry, data, timelineDock, transforms, onNodeTransform, onSelect, frames, onProgress, pinned, }: EditablePageProps): ReactElement;
58
60
 
59
61
  interface CanvasProps {
60
62
  doc: PageDoc;
package/dist/editor.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { ReactElement, ReactNode } from 'react';
2
2
  import { P as PageDoc, i as NodeId, N as Node, m as StyleProps, L as LayoutMode } from './types-CpfPEq3V.js';
3
- import { a as ElementRegistry } from './registry-Dht9JBLU.js';
3
+ import { a as ElementRegistry, D as DataContext } from './registry-C3PioMnL.js';
4
4
  import { P as PageOp } from './ops-BsM6kZxY.js';
5
5
 
6
6
  interface EditorProps {
@@ -28,6 +28,8 @@ interface NodeTransform {
28
28
  interface EditablePageProps {
29
29
  doc: PageDoc;
30
30
  registry?: ElementRegistry;
31
+ /** Data context for `{ $bind }` props + repeaters (server props, etc.). */
32
+ data?: DataContext;
31
33
  /** Slot for the fancy-motion timeline dock (rendered at the bottom in EditMode). */
32
34
  timelineDock?: ReactNode;
33
35
  /** Per-node transforms applied to the page (e.g. the sampled keyframe snapshot). */
@@ -54,7 +56,7 @@ interface EditablePageProps {
54
56
  * toolbar styles it, and the selection can be **dragged to move** / **resized**
55
57
  * — committed as transforms the host captures into a timeline keyframe.
56
58
  */
57
- declare function EditablePage({ doc, registry, timelineDock, transforms, onNodeTransform, onSelect, frames, onProgress, pinned, }: EditablePageProps): ReactElement;
59
+ declare function EditablePage({ doc, registry, data, timelineDock, transforms, onNodeTransform, onSelect, frames, onProgress, pinned, }: EditablePageProps): ReactElement;
58
60
 
59
61
  interface CanvasProps {
60
62
  doc: PageDoc;
package/dist/editor.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { keyBetween } from './chunk-7YYLYBLI.js';
2
- import { CmsPage, defaultRegistry } from './chunk-E5AAQX7P.js';
3
- import { reduce, childrenOf } from './chunk-3YZMELJJ.js';
2
+ import { CmsPage, defaultRegistry } from './chunk-IXPYY4S2.js';
3
+ import { reduce, childrenOf, isBinding } from './chunk-3YZMELJJ.js';
4
4
  import { useReducer, useCallback, useMemo, useRef, useState, useLayoutEffect, Fragment, useEffect } from 'react';
5
5
  import { jsxs, jsx, Fragment as Fragment$1 } from 'react/jsx-runtime';
6
6
  import { ContextMenu } from '@particle-academy/react-fancy';
@@ -414,7 +414,7 @@ function NodeInspector({
414
414
  const setT = (patch) => onTransform({ ...transform, ...patch });
415
415
  const handled = /* @__PURE__ */ new Set(["content", "label"]);
416
416
  const extraKeys = Object.keys(node.props).filter(
417
- (k) => !handled.has(k) && ["string", "number", "boolean"].includes(typeof node.props[k])
417
+ (k) => !handled.has(k) && (["string", "number", "boolean"].includes(typeof node.props[k]) || isBinding(node.props[k]))
418
418
  );
419
419
  return /* @__PURE__ */ jsxs("div", { style: panel, onPointerDown: (e) => e.stopPropagation(), children: [
420
420
  /* @__PURE__ */ jsxs("div", { style: headRow, children: [
@@ -539,24 +539,50 @@ function Row({ children }) {
539
539
  return /* @__PURE__ */ jsx("div", { style: { display: "flex", gap: 8 }, children });
540
540
  }
541
541
  function PropField({ name, value, onChange }) {
542
+ const bound = isBinding(value);
543
+ const link = /* @__PURE__ */ jsx(
544
+ "button",
545
+ {
546
+ type: "button",
547
+ title: bound ? "Unbind (use a literal value)" : "Bind to data (e.g. item.name)",
548
+ onClick: () => onChange(bound ? "" : { $bind: "" }),
549
+ style: { background: "none", border: "none", cursor: "pointer", padding: 0, fontSize: 11, color: bound ? "#a78bfa" : "#64748b" },
550
+ children: "\u{1F517}"
551
+ }
552
+ );
553
+ if (bound) {
554
+ return /* @__PURE__ */ jsxs("label", { style: field, children: [
555
+ /* @__PURE__ */ jsxs("span", { style: { ...fieldLabel, display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
556
+ name,
557
+ " ",
558
+ link
559
+ ] }),
560
+ /* @__PURE__ */ jsx("input", { style: { ...input2, borderColor: "#7c3aed" }, placeholder: "data path \xB7 e.g. item.name", value: value.$bind, onChange: (e) => onChange({ $bind: e.target.value }) })
561
+ ] });
562
+ }
542
563
  if (typeof value === "boolean") {
543
564
  return /* @__PURE__ */ jsxs("label", { style: { display: "flex", alignItems: "center", gap: 8, fontSize: 12 }, children: [
544
565
  /* @__PURE__ */ jsx("input", { type: "checkbox", checked: value, onChange: (e) => onChange(e.target.checked) }),
545
- /* @__PURE__ */ jsx("span", { style: { textTransform: "capitalize" }, children: name })
566
+ /* @__PURE__ */ jsx("span", { style: { textTransform: "capitalize", flex: 1 }, children: name }),
567
+ link
546
568
  ] });
547
569
  }
548
570
  if (name === "variant") {
549
- return /* @__PURE__ */ jsx(Sel, { label: name, value: String(value), options: [["primary", "Primary"], ["ghost", "Ghost"], ["outline", "Outline"]], onChange });
571
+ return /* @__PURE__ */ jsx(Sel, { label: name, value: String(value ?? ""), options: [["primary", "Primary"], ["ghost", "Ghost"], ["outline", "Outline"]], onChange });
550
572
  }
551
573
  const isNum = typeof value === "number";
552
574
  return /* @__PURE__ */ jsxs("label", { style: field, children: [
553
- /* @__PURE__ */ jsx("span", { style: fieldLabel, children: name }),
575
+ /* @__PURE__ */ jsxs("span", { style: { ...fieldLabel, display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
576
+ name,
577
+ " ",
578
+ link
579
+ ] }),
554
580
  /* @__PURE__ */ jsx(
555
581
  "input",
556
582
  {
557
583
  style: input2,
558
584
  type: isNum ? "number" : "text",
559
- value: String(value),
585
+ value: String(value ?? ""),
560
586
  onChange: (e) => onChange(isNum ? Number(e.target.value) : e.target.value)
561
587
  }
562
588
  )
@@ -744,6 +770,7 @@ var SNAP = 6;
744
770
  function EditablePage({
745
771
  doc,
746
772
  registry = defaultRegistry,
773
+ data,
747
774
  timelineDock,
748
775
  transforms,
749
776
  onNodeTransform,
@@ -963,7 +990,7 @@ function EditablePage({
963
990
  onContextMenu: onContextMenuSelect,
964
991
  onDragOver: editing ? (e) => e.preventDefault() : void 0,
965
992
  onDrop: editing ? onPageDrop : void 0,
966
- children: /* @__PURE__ */ jsx(CmsPage, { doc: ed.state.doc, registry })
993
+ children: /* @__PURE__ */ jsx(CmsPage, { doc: ed.state.doc, registry, data })
967
994
  }
968
995
  );
969
996
  const pageShell = pinned ? /* @__PURE__ */ jsx("div", { ref: spacerRef, style: { height: `${Math.max(1, frames) * 100}vh` }, children: /* @__PURE__ */ jsx("div", { style: { position: "sticky", top: 0, height: "100vh", overflow: "hidden" }, children: page }) }) : frames > 1 ? (
@@ -1098,7 +1125,7 @@ function ElementPalette({ open, onDragChange }) {
1098
1125
  }
1099
1126
  );
1100
1127
  }
1101
- var CONTAINER_TYPES2 = /* @__PURE__ */ new Set(["section", "frame", "stack", "grid", "shape", "card", "device"]);
1128
+ var CONTAINER_TYPES2 = /* @__PURE__ */ new Set(["section", "frame", "stack", "grid", "shape", "card", "device", "repeater"]);
1102
1129
  var ADD_DEFAULTS = {
1103
1130
  text: { type: "text", props: { content: "New text" }, style: { color: "inherit" } },
1104
1131
  heading: { type: "heading", props: { content: "New heading" }, style: { fontSize: { value: 28, unit: "px" }, fontWeight: 700 } },
@@ -1111,7 +1138,8 @@ var ADD_DEFAULTS = {
1111
1138
  card: { type: "card", props: {}, style: { padding: { value: 16, unit: "px" }, radius: { value: 12, unit: "px" }, border: "1px solid #e2e8f0" } },
1112
1139
  callout: { type: "callout", props: { content: "Heads up \u2014 this is a callout.", variant: "info" }, style: {} },
1113
1140
  divider: { type: "divider", props: {}, style: {} },
1114
- code: { type: "code", props: { content: "npm install @particle-academy/react-fancy", lang: "bash" }, style: {} }
1141
+ code: { type: "code", props: { content: "npm install @particle-academy/react-fancy", lang: "bash" }, style: {} },
1142
+ repeater: { type: "repeater", props: { items: "" }, style: { gap: { value: 12, unit: "px" } }, layout: "stack" }
1115
1143
  };
1116
1144
  var GRIPS = [
1117
1145
  { key: "nw", north: true, west: true, cursor: "nwse-resize" },
@@ -1322,7 +1350,8 @@ var ADD_MENU = [
1322
1350
  { kind: "grid", label: "Grid" },
1323
1351
  { kind: "box", label: "Box" },
1324
1352
  { kind: "divider", label: "Divider" },
1325
- { kind: "code", label: "Code" }
1353
+ { kind: "code", label: "Code" },
1354
+ { kind: "repeater", label: "Repeater" }
1326
1355
  ];
1327
1356
  function EditBar({
1328
1357
  editing,