@particle-academy/fancy-cms-ui 0.8.0 → 0.10.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,7 +1,7 @@
1
- import { B as Binding, P as PageDoc, m as NodeId, N as Node, J as Json, q as StyleProps, L as LayoutMode } from './registry-B4FaQDip.cjs';
2
- export { A as Action, a as ActionEvent, b as ActionHandler, c as Anim, d as AnimDriver, e as Bound, f as Breakpoint, C as Constraints, D as DEFAULT_BREAKPOINTS, g as DataContext, E as ElementContext, h as ElementRegistry, i as ElementRenderer, K as Keyframe, j as LegacyPageDoc, k as Length, l as LengthUnit, M as MigrateResult, n as PageMeta, o as PerBreakpoint, S as ScrollMode, p as SizeMode, T as ThemeTokens, r as defaultRegistry, s as emptyDoc, t as getPath, u as hasNodeMap, v as isBinding, w as migrateDoc, x as migrateDocVerbose, y as needsMigration, z as resolveValue } from './registry-B4FaQDip.cjs';
3
- import { P as PageOp } from './useEditor-CIRm2oi-.cjs';
4
- export { A as Actor, C as Canvas, a as CanvasProps, E as Editor, b as EditorAction, c as EditorApi, d as EditorProps, e as EditorState, I as Inspector, f as InspectorProps, L as LayersPanel, g as LayersPanelProps, O as OpEnvelope, h as PageOpType, i as editorReduce, j as initEditor, u as useEditor } from './useEditor-CIRm2oi-.cjs';
1
+ import { B as Binding, P as PageDoc, m as NodeId, N as Node, J as Json, q as StyleProps, L as LayoutMode } from './registry-F2TAMjhx.cjs';
2
+ export { A as Action, a as ActionEvent, b as ActionHandler, c as Anim, d as AnimDriver, e as Bound, f as Breakpoint, C as Constraints, D as DEFAULT_BREAKPOINTS, g as DataContext, E as ElementContext, h as ElementRegistry, i as ElementRenderer, K as Keyframe, j as LegacyPageDoc, k as Length, l as LengthUnit, M as MigrateResult, n as PageMeta, o as PerBreakpoint, S as ScrollMode, p as SizeMode, T as ThemeTokens, r as defaultRegistry, s as emptyDoc, t as getPath, u as hasNodeMap, v as isBinding, w as migrateDoc, x as migrateDocVerbose, y as needsMigration, z as resolveValue, F as withNodeDefaults } from './registry-F2TAMjhx.cjs';
3
+ import { P as PageOp } from './useEditor-fIQEaKzZ.cjs';
4
+ export { A as Actor, C as Canvas, a as CanvasProps, E as Editor, b as EditorAction, c as EditorApi, d as EditorProps, e as EditorState, I as Inspector, f as InspectorProps, L as LayersPanel, g as LayersPanelProps, O as OpEnvelope, h as PageOpType, i as editorReduce, j as initEditor, u as useEditor } from './useEditor-fIQEaKzZ.cjs';
5
5
  export { fractionalKey, fractionalKey as keyBetween } from '@particle-academy/fancy-doc-commons';
6
6
  export { CmsPage, CmsPageProps, CmsRegion, CmsRegionProps, RenderNode, RenderNodeProps } from './react.cjs';
