@particle-academy/fancy-cms-ui 0.0.1-dev.6 → 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 +380 -61
- 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 +354 -59
- 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,22 +598,16 @@ 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
607
|
const compute = () => {
|
|
418
|
-
const
|
|
608
|
+
const len2 = spacer.offsetHeight - window.innerHeight;
|
|
419
609
|
const top = spacer.getBoundingClientRect().top;
|
|
420
|
-
onProgress(
|
|
610
|
+
onProgress(len2 > 0 ? Math.min(1, Math.max(0, -top / len2)) : 0);
|
|
421
611
|
};
|
|
422
612
|
compute();
|
|
423
613
|
window.addEventListener("scroll", compute, { passive: true });
|
|
@@ -442,7 +632,7 @@ function EditablePage({
|
|
|
442
632
|
window.removeEventListener("scroll", measureBox);
|
|
443
633
|
window.removeEventListener("resize", measureBox);
|
|
444
634
|
};
|
|
445
|
-
}, [measureBox, ed.state.doc
|
|
635
|
+
}, [measureBox, ed.state.doc]);
|
|
446
636
|
useEffect(() => {
|
|
447
637
|
if (!editing || !selection || !pageRef.current || selNode?.type !== "text") return;
|
|
448
638
|
const el = pageRef.current.querySelector(`[data-cms="${cssEscape2(selection)}"]`);
|
|
@@ -467,17 +657,29 @@ function EditablePage({
|
|
|
467
657
|
ed.select(el.getAttribute("data-cms"));
|
|
468
658
|
}
|
|
469
659
|
};
|
|
470
|
-
const
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
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
|
+
);
|
|
478
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 }) });
|
|
479
681
|
return /* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
|
|
480
|
-
/* @__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,
|
|
481
683
|
editing && box && selection ? /* @__PURE__ */ jsx(
|
|
482
684
|
SelectionOverlay,
|
|
483
685
|
{
|
|
@@ -489,7 +691,20 @@ function EditablePage({
|
|
|
489
691
|
onLive: measureBox
|
|
490
692
|
}
|
|
491
693
|
) : null,
|
|
492
|
-
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,
|
|
493
708
|
revealed || editing ? /* @__PURE__ */ jsx(
|
|
494
709
|
EditBar,
|
|
495
710
|
{
|
|
@@ -502,12 +717,30 @@ function EditablePage({
|
|
|
502
717
|
canRedo: ed.canRedo,
|
|
503
718
|
onUndo: ed.undo,
|
|
504
719
|
onRedo: ed.redo,
|
|
505
|
-
|
|
720
|
+
onAdd: addNode
|
|
506
721
|
}
|
|
507
722
|
) : null,
|
|
508
|
-
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
|
|
509
724
|
] });
|
|
510
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
|
+
];
|
|
511
744
|
function SelectionOverlay({
|
|
512
745
|
box,
|
|
513
746
|
base,
|
|
@@ -519,29 +752,48 @@ function SelectionOverlay({
|
|
|
519
752
|
const drag = useRef(null);
|
|
520
753
|
const apply = (t) => {
|
|
521
754
|
const el = getEl();
|
|
522
|
-
if (el)
|
|
523
|
-
el.style.transform = `translate3d(${t.x ?? 0}px, ${t.y ?? 0}px, 0) scale(${t.scale ?? 1})`;
|
|
524
|
-
el.style.opacity = t.opacity != null ? String(t.opacity) : "";
|
|
525
|
-
}
|
|
755
|
+
if (el) applyTransform(el, t);
|
|
526
756
|
};
|
|
527
|
-
const
|
|
757
|
+
const startMove = (e) => {
|
|
528
758
|
e.stopPropagation();
|
|
529
759
|
e.preventDefault();
|
|
530
760
|
e.currentTarget.setPointerCapture(e.pointerId);
|
|
531
|
-
drag.current = {
|
|
761
|
+
drag.current = { x: e.clientX, y: e.clientY, w: box.w, h: box.h, live: { ...base } };
|
|
532
762
|
};
|
|
533
|
-
const
|
|
763
|
+
const moveMove = (e) => {
|
|
534
764
|
const d = drag.current;
|
|
535
765
|
if (!d) return;
|
|
536
|
-
|
|
537
|
-
d.live = { ...base, x: (base.x ?? 0) + (e.clientX - d.x), y: (base.y ?? 0) + (e.clientY - d.y) };
|
|
538
|
-
} else {
|
|
539
|
-
const factor = Math.max(0.1, (d.w + (e.clientX - d.x)) / d.w);
|
|
540
|
-
d.live = { ...base, scale: Number(((base.scale ?? 1) * factor).toFixed(3)) };
|
|
541
|
-
}
|
|
766
|
+
d.live = { ...base, x: (base.x ?? 0) + (e.clientX - d.x), y: (base.y ?? 0) + (e.clientY - d.y) };
|
|
542
767
|
apply(d.live);
|
|
543
768
|
onLive();
|
|
544
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
|
+
};
|
|
545
797
|
const end = () => {
|
|
546
798
|
const d = drag.current;
|
|
547
799
|
if (d) onTransform(d.live);
|
|
@@ -556,17 +808,23 @@ function SelectionOverlay({
|
|
|
556
808
|
outline: "2px solid #8b5cf6",
|
|
557
809
|
borderRadius: 4,
|
|
558
810
|
pointerEvents: "none",
|
|
559
|
-
zIndex:
|
|
811
|
+
zIndex: Z2
|
|
560
812
|
};
|
|
561
813
|
const handle = {
|
|
562
814
|
position: "fixed",
|
|
563
|
-
width:
|
|
564
|
-
height:
|
|
565
|
-
background: "#
|
|
566
|
-
border: "2px solid #
|
|
567
|
-
borderRadius:
|
|
568
|
-
zIndex:
|
|
569
|
-
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 };
|
|
570
828
|
};
|
|
571
829
|
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
572
830
|
/* @__PURE__ */ jsx("div", { style: outline }),
|
|
@@ -575,22 +833,23 @@ function SelectionOverlay({
|
|
|
575
833
|
"div",
|
|
576
834
|
{
|
|
577
835
|
title: "Drag to move",
|
|
578
|
-
onPointerDown:
|
|
579
|
-
onPointerMove:
|
|
836
|
+
onPointerDown: startMove,
|
|
837
|
+
onPointerMove: moveMove,
|
|
580
838
|
onPointerUp: end,
|
|
581
|
-
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" }
|
|
582
840
|
}
|
|
583
841
|
),
|
|
584
|
-
/* @__PURE__ */ jsx(
|
|
842
|
+
GRIPS.map((g) => /* @__PURE__ */ jsx(
|
|
585
843
|
"div",
|
|
586
844
|
{
|
|
587
845
|
title: "Drag to resize",
|
|
588
|
-
onPointerDown:
|
|
589
|
-
onPointerMove:
|
|
846
|
+
onPointerDown: startResize(g),
|
|
847
|
+
onPointerMove: resizeMove(g),
|
|
590
848
|
onPointerUp: end,
|
|
591
|
-
style: { ...handle,
|
|
592
|
-
}
|
|
593
|
-
|
|
849
|
+
style: { ...handle, ...gripPos(g) }
|
|
850
|
+
},
|
|
851
|
+
g.key
|
|
852
|
+
))
|
|
594
853
|
] }) : null
|
|
595
854
|
] });
|
|
596
855
|
}
|
|
@@ -613,7 +872,7 @@ function FloatingToolbar({
|
|
|
613
872
|
border: "1px solid rgba(255,255,255,0.12)",
|
|
614
873
|
borderRadius: 999,
|
|
615
874
|
boxShadow: "0 8px 24px -8px rgba(0,0,0,0.5)",
|
|
616
|
-
zIndex:
|
|
875
|
+
zIndex: Z2 + 2,
|
|
617
876
|
fontFamily: "system-ui, sans-serif",
|
|
618
877
|
fontSize: 12
|
|
619
878
|
};
|
|
@@ -631,6 +890,13 @@ function FloatingToolbar({
|
|
|
631
890
|
] })
|
|
632
891
|
] });
|
|
633
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
|
+
];
|
|
634
900
|
function EditBar({
|
|
635
901
|
editing,
|
|
636
902
|
onToggle,
|
|
@@ -638,19 +904,48 @@ function EditBar({
|
|
|
638
904
|
canRedo,
|
|
639
905
|
onUndo,
|
|
640
906
|
onRedo,
|
|
641
|
-
|
|
907
|
+
onAdd
|
|
642
908
|
}) {
|
|
643
|
-
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 };
|
|
644
911
|
const btn = { font: "inherit", border: "none", background: "transparent", color: "inherit", cursor: "pointer", padding: "4px 8px", borderRadius: 999 };
|
|
645
912
|
return /* @__PURE__ */ jsxs("div", { style: bar, children: [
|
|
646
913
|
/* @__PURE__ */ jsx("button", { type: "button", style: { ...btn, background: editing ? "#8b5cf6" : "transparent" }, onClick: onToggle, children: editing ? "\u25CF Editing" : "Edit" }),
|
|
647
914
|
editing ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
648
|
-
/* @__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
|
+
] }),
|
|
649
931
|
/* @__PURE__ */ jsx("button", { type: "button", style: { ...btn, opacity: canUndo ? 1 : 0.4 }, disabled: !canUndo, onClick: onUndo, children: "\u21B6" }),
|
|
650
932
|
/* @__PURE__ */ jsx("button", { type: "button", style: { ...btn, opacity: canRedo ? 1 : 0.4 }, disabled: !canRedo, onClick: onRedo, children: "\u21B7" })
|
|
651
933
|
] }) : null
|
|
652
934
|
] });
|
|
653
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
|
+
}
|
|
654
949
|
function normalizeColor(v) {
|
|
655
950
|
return v && /^#[0-9a-fA-F]{6}$/.test(v) ? v : "#ffffff";
|
|
656
951
|
}
|
|
@@ -658,6 +953,6 @@ function cssEscape2(value) {
|
|
|
658
953
|
return value.replace(/["\\]/g, "\\$&");
|
|
659
954
|
}
|
|
660
955
|
|
|
661
|
-
export { Canvas, EditablePage, Editor, Inspector, LayersPanel, editorReduce, initEditor, useEditor };
|
|
956
|
+
export { Canvas, EditablePage, Editor, Inspector, LayersPanel, NodeInspector, editorReduce, initEditor, useEditor };
|
|
662
957
|
//# sourceMappingURL=editor.js.map
|
|
663
958
|
//# sourceMappingURL=editor.js.map
|