@pixerate/editor-react 0.80.0 → 0.82.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/canvas/index.cjs +1303 -580
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +66 -5
- package/dist/canvas/index.d.ts +66 -5
- package/dist/canvas/index.js +365 -199
- package/dist/canvas/index.js.map +1 -1
- package/package.json +3 -3
package/dist/canvas/index.js
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EffectParameters,
|
|
3
|
+
EffectsBrowser,
|
|
4
|
+
useEffectDescription
|
|
5
|
+
} from "../chunk-WOQ3H7KA.js";
|
|
6
|
+
import "../chunk-ZQZAKUUM.js";
|
|
7
|
+
|
|
1
8
|
// src/canvas/AgentPresenceLayer.tsx
|
|
2
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
10
|
function AgentPresenceLayer({ presences, className = "" }) {
|
|
@@ -832,7 +839,8 @@ function useCanvasArrangeShortcuts(options) {
|
|
|
832
839
|
import { useMemo as useMemo2, useRef as useRef6, useSyncExternalStore } from "react";
|
|
833
840
|
import {
|
|
834
841
|
CanvasScenesStore,
|
|
835
|
-
fitViewportToNodes
|
|
842
|
+
fitViewportToNodes,
|
|
843
|
+
transitionCanvasView
|
|
836
844
|
} from "@pixerate/editor/canvas";
|
|
837
845
|
function useCanvasScenes(options = {}) {
|
|
838
846
|
const optionsRef = useRef6(options);
|
|
@@ -847,9 +855,13 @@ function useCanvasScenes(options = {}) {
|
|
|
847
855
|
);
|
|
848
856
|
const actions = useMemo2(() => {
|
|
849
857
|
const show = (scene) => {
|
|
850
|
-
if (scene)
|
|
851
|
-
|
|
852
|
-
|
|
858
|
+
if (!scene) return scene;
|
|
859
|
+
const o = optionsRef.current;
|
|
860
|
+
const provider = o.transitions?.provider;
|
|
861
|
+
const element = o.transitions?.element();
|
|
862
|
+
if (scene.transition && provider && element) {
|
|
863
|
+
void transitionCanvasView({ provider, transition: scene.transition, element, jump: () => o.setViewport?.(scene.viewport, { duration: 0 }) });
|
|
864
|
+
} else o.setViewport?.(scene.viewport, { duration: o.duration ?? 300 });
|
|
853
865
|
return scene;
|
|
854
866
|
};
|
|
855
867
|
return {
|
|
@@ -1338,7 +1350,7 @@ import {
|
|
|
1338
1350
|
} from "@pixerate/editor/canvas";
|
|
1339
1351
|
|
|
1340
1352
|
// src/canvas/ShapeNode.tsx
|
|
1341
|
-
import { getShapeRenderData, isShapeDescription } from "@pixerate/editor/canvas";
|
|
1353
|
+
import { getShapeRenderData, isShapeDescription as isShapeDescription2 } from "@pixerate/editor/canvas";
|
|
1342
1354
|
|
|
1343
1355
|
// src/canvas/useShapeBrushstroke.tsx
|
|
1344
1356
|
import { createContext, useContext, useEffect as useEffect7, useMemo as useMemo6, useState as useState6 } from "react";
|
|
@@ -1397,14 +1409,159 @@ function useCanvasBrushes() {
|
|
|
1397
1409
|
return useMemo6(() => state, [state]);
|
|
1398
1410
|
}
|
|
1399
1411
|
|
|
1412
|
+
// src/canvas/CanvasEffects.tsx
|
|
1413
|
+
import { createContext as createContext2, useContext as useContext2, useEffect as useEffect8, useMemo as useMemo7, useRef as useRef11, useState as useState7 } from "react";
|
|
1414
|
+
import {
|
|
1415
|
+
createCanvasEffectsController,
|
|
1416
|
+
createCanvasEffectsToolProvider,
|
|
1417
|
+
isShapeDescription,
|
|
1418
|
+
runCanvasNodeEffect
|
|
1419
|
+
} from "@pixerate/editor/canvas";
|
|
1420
|
+
import { Fragment, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1421
|
+
var ProviderContext = createContext2(null);
|
|
1422
|
+
function CanvasEffectsProvider({ provider, children }) {
|
|
1423
|
+
return /* @__PURE__ */ jsx5(ProviderContext.Provider, { value: provider ?? null, children });
|
|
1424
|
+
}
|
|
1425
|
+
var useCanvasEffectsProviderContext = () => useContext2(ProviderContext);
|
|
1426
|
+
function CanvasNodeEffectLayer({ effect, width, height, clipPath, clipTransform }) {
|
|
1427
|
+
const provider = useCanvasEffectsProviderContext();
|
|
1428
|
+
const ref = useRef11(null);
|
|
1429
|
+
const [failed, setFailed] = useState7(false);
|
|
1430
|
+
const dpr = typeof window !== "undefined" ? Math.min(2, window.devicePixelRatio || 1) : 1;
|
|
1431
|
+
const pw = Math.max(1, Math.round(width * dpr));
|
|
1432
|
+
const ph = Math.max(1, Math.round(height * dpr));
|
|
1433
|
+
const key = JSON.stringify(effect);
|
|
1434
|
+
useEffect8(() => {
|
|
1435
|
+
const canvas2 = ref.current;
|
|
1436
|
+
if (!provider || !canvas2) return;
|
|
1437
|
+
setFailed(false);
|
|
1438
|
+
const run = runCanvasNodeEffect({ provider, effect, target: canvas2, onError: () => setFailed(true) });
|
|
1439
|
+
return () => run.stop();
|
|
1440
|
+
}, [provider, key, pw, ph]);
|
|
1441
|
+
const clipId = useMemo7(() => `pixerate-effect-clip-${Math.random().toString(36).slice(2)}`, []);
|
|
1442
|
+
if (!provider || failed || !(width > 0 && height > 0)) return null;
|
|
1443
|
+
const style = { position: "absolute", inset: 0, width: "100%", height: "100%", pointerEvents: "none", opacity: effect.opacity ?? 1 };
|
|
1444
|
+
const canvas = /* @__PURE__ */ jsx5("canvas", { ref, width: pw, height: ph, style: { width: "100%", height: "100%", display: "block" }, "data-canvas-effect": effect.effect });
|
|
1445
|
+
if (effect.mode === "overlay" || !clipPath) return /* @__PURE__ */ jsx5("div", { style, children: canvas });
|
|
1446
|
+
return /* @__PURE__ */ jsxs4("svg", { style, viewBox: `0 0 ${width} ${height}`, preserveAspectRatio: "none", "aria-hidden": "true", children: [
|
|
1447
|
+
/* @__PURE__ */ jsx5("defs", { children: /* @__PURE__ */ jsx5("clipPath", { id: clipId, children: /* @__PURE__ */ jsx5("path", { d: clipPath, transform: clipTransform }) }) }),
|
|
1448
|
+
/* @__PURE__ */ jsx5("foreignObject", { x: 0, y: 0, width, height, clipPath: `url(#${clipId})`, children: canvas })
|
|
1449
|
+
] });
|
|
1450
|
+
}
|
|
1451
|
+
function useCanvasEffects(options) {
|
|
1452
|
+
const opts = useRef11(options);
|
|
1453
|
+
opts.current = options;
|
|
1454
|
+
const controller = useMemo7(
|
|
1455
|
+
() => createCanvasEffectsController({
|
|
1456
|
+
getNodes: () => opts.current.getNodes(),
|
|
1457
|
+
setNodes: (n) => opts.current.setNodes(n),
|
|
1458
|
+
history: { execute: (c) => opts.current.history ? opts.current.history.execute(c) : c.execute() },
|
|
1459
|
+
get scenes() {
|
|
1460
|
+
return opts.current.scenes;
|
|
1461
|
+
}
|
|
1462
|
+
}),
|
|
1463
|
+
[]
|
|
1464
|
+
);
|
|
1465
|
+
useEffect8(() => {
|
|
1466
|
+
if (!options.effects) return;
|
|
1467
|
+
return controller.useEffects(options.effects);
|
|
1468
|
+
}, [controller, options.effects]);
|
|
1469
|
+
return controller;
|
|
1470
|
+
}
|
|
1471
|
+
function useCanvasEffectsTools(registry, controller, options = {}) {
|
|
1472
|
+
const { id, namespace, readOnly, subscribe } = options;
|
|
1473
|
+
useEffect8(() => {
|
|
1474
|
+
if (!registry) return;
|
|
1475
|
+
return registry.register(createCanvasEffectsToolProvider(controller, { id, namespace, readOnly, subscribe }));
|
|
1476
|
+
}, [registry, controller, id, namespace, readOnly, subscribe]);
|
|
1477
|
+
}
|
|
1478
|
+
var btn = "rounded border border-border px-1.5 py-0.5 text-[11px] disabled:opacity-40";
|
|
1479
|
+
function Controls({ controller, nodeId, effect }) {
|
|
1480
|
+
const { description, error } = useEffectDescription(controller.effectsProvider, effect.effect);
|
|
1481
|
+
const [message, setMessage] = useState7(null);
|
|
1482
|
+
const run = (work) => void work.then(() => setMessage(null), (e) => setMessage(e instanceof Error ? e.message : String(e)));
|
|
1483
|
+
if (error) return /* @__PURE__ */ jsx5("p", { className: "text-[11px] text-amber-500", children: error });
|
|
1484
|
+
if (!description) return /* @__PURE__ */ jsx5("p", { className: "text-[11px] text-muted-foreground", children: "Loading\u2026" });
|
|
1485
|
+
return /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
1486
|
+
/* @__PURE__ */ jsx5(
|
|
1487
|
+
EffectParameters,
|
|
1488
|
+
{
|
|
1489
|
+
description,
|
|
1490
|
+
values: effect.values,
|
|
1491
|
+
onChange: (k, v) => run(controller.updateNodeEffect(nodeId, { values: { [k]: v } })),
|
|
1492
|
+
onReset: (k) => run(controller.updateNodeEffect(nodeId, { values: { [k]: null } })),
|
|
1493
|
+
onPreset: (v) => run(controller.updateNodeEffect(nodeId, { values: v }))
|
|
1494
|
+
}
|
|
1495
|
+
),
|
|
1496
|
+
message && /* @__PURE__ */ jsx5("p", { role: "alert", className: "text-[11px] text-destructive", children: message })
|
|
1497
|
+
] });
|
|
1498
|
+
}
|
|
1499
|
+
function CanvasEffectsPanel({ controller, nodeId, shape, sceneId, className = "" }) {
|
|
1500
|
+
const [, setTick] = useState7(0);
|
|
1501
|
+
useEffect8(() => controller.effects.subscribe(() => setTick((n) => n + 1)), [controller]);
|
|
1502
|
+
const provider = controller.effectsProvider;
|
|
1503
|
+
const [browse, setBrowse] = useState7(null);
|
|
1504
|
+
const [message, setMessage] = useState7(null);
|
|
1505
|
+
const run = (work) => {
|
|
1506
|
+
setMessage(null);
|
|
1507
|
+
Promise.resolve().then(work).then(() => setTick((n) => n + 1), (e) => setMessage(e instanceof Error ? e.message : String(e)));
|
|
1508
|
+
};
|
|
1509
|
+
const effect = isShapeDescription(shape) ? shape.effect : void 0;
|
|
1510
|
+
const transition = sceneId ? controller.sceneTransition(sceneId) : void 0;
|
|
1511
|
+
return /* @__PURE__ */ jsxs4("section", { className: `flex flex-col gap-2 text-xs ${className}`, "aria-label": "Canvas effects", "data-canvas-effects": "", children: [
|
|
1512
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
1513
|
+
/* @__PURE__ */ jsx5("span", { className: "flex-1 font-semibold", children: "Effects" }),
|
|
1514
|
+
/* @__PURE__ */ jsx5("button", { type: "button", className: btn, disabled: !provider || !nodeId || !shape, "aria-pressed": browse === "fill", onClick: () => setBrowse(browse === "fill" ? null : "fill"), children: "Fill\u2026" }),
|
|
1515
|
+
/* @__PURE__ */ jsx5("button", { type: "button", className: btn, disabled: !provider || !nodeId || !shape, "aria-pressed": browse === "overlay", onClick: () => setBrowse(browse === "overlay" ? null : "overlay"), children: "Overlay\u2026" }),
|
|
1516
|
+
/* @__PURE__ */ jsx5("button", { type: "button", className: btn, disabled: !provider || !sceneId, "aria-pressed": browse === "transition", onClick: () => setBrowse(browse === "transition" ? null : "transition"), children: "Scene transition\u2026" })
|
|
1517
|
+
] }),
|
|
1518
|
+
!provider && /* @__PURE__ */ jsx5("p", { className: "text-[11px] text-muted-foreground", children: "No effects provider is registered. Effects on the canvas are kept." }),
|
|
1519
|
+
browse === "fill" && nodeId && /* @__PURE__ */ jsx5(EffectsBrowser, { provider, uses: ["generator", "interactive"], title: "Fills", onPick: (e) => (setBrowse(null), run(() => controller.applyNodeEffect(nodeId, e.id, { mode: "fill" }))) }),
|
|
1520
|
+
browse === "overlay" && nodeId && /* @__PURE__ */ jsx5(EffectsBrowser, { provider, uses: ["overlay", "title", "interactive", "generator"], title: "Overlays", onPick: (e) => (setBrowse(null), run(() => controller.applyNodeEffect(nodeId, e.id, { mode: "overlay" }))) }),
|
|
1521
|
+
browse === "transition" && sceneId && /* @__PURE__ */ jsx5(EffectsBrowser, { provider, uses: ["transition"], title: "Transitions", onPick: (e) => (setBrowse(null), run(() => controller.setSceneTransition(sceneId, e.id))) }),
|
|
1522
|
+
effect && nodeId && /* @__PURE__ */ jsxs4("div", { className: "space-y-1 rounded border border-border p-1", "data-canvas-node-effect": nodeId, children: [
|
|
1523
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-1", children: [
|
|
1524
|
+
/* @__PURE__ */ jsxs4("span", { className: "min-w-0 flex-1 truncate font-medium", children: [
|
|
1525
|
+
effect.name ?? effect.effect,
|
|
1526
|
+
" ",
|
|
1527
|
+
/* @__PURE__ */ jsxs4("span", { className: "text-muted-foreground", children: [
|
|
1528
|
+
"\xB7 ",
|
|
1529
|
+
effect.mode
|
|
1530
|
+
] })
|
|
1531
|
+
] }),
|
|
1532
|
+
/* @__PURE__ */ jsxs4("label", { className: "flex items-center gap-1", children: [
|
|
1533
|
+
/* @__PURE__ */ jsx5("input", { type: "checkbox", checked: effect.playing !== false, "aria-label": "Play", onChange: (e) => {
|
|
1534
|
+
const playing = e.currentTarget.checked;
|
|
1535
|
+
run(() => controller.updateNodeEffect(nodeId, { playing }));
|
|
1536
|
+
} }),
|
|
1537
|
+
" Play"
|
|
1538
|
+
] }),
|
|
1539
|
+
/* @__PURE__ */ jsx5("button", { type: "button", className: btn, "aria-label": "Remove effect", onClick: () => run(() => controller.removeNodeEffect(nodeId)), children: "\u2715" })
|
|
1540
|
+
] }),
|
|
1541
|
+
provider && /* @__PURE__ */ jsx5(Controls, { controller, nodeId, effect })
|
|
1542
|
+
] }),
|
|
1543
|
+
sceneId && transition && /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-1", "data-canvas-scene-transition": sceneId, children: [
|
|
1544
|
+
/* @__PURE__ */ jsxs4("span", { className: "min-w-0 flex-1 truncate", children: [
|
|
1545
|
+
"Into scene: ",
|
|
1546
|
+
transition.name ?? transition.effect,
|
|
1547
|
+
" (",
|
|
1548
|
+
transition.duration ?? 600,
|
|
1549
|
+
" ms)"
|
|
1550
|
+
] }),
|
|
1551
|
+
/* @__PURE__ */ jsx5("button", { type: "button", className: btn, "aria-label": "Remove transition", onClick: () => run(() => controller.setSceneTransition(sceneId, null)), children: "\u2715" })
|
|
1552
|
+
] }),
|
|
1553
|
+
message && /* @__PURE__ */ jsx5("p", { role: "alert", className: "text-[11px] text-destructive", children: message })
|
|
1554
|
+
] });
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1400
1557
|
// src/canvas/ShapeNode.tsx
|
|
1401
|
-
import { jsx as
|
|
1558
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1402
1559
|
function ShapeNode({ id, data, width, height, selected, className = "", children }) {
|
|
1403
1560
|
const shape = data?.shape;
|
|
1404
|
-
const brushImage = useShapeBrushstroke(
|
|
1405
|
-
if (!
|
|
1561
|
+
const brushImage = useShapeBrushstroke(isShapeDescription2(shape) ? shape : null, width, height);
|
|
1562
|
+
if (!isShapeDescription2(shape)) return null;
|
|
1406
1563
|
const render = getShapeRenderData(shape, { width, height }, { id: id || data?.id });
|
|
1407
|
-
return /* @__PURE__ */
|
|
1564
|
+
return /* @__PURE__ */ jsxs5(
|
|
1408
1565
|
"div",
|
|
1409
1566
|
{
|
|
1410
1567
|
className: `pixerate-shape-node ${className}`.trim(),
|
|
@@ -1412,7 +1569,7 @@ function ShapeNode({ id, data, width, height, selected, className = "", children
|
|
|
1412
1569
|
"data-selected": selected ? "true" : void 0,
|
|
1413
1570
|
style: { position: "relative", width: "100%", height: "100%" },
|
|
1414
1571
|
children: [
|
|
1415
|
-
/* @__PURE__ */
|
|
1572
|
+
/* @__PURE__ */ jsxs5(
|
|
1416
1573
|
"svg",
|
|
1417
1574
|
{
|
|
1418
1575
|
viewBox: render.viewBox,
|
|
@@ -1422,13 +1579,13 @@ function ShapeNode({ id, data, width, height, selected, className = "", children
|
|
|
1422
1579
|
style: { display: "block", overflow: "visible" },
|
|
1423
1580
|
"aria-hidden": "true",
|
|
1424
1581
|
children: [
|
|
1425
|
-
(render.fillGradient || render.strokeGradient) && /* @__PURE__ */
|
|
1426
|
-
render.fillGradient && render.fillGradient.type === "linear" && /* @__PURE__ */
|
|
1427
|
-
render.fillGradient && render.fillGradient.type === "radial" && /* @__PURE__ */
|
|
1428
|
-
render.strokeGradient && render.strokeGradient.type === "linear" && /* @__PURE__ */
|
|
1429
|
-
render.strokeGradient && render.strokeGradient.type === "radial" && /* @__PURE__ */
|
|
1582
|
+
(render.fillGradient || render.strokeGradient) && /* @__PURE__ */ jsxs5("defs", { children: [
|
|
1583
|
+
render.fillGradient && render.fillGradient.type === "linear" && /* @__PURE__ */ jsx6("linearGradient", { id: render.fillGradient.id, ...render.fillGradient.attrs, children: render.fillGradient.stops.map((stop, i) => /* @__PURE__ */ jsx6("stop", { offset: stop.offset, stopColor: stop.stopColor, stopOpacity: stop.stopOpacity }, i)) }),
|
|
1584
|
+
render.fillGradient && render.fillGradient.type === "radial" && /* @__PURE__ */ jsx6("radialGradient", { id: render.fillGradient.id, ...render.fillGradient.attrs, children: render.fillGradient.stops.map((stop, i) => /* @__PURE__ */ jsx6("stop", { offset: stop.offset, stopColor: stop.stopColor, stopOpacity: stop.stopOpacity }, i)) }),
|
|
1585
|
+
render.strokeGradient && render.strokeGradient.type === "linear" && /* @__PURE__ */ jsx6("linearGradient", { id: render.strokeGradient.id, ...render.strokeGradient.attrs, children: render.strokeGradient.stops.map((stop, i) => /* @__PURE__ */ jsx6("stop", { offset: stop.offset, stopColor: stop.stopColor, stopOpacity: stop.stopOpacity }, i)) }),
|
|
1586
|
+
render.strokeGradient && render.strokeGradient.type === "radial" && /* @__PURE__ */ jsx6("radialGradient", { id: render.strokeGradient.id, ...render.strokeGradient.attrs, children: render.strokeGradient.stops.map((stop, i) => /* @__PURE__ */ jsx6("stop", { offset: stop.offset, stopColor: stop.stopColor, stopOpacity: stop.stopOpacity }, i)) })
|
|
1430
1587
|
] }),
|
|
1431
|
-
brushImage ? /* @__PURE__ */
|
|
1588
|
+
brushImage ? /* @__PURE__ */ jsx6("g", { transform: render.transform, children: /* @__PURE__ */ jsx6(
|
|
1432
1589
|
"image",
|
|
1433
1590
|
{
|
|
1434
1591
|
className: "pixerate-shape-brushstroke",
|
|
@@ -1440,7 +1597,7 @@ function ShapeNode({ id, data, width, height, selected, className = "", children
|
|
|
1440
1597
|
preserveAspectRatio: "none",
|
|
1441
1598
|
opacity: render.opacity
|
|
1442
1599
|
}
|
|
1443
|
-
) }) : /* @__PURE__ */
|
|
1600
|
+
) }) : /* @__PURE__ */ jsx6(
|
|
1444
1601
|
"path",
|
|
1445
1602
|
{
|
|
1446
1603
|
d: render.d,
|
|
@@ -1458,6 +1615,7 @@ function ShapeNode({ id, data, width, height, selected, className = "", children
|
|
|
1458
1615
|
]
|
|
1459
1616
|
}
|
|
1460
1617
|
),
|
|
1618
|
+
shape.effect && width && height ? /* @__PURE__ */ jsx6(CanvasNodeEffectLayer, { effect: shape.effect, width, height, clipPath: render.d, clipTransform: render.transform }) : null,
|
|
1461
1619
|
children
|
|
1462
1620
|
]
|
|
1463
1621
|
}
|
|
@@ -1477,7 +1635,7 @@ import {
|
|
|
1477
1635
|
SHAPE_NODE_TYPE,
|
|
1478
1636
|
SHAPE_OPERATIONS,
|
|
1479
1637
|
SHAPE_KINDS,
|
|
1480
|
-
isShapeDescription as
|
|
1638
|
+
isShapeDescription as isShapeDescription3,
|
|
1481
1639
|
shapeToPolygon,
|
|
1482
1640
|
getShapeSvg,
|
|
1483
1641
|
getShapeRenderData as getShapeRenderData2,
|
|
@@ -1591,17 +1749,17 @@ import {
|
|
|
1591
1749
|
} from "@pixerate/editor/canvas";
|
|
1592
1750
|
|
|
1593
1751
|
// src/canvas/useCanvasAutoLayout.ts
|
|
1594
|
-
import { useLayoutEffect, useMemo as
|
|
1752
|
+
import { useLayoutEffect, useMemo as useMemo8, useRef as useRef12, useState as useState8 } from "react";
|
|
1595
1753
|
import {
|
|
1596
1754
|
createCanvasAutoLayoutController
|
|
1597
1755
|
} from "@pixerate/editor/canvas";
|
|
1598
1756
|
function useCanvasAutoLayout(options) {
|
|
1599
|
-
const [guides, setGuides] =
|
|
1600
|
-
const nodesRef =
|
|
1757
|
+
const [guides, setGuides] = useState8([]);
|
|
1758
|
+
const nodesRef = useRef12(options.nodes);
|
|
1601
1759
|
nodesRef.current = options.nodes;
|
|
1602
|
-
const optionsRef =
|
|
1760
|
+
const optionsRef = useRef12(options);
|
|
1603
1761
|
optionsRef.current = options;
|
|
1604
|
-
const controller =
|
|
1762
|
+
const controller = useMemo8(
|
|
1605
1763
|
() => createCanvasAutoLayoutController({
|
|
1606
1764
|
getNodes: () => nodesRef.current,
|
|
1607
1765
|
setNodes: (next) => {
|
|
@@ -1630,7 +1788,7 @@ function useCanvasAutoLayout(options) {
|
|
|
1630
1788
|
useLayoutEffect(() => {
|
|
1631
1789
|
if (controller.hasPending) controller.flush();
|
|
1632
1790
|
}, [options.nodes, controller]);
|
|
1633
|
-
return
|
|
1791
|
+
return useMemo8(
|
|
1634
1792
|
() => ({
|
|
1635
1793
|
...controller,
|
|
1636
1794
|
/** Drop marker of the active reorder drag (flow coordinates). */
|
|
@@ -1644,7 +1802,7 @@ function useCanvasAutoLayout(options) {
|
|
|
1644
1802
|
}
|
|
1645
1803
|
|
|
1646
1804
|
// src/canvas/useCanvasTokens.ts
|
|
1647
|
-
import { useCallback as useCallback9, useEffect as
|
|
1805
|
+
import { useCallback as useCallback9, useEffect as useEffect9, useRef as useRef13, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
1648
1806
|
import {
|
|
1649
1807
|
bindCanvasToken,
|
|
1650
1808
|
detachTokenBindings,
|
|
@@ -1655,10 +1813,10 @@ import {
|
|
|
1655
1813
|
function useCanvasTokens(options) {
|
|
1656
1814
|
const { store, nodes, setNodes, modes, properties } = options;
|
|
1657
1815
|
const state = useSyncExternalStore2(store.subscribe, store.getState, store.getState);
|
|
1658
|
-
const latest =
|
|
1816
|
+
const latest = useRef13({ nodes, setNodes, modes, properties });
|
|
1659
1817
|
latest.current = { nodes, setNodes, modes, properties };
|
|
1660
1818
|
const opts = () => ({ modes: latest.current.modes, properties: latest.current.properties });
|
|
1661
|
-
|
|
1819
|
+
useEffect9(
|
|
1662
1820
|
() => store.subscribe((event) => {
|
|
1663
1821
|
if (event.deletedVariableIds.length === 0) return;
|
|
1664
1822
|
latest.current.setNodes((prev) => detachTokenBindings(prev, event.previous, event.deletedVariableIds, opts()));
|
|
@@ -1667,7 +1825,7 @@ function useCanvasTokens(options) {
|
|
|
1667
1825
|
[store]
|
|
1668
1826
|
);
|
|
1669
1827
|
const modesKey = JSON.stringify(modes ?? {});
|
|
1670
|
-
|
|
1828
|
+
useEffect9(() => {
|
|
1671
1829
|
const next = resolveCanvasTokens(nodes, state, opts());
|
|
1672
1830
|
if (next !== nodes) setNodes(next);
|
|
1673
1831
|
}, [nodes, state, modesKey, properties]);
|
|
@@ -1709,7 +1867,7 @@ import {
|
|
|
1709
1867
|
getTokensForProperty
|
|
1710
1868
|
} from "@pixerate/editor/canvas";
|
|
1711
1869
|
import { getCurrentMode, resolveToken } from "@pixerate/editor/tokens";
|
|
1712
|
-
import { jsx as
|
|
1870
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1713
1871
|
function TokenBindingPicker({
|
|
1714
1872
|
state,
|
|
1715
1873
|
nodes,
|
|
@@ -1726,15 +1884,15 @@ function TokenBindingPicker({
|
|
|
1726
1884
|
let rows = getBindableTokenProperties(first, options);
|
|
1727
1885
|
if (properties) rows = properties.map((key) => rows.find((p) => p.key === key)).filter((p) => !!p);
|
|
1728
1886
|
const modes = getEffectiveTokenModes2(first, nodes, state, options);
|
|
1729
|
-
return /* @__PURE__ */
|
|
1887
|
+
return /* @__PURE__ */ jsxs6("div", { "data-token-binding-picker": "", className: `flex flex-col gap-1 text-xs text-foreground ${className}`, children: [
|
|
1730
1888
|
rows.map((property) => {
|
|
1731
1889
|
const ids = new Set(selected.map((n) => getNodeTokenBindings(n)[property.key] ?? ""));
|
|
1732
1890
|
const value = ids.size === 1 ? [...ids][0] : "__mixed";
|
|
1733
1891
|
const candidates = getTokensForProperty(state, property, first);
|
|
1734
1892
|
const resolved = value && value !== "__mixed" ? resolveToken(state, value, modes) : null;
|
|
1735
|
-
return /* @__PURE__ */
|
|
1736
|
-
/* @__PURE__ */
|
|
1737
|
-
/* @__PURE__ */
|
|
1893
|
+
return /* @__PURE__ */ jsxs6("label", { className: "flex items-center gap-2", "data-token-property": property.key, children: [
|
|
1894
|
+
/* @__PURE__ */ jsx7("span", { className: "w-28 shrink-0 text-muted-foreground", children: property.label }),
|
|
1895
|
+
/* @__PURE__ */ jsxs6(
|
|
1738
1896
|
"select",
|
|
1739
1897
|
{
|
|
1740
1898
|
"aria-label": `${property.label} variable`,
|
|
@@ -1749,11 +1907,11 @@ function TokenBindingPicker({
|
|
|
1749
1907
|
}
|
|
1750
1908
|
},
|
|
1751
1909
|
children: [
|
|
1752
|
-
value === "__mixed" ? /* @__PURE__ */
|
|
1753
|
-
/* @__PURE__ */
|
|
1910
|
+
value === "__mixed" ? /* @__PURE__ */ jsx7("option", { value: "__mixed", children: "Mixed" }) : null,
|
|
1911
|
+
/* @__PURE__ */ jsx7("option", { value: "", children: "None" }),
|
|
1754
1912
|
candidates.map((v) => {
|
|
1755
1913
|
const collection = state.collections.find((c) => c.id === v.collectionId);
|
|
1756
|
-
return /* @__PURE__ */
|
|
1914
|
+
return /* @__PURE__ */ jsxs6("option", { value: v.id, children: [
|
|
1757
1915
|
v.name,
|
|
1758
1916
|
collection && state.collections.length > 1 ? ` (${collection.name})` : ""
|
|
1759
1917
|
] }, v.id);
|
|
@@ -1761,17 +1919,17 @@ function TokenBindingPicker({
|
|
|
1761
1919
|
]
|
|
1762
1920
|
}
|
|
1763
1921
|
),
|
|
1764
|
-
/* @__PURE__ */
|
|
1922
|
+
/* @__PURE__ */ jsx7("span", { className: "w-16 shrink-0 truncate text-right text-muted-foreground", "data-token-resolved": "", children: resolved?.ok ? property.type === "color" ? /* @__PURE__ */ jsx7(
|
|
1765
1923
|
"span",
|
|
1766
1924
|
{
|
|
1767
1925
|
className: "inline-block h-3 w-3 rounded border border-border align-middle",
|
|
1768
1926
|
style: { background: String(resolved.value) },
|
|
1769
1927
|
title: String(resolved.value)
|
|
1770
1928
|
}
|
|
1771
|
-
) : String(resolved.value) : resolved ? /* @__PURE__ */
|
|
1929
|
+
) : String(resolved.value) : resolved ? /* @__PURE__ */ jsx7("span", { title: resolved.message, children: "\u26A0" }) : null })
|
|
1772
1930
|
] }, property.key);
|
|
1773
1931
|
}),
|
|
1774
|
-
state.collections.length === 0 ? /* @__PURE__ */
|
|
1932
|
+
state.collections.length === 0 ? /* @__PURE__ */ jsx7("p", { className: "text-muted-foreground", children: "No variables yet." }) : null
|
|
1775
1933
|
] });
|
|
1776
1934
|
}
|
|
1777
1935
|
function TokenModeSwitcher({
|
|
@@ -1789,12 +1947,12 @@ function TokenModeSwitcher({
|
|
|
1789
1947
|
const parent = first.parentId ? nodes.find((n) => n.id === first.parentId) : void 0;
|
|
1790
1948
|
const inherited = parent ? getEffectiveTokenModes2(parent, nodes, state, options) : { ...options.modes };
|
|
1791
1949
|
const collections = state.collections.filter((c) => showSingleMode || c.modes.length > 1);
|
|
1792
|
-
return /* @__PURE__ */
|
|
1950
|
+
return /* @__PURE__ */ jsx7("div", { "data-token-mode-switcher": "", className: `flex flex-col gap-1 text-xs text-foreground ${className}`, children: collections.map((collection) => {
|
|
1793
1951
|
const auto = getCurrentMode(collection, inherited);
|
|
1794
1952
|
const explicit = collection.modes.some((m) => m.id === own[collection.id]) ? own[collection.id] : "";
|
|
1795
|
-
return /* @__PURE__ */
|
|
1796
|
-
/* @__PURE__ */
|
|
1797
|
-
/* @__PURE__ */
|
|
1953
|
+
return /* @__PURE__ */ jsxs6("label", { className: "flex items-center gap-2", "data-token-collection": collection.id, children: [
|
|
1954
|
+
/* @__PURE__ */ jsx7("span", { className: "w-28 shrink-0 truncate text-muted-foreground", children: collection.name }),
|
|
1955
|
+
/* @__PURE__ */ jsxs6(
|
|
1798
1956
|
"select",
|
|
1799
1957
|
{
|
|
1800
1958
|
"aria-label": `${collection.name} mode`,
|
|
@@ -1802,12 +1960,12 @@ function TokenModeSwitcher({
|
|
|
1802
1960
|
value: explicit,
|
|
1803
1961
|
onChange: (e) => onChange(setCanvasTokenMode2(nodes, nodeIds, collection.id, e.currentTarget.value || null, state, options)),
|
|
1804
1962
|
children: [
|
|
1805
|
-
/* @__PURE__ */
|
|
1963
|
+
/* @__PURE__ */ jsxs6("option", { value: "", children: [
|
|
1806
1964
|
"Auto (",
|
|
1807
1965
|
auto.name,
|
|
1808
1966
|
")"
|
|
1809
1967
|
] }),
|
|
1810
|
-
collection.modes.map((m) => /* @__PURE__ */
|
|
1968
|
+
collection.modes.map((m) => /* @__PURE__ */ jsx7("option", { value: m.id, children: m.name }, m.id))
|
|
1811
1969
|
]
|
|
1812
1970
|
}
|
|
1813
1971
|
)
|
|
@@ -1838,16 +1996,16 @@ import {
|
|
|
1838
1996
|
} from "@pixerate/editor/canvas";
|
|
1839
1997
|
|
|
1840
1998
|
// src/canvas/useCanvasAnimation.ts
|
|
1841
|
-
import { useEffect as
|
|
1999
|
+
import { useEffect as useEffect10, useMemo as useMemo9, useRef as useRef14, useSyncExternalStore as useSyncExternalStore3 } from "react";
|
|
1842
2000
|
import {
|
|
1843
2001
|
createCanvasAnimationController
|
|
1844
2002
|
} from "@pixerate/editor/canvas";
|
|
1845
2003
|
function useCanvasAnimation(options) {
|
|
1846
|
-
const nodesRef =
|
|
2004
|
+
const nodesRef = useRef14(options.nodes);
|
|
1847
2005
|
nodesRef.current = options.nodes;
|
|
1848
|
-
const optionsRef =
|
|
2006
|
+
const optionsRef = useRef14(options);
|
|
1849
2007
|
optionsRef.current = options;
|
|
1850
|
-
const controller =
|
|
2008
|
+
const controller = useMemo9(
|
|
1851
2009
|
() => createCanvasAnimationController({
|
|
1852
2010
|
getNodes: () => nodesRef.current,
|
|
1853
2011
|
setNodes: (next) => {
|
|
@@ -1874,14 +2032,14 @@ function useCanvasAnimation(options) {
|
|
|
1874
2032
|
}),
|
|
1875
2033
|
[]
|
|
1876
2034
|
);
|
|
1877
|
-
|
|
1878
|
-
|
|
2035
|
+
useEffect10(() => () => controller.destroy(), [controller]);
|
|
2036
|
+
useEffect10(() => {
|
|
1879
2037
|
if (options.loop !== void 0) controller.setLoop(options.loop);
|
|
1880
2038
|
}, [controller, options.loop]);
|
|
1881
|
-
|
|
2039
|
+
useEffect10(() => {
|
|
1882
2040
|
if (options.playbackRate !== void 0) controller.setPlaybackRate(options.playbackRate);
|
|
1883
2041
|
}, [controller, options.playbackRate]);
|
|
1884
|
-
|
|
2042
|
+
useEffect10(() => {
|
|
1885
2043
|
if (options.recording !== void 0) controller.setRecording(options.recording);
|
|
1886
2044
|
}, [controller, options.recording]);
|
|
1887
2045
|
const state = useSyncExternalStore3(
|
|
@@ -1889,11 +2047,11 @@ function useCanvasAnimation(options) {
|
|
|
1889
2047
|
() => controller.getState(),
|
|
1890
2048
|
() => controller.getState()
|
|
1891
2049
|
);
|
|
1892
|
-
|
|
2050
|
+
useEffect10(() => {
|
|
1893
2051
|
controller.refresh();
|
|
1894
2052
|
}, [controller, options.nodes]);
|
|
1895
|
-
const displayNodes =
|
|
1896
|
-
return
|
|
2053
|
+
const displayNodes = useMemo9(() => controller.display(options.nodes), [controller, options.nodes, state.time]);
|
|
2054
|
+
return useMemo9(
|
|
1897
2055
|
() => ({
|
|
1898
2056
|
...controller,
|
|
1899
2057
|
state,
|
|
@@ -1914,7 +2072,7 @@ function useCanvasAnimation(options) {
|
|
|
1914
2072
|
}
|
|
1915
2073
|
|
|
1916
2074
|
// src/canvas/AnimationTimeline.tsx
|
|
1917
|
-
import { useEffect as
|
|
2075
|
+
import { useEffect as useEffect11, useRef as useRef15 } from "react";
|
|
1918
2076
|
import {
|
|
1919
2077
|
ANIMATION_EASING_LABELS,
|
|
1920
2078
|
ANIMATION_EASING_PRESETS,
|
|
@@ -1923,7 +2081,7 @@ import {
|
|
|
1923
2081
|
timeToX,
|
|
1924
2082
|
xToTime
|
|
1925
2083
|
} from "@pixerate/editor/canvas";
|
|
1926
|
-
import { jsx as
|
|
2084
|
+
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1927
2085
|
var LOOP_LABELS = { none: "Once", loop: "Loop", "ping-pong": "Ping-pong" };
|
|
1928
2086
|
var easingValue = (easing) => typeof easing === "string" ? easing : easing ? "custom" : "linear";
|
|
1929
2087
|
function AnimationTimeline({ animation, nodeIds, width = 360, snapThreshold = 8, labelOf, className = "" }) {
|
|
@@ -1937,8 +2095,8 @@ function AnimationTimeline({ animation, nodeIds, width = 360, snapThreshold = 8,
|
|
|
1937
2095
|
for (const row of rows) for (const k of row.keyframes) if (k.selected && k.ref.property === first.property && k.ref.nodeId === first.nodeId) return easingValue(k.easing);
|
|
1938
2096
|
return "";
|
|
1939
2097
|
})();
|
|
1940
|
-
const dragRef =
|
|
1941
|
-
|
|
2098
|
+
const dragRef = useRef15(null);
|
|
2099
|
+
useEffect11(() => {
|
|
1942
2100
|
const onKey = (event) => {
|
|
1943
2101
|
if (event.key === "Escape" && dragRef.current) {
|
|
1944
2102
|
dragRef.current = null;
|
|
@@ -1991,17 +2149,17 @@ function AnimationTimeline({ animation, nodeIds, width = 360, snapThreshold = 8,
|
|
|
1991
2149
|
animation.deleteKeyframes();
|
|
1992
2150
|
}
|
|
1993
2151
|
};
|
|
1994
|
-
const
|
|
2152
|
+
const btn2 = "rounded border border-border px-2 py-0.5 text-xs hover:bg-muted disabled:opacity-50";
|
|
1995
2153
|
const playheadX = timeToX(state.time, duration, width);
|
|
1996
2154
|
const labelWidth = 120;
|
|
1997
|
-
return /* @__PURE__ */
|
|
1998
|
-
/* @__PURE__ */
|
|
1999
|
-
/* @__PURE__ */
|
|
2000
|
-
/* @__PURE__ */
|
|
2155
|
+
return /* @__PURE__ */ jsxs7("div", { "data-animation-timeline": "", className: `flex flex-col gap-1 text-xs text-foreground ${className}`, tabIndex: 0, onKeyDown: onTimelineKey, children: [
|
|
2156
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex flex-wrap items-center gap-2", role: "toolbar", "aria-label": "Animation", children: [
|
|
2157
|
+
/* @__PURE__ */ jsx8("button", { type: "button", className: btn2, "data-action": "toggle-play", "aria-label": state.playing ? "Pause" : "Play", onClick: () => animation.toggle(), children: state.playing ? "\u275A\u275A" : "\u25B6" }),
|
|
2158
|
+
/* @__PURE__ */ jsx8(
|
|
2001
2159
|
"button",
|
|
2002
2160
|
{
|
|
2003
2161
|
type: "button",
|
|
2004
|
-
className: `${
|
|
2162
|
+
className: `${btn2} ${state.recording ? "text-red-500" : ""}`,
|
|
2005
2163
|
"data-action": "record",
|
|
2006
2164
|
"aria-pressed": state.recording,
|
|
2007
2165
|
"aria-label": "Record keyframes",
|
|
@@ -2009,13 +2167,13 @@ function AnimationTimeline({ animation, nodeIds, width = 360, snapThreshold = 8,
|
|
|
2009
2167
|
children: "\u25CF Rec"
|
|
2010
2168
|
}
|
|
2011
2169
|
),
|
|
2012
|
-
/* @__PURE__ */
|
|
2013
|
-
/* @__PURE__ */
|
|
2170
|
+
/* @__PURE__ */ jsx8("button", { type: "button", className: btn2, "data-action": "add-keyframe", onClick: () => animation.addKeyframe(), children: "\u25C6 Key" }),
|
|
2171
|
+
/* @__PURE__ */ jsxs7("span", { "data-time": "", className: "tabular-nums text-muted-foreground", children: [
|
|
2014
2172
|
formatAnimationTime(state.time),
|
|
2015
2173
|
" / ",
|
|
2016
2174
|
formatAnimationTime(duration)
|
|
2017
2175
|
] }),
|
|
2018
|
-
/* @__PURE__ */
|
|
2176
|
+
/* @__PURE__ */ jsxs7(
|
|
2019
2177
|
"select",
|
|
2020
2178
|
{
|
|
2021
2179
|
"aria-label": "Easing",
|
|
@@ -2025,13 +2183,13 @@ function AnimationTimeline({ animation, nodeIds, width = 360, snapThreshold = 8,
|
|
|
2025
2183
|
disabled: state.selection.length === 0,
|
|
2026
2184
|
onChange: (e) => e.target.value && e.target.value !== "custom" && animation.setEasing(e.target.value),
|
|
2027
2185
|
children: [
|
|
2028
|
-
/* @__PURE__ */
|
|
2029
|
-
ANIMATION_EASING_PRESETS.map((preset) => /* @__PURE__ */
|
|
2030
|
-
selectedEasing === "custom" ? /* @__PURE__ */
|
|
2186
|
+
/* @__PURE__ */ jsx8("option", { value: "", children: "Easing\u2026" }),
|
|
2187
|
+
ANIMATION_EASING_PRESETS.map((preset) => /* @__PURE__ */ jsx8("option", { value: preset, children: ANIMATION_EASING_LABELS[preset] }, preset)),
|
|
2188
|
+
selectedEasing === "custom" ? /* @__PURE__ */ jsx8("option", { value: "custom", children: "Custom" }) : null
|
|
2031
2189
|
]
|
|
2032
2190
|
}
|
|
2033
2191
|
),
|
|
2034
|
-
/* @__PURE__ */
|
|
2192
|
+
/* @__PURE__ */ jsx8(
|
|
2035
2193
|
"select",
|
|
2036
2194
|
{
|
|
2037
2195
|
"aria-label": "Loop",
|
|
@@ -2039,13 +2197,13 @@ function AnimationTimeline({ animation, nodeIds, width = 360, snapThreshold = 8,
|
|
|
2039
2197
|
className: "rounded border border-border bg-background px-1 py-0.5",
|
|
2040
2198
|
value: state.loop,
|
|
2041
2199
|
onChange: (e) => animation.setLoop(e.target.value),
|
|
2042
|
-
children: Object.keys(LOOP_LABELS).map((mode) => /* @__PURE__ */
|
|
2200
|
+
children: Object.keys(LOOP_LABELS).map((mode) => /* @__PURE__ */ jsx8("option", { value: mode, children: LOOP_LABELS[mode] }, mode))
|
|
2043
2201
|
}
|
|
2044
2202
|
)
|
|
2045
2203
|
] }),
|
|
2046
|
-
/* @__PURE__ */
|
|
2047
|
-
/* @__PURE__ */
|
|
2048
|
-
/* @__PURE__ */
|
|
2204
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex", children: [
|
|
2205
|
+
/* @__PURE__ */ jsx8("div", { style: { width: labelWidth }, className: "shrink-0" }),
|
|
2206
|
+
/* @__PURE__ */ jsxs7(
|
|
2049
2207
|
"div",
|
|
2050
2208
|
{
|
|
2051
2209
|
"data-timeline-ruler": "",
|
|
@@ -2053,15 +2211,15 @@ function AnimationTimeline({ animation, nodeIds, width = 360, snapThreshold = 8,
|
|
|
2053
2211
|
style: { width },
|
|
2054
2212
|
onPointerDown: onRulerDown,
|
|
2055
2213
|
children: [
|
|
2056
|
-
ticks.map((tick) => /* @__PURE__ */
|
|
2057
|
-
/* @__PURE__ */
|
|
2214
|
+
ticks.map((tick) => /* @__PURE__ */ jsx8("span", { className: "absolute top-0 -translate-x-1/2 text-[10px] text-muted-foreground", style: { left: tick.x }, children: tick.label }, tick.time)),
|
|
2215
|
+
/* @__PURE__ */ jsx8("div", { "data-playhead": "", className: "absolute top-0 h-5 w-px bg-red-500", style: { left: playheadX } })
|
|
2058
2216
|
]
|
|
2059
2217
|
}
|
|
2060
2218
|
)
|
|
2061
2219
|
] }),
|
|
2062
|
-
rows.length === 0 ? /* @__PURE__ */
|
|
2063
|
-
/* @__PURE__ */
|
|
2064
|
-
/* @__PURE__ */
|
|
2220
|
+
rows.length === 0 ? /* @__PURE__ */ jsx8("p", { className: "text-muted-foreground", "data-timeline-empty": "", children: "Select an animated node, or press \u25C6 Key to add a keyframe." }) : rows.map((row) => /* @__PURE__ */ jsxs7("div", { className: "flex items-center", "data-track": row.id, children: [
|
|
2221
|
+
/* @__PURE__ */ jsxs7("label", { className: "flex shrink-0 items-center gap-1 truncate pr-2", style: { width: labelWidth }, title: `${row.nodeLabel} \xB7 ${row.label}`, children: [
|
|
2222
|
+
/* @__PURE__ */ jsx8(
|
|
2065
2223
|
"input",
|
|
2066
2224
|
{
|
|
2067
2225
|
type: "checkbox",
|
|
@@ -2070,15 +2228,15 @@ function AnimationTimeline({ animation, nodeIds, width = 360, snapThreshold = 8,
|
|
|
2070
2228
|
onChange: (e) => animation.setTrackEnabled(row.nodeId, row.property, e.target.checked)
|
|
2071
2229
|
}
|
|
2072
2230
|
),
|
|
2073
|
-
/* @__PURE__ */
|
|
2231
|
+
/* @__PURE__ */ jsxs7("span", { className: "truncate", children: [
|
|
2074
2232
|
rows.filter((r) => r.nodeId === row.nodeId).length < rows.length ? `${row.nodeLabel} \xB7 ` : "",
|
|
2075
2233
|
row.label
|
|
2076
2234
|
] })
|
|
2077
2235
|
] }),
|
|
2078
|
-
/* @__PURE__ */
|
|
2079
|
-
/* @__PURE__ */
|
|
2080
|
-
state.drag?.target != null ? /* @__PURE__ */
|
|
2081
|
-
row.keyframes.map((k) => /* @__PURE__ */
|
|
2236
|
+
/* @__PURE__ */ jsxs7("div", { "data-lane": "", className: `relative h-5 rounded bg-muted/40 ${row.enabled ? "" : "opacity-50"}`, style: { width }, children: [
|
|
2237
|
+
/* @__PURE__ */ jsx8("div", { className: "pointer-events-none absolute top-0 h-5 w-px bg-red-500/60", style: { left: playheadX } }),
|
|
2238
|
+
state.drag?.target != null ? /* @__PURE__ */ jsx8("div", { "data-snap-target": "", className: "pointer-events-none absolute top-0 h-5 w-px bg-sky-400", style: { left: timeToX(state.drag.target, duration, width) } }) : null,
|
|
2239
|
+
row.keyframes.map((k) => /* @__PURE__ */ jsx8(
|
|
2082
2240
|
"button",
|
|
2083
2241
|
{
|
|
2084
2242
|
type: "button",
|
|
@@ -2176,16 +2334,16 @@ import {
|
|
|
2176
2334
|
} from "@pixerate/editor/canvas";
|
|
2177
2335
|
|
|
2178
2336
|
// src/canvas/useCanvasComponents.ts
|
|
2179
|
-
import { useLayoutEffect as useLayoutEffect2, useMemo as
|
|
2337
|
+
import { useLayoutEffect as useLayoutEffect2, useMemo as useMemo10, useRef as useRef16 } from "react";
|
|
2180
2338
|
import {
|
|
2181
2339
|
createCanvasComponentsController
|
|
2182
2340
|
} from "@pixerate/editor/canvas";
|
|
2183
2341
|
function useCanvasComponents(options) {
|
|
2184
|
-
const nodesRef =
|
|
2342
|
+
const nodesRef = useRef16(options.nodes);
|
|
2185
2343
|
nodesRef.current = options.nodes;
|
|
2186
|
-
const optionsRef =
|
|
2344
|
+
const optionsRef = useRef16(options);
|
|
2187
2345
|
optionsRef.current = options;
|
|
2188
|
-
const controller =
|
|
2346
|
+
const controller = useMemo10(
|
|
2189
2347
|
() => createCanvasComponentsController({
|
|
2190
2348
|
getNodes: () => nodesRef.current,
|
|
2191
2349
|
setNodes: (next) => {
|
|
@@ -2221,15 +2379,15 @@ function useCanvasComponents(options) {
|
|
|
2221
2379
|
}
|
|
2222
2380
|
|
|
2223
2381
|
// src/canvas/CanvasComponentsPanel.tsx
|
|
2224
|
-
import { useState as
|
|
2382
|
+
import { useState as useState9 } from "react";
|
|
2225
2383
|
import {
|
|
2226
2384
|
CANVAS_COMPONENT_DRAG_TYPE,
|
|
2227
2385
|
inspectCanvasInstance,
|
|
2228
2386
|
listCanvasComponents
|
|
2229
2387
|
} from "@pixerate/editor/canvas";
|
|
2230
|
-
import { Fragment, jsx as
|
|
2388
|
+
import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2231
2389
|
function InlineField({ value, label, onCommit }) {
|
|
2232
|
-
return /* @__PURE__ */
|
|
2390
|
+
return /* @__PURE__ */ jsx9(
|
|
2233
2391
|
"input",
|
|
2234
2392
|
{
|
|
2235
2393
|
type: "text",
|
|
@@ -2260,10 +2418,10 @@ function CanvasComponentsPanel({
|
|
|
2260
2418
|
search = true,
|
|
2261
2419
|
className = ""
|
|
2262
2420
|
}) {
|
|
2263
|
-
const [query, setQuery] =
|
|
2264
|
-
const [propsOpen, setPropsOpen] =
|
|
2265
|
-
const [menuFor, setMenuFor] =
|
|
2266
|
-
const [editing, setEditing] =
|
|
2421
|
+
const [query, setQuery] = useState9("");
|
|
2422
|
+
const [propsOpen, setPropsOpen] = useState9(null);
|
|
2423
|
+
const [menuFor, setMenuFor] = useState9(null);
|
|
2424
|
+
const [editing, setEditing] = useState9(null);
|
|
2267
2425
|
const { components: all, sets } = listCanvasComponents(nodes);
|
|
2268
2426
|
const q = query.trim().toLowerCase();
|
|
2269
2427
|
const match = (name) => !q || name.toLowerCase().includes(q);
|
|
@@ -2275,7 +2433,7 @@ function CanvasComponentsPanel({
|
|
|
2275
2433
|
};
|
|
2276
2434
|
const small = "shrink-0 rounded px-1 text-[10px] text-muted-foreground hover:bg-muted hover:text-foreground disabled:opacity-40";
|
|
2277
2435
|
const menuItem = "rounded px-2 py-0.5 text-left hover:bg-muted disabled:opacity-40";
|
|
2278
|
-
const item = (id, name, count, extra = {}, onContextMenu) => /* @__PURE__ */
|
|
2436
|
+
const item = (id, name, count, extra = {}, onContextMenu) => /* @__PURE__ */ jsxs8(
|
|
2279
2437
|
"button",
|
|
2280
2438
|
{
|
|
2281
2439
|
type: "button",
|
|
@@ -2292,17 +2450,17 @@ function CanvasComponentsPanel({
|
|
|
2292
2450
|
e.dataTransfer.effectAllowed = "copy";
|
|
2293
2451
|
},
|
|
2294
2452
|
children: [
|
|
2295
|
-
/* @__PURE__ */
|
|
2296
|
-
/* @__PURE__ */
|
|
2453
|
+
/* @__PURE__ */ jsxs8("span", { className: "truncate", children: [
|
|
2454
|
+
/* @__PURE__ */ jsx9("span", { "aria-hidden": true, className: "mr-1 text-muted-foreground", children: "\u25C7" }),
|
|
2297
2455
|
name
|
|
2298
2456
|
] }),
|
|
2299
|
-
/* @__PURE__ */
|
|
2457
|
+
/* @__PURE__ */ jsx9("span", { className: "text-[10px] text-muted-foreground", "data-instance-count": "", children: count })
|
|
2300
2458
|
]
|
|
2301
2459
|
},
|
|
2302
2460
|
id
|
|
2303
2461
|
);
|
|
2304
|
-
return /* @__PURE__ */
|
|
2305
|
-
search ? /* @__PURE__ */
|
|
2462
|
+
return /* @__PURE__ */ jsxs8("div", { "data-components-panel": "", className: `flex flex-col gap-1 text-xs text-foreground ${className}`, children: [
|
|
2463
|
+
search ? /* @__PURE__ */ jsx9(
|
|
2306
2464
|
"input",
|
|
2307
2465
|
{
|
|
2308
2466
|
type: "search",
|
|
@@ -2312,11 +2470,11 @@ function CanvasComponentsPanel({
|
|
|
2312
2470
|
onInput: (e) => setQuery(e.target.value)
|
|
2313
2471
|
}
|
|
2314
2472
|
) : null,
|
|
2315
|
-
shownSets.map((set) => /* @__PURE__ */
|
|
2316
|
-
/* @__PURE__ */
|
|
2473
|
+
shownSets.map((set) => /* @__PURE__ */ jsxs8("div", { "data-component-set": set.id, className: "flex flex-col", children: [
|
|
2474
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-1", children: [
|
|
2317
2475
|
item(set.id, set.name, set.variants.reduce((sum, v) => sum + v.instanceCount, 0), { "data-kind": "set" }),
|
|
2318
|
-
components ? /* @__PURE__ */
|
|
2319
|
-
/* @__PURE__ */
|
|
2476
|
+
components ? /* @__PURE__ */ jsxs8(Fragment2, { children: [
|
|
2477
|
+
/* @__PURE__ */ jsx9(
|
|
2320
2478
|
"button",
|
|
2321
2479
|
{
|
|
2322
2480
|
type: "button",
|
|
@@ -2328,7 +2486,7 @@ function CanvasComponentsPanel({
|
|
|
2328
2486
|
children: "+\xA0Variant"
|
|
2329
2487
|
}
|
|
2330
2488
|
),
|
|
2331
|
-
/* @__PURE__ */
|
|
2489
|
+
/* @__PURE__ */ jsx9(
|
|
2332
2490
|
"button",
|
|
2333
2491
|
{
|
|
2334
2492
|
type: "button",
|
|
@@ -2343,8 +2501,8 @@ function CanvasComponentsPanel({
|
|
|
2343
2501
|
)
|
|
2344
2502
|
] }) : null
|
|
2345
2503
|
] }),
|
|
2346
|
-
components && propsOpen === set.id ? /* @__PURE__ */
|
|
2347
|
-
/* @__PURE__ */
|
|
2504
|
+
components && propsOpen === set.id ? /* @__PURE__ */ jsx9("div", { "data-variant-properties": set.id, className: "ml-3 flex flex-col gap-1 border-l border-border py-1 pl-2", children: set.options.map((option) => /* @__PURE__ */ jsxs8("div", { "data-variant-option": option.name, className: "flex flex-col gap-0.5", children: [
|
|
2505
|
+
/* @__PURE__ */ jsx9(
|
|
2348
2506
|
InlineField,
|
|
2349
2507
|
{
|
|
2350
2508
|
value: option.name,
|
|
@@ -2352,7 +2510,7 @@ function CanvasComponentsPanel({
|
|
|
2352
2510
|
onCommit: (next) => report(components.renameVariantProperty(option.name, next, set.id))
|
|
2353
2511
|
}
|
|
2354
2512
|
),
|
|
2355
|
-
/* @__PURE__ */
|
|
2513
|
+
/* @__PURE__ */ jsx9("div", { className: "ml-2 flex flex-wrap gap-1", children: option.values.map((value) => /* @__PURE__ */ jsx9(
|
|
2356
2514
|
InlineField,
|
|
2357
2515
|
{
|
|
2358
2516
|
value,
|
|
@@ -2362,8 +2520,8 @@ function CanvasComponentsPanel({
|
|
|
2362
2520
|
value
|
|
2363
2521
|
)) })
|
|
2364
2522
|
] }, option.name)) }) : null,
|
|
2365
|
-
/* @__PURE__ */
|
|
2366
|
-
/* @__PURE__ */
|
|
2523
|
+
/* @__PURE__ */ jsx9("div", { className: "ml-3 flex flex-col border-l border-border pl-1", children: set.variants.map((v) => /* @__PURE__ */ jsxs8("div", { "data-variant-row": v.id, className: "flex flex-col", children: [
|
|
2524
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-1", children: [
|
|
2367
2525
|
item(
|
|
2368
2526
|
v.id,
|
|
2369
2527
|
v.name,
|
|
@@ -2374,7 +2532,7 @@ function CanvasComponentsPanel({
|
|
|
2374
2532
|
setMenuFor(v.id);
|
|
2375
2533
|
} : void 0
|
|
2376
2534
|
),
|
|
2377
|
-
components ? /* @__PURE__ */
|
|
2535
|
+
components ? /* @__PURE__ */ jsx9(
|
|
2378
2536
|
"button",
|
|
2379
2537
|
{
|
|
2380
2538
|
type: "button",
|
|
@@ -2388,8 +2546,8 @@ function CanvasComponentsPanel({
|
|
|
2388
2546
|
}
|
|
2389
2547
|
) : null
|
|
2390
2548
|
] }),
|
|
2391
|
-
components && menuFor === v.id ? /* @__PURE__ */
|
|
2392
|
-
/* @__PURE__ */
|
|
2549
|
+
components && menuFor === v.id ? /* @__PURE__ */ jsxs8("div", { role: "menu", "data-variant-menu": v.id, className: "ml-2 flex flex-col rounded border border-border bg-background p-1 shadow", children: [
|
|
2550
|
+
/* @__PURE__ */ jsx9(
|
|
2393
2551
|
"button",
|
|
2394
2552
|
{
|
|
2395
2553
|
type: "button",
|
|
@@ -2403,7 +2561,7 @@ function CanvasComponentsPanel({
|
|
|
2403
2561
|
children: "Edit values\u2026"
|
|
2404
2562
|
}
|
|
2405
2563
|
),
|
|
2406
|
-
/* @__PURE__ */
|
|
2564
|
+
/* @__PURE__ */ jsx9(
|
|
2407
2565
|
"button",
|
|
2408
2566
|
{
|
|
2409
2567
|
type: "button",
|
|
@@ -2417,7 +2575,7 @@ function CanvasComponentsPanel({
|
|
|
2417
2575
|
children: "Duplicate"
|
|
2418
2576
|
}
|
|
2419
2577
|
),
|
|
2420
|
-
/* @__PURE__ */
|
|
2578
|
+
/* @__PURE__ */ jsx9(
|
|
2421
2579
|
"button",
|
|
2422
2580
|
{
|
|
2423
2581
|
type: "button",
|
|
@@ -2434,7 +2592,7 @@ function CanvasComponentsPanel({
|
|
|
2434
2592
|
}
|
|
2435
2593
|
)
|
|
2436
2594
|
] }) : null,
|
|
2437
|
-
components && editing === v.id ? /* @__PURE__ */
|
|
2595
|
+
components && editing === v.id ? /* @__PURE__ */ jsxs8(
|
|
2438
2596
|
"form",
|
|
2439
2597
|
{
|
|
2440
2598
|
"data-variant-editor": v.id,
|
|
@@ -2448,9 +2606,9 @@ function CanvasComponentsPanel({
|
|
|
2448
2606
|
if (report(components.setVariantProperties(values, v.id))) setEditing(null);
|
|
2449
2607
|
},
|
|
2450
2608
|
children: [
|
|
2451
|
-
set.options.map((option) => /* @__PURE__ */
|
|
2452
|
-
/* @__PURE__ */
|
|
2453
|
-
/* @__PURE__ */
|
|
2609
|
+
set.options.map((option) => /* @__PURE__ */ jsxs8("label", { className: "flex items-center gap-2", children: [
|
|
2610
|
+
/* @__PURE__ */ jsx9("span", { className: "w-16 shrink-0 truncate text-muted-foreground", children: option.name }),
|
|
2611
|
+
/* @__PURE__ */ jsx9(
|
|
2454
2612
|
"input",
|
|
2455
2613
|
{
|
|
2456
2614
|
type: "text",
|
|
@@ -2461,9 +2619,9 @@ function CanvasComponentsPanel({
|
|
|
2461
2619
|
}
|
|
2462
2620
|
)
|
|
2463
2621
|
] }, option.name)),
|
|
2464
|
-
/* @__PURE__ */
|
|
2465
|
-
/* @__PURE__ */
|
|
2466
|
-
/* @__PURE__ */
|
|
2622
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex gap-1", children: [
|
|
2623
|
+
/* @__PURE__ */ jsx9("button", { type: "submit", className: "rounded border border-border px-2 py-0.5 hover:bg-muted", "data-action": "save-variant", children: "Save" }),
|
|
2624
|
+
/* @__PURE__ */ jsx9("button", { type: "button", className: "rounded px-2 py-0.5 hover:bg-muted", "data-action": "cancel-variant", onClick: () => setEditing(null), children: "Cancel" })
|
|
2467
2625
|
] })
|
|
2468
2626
|
]
|
|
2469
2627
|
}
|
|
@@ -2471,7 +2629,7 @@ function CanvasComponentsPanel({
|
|
|
2471
2629
|
] }, v.id)) })
|
|
2472
2630
|
] }, set.id)),
|
|
2473
2631
|
lone.map((c) => item(c.id, c.name, c.instanceCount, { "data-kind": "component" })),
|
|
2474
|
-
all.length === 0 ? /* @__PURE__ */
|
|
2632
|
+
all.length === 0 ? /* @__PURE__ */ jsx9("p", { className: "text-muted-foreground", children: "No components yet. Select a frame and choose Create Component." }) : null
|
|
2475
2633
|
] });
|
|
2476
2634
|
}
|
|
2477
2635
|
function CanvasInstanceInspector({
|
|
@@ -2489,28 +2647,28 @@ function CanvasInstanceInspector({
|
|
|
2489
2647
|
const setProp = (name, value) => report(components.setInstanceProperties({ [name]: value }, [info.id]));
|
|
2490
2648
|
const allComponents = listCanvasComponents(nodes).components;
|
|
2491
2649
|
const linked = info.status === "linked";
|
|
2492
|
-
const
|
|
2493
|
-
return /* @__PURE__ */
|
|
2494
|
-
/* @__PURE__ */
|
|
2495
|
-
/* @__PURE__ */
|
|
2496
|
-
info.nested ? /* @__PURE__ */
|
|
2650
|
+
const btn2 = "rounded border border-border px-2 py-0.5 text-xs hover:bg-muted disabled:opacity-40";
|
|
2651
|
+
return /* @__PURE__ */ jsxs8("div", { "data-instance-inspector": "", "data-instance-id": info.id, className: `flex flex-col gap-2 text-xs text-foreground ${className}`, children: [
|
|
2652
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex items-center justify-between gap-2", children: [
|
|
2653
|
+
/* @__PURE__ */ jsx9("span", { className: "truncate font-medium", "data-instance-main": "", children: linked ? info.componentName : "Main component missing" }),
|
|
2654
|
+
info.nested ? /* @__PURE__ */ jsx9("span", { className: "text-muted-foreground", children: "Nested" }) : null
|
|
2497
2655
|
] }),
|
|
2498
|
-
info.variantOptions.map((option) => /* @__PURE__ */
|
|
2499
|
-
/* @__PURE__ */
|
|
2500
|
-
/* @__PURE__ */
|
|
2656
|
+
info.variantOptions.map((option) => /* @__PURE__ */ jsxs8("label", { className: "flex items-center gap-2", "data-variant-property": option.name, children: [
|
|
2657
|
+
/* @__PURE__ */ jsx9("span", { className: "w-24 shrink-0 truncate text-muted-foreground", children: option.name }),
|
|
2658
|
+
/* @__PURE__ */ jsx9(
|
|
2501
2659
|
"select",
|
|
2502
2660
|
{
|
|
2503
2661
|
"aria-label": `${option.name} variant`,
|
|
2504
2662
|
className: "min-w-0 flex-1 rounded border border-border bg-background px-1 py-0.5 text-xs",
|
|
2505
2663
|
value: info.variant[option.name] ?? "",
|
|
2506
2664
|
onChange: (e) => setProp(option.name, e.currentTarget.value),
|
|
2507
|
-
children: option.values.map((v) => /* @__PURE__ */
|
|
2665
|
+
children: option.values.map((v) => /* @__PURE__ */ jsx9("option", { value: v, children: v }, v))
|
|
2508
2666
|
}
|
|
2509
2667
|
)
|
|
2510
2668
|
] }, option.name)),
|
|
2511
|
-
info.properties.map((p) => /* @__PURE__ */
|
|
2512
|
-
/* @__PURE__ */
|
|
2513
|
-
p.type === "boolean" ? /* @__PURE__ */
|
|
2669
|
+
info.properties.map((p) => /* @__PURE__ */ jsxs8("label", { className: "flex items-center gap-2", "data-component-property": p.name, children: [
|
|
2670
|
+
/* @__PURE__ */ jsx9("span", { className: "w-24 shrink-0 truncate text-muted-foreground", children: p.name }),
|
|
2671
|
+
p.type === "boolean" ? /* @__PURE__ */ jsx9("input", { type: "checkbox", "aria-label": p.name, checked: p.value === true, onChange: (e) => setProp(p.name, e.currentTarget.checked) }) : p.type === "text" ? /* @__PURE__ */ jsx9(
|
|
2514
2672
|
"input",
|
|
2515
2673
|
{
|
|
2516
2674
|
type: "text",
|
|
@@ -2525,22 +2683,22 @@ function CanvasInstanceInspector({
|
|
|
2525
2683
|
}
|
|
2526
2684
|
},
|
|
2527
2685
|
String(p.value)
|
|
2528
|
-
) : /* @__PURE__ */
|
|
2686
|
+
) : /* @__PURE__ */ jsx9(
|
|
2529
2687
|
"select",
|
|
2530
2688
|
{
|
|
2531
2689
|
"aria-label": p.name,
|
|
2532
2690
|
className: "min-w-0 flex-1 rounded border border-border bg-background px-1 py-0.5 text-xs",
|
|
2533
2691
|
value: String(p.value),
|
|
2534
2692
|
onChange: (e) => setProp(p.name, e.currentTarget.value),
|
|
2535
|
-
children: allComponents.filter((c) => !p.preferred?.length || p.preferred.includes(c.id) || c.id === p.value).map((c) => /* @__PURE__ */
|
|
2693
|
+
children: allComponents.filter((c) => !p.preferred?.length || p.preferred.includes(c.id) || c.id === p.value).map((c) => /* @__PURE__ */ jsx9("option", { value: c.id, children: c.name }, c.id))
|
|
2536
2694
|
}
|
|
2537
2695
|
)
|
|
2538
2696
|
] }, p.name)),
|
|
2539
|
-
info.overrides.length ? /* @__PURE__ */
|
|
2540
|
-
/* @__PURE__ */
|
|
2541
|
-
info.overrides.map((o) => /* @__PURE__ */
|
|
2542
|
-
/* @__PURE__ */
|
|
2543
|
-
o.groups.map((g) => /* @__PURE__ */
|
|
2697
|
+
info.overrides.length ? /* @__PURE__ */ jsxs8("div", { className: "flex flex-col gap-1", "data-instance-overrides": "", children: [
|
|
2698
|
+
/* @__PURE__ */ jsx9("span", { className: "text-muted-foreground", children: "Overrides" }),
|
|
2699
|
+
info.overrides.map((o) => /* @__PURE__ */ jsxs8("div", { className: "flex flex-wrap items-center gap-1", "data-override-layer": o.id, children: [
|
|
2700
|
+
/* @__PURE__ */ jsx9("span", { className: "mr-1 truncate", children: o.name }),
|
|
2701
|
+
o.groups.map((g) => /* @__PURE__ */ jsxs8(
|
|
2544
2702
|
"button",
|
|
2545
2703
|
{
|
|
2546
2704
|
type: "button",
|
|
@@ -2557,27 +2715,27 @@ function CanvasInstanceInspector({
|
|
|
2557
2715
|
))
|
|
2558
2716
|
] }, o.id))
|
|
2559
2717
|
] }) : null,
|
|
2560
|
-
/* @__PURE__ */
|
|
2561
|
-
linked ? /* @__PURE__ */
|
|
2562
|
-
/* @__PURE__ */
|
|
2563
|
-
/* @__PURE__ */
|
|
2564
|
-
/* @__PURE__ */
|
|
2718
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex flex-wrap gap-1", children: [
|
|
2719
|
+
linked ? /* @__PURE__ */ jsxs8(Fragment2, { children: [
|
|
2720
|
+
/* @__PURE__ */ jsx9("button", { type: "button", className: btn2, "data-action": "reset", onClick: () => report(components.resetOverrides(info.id)), children: "Reset all" }),
|
|
2721
|
+
/* @__PURE__ */ jsx9("button", { type: "button", className: btn2, "data-action": "go-to-main", onClick: () => components.goToMainComponent(info.id), children: "Go to main" }),
|
|
2722
|
+
/* @__PURE__ */ jsx9(
|
|
2565
2723
|
"button",
|
|
2566
2724
|
{
|
|
2567
2725
|
type: "button",
|
|
2568
|
-
className:
|
|
2726
|
+
className: btn2,
|
|
2569
2727
|
"data-action": "push",
|
|
2570
2728
|
disabled: info.overrides.length === 0,
|
|
2571
2729
|
onClick: () => report(components.pushOverrides(info.rootId)),
|
|
2572
2730
|
children: "Push changes"
|
|
2573
2731
|
}
|
|
2574
2732
|
)
|
|
2575
|
-
] }) : /* @__PURE__ */
|
|
2576
|
-
/* @__PURE__ */
|
|
2733
|
+
] }) : /* @__PURE__ */ jsx9("button", { type: "button", className: btn2, "data-action": "restore", onClick: () => report(components.restoreMainComponent(info.rootId)), children: "Restore main component" }),
|
|
2734
|
+
/* @__PURE__ */ jsx9(
|
|
2577
2735
|
"button",
|
|
2578
2736
|
{
|
|
2579
2737
|
type: "button",
|
|
2580
|
-
className:
|
|
2738
|
+
className: btn2,
|
|
2581
2739
|
"data-action": "detach",
|
|
2582
2740
|
disabled: info.nested,
|
|
2583
2741
|
title: info.nested ? "Detach the outer instance first" : void 0,
|
|
@@ -2635,6 +2793,7 @@ import {
|
|
|
2635
2793
|
isBrushedShape as isBrushedShape2,
|
|
2636
2794
|
listCanvasBrushes as listCanvasBrushes2,
|
|
2637
2795
|
validateCanvasBrush,
|
|
2796
|
+
validateCanvasBrushPaint,
|
|
2638
2797
|
renderShapeBrushstroke as renderShapeBrushstroke2,
|
|
2639
2798
|
getBrushedShapeSvg,
|
|
2640
2799
|
loadCanvasBrushstrokeRenderer,
|
|
@@ -2652,7 +2811,7 @@ import {
|
|
|
2652
2811
|
// src/canvas/MermaidFamilyScene.tsx
|
|
2653
2812
|
import { useId } from "react";
|
|
2654
2813
|
import { diagramTextBaseline } from "@pixerate/editor/canvas";
|
|
2655
|
-
import { jsx as
|
|
2814
|
+
import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2656
2815
|
function MermaidFamilyScene({
|
|
2657
2816
|
scene,
|
|
2658
2817
|
padding = 16,
|
|
@@ -2683,7 +2842,7 @@ function MermaidFamilyScene({
|
|
|
2683
2842
|
cursor: "pointer"
|
|
2684
2843
|
} : { pointerEvents: "none" };
|
|
2685
2844
|
const stroke = (mark) => mark.selected ? { stroke: selectionColor, strokeWidth: Math.max(2, mark.strokeWidth ?? 0) } : { stroke: mark.stroke, strokeWidth: mark.strokeWidth };
|
|
2686
|
-
return /* @__PURE__ */
|
|
2845
|
+
return /* @__PURE__ */ jsxs9(
|
|
2687
2846
|
"svg",
|
|
2688
2847
|
{
|
|
2689
2848
|
className: `pixerate-diagram-scene ${className}`.trim(),
|
|
@@ -2696,15 +2855,15 @@ function MermaidFamilyScene({
|
|
|
2696
2855
|
style: { display: "block", maxWidth: "100%", height: "auto", overflow: "visible", ...style },
|
|
2697
2856
|
onClick: interactive ? (event) => onSelect?.(null, event) : void 0,
|
|
2698
2857
|
children: [
|
|
2699
|
-
/* @__PURE__ */
|
|
2700
|
-
/* @__PURE__ */
|
|
2701
|
-
/* @__PURE__ */
|
|
2858
|
+
/* @__PURE__ */ jsxs9("defs", { children: [
|
|
2859
|
+
/* @__PURE__ */ jsx10("marker", { id: `${uid}-arrowclosed`, viewBox: "0 0 10 10", refX: "9", refY: "5", markerWidth: "8", markerHeight: "8", orient: "auto-start-reverse", children: /* @__PURE__ */ jsx10("path", { d: "M0,0 L10,5 L0,10 Z", style: { fill: markerColor } }) }),
|
|
2860
|
+
/* @__PURE__ */ jsx10("marker", { id: `${uid}-arrow`, viewBox: "0 0 10 10", refX: "9", refY: "5", markerWidth: "8", markerHeight: "8", orient: "auto-start-reverse", children: /* @__PURE__ */ jsx10("path", { d: "M0,0 L10,5 L0,10", style: { fill: "none", stroke: markerColor, strokeWidth: 1.5 } }) })
|
|
2702
2861
|
] }),
|
|
2703
2862
|
scene.marks.map((mark) => {
|
|
2704
2863
|
const common = { "data-role": mark.role, "data-target": mark.target, "data-selected": mark.selected ? "" : void 0, opacity: mark.opacity, ...handlers(mark) };
|
|
2705
2864
|
switch (mark.kind) {
|
|
2706
2865
|
case "rect":
|
|
2707
|
-
return /* @__PURE__ */
|
|
2866
|
+
return /* @__PURE__ */ jsx10(
|
|
2708
2867
|
"rect",
|
|
2709
2868
|
{
|
|
2710
2869
|
...common,
|
|
@@ -2719,9 +2878,9 @@ function MermaidFamilyScene({
|
|
|
2719
2878
|
mark.key
|
|
2720
2879
|
);
|
|
2721
2880
|
case "circle":
|
|
2722
|
-
return /* @__PURE__ */
|
|
2881
|
+
return /* @__PURE__ */ jsx10("circle", { ...common, cx: mark.cx, cy: mark.cy, r: mark.r, style: { fill: mark.fill, ...stroke(mark) } }, mark.key);
|
|
2723
2882
|
case "line":
|
|
2724
|
-
return /* @__PURE__ */
|
|
2883
|
+
return /* @__PURE__ */ jsx10(
|
|
2725
2884
|
"line",
|
|
2726
2885
|
{
|
|
2727
2886
|
...common,
|
|
@@ -2737,7 +2896,7 @@ function MermaidFamilyScene({
|
|
|
2737
2896
|
mark.key
|
|
2738
2897
|
);
|
|
2739
2898
|
case "path":
|
|
2740
|
-
return /* @__PURE__ */
|
|
2899
|
+
return /* @__PURE__ */ jsx10(
|
|
2741
2900
|
"path",
|
|
2742
2901
|
{
|
|
2743
2902
|
...common,
|
|
@@ -2751,7 +2910,7 @@ function MermaidFamilyScene({
|
|
|
2751
2910
|
mark.key
|
|
2752
2911
|
);
|
|
2753
2912
|
case "text":
|
|
2754
|
-
return /* @__PURE__ */
|
|
2913
|
+
return /* @__PURE__ */ jsx10(
|
|
2755
2914
|
"text",
|
|
2756
2915
|
{
|
|
2757
2916
|
...common,
|
|
@@ -2779,7 +2938,7 @@ function MermaidFamilyScene({
|
|
|
2779
2938
|
}
|
|
2780
2939
|
|
|
2781
2940
|
// src/canvas/useMermaidDiagram.ts
|
|
2782
|
-
import { useEffect as
|
|
2941
|
+
import { useEffect as useEffect12, useMemo as useMemo11, useRef as useRef17, useState as useState10, useSyncExternalStore as useSyncExternalStore4 } from "react";
|
|
2783
2942
|
import {
|
|
2784
2943
|
DiagramController
|
|
2785
2944
|
} from "@pixerate/editor/diagram";
|
|
@@ -2797,7 +2956,7 @@ function useDiagramState(controller) {
|
|
|
2797
2956
|
return useSyncExternalStore4(controller.subscribe, controller.getState, controller.getState);
|
|
2798
2957
|
}
|
|
2799
2958
|
function useMermaidDiagram(controllerOrOptions = {}, view = {}) {
|
|
2800
|
-
const own =
|
|
2959
|
+
const own = useRef17(null);
|
|
2801
2960
|
let controller;
|
|
2802
2961
|
if (controllerOrOptions instanceof DiagramController) controller = controllerOrOptions;
|
|
2803
2962
|
else {
|
|
@@ -2807,19 +2966,19 @@ function useMermaidDiagram(controllerOrOptions = {}, view = {}) {
|
|
|
2807
2966
|
const layoutOptions = (controllerOrOptions instanceof DiagramController ? void 0 : controllerOrOptions.layoutOptions) ?? view.layoutOptions;
|
|
2808
2967
|
const sceneTheme = (controllerOrOptions instanceof DiagramController ? void 0 : controllerOrOptions.sceneTheme) ?? view.sceneTheme;
|
|
2809
2968
|
const state = useDiagramState(controller);
|
|
2810
|
-
const canvas =
|
|
2969
|
+
const canvas = useMemo11(
|
|
2811
2970
|
() => mermaidToCanvas(state.document, { ...layoutOptions, editable: state.editable }),
|
|
2812
2971
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2813
2972
|
[state.document, state.editable]
|
|
2814
2973
|
);
|
|
2815
|
-
const scene =
|
|
2974
|
+
const scene = useMemo11(
|
|
2816
2975
|
() => state.document.tier === "editable" ? familySceneFromLayout(state.document.family, state.document.graph, canvas.layout, { theme: { ...CSS_VARIABLE_DIAGRAM_SCENE_THEME, ...sceneTheme }, selection: state.selection }) : null,
|
|
2817
2976
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2818
2977
|
[state.document, canvas.layout, state.selection]
|
|
2819
2978
|
);
|
|
2820
|
-
const layoutRef =
|
|
2979
|
+
const layoutRef = useRef17(canvas.layout);
|
|
2821
2980
|
layoutRef.current = canvas.layout;
|
|
2822
|
-
const actions =
|
|
2981
|
+
const actions = useMemo11(
|
|
2823
2982
|
() => ({
|
|
2824
2983
|
apply: (ops, label) => controller.apply(ops, label),
|
|
2825
2984
|
load: (source, options) => controller.load(source, options),
|
|
@@ -2856,13 +3015,13 @@ function useMermaidDiagram(controllerOrOptions = {}, view = {}) {
|
|
|
2856
3015
|
}
|
|
2857
3016
|
function useMermaidStream(source, options = {}) {
|
|
2858
3017
|
const { complete = false, duration = 300, ...layoutOptions } = options;
|
|
2859
|
-
const stream =
|
|
3018
|
+
const stream = useRef17(null);
|
|
2860
3019
|
if (!stream.current) stream.current = new DiagramStream(layoutOptions);
|
|
2861
|
-
const result =
|
|
2862
|
-
const [shown, setShown] =
|
|
2863
|
-
const shownRef =
|
|
3020
|
+
const result = useMemo11(() => stream.current.update(source, complete), [source, complete]);
|
|
3021
|
+
const [shown, setShown] = useState10({ layout: result.layout, settled: true });
|
|
3022
|
+
const shownRef = useRef17(shown.layout);
|
|
2864
3023
|
shownRef.current = shown.layout;
|
|
2865
|
-
|
|
3024
|
+
useEffect12(() => {
|
|
2866
3025
|
const target = result.layout;
|
|
2867
3026
|
if (!target) return setShown({ layout: null, settled: true });
|
|
2868
3027
|
const from = shownRef.current;
|
|
@@ -2879,7 +3038,7 @@ function useMermaidStream(source, options = {}) {
|
|
|
2879
3038
|
return () => cancelAnimationFrame(frame);
|
|
2880
3039
|
}, [result.layout, duration]);
|
|
2881
3040
|
const doc = result.document.tier === "editable" ? result.document : null;
|
|
2882
|
-
const canvas =
|
|
3041
|
+
const canvas = useMemo11(() => {
|
|
2883
3042
|
if (!doc || !shown.layout) return { nodes: [], edges: [] };
|
|
2884
3043
|
const placed = new Set(Object.keys(shown.layout.positions));
|
|
2885
3044
|
const graph = {
|
|
@@ -2895,7 +3054,7 @@ function useMermaidStream(source, options = {}) {
|
|
|
2895
3054
|
|
|
2896
3055
|
// src/canvas/MermaidDiagramNode.tsx
|
|
2897
3056
|
import { MERMAID_SHAPE_PAINT, mermaidLabelLines, mermaidNodeMembers, mermaidNodePaint, mermaidShapePaths } from "@pixerate/editor/canvas";
|
|
2898
|
-
import { jsx as
|
|
3057
|
+
import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2899
3058
|
function mermaidNodeStyle(styles = {}, selected = false) {
|
|
2900
3059
|
const paint = mermaidNodePaint(styles, selected);
|
|
2901
3060
|
const { color, "stroke-width": strokeWidth, "stroke-dasharray": strokeDasharray, ...vars } = paint;
|
|
@@ -2905,7 +3064,7 @@ function MermaidDiagramNode({ data, width = 160, height = 56, selected, classNam
|
|
|
2905
3064
|
const node = data.node;
|
|
2906
3065
|
if (!node) return null;
|
|
2907
3066
|
const members = mermaidNodeMembers(node.data);
|
|
2908
|
-
return /* @__PURE__ */
|
|
3067
|
+
return /* @__PURE__ */ jsxs10(
|
|
2909
3068
|
"div",
|
|
2910
3069
|
{
|
|
2911
3070
|
className: `pixerate-diagram-node ${className}`.trim(),
|
|
@@ -2913,14 +3072,14 @@ function MermaidDiagramNode({ data, width = 160, height = 56, selected, classNam
|
|
|
2913
3072
|
"data-selected": selected ? "true" : void 0,
|
|
2914
3073
|
style: { position: "relative", width: "100%", height: "100%", ...mermaidNodeStyle(data.resolvedStyles, selected) },
|
|
2915
3074
|
children: [
|
|
2916
|
-
/* @__PURE__ */
|
|
2917
|
-
/* @__PURE__ */
|
|
3075
|
+
/* @__PURE__ */ jsx11("svg", { viewBox: `0 0 ${width} ${height}`, preserveAspectRatio: "none", width: "100%", height: "100%", style: { position: "absolute", inset: 0, overflow: "visible" }, "aria-hidden": "true", children: mermaidShapePaths(node.shape, width, height).map((path, i) => /* @__PURE__ */ jsx11("path", { d: path.d, style: { ...MERMAID_SHAPE_PAINT[path.paint], vectorEffect: "non-scaling-stroke" } }, i)) }),
|
|
3076
|
+
/* @__PURE__ */ jsxs10(
|
|
2918
3077
|
"div",
|
|
2919
3078
|
{
|
|
2920
3079
|
style: { position: "relative", display: "flex", flexDirection: "column", alignItems: "center", justifyContent: members.length ? "flex-start" : "center", height: "100%", padding: "6px 10px", boxSizing: "border-box", fontSize: 13, lineHeight: 1.3, textAlign: "center", pointerEvents: "none" },
|
|
2921
3080
|
children: [
|
|
2922
|
-
mermaidLabelLines(node.label).map((line, i) => /* @__PURE__ */
|
|
2923
|
-
members.length > 0 && /* @__PURE__ */
|
|
3081
|
+
mermaidLabelLines(node.label).map((line, i) => /* @__PURE__ */ jsx11("span", { style: { fontWeight: members.length ? 600 : void 0 }, children: line }, i)),
|
|
3082
|
+
members.length > 0 && /* @__PURE__ */ jsx11("div", { style: { alignSelf: "stretch", marginTop: 4, paddingTop: 4, borderTop: "1px solid var(--pixerate-diagram-node-border)", textAlign: "left", fontSize: 12 }, children: members.map((m, i) => /* @__PURE__ */ jsx11("div", { children: m }, i)) })
|
|
2924
3083
|
]
|
|
2925
3084
|
}
|
|
2926
3085
|
),
|
|
@@ -2932,7 +3091,7 @@ function MermaidDiagramNode({ data, width = 160, height = 56, selected, classNam
|
|
|
2932
3091
|
function MermaidDiagramGroup({ data, selected, className = "", children }) {
|
|
2933
3092
|
const group = data.group;
|
|
2934
3093
|
if (!group) return null;
|
|
2935
|
-
return /* @__PURE__ */
|
|
3094
|
+
return /* @__PURE__ */ jsxs10(
|
|
2936
3095
|
"div",
|
|
2937
3096
|
{
|
|
2938
3097
|
className: `pixerate-diagram-group ${className}`.trim(),
|
|
@@ -2947,7 +3106,7 @@ function MermaidDiagramGroup({ data, selected, className = "", children }) {
|
|
|
2947
3106
|
color: data.resolvedStyles?.color ?? "var(--muted-foreground, #475569)"
|
|
2948
3107
|
},
|
|
2949
3108
|
children: [
|
|
2950
|
-
/* @__PURE__ */
|
|
3109
|
+
/* @__PURE__ */ jsx11("div", { style: { padding: "6px 10px", fontSize: 12, fontWeight: 600 }, children: mermaidLabelLines(group.label).join(" ") }),
|
|
2951
3110
|
children
|
|
2952
3111
|
]
|
|
2953
3112
|
}
|
|
@@ -2955,29 +3114,29 @@ function MermaidDiagramGroup({ data, selected, className = "", children }) {
|
|
|
2955
3114
|
}
|
|
2956
3115
|
|
|
2957
3116
|
// src/canvas/MermaidThumbnail.tsx
|
|
2958
|
-
import { useMemo as
|
|
3117
|
+
import { useMemo as useMemo12 } from "react";
|
|
2959
3118
|
import { parseMermaid } from "@pixerate/editor/diagram";
|
|
2960
3119
|
import { mermaidThumbnailSvg } from "@pixerate/editor/canvas";
|
|
2961
|
-
import { Fragment as
|
|
3120
|
+
import { Fragment as Fragment3, jsx as jsx12 } from "react/jsx-runtime";
|
|
2962
3121
|
function MermaidThumbnail({ source, className = "", fallback = null, ...options }) {
|
|
2963
|
-
const doc =
|
|
3122
|
+
const doc = useMemo12(() => typeof source === "string" ? parseMermaid(source) : source, [source]);
|
|
2964
3123
|
const key = JSON.stringify(options);
|
|
2965
|
-
const drawn =
|
|
3124
|
+
const drawn = useMemo12(
|
|
2966
3125
|
() => doc.tier === "editable" && doc.graph.nodes.length ? mermaidThumbnailSvg(doc, options) : null,
|
|
2967
3126
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2968
3127
|
[doc, key]
|
|
2969
3128
|
);
|
|
2970
|
-
if (!drawn) return /* @__PURE__ */
|
|
2971
|
-
return /* @__PURE__ */
|
|
3129
|
+
if (!drawn) return /* @__PURE__ */ jsx12(Fragment3, { children: fallback });
|
|
3130
|
+
return /* @__PURE__ */ jsx12("span", { className: `pixerate-diagram-thumbnail ${className}`.trim(), style: { display: "inline-block", lineHeight: 0 }, dangerouslySetInnerHTML: { __html: drawn.svg } });
|
|
2972
3131
|
}
|
|
2973
3132
|
|
|
2974
3133
|
// src/canvas/useDiagramDirector.ts
|
|
2975
|
-
import { useRef as
|
|
3134
|
+
import { useRef as useRef18, useSyncExternalStore as useSyncExternalStore5 } from "react";
|
|
2976
3135
|
import { DiagramDirector, PresenceStore } from "@pixerate/editor/diagram";
|
|
2977
3136
|
function useDiagramDirector(controller, options) {
|
|
2978
|
-
const placement =
|
|
3137
|
+
const placement = useRef18(options.placement);
|
|
2979
3138
|
placement.current = options.placement;
|
|
2980
|
-
const ref =
|
|
3139
|
+
const ref = useRef18(null);
|
|
2981
3140
|
if (!ref.current) {
|
|
2982
3141
|
const presence = new PresenceStore();
|
|
2983
3142
|
ref.current = {
|
|
@@ -2992,13 +3151,13 @@ function usePresenceState(presence) {
|
|
|
2992
3151
|
}
|
|
2993
3152
|
|
|
2994
3153
|
// src/canvas/DiagramPresenceLayer.tsx
|
|
2995
|
-
import { jsx as
|
|
3154
|
+
import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2996
3155
|
function DiagramPresenceLayer({ presence, viewport, className = "" }) {
|
|
2997
3156
|
const { actors } = usePresenceState(presence);
|
|
2998
3157
|
if (!actors.length) return null;
|
|
2999
|
-
return /* @__PURE__ */
|
|
3000
|
-
/* @__PURE__ */
|
|
3001
|
-
/* @__PURE__ */
|
|
3158
|
+
return /* @__PURE__ */ jsx13("div", { className: `pixerate-diagram-presence ${className}`.trim(), "aria-hidden": "true", style: { position: "absolute", inset: 0, pointerEvents: "none", overflow: "hidden", zIndex: 50 }, children: actors.map((a) => /* @__PURE__ */ jsxs11("div", { "data-actor": a.id, style: { position: "absolute", left: 0, top: 0, transform: `translate(${a.x * viewport.zoom + viewport.x}px, ${a.y * viewport.zoom + viewport.y}px)` }, children: [
|
|
3159
|
+
/* @__PURE__ */ jsx13("svg", { width: "18", height: "20", viewBox: "0 0 12 18", style: { display: "block", transform: a.pressed ? "scale(0.85)" : void 0, transformOrigin: "0 0" }, children: /* @__PURE__ */ jsx13("path", { d: "M0,0 L0,14 L4,10.5 L7,17 L9.5,16 L6.5,9.5 L11.5,9.5 Z", style: { fill: a.color, stroke: "#ffffff", strokeWidth: 1 } }) }),
|
|
3160
|
+
/* @__PURE__ */ jsx13("span", { style: { position: "absolute", left: 14, top: 16, whiteSpace: "nowrap", borderRadius: 4, padding: "1px 6px", fontSize: 11, fontWeight: 600, color: "#ffffff", background: a.color }, children: a.message ?? a.name })
|
|
3002
3161
|
] }, a.id)) });
|
|
3003
3162
|
}
|
|
3004
3163
|
export {
|
|
@@ -3021,8 +3180,11 @@ export {
|
|
|
3021
3180
|
CUBIC_BEZIER_PRESETS,
|
|
3022
3181
|
CanvasComponentsPanel,
|
|
3023
3182
|
CanvasDrawLayer,
|
|
3183
|
+
CanvasEffectsPanel,
|
|
3184
|
+
CanvasEffectsProvider,
|
|
3024
3185
|
CanvasGuidesLayer,
|
|
3025
3186
|
CanvasInstanceInspector,
|
|
3187
|
+
CanvasNodeEffectLayer,
|
|
3026
3188
|
CanvasScenesStore2 as CanvasScenesStore,
|
|
3027
3189
|
DEFAULT_ARRANGE_SHORTCUTS,
|
|
3028
3190
|
DiagramPresenceLayer,
|
|
@@ -3196,7 +3358,7 @@ export {
|
|
|
3196
3358
|
isLocked,
|
|
3197
3359
|
isMeasureModifierHeld2 as isMeasureModifierHeld,
|
|
3198
3360
|
isNodeAnimated,
|
|
3199
|
-
|
|
3361
|
+
isShapeDescription3 as isShapeDescription,
|
|
3200
3362
|
isShapeNode,
|
|
3201
3363
|
isStraightCubic,
|
|
3202
3364
|
isValidCanvasNode,
|
|
@@ -3337,6 +3499,9 @@ export {
|
|
|
3337
3499
|
useCanvasComponents,
|
|
3338
3500
|
useCanvasDocking,
|
|
3339
3501
|
useCanvasDraw,
|
|
3502
|
+
useCanvasEffects,
|
|
3503
|
+
useCanvasEffectsProviderContext,
|
|
3504
|
+
useCanvasEffectsTools,
|
|
3340
3505
|
useCanvasExplosion,
|
|
3341
3506
|
useCanvasGraph,
|
|
3342
3507
|
useCanvasLayout,
|
|
@@ -3352,6 +3517,7 @@ export {
|
|
|
3352
3517
|
useShapeBrushstroke,
|
|
3353
3518
|
useStreamingCanvas,
|
|
3354
3519
|
validateCanvasBrush,
|
|
3520
|
+
validateCanvasBrushPaint,
|
|
3355
3521
|
withNodeAnimation,
|
|
3356
3522
|
withStyleSize,
|
|
3357
3523
|
wouldCreateComponentCycle,
|