7
7
  import 'react';
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { B as Binding, P as PageDoc, m as NodeId, N as Node, J as Json, q as StyleProps, L as LayoutMode } from './registry-B4FaQDip.js';
2
- export { A as Action, a as ActionEvent, b as ActionHandler, c as Anim, d as AnimDriver, e as Bound, f as Breakpoint, C as Constraints, D as DEFAULT_BREAKPOINTS, g as DataContext, E as ElementContext, h as ElementRegistry, i as ElementRenderer, K as Keyframe, j as LegacyPageDoc, k as Length, l as LengthUnit, M as MigrateResult, n as PageMeta, o as PerBreakpoint, S as ScrollMode, p as SizeMode, T as ThemeTokens, r as defaultRegistry, s as emptyDoc, t as getPath, u as hasNodeMap, v as isBinding, w as migrateDoc, x as migrateDocVerbose, y as needsMigration, z as resolveValue } from './registry-B4FaQDip.js';
3
- import { P as PageOp } from './useEditor-DZDD9qpS.js';
4
- export { A as Actor, C as Canvas, a as CanvasProps, E as Editor, b as EditorAction, c as EditorApi, d as EditorProps, e as EditorState, I as Inspector, f as InspectorProps, L as LayersPanel, g as LayersPanelProps, O as OpEnvelope, h as PageOpType, i as editorReduce, j as initEditor, u as useEditor } from './useEditor-DZDD9qpS.js';
1
+ import { B as Binding, P as PageDoc, m as NodeId, N as Node, J as Json, q as StyleProps, L as LayoutMode } from './registry-F2TAMjhx.js';
2
+ export { A as Action, a as ActionEvent, b as ActionHandler, c as Anim, d as AnimDriver, e as Bound, f as Breakpoint, C as Constraints, D as DEFAULT_BREAKPOINTS, g as DataContext, E as ElementContext, h as ElementRegistry, i as ElementRenderer, K as Keyframe, j as LegacyPageDoc, k as Length, l as LengthUnit, M as MigrateResult, n as PageMeta, o as PerBreakpoint, S as ScrollMode, p as SizeMode, T as ThemeTokens, r as defaultRegistry, s as emptyDoc, t as getPath, u as hasNodeMap, v as isBinding, w as migrateDoc, x as migrateDocVerbose, y as needsMigration, z as resolveValue, F as withNodeDefaults } from './registry-F2TAMjhx.js';
3
+ import { P as PageOp } from './useEditor-wGEqxpJT.js';
4
+ export { A as Actor, C as Canvas, a as CanvasProps, E as Editor, b as EditorAction, c as EditorApi, d as EditorProps, e as EditorState, I as Inspector, f as InspectorProps, L as LayersPanel, g as LayersPanelProps, O as OpEnvelope, h as PageOpType, i as editorReduce, j as initEditor, u as useEditor } from './useEditor-wGEqxpJT.js';
5
5
  export { fractionalKey, fractionalKey as keyBetween } from '@particle-academy/fancy-doc-commons';
6
6
  export { CmsPage, CmsPageProps, CmsRegion, CmsRegionProps, RenderNode, RenderNodeProps } from './react.js';
7
7
  import 'react';
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
- export { CmsRegion } from './chunk-V6QIOJI7.js';
2
- export { ADD_DEFAULTS, ADD_MENU, CONTAINER_TYPES, Canvas, Editor, Inspector, LayersPanel, buildInsertOp, editorReduce, initEditor, resolveInsertParent, useEditor } from './chunk-IOMIYI45.js';
3
- import { isBinding } from './chunk-SJYKJ6SG.js';
4
- export { CmsPage, DEFAULT_BREAKPOINTS, RenderNode, childrenOf, defaultRegistry, descendantIds, emitDocCss, emptyDoc, getPath, hasNodeMap, invert, isBinding, lastRootId, migrateDoc, migrateDocVerbose, needsMigration, reduce, reduceAll, resolveValue, rootIds } from './chunk-SJYKJ6SG.js';
1
+ export { CmsRegion } from './chunk-TJL26EAX.js';
2
+ export { ADD_DEFAULTS, ADD_MENU, CONTAINER_TYPES, Canvas, Editor, Inspector, LayersPanel, buildInsertOp, editorReduce, initEditor, resolveInsertParent, useEditor } from './chunk-G7ULXTKI.js';
3
+ import { isBinding } from './chunk-IRG5IKKO.js';
4
+ export { CmsPage, DEFAULT_BREAKPOINTS, RenderNode, childrenOf, defaultRegistry, descendantIds, emitDocCss, emptyDoc, getPath, hasNodeMap, invert, isBinding, lastRootId, migrateDoc, migrateDocVerbose, needsMigration, reduce, reduceAll, resolveValue, rootIds, withNodeDefaults } from './chunk-IRG5IKKO.js';
5
5
  export { fractionalKey, fractionalKey as keyBetween } from '@particle-academy/fancy-doc-commons';
