@particle-academy/fancy-cms-ui 0.0.1-dev.5 → 0.0.1-dev.7
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/{chunk-5PWZGIYZ.js → chunk-5O6U4VIU.js} +25 -2
- package/dist/chunk-5O6U4VIU.js.map +1 -0
- package/dist/editor.cjs +384 -71
- package/dist/editor.cjs.map +1 -1
- package/dist/editor.d.cts +42 -3
- package/dist/editor.d.ts +42 -3
- package/dist/editor.js +358 -69
- package/dist/editor.js.map +1 -1
- package/dist/react.cjs +23 -0
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +2 -2
- package/package.json +4 -4
- package/dist/chunk-5PWZGIYZ.js.map +0 -1
package/dist/editor.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { keyBetween } from './chunk-7YYLYBLI.js';
|
|
2
|
-
import { CmsPage, defaultRegistry } from './chunk-
|
|
2
|
+
import { CmsPage, defaultRegistry } from './chunk-5O6U4VIU.js';
|
|
3
3
|
import { reduce, childrenOf } from './chunk-HYHNMW47.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';
|
|
@@ -364,7 +364,202 @@ function Toolbar({ ed }) {
|
|
|
364
364
|
}
|
|
365
365
|
);
|
|
366
366
|
}
|
|
367
|
+
var CONTAINER_TYPES = /* @__PURE__ */ new Set(["section", "frame", "stack", "grid", "shape"]);
|
|
368
|
+
function NodeInspector({
|
|
369
|
+
node,
|
|
370
|
+
transform,
|
|
371
|
+
measured,
|
|
372
|
+
onProps,
|
|
373
|
+
onStyle,
|
|
374
|
+
onTransform,
|
|
375
|
+
onRemove,
|
|
376
|
+
onClose
|
|
377
|
+
}) {
|
|
378
|
+
const base = node.style.base ?? {};
|
|
379
|
+
const setT = (patch) => onTransform({ ...transform, ...patch });
|
|
380
|
+
const handled = /* @__PURE__ */ new Set(["content", "label"]);
|
|
381
|
+
const extraKeys = Object.keys(node.props).filter(
|
|
382
|
+
(k) => !handled.has(k) && ["string", "number", "boolean"].includes(typeof node.props[k])
|
|
383
|
+
);
|
|
384
|
+
return /* @__PURE__ */ jsxs("div", { style: panel, onPointerDown: (e) => e.stopPropagation(), children: [
|
|
385
|
+
/* @__PURE__ */ jsxs("div", { style: headRow, children: [
|
|
386
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 2, minWidth: 0 }, children: [
|
|
387
|
+
/* @__PURE__ */ jsx("strong", { style: { fontSize: 12, textTransform: "capitalize" }, children: node.type }),
|
|
388
|
+
/* @__PURE__ */ jsx("span", { style: { fontSize: 10, opacity: 0.5, fontFamily: "ui-monospace, monospace", overflow: "hidden", textOverflow: "ellipsis" }, children: node.id })
|
|
389
|
+
] }),
|
|
390
|
+
/* @__PURE__ */ jsx("span", { style: { flex: 1 } }),
|
|
391
|
+
/* @__PURE__ */ jsx("button", { type: "button", style: { ...iconBtn, color: "#fca5a5" }, title: "Delete element", onClick: onRemove, children: "\u{1F5D1}" }),
|
|
392
|
+
/* @__PURE__ */ jsx("button", { type: "button", style: iconBtn, title: "Close", onClick: onClose, children: "\u2715" })
|
|
393
|
+
] }),
|
|
394
|
+
/* @__PURE__ */ jsxs("div", { style: body, children: [
|
|
395
|
+
"content" in node.props ? /* @__PURE__ */ jsx(Group, { label: "Content", children: /* @__PURE__ */ jsx(
|
|
396
|
+
"textarea",
|
|
397
|
+
{
|
|
398
|
+
style: { ...input2, minHeight: 64, resize: "vertical", lineHeight: 1.4 },
|
|
399
|
+
value: String(node.props.content ?? ""),
|
|
400
|
+
onChange: (e) => onProps({ content: e.target.value })
|
|
401
|
+
}
|
|
402
|
+
) }) : null,
|
|
403
|
+
"label" in node.props ? /* @__PURE__ */ jsx(Group, { label: "Label", children: /* @__PURE__ */ jsx("input", { style: input2, value: String(node.props.label ?? ""), onChange: (e) => onProps({ label: e.target.value }) }) }) : null,
|
|
404
|
+
extraKeys.length ? /* @__PURE__ */ jsx(Group, { label: "Properties", children: extraKeys.map((k) => /* @__PURE__ */ jsx(PropField, { name: k, value: node.props[k], onChange: (v) => onProps({ [k]: v }) }, k)) }) : null,
|
|
405
|
+
/* @__PURE__ */ jsxs(Group, { label: "Position & size", children: [
|
|
406
|
+
/* @__PURE__ */ jsxs(Row, { children: [
|
|
407
|
+
/* @__PURE__ */ jsx(Num, { label: "X", value: transform.x, placeholder: "0", onChange: (v) => setT({ x: v }) }),
|
|
408
|
+
/* @__PURE__ */ jsx(Num, { label: "Y", value: transform.y, placeholder: "0", onChange: (v) => setT({ y: v }) })
|
|
409
|
+
] }),
|
|
410
|
+
/* @__PURE__ */ jsxs(Row, { children: [
|
|
411
|
+
/* @__PURE__ */ jsx(Num, { label: "W", value: transform.w, placeholder: `${Math.round(measured.w)}`, onChange: (v) => setT({ w: v }) }),
|
|
412
|
+
/* @__PURE__ */ jsx(Num, { label: "H", value: transform.h, placeholder: `${Math.round(measured.h)}`, onChange: (v) => setT({ h: v }) })
|
|
413
|
+
] }),
|
|
414
|
+
/* @__PURE__ */ jsxs(Row, { children: [
|
|
415
|
+
/* @__PURE__ */ jsx(Num, { label: "Scale", value: transform.scale, placeholder: "1", step: 0.05, onChange: (v) => setT({ scale: v }) }),
|
|
416
|
+
/* @__PURE__ */ jsx(Num, { label: "Rotate", value: transform.rotate, placeholder: "0", onChange: (v) => setT({ rotate: v }) })
|
|
417
|
+
] }),
|
|
418
|
+
/* @__PURE__ */ jsxs(Row, { children: [
|
|
419
|
+
/* @__PURE__ */ jsx(Num, { label: "Opacity", value: transform.opacity, placeholder: "1", min: 0, max: 1, step: 0.05, onChange: (v) => setT({ opacity: v }) }),
|
|
420
|
+
/* @__PURE__ */ jsx("button", { type: "button", style: { ...miniBtn, alignSelf: "end" }, onClick: () => onTransform({}), title: "Clear transform", children: "Reset" })
|
|
421
|
+
] })
|
|
422
|
+
] }),
|
|
423
|
+
!CONTAINER_TYPES.has(node.type) ? /* @__PURE__ */ jsxs(Group, { label: "Text", children: [
|
|
424
|
+
/* @__PURE__ */ jsxs(Row, { children: [
|
|
425
|
+
/* @__PURE__ */ jsx(Color, { label: "Color", value: base.color ?? "#0f172a", onChange: (v) => onStyle({ color: v }) }),
|
|
426
|
+
/* @__PURE__ */ jsx(Num, { label: "Size", value: base.fontSize?.value, placeholder: "16", onChange: (v) => onStyle({ fontSize: v == null ? void 0 : len(v) }) })
|
|
427
|
+
] }),
|
|
428
|
+
/* @__PURE__ */ jsxs(Row, { children: [
|
|
429
|
+
/* @__PURE__ */ jsx(
|
|
430
|
+
Sel,
|
|
431
|
+
{
|
|
432
|
+
label: "Weight",
|
|
433
|
+
value: String(base.fontWeight ?? ""),
|
|
434
|
+
options: [["", "\u2014"], ["400", "Regular"], ["500", "Medium"], ["600", "Semibold"], ["700", "Bold"], ["800", "Heavy"]],
|
|
435
|
+
onChange: (v) => onStyle({ fontWeight: v ? Number(v) : void 0 })
|
|
436
|
+
}
|
|
437
|
+
),
|
|
438
|
+
/* @__PURE__ */ jsx(
|
|
439
|
+
Sel,
|
|
440
|
+
{
|
|
441
|
+
label: "Align",
|
|
442
|
+
value: base.textAlign ?? "",
|
|
443
|
+
options: [["", "\u2014"], ["left", "Left"], ["center", "Center"], ["right", "Right"], ["justify", "Justify"]],
|
|
444
|
+
onChange: (v) => onStyle({ textAlign: v || void 0 })
|
|
445
|
+
}
|
|
446
|
+
)
|
|
447
|
+
] })
|
|
448
|
+
] }) : null,
|
|
449
|
+
/* @__PURE__ */ jsxs(Group, { label: "Box", children: [
|
|
450
|
+
/* @__PURE__ */ jsxs(Row, { children: [
|
|
451
|
+
/* @__PURE__ */ jsx(Color, { label: "Background", value: hex(base.background), onChange: (v) => onStyle({ background: v }) }),
|
|
452
|
+
/* @__PURE__ */ jsx(Num, { label: "Radius", value: base.radius?.value, placeholder: "0", onChange: (v) => onStyle({ radius: v == null ? void 0 : len(v) }) })
|
|
453
|
+
] }),
|
|
454
|
+
/* @__PURE__ */ jsxs(Row, { children: [
|
|
455
|
+
/* @__PURE__ */ jsx(Num, { label: "Padding", value: base.padding?.value, placeholder: "0", onChange: (v) => onStyle({ padding: v == null ? void 0 : len(v) }) }),
|
|
456
|
+
/* @__PURE__ */ jsx(Num, { label: "Gap", value: base.gap?.value, placeholder: "0", onChange: (v) => onStyle({ gap: v == null ? void 0 : len(v) }) })
|
|
457
|
+
] })
|
|
458
|
+
] })
|
|
459
|
+
] })
|
|
460
|
+
] });
|
|
461
|
+
}
|
|
462
|
+
function Group({ label: label2, children }) {
|
|
463
|
+
return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 8, paddingBottom: 12, marginBottom: 12, borderBottom: "1px solid #1e293b" }, children: [
|
|
464
|
+
/* @__PURE__ */ jsx("span", { style: { fontSize: 10, letterSpacing: "0.06em", textTransform: "uppercase", opacity: 0.5 }, children: label2 }),
|
|
465
|
+
children
|
|
466
|
+
] });
|
|
467
|
+
}
|
|
468
|
+
function Row({ children }) {
|
|
469
|
+
return /* @__PURE__ */ jsx("div", { style: { display: "flex", gap: 8 }, children });
|
|
470
|
+
}
|
|
471
|
+
function PropField({ name, value, onChange }) {
|
|
472
|
+
if (typeof value === "boolean") {
|
|
473
|
+
return /* @__PURE__ */ jsxs("label", { style: { display: "flex", alignItems: "center", gap: 8, fontSize: 12 }, children: [
|
|
474
|
+
/* @__PURE__ */ jsx("input", { type: "checkbox", checked: value, onChange: (e) => onChange(e.target.checked) }),
|
|
475
|
+
/* @__PURE__ */ jsx("span", { style: { textTransform: "capitalize" }, children: name })
|
|
476
|
+
] });
|
|
477
|
+
}
|
|
478
|
+
if (name === "variant") {
|
|
479
|
+
return /* @__PURE__ */ jsx(Sel, { label: name, value: String(value), options: [["primary", "Primary"], ["ghost", "Ghost"], ["outline", "Outline"]], onChange });
|
|
480
|
+
}
|
|
481
|
+
const isNum = typeof value === "number";
|
|
482
|
+
return /* @__PURE__ */ jsxs("label", { style: field, children: [
|
|
483
|
+
/* @__PURE__ */ jsx("span", { style: fieldLabel, children: name }),
|
|
484
|
+
/* @__PURE__ */ jsx(
|
|
485
|
+
"input",
|
|
486
|
+
{
|
|
487
|
+
style: input2,
|
|
488
|
+
type: isNum ? "number" : "text",
|
|
489
|
+
value: String(value),
|
|
490
|
+
onChange: (e) => onChange(isNum ? Number(e.target.value) : e.target.value)
|
|
491
|
+
}
|
|
492
|
+
)
|
|
493
|
+
] });
|
|
494
|
+
}
|
|
495
|
+
function Num({ label: label2, value, placeholder, onChange, step, min, max }) {
|
|
496
|
+
return /* @__PURE__ */ jsxs("label", { style: field, children: [
|
|
497
|
+
/* @__PURE__ */ jsx("span", { style: fieldLabel, children: label2 }),
|
|
498
|
+
/* @__PURE__ */ jsx(
|
|
499
|
+
"input",
|
|
500
|
+
{
|
|
501
|
+
style: input2,
|
|
502
|
+
type: "number",
|
|
503
|
+
step,
|
|
504
|
+
min,
|
|
505
|
+
max,
|
|
506
|
+
value: value ?? "",
|
|
507
|
+
placeholder,
|
|
508
|
+
onChange: (e) => onChange(e.target.value === "" ? void 0 : Number(e.target.value))
|
|
509
|
+
}
|
|
510
|
+
)
|
|
511
|
+
] });
|
|
512
|
+
}
|
|
513
|
+
function Color({ label: label2, value, onChange }) {
|
|
514
|
+
return /* @__PURE__ */ jsxs("label", { style: field, children: [
|
|
515
|
+
/* @__PURE__ */ jsx("span", { style: fieldLabel, children: label2 }),
|
|
516
|
+
/* @__PURE__ */ jsx("input", { style: { ...input2, padding: 2, height: 30 }, type: "color", value, onChange: (e) => onChange(e.target.value) })
|
|
517
|
+
] });
|
|
518
|
+
}
|
|
519
|
+
function Sel({ label: label2, value, options, onChange }) {
|
|
520
|
+
return /* @__PURE__ */ jsxs("label", { style: field, children: [
|
|
521
|
+
/* @__PURE__ */ jsx("span", { style: fieldLabel, children: label2 }),
|
|
522
|
+
/* @__PURE__ */ jsx("select", { style: input2, value, onChange: (e) => onChange(e.target.value), children: options.map(([v, l]) => /* @__PURE__ */ jsx("option", { value: v, children: l }, v)) })
|
|
523
|
+
] });
|
|
524
|
+
}
|
|
525
|
+
var len = (value) => ({ value, unit: "px" });
|
|
526
|
+
var hex = (v) => v && /^#[0-9a-fA-F]{6}$/.test(v) ? v : "#ffffff";
|
|
367
527
|
var Z = 2147483e3;
|
|
528
|
+
var panel = {
|
|
529
|
+
position: "fixed",
|
|
530
|
+
top: 60,
|
|
531
|
+
right: 12,
|
|
532
|
+
bottom: 96,
|
|
533
|
+
width: 264,
|
|
534
|
+
display: "flex",
|
|
535
|
+
flexDirection: "column",
|
|
536
|
+
background: "#0b1220",
|
|
537
|
+
color: "#e2e8f0",
|
|
538
|
+
border: "1px solid #1e293b",
|
|
539
|
+
borderRadius: 12,
|
|
540
|
+
boxShadow: "0 18px 48px -16px rgba(0,0,0,0.6)",
|
|
541
|
+
zIndex: Z + 2,
|
|
542
|
+
fontFamily: "system-ui, sans-serif",
|
|
543
|
+
overflow: "hidden"
|
|
544
|
+
};
|
|
545
|
+
var headRow = { display: "flex", alignItems: "center", gap: 8, padding: "10px 12px", borderBottom: "1px solid #1e293b" };
|
|
546
|
+
var body = { padding: 12, overflowY: "auto" };
|
|
547
|
+
var field = { display: "flex", flexDirection: "column", gap: 4, flex: 1, minWidth: 0 };
|
|
548
|
+
var fieldLabel = { fontSize: 10, opacity: 0.6 };
|
|
549
|
+
var input2 = {
|
|
550
|
+
width: "100%",
|
|
551
|
+
boxSizing: "border-box",
|
|
552
|
+
background: "#0f172a",
|
|
553
|
+
color: "#e2e8f0",
|
|
554
|
+
border: "1px solid #334155",
|
|
555
|
+
borderRadius: 6,
|
|
556
|
+
padding: "5px 7px",
|
|
557
|
+
font: "inherit",
|
|
558
|
+
fontSize: 12
|
|
559
|
+
};
|
|
560
|
+
var iconBtn = { background: "transparent", border: "none", color: "#e2e8f0", cursor: "pointer", fontSize: 13, padding: 4, borderRadius: 6 };
|
|
561
|
+
var miniBtn = { font: "inherit", fontSize: 11, color: "#e2e8f0", background: "#334155", border: "1px solid #475569", borderRadius: 6, padding: "5px 10px", cursor: "pointer" };
|
|
562
|
+
var Z2 = 2147483e3;
|
|
368
563
|
function EditablePage({
|
|
369
564
|
doc,
|
|
370
565
|
registry = defaultRegistry,
|
|
@@ -373,7 +568,8 @@ function EditablePage({
|
|
|
373
568
|
onNodeTransform,
|
|
374
569
|
onSelect,
|
|
375
570
|
frames = 1,
|
|
376
|
-
onProgress
|
|
571
|
+
onProgress,
|
|
572
|
+
pinned = true
|
|
377
573
|
}) {
|
|
378
574
|
const ed = useEditor(doc);
|
|
379
575
|
const [editing, setEditing] = useState(false);
|
|
@@ -402,35 +598,23 @@ function EditablePage({
|
|
|
402
598
|
root.querySelectorAll("[data-cms]").forEach((el) => {
|
|
403
599
|
const id = el.dataset.cms;
|
|
404
600
|
const t = id ? transforms?.[id] : void 0;
|
|
405
|
-
|
|
406
|
-
el.style.transform = `translate3d(${t.x ?? 0}px, ${t.y ?? 0}px, 0) scale(${t.scale ?? 1})`;
|
|
407
|
-
el.style.opacity = t.opacity != null ? String(t.opacity) : "";
|
|
408
|
-
} else {
|
|
409
|
-
el.style.transform = "";
|
|
410
|
-
el.style.opacity = "";
|
|
411
|
-
}
|
|
601
|
+
applyTransform(el, t);
|
|
412
602
|
});
|
|
413
603
|
}, [transforms, ed.state.doc]);
|
|
414
604
|
useEffect(() => {
|
|
415
605
|
const spacer = spacerRef.current;
|
|
416
606
|
if (!spacer || !onProgress) return;
|
|
417
|
-
let raf = 0;
|
|
418
607
|
const compute = () => {
|
|
419
|
-
|
|
420
|
-
const len = spacer.offsetHeight - window.innerHeight;
|
|
608
|
+
const len2 = spacer.offsetHeight - window.innerHeight;
|
|
421
609
|
const top = spacer.getBoundingClientRect().top;
|
|
422
|
-
onProgress(
|
|
423
|
-
};
|
|
424
|
-
const onScroll = () => {
|
|
425
|
-
if (!raf) raf = requestAnimationFrame(compute);
|
|
610
|
+
onProgress(len2 > 0 ? Math.min(1, Math.max(0, -top / len2)) : 0);
|
|
426
611
|
};
|
|
427
612
|
compute();
|
|
428
|
-
window.addEventListener("scroll",
|
|
429
|
-
window.addEventListener("resize",
|
|
613
|
+
window.addEventListener("scroll", compute, { passive: true });
|
|
614
|
+
window.addEventListener("resize", compute);
|
|
430
615
|
return () => {
|
|
431
|
-
window.removeEventListener("scroll",
|
|
432
|
-
window.removeEventListener("resize",
|
|
433
|
-
if (raf) cancelAnimationFrame(raf);
|
|
616
|
+
window.removeEventListener("scroll", compute);
|
|
617
|
+
window.removeEventListener("resize", compute);
|
|
434
618
|
};
|
|
435
619
|
}, [onProgress, frames]);
|
|
436
620
|
const measureBox = useCallback(() => {
|
|
@@ -448,7 +632,7 @@ function EditablePage({
|
|
|
448
632
|
window.removeEventListener("scroll", measureBox);
|
|
449
633
|
window.removeEventListener("resize", measureBox);
|
|
450
634
|
};
|
|
451
|
-
}, [measureBox, ed.state.doc
|
|
635
|
+
}, [measureBox, ed.state.doc]);
|
|
452
636
|
useEffect(() => {
|
|
453
637
|
if (!editing || !selection || !pageRef.current || selNode?.type !== "text") return;
|
|
454
638
|
const el = pageRef.current.querySelector(`[data-cms="${cssEscape2(selection)}"]`);
|
|
@@ -473,17 +657,29 @@ function EditablePage({
|
|
|
473
657
|
ed.select(el.getAttribute("data-cms"));
|
|
474
658
|
}
|
|
475
659
|
};
|
|
476
|
-
const
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
660
|
+
const addNode = useCallback(
|
|
661
|
+
(kind) => {
|
|
662
|
+
const doc2 = ed.state.doc;
|
|
663
|
+
const parent = selNode ? CONTAINER_TYPES2.has(selNode.type) ? selNode.id : selNode.parent : doc2.sections[doc2.sections.length - 1] ?? null;
|
|
664
|
+
const siblings = childrenOf(doc2, parent);
|
|
665
|
+
const order = keyBetween(siblings.length ? siblings[siblings.length - 1].order : null, null);
|
|
666
|
+
const id = `n${doc2.seq + 1}-${Math.floor(performance.now())}`;
|
|
667
|
+
const def = ADD_DEFAULTS[kind];
|
|
668
|
+
ed.apply({ t: "insert_node", node: { id, type: def.type, parent, order, props: { ...def.props }, style: { base: { ...def.style } } } });
|
|
669
|
+
ed.select(id);
|
|
670
|
+
},
|
|
671
|
+
[ed, selNode]
|
|
672
|
+
);
|
|
484
673
|
const setStyle = (patch) => selection && ed.apply({ t: "set_style", id: selection, breakpoint: "base", patch });
|
|
674
|
+
const setProps = (patch) => selection && ed.apply({ t: "set_props", id: selection, patch });
|
|
675
|
+
const removeSelected = () => {
|
|
676
|
+
if (!selection) return;
|
|
677
|
+
ed.apply({ t: "remove_node", id: selection });
|
|
678
|
+
ed.select(null);
|
|
679
|
+
};
|
|
680
|
+
const page = /* @__PURE__ */ jsx("div", { ref: pageRef, onClickCapture, children: /* @__PURE__ */ jsx(CmsPage, { doc: ed.state.doc, registry }) });
|
|
485
681
|
return /* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
|
|
486
|
-
/* @__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:
|
|
682
|
+
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 }) }) : page,
|
|
487
683
|
editing && box && selection ? /* @__PURE__ */ jsx(
|
|
488
684
|
SelectionOverlay,
|
|
489
685
|
{
|
|
@@ -495,7 +691,20 @@ function EditablePage({
|
|
|
495
691
|
onLive: measureBox
|
|
496
692
|
}
|
|
497
693
|
) : null,
|
|
498
|
-
editing && box && selNode ? /* @__PURE__ */ jsx(FloatingToolbar, { box, isText: selNode.type === "text", base: selNode.style.base, setStyle }) : null,
|
|
694
|
+
editing && box && selNode ? /* @__PURE__ */ jsx(FloatingToolbar, { box, isText: selNode.type === "text" || selNode.type === "heading", base: selNode.style.base, setStyle }) : null,
|
|
695
|
+
editing && selNode && box ? /* @__PURE__ */ jsx(
|
|
696
|
+
NodeInspector,
|
|
697
|
+
{
|
|
698
|
+
node: selNode,
|
|
699
|
+
transform: (selection ? transforms?.[selection] : void 0) ?? {},
|
|
700
|
+
measured: { w: box.w, h: box.h },
|
|
701
|
+
onProps: setProps,
|
|
702
|
+
onStyle: setStyle,
|
|
703
|
+
onTransform: (t) => selection && onNodeTransform?.(selection, t),
|
|
704
|
+
onRemove: removeSelected,
|
|
705
|
+
onClose: () => ed.select(null)
|
|
706
|
+
}
|
|
707
|
+
) : null,
|
|
499
708
|
revealed || editing ? /* @__PURE__ */ jsx(
|
|
500
709
|
EditBar,
|
|
501
710
|
{
|
|
@@ -508,12 +717,30 @@ function EditablePage({
|
|
|
508
717
|
canRedo: ed.canRedo,
|
|
509
718
|
onUndo: ed.undo,
|
|
510
719
|
onRedo: ed.redo,
|
|
511
|
-
|
|
720
|
+
onAdd: addNode
|
|
512
721
|
}
|
|
513
722
|
) : null,
|
|
514
|
-
editing && timelineDock ? /* @__PURE__ */ jsx("div", { style: { position: "fixed", left: 0, right: 0, bottom: 0, zIndex:
|
|
723
|
+
editing && timelineDock ? /* @__PURE__ */ jsx("div", { style: { position: "fixed", left: 0, right: 0, bottom: 0, zIndex: Z2 }, children: timelineDock }) : null
|
|
515
724
|
] });
|
|
516
725
|
}
|
|
726
|
+
var CONTAINER_TYPES2 = /* @__PURE__ */ new Set(["section", "frame", "stack", "grid", "shape"]);
|
|
727
|
+
var ADD_DEFAULTS = {
|
|
728
|
+
text: { type: "text", props: { content: "New text" }, style: { color: "inherit" } },
|
|
729
|
+
heading: { type: "heading", props: { content: "New heading" }, style: { fontSize: { value: 28, unit: "px" }, fontWeight: 700 } },
|
|
730
|
+
button: { type: "button", props: { label: "Button", href: "#", variant: "primary" }, style: {} },
|
|
731
|
+
image: { type: "image", props: { src: "", alt: "" }, style: {} },
|
|
732
|
+
box: { type: "frame", props: {}, style: { padding: { value: 16, unit: "px" } } }
|
|
733
|
+
};
|
|
734
|
+
var GRIPS = [
|
|
735
|
+
{ key: "nw", north: true, west: true, cursor: "nwse-resize" },
|
|
736
|
+
{ key: "n", north: true, cursor: "ns-resize" },
|
|
737
|
+
{ key: "ne", north: true, east: true, cursor: "nesw-resize" },
|
|
738
|
+
{ key: "e", east: true, cursor: "ew-resize" },
|
|
739
|
+
{ key: "se", south: true, east: true, cursor: "nwse-resize" },
|
|
740
|
+
{ key: "s", south: true, cursor: "ns-resize" },
|
|
741
|
+
{ key: "sw", south: true, west: true, cursor: "nesw-resize" },
|
|
742
|
+
{ key: "w", west: true, cursor: "ew-resize" }
|
|
743
|
+
];
|
|
517
744
|
function SelectionOverlay({
|
|
518
745
|
box,
|
|
519
746
|
base,
|
|
@@ -525,29 +752,48 @@ function SelectionOverlay({
|
|
|
525
752
|
const drag = useRef(null);
|
|
526
753
|
const apply = (t) => {
|
|
527
754
|
const el = getEl();
|
|
528
|
-
if (el)
|
|
529
|
-
el.style.transform = `translate3d(${t.x ?? 0}px, ${t.y ?? 0}px, 0) scale(${t.scale ?? 1})`;
|
|
530
|
-
el.style.opacity = t.opacity != null ? String(t.opacity) : "";
|
|
531
|
-
}
|
|
755
|
+
if (el) applyTransform(el, t);
|
|
532
756
|
};
|
|
533
|
-
const
|
|
757
|
+
const startMove = (e) => {
|
|
534
758
|
e.stopPropagation();
|
|
535
759
|
e.preventDefault();
|
|
536
760
|
e.currentTarget.setPointerCapture(e.pointerId);
|
|
537
|
-
drag.current = {
|
|
761
|
+
drag.current = { x: e.clientX, y: e.clientY, w: box.w, h: box.h, live: { ...base } };
|
|
538
762
|
};
|
|
539
|
-
const
|
|
763
|
+
const moveMove = (e) => {
|
|
540
764
|
const d = drag.current;
|
|
541
765
|
if (!d) return;
|
|
542
|
-
|
|
543
|
-
d.live = { ...base, x: (base.x ?? 0) + (e.clientX - d.x), y: (base.y ?? 0) + (e.clientY - d.y) };
|
|
544
|
-
} else {
|
|
545
|
-
const factor = Math.max(0.1, (d.w + (e.clientX - d.x)) / d.w);
|
|
546
|
-
d.live = { ...base, scale: Number(((base.scale ?? 1) * factor).toFixed(3)) };
|
|
547
|
-
}
|
|
766
|
+
d.live = { ...base, x: (base.x ?? 0) + (e.clientX - d.x), y: (base.y ?? 0) + (e.clientY - d.y) };
|
|
548
767
|
apply(d.live);
|
|
549
768
|
onLive();
|
|
550
769
|
};
|
|
770
|
+
const startResize = (g) => (e) => {
|
|
771
|
+
e.stopPropagation();
|
|
772
|
+
e.preventDefault();
|
|
773
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
774
|
+
drag.current = { x: e.clientX, y: e.clientY, w: base.w ?? box.w, h: base.h ?? box.h, live: { ...base } };
|
|
775
|
+
e.currentTarget.dataset.grip = g.key;
|
|
776
|
+
};
|
|
777
|
+
const resizeMove = (g) => (e) => {
|
|
778
|
+
const d = drag.current;
|
|
779
|
+
if (!d) return;
|
|
780
|
+
const dx = e.clientX - d.x;
|
|
781
|
+
const dy = e.clientY - d.y;
|
|
782
|
+
const live = { ...base };
|
|
783
|
+
if (g.east) live.w = Math.max(16, Math.round(d.w + dx));
|
|
784
|
+
if (g.west) {
|
|
785
|
+
live.w = Math.max(16, Math.round(d.w - dx));
|
|
786
|
+
live.x = (base.x ?? 0) + (d.w - live.w);
|
|
787
|
+
}
|
|
788
|
+
if (g.south) live.h = Math.max(16, Math.round(d.h + dy));
|
|
789
|
+
if (g.north) {
|
|
790
|
+
live.h = Math.max(16, Math.round(d.h - dy));
|
|
791
|
+
live.y = (base.y ?? 0) + (d.h - live.h);
|
|
792
|
+
}
|
|
793
|
+
d.live = live;
|
|
794
|
+
apply(live);
|
|
795
|
+
onLive();
|
|
796
|
+
};
|
|
551
797
|
const end = () => {
|
|
552
798
|
const d = drag.current;
|
|
553
799
|
if (d) onTransform(d.live);
|
|
@@ -562,17 +808,23 @@ function SelectionOverlay({
|
|
|
562
808
|
outline: "2px solid #8b5cf6",
|
|
563
809
|
borderRadius: 4,
|
|
564
810
|
pointerEvents: "none",
|
|
565
|
-
zIndex:
|
|
811
|
+
zIndex: Z2
|
|
566
812
|
};
|
|
567
813
|
const handle = {
|
|
568
814
|
position: "fixed",
|
|
569
|
-
width:
|
|
570
|
-
height:
|
|
571
|
-
background: "#
|
|
572
|
-
border: "2px solid #
|
|
573
|
-
borderRadius:
|
|
574
|
-
zIndex:
|
|
575
|
-
touchAction: "none"
|
|
815
|
+
width: 12,
|
|
816
|
+
height: 12,
|
|
817
|
+
background: "#fff",
|
|
818
|
+
border: "2px solid #8b5cf6",
|
|
819
|
+
borderRadius: 3,
|
|
820
|
+
zIndex: Z2 + 1,
|
|
821
|
+
touchAction: "none",
|
|
822
|
+
boxSizing: "border-box"
|
|
823
|
+
};
|
|
824
|
+
const gripPos = (g) => {
|
|
825
|
+
const cx = g.west ? box.x : g.east ? box.x + box.w : box.x + box.w / 2;
|
|
826
|
+
const cy = g.north ? box.y : g.south ? box.y + box.h : box.y + box.h / 2;
|
|
827
|
+
return { left: cx - 6, top: cy - 6, cursor: g.cursor };
|
|
576
828
|
};
|
|
577
829
|
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
578
830
|
/* @__PURE__ */ jsx("div", { style: outline }),
|
|
@@ -581,22 +833,23 @@ function SelectionOverlay({
|
|
|
581
833
|
"div",
|
|
582
834
|
{
|
|
583
835
|
title: "Drag to move",
|
|
584
|
-
onPointerDown:
|
|
585
|
-
onPointerMove:
|
|
836
|
+
onPointerDown: startMove,
|
|
837
|
+
onPointerMove: moveMove,
|
|
586
838
|
onPointerUp: end,
|
|
587
|
-
style: { ...handle, left: box.x -
|
|
839
|
+
style: { ...handle, width: 18, height: 18, borderRadius: 9, background: "#8b5cf6", border: "2px solid #fff", left: box.x - 22, top: box.y - 22, cursor: "move" }
|
|
588
840
|
}
|
|
589
841
|
),
|
|
590
|
-
/* @__PURE__ */ jsx(
|
|
842
|
+
GRIPS.map((g) => /* @__PURE__ */ jsx(
|
|
591
843
|
"div",
|
|
592
844
|
{
|
|
593
845
|
title: "Drag to resize",
|
|
594
|
-
onPointerDown:
|
|
595
|
-
onPointerMove:
|
|
846
|
+
onPointerDown: startResize(g),
|
|
847
|
+
onPointerMove: resizeMove(g),
|
|
596
848
|
onPointerUp: end,
|
|
597
|
-
style: { ...handle,
|
|
598
|
-
}
|
|
599
|
-
|
|
849
|
+
style: { ...handle, ...gripPos(g) }
|
|
850
|
+
},
|
|
851
|
+
g.key
|
|
852
|
+
))
|
|
600
853
|
] }) : null
|
|
601
854
|
] });
|
|
602
855
|
}
|
|
@@ -619,7 +872,7 @@ function FloatingToolbar({
|
|
|
619
872
|
border: "1px solid rgba(255,255,255,0.12)",
|
|
620
873
|
borderRadius: 999,
|
|
621
874
|
boxShadow: "0 8px 24px -8px rgba(0,0,0,0.5)",
|
|
622
|
-
zIndex:
|
|
875
|
+
zIndex: Z2 + 2,
|
|
623
876
|
fontFamily: "system-ui, sans-serif",
|
|
624
877
|
fontSize: 12
|
|
625
878
|
};
|
|
@@ -637,6 +890,13 @@ function FloatingToolbar({
|
|
|
637
890
|
] })
|
|
638
891
|
] });
|
|
639
892
|
}
|
|
893
|
+
var ADD_MENU = [
|
|
894
|
+
{ kind: "text", label: "Text" },
|
|
895
|
+
{ kind: "heading", label: "Heading" },
|
|
896
|
+
{ kind: "button", label: "Button" },
|
|
897
|
+
{ kind: "image", label: "Image" },
|
|
898
|
+
{ kind: "box", label: "Box" }
|
|
899
|
+
];
|
|
640
900
|
function EditBar({
|
|
641
901
|
editing,
|
|
642
902
|
onToggle,
|
|
@@ -644,19 +904,48 @@ function EditBar({
|
|
|
644
904
|
canRedo,
|
|
645
905
|
onUndo,
|
|
646
906
|
onRedo,
|
|
647
|
-
|
|
907
|
+
onAdd
|
|
648
908
|
}) {
|
|
649
|
-
const
|
|
909
|
+
const [open, setOpen] = useState(false);
|
|
910
|
+
const bar = { position: "fixed", top: 12, right: 12, display: "flex", gap: 6, alignItems: "center", padding: 6, background: "#0f172a", color: "#fff", borderRadius: 999, boxShadow: "0 8px 24px -8px rgba(0,0,0,0.4)", zIndex: Z2 + 3, fontFamily: "system-ui, sans-serif", fontSize: 12 };
|
|
650
911
|
const btn = { font: "inherit", border: "none", background: "transparent", color: "inherit", cursor: "pointer", padding: "4px 8px", borderRadius: 999 };
|
|
651
912
|
return /* @__PURE__ */ jsxs("div", { style: bar, children: [
|
|
652
913
|
/* @__PURE__ */ jsx("button", { type: "button", style: { ...btn, background: editing ? "#8b5cf6" : "transparent" }, onClick: onToggle, children: editing ? "\u25CF Editing" : "Edit" }),
|
|
653
914
|
editing ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
654
|
-
/* @__PURE__ */
|
|
915
|
+
/* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
|
|
916
|
+
/* @__PURE__ */ jsx("button", { type: "button", style: { ...btn, background: open ? "#1e293b" : "transparent" }, onClick: () => setOpen((v) => !v), title: "Add an element", children: "\uFF0B Add \u25BE" }),
|
|
917
|
+
open ? /* @__PURE__ */ jsx("div", { style: { position: "absolute", top: "calc(100% + 6px)", right: 0, background: "#0f172a", border: "1px solid #1e293b", borderRadius: 10, padding: 4, display: "flex", flexDirection: "column", minWidth: 132, boxShadow: "0 12px 32px -10px rgba(0,0,0,0.6)" }, children: ADD_MENU.map((m) => /* @__PURE__ */ jsx(
|
|
918
|
+
"button",
|
|
919
|
+
{
|
|
920
|
+
type: "button",
|
|
921
|
+
style: { ...btn, textAlign: "left", borderRadius: 6, padding: "6px 10px" },
|
|
922
|
+
onClick: () => {
|
|
923
|
+
onAdd(m.kind);
|
|
924
|
+
setOpen(false);
|
|
925
|
+
},
|
|
926
|
+
children: m.label
|
|
927
|
+
},
|
|
928
|
+
m.kind
|
|
929
|
+
)) }) : null
|
|
930
|
+
] }),
|
|
655
931
|
/* @__PURE__ */ jsx("button", { type: "button", style: { ...btn, opacity: canUndo ? 1 : 0.4 }, disabled: !canUndo, onClick: onUndo, children: "\u21B6" }),
|
|
656
932
|
/* @__PURE__ */ jsx("button", { type: "button", style: { ...btn, opacity: canRedo ? 1 : 0.4 }, disabled: !canRedo, onClick: onRedo, children: "\u21B7" })
|
|
657
933
|
] }) : null
|
|
658
934
|
] });
|
|
659
935
|
}
|
|
936
|
+
function applyTransform(el, t) {
|
|
937
|
+
if (t && (t.x != null || t.y != null || t.scale != null || t.rotate != null || t.opacity != null || t.w != null || t.h != null)) {
|
|
938
|
+
el.style.transform = `translate3d(${t.x ?? 0}px, ${t.y ?? 0}px, 0) scale(${t.scale ?? 1}) rotate(${t.rotate ?? 0}deg)`;
|
|
939
|
+
el.style.opacity = t.opacity != null ? String(t.opacity) : "";
|
|
940
|
+
el.style.width = t.w != null ? `${t.w}px` : "";
|
|
941
|
+
el.style.height = t.h != null ? `${t.h}px` : "";
|
|
942
|
+
} else {
|
|
943
|
+
el.style.transform = "";
|
|
944
|
+
el.style.opacity = "";
|
|
945
|
+
el.style.width = "";
|
|
946
|
+
el.style.height = "";
|
|
947
|
+
}
|
|
948
|
+
}
|
|
660
949
|
function normalizeColor(v) {
|
|
661
950
|
return v && /^#[0-9a-fA-F]{6}$/.test(v) ? v : "#ffffff";
|
|
662
951
|
}
|
|
@@ -664,6 +953,6 @@ function cssEscape2(value) {
|
|
|
664
953
|
return value.replace(/["\\]/g, "\\$&");
|
|
665
954
|
}
|
|
666
955
|
|
|
667
|
-
export { Canvas, EditablePage, Editor, Inspector, LayersPanel, editorReduce, initEditor, useEditor };
|
|
956
|
+
export { Canvas, EditablePage, Editor, Inspector, LayersPanel, NodeInspector, editorReduce, initEditor, useEditor };
|
|
668
957
|
//# sourceMappingURL=editor.js.map
|
|
669
958
|
//# sourceMappingURL=editor.js.map
|