6
6
 
7
7
  // src/document/bindings.ts
package/dist/react.cjs CHANGED
@@ -15,6 +15,12 @@ function hasNodeMap(value) {
15
15
  const nodes = value.nodes;
16
16
  return typeof nodes === "object" && nodes !== null && !Array.isArray(nodes);
17
17
  }
18
+ function withNodeDefaults(node) {
19
+ const props = typeof node.props === "object" && node.props !== null ? node.props : {};
20
+ const style = typeof node.style === "object" && node.style !== null ? node.style : { base: {} };
21
+ const base = typeof style.base === "object" && style.base !== null ? style.base : {};
22
+ return props === node.props && style === node.style && base === style.base ? node : { ...node, props, style: { ...style, base } };
23
+ }
18
24
  var DEFAULT_BREAKPOINTS = {
19
25
  base: 0,
20
26
  md: 768,
@@ -89,10 +95,17 @@ function elementFor(node, text) {
89
95
  case "button":
90
96
  case "link": {
91
97
  const href = safeHref(text(node.props.href));
92
- if (href === null) return { tag: node.type === "link" ? "span" : "div" };
93
- const attrs = { href };
94
- if (/^https?:\/\//i.test(href)) attrs.rel = "noopener noreferrer";
95
- return { tag: "a", attrs };
98
+ const attrs = {};
99
+ if (href !== null) {
100
+ attrs.href = href;
101
+ if (/^https?:\/\//i.test(href)) attrs.rel = "noopener noreferrer";
102
+ }
103
+ if (node.type === "button") attrs["data-cms-button"] = BUTTON_VARIANTS.has(text(node.props.variant)) ? text(node.props.variant) : "primary";
104
+ return { tag: href !== null ? "a" : node.type === "link" ? "span" : "div", attrs };
105
+ }
106
+ case "callout": {
107
+ const variant = text(node.props.variant);
108
+ return { tag: "div", attrs: { "data-cms-callout": CALLOUT_VARIANTS.has(variant) ? variant : "info" } };
96
109
  }
97
110
  default:
98
111
  return { tag: CONTAINERS.has(node.type) && LANDMARKS.has(as) ? as : "div" };
@@ -116,51 +129,32 @@ var defaultRegistry = {
116
129
  const items = resolve(node.props.items);
117
130
  return Array.isArray(items) ? items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: item === null || item === void 0 ? "" : String(item) }, i)) : null;
118
131
  },
119
- divider: () => /* @__PURE__ */ jsxRuntime.jsx("hr", { style: { border: "none", borderTop: "1px solid #e2e8f0", margin: 0 } }),
120
- callout: ({ node, text }) => {
121
- const tone = { info: "#3b82f6", success: "#10b981", warning: "#f59e0b", danger: "#ef4444" }[text(node.props.variant)] ?? "#3b82f6";
122
- return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", gap: 10, padding: "12px 14px", borderRadius: 10, background: `${tone}14`, borderLeft: `3px solid ${tone}` }, children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 13 }, children: text(node.props.content) || "Callout" }) });
123
- },
124
- code: ({ node, text }) => /* @__PURE__ */ jsxRuntime.jsx("pre", { style: { margin: 0, padding: "12px 14px", borderRadius: 10, background: "#0b1220", color: "#e2e8f0", fontFamily: "ui-monospace, monospace", fontSize: 13, overflowX: "auto" }, children: /* @__PURE__ */ jsxRuntime.jsx("code", { children: text(node.props.content) }) }),
125
- button: ({ node, text }) => {
126
- const label = text(node.props.label) || text(node.props.content) || "Button";
127
- const variant = text(node.props.variant) || "primary";
128
- return /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cms-button": variant, style: buttonStyle(variant), children: label });
129
- },
132
+ // Looks come from the base stylesheet (render/css.ts BASE_CSS), never from
133
+ // inline style objects, so the PHP renderer emits the same markup.
134
+ divider: () => /* @__PURE__ */ jsxRuntime.jsx("hr", {}),
135
+ callout: ({ node, text }) => text(node.props.content) || "Callout",
136
+ code: ({ node, text }) => /* @__PURE__ */ jsxRuntime.jsx("pre", { children: /* @__PURE__ */ jsxRuntime.jsx("code", { children: text(node.props.content) }) }),
137
+ button: ({ node, text }) => text(node.props.label) || text(node.props.content) || "Button",
130
138
  image: ({ node, text }) => {
131
139
  const fit = text(node.props.fit);
132
140
  return /* @__PURE__ */ jsxRuntime.jsx(
133
141
  "img",
134
142
  {
135
- src: text(node.props.src),
143
+ src: text(node.props.src) || void 0,
136
144
  alt: text(node.props.alt),
137
145
  loading: text(node.props.loading) === "eager" ? "eager" : "lazy",
138
- style: { width: "100%", height: "100%", objectFit: IMAGE_FITS.has(fit) ? fit : "cover", display: "block" }
146
+ "data-cms-fit": IMAGE_FITS.has(fit) && fit !== "cover" ? fit : void 0
139
147
  }
140
148
  );
141
149
  }
142
150
  };
143
151
  var IMAGE_FITS = /* @__PURE__ */ new Set(["cover", "contain", "fill", "none", "scale-down"]);
144
- function buttonStyle(variant) {
145
- const base = {
146
- display: "inline-flex",
147
- alignItems: "center",
148
- gap: 6,
149
- padding: "9px 16px",
150
- borderRadius: 8,
151
- fontWeight: 600,
152
- fontSize: 14,
153
- lineHeight: 1,
154
- cursor: "pointer",
155
- userSelect: "none"
156
- };
157
- if (variant === "ghost") return { ...base, background: "transparent", color: "inherit", border: "1px solid currentColor" };
158
- if (variant === "outline") return { ...base, background: "transparent", color: "#7c3aed", border: "1px solid #7c3aed" };
159
- return { ...base, background: "#7c3aed", color: "#fff", border: "1px solid #7c3aed" };
160
- }
152
+ var BUTTON_VARIANTS = /* @__PURE__ */ new Set(["primary", "outline", "ghost"]);
153
+ var CALLOUT_VARIANTS = /* @__PURE__ */ new Set(["info", "success", "warning", "danger"]);
161
154
  function RenderNode({ doc, id, registry = defaultRegistry, data }) {
162
- const node = own(doc.nodes, id);
163
- if (!node) return null;
155
+ const stored = own(doc.nodes, id);
156
+ if (!stored) return null;
157
+ const node = withNodeDefaults(stored);
164
158
  if (node.type === "repeater") {
165
159
  const arr = resolveValue(node.props.items, data);
166
160
  const items = Array.isArray(arr) ? arr : [];
@@ -246,6 +240,28 @@ function cssString(value) {
246
240
  return out;
247
241
  }
248
242
  var selectorFor = (id) => `[data-cms="${cssString(id)}"]`;
243
+ var BASE_CSS = [
244
+ "/* fancy-cms base */",
245
+ ":where([data-cms]) {\n box-sizing: border-box;\n}",
246
+ ":where(h1, h2, h3, h4, h5, h6, p, ul, ol)[data-cms] {\n margin: 0;\n}",
247
+ ":where(ul, ol)[data-cms] {\n padding-left: 1.25em;\n}",
248
+ ":where(a[data-cms]) {\n color: inherit;\n}",
249
+ ":where([data-cms] > img) {\n display: block;\n height: 100%;\n object-fit: cover;\n width: 100%;\n}",
250
+ ':where([data-cms] > img[data-cms-fit="contain"]) {\n object-fit: contain;\n}',
251
+ ':where([data-cms] > img[data-cms-fit="fill"]) {\n object-fit: fill;\n}',
252
+ ':where([data-cms] > img[data-cms-fit="none"]) {\n object-fit: none;\n}',
253
+ ':where([data-cms] > img[data-cms-fit="scale-down"]) {\n object-fit: scale-down;\n}',
254
+ ":where([data-cms-button]) {\n align-items: center;\n border: 1px solid var(--cms-color-primary, #7c3aed);\n border-radius: 8px;\n cursor: pointer;\n display: inline-flex;\n font-weight: 600;\n gap: 6px;\n justify-content: center;\n line-height: 1.2;\n padding: 10px 18px;\n text-decoration: none;\n}",
255
+ ':where([data-cms-button="primary"]) {\n background: var(--cms-color-primary, #7c3aed);\n color: #ffffff;\n}',
256
+ ':where([data-cms-button="outline"]) {\n background: transparent;\n color: var(--cms-color-primary, #7c3aed);\n}',
257
+ ':where([data-cms-button="ghost"]) {\n background: transparent;\n border-color: currentColor;\n color: inherit;\n}',
258
+ ":where([data-cms-callout]) {\n background: #3b82f614;\n border-left: 3px solid #3b82f6;\n border-radius: 10px;\n padding: 12px 14px;\n}",
259
+ ':where([data-cms-callout="success"]) {\n background: #10b98114;\n border-left-color: #10b981;\n}',
260
+ ':where([data-cms-callout="warning"]) {\n background: #f59e0b14;\n border-left-color: #f59e0b;\n}',
261
+ ':where([data-cms-callout="danger"]) {\n background: #ef444414;\n border-left-color: #ef4444;\n}',
262
+ ":where([data-cms] > hr) {\n border: none;\n border-top: 1px solid #e2e8f0;\n margin: 0;\n}",
263
+ ":where([data-cms] > pre) {\n background: #0b1220;\n border-radius: 10px;\n color: #e2e8f0;\n font-family: ui-monospace, monospace;\n font-size: 13px;\n margin: 0;\n overflow-x: auto;\n padding: 12px 14px;\n}"
264
+ ].join("\n\n");
249
265
  var UNITS = /* @__PURE__ */ new Set(["px", "%", "vw", "vh", "rem", "fr"]);
250
266
  function lengthToCss(len) {
251
267
  if (typeof len !== "object" || len === null) return null;
@@ -458,7 +474,7 @@ function emitDocCss(doc) {
458
474
  const themeRule = serializeRule(":root", themeDecls(doc.theme), "");
459
475
  if (themeRule) blocks.push(themeRule);
460
476
  for (const id of Object.keys(doc.nodes).sort()) {
461
- const node = doc.nodes[id];
477
+ const node = withNodeDefaults(doc.nodes[id]);
462
478
  const selector = selectorFor(id);
463
479
  const parentFree = isParentFree(doc, node);
464
480
  const base = {
@@ -471,12 +487,13 @@ function emitDocCss(doc) {
471
487
  if (baseRule) blocks.push(baseRule);
472
488
  for (const bp of doc.breakpoints) {
473
489
  if (bp === "base") continue;
474
- const px = breakpointPx[bp];
475
- if (px === void 0) continue;
476
- const bpStyle = node.style[bp];
490
+ const px = own(breakpointPx, bp);
491
+ if (typeof px !== "number") continue;
492
+ const bpStyle = own(node.style, bp);
493
+ const bpConstraints = node.constraints ? own(node.constraints, bp) : void 0;
477
494
  const decls = {
478
495
  ...bpStyle ? containerDecls(node, bpStyle, false) : {},
479
- ...node.constraints?.[bp] ? constraintDecls(node.constraints[bp], parentFree) : {},
496
+ ...bpConstraints ? constraintDecls(bpConstraints, parentFree) : {},
480
497
  ...bpStyle ? styleDecls(bpStyle) : {},
481
498
  ...bpStyle ? visibilityDecls(node, bpStyle, false) : {}
482
499
  };
@@ -486,7 +503,8 @@ ${inner}
486
503
  }`);
487
504
  }
488
505
  }
489
- return blocks.join("\n\n") + (blocks.length ? "\n" : "");
506
+ if (blocks.length === 0 && Object.keys(doc.nodes).length === 0) return "";
507
+ return [BASE_CSS, ...blocks].join("\n\n") + "\n";
490
508
  }
491
509
  function CmsPage({
492
510
  doc: input,