canvu-react 0.3.17 → 0.3.19
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/chatbot.d.cts +1 -1
- package/dist/chatbot.d.ts +1 -1
- package/dist/index.cjs +87 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37 -1
- package/dist/index.d.ts +37 -1
- package/dist/index.js +79 -1
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +2445 -1710
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +326 -35
- package/dist/react.d.ts +326 -35
- package/dist/react.js +2447 -1712
- package/dist/react.js.map +1 -1
- package/dist/realtime.d.cts +2 -2
- package/dist/realtime.d.ts +2 -2
- package/dist/{types-CTyASYIm.d.cts → types-7kfWcm0L.d.cts} +33 -154
- package/dist/{types-UvUy2Eed.d.ts → types-C4k_AMvi.d.ts} +33 -154
- package/package.json +16 -1
package/dist/react.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import getStroke from 'perfect-freehand';
|
|
2
|
-
import { createContext, forwardRef, useRef, useState, useCallback, useMemo, useId, useEffect, useImperativeHandle, useLayoutEffect,
|
|
3
|
-
import {
|
|
2
|
+
import { createContext, forwardRef, useRef, useState, useCallback, useMemo, useId, useEffect, useImperativeHandle, useContext, useLayoutEffect, Children, isValidElement } from 'react';
|
|
3
|
+
import { useSensors, useSensor, PointerSensor, DndContext } from '@dnd-kit/core';
|
|
4
|
+
import { SortableContext, verticalListSortingStrategy, useSortable, arrayMove } from '@dnd-kit/sortable';
|
|
5
|
+
import { CSS } from '@dnd-kit/utilities';
|
|
6
|
+
import { Undo2, Redo2, Shapes, ChevronDown, Hand, MousePointer2, Square, Circle, Minus, ArrowUpRight, PenLine, Highlighter, Eraser, Type, Image as Image$1, Lock, LockOpen, Images, ChevronRight, GripVertical, Copy, RotateCw, Trash2 } from 'lucide-react';
|
|
4
7
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
8
|
import { createPortal } from 'react-dom';
|
|
6
9
|
|
|
@@ -1503,6 +1506,517 @@ function useCanvuChromeContext() {
|
|
|
1503
1506
|
return useContext(CanvuChromeContext);
|
|
1504
1507
|
}
|
|
1505
1508
|
|
|
1509
|
+
// src/scene/clone-item.ts
|
|
1510
|
+
init_shape_builders();
|
|
1511
|
+
function cloneVectorSceneItemWithNewId(item) {
|
|
1512
|
+
const id = createShapeId();
|
|
1513
|
+
const copy = JSON.parse(JSON.stringify(item));
|
|
1514
|
+
let next = { ...copy, id };
|
|
1515
|
+
if (next.toolKind === "arrow" && next.line) {
|
|
1516
|
+
next = {
|
|
1517
|
+
...next,
|
|
1518
|
+
childrenSvg: buildArrowSvg(id, next.line, resolveStrokeStyle(next))
|
|
1519
|
+
};
|
|
1520
|
+
}
|
|
1521
|
+
if (next.toolKind === "text" && next.text !== void 0) {
|
|
1522
|
+
return rebuildItemSvg(next);
|
|
1523
|
+
}
|
|
1524
|
+
if (next.toolKind === "custom" && next.customInnerSvg && next.customIntrinsicSize) {
|
|
1525
|
+
return rebuildItemSvg(next);
|
|
1526
|
+
}
|
|
1527
|
+
return next;
|
|
1528
|
+
}
|
|
1529
|
+
function cloneVectorSceneItemsWithNewIds(items) {
|
|
1530
|
+
return items.map(cloneVectorSceneItemWithNewId);
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
// src/scene/managed-images.ts
|
|
1534
|
+
var MANAGED_KEY = "managed";
|
|
1535
|
+
var STACK_GAP_WORLD = 16;
|
|
1536
|
+
function isManagedImage(item) {
|
|
1537
|
+
const data = item.pluginData;
|
|
1538
|
+
return data != null && data[MANAGED_KEY] === true;
|
|
1539
|
+
}
|
|
1540
|
+
function markImageAsManaged(item) {
|
|
1541
|
+
return {
|
|
1542
|
+
...item,
|
|
1543
|
+
locked: true,
|
|
1544
|
+
pluginData: { ...item.pluginData ?? {}, [MANAGED_KEY]: true }
|
|
1545
|
+
};
|
|
1546
|
+
}
|
|
1547
|
+
function restackManagedImages(items) {
|
|
1548
|
+
let anchor;
|
|
1549
|
+
for (const item of items) {
|
|
1550
|
+
if (!isManagedImage(item)) continue;
|
|
1551
|
+
if (!anchor || item.bounds.y < anchor.bounds.y) anchor = item;
|
|
1552
|
+
}
|
|
1553
|
+
if (!anchor) return [...items];
|
|
1554
|
+
const anchorCenterX = anchor.bounds.x + anchor.bounds.width / 2;
|
|
1555
|
+
const anchorTopY = anchor.bounds.y;
|
|
1556
|
+
let cursorY = anchorTopY;
|
|
1557
|
+
return items.map((item) => {
|
|
1558
|
+
if (!isManagedImage(item)) return item;
|
|
1559
|
+
const newX = anchorCenterX - item.bounds.width / 2;
|
|
1560
|
+
const newY = cursorY;
|
|
1561
|
+
cursorY = newY + item.bounds.height + STACK_GAP_WORLD;
|
|
1562
|
+
if (item.bounds.x === newX && item.bounds.y === newY) return item;
|
|
1563
|
+
return {
|
|
1564
|
+
...item,
|
|
1565
|
+
x: newX,
|
|
1566
|
+
y: newY,
|
|
1567
|
+
bounds: { ...item.bounds, x: newX, y: newY }
|
|
1568
|
+
};
|
|
1569
|
+
});
|
|
1570
|
+
}
|
|
1571
|
+
function copyManagedImage(items, id) {
|
|
1572
|
+
const idx = items.findIndex((i) => i.id === id);
|
|
1573
|
+
if (idx < 0) return [...items];
|
|
1574
|
+
const source = items[idx];
|
|
1575
|
+
if (!source) return [...items];
|
|
1576
|
+
const clone = markImageAsManaged(cloneVectorSceneItemWithNewId(source));
|
|
1577
|
+
const inserted = [...items.slice(0, idx + 1), clone, ...items.slice(idx + 1)];
|
|
1578
|
+
return restackManagedImages(inserted);
|
|
1579
|
+
}
|
|
1580
|
+
function rotateManagedImage(items, id) {
|
|
1581
|
+
return items.map(
|
|
1582
|
+
(i) => i.id === id ? { ...i, rotation: ((i.rotation ?? 0) + Math.PI / 2) % (Math.PI * 2) } : i
|
|
1583
|
+
);
|
|
1584
|
+
}
|
|
1585
|
+
function deleteManagedImage(items, id) {
|
|
1586
|
+
return restackManagedImages(items.filter((i) => i.id !== id));
|
|
1587
|
+
}
|
|
1588
|
+
function reorderManagedImages(items, orderedManagedIds) {
|
|
1589
|
+
const managedSlots = [];
|
|
1590
|
+
for (let i = 0; i < items.length; i++) {
|
|
1591
|
+
const item = items[i];
|
|
1592
|
+
if (item && isManagedImage(item)) managedSlots.push(i);
|
|
1593
|
+
}
|
|
1594
|
+
if (managedSlots.length !== orderedManagedIds.length) {
|
|
1595
|
+
return [...items];
|
|
1596
|
+
}
|
|
1597
|
+
const byId = new Map(items.map((i) => [i.id, i]));
|
|
1598
|
+
const next = [...items];
|
|
1599
|
+
managedSlots.forEach((slot, k) => {
|
|
1600
|
+
const orderedId = orderedManagedIds[k];
|
|
1601
|
+
if (orderedId === void 0) return;
|
|
1602
|
+
const replacement = byId.get(orderedId);
|
|
1603
|
+
if (replacement) next[slot] = replacement;
|
|
1604
|
+
});
|
|
1605
|
+
return restackManagedImages(next);
|
|
1606
|
+
}
|
|
1607
|
+
var panelStyle = {
|
|
1608
|
+
width: "fit-content",
|
|
1609
|
+
maxHeight: "min(85dvh, 820px)",
|
|
1610
|
+
overflow: "auto",
|
|
1611
|
+
backgroundColor: "#ffffff",
|
|
1612
|
+
border: "1px solid #e2e8f0",
|
|
1613
|
+
borderRadius: 10,
|
|
1614
|
+
boxShadow: "0 10px 40px rgba(15, 23, 42, 0.12)",
|
|
1615
|
+
fontFamily: "system-ui, sans-serif",
|
|
1616
|
+
fontSize: 14,
|
|
1617
|
+
color: "#0f172a"
|
|
1618
|
+
};
|
|
1619
|
+
var headerStyle = {
|
|
1620
|
+
display: "flex",
|
|
1621
|
+
alignItems: "center",
|
|
1622
|
+
justifyContent: "space-between",
|
|
1623
|
+
gap: 8,
|
|
1624
|
+
padding: "8px 8px 8px 14px",
|
|
1625
|
+
borderBottom: "1px solid #e2e8f0",
|
|
1626
|
+
fontWeight: 600,
|
|
1627
|
+
letterSpacing: "0.02em"
|
|
1628
|
+
};
|
|
1629
|
+
var headerTitleStyle = {
|
|
1630
|
+
display: "inline-flex",
|
|
1631
|
+
alignItems: "center",
|
|
1632
|
+
gap: 8
|
|
1633
|
+
};
|
|
1634
|
+
var countStyle = {
|
|
1635
|
+
color: "#64748b",
|
|
1636
|
+
fontWeight: 500
|
|
1637
|
+
};
|
|
1638
|
+
var listStyle = {
|
|
1639
|
+
display: "flex",
|
|
1640
|
+
flexDirection: "column",
|
|
1641
|
+
padding: 8,
|
|
1642
|
+
gap: 6
|
|
1643
|
+
};
|
|
1644
|
+
var rowStyle = {
|
|
1645
|
+
display: "flex",
|
|
1646
|
+
alignItems: "center",
|
|
1647
|
+
gap: 12,
|
|
1648
|
+
padding: "10px 12px",
|
|
1649
|
+
borderRadius: 10
|
|
1650
|
+
};
|
|
1651
|
+
var handleStyle = {
|
|
1652
|
+
display: "inline-flex",
|
|
1653
|
+
alignItems: "center",
|
|
1654
|
+
justifyContent: "center",
|
|
1655
|
+
width: 28,
|
|
1656
|
+
height: 128,
|
|
1657
|
+
border: "none",
|
|
1658
|
+
background: "transparent",
|
|
1659
|
+
color: "#94a3b8",
|
|
1660
|
+
cursor: "grab",
|
|
1661
|
+
touchAction: "none",
|
|
1662
|
+
padding: 0
|
|
1663
|
+
};
|
|
1664
|
+
var thumbBoxStyle = {
|
|
1665
|
+
width: 128,
|
|
1666
|
+
height: 128,
|
|
1667
|
+
flex: "0 0 auto",
|
|
1668
|
+
overflow: "hidden",
|
|
1669
|
+
borderRadius: 8,
|
|
1670
|
+
backgroundColor: "#e2e8f0",
|
|
1671
|
+
display: "flex",
|
|
1672
|
+
alignItems: "center",
|
|
1673
|
+
justifyContent: "center"
|
|
1674
|
+
};
|
|
1675
|
+
var thumbImgStyle = {
|
|
1676
|
+
width: "100%",
|
|
1677
|
+
height: "100%",
|
|
1678
|
+
objectFit: "cover",
|
|
1679
|
+
display: "block"
|
|
1680
|
+
};
|
|
1681
|
+
var actionsColumnStyle = {
|
|
1682
|
+
display: "flex",
|
|
1683
|
+
flexDirection: "column",
|
|
1684
|
+
alignItems: "center",
|
|
1685
|
+
justifyContent: "center",
|
|
1686
|
+
gap: 4
|
|
1687
|
+
};
|
|
1688
|
+
var actionButtonStyle = {
|
|
1689
|
+
display: "inline-flex",
|
|
1690
|
+
alignItems: "center",
|
|
1691
|
+
justifyContent: "center",
|
|
1692
|
+
width: 32,
|
|
1693
|
+
height: 32,
|
|
1694
|
+
border: "none",
|
|
1695
|
+
borderRadius: 6,
|
|
1696
|
+
background: "transparent",
|
|
1697
|
+
color: "#0f172a",
|
|
1698
|
+
cursor: "pointer",
|
|
1699
|
+
padding: 0
|
|
1700
|
+
};
|
|
1701
|
+
var tooltipWrapperStyle = {
|
|
1702
|
+
position: "relative",
|
|
1703
|
+
display: "inline-flex"
|
|
1704
|
+
};
|
|
1705
|
+
var tooltipBubbleStyle = {
|
|
1706
|
+
position: "absolute",
|
|
1707
|
+
right: "calc(100% + 8px)",
|
|
1708
|
+
top: "50%",
|
|
1709
|
+
transform: "translateY(-50%)",
|
|
1710
|
+
padding: "4px 8px",
|
|
1711
|
+
backgroundColor: "#0f172a",
|
|
1712
|
+
color: "#ffffff",
|
|
1713
|
+
fontSize: 11,
|
|
1714
|
+
fontWeight: 500,
|
|
1715
|
+
borderRadius: 4,
|
|
1716
|
+
whiteSpace: "nowrap",
|
|
1717
|
+
pointerEvents: "none",
|
|
1718
|
+
zIndex: 100,
|
|
1719
|
+
boxShadow: "0 2px 8px rgba(15, 23, 42, 0.25)"
|
|
1720
|
+
};
|
|
1721
|
+
var dangerColor = "#b91c1c";
|
|
1722
|
+
var collapseButtonStyle = {
|
|
1723
|
+
display: "inline-flex",
|
|
1724
|
+
alignItems: "center",
|
|
1725
|
+
justifyContent: "center",
|
|
1726
|
+
width: 32,
|
|
1727
|
+
height: 32,
|
|
1728
|
+
border: "none",
|
|
1729
|
+
borderRadius: 8,
|
|
1730
|
+
background: "transparent",
|
|
1731
|
+
color: "#0f172a",
|
|
1732
|
+
cursor: "pointer",
|
|
1733
|
+
padding: 0
|
|
1734
|
+
};
|
|
1735
|
+
var collapsedButtonStyle = {
|
|
1736
|
+
display: "inline-flex",
|
|
1737
|
+
alignItems: "center",
|
|
1738
|
+
justifyContent: "center",
|
|
1739
|
+
gap: 6,
|
|
1740
|
+
height: 44,
|
|
1741
|
+
minWidth: 44,
|
|
1742
|
+
padding: "0 12px",
|
|
1743
|
+
border: "1px solid #e2e8f0",
|
|
1744
|
+
borderRadius: 22,
|
|
1745
|
+
background: "#ffffff",
|
|
1746
|
+
color: "#0f172a",
|
|
1747
|
+
cursor: "pointer",
|
|
1748
|
+
fontFamily: "system-ui, sans-serif",
|
|
1749
|
+
fontSize: 13,
|
|
1750
|
+
fontWeight: 600,
|
|
1751
|
+
boxShadow: "0 8px 24px rgba(15, 23, 42, 0.12)"
|
|
1752
|
+
};
|
|
1753
|
+
var collapsedCountStyle = {
|
|
1754
|
+
display: "inline-flex",
|
|
1755
|
+
alignItems: "center",
|
|
1756
|
+
justifyContent: "center",
|
|
1757
|
+
minWidth: 20,
|
|
1758
|
+
height: 20,
|
|
1759
|
+
padding: "0 6px",
|
|
1760
|
+
borderRadius: 10,
|
|
1761
|
+
backgroundColor: "#0f172a",
|
|
1762
|
+
color: "#ffffff",
|
|
1763
|
+
fontSize: 11,
|
|
1764
|
+
fontWeight: 600
|
|
1765
|
+
};
|
|
1766
|
+
var defaultLabels = {
|
|
1767
|
+
title: "Images",
|
|
1768
|
+
dragHandle: "Drag to reorder",
|
|
1769
|
+
focus: "Focus on canvas",
|
|
1770
|
+
copy: "Copy",
|
|
1771
|
+
rotate: "Rotate",
|
|
1772
|
+
delete: "Delete",
|
|
1773
|
+
collapse: "Collapse images menu",
|
|
1774
|
+
expand: "Open images menu"
|
|
1775
|
+
};
|
|
1776
|
+
function ImagesMenu({
|
|
1777
|
+
items,
|
|
1778
|
+
onItemsChange,
|
|
1779
|
+
onFocusItem,
|
|
1780
|
+
labels
|
|
1781
|
+
}) {
|
|
1782
|
+
const managed = useMemo(() => items.filter(isManagedImage), [items]);
|
|
1783
|
+
const sensors = useSensors(
|
|
1784
|
+
useSensor(PointerSensor, {
|
|
1785
|
+
activationConstraint: { distance: 4 }
|
|
1786
|
+
})
|
|
1787
|
+
);
|
|
1788
|
+
const [collapsed, setCollapsed] = useState(false);
|
|
1789
|
+
if (managed.length === 0) {
|
|
1790
|
+
return null;
|
|
1791
|
+
}
|
|
1792
|
+
const resolvedLabels = { ...defaultLabels, ...labels };
|
|
1793
|
+
if (collapsed) {
|
|
1794
|
+
return /* @__PURE__ */ jsxs(
|
|
1795
|
+
"button",
|
|
1796
|
+
{
|
|
1797
|
+
type: "button",
|
|
1798
|
+
"data-slot": "images-menu-collapsed",
|
|
1799
|
+
style: collapsedButtonStyle,
|
|
1800
|
+
"aria-label": resolvedLabels.expand,
|
|
1801
|
+
title: resolvedLabels.expand,
|
|
1802
|
+
onClick: () => setCollapsed(false),
|
|
1803
|
+
children: [
|
|
1804
|
+
/* @__PURE__ */ jsx(Images, { size: 20 }),
|
|
1805
|
+
/* @__PURE__ */ jsx("span", { style: collapsedCountStyle, children: managed.length })
|
|
1806
|
+
]
|
|
1807
|
+
}
|
|
1808
|
+
);
|
|
1809
|
+
}
|
|
1810
|
+
const onDragEnd = (event) => {
|
|
1811
|
+
const { active, over } = event;
|
|
1812
|
+
if (!over || active.id === over.id) return;
|
|
1813
|
+
const oldIndex = managed.findIndex((i) => i.id === active.id);
|
|
1814
|
+
const newIndex = managed.findIndex((i) => i.id === over.id);
|
|
1815
|
+
if (oldIndex < 0 || newIndex < 0) return;
|
|
1816
|
+
const reorderedManaged = arrayMove(managed, oldIndex, newIndex);
|
|
1817
|
+
const orderedIds = reorderedManaged.map((i) => i.id);
|
|
1818
|
+
onItemsChange(reorderManagedImages(items, orderedIds));
|
|
1819
|
+
};
|
|
1820
|
+
return /* @__PURE__ */ jsxs(
|
|
1821
|
+
"section",
|
|
1822
|
+
{
|
|
1823
|
+
"data-slot": "images-menu",
|
|
1824
|
+
style: panelStyle,
|
|
1825
|
+
"aria-label": resolvedLabels.title,
|
|
1826
|
+
children: [
|
|
1827
|
+
/* @__PURE__ */ jsxs("div", { style: headerStyle, children: [
|
|
1828
|
+
/* @__PURE__ */ jsxs("span", { style: headerTitleStyle, children: [
|
|
1829
|
+
/* @__PURE__ */ jsx("span", { children: resolvedLabels.title }),
|
|
1830
|
+
/* @__PURE__ */ jsx("span", { style: countStyle, children: managed.length })
|
|
1831
|
+
] }),
|
|
1832
|
+
/* @__PURE__ */ jsx(
|
|
1833
|
+
"button",
|
|
1834
|
+
{
|
|
1835
|
+
type: "button",
|
|
1836
|
+
style: collapseButtonStyle,
|
|
1837
|
+
"aria-label": resolvedLabels.collapse,
|
|
1838
|
+
title: resolvedLabels.collapse,
|
|
1839
|
+
onClick: () => setCollapsed(true),
|
|
1840
|
+
children: /* @__PURE__ */ jsx(ChevronRight, { size: 20 })
|
|
1841
|
+
}
|
|
1842
|
+
)
|
|
1843
|
+
] }),
|
|
1844
|
+
/* @__PURE__ */ jsx(DndContext, { sensors, onDragEnd, children: /* @__PURE__ */ jsx(
|
|
1845
|
+
SortableContext,
|
|
1846
|
+
{
|
|
1847
|
+
items: managed.map((i) => i.id),
|
|
1848
|
+
strategy: verticalListSortingStrategy,
|
|
1849
|
+
children: /* @__PURE__ */ jsx("div", { style: listStyle, children: managed.map((item) => /* @__PURE__ */ jsx(
|
|
1850
|
+
ImagesMenuRow,
|
|
1851
|
+
{
|
|
1852
|
+
item,
|
|
1853
|
+
labels: resolvedLabels,
|
|
1854
|
+
onFocus: onFocusItem ? () => onFocusItem(item) : void 0,
|
|
1855
|
+
onCopy: () => onItemsChange(copyManagedImage(items, item.id)),
|
|
1856
|
+
onRotate: () => onItemsChange(rotateManagedImage(items, item.id)),
|
|
1857
|
+
onDelete: () => onItemsChange(deleteManagedImage(items, item.id))
|
|
1858
|
+
},
|
|
1859
|
+
item.id
|
|
1860
|
+
)) })
|
|
1861
|
+
}
|
|
1862
|
+
) })
|
|
1863
|
+
]
|
|
1864
|
+
}
|
|
1865
|
+
);
|
|
1866
|
+
}
|
|
1867
|
+
function ImagesMenuRow({
|
|
1868
|
+
item,
|
|
1869
|
+
labels,
|
|
1870
|
+
onFocus,
|
|
1871
|
+
onCopy,
|
|
1872
|
+
onRotate,
|
|
1873
|
+
onDelete
|
|
1874
|
+
}) {
|
|
1875
|
+
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id: item.id });
|
|
1876
|
+
const wrapperStyle = {
|
|
1877
|
+
...rowStyle,
|
|
1878
|
+
transform: CSS.Transform.toString(transform),
|
|
1879
|
+
transition,
|
|
1880
|
+
background: isDragging ? "#eef2f7" : "transparent",
|
|
1881
|
+
opacity: isDragging ? 0.85 : 1
|
|
1882
|
+
};
|
|
1883
|
+
const src = item.imageThumbnailHref ?? item.imageRasterHref ?? "";
|
|
1884
|
+
return /* @__PURE__ */ jsxs("div", { ref: setNodeRef, style: wrapperStyle, children: [
|
|
1885
|
+
/* @__PURE__ */ jsx(
|
|
1886
|
+
"button",
|
|
1887
|
+
{
|
|
1888
|
+
type: "button",
|
|
1889
|
+
style: handleStyle,
|
|
1890
|
+
"aria-label": labels.dragHandle,
|
|
1891
|
+
title: labels.dragHandle,
|
|
1892
|
+
...attributes,
|
|
1893
|
+
...listeners,
|
|
1894
|
+
children: /* @__PURE__ */ jsx(GripVertical, { size: 18 })
|
|
1895
|
+
}
|
|
1896
|
+
),
|
|
1897
|
+
/* @__PURE__ */ jsx(FocusTarget, { label: labels.focus, onFocus, children: /* @__PURE__ */ jsx("div", { style: thumbBoxStyle, children: src ? /* @__PURE__ */ jsx("img", { src, alt: "", style: thumbImgStyle, draggable: false }) : null }) }),
|
|
1898
|
+
/* @__PURE__ */ jsxs("div", { style: actionsColumnStyle, children: [
|
|
1899
|
+
/* @__PURE__ */ jsx(ImagesMenuAction, { label: labels.copy, onClick: onCopy, children: /* @__PURE__ */ jsx(Copy, { size: 18 }) }),
|
|
1900
|
+
/* @__PURE__ */ jsx(ImagesMenuAction, { label: labels.rotate, onClick: onRotate, children: /* @__PURE__ */ jsx(RotateCw, { size: 18 }) }),
|
|
1901
|
+
/* @__PURE__ */ jsx(ImagesMenuAction, { label: labels.delete, onClick: onDelete, danger: true, children: /* @__PURE__ */ jsx(Trash2, { size: 18 }) })
|
|
1902
|
+
] })
|
|
1903
|
+
] });
|
|
1904
|
+
}
|
|
1905
|
+
var focusTargetBaseStyle = {
|
|
1906
|
+
display: "flex",
|
|
1907
|
+
alignItems: "center",
|
|
1908
|
+
flex: "0 0 auto",
|
|
1909
|
+
padding: 0,
|
|
1910
|
+
border: "none",
|
|
1911
|
+
background: "transparent",
|
|
1912
|
+
textAlign: "left",
|
|
1913
|
+
color: "inherit",
|
|
1914
|
+
font: "inherit"
|
|
1915
|
+
};
|
|
1916
|
+
function FocusTarget({ label, onFocus, children }) {
|
|
1917
|
+
if (!onFocus) {
|
|
1918
|
+
return /* @__PURE__ */ jsx("div", { style: { ...focusTargetBaseStyle, cursor: "default" }, children });
|
|
1919
|
+
}
|
|
1920
|
+
return /* @__PURE__ */ jsx(
|
|
1921
|
+
"button",
|
|
1922
|
+
{
|
|
1923
|
+
type: "button",
|
|
1924
|
+
style: { ...focusTargetBaseStyle, cursor: "pointer" },
|
|
1925
|
+
"aria-label": label,
|
|
1926
|
+
title: label,
|
|
1927
|
+
onClick: onFocus,
|
|
1928
|
+
children
|
|
1929
|
+
}
|
|
1930
|
+
);
|
|
1931
|
+
}
|
|
1932
|
+
function ImagesMenuAction({
|
|
1933
|
+
label,
|
|
1934
|
+
onClick,
|
|
1935
|
+
danger,
|
|
1936
|
+
children
|
|
1937
|
+
}) {
|
|
1938
|
+
const [open, setOpen] = useState(false);
|
|
1939
|
+
const style = {
|
|
1940
|
+
...actionButtonStyle,
|
|
1941
|
+
color: danger ? dangerColor : actionButtonStyle.color
|
|
1942
|
+
};
|
|
1943
|
+
return /* @__PURE__ */ jsxs("span", { style: tooltipWrapperStyle, children: [
|
|
1944
|
+
/* @__PURE__ */ jsx(
|
|
1945
|
+
"button",
|
|
1946
|
+
{
|
|
1947
|
+
type: "button",
|
|
1948
|
+
style,
|
|
1949
|
+
"aria-label": label,
|
|
1950
|
+
onClick,
|
|
1951
|
+
onMouseEnter: () => setOpen(true),
|
|
1952
|
+
onMouseLeave: () => setOpen(false),
|
|
1953
|
+
onFocus: () => setOpen(true),
|
|
1954
|
+
onBlur: () => setOpen(false),
|
|
1955
|
+
children
|
|
1956
|
+
}
|
|
1957
|
+
),
|
|
1958
|
+
open ? /* @__PURE__ */ jsx("span", { role: "tooltip", style: tooltipBubbleStyle, children: label }) : null
|
|
1959
|
+
] });
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
// src/react/board-position.ts
|
|
1963
|
+
function getBoardPositionStyle(position, inset = 12, zIndex = 40) {
|
|
1964
|
+
const base2 = { position: "absolute", zIndex };
|
|
1965
|
+
switch (position) {
|
|
1966
|
+
case "fill":
|
|
1967
|
+
return { ...base2, inset };
|
|
1968
|
+
case "top-left":
|
|
1969
|
+
case "left-top":
|
|
1970
|
+
return { ...base2, top: inset, left: inset };
|
|
1971
|
+
case "top-center":
|
|
1972
|
+
return {
|
|
1973
|
+
...base2,
|
|
1974
|
+
top: inset,
|
|
1975
|
+
left: "50%",
|
|
1976
|
+
transform: "translateX(-50%)"
|
|
1977
|
+
};
|
|
1978
|
+
case "top-right":
|
|
1979
|
+
case "right-top":
|
|
1980
|
+
return { ...base2, top: inset, right: inset };
|
|
1981
|
+
case "bottom-left":
|
|
1982
|
+
case "left-bottom":
|
|
1983
|
+
return { ...base2, bottom: inset, left: inset };
|
|
1984
|
+
case "bottom-center":
|
|
1985
|
+
return {
|
|
1986
|
+
...base2,
|
|
1987
|
+
bottom: inset,
|
|
1988
|
+
left: "50%",
|
|
1989
|
+
transform: "translateX(-50%)"
|
|
1990
|
+
};
|
|
1991
|
+
case "bottom-right":
|
|
1992
|
+
case "right-bottom":
|
|
1993
|
+
return { ...base2, bottom: inset, right: inset };
|
|
1994
|
+
case "left-center":
|
|
1995
|
+
return {
|
|
1996
|
+
...base2,
|
|
1997
|
+
left: inset,
|
|
1998
|
+
top: "50%",
|
|
1999
|
+
transform: "translateY(-50%)"
|
|
2000
|
+
};
|
|
2001
|
+
case "right-center":
|
|
2002
|
+
return {
|
|
2003
|
+
...base2,
|
|
2004
|
+
right: inset,
|
|
2005
|
+
top: "50%",
|
|
2006
|
+
transform: "translateY(-50%)"
|
|
2007
|
+
};
|
|
2008
|
+
case "center":
|
|
2009
|
+
return {
|
|
2010
|
+
...base2,
|
|
2011
|
+
top: "50%",
|
|
2012
|
+
left: "50%",
|
|
2013
|
+
transform: "translate(-50%, -50%)"
|
|
2014
|
+
};
|
|
2015
|
+
default:
|
|
2016
|
+
return base2;
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
2019
|
+
|
|
1506
2020
|
// src/math/item-transform.ts
|
|
1507
2021
|
init_rect();
|
|
1508
2022
|
function getItemRotationRad(item) {
|
|
@@ -1564,1444 +2078,1498 @@ function boundsAabbForRotatedItem(item) {
|
|
|
1564
2078
|
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
1565
2079
|
}
|
|
1566
2080
|
|
|
1567
|
-
// src/react/
|
|
2081
|
+
// src/react/navmenu/minimap.tsx
|
|
1568
2082
|
init_rect();
|
|
1569
|
-
var
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
2083
|
+
var NavMenuMinimapSlotContext = createContext(null);
|
|
2084
|
+
function noop() {
|
|
2085
|
+
}
|
|
2086
|
+
function preventMouseDefault(e) {
|
|
2087
|
+
if (e.pointerType === "mouse") {
|
|
2088
|
+
e.preventDefault();
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
var BG = "#ffffff";
|
|
2092
|
+
var BORDER_COLOR = "rgba(0,0,0,0.12)";
|
|
2093
|
+
var BORDER_RADIUS = 8;
|
|
2094
|
+
var btnStyle = {
|
|
2095
|
+
pointerEvents: "auto",
|
|
2096
|
+
width: 36,
|
|
2097
|
+
height: 36,
|
|
2098
|
+
display: "inline-flex",
|
|
2099
|
+
alignItems: "center",
|
|
2100
|
+
justifyContent: "center",
|
|
2101
|
+
cursor: "pointer",
|
|
2102
|
+
fontSize: 18,
|
|
2103
|
+
lineHeight: 1,
|
|
2104
|
+
color: "#18181b",
|
|
2105
|
+
padding: 0,
|
|
2106
|
+
border: "none",
|
|
2107
|
+
outline: "none",
|
|
2108
|
+
background: "none",
|
|
2109
|
+
WebkitTapHighlightColor: "transparent"
|
|
2110
|
+
};
|
|
2111
|
+
var chevronBtnStyle = {
|
|
2112
|
+
pointerEvents: "auto",
|
|
2113
|
+
width: 24,
|
|
2114
|
+
height: 36,
|
|
2115
|
+
display: "inline-flex",
|
|
2116
|
+
alignItems: "center",
|
|
2117
|
+
justifyContent: "center",
|
|
2118
|
+
cursor: "pointer",
|
|
2119
|
+
fontSize: 12,
|
|
2120
|
+
lineHeight: 1,
|
|
2121
|
+
color: "#52525b",
|
|
2122
|
+
padding: 0,
|
|
2123
|
+
border: "none",
|
|
2124
|
+
outline: "none",
|
|
2125
|
+
background: "none",
|
|
2126
|
+
WebkitTapHighlightColor: "transparent"
|
|
2127
|
+
};
|
|
2128
|
+
var undoBtnStyle = {
|
|
2129
|
+
...chevronBtnStyle,
|
|
2130
|
+
width: 30,
|
|
2131
|
+
opacity: 1,
|
|
2132
|
+
color: "#18181b"
|
|
1580
2133
|
};
|
|
1581
2134
|
var labelStyle = {
|
|
2135
|
+
fontSize: 10,
|
|
2136
|
+
fontWeight: 600,
|
|
2137
|
+
color: "#52525b",
|
|
2138
|
+
textAlign: "center",
|
|
2139
|
+
userSelect: "none",
|
|
2140
|
+
padding: "2px 0"
|
|
2141
|
+
};
|
|
2142
|
+
var panelLayoutStyle = {
|
|
1582
2143
|
display: "flex",
|
|
1583
2144
|
flexDirection: "column",
|
|
2145
|
+
alignItems: "flex-start",
|
|
1584
2146
|
gap: 4,
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
2147
|
+
touchAction: "none",
|
|
2148
|
+
pointerEvents: "none",
|
|
2149
|
+
userSelect: "none"
|
|
1588
2150
|
};
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
2151
|
+
var innerStyle = {
|
|
2152
|
+
pointerEvents: "auto",
|
|
2153
|
+
display: "flex",
|
|
2154
|
+
flexDirection: "row",
|
|
2155
|
+
alignItems: "center",
|
|
2156
|
+
gap: 4,
|
|
2157
|
+
background: BG,
|
|
2158
|
+
borderRadius: BORDER_RADIUS,
|
|
2159
|
+
border: `1px solid ${BORDER_COLOR}`,
|
|
2160
|
+
boxShadow: "0 1px 3px rgba(0,0,0,0.08)",
|
|
2161
|
+
padding: 4
|
|
2162
|
+
};
|
|
2163
|
+
var minimapSlotStyle = {
|
|
2164
|
+
display: "contents"
|
|
2165
|
+
};
|
|
2166
|
+
var MINIMAP_W = 180;
|
|
2167
|
+
var MINIMAP_H = 120;
|
|
2168
|
+
var PADDING = 12;
|
|
2169
|
+
var ITEM_FILL = "rgba(0,0,0,0.08)";
|
|
2170
|
+
var ITEM_STROKE = "rgba(0,0,0,0.15)";
|
|
2171
|
+
var VIEWPORT_FILL = "rgba(59,130,246,0.08)";
|
|
2172
|
+
var VIEWPORT_STROKE = "#3b82f6";
|
|
2173
|
+
function NavMenuMinimap({
|
|
1603
2174
|
className,
|
|
1604
|
-
|
|
1605
|
-
|
|
2175
|
+
defaultExpanded = false,
|
|
2176
|
+
camera: cameraProp,
|
|
2177
|
+
viewportWidth: viewportWidthProp,
|
|
2178
|
+
viewportHeight: viewportHeightProp,
|
|
2179
|
+
items: itemsProp,
|
|
2180
|
+
onRequestRender: onRequestRenderProp
|
|
2181
|
+
} = {}) {
|
|
1606
2182
|
const ctx = useCanvuChromeContext();
|
|
1607
|
-
const
|
|
1608
|
-
const
|
|
1609
|
-
const
|
|
1610
|
-
|
|
1611
|
-
const
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
2183
|
+
const camera = cameraProp ?? ctx?.camera ?? null;
|
|
2184
|
+
const viewportWidth = viewportWidthProp ?? ctx?.viewportWidth ?? 0;
|
|
2185
|
+
const viewportHeight = viewportHeightProp ?? ctx?.viewportHeight ?? 0;
|
|
2186
|
+
const items = itemsProp ?? ctx?.items ?? [];
|
|
2187
|
+
const onRequestRender = onRequestRenderProp ?? ctx?.onRequestRender ?? noop;
|
|
2188
|
+
const slotEl = useContext(NavMenuMinimapSlotContext);
|
|
2189
|
+
const [expanded, setExpanded] = useState(defaultExpanded);
|
|
2190
|
+
const svgRef = useRef(null);
|
|
2191
|
+
const [dragging, setDragging] = useState(false);
|
|
2192
|
+
const [mouseDown, setMouseDown] = useState(false);
|
|
2193
|
+
const worldBounds = computeWorldBounds(items);
|
|
2194
|
+
const isEmpty = worldBounds.width <= 0 || worldBounds.height <= 0;
|
|
2195
|
+
const scale = Math.min(
|
|
2196
|
+
(MINIMAP_W - PADDING * 2) / Math.max(worldBounds.width, 1),
|
|
2197
|
+
(MINIMAP_H - PADDING * 2) / Math.max(worldBounds.height, 1)
|
|
2198
|
+
);
|
|
2199
|
+
const originX = worldBounds.x;
|
|
2200
|
+
const originY = worldBounds.y;
|
|
2201
|
+
const toMinimapX = (wx) => (wx - originX) * scale + PADDING;
|
|
2202
|
+
const toMinimapY = (wy) => (wy - originY) * scale + PADDING;
|
|
2203
|
+
const toMinimapW = (ww) => ww * scale;
|
|
2204
|
+
const toMinimapH = (wh) => wh * scale;
|
|
2205
|
+
const viewportWorld = camera ? camera.getVisibleWorldRect(viewportWidth, viewportHeight) : { x: 0, y: 0, width: 0, height: 0 };
|
|
2206
|
+
const vpMinimap = {
|
|
2207
|
+
x: toMinimapX(viewportWorld.x),
|
|
2208
|
+
y: toMinimapY(viewportWorld.y),
|
|
2209
|
+
width: toMinimapW(viewportWorld.width),
|
|
2210
|
+
height: toMinimapH(viewportWorld.height)
|
|
1615
2211
|
};
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
2212
|
+
const worldFromMinimap = useCallback(
|
|
2213
|
+
(mx, my) => ({
|
|
2214
|
+
worldX: (mx - PADDING) / scale + originX,
|
|
2215
|
+
worldY: (my - PADDING) / scale + originY
|
|
2216
|
+
}),
|
|
2217
|
+
[scale, originX, originY]
|
|
2218
|
+
);
|
|
2219
|
+
const panTo = useCallback(
|
|
2220
|
+
(mx, my) => {
|
|
2221
|
+
if (!camera) return;
|
|
2222
|
+
const { worldX, worldY } = worldFromMinimap(mx, my);
|
|
2223
|
+
camera.x = viewportWidth / 2 - worldX * camera.zoom;
|
|
2224
|
+
camera.y = viewportHeight / 2 - worldY * camera.zoom;
|
|
2225
|
+
onRequestRender();
|
|
2226
|
+
},
|
|
2227
|
+
[worldFromMinimap, camera, viewportWidth, viewportHeight, onRequestRender]
|
|
2228
|
+
);
|
|
2229
|
+
const handlePointerDown = useCallback(
|
|
2230
|
+
(e) => {
|
|
2231
|
+
if (isEmpty) return;
|
|
2232
|
+
setDragging(true);
|
|
2233
|
+
setMouseDown(true);
|
|
2234
|
+
const rect = svgRef.current?.getBoundingClientRect();
|
|
2235
|
+
if (!rect) return;
|
|
2236
|
+
panTo(e.clientX - rect.left, e.clientY - rect.top);
|
|
2237
|
+
svgRef.current?.setPointerCapture(e.pointerId);
|
|
2238
|
+
},
|
|
2239
|
+
[isEmpty, panTo]
|
|
2240
|
+
);
|
|
2241
|
+
const handlePointerMove = useCallback(
|
|
2242
|
+
(e) => {
|
|
2243
|
+
if (!mouseDown || isEmpty) return;
|
|
2244
|
+
const rect = svgRef.current?.getBoundingClientRect();
|
|
2245
|
+
if (!rect) return;
|
|
2246
|
+
panTo(e.clientX - rect.left, e.clientY - rect.top);
|
|
2247
|
+
},
|
|
2248
|
+
[mouseDown, isEmpty, panTo]
|
|
2249
|
+
);
|
|
2250
|
+
const handlePointerUp = useCallback(() => {
|
|
2251
|
+
setDragging(false);
|
|
2252
|
+
setMouseDown(false);
|
|
2253
|
+
}, []);
|
|
2254
|
+
const toggleExpanded = useCallback(() => {
|
|
2255
|
+
setExpanded((v) => !v);
|
|
2256
|
+
}, []);
|
|
2257
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2258
|
+
/* @__PURE__ */ jsx(
|
|
2259
|
+
"button",
|
|
1624
2260
|
{
|
|
1625
|
-
|
|
1626
|
-
"data-position": position,
|
|
2261
|
+
type: "button",
|
|
1627
2262
|
className,
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
2263
|
+
style: chevronBtnStyle,
|
|
2264
|
+
"aria-label": expanded ? "Hide minimap" : "Show minimap",
|
|
2265
|
+
title: expanded ? "Hide minimap" : "Show minimap",
|
|
2266
|
+
"aria-expanded": expanded,
|
|
2267
|
+
onPointerDown: preventMouseDefault,
|
|
2268
|
+
onClick: toggleExpanded,
|
|
2269
|
+
children: /* @__PURE__ */ jsx(
|
|
2270
|
+
"svg",
|
|
2271
|
+
{
|
|
2272
|
+
width: "12",
|
|
2273
|
+
height: "12",
|
|
2274
|
+
viewBox: "0 0 12 12",
|
|
2275
|
+
style: {
|
|
2276
|
+
transform: expanded ? "rotate(180deg)" : "rotate(0deg)",
|
|
2277
|
+
transition: "transform 0.15s ease"
|
|
2278
|
+
},
|
|
2279
|
+
"aria-hidden": true,
|
|
2280
|
+
children: /* @__PURE__ */ jsx(
|
|
2281
|
+
"path",
|
|
1635
2282
|
{
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
}),
|
|
1643
|
-
style: {
|
|
1644
|
-
width: "100%",
|
|
1645
|
-
height: 32,
|
|
1646
|
-
padding: 0,
|
|
1647
|
-
border: "none",
|
|
1648
|
-
cursor: "pointer",
|
|
1649
|
-
background: "transparent"
|
|
1650
|
-
}
|
|
2283
|
+
d: "M2 4 L6 8 L10 4",
|
|
2284
|
+
fill: "none",
|
|
2285
|
+
stroke: "currentColor",
|
|
2286
|
+
strokeWidth: "1.5",
|
|
2287
|
+
strokeLinecap: "round",
|
|
2288
|
+
strokeLinejoin: "round"
|
|
1651
2289
|
}
|
|
1652
2290
|
)
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
2291
|
+
}
|
|
2292
|
+
)
|
|
2293
|
+
}
|
|
2294
|
+
),
|
|
2295
|
+
expanded && slotEl ? createPortal(
|
|
2296
|
+
/* @__PURE__ */ jsx("nav", { "aria-label": "Minimap", style: { pointerEvents: "auto" }, children: /* @__PURE__ */ jsx(
|
|
2297
|
+
"svg",
|
|
2298
|
+
{
|
|
2299
|
+
ref: svgRef,
|
|
2300
|
+
style: {
|
|
2301
|
+
width: MINIMAP_W,
|
|
2302
|
+
height: MINIMAP_H,
|
|
2303
|
+
borderRadius: BORDER_RADIUS,
|
|
2304
|
+
border: `1px solid ${BORDER_COLOR}`,
|
|
2305
|
+
background: BG,
|
|
2306
|
+
boxShadow: "0 1px 3px rgba(0,0,0,0.08)",
|
|
2307
|
+
cursor: isEmpty ? "default" : dragging ? "grabbing" : "grab",
|
|
2308
|
+
display: "block",
|
|
2309
|
+
pointerEvents: "auto"
|
|
2310
|
+
},
|
|
2311
|
+
onPointerDown: handlePointerDown,
|
|
2312
|
+
onPointerMove: handlePointerMove,
|
|
2313
|
+
onPointerUp: handlePointerUp,
|
|
2314
|
+
onPointerCancel: handlePointerUp,
|
|
2315
|
+
children: isEmpty ? null : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2316
|
+
items.map((it) => {
|
|
2317
|
+
const b = normalizeRect(boundsAabbForRotatedItem(it));
|
|
2318
|
+
return /* @__PURE__ */ jsx(
|
|
2319
|
+
"rect",
|
|
2320
|
+
{
|
|
2321
|
+
x: toMinimapX(b.x),
|
|
2322
|
+
y: toMinimapY(b.y),
|
|
2323
|
+
width: toMinimapW(b.width),
|
|
2324
|
+
height: toMinimapH(b.height),
|
|
2325
|
+
fill: ITEM_FILL,
|
|
2326
|
+
stroke: ITEM_STROKE,
|
|
2327
|
+
strokeWidth: 0.5,
|
|
2328
|
+
rx: 1
|
|
2329
|
+
},
|
|
2330
|
+
it.id
|
|
2331
|
+
);
|
|
2332
|
+
}),
|
|
1656
2333
|
/* @__PURE__ */ jsx(
|
|
1657
|
-
"
|
|
2334
|
+
"rect",
|
|
1658
2335
|
{
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
})
|
|
2336
|
+
x: vpMinimap.x,
|
|
2337
|
+
y: vpMinimap.y,
|
|
2338
|
+
width: vpMinimap.width,
|
|
2339
|
+
height: vpMinimap.height,
|
|
2340
|
+
fill: VIEWPORT_FILL,
|
|
2341
|
+
stroke: VIEWPORT_STROKE,
|
|
2342
|
+
strokeWidth: 1.5,
|
|
2343
|
+
rx: 2
|
|
1668
2344
|
}
|
|
1669
2345
|
)
|
|
1670
|
-
] }),
|
|
1671
|
-
showMarkerOpacity2 && /* @__PURE__ */ jsxs("label", { style: labelStyle, children: [
|
|
1672
|
-
"Opacidade (marcador)",
|
|
1673
|
-
/* @__PURE__ */ jsx(
|
|
1674
|
-
"input",
|
|
1675
|
-
{
|
|
1676
|
-
type: "range",
|
|
1677
|
-
min: 10,
|
|
1678
|
-
max: 100,
|
|
1679
|
-
value: opacityPct2,
|
|
1680
|
-
onChange: (e) => {
|
|
1681
|
-
const v = Number(e.target.value) / 100;
|
|
1682
|
-
onChange({
|
|
1683
|
-
stroke: hex2,
|
|
1684
|
-
strokeWidth: strokeWidth2,
|
|
1685
|
-
strokeOpacity: v
|
|
1686
|
-
});
|
|
1687
|
-
}
|
|
1688
|
-
}
|
|
1689
|
-
),
|
|
1690
|
-
/* @__PURE__ */ jsxs("span", { style: { fontWeight: 500, color: "#71717a" }, children: [
|
|
1691
|
-
opacityPct2,
|
|
1692
|
-
"%"
|
|
1693
|
-
] })
|
|
1694
2346
|
] })
|
|
1695
|
-
|
|
1696
|
-
}
|
|
1697
|
-
|
|
2347
|
+
}
|
|
2348
|
+
) }),
|
|
2349
|
+
slotEl
|
|
2350
|
+
) : null
|
|
2351
|
+
] });
|
|
2352
|
+
}
|
|
2353
|
+
function computeWorldBounds(items) {
|
|
2354
|
+
if (items.length === 0) {
|
|
2355
|
+
return { x: 0, y: 0, width: 0, height: 0 };
|
|
1698
2356
|
}
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
const
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
);
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
2357
|
+
let minX = Infinity;
|
|
2358
|
+
let minY = Infinity;
|
|
2359
|
+
let maxX = -Infinity;
|
|
2360
|
+
let maxY = -Infinity;
|
|
2361
|
+
for (const it of items) {
|
|
2362
|
+
const b = boundsAabbForRotatedItem(it);
|
|
2363
|
+
minX = Math.min(minX, b.x);
|
|
2364
|
+
minY = Math.min(minY, b.y);
|
|
2365
|
+
maxX = Math.max(maxX, b.x + b.width);
|
|
2366
|
+
maxY = Math.max(maxY, b.y + b.height);
|
|
2367
|
+
}
|
|
2368
|
+
const pad = Math.max((maxX - minX) * 0.1, (maxY - minY) * 0.1, 40);
|
|
2369
|
+
return {
|
|
2370
|
+
x: minX - pad,
|
|
2371
|
+
y: minY - pad,
|
|
2372
|
+
width: maxX - minX + pad * 2,
|
|
2373
|
+
height: maxY - minY + pad * 2
|
|
2374
|
+
};
|
|
2375
|
+
}
|
|
2376
|
+
function NavMenuUndoRedo({
|
|
2377
|
+
className,
|
|
2378
|
+
style,
|
|
2379
|
+
onUndo: onUndoProp,
|
|
2380
|
+
onRedo: onRedoProp,
|
|
2381
|
+
canUndo: canUndoProp,
|
|
2382
|
+
canRedo: canRedoProp
|
|
2383
|
+
} = {}) {
|
|
2384
|
+
const ctx = useCanvuChromeContext();
|
|
2385
|
+
const onUndo = onUndoProp ?? ctx?.onUndo ?? noop;
|
|
2386
|
+
const onRedo = onRedoProp ?? ctx?.onRedo ?? noop;
|
|
2387
|
+
const canUndo = canUndoProp ?? ctx?.canUndo ?? false;
|
|
2388
|
+
const canRedo = canRedoProp ?? ctx?.canRedo ?? false;
|
|
2389
|
+
return /* @__PURE__ */ jsxs(
|
|
2390
|
+
"span",
|
|
2391
|
+
{
|
|
2392
|
+
className,
|
|
2393
|
+
style: { display: "inline-flex", alignItems: "center", ...style },
|
|
2394
|
+
children: [
|
|
2395
|
+
/* @__PURE__ */ jsx(
|
|
2396
|
+
"button",
|
|
2397
|
+
{
|
|
2398
|
+
type: "button",
|
|
2399
|
+
style: undoBtnStyle,
|
|
2400
|
+
"aria-label": "Undo",
|
|
2401
|
+
title: "Undo",
|
|
2402
|
+
disabled: !canUndo,
|
|
2403
|
+
onPointerDown: preventMouseDefault,
|
|
2404
|
+
onClick: onUndo,
|
|
2405
|
+
children: /* @__PURE__ */ jsx(Undo2, { size: 16 })
|
|
2406
|
+
}
|
|
2407
|
+
),
|
|
2408
|
+
/* @__PURE__ */ jsx(
|
|
2409
|
+
"button",
|
|
2410
|
+
{
|
|
2411
|
+
type: "button",
|
|
2412
|
+
style: undoBtnStyle,
|
|
2413
|
+
"aria-label": "Redo",
|
|
2414
|
+
title: "Redo",
|
|
2415
|
+
disabled: !canRedo,
|
|
2416
|
+
onPointerDown: preventMouseDefault,
|
|
2417
|
+
onClick: onRedo,
|
|
2418
|
+
children: /* @__PURE__ */ jsx(Redo2, { size: 16 })
|
|
2419
|
+
}
|
|
2420
|
+
)
|
|
2421
|
+
]
|
|
2422
|
+
}
|
|
1719
2423
|
);
|
|
1720
|
-
|
|
2424
|
+
}
|
|
2425
|
+
function NavMenuZoomControls({
|
|
2426
|
+
className,
|
|
2427
|
+
style,
|
|
2428
|
+
zoomPercent: zoomPercentProp,
|
|
2429
|
+
onZoomIn: onZoomInProp,
|
|
2430
|
+
onZoomOut: onZoomOutProp
|
|
2431
|
+
} = {}) {
|
|
2432
|
+
const ctx = useCanvuChromeContext();
|
|
2433
|
+
const zoomPercent = zoomPercentProp ?? ctx?.zoomPercent ?? 100;
|
|
2434
|
+
const onZoomIn = onZoomInProp ?? ctx?.onZoomIn ?? noop;
|
|
2435
|
+
const onZoomOut = onZoomOutProp ?? ctx?.onZoomOut ?? noop;
|
|
1721
2436
|
return /* @__PURE__ */ jsxs(
|
|
1722
|
-
"
|
|
2437
|
+
"span",
|
|
1723
2438
|
{
|
|
1724
|
-
"data-slot": "vector-selection-inspector",
|
|
1725
|
-
"data-position": position,
|
|
1726
2439
|
className,
|
|
1727
|
-
"
|
|
1728
|
-
style: shell,
|
|
2440
|
+
style: { display: "inline-flex", alignItems: "center", ...style },
|
|
1729
2441
|
children: [
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
2442
|
+
/* @__PURE__ */ jsx(
|
|
2443
|
+
"button",
|
|
2444
|
+
{
|
|
2445
|
+
type: "button",
|
|
2446
|
+
style: btnStyle,
|
|
2447
|
+
"aria-label": "Zoom out",
|
|
2448
|
+
title: "Zoom out",
|
|
2449
|
+
onPointerDown: preventMouseDefault,
|
|
2450
|
+
onClick: onZoomOut,
|
|
2451
|
+
children: "\u2212"
|
|
2452
|
+
}
|
|
2453
|
+
),
|
|
2454
|
+
/* @__PURE__ */ jsxs("span", { style: labelStyle, "aria-hidden": true, children: [
|
|
2455
|
+
zoomPercent,
|
|
2456
|
+
"%"
|
|
1733
2457
|
] }),
|
|
1734
|
-
/* @__PURE__ */
|
|
1735
|
-
"
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
2458
|
+
/* @__PURE__ */ jsx(
|
|
2459
|
+
"button",
|
|
2460
|
+
{
|
|
2461
|
+
type: "button",
|
|
2462
|
+
style: btnStyle,
|
|
2463
|
+
"aria-label": "Zoom in",
|
|
2464
|
+
title: "Zoom in",
|
|
2465
|
+
onPointerDown: preventMouseDefault,
|
|
2466
|
+
onClick: onZoomIn,
|
|
2467
|
+
children: "+"
|
|
2468
|
+
}
|
|
2469
|
+
)
|
|
2470
|
+
]
|
|
2471
|
+
}
|
|
2472
|
+
);
|
|
2473
|
+
}
|
|
2474
|
+
function NavMenuComponent({
|
|
2475
|
+
camera: cameraProp,
|
|
2476
|
+
viewportWidth: viewportWidthProp,
|
|
2477
|
+
viewportHeight: viewportHeightProp,
|
|
2478
|
+
items: itemsProp,
|
|
2479
|
+
zoomPercent: zoomPercentProp,
|
|
2480
|
+
onZoomIn: onZoomInProp,
|
|
2481
|
+
onZoomOut: onZoomOutProp,
|
|
2482
|
+
onUndo: onUndoProp,
|
|
2483
|
+
onRedo: onRedoProp,
|
|
2484
|
+
canUndo: canUndoProp,
|
|
2485
|
+
canRedo: canRedoProp,
|
|
2486
|
+
onRequestRender: onRequestRenderProp,
|
|
2487
|
+
position = "bottom-left",
|
|
2488
|
+
inset = 12,
|
|
2489
|
+
zIndex = 23,
|
|
2490
|
+
className,
|
|
2491
|
+
style,
|
|
2492
|
+
children
|
|
2493
|
+
}) {
|
|
2494
|
+
const [slotEl, setSlotEl] = useState(null);
|
|
2495
|
+
const anchorStyle = getBoardPositionStyle(position, inset, zIndex);
|
|
2496
|
+
return /* @__PURE__ */ jsx(
|
|
2497
|
+
"fieldset",
|
|
2498
|
+
{
|
|
2499
|
+
"data-slot": "canvu-nav-menu",
|
|
2500
|
+
"data-position": position,
|
|
2501
|
+
className,
|
|
2502
|
+
style: {
|
|
2503
|
+
...anchorStyle,
|
|
2504
|
+
...panelLayoutStyle,
|
|
2505
|
+
border: "none",
|
|
2506
|
+
margin: 0,
|
|
2507
|
+
padding: 0,
|
|
2508
|
+
minWidth: 0,
|
|
2509
|
+
...style
|
|
2510
|
+
},
|
|
2511
|
+
"aria-label": "Zoom and minimap controls",
|
|
2512
|
+
children: /* @__PURE__ */ jsxs(NavMenuMinimapSlotContext.Provider, { value: slotEl, children: [
|
|
2513
|
+
/* @__PURE__ */ jsx("div", { style: innerStyle, children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1740
2514
|
/* @__PURE__ */ jsx(
|
|
1741
|
-
|
|
2515
|
+
NavMenuZoomControls,
|
|
1742
2516
|
{
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
stroke: e.target.value,
|
|
1747
|
-
strokeWidth
|
|
1748
|
-
}),
|
|
1749
|
-
style: {
|
|
1750
|
-
width: "100%",
|
|
1751
|
-
height: 32,
|
|
1752
|
-
padding: 0,
|
|
1753
|
-
border: "none",
|
|
1754
|
-
cursor: "pointer",
|
|
1755
|
-
background: "transparent"
|
|
1756
|
-
}
|
|
2517
|
+
zoomPercent: zoomPercentProp,
|
|
2518
|
+
onZoomIn: onZoomInProp,
|
|
2519
|
+
onZoomOut: onZoomOutProp
|
|
1757
2520
|
}
|
|
1758
|
-
)
|
|
1759
|
-
] }),
|
|
1760
|
-
/* @__PURE__ */ jsxs("label", { style: labelStyle, children: [
|
|
1761
|
-
"Grossura",
|
|
1762
|
-
!allSameWidth && /* @__PURE__ */ jsx("span", { style: { fontWeight: 400, color: "#a1a1aa" }, children: " (misturado)" }),
|
|
2521
|
+
),
|
|
1763
2522
|
/* @__PURE__ */ jsx(
|
|
1764
|
-
|
|
2523
|
+
NavMenuUndoRedo,
|
|
1765
2524
|
{
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
onChange: (e) => onChange({
|
|
1771
|
-
stroke: hex,
|
|
1772
|
-
strokeWidth: Number(e.target.value)
|
|
1773
|
-
})
|
|
2525
|
+
onUndo: onUndoProp,
|
|
2526
|
+
onRedo: onRedoProp,
|
|
2527
|
+
canUndo: canUndoProp,
|
|
2528
|
+
canRedo: canRedoProp
|
|
1774
2529
|
}
|
|
1775
|
-
)
|
|
1776
|
-
] }),
|
|
1777
|
-
showMarkerOpacity && firstMarker && /* @__PURE__ */ jsxs("label", { style: labelStyle, children: [
|
|
1778
|
-
"Opacidade (marcador)",
|
|
1779
|
-
!allSameMarkerOpacity && markers.length > 1 && /* @__PURE__ */ jsx("span", { style: { fontWeight: 400, color: "#a1a1aa" }, children: " (misturado)" }),
|
|
2530
|
+
),
|
|
1780
2531
|
/* @__PURE__ */ jsx(
|
|
1781
|
-
|
|
2532
|
+
NavMenuMinimap,
|
|
1782
2533
|
{
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
const v = Number(e.target.value) / 100;
|
|
1789
|
-
onChange({
|
|
1790
|
-
stroke: hex,
|
|
1791
|
-
strokeWidth,
|
|
1792
|
-
strokeOpacity: v
|
|
1793
|
-
});
|
|
1794
|
-
}
|
|
2534
|
+
camera: cameraProp,
|
|
2535
|
+
viewportWidth: viewportWidthProp,
|
|
2536
|
+
viewportHeight: viewportHeightProp,
|
|
2537
|
+
items: itemsProp,
|
|
2538
|
+
onRequestRender: onRequestRenderProp
|
|
1795
2539
|
}
|
|
1796
|
-
)
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
] })
|
|
1801
|
-
] })
|
|
1802
|
-
]
|
|
2540
|
+
)
|
|
2541
|
+
] }) }),
|
|
2542
|
+
/* @__PURE__ */ jsx("div", { ref: setSlotEl, style: minimapSlotStyle })
|
|
2543
|
+
] })
|
|
1803
2544
|
}
|
|
1804
2545
|
);
|
|
1805
2546
|
}
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
...base2,
|
|
1830
|
-
bottom: inset,
|
|
1831
|
-
left: "50%",
|
|
1832
|
-
transform: "translateX(-50%)"
|
|
1833
|
-
};
|
|
1834
|
-
case "bottom-right":
|
|
1835
|
-
case "right-bottom":
|
|
1836
|
-
return { ...base2, bottom: inset, right: inset };
|
|
1837
|
-
case "left-center":
|
|
1838
|
-
return {
|
|
1839
|
-
...base2,
|
|
1840
|
-
left: inset,
|
|
1841
|
-
top: "50%",
|
|
1842
|
-
transform: "translateY(-50%)"
|
|
1843
|
-
};
|
|
1844
|
-
case "right-center":
|
|
1845
|
-
return {
|
|
1846
|
-
...base2,
|
|
1847
|
-
right: inset,
|
|
1848
|
-
top: "50%",
|
|
1849
|
-
transform: "translateY(-50%)"
|
|
1850
|
-
};
|
|
1851
|
-
case "center":
|
|
1852
|
-
return {
|
|
1853
|
-
...base2,
|
|
1854
|
-
top: "50%",
|
|
1855
|
-
left: "50%",
|
|
1856
|
-
transform: "translate(-50%, -50%)"
|
|
1857
|
-
};
|
|
1858
|
-
default:
|
|
1859
|
-
return base2;
|
|
1860
|
-
}
|
|
1861
|
-
}
|
|
1862
|
-
var rootStyle = {
|
|
1863
|
-
display: "flex",
|
|
1864
|
-
flexDirection: "column",
|
|
1865
|
-
height: "100%",
|
|
1866
|
-
minHeight: 0,
|
|
1867
|
-
width: "100%"
|
|
1868
|
-
};
|
|
1869
|
-
var headerStyle = {
|
|
1870
|
-
flexShrink: 0,
|
|
1871
|
-
display: "flex",
|
|
1872
|
-
flexWrap: "wrap",
|
|
1873
|
-
alignItems: "center",
|
|
1874
|
-
gap: "0.75rem",
|
|
1875
|
-
padding: "0.75rem 1rem",
|
|
1876
|
-
borderBottom: "1px solid #e4e4e7",
|
|
1877
|
-
background: "#fff",
|
|
1878
|
-
fontSize: "0.875rem"
|
|
1879
|
-
};
|
|
1880
|
-
var bodyStyle = {
|
|
1881
|
-
flex: 1,
|
|
1882
|
-
minHeight: 0,
|
|
1883
|
-
display: "flex",
|
|
1884
|
-
flexDirection: "column"
|
|
1885
|
-
};
|
|
1886
|
-
var mainStyle = {
|
|
1887
|
-
flex: 1,
|
|
1888
|
-
minHeight: 0,
|
|
1889
|
-
position: "relative",
|
|
1890
|
-
display: "flex",
|
|
1891
|
-
flexDirection: "column"
|
|
1892
|
-
};
|
|
1893
|
-
var viewportSurfaceStyle = {
|
|
1894
|
-
flex: 1,
|
|
1895
|
-
minHeight: 0,
|
|
1896
|
-
position: "relative",
|
|
1897
|
-
width: "100%",
|
|
1898
|
-
alignSelf: "stretch",
|
|
1899
|
-
background: "#fff",
|
|
1900
|
-
touchAction: "none"
|
|
1901
|
-
};
|
|
1902
|
-
function mergeStyle(base2, style) {
|
|
1903
|
-
return style ? { ...base2, ...style } : base2;
|
|
2547
|
+
NavMenuComponent.displayName = "NavMenu";
|
|
2548
|
+
var NavMenu = Object.assign(NavMenuComponent, {
|
|
2549
|
+
ZoomControls: NavMenuZoomControls,
|
|
2550
|
+
UndoRedo: NavMenuUndoRedo,
|
|
2551
|
+
Minimap: NavMenuMinimap
|
|
2552
|
+
});
|
|
2553
|
+
|
|
2554
|
+
// src/react/persistence/indexed-db-adapter.ts
|
|
2555
|
+
init_shape_builders();
|
|
2556
|
+
var DOCUMENT_STORE = "document";
|
|
2557
|
+
var DOCUMENT_KEY = "main";
|
|
2558
|
+
function openDocumentDb(dbName) {
|
|
2559
|
+
return new Promise((resolve, reject) => {
|
|
2560
|
+
const req = indexedDB.open(dbName, 1);
|
|
2561
|
+
req.onupgradeneeded = () => {
|
|
2562
|
+
const db = req.result;
|
|
2563
|
+
if (!db.objectStoreNames.contains(DOCUMENT_STORE)) {
|
|
2564
|
+
db.createObjectStore(DOCUMENT_STORE);
|
|
2565
|
+
}
|
|
2566
|
+
};
|
|
2567
|
+
req.onsuccess = () => resolve(req.result);
|
|
2568
|
+
req.onerror = () => reject(req.error);
|
|
2569
|
+
});
|
|
1904
2570
|
}
|
|
1905
|
-
function
|
|
2571
|
+
function createIndexedDbPersistenceAdapter(options = {}) {
|
|
2572
|
+
const dbName = options.dbName ?? "canvu-document";
|
|
2573
|
+
const imageStore = new IndexedDbImageStore();
|
|
2574
|
+
let documentDbPromise = null;
|
|
2575
|
+
function getDocDb() {
|
|
2576
|
+
if (!documentDbPromise) {
|
|
2577
|
+
documentDbPromise = openDocumentDb(dbName);
|
|
2578
|
+
}
|
|
2579
|
+
return documentDbPromise;
|
|
2580
|
+
}
|
|
2581
|
+
async function getFromDocDb(key) {
|
|
2582
|
+
const db = await getDocDb();
|
|
2583
|
+
return new Promise((resolve, reject) => {
|
|
2584
|
+
const tx = db.transaction(DOCUMENT_STORE, "readonly");
|
|
2585
|
+
const req = tx.objectStore(DOCUMENT_STORE).get(key);
|
|
2586
|
+
req.onsuccess = () => resolve(req.result);
|
|
2587
|
+
req.onerror = () => reject(req.error);
|
|
2588
|
+
});
|
|
2589
|
+
}
|
|
2590
|
+
async function putInDocDb(key, value) {
|
|
2591
|
+
const db = await getDocDb();
|
|
2592
|
+
return new Promise((resolve, reject) => {
|
|
2593
|
+
const tx = db.transaction(DOCUMENT_STORE, "readwrite");
|
|
2594
|
+
const req = tx.objectStore(DOCUMENT_STORE).put(value, key);
|
|
2595
|
+
req.onsuccess = () => resolve();
|
|
2596
|
+
req.onerror = () => reject(req.error);
|
|
2597
|
+
});
|
|
2598
|
+
}
|
|
2599
|
+
const liveHrefs = /* @__PURE__ */ new Set();
|
|
2600
|
+
function stripBlobsForPersist(item) {
|
|
2601
|
+
const out = { ...item };
|
|
2602
|
+
delete out.imageRasterHref;
|
|
2603
|
+
delete out.imageThumbnailHref;
|
|
2604
|
+
if (item.toolKind === "image") {
|
|
2605
|
+
out.childrenSvg = "";
|
|
2606
|
+
}
|
|
2607
|
+
return out;
|
|
2608
|
+
}
|
|
2609
|
+
function collectLiveHrefs(items) {
|
|
2610
|
+
const set = /* @__PURE__ */ new Set();
|
|
2611
|
+
for (const item of items) {
|
|
2612
|
+
if (item.imageRasterHref?.startsWith("blob:")) {
|
|
2613
|
+
set.add(item.imageRasterHref);
|
|
2614
|
+
}
|
|
2615
|
+
if (item.imageThumbnailHref?.startsWith("blob:")) {
|
|
2616
|
+
set.add(item.imageThumbnailHref);
|
|
2617
|
+
}
|
|
2618
|
+
}
|
|
2619
|
+
return set;
|
|
2620
|
+
}
|
|
1906
2621
|
return {
|
|
1907
|
-
|
|
1908
|
-
|
|
2622
|
+
async load() {
|
|
2623
|
+
const raw = await getFromDocDb(DOCUMENT_KEY);
|
|
2624
|
+
if (!raw?.items) return null;
|
|
2625
|
+
const resolved = [];
|
|
2626
|
+
for (const item of raw.items) {
|
|
2627
|
+
if (item.toolKind === "image" && item.imageBlobId) {
|
|
2628
|
+
const itemWithBlob = { ...item };
|
|
2629
|
+
if (item.imageThumbnailBlobId) {
|
|
2630
|
+
const thumbUrl = await createThumbnailBlobUrlFromStore(
|
|
2631
|
+
imageStore,
|
|
2632
|
+
item.imageThumbnailBlobId
|
|
2633
|
+
);
|
|
2634
|
+
if (thumbUrl) {
|
|
2635
|
+
itemWithBlob.imageThumbnailHref = thumbUrl;
|
|
2636
|
+
}
|
|
2637
|
+
}
|
|
2638
|
+
const fullUrl = await createBlobUrlFromStore(imageStore, item.imageBlobId);
|
|
2639
|
+
if (fullUrl) {
|
|
2640
|
+
itemWithBlob.imageRasterHref = fullUrl;
|
|
2641
|
+
}
|
|
2642
|
+
const rebuilt = rebuildItemSvg(itemWithBlob);
|
|
2643
|
+
resolved.push(rebuilt);
|
|
2644
|
+
} else {
|
|
2645
|
+
resolved.push(item);
|
|
2646
|
+
}
|
|
2647
|
+
}
|
|
2648
|
+
return { items: resolved, version: raw.version ?? 1 };
|
|
2649
|
+
},
|
|
2650
|
+
async save(snapshot) {
|
|
2651
|
+
const nextLive = collectLiveHrefs(snapshot.items);
|
|
2652
|
+
for (const href of liveHrefs) {
|
|
2653
|
+
if (!nextLive.has(href)) {
|
|
2654
|
+
URL.revokeObjectURL(href);
|
|
2655
|
+
}
|
|
2656
|
+
}
|
|
2657
|
+
liveHrefs.clear();
|
|
2658
|
+
for (const href of nextLive) liveHrefs.add(href);
|
|
2659
|
+
const cleanItems = snapshot.items.map(stripBlobsForPersist);
|
|
2660
|
+
await putInDocDb(DOCUMENT_KEY, {
|
|
2661
|
+
items: cleanItems,
|
|
2662
|
+
version: snapshot.version ?? 1
|
|
2663
|
+
});
|
|
2664
|
+
}
|
|
1909
2665
|
};
|
|
1910
2666
|
}
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
}) {
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
2667
|
+
|
|
2668
|
+
// src/react/persistence/local-storage-adapter.ts
|
|
2669
|
+
var DEFAULT_VECTOR_CANVAS_STORAGE_KEY = "trazo.vector-canvas.v1";
|
|
2670
|
+
var SNAPSHOT_VERSION = 1;
|
|
2671
|
+
function createLocalStoragePersistenceAdapter(options = {}) {
|
|
2672
|
+
const key = options.key ?? DEFAULT_VECTOR_CANVAS_STORAGE_KEY;
|
|
2673
|
+
const storage = options.storage ?? (typeof globalThis !== "undefined" && "localStorage" in globalThis && globalThis.localStorage ? globalThis.localStorage : null);
|
|
2674
|
+
return {
|
|
2675
|
+
load() {
|
|
2676
|
+
if (!storage) return Promise.resolve(null);
|
|
2677
|
+
try {
|
|
2678
|
+
const raw = storage.getItem(key);
|
|
2679
|
+
if (!raw) return Promise.resolve(null);
|
|
2680
|
+
const parsed = JSON.parse(raw);
|
|
2681
|
+
if (!parsed || typeof parsed !== "object" || !("items" in parsed) || !Array.isArray(parsed.items)) {
|
|
2682
|
+
return Promise.resolve(null);
|
|
2683
|
+
}
|
|
2684
|
+
return Promise.resolve(parsed);
|
|
2685
|
+
} catch {
|
|
2686
|
+
return Promise.resolve(null);
|
|
2687
|
+
}
|
|
2688
|
+
},
|
|
2689
|
+
save(snapshot) {
|
|
2690
|
+
if (!storage) return Promise.resolve();
|
|
2691
|
+
try {
|
|
2692
|
+
storage.setItem(
|
|
2693
|
+
key,
|
|
2694
|
+
JSON.stringify({
|
|
2695
|
+
...snapshot,
|
|
2696
|
+
version: snapshot.version ?? SNAPSHOT_VERSION
|
|
2697
|
+
})
|
|
2698
|
+
);
|
|
2699
|
+
} catch {
|
|
2700
|
+
}
|
|
2701
|
+
return Promise.resolve();
|
|
1923
2702
|
}
|
|
1924
|
-
|
|
2703
|
+
};
|
|
1925
2704
|
}
|
|
1926
|
-
function
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
}
|
|
1931
|
-
return /* @__PURE__ */ jsx(
|
|
1932
|
-
"header",
|
|
1933
|
-
{
|
|
1934
|
-
"data-slot": "vector-canvas-header",
|
|
1935
|
-
className,
|
|
1936
|
-
style: mergeStyle(headerStyle, style),
|
|
1937
|
-
children
|
|
1938
|
-
}
|
|
1939
|
-
);
|
|
2705
|
+
function createNoopPersistenceAdapter() {
|
|
2706
|
+
return {
|
|
2707
|
+
load: () => Promise.resolve(null),
|
|
2708
|
+
save: () => Promise.resolve()
|
|
2709
|
+
};
|
|
1940
2710
|
}
|
|
1941
|
-
function
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
);
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
2711
|
+
function useVectorCanvasDocument(options = {}) {
|
|
2712
|
+
const {
|
|
2713
|
+
persistenceKey = DEFAULT_VECTOR_CANVAS_STORAGE_KEY,
|
|
2714
|
+
persistence,
|
|
2715
|
+
debounceMs = 400,
|
|
2716
|
+
remote
|
|
2717
|
+
} = options;
|
|
2718
|
+
const adapter = useMemo(() => {
|
|
2719
|
+
if (persistence === false) return createNoopPersistenceAdapter();
|
|
2720
|
+
if (persistence) return persistence;
|
|
2721
|
+
return createLocalStoragePersistenceAdapter({ key: persistenceKey });
|
|
2722
|
+
}, [persistence, persistenceKey]);
|
|
2723
|
+
const [items, setItems] = useState([]);
|
|
2724
|
+
const [isHydrated, setIsHydrated] = useState(false);
|
|
2725
|
+
const saveTimerRef = useRef(null);
|
|
2726
|
+
const adapterRef = useRef(adapter);
|
|
2727
|
+
adapterRef.current = adapter;
|
|
2728
|
+
useEffect(() => {
|
|
2729
|
+
let cancelled = false;
|
|
2730
|
+
adapter.load().then((snap) => {
|
|
2731
|
+
if (cancelled) return;
|
|
2732
|
+
if (snap?.items && snap.items.length > 0) {
|
|
2733
|
+
setItems(snap.items);
|
|
2734
|
+
}
|
|
2735
|
+
setIsHydrated(true);
|
|
2736
|
+
});
|
|
2737
|
+
return () => {
|
|
2738
|
+
cancelled = true;
|
|
2739
|
+
};
|
|
2740
|
+
}, [adapter]);
|
|
2741
|
+
const persist = useCallback((next) => {
|
|
2742
|
+
void adapterRef.current.save({ items: next, version: 1 });
|
|
2743
|
+
}, []);
|
|
2744
|
+
const onItemsChange = useCallback(
|
|
2745
|
+
(next) => {
|
|
2746
|
+
setItems(next);
|
|
2747
|
+
remote?.send?.(next);
|
|
2748
|
+
if (saveTimerRef.current) clearTimeout(saveTimerRef.current);
|
|
2749
|
+
saveTimerRef.current = setTimeout(() => {
|
|
2750
|
+
persist(next);
|
|
2751
|
+
saveTimerRef.current = null;
|
|
2752
|
+
}, debounceMs);
|
|
2753
|
+
},
|
|
2754
|
+
[debounceMs, persist, remote]
|
|
1969
2755
|
);
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
})
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
{
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
children
|
|
1983
|
-
}
|
|
2756
|
+
useEffect(() => {
|
|
2757
|
+
if (!remote || !isHydrated) return;
|
|
2758
|
+
return remote.subscribe((serverItems) => {
|
|
2759
|
+
setItems(serverItems);
|
|
2760
|
+
persist(serverItems);
|
|
2761
|
+
});
|
|
2762
|
+
}, [remote, isHydrated, persist]);
|
|
2763
|
+
useEffect(
|
|
2764
|
+
() => () => {
|
|
2765
|
+
if (saveTimerRef.current) clearTimeout(saveTimerRef.current);
|
|
2766
|
+
},
|
|
2767
|
+
[]
|
|
1984
2768
|
);
|
|
2769
|
+
const clearPersistedDocument = useCallback(() => {
|
|
2770
|
+
setItems([]);
|
|
2771
|
+
void adapterRef.current.save({ items: [], version: 1 });
|
|
2772
|
+
}, []);
|
|
2773
|
+
return {
|
|
2774
|
+
items,
|
|
2775
|
+
onItemsChange,
|
|
2776
|
+
setItems: onItemsChange,
|
|
2777
|
+
isHydrated,
|
|
2778
|
+
clearPersistedDocument
|
|
2779
|
+
};
|
|
1985
2780
|
}
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2781
|
+
var CanvuPluginContext = createContext(
|
|
2782
|
+
null
|
|
2783
|
+
);
|
|
2784
|
+
function createCanvuPlugin(plugin) {
|
|
2785
|
+
return plugin;
|
|
2786
|
+
}
|
|
2787
|
+
function useCanvuPluginContext() {
|
|
2788
|
+
const ctx = useContext(CanvuPluginContext);
|
|
2789
|
+
if (!ctx) {
|
|
2790
|
+
throw new Error(
|
|
2791
|
+
"useCanvuPluginContext must be used inside a VectorViewport plugin runtime."
|
|
2792
|
+
);
|
|
2793
|
+
}
|
|
2794
|
+
return ctx;
|
|
2795
|
+
}
|
|
2796
|
+
function useCanvuViewportContext() {
|
|
2797
|
+
const { viewportRef, viewport } = useCanvuPluginContext();
|
|
2798
|
+
return { viewportRef, viewport };
|
|
2799
|
+
}
|
|
2800
|
+
function useCanvuDocumentContext() {
|
|
2801
|
+
const { viewport } = useCanvuPluginContext();
|
|
2802
|
+
return {
|
|
2803
|
+
items: viewport.items,
|
|
2804
|
+
onItemsChange: viewport.onItemsChange
|
|
2001
2805
|
};
|
|
2002
|
-
return /* @__PURE__ */ jsx(
|
|
2003
|
-
"div",
|
|
2004
|
-
{
|
|
2005
|
-
"data-slot": "vector-canvas-toolbar",
|
|
2006
|
-
"data-position": position,
|
|
2007
|
-
className,
|
|
2008
|
-
style: mergeStyle(base2, style),
|
|
2009
|
-
children: /* @__PURE__ */ jsx("div", { style: { pointerEvents: "auto" }, children })
|
|
2010
|
-
}
|
|
2011
|
-
);
|
|
2012
2806
|
}
|
|
2013
|
-
function
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2807
|
+
function useCanvuResolvedTools() {
|
|
2808
|
+
return useCanvuPluginContext().resolvedTools;
|
|
2809
|
+
}
|
|
2810
|
+
function useCanvuPluginContribution(pluginId, contribution) {
|
|
2811
|
+
const { registerContribution, unregisterContribution } = useCanvuPluginContext();
|
|
2812
|
+
useLayoutEffect(() => {
|
|
2813
|
+
registerContribution(pluginId, contribution);
|
|
2814
|
+
return () => unregisterContribution(pluginId);
|
|
2815
|
+
}, [contribution, pluginId, registerContribution, unregisterContribution]);
|
|
2816
|
+
}
|
|
2817
|
+
function ToolPluginComponent({
|
|
2818
|
+
pluginId,
|
|
2819
|
+
tool,
|
|
2820
|
+
toolTransform,
|
|
2821
|
+
createItem
|
|
2021
2822
|
}) {
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2823
|
+
const contribution = useMemo(
|
|
2824
|
+
() => ({
|
|
2825
|
+
tools: [tool],
|
|
2826
|
+
toolTransform,
|
|
2827
|
+
customPlacements: createItem ? [
|
|
2828
|
+
{
|
|
2829
|
+
toolId: tool.id,
|
|
2830
|
+
createItem
|
|
2831
|
+
}
|
|
2832
|
+
] : void 0
|
|
2833
|
+
}),
|
|
2834
|
+
[createItem, tool, toolTransform]
|
|
2030
2835
|
);
|
|
2836
|
+
useCanvuPluginContribution(pluginId, contribution);
|
|
2837
|
+
return null;
|
|
2031
2838
|
}
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
var
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
lineHeight: 1,
|
|
2063
|
-
color: "#18181b",
|
|
2064
|
-
padding: 0,
|
|
2065
|
-
border: "none",
|
|
2066
|
-
outline: "none",
|
|
2067
|
-
background: "none",
|
|
2068
|
-
WebkitTapHighlightColor: "transparent"
|
|
2839
|
+
function createToolPlugin(options) {
|
|
2840
|
+
const { createItem, toolTransform, ...tool } = options;
|
|
2841
|
+
const pluginId = `canvu.plugin.tool:${tool.id}`;
|
|
2842
|
+
return createCanvuPlugin({
|
|
2843
|
+
id: pluginId,
|
|
2844
|
+
Component() {
|
|
2845
|
+
return /* @__PURE__ */ jsx(
|
|
2846
|
+
ToolPluginComponent,
|
|
2847
|
+
{
|
|
2848
|
+
pluginId,
|
|
2849
|
+
tool,
|
|
2850
|
+
toolTransform,
|
|
2851
|
+
createItem
|
|
2852
|
+
}
|
|
2853
|
+
);
|
|
2854
|
+
}
|
|
2855
|
+
});
|
|
2856
|
+
}
|
|
2857
|
+
var menuStyle = {
|
|
2858
|
+
position: "fixed",
|
|
2859
|
+
zIndex: 1e4,
|
|
2860
|
+
minWidth: 200,
|
|
2861
|
+
padding: 4,
|
|
2862
|
+
backgroundColor: "#ffffff",
|
|
2863
|
+
border: "1px solid #e2e8f0",
|
|
2864
|
+
borderRadius: 8,
|
|
2865
|
+
boxShadow: "0 10px 40px rgba(15, 23, 42, 0.12)",
|
|
2866
|
+
fontSize: 13,
|
|
2867
|
+
fontFamily: "system-ui, sans-serif",
|
|
2868
|
+
color: "#0f172a"
|
|
2069
2869
|
};
|
|
2070
|
-
var
|
|
2071
|
-
|
|
2072
|
-
width:
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
justifyContent: "center",
|
|
2077
|
-
cursor: "pointer",
|
|
2078
|
-
fontSize: 12,
|
|
2079
|
-
lineHeight: 1,
|
|
2080
|
-
color: "#52525b",
|
|
2081
|
-
padding: 0,
|
|
2870
|
+
var itemStyle = {
|
|
2871
|
+
display: "block",
|
|
2872
|
+
width: "100%",
|
|
2873
|
+
textAlign: "left",
|
|
2874
|
+
padding: "8px 12px",
|
|
2875
|
+
margin: 0,
|
|
2082
2876
|
border: "none",
|
|
2083
|
-
|
|
2084
|
-
background: "
|
|
2085
|
-
|
|
2086
|
-
};
|
|
2087
|
-
var undoBtnStyle = {
|
|
2088
|
-
...chevronBtnStyle,
|
|
2089
|
-
width: 30,
|
|
2090
|
-
opacity: 1,
|
|
2091
|
-
color: "#18181b"
|
|
2092
|
-
};
|
|
2093
|
-
var labelStyle2 = {
|
|
2094
|
-
fontSize: 10,
|
|
2095
|
-
fontWeight: 600,
|
|
2096
|
-
color: "#52525b",
|
|
2097
|
-
textAlign: "center",
|
|
2098
|
-
userSelect: "none",
|
|
2099
|
-
padding: "2px 0"
|
|
2100
|
-
};
|
|
2101
|
-
var panelLayoutStyle = {
|
|
2102
|
-
display: "flex",
|
|
2103
|
-
flexDirection: "column",
|
|
2104
|
-
alignItems: "flex-start",
|
|
2105
|
-
gap: 4,
|
|
2106
|
-
touchAction: "none",
|
|
2107
|
-
pointerEvents: "none",
|
|
2108
|
-
userSelect: "none"
|
|
2877
|
+
borderRadius: 4,
|
|
2878
|
+
background: "transparent",
|
|
2879
|
+
cursor: "pointer"
|
|
2109
2880
|
};
|
|
2110
|
-
var
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
alignItems: "center",
|
|
2115
|
-
gap: 4,
|
|
2116
|
-
background: BG,
|
|
2117
|
-
borderRadius: BORDER_RADIUS,
|
|
2118
|
-
border: `1px solid ${BORDER_COLOR}`,
|
|
2119
|
-
boxShadow: "0 1px 3px rgba(0,0,0,0.08)",
|
|
2120
|
-
padding: 4
|
|
2881
|
+
var dividerStyle = {
|
|
2882
|
+
height: 1,
|
|
2883
|
+
margin: "4px 8px",
|
|
2884
|
+
background: "#e2e8f0"
|
|
2121
2885
|
};
|
|
2122
|
-
function
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
inset = 12,
|
|
2137
|
-
zIndex = 23,
|
|
2138
|
-
className,
|
|
2139
|
-
style
|
|
2886
|
+
function ShapeContextMenu({
|
|
2887
|
+
x,
|
|
2888
|
+
y,
|
|
2889
|
+
allSelectedLocked,
|
|
2890
|
+
onClose,
|
|
2891
|
+
onToggleLock,
|
|
2892
|
+
onCut,
|
|
2893
|
+
onCopy,
|
|
2894
|
+
onBringToFront,
|
|
2895
|
+
onBringForward,
|
|
2896
|
+
onSendBackward,
|
|
2897
|
+
onSendToBack,
|
|
2898
|
+
onDuplicate,
|
|
2899
|
+
onDelete
|
|
2140
2900
|
}) {
|
|
2141
|
-
const
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2901
|
+
const rootRef = useRef(null);
|
|
2902
|
+
useLayoutEffect(() => {
|
|
2903
|
+
const el = rootRef.current;
|
|
2904
|
+
if (!el) return;
|
|
2905
|
+
const pad = 8;
|
|
2906
|
+
const w = el.offsetWidth || 200;
|
|
2907
|
+
const h = el.offsetHeight || 160;
|
|
2908
|
+
let left = x;
|
|
2909
|
+
let top = y;
|
|
2910
|
+
if (left + w + pad > window.innerWidth) {
|
|
2911
|
+
left = Math.max(pad, window.innerWidth - w - pad);
|
|
2912
|
+
}
|
|
2913
|
+
if (top + h + pad > window.innerHeight) {
|
|
2914
|
+
top = Math.max(pad, window.innerHeight - h - pad);
|
|
2915
|
+
}
|
|
2916
|
+
el.style.left = `${left}px`;
|
|
2917
|
+
el.style.top = `${top}px`;
|
|
2918
|
+
}, [x, y]);
|
|
2919
|
+
useEffect(() => {
|
|
2920
|
+
const onKey = (e) => {
|
|
2921
|
+
if (e.key === "Escape") {
|
|
2922
|
+
onClose();
|
|
2923
|
+
}
|
|
2924
|
+
};
|
|
2925
|
+
const onPointerDown = (e) => {
|
|
2926
|
+
const t = e.target;
|
|
2927
|
+
if (t && rootRef.current?.contains(t)) {
|
|
2928
|
+
return;
|
|
2929
|
+
}
|
|
2930
|
+
onClose();
|
|
2931
|
+
};
|
|
2932
|
+
document.addEventListener("keydown", onKey);
|
|
2933
|
+
document.addEventListener("pointerdown", onPointerDown, true);
|
|
2934
|
+
return () => {
|
|
2935
|
+
document.removeEventListener("keydown", onKey);
|
|
2936
|
+
document.removeEventListener("pointerdown", onPointerDown, true);
|
|
2937
|
+
};
|
|
2938
|
+
}, [onClose]);
|
|
2939
|
+
const run = (fn) => () => {
|
|
2940
|
+
fn();
|
|
2941
|
+
onClose();
|
|
2176
2942
|
};
|
|
2177
|
-
const
|
|
2178
|
-
|
|
2179
|
-
worldX: (mx - PADDING) / scale + originX,
|
|
2180
|
-
worldY: (my - PADDING) / scale + originY
|
|
2181
|
-
}),
|
|
2182
|
-
[scale, originX, originY]
|
|
2183
|
-
);
|
|
2184
|
-
const panTo = useCallback(
|
|
2185
|
-
(mx, my) => {
|
|
2186
|
-
if (!camera) return;
|
|
2187
|
-
const { worldX, worldY } = worldFromMinimap(mx, my);
|
|
2188
|
-
camera.x = viewportWidth / 2 - worldX * camera.zoom;
|
|
2189
|
-
camera.y = viewportHeight / 2 - worldY * camera.zoom;
|
|
2190
|
-
onRequestRender();
|
|
2191
|
-
},
|
|
2192
|
-
[worldFromMinimap, camera, viewportWidth, viewportHeight, onRequestRender]
|
|
2193
|
-
);
|
|
2194
|
-
const handlePointerDown = useCallback(
|
|
2195
|
-
(e) => {
|
|
2196
|
-
if (isEmpty) return;
|
|
2197
|
-
setDragging(true);
|
|
2198
|
-
setMouseDown(true);
|
|
2199
|
-
const rect = svgRef.current?.getBoundingClientRect();
|
|
2200
|
-
if (!rect) return;
|
|
2201
|
-
panTo(e.clientX - rect.left, e.clientY - rect.top);
|
|
2202
|
-
svgRef.current?.setPointerCapture(e.pointerId);
|
|
2203
|
-
},
|
|
2204
|
-
[isEmpty, panTo]
|
|
2205
|
-
);
|
|
2206
|
-
const handlePointerMove = useCallback(
|
|
2207
|
-
(e) => {
|
|
2208
|
-
if (!mouseDown || isEmpty) return;
|
|
2209
|
-
const rect = svgRef.current?.getBoundingClientRect();
|
|
2210
|
-
if (!rect) return;
|
|
2211
|
-
panTo(e.clientX - rect.left, e.clientY - rect.top);
|
|
2212
|
-
},
|
|
2213
|
-
[mouseDown, isEmpty, panTo]
|
|
2214
|
-
);
|
|
2215
|
-
const handlePointerUp = useCallback(() => {
|
|
2216
|
-
setDragging(false);
|
|
2217
|
-
setMouseDown(false);
|
|
2218
|
-
}, []);
|
|
2219
|
-
const toggleExpanded = useCallback(() => {
|
|
2220
|
-
setExpanded((v) => !v);
|
|
2221
|
-
}, []);
|
|
2222
|
-
const anchorStyle = getBoardPositionStyle(position, inset, zIndex);
|
|
2223
|
-
return /* @__PURE__ */ jsxs(
|
|
2224
|
-
"fieldset",
|
|
2943
|
+
const renderAction = (label, onClick, options) => /* @__PURE__ */ jsx(
|
|
2944
|
+
"button",
|
|
2225
2945
|
{
|
|
2226
|
-
|
|
2227
|
-
"
|
|
2228
|
-
className,
|
|
2946
|
+
type: "button",
|
|
2947
|
+
role: "menuitem",
|
|
2229
2948
|
style: {
|
|
2230
|
-
...
|
|
2231
|
-
...
|
|
2232
|
-
border: "none",
|
|
2233
|
-
margin: 0,
|
|
2234
|
-
padding: 0,
|
|
2235
|
-
minWidth: 0,
|
|
2236
|
-
...style
|
|
2949
|
+
...itemStyle,
|
|
2950
|
+
...options?.danger ? { color: "#b91c1c" } : {}
|
|
2237
2951
|
},
|
|
2238
|
-
|
|
2952
|
+
onMouseEnter: (e) => {
|
|
2953
|
+
e.currentTarget.style.background = options?.danger ? "#fef2f2" : "#f1f5f9";
|
|
2954
|
+
},
|
|
2955
|
+
onMouseLeave: (e) => {
|
|
2956
|
+
e.currentTarget.style.background = "transparent";
|
|
2957
|
+
},
|
|
2958
|
+
onClick: run(onClick),
|
|
2959
|
+
children: label
|
|
2960
|
+
}
|
|
2961
|
+
);
|
|
2962
|
+
const menu = /* @__PURE__ */ jsxs(
|
|
2963
|
+
"div",
|
|
2964
|
+
{
|
|
2965
|
+
ref: rootRef,
|
|
2966
|
+
"data-slot": "shape-context-menu",
|
|
2967
|
+
style: { ...menuStyle, left: x, top: y },
|
|
2968
|
+
role: "menu",
|
|
2239
2969
|
children: [
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
onClick: onZoomOut,
|
|
2252
|
-
children: "\u2212"
|
|
2253
|
-
}
|
|
2254
|
-
),
|
|
2255
|
-
/* @__PURE__ */ jsxs("span", { style: labelStyle2, "aria-hidden": true, children: [
|
|
2256
|
-
zoomPercent,
|
|
2257
|
-
"%"
|
|
2258
|
-
] }),
|
|
2259
|
-
/* @__PURE__ */ jsx(
|
|
2260
|
-
"button",
|
|
2261
|
-
{
|
|
2262
|
-
type: "button",
|
|
2263
|
-
style: btnStyle,
|
|
2264
|
-
"aria-label": "Zoom in",
|
|
2265
|
-
title: "Zoom in",
|
|
2266
|
-
onPointerDown: (e) => {
|
|
2267
|
-
if (e.pointerType === "mouse") e.preventDefault();
|
|
2268
|
-
},
|
|
2269
|
-
onClick: onZoomIn,
|
|
2270
|
-
children: "+"
|
|
2271
|
-
}
|
|
2272
|
-
),
|
|
2273
|
-
/* @__PURE__ */ jsx(
|
|
2274
|
-
"button",
|
|
2275
|
-
{
|
|
2276
|
-
type: "button",
|
|
2277
|
-
style: undoBtnStyle,
|
|
2278
|
-
"aria-label": "Undo",
|
|
2279
|
-
title: "Undo",
|
|
2280
|
-
disabled: !canUndo,
|
|
2281
|
-
onPointerDown: (e) => {
|
|
2282
|
-
if (e.pointerType === "mouse") e.preventDefault();
|
|
2283
|
-
},
|
|
2284
|
-
onClick: onUndo,
|
|
2285
|
-
children: /* @__PURE__ */ jsx(Undo2, { size: 16 })
|
|
2286
|
-
}
|
|
2287
|
-
),
|
|
2288
|
-
/* @__PURE__ */ jsx(
|
|
2289
|
-
"button",
|
|
2290
|
-
{
|
|
2291
|
-
type: "button",
|
|
2292
|
-
style: undoBtnStyle,
|
|
2293
|
-
"aria-label": "Redo",
|
|
2294
|
-
title: "Redo",
|
|
2295
|
-
disabled: !canRedo,
|
|
2296
|
-
onPointerDown: (e) => {
|
|
2297
|
-
if (e.pointerType === "mouse") e.preventDefault();
|
|
2298
|
-
},
|
|
2299
|
-
onClick: onRedo,
|
|
2300
|
-
children: /* @__PURE__ */ jsx(Redo2, { size: 16 })
|
|
2301
|
-
}
|
|
2302
|
-
),
|
|
2303
|
-
/* @__PURE__ */ jsx(
|
|
2304
|
-
"button",
|
|
2305
|
-
{
|
|
2306
|
-
type: "button",
|
|
2307
|
-
style: chevronBtnStyle,
|
|
2308
|
-
"aria-label": expanded ? "Hide minimap" : "Show minimap",
|
|
2309
|
-
title: expanded ? "Hide minimap" : "Show minimap",
|
|
2310
|
-
onPointerDown: (e) => {
|
|
2311
|
-
if (e.pointerType === "mouse") e.preventDefault();
|
|
2312
|
-
},
|
|
2313
|
-
onClick: toggleExpanded,
|
|
2314
|
-
children: /* @__PURE__ */ jsx(
|
|
2315
|
-
"svg",
|
|
2316
|
-
{
|
|
2317
|
-
width: "12",
|
|
2318
|
-
height: "12",
|
|
2319
|
-
viewBox: "0 0 12 12",
|
|
2320
|
-
style: {
|
|
2321
|
-
transform: expanded ? "rotate(180deg)" : "rotate(0deg)",
|
|
2322
|
-
transition: "transform 0.15s ease"
|
|
2323
|
-
},
|
|
2324
|
-
"aria-hidden": true,
|
|
2325
|
-
children: /* @__PURE__ */ jsx(
|
|
2326
|
-
"path",
|
|
2327
|
-
{
|
|
2328
|
-
d: "M2 4 L6 8 L10 4",
|
|
2329
|
-
fill: "none",
|
|
2330
|
-
stroke: "currentColor",
|
|
2331
|
-
strokeWidth: "1.5",
|
|
2332
|
-
strokeLinecap: "round",
|
|
2333
|
-
strokeLinejoin: "round"
|
|
2334
|
-
}
|
|
2335
|
-
)
|
|
2336
|
-
}
|
|
2337
|
-
)
|
|
2338
|
-
}
|
|
2339
|
-
)
|
|
2340
|
-
] }),
|
|
2341
|
-
expanded && /* @__PURE__ */ jsx("nav", { "aria-label": "Minimap", children: /* @__PURE__ */ jsx(
|
|
2342
|
-
"svg",
|
|
2343
|
-
{
|
|
2344
|
-
ref: svgRef,
|
|
2345
|
-
style: {
|
|
2346
|
-
width: MINIMAP_W,
|
|
2347
|
-
height: MINIMAP_H,
|
|
2348
|
-
borderRadius: BORDER_RADIUS,
|
|
2349
|
-
border: `1px solid ${BORDER_COLOR}`,
|
|
2350
|
-
background: BG,
|
|
2351
|
-
boxShadow: "0 1px 3px rgba(0,0,0,0.08)",
|
|
2352
|
-
cursor: isEmpty ? "default" : dragging ? "grabbing" : "grab",
|
|
2353
|
-
display: "block",
|
|
2354
|
-
pointerEvents: "auto"
|
|
2355
|
-
},
|
|
2356
|
-
onPointerDown: handlePointerDown,
|
|
2357
|
-
onPointerMove: handlePointerMove,
|
|
2358
|
-
onPointerUp: handlePointerUp,
|
|
2359
|
-
onPointerCancel: handlePointerUp,
|
|
2360
|
-
children: isEmpty ? null : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2361
|
-
items.map((it) => {
|
|
2362
|
-
const b = normalizeRect(boundsAabbForRotatedItem(it));
|
|
2363
|
-
return /* @__PURE__ */ jsx(
|
|
2364
|
-
"rect",
|
|
2365
|
-
{
|
|
2366
|
-
x: toMinimapX(b.x),
|
|
2367
|
-
y: toMinimapY(b.y),
|
|
2368
|
-
width: toMinimapW(b.width),
|
|
2369
|
-
height: toMinimapH(b.height),
|
|
2370
|
-
fill: ITEM_FILL,
|
|
2371
|
-
stroke: ITEM_STROKE,
|
|
2372
|
-
strokeWidth: 0.5,
|
|
2373
|
-
rx: 1
|
|
2374
|
-
},
|
|
2375
|
-
it.id
|
|
2376
|
-
);
|
|
2377
|
-
}),
|
|
2378
|
-
/* @__PURE__ */ jsx(
|
|
2379
|
-
"rect",
|
|
2380
|
-
{
|
|
2381
|
-
x: vpMinimap.x,
|
|
2382
|
-
y: vpMinimap.y,
|
|
2383
|
-
width: vpMinimap.width,
|
|
2384
|
-
height: vpMinimap.height,
|
|
2385
|
-
fill: VIEWPORT_FILL,
|
|
2386
|
-
stroke: VIEWPORT_STROKE,
|
|
2387
|
-
strokeWidth: 1.5,
|
|
2388
|
-
rx: 2
|
|
2389
|
-
}
|
|
2390
|
-
)
|
|
2391
|
-
] })
|
|
2392
|
-
}
|
|
2393
|
-
) })
|
|
2970
|
+
renderAction("Recortar", onCut),
|
|
2971
|
+
renderAction("Copiar", onCopy),
|
|
2972
|
+
renderAction("Duplicar", onDuplicate),
|
|
2973
|
+
/* @__PURE__ */ jsx("div", { "aria-hidden": true, style: dividerStyle }),
|
|
2974
|
+
renderAction("Trazer para frente", onBringToFront),
|
|
2975
|
+
renderAction("Avancar uma camada", onBringForward),
|
|
2976
|
+
renderAction("Recuar uma camada", onSendBackward),
|
|
2977
|
+
renderAction("Enviar para tras", onSendToBack),
|
|
2978
|
+
/* @__PURE__ */ jsx("div", { "aria-hidden": true, style: dividerStyle }),
|
|
2979
|
+
renderAction(allSelectedLocked ? "Desbloquear" : "Bloquear", onToggleLock),
|
|
2980
|
+
renderAction("Apagar", onDelete, { danger: true })
|
|
2394
2981
|
]
|
|
2395
2982
|
}
|
|
2396
2983
|
);
|
|
2984
|
+
if (typeof document === "undefined") {
|
|
2985
|
+
return null;
|
|
2986
|
+
}
|
|
2987
|
+
return createPortal(menu, document.body);
|
|
2397
2988
|
}
|
|
2398
|
-
|
|
2989
|
+
var base = {
|
|
2990
|
+
width: 20,
|
|
2991
|
+
height: 20,
|
|
2992
|
+
viewBox: "0 0 24 24",
|
|
2993
|
+
fill: "none",
|
|
2994
|
+
stroke: "currentColor",
|
|
2995
|
+
strokeWidth: 2,
|
|
2996
|
+
strokeLinecap: "round",
|
|
2997
|
+
strokeLinejoin: "round"
|
|
2998
|
+
};
|
|
2999
|
+
function IconHand(props) {
|
|
3000
|
+
return /* @__PURE__ */ jsxs("svg", { ...base, ...props, "aria-hidden": true, children: [
|
|
3001
|
+
/* @__PURE__ */ jsx("path", { d: "M18 11V6a2 2 0 0 0-2-2v0a2 2 0 0 0-2 2v0" }),
|
|
3002
|
+
/* @__PURE__ */ jsx("path", { d: "M14 10V4a2 2 0 0 0-2-2v0a2 2 0 0 0-2 2v2" }),
|
|
3003
|
+
/* @__PURE__ */ jsx("path", { d: "M10 10.5V6a2 2 0 0 0-2-2v0a2 2 0 0 0-2 2v8" }),
|
|
3004
|
+
/* @__PURE__ */ jsx("path", { d: "M18 8a2 2 0 1 1 4 0v5a8 8 0 0 1-8 8h-2c-2.8 0-4.5-.86-5.99-2.34l-3.6-3.6a2 2 0 0 1 2.83-2.82L7 15" })
|
|
3005
|
+
] });
|
|
2399
3006
|
}
|
|
2400
|
-
function
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
let minY = Infinity;
|
|
2406
|
-
let maxX = -Infinity;
|
|
2407
|
-
let maxY = -Infinity;
|
|
2408
|
-
for (const it of items) {
|
|
2409
|
-
const b = boundsAabbForRotatedItem(it);
|
|
2410
|
-
minX = Math.min(minX, b.x);
|
|
2411
|
-
minY = Math.min(minY, b.y);
|
|
2412
|
-
maxX = Math.max(maxX, b.x + b.width);
|
|
2413
|
-
maxY = Math.max(maxY, b.y + b.height);
|
|
2414
|
-
}
|
|
2415
|
-
const pad = Math.max((maxX - minX) * 0.1, (maxY - minY) * 0.1, 40);
|
|
2416
|
-
return {
|
|
2417
|
-
x: minX - pad,
|
|
2418
|
-
y: minY - pad,
|
|
2419
|
-
width: maxX - minX + pad * 2,
|
|
2420
|
-
height: maxY - minY + pad * 2
|
|
2421
|
-
};
|
|
3007
|
+
function IconSelect(props) {
|
|
3008
|
+
return /* @__PURE__ */ jsxs("svg", { ...base, ...props, "aria-hidden": true, children: [
|
|
3009
|
+
/* @__PURE__ */ jsx("path", { d: "M3 3l7.07 16.97 2.51-7.39 7.39-2.51L3 3z" }),
|
|
3010
|
+
/* @__PURE__ */ jsx("path", { d: "M13 13l6 6" })
|
|
3011
|
+
] });
|
|
2422
3012
|
}
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
init_shape_builders();
|
|
2426
|
-
var DOCUMENT_STORE = "document";
|
|
2427
|
-
var DOCUMENT_KEY = "main";
|
|
2428
|
-
function openDocumentDb(dbName) {
|
|
2429
|
-
return new Promise((resolve, reject) => {
|
|
2430
|
-
const req = indexedDB.open(dbName, 1);
|
|
2431
|
-
req.onupgradeneeded = () => {
|
|
2432
|
-
const db = req.result;
|
|
2433
|
-
if (!db.objectStoreNames.contains(DOCUMENT_STORE)) {
|
|
2434
|
-
db.createObjectStore(DOCUMENT_STORE);
|
|
2435
|
-
}
|
|
2436
|
-
};
|
|
2437
|
-
req.onsuccess = () => resolve(req.result);
|
|
2438
|
-
req.onerror = () => reject(req.error);
|
|
2439
|
-
});
|
|
3013
|
+
function IconRect(props) {
|
|
3014
|
+
return /* @__PURE__ */ jsx("svg", { ...base, ...props, "aria-hidden": true, children: /* @__PURE__ */ jsx("rect", { x: "4", y: "4", width: "16", height: "16", rx: "2" }) });
|
|
2440
3015
|
}
|
|
2441
|
-
function
|
|
2442
|
-
|
|
2443
|
-
const imageStore = new IndexedDbImageStore();
|
|
2444
|
-
let documentDbPromise = null;
|
|
2445
|
-
function getDocDb() {
|
|
2446
|
-
if (!documentDbPromise) {
|
|
2447
|
-
documentDbPromise = openDocumentDb(dbName);
|
|
2448
|
-
}
|
|
2449
|
-
return documentDbPromise;
|
|
2450
|
-
}
|
|
2451
|
-
async function getFromDocDb(key) {
|
|
2452
|
-
const db = await getDocDb();
|
|
2453
|
-
return new Promise((resolve, reject) => {
|
|
2454
|
-
const tx = db.transaction(DOCUMENT_STORE, "readonly");
|
|
2455
|
-
const req = tx.objectStore(DOCUMENT_STORE).get(key);
|
|
2456
|
-
req.onsuccess = () => resolve(req.result);
|
|
2457
|
-
req.onerror = () => reject(req.error);
|
|
2458
|
-
});
|
|
2459
|
-
}
|
|
2460
|
-
async function putInDocDb(key, value) {
|
|
2461
|
-
const db = await getDocDb();
|
|
2462
|
-
return new Promise((resolve, reject) => {
|
|
2463
|
-
const tx = db.transaction(DOCUMENT_STORE, "readwrite");
|
|
2464
|
-
const req = tx.objectStore(DOCUMENT_STORE).put(value, key);
|
|
2465
|
-
req.onsuccess = () => resolve();
|
|
2466
|
-
req.onerror = () => reject(req.error);
|
|
2467
|
-
});
|
|
2468
|
-
}
|
|
2469
|
-
const revokedHrefs = /* @__PURE__ */ new Set();
|
|
2470
|
-
function revokeItemBlob(item) {
|
|
2471
|
-
if (item.imageRasterHref?.startsWith("blob:")) {
|
|
2472
|
-
revokedHrefs.add(item.imageRasterHref);
|
|
2473
|
-
}
|
|
2474
|
-
if (item.imageThumbnailHref?.startsWith("blob:")) {
|
|
2475
|
-
revokedHrefs.add(item.imageThumbnailHref);
|
|
2476
|
-
}
|
|
2477
|
-
const out = { ...item };
|
|
2478
|
-
delete out.imageRasterHref;
|
|
2479
|
-
delete out.imageThumbnailHref;
|
|
2480
|
-
if (item.toolKind === "image") {
|
|
2481
|
-
out.childrenSvg = "";
|
|
2482
|
-
}
|
|
2483
|
-
return out;
|
|
2484
|
-
}
|
|
2485
|
-
return {
|
|
2486
|
-
async load() {
|
|
2487
|
-
const raw = await getFromDocDb(DOCUMENT_KEY);
|
|
2488
|
-
if (!raw?.items) return null;
|
|
2489
|
-
const resolved = [];
|
|
2490
|
-
for (const item of raw.items) {
|
|
2491
|
-
if (item.toolKind === "image" && item.imageBlobId) {
|
|
2492
|
-
const itemWithBlob = { ...item };
|
|
2493
|
-
if (item.imageThumbnailBlobId) {
|
|
2494
|
-
const thumbUrl = await createThumbnailBlobUrlFromStore(
|
|
2495
|
-
imageStore,
|
|
2496
|
-
item.imageThumbnailBlobId
|
|
2497
|
-
);
|
|
2498
|
-
if (thumbUrl) {
|
|
2499
|
-
itemWithBlob.imageThumbnailHref = thumbUrl;
|
|
2500
|
-
}
|
|
2501
|
-
}
|
|
2502
|
-
const fullUrl = await createBlobUrlFromStore(imageStore, item.imageBlobId);
|
|
2503
|
-
if (fullUrl) {
|
|
2504
|
-
itemWithBlob.imageRasterHref = fullUrl;
|
|
2505
|
-
}
|
|
2506
|
-
const rebuilt = rebuildItemSvg(itemWithBlob);
|
|
2507
|
-
resolved.push(rebuilt);
|
|
2508
|
-
} else {
|
|
2509
|
-
resolved.push(item);
|
|
2510
|
-
}
|
|
2511
|
-
}
|
|
2512
|
-
return { items: resolved, version: raw.version ?? 1 };
|
|
2513
|
-
},
|
|
2514
|
-
async save(snapshot) {
|
|
2515
|
-
for (const href of revokedHrefs) {
|
|
2516
|
-
URL.revokeObjectURL(href);
|
|
2517
|
-
}
|
|
2518
|
-
revokedHrefs.clear();
|
|
2519
|
-
const cleanItems = snapshot.items.map(revokeItemBlob);
|
|
2520
|
-
await putInDocDb(DOCUMENT_KEY, {
|
|
2521
|
-
items: cleanItems,
|
|
2522
|
-
version: snapshot.version ?? 1
|
|
2523
|
-
});
|
|
2524
|
-
}
|
|
2525
|
-
};
|
|
3016
|
+
function IconEllipse(props) {
|
|
3017
|
+
return /* @__PURE__ */ jsx("svg", { ...base, ...props, "aria-hidden": true, children: /* @__PURE__ */ jsx("ellipse", { cx: "12", cy: "12", rx: "9", ry: "6" }) });
|
|
2526
3018
|
}
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
var DEFAULT_VECTOR_CANVAS_STORAGE_KEY = "trazo.vector-canvas.v1";
|
|
2530
|
-
var SNAPSHOT_VERSION = 1;
|
|
2531
|
-
function createLocalStoragePersistenceAdapter(options = {}) {
|
|
2532
|
-
const key = options.key ?? DEFAULT_VECTOR_CANVAS_STORAGE_KEY;
|
|
2533
|
-
const storage = options.storage ?? (typeof globalThis !== "undefined" && "localStorage" in globalThis && globalThis.localStorage ? globalThis.localStorage : null);
|
|
2534
|
-
return {
|
|
2535
|
-
load() {
|
|
2536
|
-
if (!storage) return Promise.resolve(null);
|
|
2537
|
-
try {
|
|
2538
|
-
const raw = storage.getItem(key);
|
|
2539
|
-
if (!raw) return Promise.resolve(null);
|
|
2540
|
-
const parsed = JSON.parse(raw);
|
|
2541
|
-
if (!parsed || typeof parsed !== "object" || !("items" in parsed) || !Array.isArray(parsed.items)) {
|
|
2542
|
-
return Promise.resolve(null);
|
|
2543
|
-
}
|
|
2544
|
-
return Promise.resolve(parsed);
|
|
2545
|
-
} catch {
|
|
2546
|
-
return Promise.resolve(null);
|
|
2547
|
-
}
|
|
2548
|
-
},
|
|
2549
|
-
save(snapshot) {
|
|
2550
|
-
if (!storage) return Promise.resolve();
|
|
2551
|
-
try {
|
|
2552
|
-
storage.setItem(
|
|
2553
|
-
key,
|
|
2554
|
-
JSON.stringify({
|
|
2555
|
-
...snapshot,
|
|
2556
|
-
version: snapshot.version ?? SNAPSHOT_VERSION
|
|
2557
|
-
})
|
|
2558
|
-
);
|
|
2559
|
-
} catch {
|
|
2560
|
-
}
|
|
2561
|
-
return Promise.resolve();
|
|
2562
|
-
}
|
|
2563
|
-
};
|
|
3019
|
+
function IconLine(props) {
|
|
3020
|
+
return /* @__PURE__ */ jsx("svg", { ...base, ...props, "aria-hidden": true, children: /* @__PURE__ */ jsx("line", { x1: "5", y1: "19", x2: "19", y2: "5" }) });
|
|
2564
3021
|
}
|
|
2565
|
-
function
|
|
2566
|
-
return {
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
};
|
|
2570
|
-
}
|
|
2571
|
-
function useVectorCanvasDocument(options = {}) {
|
|
2572
|
-
const {
|
|
2573
|
-
persistenceKey = DEFAULT_VECTOR_CANVAS_STORAGE_KEY,
|
|
2574
|
-
persistence,
|
|
2575
|
-
debounceMs = 400,
|
|
2576
|
-
remote
|
|
2577
|
-
} = options;
|
|
2578
|
-
const adapter = useMemo(() => {
|
|
2579
|
-
if (persistence === false) return createNoopPersistenceAdapter();
|
|
2580
|
-
if (persistence) return persistence;
|
|
2581
|
-
return createLocalStoragePersistenceAdapter({ key: persistenceKey });
|
|
2582
|
-
}, [persistence, persistenceKey]);
|
|
2583
|
-
const [items, setItems] = useState([]);
|
|
2584
|
-
const [isHydrated, setIsHydrated] = useState(false);
|
|
2585
|
-
const saveTimerRef = useRef(null);
|
|
2586
|
-
const adapterRef = useRef(adapter);
|
|
2587
|
-
adapterRef.current = adapter;
|
|
2588
|
-
useEffect(() => {
|
|
2589
|
-
let cancelled = false;
|
|
2590
|
-
adapter.load().then((snap) => {
|
|
2591
|
-
if (cancelled) return;
|
|
2592
|
-
if (snap?.items && snap.items.length > 0) {
|
|
2593
|
-
setItems(snap.items);
|
|
2594
|
-
}
|
|
2595
|
-
setIsHydrated(true);
|
|
2596
|
-
});
|
|
2597
|
-
return () => {
|
|
2598
|
-
cancelled = true;
|
|
2599
|
-
};
|
|
2600
|
-
}, [adapter]);
|
|
2601
|
-
const persist = useCallback((next) => {
|
|
2602
|
-
void adapterRef.current.save({ items: next, version: 1 });
|
|
2603
|
-
}, []);
|
|
2604
|
-
const onItemsChange = useCallback(
|
|
2605
|
-
(next) => {
|
|
2606
|
-
setItems(next);
|
|
2607
|
-
remote?.send?.(next);
|
|
2608
|
-
if (saveTimerRef.current) clearTimeout(saveTimerRef.current);
|
|
2609
|
-
saveTimerRef.current = setTimeout(() => {
|
|
2610
|
-
persist(next);
|
|
2611
|
-
saveTimerRef.current = null;
|
|
2612
|
-
}, debounceMs);
|
|
2613
|
-
},
|
|
2614
|
-
[debounceMs, persist, remote]
|
|
2615
|
-
);
|
|
2616
|
-
useEffect(() => {
|
|
2617
|
-
if (!remote || !isHydrated) return;
|
|
2618
|
-
return remote.subscribe((serverItems) => {
|
|
2619
|
-
setItems(serverItems);
|
|
2620
|
-
persist(serverItems);
|
|
2621
|
-
});
|
|
2622
|
-
}, [remote, isHydrated, persist]);
|
|
2623
|
-
useEffect(
|
|
2624
|
-
() => () => {
|
|
2625
|
-
if (saveTimerRef.current) clearTimeout(saveTimerRef.current);
|
|
2626
|
-
},
|
|
2627
|
-
[]
|
|
2628
|
-
);
|
|
2629
|
-
const clearPersistedDocument = useCallback(() => {
|
|
2630
|
-
setItems([]);
|
|
2631
|
-
void adapterRef.current.save({ items: [], version: 1 });
|
|
2632
|
-
}, []);
|
|
2633
|
-
return {
|
|
2634
|
-
items,
|
|
2635
|
-
onItemsChange,
|
|
2636
|
-
setItems: onItemsChange,
|
|
2637
|
-
isHydrated,
|
|
2638
|
-
clearPersistedDocument
|
|
2639
|
-
};
|
|
3022
|
+
function IconArrow(props) {
|
|
3023
|
+
return /* @__PURE__ */ jsxs("svg", { ...base, ...props, "aria-hidden": true, children: [
|
|
3024
|
+
/* @__PURE__ */ jsx("line", { x1: "5", y1: "19", x2: "19", y2: "5" }),
|
|
3025
|
+
/* @__PURE__ */ jsx("polyline", { points: "12 5 19 5 19 12" })
|
|
3026
|
+
] });
|
|
2640
3027
|
}
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
)
|
|
2644
|
-
|
|
2645
|
-
|
|
3028
|
+
function IconDraw(props) {
|
|
3029
|
+
return /* @__PURE__ */ jsxs("svg", { ...base, ...props, "aria-hidden": true, children: [
|
|
3030
|
+
/* @__PURE__ */ jsx("path", { d: "M12 19l7-7 3 3-7 7-3-3z" }),
|
|
3031
|
+
/* @__PURE__ */ jsx("path", { d: "M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z" }),
|
|
3032
|
+
/* @__PURE__ */ jsx("path", { d: "M2 2l7.586 7.586" }),
|
|
3033
|
+
/* @__PURE__ */ jsx("circle", { cx: "11", cy: "11", r: "2" })
|
|
3034
|
+
] });
|
|
2646
3035
|
}
|
|
2647
|
-
function
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
}
|
|
2654
|
-
return ctx;
|
|
3036
|
+
function IconText(props) {
|
|
3037
|
+
return /* @__PURE__ */ jsxs("svg", { ...base, ...props, "aria-hidden": true, children: [
|
|
3038
|
+
/* @__PURE__ */ jsx("path", { d: "M4 7V5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2" }),
|
|
3039
|
+
/* @__PURE__ */ jsx("path", { d: "M9 21h6" }),
|
|
3040
|
+
/* @__PURE__ */ jsx("path", { d: "M12 3v18" })
|
|
3041
|
+
] });
|
|
2655
3042
|
}
|
|
2656
|
-
function
|
|
2657
|
-
|
|
2658
|
-
|
|
3043
|
+
function IconImage(props) {
|
|
3044
|
+
return /* @__PURE__ */ jsxs("svg", { ...base, ...props, "aria-hidden": true, children: [
|
|
3045
|
+
/* @__PURE__ */ jsx("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
|
|
3046
|
+
/* @__PURE__ */ jsx("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
|
|
3047
|
+
/* @__PURE__ */ jsx("polyline", { points: "21 15 16 10 5 21" })
|
|
3048
|
+
] });
|
|
2659
3049
|
}
|
|
2660
|
-
function
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
3050
|
+
function IconLaser(props) {
|
|
3051
|
+
return /* @__PURE__ */ jsxs("svg", { ...base, ...props, "aria-hidden": true, children: [
|
|
3052
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "2.5" }),
|
|
3053
|
+
/* @__PURE__ */ jsx("path", { d: "M12 4v4" }),
|
|
3054
|
+
/* @__PURE__ */ jsx("path", { d: "M12 16v4" }),
|
|
3055
|
+
/* @__PURE__ */ jsx("path", { d: "M4 12h4" }),
|
|
3056
|
+
/* @__PURE__ */ jsx("path", { d: "M16 12h4" })
|
|
3057
|
+
] });
|
|
2666
3058
|
}
|
|
2667
|
-
|
|
2668
|
-
|
|
3059
|
+
var ic = { size: 20, strokeWidth: 2 };
|
|
3060
|
+
var DEFAULT_OVERFLOW_TOOL_IDS = [
|
|
3061
|
+
"rect",
|
|
3062
|
+
"ellipse",
|
|
3063
|
+
"line",
|
|
3064
|
+
"marker",
|
|
3065
|
+
"laser",
|
|
3066
|
+
"image"
|
|
3067
|
+
];
|
|
3068
|
+
var DEFAULT_VECTOR_TOOLS = [
|
|
3069
|
+
{
|
|
3070
|
+
id: "hand",
|
|
3071
|
+
label: "Hand",
|
|
3072
|
+
icon: /* @__PURE__ */ jsx(Hand, { ...ic, "aria-hidden": true }),
|
|
3073
|
+
shortcutHint: "H"
|
|
3074
|
+
},
|
|
3075
|
+
{
|
|
3076
|
+
id: "select",
|
|
3077
|
+
label: "Select",
|
|
3078
|
+
icon: /* @__PURE__ */ jsx(MousePointer2, { ...ic, "aria-hidden": true }),
|
|
3079
|
+
shortcutHint: "V"
|
|
3080
|
+
},
|
|
3081
|
+
{
|
|
3082
|
+
id: "rect",
|
|
3083
|
+
label: "Rectangle",
|
|
3084
|
+
icon: /* @__PURE__ */ jsx(Square, { ...ic, "aria-hidden": true }),
|
|
3085
|
+
shortcutHint: "R"
|
|
3086
|
+
},
|
|
3087
|
+
{
|
|
3088
|
+
id: "ellipse",
|
|
3089
|
+
label: "Ellipse",
|
|
3090
|
+
icon: /* @__PURE__ */ jsx(Circle, { ...ic, "aria-hidden": true }),
|
|
3091
|
+
shortcutHint: "O"
|
|
3092
|
+
},
|
|
3093
|
+
{
|
|
3094
|
+
id: "line",
|
|
3095
|
+
label: "Line",
|
|
3096
|
+
icon: /* @__PURE__ */ jsx(Minus, { ...ic, "aria-hidden": true }),
|
|
3097
|
+
shortcutHint: "L"
|
|
3098
|
+
},
|
|
3099
|
+
{
|
|
3100
|
+
id: "arrow",
|
|
3101
|
+
label: "Arrow",
|
|
3102
|
+
icon: /* @__PURE__ */ jsx(ArrowUpRight, { ...ic, "aria-hidden": true }),
|
|
3103
|
+
shortcutHint: "A"
|
|
3104
|
+
},
|
|
3105
|
+
{
|
|
3106
|
+
id: "draw",
|
|
3107
|
+
label: "Desenhar",
|
|
3108
|
+
tooltipLabel: "Draw",
|
|
3109
|
+
icon: /* @__PURE__ */ jsx(PenLine, { ...ic, "aria-hidden": true }),
|
|
3110
|
+
shortcutHint: "D"
|
|
3111
|
+
},
|
|
3112
|
+
{
|
|
3113
|
+
id: "marker",
|
|
3114
|
+
label: "Realce",
|
|
3115
|
+
tooltipLabel: "Highlighter",
|
|
3116
|
+
icon: /* @__PURE__ */ jsx(Highlighter, { ...ic, "aria-hidden": true }),
|
|
3117
|
+
shortcutHint: "M"
|
|
3118
|
+
},
|
|
3119
|
+
{
|
|
3120
|
+
id: "laser",
|
|
3121
|
+
label: "Laser",
|
|
3122
|
+
icon: /* @__PURE__ */ jsx(IconLaser, { "aria-hidden": true }),
|
|
3123
|
+
shortcutHint: "K"
|
|
3124
|
+
},
|
|
3125
|
+
{
|
|
3126
|
+
id: "eraser",
|
|
3127
|
+
label: "Borracha",
|
|
3128
|
+
tooltipLabel: "Eraser",
|
|
3129
|
+
icon: /* @__PURE__ */ jsx(Eraser, { ...ic, "aria-hidden": true }),
|
|
3130
|
+
shortcutHint: "E"
|
|
3131
|
+
},
|
|
3132
|
+
{
|
|
3133
|
+
id: "text",
|
|
3134
|
+
label: "Text",
|
|
3135
|
+
icon: /* @__PURE__ */ jsx(Type, { ...ic, "aria-hidden": true }),
|
|
3136
|
+
shortcutHint: "T"
|
|
3137
|
+
},
|
|
3138
|
+
{
|
|
3139
|
+
id: "image",
|
|
3140
|
+
label: "File",
|
|
3141
|
+
icon: /* @__PURE__ */ jsx(Image$1, { ...ic, "aria-hidden": true }),
|
|
3142
|
+
shortcutHint: "I"
|
|
3143
|
+
}
|
|
3144
|
+
];
|
|
3145
|
+
var shellLook = {
|
|
3146
|
+
display: "flex",
|
|
3147
|
+
flexDirection: "column",
|
|
3148
|
+
gap: 8,
|
|
3149
|
+
minWidth: 160,
|
|
3150
|
+
padding: "10px 12px",
|
|
3151
|
+
borderRadius: 8,
|
|
3152
|
+
border: "1px solid rgba(0,0,0,0.12)",
|
|
3153
|
+
background: "rgba(255,255,255,0.96)",
|
|
3154
|
+
boxShadow: "0 1px 3px rgba(0,0,0,0.08)",
|
|
3155
|
+
pointerEvents: "auto"
|
|
3156
|
+
};
|
|
3157
|
+
var labelStyle2 = {
|
|
3158
|
+
display: "flex",
|
|
3159
|
+
flexDirection: "column",
|
|
3160
|
+
gap: 4,
|
|
3161
|
+
fontSize: 11,
|
|
3162
|
+
fontWeight: 600,
|
|
3163
|
+
color: "#52525b"
|
|
3164
|
+
};
|
|
3165
|
+
function normalizeHex(stroke) {
|
|
3166
|
+
if (/^#[0-9A-Fa-f]{6}$/.test(stroke)) return stroke;
|
|
3167
|
+
return "#2563eb";
|
|
2669
3168
|
}
|
|
2670
|
-
function
|
|
2671
|
-
|
|
2672
|
-
useLayoutEffect(() => {
|
|
2673
|
-
registerContribution(pluginId, contribution);
|
|
2674
|
-
return () => unregisterContribution(pluginId);
|
|
2675
|
-
}, [contribution, pluginId, registerContribution, unregisterContribution]);
|
|
3169
|
+
function isStylableKind(tk) {
|
|
3170
|
+
return tk === "rect" || tk === "ellipse" || tk === "line" || tk === "arrow" || tk === "draw" || tk === "pencil" || tk === "brush" || tk === "marker" || tk === "text";
|
|
2676
3171
|
}
|
|
2677
|
-
function
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
toolTransform,
|
|
2687
|
-
customPlacements: createItem ? [
|
|
2688
|
-
{
|
|
2689
|
-
toolId: tool.id,
|
|
2690
|
-
createItem
|
|
2691
|
-
}
|
|
2692
|
-
] : void 0
|
|
2693
|
-
}),
|
|
2694
|
-
[createItem, tool, toolTransform]
|
|
2695
|
-
);
|
|
2696
|
-
useCanvuPluginContribution(pluginId, contribution);
|
|
2697
|
-
return null;
|
|
2698
|
-
}
|
|
2699
|
-
function createToolPlugin(options) {
|
|
2700
|
-
const { createItem, toolTransform, ...tool } = options;
|
|
2701
|
-
const pluginId = `canvu.plugin.tool:${tool.id}`;
|
|
2702
|
-
return createCanvuPlugin({
|
|
2703
|
-
id: pluginId,
|
|
2704
|
-
Component() {
|
|
2705
|
-
return /* @__PURE__ */ jsx(
|
|
2706
|
-
ToolPluginComponent,
|
|
2707
|
-
{
|
|
2708
|
-
pluginId,
|
|
2709
|
-
tool,
|
|
2710
|
-
toolTransform,
|
|
2711
|
-
createItem
|
|
2712
|
-
}
|
|
2713
|
-
);
|
|
2714
|
-
}
|
|
2715
|
-
});
|
|
2716
|
-
}
|
|
2717
|
-
var menuStyle = {
|
|
2718
|
-
position: "fixed",
|
|
2719
|
-
zIndex: 1e4,
|
|
2720
|
-
minWidth: 200,
|
|
2721
|
-
padding: 4,
|
|
2722
|
-
backgroundColor: "#ffffff",
|
|
2723
|
-
border: "1px solid #e2e8f0",
|
|
2724
|
-
borderRadius: 8,
|
|
2725
|
-
boxShadow: "0 10px 40px rgba(15, 23, 42, 0.12)",
|
|
2726
|
-
fontSize: 13,
|
|
2727
|
-
fontFamily: "system-ui, sans-serif",
|
|
2728
|
-
color: "#0f172a"
|
|
2729
|
-
};
|
|
2730
|
-
var itemStyle = {
|
|
2731
|
-
display: "block",
|
|
2732
|
-
width: "100%",
|
|
2733
|
-
textAlign: "left",
|
|
2734
|
-
padding: "8px 12px",
|
|
2735
|
-
margin: 0,
|
|
2736
|
-
border: "none",
|
|
2737
|
-
borderRadius: 4,
|
|
2738
|
-
background: "transparent",
|
|
2739
|
-
cursor: "pointer"
|
|
2740
|
-
};
|
|
2741
|
-
var dividerStyle = {
|
|
2742
|
-
height: 1,
|
|
2743
|
-
margin: "4px 8px",
|
|
2744
|
-
background: "#e2e8f0"
|
|
2745
|
-
};
|
|
2746
|
-
function ShapeContextMenu({
|
|
2747
|
-
x,
|
|
2748
|
-
y,
|
|
2749
|
-
allSelectedLocked,
|
|
2750
|
-
onClose,
|
|
2751
|
-
onToggleLock,
|
|
2752
|
-
onCut,
|
|
2753
|
-
onCopy,
|
|
2754
|
-
onBringToFront,
|
|
2755
|
-
onBringForward,
|
|
2756
|
-
onSendBackward,
|
|
2757
|
-
onSendToBack,
|
|
2758
|
-
onDuplicate,
|
|
2759
|
-
onDelete
|
|
3172
|
+
function VectorSelectionInspector({
|
|
3173
|
+
items: itemsProp,
|
|
3174
|
+
activeToolStyle: activeToolStyleProp,
|
|
3175
|
+
onChange: onChangeProp,
|
|
3176
|
+
position = "top-left",
|
|
3177
|
+
inset = 12,
|
|
3178
|
+
zIndex = 24,
|
|
3179
|
+
className,
|
|
3180
|
+
style
|
|
2760
3181
|
}) {
|
|
2761
|
-
const
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
if (left + w + pad > window.innerWidth) {
|
|
2771
|
-
left = Math.max(pad, window.innerWidth - w - pad);
|
|
2772
|
-
}
|
|
2773
|
-
if (top + h + pad > window.innerHeight) {
|
|
2774
|
-
top = Math.max(pad, window.innerHeight - h - pad);
|
|
2775
|
-
}
|
|
2776
|
-
el.style.left = `${left}px`;
|
|
2777
|
-
el.style.top = `${top}px`;
|
|
2778
|
-
}, [x, y]);
|
|
2779
|
-
useEffect(() => {
|
|
2780
|
-
const onKey = (e) => {
|
|
2781
|
-
if (e.key === "Escape") {
|
|
2782
|
-
onClose();
|
|
2783
|
-
}
|
|
2784
|
-
};
|
|
2785
|
-
const onPointerDown = (e) => {
|
|
2786
|
-
const t = e.target;
|
|
2787
|
-
if (t && rootRef.current?.contains(t)) {
|
|
2788
|
-
return;
|
|
2789
|
-
}
|
|
2790
|
-
onClose();
|
|
2791
|
-
};
|
|
2792
|
-
document.addEventListener("keydown", onKey);
|
|
2793
|
-
document.addEventListener("pointerdown", onPointerDown, true);
|
|
2794
|
-
return () => {
|
|
2795
|
-
document.removeEventListener("keydown", onKey);
|
|
2796
|
-
document.removeEventListener("pointerdown", onPointerDown, true);
|
|
2797
|
-
};
|
|
2798
|
-
}, [onClose]);
|
|
2799
|
-
const run = (fn) => () => {
|
|
2800
|
-
fn();
|
|
2801
|
-
onClose();
|
|
3182
|
+
const ctx = useCanvuChromeContext();
|
|
3183
|
+
const items = itemsProp ?? ctx?.selectedItems ?? [];
|
|
3184
|
+
const activeToolStyle = activeToolStyleProp === void 0 ? ctx?.activeToolStyle ?? null : activeToolStyleProp;
|
|
3185
|
+
const onChange = onChangeProp ?? ctx?.onSelectionStyleChange ?? null;
|
|
3186
|
+
if (!onChange) return null;
|
|
3187
|
+
const shell = {
|
|
3188
|
+
...getBoardPositionStyle(position, inset, zIndex),
|
|
3189
|
+
...shellLook,
|
|
3190
|
+
...style
|
|
2802
3191
|
};
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
3192
|
+
if (activeToolStyle) {
|
|
3193
|
+
const stroke2 = activeToolStyle.stroke;
|
|
3194
|
+
const strokeWidth2 = activeToolStyle.strokeWidth;
|
|
3195
|
+
const hex2 = normalizeHex(stroke2);
|
|
3196
|
+
const showMarkerOpacity2 = activeToolStyle.toolKind === "marker";
|
|
3197
|
+
const opacityPct2 = Math.round((activeToolStyle.strokeOpacity ?? 1) * 100);
|
|
3198
|
+
return /* @__PURE__ */ jsxs(
|
|
3199
|
+
"section",
|
|
3200
|
+
{
|
|
3201
|
+
"data-slot": "vector-selection-inspector",
|
|
3202
|
+
"data-position": position,
|
|
3203
|
+
className,
|
|
3204
|
+
"aria-label": activeToolStyle.label ?? "Estilo da ferramenta",
|
|
3205
|
+
style: shell,
|
|
3206
|
+
children: [
|
|
3207
|
+
/* @__PURE__ */ jsxs("label", { style: labelStyle2, children: [
|
|
3208
|
+
"Cor",
|
|
3209
|
+
/* @__PURE__ */ jsx(
|
|
3210
|
+
"input",
|
|
3211
|
+
{
|
|
3212
|
+
type: "color",
|
|
3213
|
+
value: hex2,
|
|
3214
|
+
onChange: (e) => onChange({
|
|
3215
|
+
stroke: e.target.value,
|
|
3216
|
+
strokeWidth: strokeWidth2,
|
|
3217
|
+
...activeToolStyle.strokeOpacity != null ? { strokeOpacity: activeToolStyle.strokeOpacity } : {}
|
|
3218
|
+
}),
|
|
3219
|
+
style: {
|
|
3220
|
+
width: "100%",
|
|
3221
|
+
height: 32,
|
|
3222
|
+
padding: 0,
|
|
3223
|
+
border: "none",
|
|
3224
|
+
cursor: "pointer",
|
|
3225
|
+
background: "transparent"
|
|
3226
|
+
}
|
|
3227
|
+
}
|
|
3228
|
+
)
|
|
3229
|
+
] }),
|
|
3230
|
+
/* @__PURE__ */ jsxs("label", { style: labelStyle2, children: [
|
|
3231
|
+
"Grossura",
|
|
3232
|
+
/* @__PURE__ */ jsx(
|
|
3233
|
+
"input",
|
|
3234
|
+
{
|
|
3235
|
+
type: "range",
|
|
3236
|
+
min: 1,
|
|
3237
|
+
max: 48,
|
|
3238
|
+
value: strokeWidth2,
|
|
3239
|
+
onChange: (e) => onChange({
|
|
3240
|
+
stroke: hex2,
|
|
3241
|
+
strokeWidth: Number(e.target.value),
|
|
3242
|
+
...activeToolStyle.strokeOpacity != null ? { strokeOpacity: activeToolStyle.strokeOpacity } : {}
|
|
3243
|
+
})
|
|
3244
|
+
}
|
|
3245
|
+
)
|
|
3246
|
+
] }),
|
|
3247
|
+
showMarkerOpacity2 && /* @__PURE__ */ jsxs("label", { style: labelStyle2, children: [
|
|
3248
|
+
"Opacidade (marcador)",
|
|
3249
|
+
/* @__PURE__ */ jsx(
|
|
3250
|
+
"input",
|
|
3251
|
+
{
|
|
3252
|
+
type: "range",
|
|
3253
|
+
min: 10,
|
|
3254
|
+
max: 100,
|
|
3255
|
+
value: opacityPct2,
|
|
3256
|
+
onChange: (e) => {
|
|
3257
|
+
const v = Number(e.target.value) / 100;
|
|
3258
|
+
onChange({
|
|
3259
|
+
stroke: hex2,
|
|
3260
|
+
strokeWidth: strokeWidth2,
|
|
3261
|
+
strokeOpacity: v
|
|
3262
|
+
});
|
|
3263
|
+
}
|
|
3264
|
+
}
|
|
3265
|
+
),
|
|
3266
|
+
/* @__PURE__ */ jsxs("span", { style: { fontWeight: 500, color: "#71717a" }, children: [
|
|
3267
|
+
opacityPct2,
|
|
3268
|
+
"%"
|
|
3269
|
+
] })
|
|
3270
|
+
] })
|
|
3271
|
+
]
|
|
3272
|
+
}
|
|
3273
|
+
);
|
|
3274
|
+
}
|
|
3275
|
+
const stylable = items.filter(
|
|
3276
|
+
(it) => !it.locked && it.toolKind && isStylableKind(it.toolKind)
|
|
2821
3277
|
);
|
|
2822
|
-
|
|
2823
|
-
|
|
3278
|
+
if (stylable.length === 0) return null;
|
|
3279
|
+
const first = stylable[0];
|
|
3280
|
+
if (!first) return null;
|
|
3281
|
+
const allSameStroke = stylable.every(
|
|
3282
|
+
(it) => (it.stroke ?? "#2563eb") === (first.stroke ?? "#2563eb")
|
|
3283
|
+
);
|
|
3284
|
+
const allSameWidth = stylable.every(
|
|
3285
|
+
(it) => (it.strokeWidth ?? 2) === (first.strokeWidth ?? 2)
|
|
3286
|
+
);
|
|
3287
|
+
const stroke = first.stroke ?? "#2563eb";
|
|
3288
|
+
const strokeWidth = first.strokeWidth ?? 2;
|
|
3289
|
+
const hex = normalizeHex(stroke);
|
|
3290
|
+
const markers = stylable.filter((it) => it.toolKind === "marker");
|
|
3291
|
+
const showMarkerOpacity = markers.length > 0;
|
|
3292
|
+
const firstMarker = markers[0];
|
|
3293
|
+
const allSameMarkerOpacity = markers.length > 0 && markers.every(
|
|
3294
|
+
(it) => (it.strokeOpacity ?? 1) === (firstMarker?.strokeOpacity ?? 1)
|
|
3295
|
+
);
|
|
3296
|
+
const opacityPct = firstMarker ? Math.round((firstMarker.strokeOpacity ?? 1) * 100) : 100;
|
|
3297
|
+
return /* @__PURE__ */ jsxs(
|
|
3298
|
+
"section",
|
|
2824
3299
|
{
|
|
2825
|
-
|
|
2826
|
-
"data-
|
|
2827
|
-
|
|
2828
|
-
|
|
3300
|
+
"data-slot": "vector-selection-inspector",
|
|
3301
|
+
"data-position": position,
|
|
3302
|
+
className,
|
|
3303
|
+
"aria-label": "Estilo da sele\xE7\xE3o",
|
|
3304
|
+
style: shell,
|
|
2829
3305
|
children: [
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
3306
|
+
stylable.length > 1 && /* @__PURE__ */ jsxs("p", { style: { margin: 0, fontSize: 11, color: "#71717a" }, children: [
|
|
3307
|
+
stylable.length,
|
|
3308
|
+
" objetos selecionados"
|
|
3309
|
+
] }),
|
|
3310
|
+
/* @__PURE__ */ jsxs("label", { style: labelStyle2, children: [
|
|
3311
|
+
"Cor",
|
|
3312
|
+
!allSameStroke && /* @__PURE__ */ jsxs("span", { style: { fontWeight: 400, color: "#a1a1aa" }, children: [
|
|
3313
|
+
" ",
|
|
3314
|
+
"(valores misturados \u2014 novo valor aplica a todos)"
|
|
3315
|
+
] }),
|
|
3316
|
+
/* @__PURE__ */ jsx(
|
|
3317
|
+
"input",
|
|
3318
|
+
{
|
|
3319
|
+
type: "color",
|
|
3320
|
+
value: hex,
|
|
3321
|
+
onChange: (e) => onChange({
|
|
3322
|
+
stroke: e.target.value,
|
|
3323
|
+
strokeWidth
|
|
3324
|
+
}),
|
|
3325
|
+
style: {
|
|
3326
|
+
width: "100%",
|
|
3327
|
+
height: 32,
|
|
3328
|
+
padding: 0,
|
|
3329
|
+
border: "none",
|
|
3330
|
+
cursor: "pointer",
|
|
3331
|
+
background: "transparent"
|
|
3332
|
+
}
|
|
3333
|
+
}
|
|
3334
|
+
)
|
|
3335
|
+
] }),
|
|
3336
|
+
/* @__PURE__ */ jsxs("label", { style: labelStyle2, children: [
|
|
3337
|
+
"Grossura",
|
|
3338
|
+
!allSameWidth && /* @__PURE__ */ jsx("span", { style: { fontWeight: 400, color: "#a1a1aa" }, children: " (misturado)" }),
|
|
3339
|
+
/* @__PURE__ */ jsx(
|
|
3340
|
+
"input",
|
|
3341
|
+
{
|
|
3342
|
+
type: "range",
|
|
3343
|
+
min: 1,
|
|
3344
|
+
max: 48,
|
|
3345
|
+
value: strokeWidth,
|
|
3346
|
+
onChange: (e) => onChange({
|
|
3347
|
+
stroke: hex,
|
|
3348
|
+
strokeWidth: Number(e.target.value)
|
|
3349
|
+
})
|
|
3350
|
+
}
|
|
3351
|
+
)
|
|
3352
|
+
] }),
|
|
3353
|
+
showMarkerOpacity && firstMarker && /* @__PURE__ */ jsxs("label", { style: labelStyle2, children: [
|
|
3354
|
+
"Opacidade (marcador)",
|
|
3355
|
+
!allSameMarkerOpacity && markers.length > 1 && /* @__PURE__ */ jsx("span", { style: { fontWeight: 400, color: "#a1a1aa" }, children: " (misturado)" }),
|
|
3356
|
+
/* @__PURE__ */ jsx(
|
|
3357
|
+
"input",
|
|
3358
|
+
{
|
|
3359
|
+
type: "range",
|
|
3360
|
+
min: 10,
|
|
3361
|
+
max: 100,
|
|
3362
|
+
value: opacityPct,
|
|
3363
|
+
onChange: (e) => {
|
|
3364
|
+
const v = Number(e.target.value) / 100;
|
|
3365
|
+
onChange({
|
|
3366
|
+
stroke: hex,
|
|
3367
|
+
strokeWidth,
|
|
3368
|
+
strokeOpacity: v
|
|
3369
|
+
});
|
|
3370
|
+
}
|
|
3371
|
+
}
|
|
3372
|
+
),
|
|
3373
|
+
/* @__PURE__ */ jsxs("span", { style: { fontWeight: 500, color: "#71717a" }, children: [
|
|
3374
|
+
opacityPct,
|
|
3375
|
+
"%"
|
|
3376
|
+
] })
|
|
3377
|
+
] })
|
|
2841
3378
|
]
|
|
2842
3379
|
}
|
|
2843
3380
|
);
|
|
2844
|
-
if (typeof document === "undefined") {
|
|
2845
|
-
return null;
|
|
2846
|
-
}
|
|
2847
|
-
return createPortal(menu, document.body);
|
|
2848
3381
|
}
|
|
2849
|
-
var
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
strokeWidth: 2,
|
|
2856
|
-
strokeLinecap: "round",
|
|
2857
|
-
strokeLinejoin: "round"
|
|
3382
|
+
var rootStyle = {
|
|
3383
|
+
display: "flex",
|
|
3384
|
+
flexDirection: "column",
|
|
3385
|
+
height: "100%",
|
|
3386
|
+
minHeight: 0,
|
|
3387
|
+
width: "100%"
|
|
2858
3388
|
};
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
}
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
] });
|
|
3389
|
+
var headerStyle2 = {
|
|
3390
|
+
flexShrink: 0,
|
|
3391
|
+
display: "flex",
|
|
3392
|
+
flexWrap: "wrap",
|
|
3393
|
+
alignItems: "center",
|
|
3394
|
+
gap: "0.75rem",
|
|
3395
|
+
padding: "0.75rem 1rem",
|
|
3396
|
+
borderBottom: "1px solid #e4e4e7",
|
|
3397
|
+
background: "#fff",
|
|
3398
|
+
fontSize: "0.875rem"
|
|
3399
|
+
};
|
|
3400
|
+
var bodyStyle = {
|
|
3401
|
+
flex: 1,
|
|
3402
|
+
minHeight: 0,
|
|
3403
|
+
display: "flex",
|
|
3404
|
+
flexDirection: "column"
|
|
3405
|
+
};
|
|
3406
|
+
var mainStyle = {
|
|
3407
|
+
flex: 1,
|
|
3408
|
+
minHeight: 0,
|
|
3409
|
+
position: "relative",
|
|
3410
|
+
display: "flex",
|
|
3411
|
+
flexDirection: "column"
|
|
3412
|
+
};
|
|
3413
|
+
var viewportSurfaceStyle = {
|
|
3414
|
+
flex: 1,
|
|
3415
|
+
minHeight: 0,
|
|
3416
|
+
position: "relative",
|
|
3417
|
+
width: "100%",
|
|
3418
|
+
alignSelf: "stretch",
|
|
3419
|
+
background: "#fff",
|
|
3420
|
+
touchAction: "none"
|
|
3421
|
+
};
|
|
3422
|
+
function mergeStyle(base2, style) {
|
|
3423
|
+
return style ? { ...base2, ...style } : base2;
|
|
2895
3424
|
}
|
|
2896
|
-
function
|
|
2897
|
-
return
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
] });
|
|
3425
|
+
function vectorCanvasSpaceStyle(position, inset, zIndex) {
|
|
3426
|
+
return {
|
|
3427
|
+
...getBoardPositionStyle(position, inset, zIndex),
|
|
3428
|
+
pointerEvents: "none"
|
|
3429
|
+
};
|
|
2902
3430
|
}
|
|
2903
|
-
function
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
3431
|
+
function VectorCanvasRoot({
|
|
3432
|
+
children,
|
|
3433
|
+
className,
|
|
3434
|
+
style
|
|
3435
|
+
}) {
|
|
3436
|
+
return /* @__PURE__ */ jsx(
|
|
3437
|
+
"div",
|
|
3438
|
+
{
|
|
3439
|
+
"data-slot": "vector-canvas-root",
|
|
3440
|
+
className,
|
|
3441
|
+
style: mergeStyle(rootStyle, style),
|
|
3442
|
+
children
|
|
3443
|
+
}
|
|
3444
|
+
);
|
|
2909
3445
|
}
|
|
2910
|
-
function
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
3446
|
+
function VectorCanvasHeader({
|
|
3447
|
+
children,
|
|
3448
|
+
className,
|
|
3449
|
+
style
|
|
3450
|
+
}) {
|
|
3451
|
+
return /* @__PURE__ */ jsx(
|
|
3452
|
+
"header",
|
|
3453
|
+
{
|
|
3454
|
+
"data-slot": "vector-canvas-header",
|
|
3455
|
+
className,
|
|
3456
|
+
style: mergeStyle(headerStyle2, style),
|
|
3457
|
+
children
|
|
3458
|
+
}
|
|
3459
|
+
);
|
|
2918
3460
|
}
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
{
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3461
|
+
function VectorCanvasBody({
|
|
3462
|
+
children,
|
|
3463
|
+
className,
|
|
3464
|
+
style
|
|
3465
|
+
}) {
|
|
3466
|
+
return /* @__PURE__ */ jsx(
|
|
3467
|
+
"div",
|
|
3468
|
+
{
|
|
3469
|
+
"data-slot": "vector-canvas-body",
|
|
3470
|
+
className,
|
|
3471
|
+
style: mergeStyle(bodyStyle, style),
|
|
3472
|
+
children
|
|
3473
|
+
}
|
|
3474
|
+
);
|
|
3475
|
+
}
|
|
3476
|
+
function VectorCanvasMain({
|
|
3477
|
+
children,
|
|
3478
|
+
className,
|
|
3479
|
+
style
|
|
3480
|
+
}) {
|
|
3481
|
+
return /* @__PURE__ */ jsx(
|
|
3482
|
+
"div",
|
|
3483
|
+
{
|
|
3484
|
+
"data-slot": "vector-canvas-main",
|
|
3485
|
+
className,
|
|
3486
|
+
style: mergeStyle(mainStyle, style),
|
|
3487
|
+
children
|
|
3488
|
+
}
|
|
3489
|
+
);
|
|
3490
|
+
}
|
|
3491
|
+
function VectorCanvasViewportSurface({
|
|
3492
|
+
children,
|
|
3493
|
+
className,
|
|
3494
|
+
style
|
|
3495
|
+
}) {
|
|
3496
|
+
return /* @__PURE__ */ jsx(
|
|
3497
|
+
"div",
|
|
3498
|
+
{
|
|
3499
|
+
"data-slot": "vector-canvas-viewport-surface",
|
|
3500
|
+
className,
|
|
3501
|
+
style: mergeStyle(viewportSurfaceStyle, style),
|
|
3502
|
+
children
|
|
3503
|
+
}
|
|
3504
|
+
);
|
|
3505
|
+
}
|
|
3506
|
+
function VectorCanvasToolbar({
|
|
3507
|
+
children,
|
|
3508
|
+
className,
|
|
3509
|
+
style,
|
|
3510
|
+
position = "bottom-center",
|
|
3511
|
+
inset = 12,
|
|
3512
|
+
zIndex = 30
|
|
3513
|
+
}) {
|
|
3514
|
+
const base2 = {
|
|
3515
|
+
...getBoardPositionStyle(position, inset, zIndex),
|
|
3516
|
+
display: "flex",
|
|
3517
|
+
justifyContent: "center",
|
|
3518
|
+
alignItems: "center",
|
|
3519
|
+
maxWidth: "calc(100% - 24px)",
|
|
3520
|
+
pointerEvents: "none"
|
|
3521
|
+
};
|
|
3522
|
+
return /* @__PURE__ */ jsx(
|
|
3523
|
+
"div",
|
|
3524
|
+
{
|
|
3525
|
+
"data-slot": "vector-canvas-toolbar",
|
|
3526
|
+
"data-position": position,
|
|
3527
|
+
className,
|
|
3528
|
+
style: mergeStyle(base2, style),
|
|
3529
|
+
children: /* @__PURE__ */ jsx("div", { style: { pointerEvents: "auto" }, children })
|
|
3530
|
+
}
|
|
3531
|
+
);
|
|
3532
|
+
}
|
|
3533
|
+
function VectorCanvasSpace({
|
|
3534
|
+
children,
|
|
3535
|
+
className,
|
|
3536
|
+
style,
|
|
3537
|
+
position = "top-right",
|
|
3538
|
+
inset = 12,
|
|
3539
|
+
zIndex = 40,
|
|
3540
|
+
contentPointerEvents = "auto"
|
|
3541
|
+
}) {
|
|
3542
|
+
return /* @__PURE__ */ jsx(
|
|
3543
|
+
"div",
|
|
3544
|
+
{
|
|
3545
|
+
"data-slot": `vector-canvas-space-${position}`,
|
|
3546
|
+
className,
|
|
3547
|
+
style: mergeStyle(vectorCanvasSpaceStyle(position, inset, zIndex), style),
|
|
3548
|
+
children: /* @__PURE__ */ jsx("div", { style: { pointerEvents: contentPointerEvents }, children })
|
|
3549
|
+
}
|
|
3550
|
+
);
|
|
3551
|
+
}
|
|
3552
|
+
var VectorCanvas = {
|
|
3553
|
+
Root: VectorCanvasRoot,
|
|
3554
|
+
Header: VectorCanvasHeader,
|
|
3555
|
+
Body: VectorCanvasBody,
|
|
3556
|
+
Main: VectorCanvasMain,
|
|
3557
|
+
ViewportSurface: VectorCanvasViewportSurface,
|
|
3558
|
+
Toolbar: VectorCanvasToolbar,
|
|
3559
|
+
Space: VectorCanvasSpace,
|
|
3560
|
+
NavMenu,
|
|
3561
|
+
SelectionInspector: VectorSelectionInspector
|
|
3562
|
+
};
|
|
3563
|
+
var VectorToolbarItemContext = createContext(
|
|
3564
|
+
null
|
|
3565
|
+
);
|
|
3566
|
+
function useVectorToolbarItemContext(componentName) {
|
|
3567
|
+
const ctx = useContext(VectorToolbarItemContext);
|
|
3568
|
+
if (!ctx) {
|
|
3569
|
+
throw new Error(`${componentName} must be used inside <VectorToolbar>`);
|
|
3003
3570
|
}
|
|
3004
|
-
|
|
3571
|
+
return ctx;
|
|
3572
|
+
}
|
|
3005
3573
|
var toolbarStyles = {
|
|
3006
3574
|
display: "flex",
|
|
3007
3575
|
gap: "4px",
|
|
@@ -3250,6 +3818,20 @@ var overflowGridCellButtonStyle = {
|
|
|
3250
3818
|
outline: "none",
|
|
3251
3819
|
WebkitTapHighlightColor: "transparent"
|
|
3252
3820
|
};
|
|
3821
|
+
var activeToggleStyle = {
|
|
3822
|
+
background: "rgba(24,24,27,0.1)",
|
|
3823
|
+
borderColor: "rgba(24,24,27,0.28)",
|
|
3824
|
+
boxShadow: "inset 0 0 0 1px rgba(24,24,27,0.08)"
|
|
3825
|
+
};
|
|
3826
|
+
var inactiveToggleStyle = {
|
|
3827
|
+
borderColor: "transparent",
|
|
3828
|
+
boxShadow: "none"
|
|
3829
|
+
};
|
|
3830
|
+
function preventMouseDefault2(e) {
|
|
3831
|
+
if (e.pointerType === "mouse") {
|
|
3832
|
+
e.preventDefault();
|
|
3833
|
+
}
|
|
3834
|
+
}
|
|
3253
3835
|
function ToolLockGlyph({ locked }) {
|
|
3254
3836
|
const Icon = locked ? Lock : LockOpen;
|
|
3255
3837
|
return /* @__PURE__ */ jsx(Icon, { size: 18, strokeWidth: 2, "aria-hidden": true });
|
|
@@ -3263,7 +3845,406 @@ function splitToolbarTools(tools, overflowIds) {
|
|
|
3263
3845
|
const overflow = overflowIds.map((id) => tools.find((t) => t.id === id)).filter((t) => Boolean(t));
|
|
3264
3846
|
return { primary, overflow };
|
|
3265
3847
|
}
|
|
3266
|
-
var icOverflow = { size: 18, strokeWidth: 2 };
|
|
3848
|
+
var icOverflow = { size: 18, strokeWidth: 2 };
|
|
3849
|
+
function useOverflowDropdown() {
|
|
3850
|
+
const [open, setOpen] = useState(false);
|
|
3851
|
+
const wrapRef = useRef(null);
|
|
3852
|
+
const triggerRef = useRef(null);
|
|
3853
|
+
const menuId = useId();
|
|
3854
|
+
const close = useCallback(() => {
|
|
3855
|
+
setOpen(false);
|
|
3856
|
+
}, []);
|
|
3857
|
+
const prevOpenRef = useRef(open);
|
|
3858
|
+
useEffect(() => {
|
|
3859
|
+
if (!open) {
|
|
3860
|
+
return;
|
|
3861
|
+
}
|
|
3862
|
+
const onDocPointerDown = (e) => {
|
|
3863
|
+
if (wrapRef.current?.contains(e.target)) {
|
|
3864
|
+
return;
|
|
3865
|
+
}
|
|
3866
|
+
close();
|
|
3867
|
+
};
|
|
3868
|
+
const onKeyDown = (e) => {
|
|
3869
|
+
if (e.key === "Escape") {
|
|
3870
|
+
e.stopPropagation();
|
|
3871
|
+
close();
|
|
3872
|
+
triggerRef.current?.focus();
|
|
3873
|
+
}
|
|
3874
|
+
};
|
|
3875
|
+
document.addEventListener("pointerdown", onDocPointerDown, true);
|
|
3876
|
+
document.addEventListener("keydown", onKeyDown, true);
|
|
3877
|
+
return () => {
|
|
3878
|
+
document.removeEventListener("pointerdown", onDocPointerDown, true);
|
|
3879
|
+
document.removeEventListener("keydown", onKeyDown, true);
|
|
3880
|
+
};
|
|
3881
|
+
}, [open, close]);
|
|
3882
|
+
useEffect(() => {
|
|
3883
|
+
if (prevOpenRef.current && !open) {
|
|
3884
|
+
triggerRef.current?.focus({ preventScroll: true });
|
|
3885
|
+
}
|
|
3886
|
+
prevOpenRef.current = open;
|
|
3887
|
+
}, [open]);
|
|
3888
|
+
return { open, setOpen, close, wrapRef, triggerRef, menuId };
|
|
3889
|
+
}
|
|
3890
|
+
function renderInlineToolButton(tool, ctx) {
|
|
3891
|
+
const {
|
|
3892
|
+
selectedId,
|
|
3893
|
+
selectTool,
|
|
3894
|
+
density,
|
|
3895
|
+
buttonClassName,
|
|
3896
|
+
activeButtonClassName,
|
|
3897
|
+
renderToolButton
|
|
3898
|
+
} = ctx;
|
|
3899
|
+
const selected = tool.id === selectedId;
|
|
3900
|
+
const label = tool.ariaLabel ?? tool.label;
|
|
3901
|
+
if (renderToolButton) {
|
|
3902
|
+
return /* @__PURE__ */ jsx("div", { children: renderToolButton({
|
|
3903
|
+
tool,
|
|
3904
|
+
selected,
|
|
3905
|
+
onSelect: () => selectTool(tool.id)
|
|
3906
|
+
}) }, tool.id);
|
|
3907
|
+
}
|
|
3908
|
+
const tooltipName = tool.tooltipLabel ?? tool.label;
|
|
3909
|
+
const tooltipText = tool.shortcutHint !== void 0 ? `${tooltipName} \xB7 ${tool.shortcutHint}` : tooltipName;
|
|
3910
|
+
const labelOnly = tool.icon == null;
|
|
3911
|
+
const labelTextStyle = labelOnly ? {
|
|
3912
|
+
fontSize: "12px",
|
|
3913
|
+
fontWeight: 600,
|
|
3914
|
+
letterSpacing: "0.02em",
|
|
3915
|
+
lineHeight: 1.2,
|
|
3916
|
+
WebkitFontSmoothing: "antialiased",
|
|
3917
|
+
MozOsxFontSmoothing: "grayscale",
|
|
3918
|
+
textRendering: "geometricPrecision"
|
|
3919
|
+
} : {};
|
|
3920
|
+
return /* @__PURE__ */ jsxs("span", { className: "vector-toolbar-tool-wrap", children: [
|
|
3921
|
+
/* @__PURE__ */ jsxs(
|
|
3922
|
+
"button",
|
|
3923
|
+
{
|
|
3924
|
+
type: "button",
|
|
3925
|
+
"aria-pressed": selected,
|
|
3926
|
+
"aria-label": label,
|
|
3927
|
+
...tool.shortcutHint !== void 0 ? { "aria-keyshortcuts": tool.shortcutHint } : {},
|
|
3928
|
+
className: `${buttonClassName} ${selected ? activeButtonClassName : ""}`.trim(),
|
|
3929
|
+
style: {
|
|
3930
|
+
...defaultButtonStyle,
|
|
3931
|
+
...density === "compact" ? {
|
|
3932
|
+
minHeight: "40px",
|
|
3933
|
+
minWidth: labelOnly ? "52px" : "40px",
|
|
3934
|
+
padding: "6px 8px"
|
|
3935
|
+
} : {},
|
|
3936
|
+
...selected ? activeToggleStyle : inactiveToggleStyle
|
|
3937
|
+
},
|
|
3938
|
+
onPointerDown: preventMouseDefault2,
|
|
3939
|
+
onClick: () => selectTool(tool.id),
|
|
3940
|
+
children: [
|
|
3941
|
+
/* @__PURE__ */ jsx(
|
|
3942
|
+
"span",
|
|
3943
|
+
{
|
|
3944
|
+
style: {
|
|
3945
|
+
display: "flex",
|
|
3946
|
+
alignItems: "center",
|
|
3947
|
+
justifyContent: "center"
|
|
3948
|
+
},
|
|
3949
|
+
children: tool.icon ?? /* @__PURE__ */ jsx("span", { style: labelTextStyle, children: tool.label })
|
|
3950
|
+
}
|
|
3951
|
+
),
|
|
3952
|
+
density === "comfortable" && tool.icon ? /* @__PURE__ */ jsx(
|
|
3953
|
+
"span",
|
|
3954
|
+
{
|
|
3955
|
+
style: {
|
|
3956
|
+
lineHeight: 1,
|
|
3957
|
+
maxWidth: "56px",
|
|
3958
|
+
overflow: "hidden",
|
|
3959
|
+
textOverflow: "ellipsis"
|
|
3960
|
+
},
|
|
3961
|
+
children: tool.label
|
|
3962
|
+
}
|
|
3963
|
+
) : null
|
|
3964
|
+
]
|
|
3965
|
+
}
|
|
3966
|
+
),
|
|
3967
|
+
/* @__PURE__ */ jsx("span", { className: "vector-toolbar-tip", "aria-hidden": "true", children: tooltipText })
|
|
3968
|
+
] }, tool.id);
|
|
3969
|
+
}
|
|
3970
|
+
function renderOverflowToolButton(tool, ctx) {
|
|
3971
|
+
const { selectedId, selectTool, closeMenu, renderToolButton, tabIndex } = ctx;
|
|
3972
|
+
const selected = tool.id === selectedId;
|
|
3973
|
+
const label = tool.ariaLabel ?? tool.label;
|
|
3974
|
+
const tooltipName = tool.tooltipLabel ?? tool.label;
|
|
3975
|
+
if (renderToolButton) {
|
|
3976
|
+
return /* @__PURE__ */ jsx(
|
|
3977
|
+
"div",
|
|
3978
|
+
{
|
|
3979
|
+
className: "vector-toolbar-overflow-cell",
|
|
3980
|
+
role: "presentation",
|
|
3981
|
+
children: renderToolButton({
|
|
3982
|
+
tool,
|
|
3983
|
+
selected,
|
|
3984
|
+
onSelect: () => {
|
|
3985
|
+
selectTool(tool.id);
|
|
3986
|
+
closeMenu();
|
|
3987
|
+
}
|
|
3988
|
+
})
|
|
3989
|
+
},
|
|
3990
|
+
tool.id
|
|
3991
|
+
);
|
|
3992
|
+
}
|
|
3993
|
+
return /* @__PURE__ */ jsx("div", { className: "vector-toolbar-overflow-cell", children: /* @__PURE__ */ jsxs(
|
|
3994
|
+
"button",
|
|
3995
|
+
{
|
|
3996
|
+
type: "button",
|
|
3997
|
+
role: "menuitemradio",
|
|
3998
|
+
"aria-checked": selected,
|
|
3999
|
+
tabIndex: tabIndex ?? -1,
|
|
4000
|
+
"aria-label": label,
|
|
4001
|
+
...tool.shortcutHint !== void 0 ? { "aria-keyshortcuts": tool.shortcutHint } : {},
|
|
4002
|
+
style: overflowGridCellButtonStyle,
|
|
4003
|
+
onPointerDown: preventMouseDefault2,
|
|
4004
|
+
onClick: () => {
|
|
4005
|
+
selectTool(tool.id);
|
|
4006
|
+
closeMenu();
|
|
4007
|
+
},
|
|
4008
|
+
children: [
|
|
4009
|
+
/* @__PURE__ */ jsx(
|
|
4010
|
+
"span",
|
|
4011
|
+
{
|
|
4012
|
+
style: {
|
|
4013
|
+
display: "flex",
|
|
4014
|
+
alignItems: "center",
|
|
4015
|
+
justifyContent: "center",
|
|
4016
|
+
lineHeight: 0
|
|
4017
|
+
},
|
|
4018
|
+
children: tool.icon ?? /* @__PURE__ */ jsx(
|
|
4019
|
+
"span",
|
|
4020
|
+
{
|
|
4021
|
+
style: {
|
|
4022
|
+
fontSize: "11px",
|
|
4023
|
+
fontWeight: 700,
|
|
4024
|
+
lineHeight: 1.1,
|
|
4025
|
+
textAlign: "center",
|
|
4026
|
+
maxWidth: "34px",
|
|
4027
|
+
overflow: "hidden",
|
|
4028
|
+
textOverflow: "ellipsis"
|
|
4029
|
+
},
|
|
4030
|
+
children: tool.label.slice(0, 3)
|
|
4031
|
+
}
|
|
4032
|
+
)
|
|
4033
|
+
}
|
|
4034
|
+
),
|
|
4035
|
+
/* @__PURE__ */ jsxs("span", { className: "vector-toolbar-overflow-tip", "aria-hidden": "true", children: [
|
|
4036
|
+
/* @__PURE__ */ jsx("span", { children: tooltipName }),
|
|
4037
|
+
tool.shortcutHint !== void 0 ? /* @__PURE__ */ jsx("span", { className: "vector-toolbar-overflow-tip-shortcut", children: tool.shortcutHint }) : null
|
|
4038
|
+
] })
|
|
4039
|
+
]
|
|
4040
|
+
}
|
|
4041
|
+
) }, tool.id);
|
|
4042
|
+
}
|
|
4043
|
+
function hasToolIdProp(value) {
|
|
4044
|
+
return typeof value === "function" && "toolId" in value && typeof value.toolId === "string";
|
|
4045
|
+
}
|
|
4046
|
+
function findActiveOverflowChild(children, selectedId) {
|
|
4047
|
+
let result = null;
|
|
4048
|
+
Children.forEach(children, (child) => {
|
|
4049
|
+
if (result || !isValidElement(child)) {
|
|
4050
|
+
return;
|
|
4051
|
+
}
|
|
4052
|
+
const childType = child.type;
|
|
4053
|
+
let toolId;
|
|
4054
|
+
let label = "";
|
|
4055
|
+
let icon = null;
|
|
4056
|
+
const childProps = child.props ?? {};
|
|
4057
|
+
if (hasToolIdProp(childType)) {
|
|
4058
|
+
toolId = childType.toolId;
|
|
4059
|
+
const def = DEFAULT_VECTOR_TOOLS.find((t) => t.id === toolId);
|
|
4060
|
+
if (def) {
|
|
4061
|
+
label = def.label;
|
|
4062
|
+
icon = def.icon ?? null;
|
|
4063
|
+
}
|
|
4064
|
+
} else {
|
|
4065
|
+
toolId = childProps.id;
|
|
4066
|
+
label = childProps.label ?? "";
|
|
4067
|
+
icon = childProps.icon ?? null;
|
|
4068
|
+
}
|
|
4069
|
+
if (childProps.icon !== void 0) {
|
|
4070
|
+
icon = childProps.icon;
|
|
4071
|
+
}
|
|
4072
|
+
if (childProps.label !== void 0 && childProps.label !== "") {
|
|
4073
|
+
label = childProps.label;
|
|
4074
|
+
}
|
|
4075
|
+
if (toolId !== void 0 && toolId === selectedId) {
|
|
4076
|
+
result = { id: toolId, label, icon };
|
|
4077
|
+
}
|
|
4078
|
+
});
|
|
4079
|
+
return result;
|
|
4080
|
+
}
|
|
4081
|
+
function VectorToolbarTool(props) {
|
|
4082
|
+
const ctx = useVectorToolbarItemContext("VectorToolbar.Tool");
|
|
4083
|
+
const tool = {
|
|
4084
|
+
id: props.id,
|
|
4085
|
+
label: props.label,
|
|
4086
|
+
tooltipLabel: props.tooltipLabel,
|
|
4087
|
+
icon: props.icon,
|
|
4088
|
+
shortcutHint: props.shortcutHint,
|
|
4089
|
+
ariaLabel: props.ariaLabel
|
|
4090
|
+
};
|
|
4091
|
+
if (ctx.insideOverflow) {
|
|
4092
|
+
return renderOverflowToolButton(tool, {
|
|
4093
|
+
selectedId: ctx.selectedId,
|
|
4094
|
+
selectTool: ctx.selectTool,
|
|
4095
|
+
closeMenu: ctx.closeOverflow,
|
|
4096
|
+
renderToolButton: ctx.renderToolButton
|
|
4097
|
+
});
|
|
4098
|
+
}
|
|
4099
|
+
return renderInlineToolButton(tool, {
|
|
4100
|
+
selectedId: ctx.selectedId,
|
|
4101
|
+
selectTool: ctx.selectTool,
|
|
4102
|
+
density: ctx.density,
|
|
4103
|
+
buttonClassName: ctx.buttonClassName,
|
|
4104
|
+
activeButtonClassName: ctx.activeButtonClassName,
|
|
4105
|
+
renderToolButton: ctx.renderToolButton
|
|
4106
|
+
});
|
|
4107
|
+
}
|
|
4108
|
+
function VectorToolbarToolLock({
|
|
4109
|
+
className,
|
|
4110
|
+
divider = true
|
|
4111
|
+
} = {}) {
|
|
4112
|
+
const ctx = useVectorToolbarItemContext("VectorToolbar.ToolLock");
|
|
4113
|
+
const {
|
|
4114
|
+
toolLocked,
|
|
4115
|
+
setToolLocked,
|
|
4116
|
+
buttonClassName,
|
|
4117
|
+
activeButtonClassName,
|
|
4118
|
+
density
|
|
4119
|
+
} = ctx;
|
|
4120
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4121
|
+
/* @__PURE__ */ jsxs("span", { className: "vector-toolbar-tool-wrap", children: [
|
|
4122
|
+
/* @__PURE__ */ jsx(
|
|
4123
|
+
"button",
|
|
4124
|
+
{
|
|
4125
|
+
type: "button",
|
|
4126
|
+
"aria-pressed": toolLocked,
|
|
4127
|
+
"aria-label": toolLocked ? "Unlock tool" : "Lock tool",
|
|
4128
|
+
className: `${buttonClassName} ${toolLocked ? activeButtonClassName : ""} ${className ?? ""}`.trim(),
|
|
4129
|
+
style: {
|
|
4130
|
+
...defaultButtonStyle,
|
|
4131
|
+
...density === "compact" ? {
|
|
4132
|
+
minHeight: "40px",
|
|
4133
|
+
minWidth: "40px",
|
|
4134
|
+
padding: "6px 8px"
|
|
4135
|
+
} : {},
|
|
4136
|
+
...toolLocked ? activeToggleStyle : inactiveToggleStyle
|
|
4137
|
+
},
|
|
4138
|
+
onPointerDown: preventMouseDefault2,
|
|
4139
|
+
onClick: () => setToolLocked(!toolLocked),
|
|
4140
|
+
children: /* @__PURE__ */ jsx(ToolLockGlyph, { locked: toolLocked })
|
|
4141
|
+
}
|
|
4142
|
+
),
|
|
4143
|
+
/* @__PURE__ */ jsx("span", { className: "vector-toolbar-tip", "aria-hidden": "true", children: toolLocked ? "Tool lock on" : "Tool lock off" })
|
|
4144
|
+
] }),
|
|
4145
|
+
divider ? /* @__PURE__ */ jsx("span", { "aria-hidden": true, style: toolLockDividerStyle }) : null
|
|
4146
|
+
] });
|
|
4147
|
+
}
|
|
4148
|
+
function VectorToolbarOverflow({
|
|
4149
|
+
children,
|
|
4150
|
+
ariaLabel = "More tools"
|
|
4151
|
+
}) {
|
|
4152
|
+
const ctx = useVectorToolbarItemContext("VectorToolbar.Overflow");
|
|
4153
|
+
const { open, setOpen, close, wrapRef, triggerRef, menuId } = useOverflowDropdown();
|
|
4154
|
+
if (ctx.insideOverflow) {
|
|
4155
|
+
throw new Error("VectorToolbar.Overflow cannot be nested.");
|
|
4156
|
+
}
|
|
4157
|
+
const activeChild = findActiveOverflowChild(children, ctx.selectedId);
|
|
4158
|
+
const triggerHighlighted = open || activeChild !== null;
|
|
4159
|
+
const customRenderer = Boolean(ctx.renderToolButton);
|
|
4160
|
+
const nestedCtx = {
|
|
4161
|
+
...ctx,
|
|
4162
|
+
insideOverflow: true,
|
|
4163
|
+
closeOverflow: close
|
|
4164
|
+
};
|
|
4165
|
+
return /* @__PURE__ */ jsxs("div", { ref: wrapRef, className: "vector-toolbar-overflow-anchor", children: [
|
|
4166
|
+
/* @__PURE__ */ jsxs("span", { className: "vector-toolbar-tool-wrap", children: [
|
|
4167
|
+
/* @__PURE__ */ jsxs(
|
|
4168
|
+
"button",
|
|
4169
|
+
{
|
|
4170
|
+
ref: triggerRef,
|
|
4171
|
+
type: "button",
|
|
4172
|
+
id: `${menuId}-trigger`,
|
|
4173
|
+
"aria-haspopup": customRenderer ? "true" : "menu",
|
|
4174
|
+
"aria-expanded": open,
|
|
4175
|
+
"aria-controls": open ? `${menuId}-menu` : void 0,
|
|
4176
|
+
"aria-label": activeChild ? `${ariaLabel}: ${activeChild.label}` : ariaLabel,
|
|
4177
|
+
className: `vector-toolbar-overflow-trigger ${ctx.buttonClassName} ${triggerHighlighted ? ctx.activeButtonClassName : ""}`.trim(),
|
|
4178
|
+
style: {
|
|
4179
|
+
...defaultButtonStyle,
|
|
4180
|
+
flexDirection: "row",
|
|
4181
|
+
minWidth: "48px",
|
|
4182
|
+
minHeight: ctx.density === "compact" ? "40px" : "44px",
|
|
4183
|
+
padding: "6px 8px",
|
|
4184
|
+
gap: "4px",
|
|
4185
|
+
...triggerHighlighted ? activeToggleStyle : inactiveToggleStyle
|
|
4186
|
+
},
|
|
4187
|
+
onPointerDown: preventMouseDefault2,
|
|
4188
|
+
onClick: () => setOpen((o) => !o),
|
|
4189
|
+
onKeyDown: (e) => {
|
|
4190
|
+
if (e.key === "ArrowDown" && !open) {
|
|
4191
|
+
e.preventDefault();
|
|
4192
|
+
setOpen(true);
|
|
4193
|
+
}
|
|
4194
|
+
},
|
|
4195
|
+
children: [
|
|
4196
|
+
/* @__PURE__ */ jsx(
|
|
4197
|
+
"span",
|
|
4198
|
+
{
|
|
4199
|
+
style: {
|
|
4200
|
+
display: "flex",
|
|
4201
|
+
alignItems: "center",
|
|
4202
|
+
justifyContent: "center",
|
|
4203
|
+
flex: 1,
|
|
4204
|
+
minWidth: 0
|
|
4205
|
+
},
|
|
4206
|
+
children: activeChild?.icon ?? /* @__PURE__ */ jsx(Shapes, { ...icOverflow, "aria-hidden": true, strokeWidth: 2 })
|
|
4207
|
+
}
|
|
4208
|
+
),
|
|
4209
|
+
/* @__PURE__ */ jsx(
|
|
4210
|
+
ChevronDown,
|
|
4211
|
+
{
|
|
4212
|
+
size: 14,
|
|
4213
|
+
strokeWidth: 2,
|
|
4214
|
+
"aria-hidden": true,
|
|
4215
|
+
style: {
|
|
4216
|
+
opacity: 0.75,
|
|
4217
|
+
flexShrink: 0,
|
|
4218
|
+
transform: open ? "rotate(180deg)" : void 0,
|
|
4219
|
+
transition: "transform 0.15s ease"
|
|
4220
|
+
}
|
|
4221
|
+
}
|
|
4222
|
+
)
|
|
4223
|
+
]
|
|
4224
|
+
}
|
|
4225
|
+
),
|
|
4226
|
+
/* @__PURE__ */ jsx("span", { className: "vector-toolbar-tip", "aria-hidden": "true", children: ariaLabel })
|
|
4227
|
+
] }),
|
|
4228
|
+
open ? customRenderer ? /* @__PURE__ */ jsx(
|
|
4229
|
+
"section",
|
|
4230
|
+
{
|
|
4231
|
+
id: `${menuId}-menu`,
|
|
4232
|
+
"aria-label": ariaLabel,
|
|
4233
|
+
className: "vector-toolbar-overflow-panel",
|
|
4234
|
+
children: /* @__PURE__ */ jsx(VectorToolbarItemContext.Provider, { value: nestedCtx, children })
|
|
4235
|
+
}
|
|
4236
|
+
) : /* @__PURE__ */ jsx(
|
|
4237
|
+
"div",
|
|
4238
|
+
{
|
|
4239
|
+
id: `${menuId}-menu`,
|
|
4240
|
+
role: "menu",
|
|
4241
|
+
"aria-label": ariaLabel,
|
|
4242
|
+
className: "vector-toolbar-overflow-panel",
|
|
4243
|
+
children: /* @__PURE__ */ jsx(VectorToolbarItemContext.Provider, { value: nestedCtx, children })
|
|
4244
|
+
}
|
|
4245
|
+
) : null
|
|
4246
|
+
] });
|
|
4247
|
+
}
|
|
3267
4248
|
function ToolbarOverflowMenu({
|
|
3268
4249
|
tools,
|
|
3269
4250
|
selectedId,
|
|
@@ -3274,46 +4255,9 @@ function ToolbarOverflowMenu({
|
|
|
3274
4255
|
renderToolButton,
|
|
3275
4256
|
menuAriaLabel
|
|
3276
4257
|
}) {
|
|
3277
|
-
const
|
|
3278
|
-
const wrapRef = useRef(null);
|
|
3279
|
-
const triggerRef = useRef(null);
|
|
3280
|
-
const menuId = useId();
|
|
4258
|
+
const { open, setOpen, close, wrapRef, triggerRef, menuId } = useOverflowDropdown();
|
|
3281
4259
|
const activeInOverflow = tools.some((t) => t.id === selectedId);
|
|
3282
4260
|
const activeTool = tools.find((t) => t.id === selectedId);
|
|
3283
|
-
const close = useCallback(() => {
|
|
3284
|
-
setOpen(false);
|
|
3285
|
-
}, []);
|
|
3286
|
-
const prevOpenRef = useRef(open);
|
|
3287
|
-
useEffect(() => {
|
|
3288
|
-
if (!open) {
|
|
3289
|
-
return;
|
|
3290
|
-
}
|
|
3291
|
-
const onDocPointerDown = (e) => {
|
|
3292
|
-
if (wrapRef.current?.contains(e.target)) {
|
|
3293
|
-
return;
|
|
3294
|
-
}
|
|
3295
|
-
close();
|
|
3296
|
-
};
|
|
3297
|
-
const onKeyDown = (e) => {
|
|
3298
|
-
if (e.key === "Escape") {
|
|
3299
|
-
e.stopPropagation();
|
|
3300
|
-
close();
|
|
3301
|
-
triggerRef.current?.focus();
|
|
3302
|
-
}
|
|
3303
|
-
};
|
|
3304
|
-
document.addEventListener("pointerdown", onDocPointerDown, true);
|
|
3305
|
-
document.addEventListener("keydown", onKeyDown, true);
|
|
3306
|
-
return () => {
|
|
3307
|
-
document.removeEventListener("pointerdown", onDocPointerDown, true);
|
|
3308
|
-
document.removeEventListener("keydown", onKeyDown, true);
|
|
3309
|
-
};
|
|
3310
|
-
}, [open, close]);
|
|
3311
|
-
useEffect(() => {
|
|
3312
|
-
if (prevOpenRef.current && !open) {
|
|
3313
|
-
triggerRef.current?.focus({ preventScroll: true });
|
|
3314
|
-
}
|
|
3315
|
-
prevOpenRef.current = open;
|
|
3316
|
-
}, [open]);
|
|
3317
4261
|
const triggerHighlighted = open || activeInOverflow;
|
|
3318
4262
|
return /* @__PURE__ */ jsxs("div", { ref: wrapRef, className: "vector-toolbar-overflow-anchor", children: [
|
|
3319
4263
|
/* @__PURE__ */ jsxs("span", { className: "vector-toolbar-tool-wrap", children: [
|
|
@@ -3335,20 +4279,9 @@ function ToolbarOverflowMenu({
|
|
|
3335
4279
|
minHeight: density === "compact" ? "40px" : "44px",
|
|
3336
4280
|
padding: "6px 8px",
|
|
3337
4281
|
gap: "4px",
|
|
3338
|
-
...triggerHighlighted ?
|
|
3339
|
-
background: "rgba(24,24,27,0.1)",
|
|
3340
|
-
borderColor: "rgba(24,24,27,0.28)",
|
|
3341
|
-
boxShadow: "inset 0 0 0 1px rgba(24,24,27,0.08)"
|
|
3342
|
-
} : {
|
|
3343
|
-
borderColor: "transparent",
|
|
3344
|
-
boxShadow: "none"
|
|
3345
|
-
}
|
|
3346
|
-
},
|
|
3347
|
-
onPointerDown: (ev) => {
|
|
3348
|
-
if (ev.pointerType === "mouse") {
|
|
3349
|
-
ev.preventDefault();
|
|
3350
|
-
}
|
|
4282
|
+
...triggerHighlighted ? activeToggleStyle : inactiveToggleStyle
|
|
3351
4283
|
},
|
|
4284
|
+
onPointerDown: preventMouseDefault2,
|
|
3352
4285
|
onClick: () => setOpen((o) => !o),
|
|
3353
4286
|
onKeyDown: (e) => {
|
|
3354
4287
|
if (e.key === "ArrowDown" && !open) {
|
|
@@ -3395,25 +4328,14 @@ function ToolbarOverflowMenu({
|
|
|
3395
4328
|
id: `${menuId}-menu`,
|
|
3396
4329
|
"aria-label": menuAriaLabel,
|
|
3397
4330
|
className: "vector-toolbar-overflow-panel",
|
|
3398
|
-
children: tools.map(
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
tool,
|
|
3407
|
-
selected,
|
|
3408
|
-
onSelect: () => {
|
|
3409
|
-
onSelect(tool.id);
|
|
3410
|
-
close();
|
|
3411
|
-
}
|
|
3412
|
-
})
|
|
3413
|
-
},
|
|
3414
|
-
tool.id
|
|
3415
|
-
);
|
|
3416
|
-
})
|
|
4331
|
+
children: tools.map(
|
|
4332
|
+
(tool) => renderOverflowToolButton(tool, {
|
|
4333
|
+
selectedId,
|
|
4334
|
+
selectTool: onSelect,
|
|
4335
|
+
closeMenu: close,
|
|
4336
|
+
renderToolButton
|
|
4337
|
+
})
|
|
4338
|
+
)
|
|
3417
4339
|
}
|
|
3418
4340
|
) : null,
|
|
3419
4341
|
open && !renderToolButton ? /* @__PURE__ */ jsx(
|
|
@@ -3423,69 +4345,19 @@ function ToolbarOverflowMenu({
|
|
|
3423
4345
|
role: "menu",
|
|
3424
4346
|
"aria-label": menuAriaLabel,
|
|
3425
4347
|
className: "vector-toolbar-overflow-panel",
|
|
3426
|
-
children: tools.map(
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
type: "button",
|
|
3435
|
-
role: "menuitemradio",
|
|
3436
|
-
"aria-checked": selected,
|
|
3437
|
-
tabIndex: index === 0 ? 0 : -1,
|
|
3438
|
-
"aria-label": label,
|
|
3439
|
-
...tool.shortcutHint !== void 0 ? { "aria-keyshortcuts": tool.shortcutHint } : {},
|
|
3440
|
-
style: overflowGridCellButtonStyle,
|
|
3441
|
-
onPointerDown: (ev) => {
|
|
3442
|
-
if (ev.pointerType === "mouse") {
|
|
3443
|
-
ev.preventDefault();
|
|
3444
|
-
}
|
|
3445
|
-
},
|
|
3446
|
-
onClick: () => {
|
|
3447
|
-
onSelect(tool.id);
|
|
3448
|
-
close();
|
|
3449
|
-
},
|
|
3450
|
-
children: /* @__PURE__ */ jsx(
|
|
3451
|
-
"span",
|
|
3452
|
-
{
|
|
3453
|
-
style: {
|
|
3454
|
-
display: "flex",
|
|
3455
|
-
alignItems: "center",
|
|
3456
|
-
justifyContent: "center",
|
|
3457
|
-
lineHeight: 0
|
|
3458
|
-
},
|
|
3459
|
-
children: tool.icon ?? /* @__PURE__ */ jsx(
|
|
3460
|
-
"span",
|
|
3461
|
-
{
|
|
3462
|
-
style: {
|
|
3463
|
-
fontSize: "11px",
|
|
3464
|
-
fontWeight: 700,
|
|
3465
|
-
lineHeight: 1.1,
|
|
3466
|
-
textAlign: "center",
|
|
3467
|
-
maxWidth: "34px",
|
|
3468
|
-
overflow: "hidden",
|
|
3469
|
-
textOverflow: "ellipsis"
|
|
3470
|
-
},
|
|
3471
|
-
children: tool.label.slice(0, 3)
|
|
3472
|
-
}
|
|
3473
|
-
)
|
|
3474
|
-
}
|
|
3475
|
-
)
|
|
3476
|
-
}
|
|
3477
|
-
),
|
|
3478
|
-
/* @__PURE__ */ jsxs("span", { className: "vector-toolbar-overflow-tip", "aria-hidden": "true", children: [
|
|
3479
|
-
/* @__PURE__ */ jsx("span", { children: tooltipName }),
|
|
3480
|
-
tool.shortcutHint !== void 0 ? /* @__PURE__ */ jsx("span", { className: "vector-toolbar-overflow-tip-shortcut", children: tool.shortcutHint }) : null
|
|
3481
|
-
] })
|
|
3482
|
-
] }, tool.id);
|
|
3483
|
-
})
|
|
4348
|
+
children: tools.map(
|
|
4349
|
+
(tool, index) => renderOverflowToolButton(tool, {
|
|
4350
|
+
selectedId,
|
|
4351
|
+
selectTool: onSelect,
|
|
4352
|
+
closeMenu: close,
|
|
4353
|
+
tabIndex: index === 0 ? 0 : -1
|
|
4354
|
+
})
|
|
4355
|
+
)
|
|
3484
4356
|
}
|
|
3485
4357
|
) : null
|
|
3486
4358
|
] });
|
|
3487
4359
|
}
|
|
3488
|
-
function
|
|
4360
|
+
function VectorToolbarComponent({
|
|
3489
4361
|
value,
|
|
3490
4362
|
onChange,
|
|
3491
4363
|
tools,
|
|
@@ -3507,23 +4379,63 @@ function VectorToolbar({
|
|
|
3507
4379
|
const pluginContext = useContext(CanvuPluginContext);
|
|
3508
4380
|
const runtimeTools = pluginContext?.resolvedTools;
|
|
3509
4381
|
const resolvedTools = tools ?? runtimeTools ?? DEFAULT_VECTOR_TOOLS;
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
4382
|
+
if (typeof children === "function") {
|
|
4383
|
+
const ctx = {
|
|
4384
|
+
tools: resolvedTools,
|
|
4385
|
+
selectedId: value,
|
|
4386
|
+
selectTool: onChange,
|
|
4387
|
+
toolLocked,
|
|
4388
|
+
setToolLocked: (locked) => onToolLockedChange?.(locked)
|
|
4389
|
+
};
|
|
3518
4390
|
return /* @__PURE__ */ jsx("div", { className, style, children: children(ctx) });
|
|
3519
4391
|
}
|
|
4392
|
+
const flexDir = orientation === "vertical" ? "column" : "row";
|
|
4393
|
+
const toolbarClass = className.trim() === "" ? "vector-toolbar" : `vector-toolbar ${className.trim()}`;
|
|
4394
|
+
if (children !== void 0 && children !== null) {
|
|
4395
|
+
const itemCtx = {
|
|
4396
|
+
selectedId: value,
|
|
4397
|
+
selectTool: onChange,
|
|
4398
|
+
toolLocked,
|
|
4399
|
+
setToolLocked: (locked) => onToolLockedChange?.(locked),
|
|
4400
|
+
density,
|
|
4401
|
+
buttonClassName,
|
|
4402
|
+
activeButtonClassName,
|
|
4403
|
+
renderToolButton,
|
|
4404
|
+
insideOverflow: false,
|
|
4405
|
+
closeOverflow: noop2,
|
|
4406
|
+
orientation
|
|
4407
|
+
};
|
|
4408
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4409
|
+
/* @__PURE__ */ jsx("style", { children: TOOLBAR_TOOLTIP_CSS }),
|
|
4410
|
+
/* @__PURE__ */ jsx("style", { children: OVERFLOW_MENU_CSS }),
|
|
4411
|
+
/* @__PURE__ */ jsx("style", { children: TOOLBAR_MOBILE_CSS }),
|
|
4412
|
+
/* @__PURE__ */ jsx(
|
|
4413
|
+
"div",
|
|
4414
|
+
{
|
|
4415
|
+
role: "toolbar",
|
|
4416
|
+
"data-orientation": orientation,
|
|
4417
|
+
"aria-label": ariaLabel,
|
|
4418
|
+
"aria-orientation": orientation === "vertical" ? "vertical" : "horizontal",
|
|
4419
|
+
className: toolbarClass,
|
|
4420
|
+
style: { ...toolbarStyles, flexDirection: flexDir, ...style },
|
|
4421
|
+
children: /* @__PURE__ */ jsx(VectorToolbarItemContext.Provider, { value: itemCtx, children })
|
|
4422
|
+
}
|
|
4423
|
+
)
|
|
4424
|
+
] });
|
|
4425
|
+
}
|
|
3520
4426
|
const { primary: primaryTools, overflow: overflowTools } = splitToolbarTools(
|
|
3521
4427
|
resolvedTools,
|
|
3522
4428
|
overflowToolIds
|
|
3523
4429
|
);
|
|
3524
|
-
const flexDir = orientation === "vertical" ? "column" : "row";
|
|
3525
4430
|
const showOverflowMenu = overflowTools.length > 0;
|
|
3526
|
-
const
|
|
4431
|
+
const inlineCtx = {
|
|
4432
|
+
selectedId: value,
|
|
4433
|
+
selectTool: onChange,
|
|
4434
|
+
density,
|
|
4435
|
+
buttonClassName,
|
|
4436
|
+
activeButtonClassName,
|
|
4437
|
+
renderToolButton
|
|
4438
|
+
};
|
|
3527
4439
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3528
4440
|
/* @__PURE__ */ jsx("style", { children: TOOLBAR_TOOLTIP_CSS }),
|
|
3529
4441
|
/* @__PURE__ */ jsx("style", { children: OVERFLOW_MENU_CSS }),
|
|
@@ -3554,20 +4466,9 @@ function VectorToolbar({
|
|
|
3554
4466
|
minWidth: "40px",
|
|
3555
4467
|
padding: "6px 8px"
|
|
3556
4468
|
} : {},
|
|
3557
|
-
...toolLocked ?
|
|
3558
|
-
background: "rgba(24,24,27,0.1)",
|
|
3559
|
-
borderColor: "rgba(24,24,27,0.28)",
|
|
3560
|
-
boxShadow: "inset 0 0 0 1px rgba(24,24,27,0.08)"
|
|
3561
|
-
} : {
|
|
3562
|
-
borderColor: "transparent",
|
|
3563
|
-
boxShadow: "none"
|
|
3564
|
-
}
|
|
3565
|
-
},
|
|
3566
|
-
onPointerDown: (ev) => {
|
|
3567
|
-
if (ev.pointerType === "mouse") {
|
|
3568
|
-
ev.preventDefault();
|
|
3569
|
-
}
|
|
4469
|
+
...toolLocked ? activeToggleStyle : inactiveToggleStyle
|
|
3570
4470
|
},
|
|
4471
|
+
onPointerDown: preventMouseDefault2,
|
|
3571
4472
|
onClick: () => onToolLockedChange?.(!toolLocked),
|
|
3572
4473
|
children: /* @__PURE__ */ jsx(ToolLockGlyph, { locked: toolLocked })
|
|
3573
4474
|
}
|
|
@@ -3576,89 +4477,7 @@ function VectorToolbar({
|
|
|
3576
4477
|
] }),
|
|
3577
4478
|
/* @__PURE__ */ jsx("span", { "aria-hidden": true, style: toolLockDividerStyle })
|
|
3578
4479
|
] }) : null,
|
|
3579
|
-
primaryTools.map((tool) =>
|
|
3580
|
-
const selected = tool.id === value;
|
|
3581
|
-
const label = tool.ariaLabel ?? tool.label;
|
|
3582
|
-
if (renderToolButton) {
|
|
3583
|
-
return /* @__PURE__ */ jsx("div", { children: renderToolButton({
|
|
3584
|
-
tool,
|
|
3585
|
-
selected,
|
|
3586
|
-
onSelect: () => onChange(tool.id)
|
|
3587
|
-
}) }, tool.id);
|
|
3588
|
-
}
|
|
3589
|
-
const tooltipName = tool.tooltipLabel ?? tool.label;
|
|
3590
|
-
const tooltipText = tool.shortcutHint !== void 0 ? `${tooltipName} \xB7 ${tool.shortcutHint}` : tooltipName;
|
|
3591
|
-
const labelOnly = tool.icon == null;
|
|
3592
|
-
const labelTextStyle = labelOnly ? {
|
|
3593
|
-
fontSize: "12px",
|
|
3594
|
-
fontWeight: 600,
|
|
3595
|
-
letterSpacing: "0.02em",
|
|
3596
|
-
lineHeight: 1.2,
|
|
3597
|
-
WebkitFontSmoothing: "antialiased",
|
|
3598
|
-
MozOsxFontSmoothing: "grayscale",
|
|
3599
|
-
textRendering: "geometricPrecision"
|
|
3600
|
-
} : {};
|
|
3601
|
-
return /* @__PURE__ */ jsxs("span", { className: "vector-toolbar-tool-wrap", children: [
|
|
3602
|
-
/* @__PURE__ */ jsxs(
|
|
3603
|
-
"button",
|
|
3604
|
-
{
|
|
3605
|
-
type: "button",
|
|
3606
|
-
"aria-pressed": selected,
|
|
3607
|
-
"aria-label": label,
|
|
3608
|
-
...tool.shortcutHint !== void 0 ? { "aria-keyshortcuts": tool.shortcutHint } : {},
|
|
3609
|
-
className: `${buttonClassName} ${selected ? activeButtonClassName : ""}`.trim(),
|
|
3610
|
-
style: {
|
|
3611
|
-
...defaultButtonStyle,
|
|
3612
|
-
...density === "compact" ? {
|
|
3613
|
-
minHeight: "40px",
|
|
3614
|
-
minWidth: labelOnly ? "52px" : "40px",
|
|
3615
|
-
padding: "6px 8px"
|
|
3616
|
-
} : {},
|
|
3617
|
-
...selected ? {
|
|
3618
|
-
background: "rgba(24,24,27,0.1)",
|
|
3619
|
-
borderColor: "rgba(24,24,27,0.28)",
|
|
3620
|
-
boxShadow: "inset 0 0 0 1px rgba(24,24,27,0.08)"
|
|
3621
|
-
} : {
|
|
3622
|
-
borderColor: "transparent",
|
|
3623
|
-
boxShadow: "none"
|
|
3624
|
-
}
|
|
3625
|
-
},
|
|
3626
|
-
onPointerDown: (ev) => {
|
|
3627
|
-
if (ev.pointerType === "mouse") {
|
|
3628
|
-
ev.preventDefault();
|
|
3629
|
-
}
|
|
3630
|
-
},
|
|
3631
|
-
onClick: () => onChange(tool.id),
|
|
3632
|
-
children: [
|
|
3633
|
-
/* @__PURE__ */ jsx(
|
|
3634
|
-
"span",
|
|
3635
|
-
{
|
|
3636
|
-
style: {
|
|
3637
|
-
display: "flex",
|
|
3638
|
-
alignItems: "center",
|
|
3639
|
-
justifyContent: "center"
|
|
3640
|
-
},
|
|
3641
|
-
children: tool.icon ?? /* @__PURE__ */ jsx("span", { style: labelTextStyle, children: tool.label })
|
|
3642
|
-
}
|
|
3643
|
-
),
|
|
3644
|
-
density === "comfortable" && tool.icon ? /* @__PURE__ */ jsx(
|
|
3645
|
-
"span",
|
|
3646
|
-
{
|
|
3647
|
-
style: {
|
|
3648
|
-
lineHeight: 1,
|
|
3649
|
-
maxWidth: "56px",
|
|
3650
|
-
overflow: "hidden",
|
|
3651
|
-
textOverflow: "ellipsis"
|
|
3652
|
-
},
|
|
3653
|
-
children: tool.label
|
|
3654
|
-
}
|
|
3655
|
-
) : null
|
|
3656
|
-
]
|
|
3657
|
-
}
|
|
3658
|
-
),
|
|
3659
|
-
/* @__PURE__ */ jsx("span", { className: "vector-toolbar-tip", "aria-hidden": "true", children: tooltipText })
|
|
3660
|
-
] }, tool.id);
|
|
3661
|
-
}),
|
|
4480
|
+
primaryTools.map((tool) => renderInlineToolButton(tool, inlineCtx)),
|
|
3662
4481
|
showOverflowMenu && orientation === "horizontal" ? /* @__PURE__ */ jsx(
|
|
3663
4482
|
"span",
|
|
3664
4483
|
{
|
|
@@ -3685,6 +4504,51 @@ function VectorToolbar({
|
|
|
3685
4504
|
)
|
|
3686
4505
|
] });
|
|
3687
4506
|
}
|
|
4507
|
+
function noop2() {
|
|
4508
|
+
}
|
|
4509
|
+
function makeToolBinding(id) {
|
|
4510
|
+
const def = DEFAULT_VECTOR_TOOLS.find((t) => t.id === id);
|
|
4511
|
+
if (!def) {
|
|
4512
|
+
throw new Error(`No default tool with id "${id}"`);
|
|
4513
|
+
}
|
|
4514
|
+
const Component = ((props) => /* @__PURE__ */ jsx(VectorToolbarTool, { ...def, className: props?.className }));
|
|
4515
|
+
Component.toolId = id;
|
|
4516
|
+
Component.displayName = `VectorToolbar.${def.label}`;
|
|
4517
|
+
return Component;
|
|
4518
|
+
}
|
|
4519
|
+
var HandBinding = makeToolBinding("hand");
|
|
4520
|
+
var SelectBinding = makeToolBinding("select");
|
|
4521
|
+
var RectBinding = makeToolBinding("rect");
|
|
4522
|
+
var EllipseBinding = makeToolBinding("ellipse");
|
|
4523
|
+
var LineBinding = makeToolBinding("line");
|
|
4524
|
+
var ArrowBinding = makeToolBinding("arrow");
|
|
4525
|
+
var DrawBinding = makeToolBinding("draw");
|
|
4526
|
+
var MarkerBinding = makeToolBinding("marker");
|
|
4527
|
+
var LaserBinding = makeToolBinding("laser");
|
|
4528
|
+
var EraserBinding = makeToolBinding("eraser");
|
|
4529
|
+
var TextBinding = makeToolBinding("text");
|
|
4530
|
+
var ImageBinding = makeToolBinding("image");
|
|
4531
|
+
VectorToolbarComponent.displayName = "VectorToolbar";
|
|
4532
|
+
var VectorToolbar = Object.assign(
|
|
4533
|
+
VectorToolbarComponent,
|
|
4534
|
+
{
|
|
4535
|
+
Tool: VectorToolbarTool,
|
|
4536
|
+
ToolLock: VectorToolbarToolLock,
|
|
4537
|
+
Overflow: VectorToolbarOverflow,
|
|
4538
|
+
Hand: HandBinding,
|
|
4539
|
+
Select: SelectBinding,
|
|
4540
|
+
Rect: RectBinding,
|
|
4541
|
+
Ellipse: EllipseBinding,
|
|
4542
|
+
Line: LineBinding,
|
|
4543
|
+
Arrow: ArrowBinding,
|
|
4544
|
+
Draw: DrawBinding,
|
|
4545
|
+
Marker: MarkerBinding,
|
|
4546
|
+
Laser: LaserBinding,
|
|
4547
|
+
Eraser: EraserBinding,
|
|
4548
|
+
Text: TextBinding,
|
|
4549
|
+
Image: ImageBinding
|
|
4550
|
+
}
|
|
4551
|
+
);
|
|
3688
4552
|
|
|
3689
4553
|
// src/camera/camera.ts
|
|
3690
4554
|
init_rect();
|
|
@@ -5054,30 +5918,6 @@ var SvgVectorRenderer = class {
|
|
|
5054
5918
|
}
|
|
5055
5919
|
};
|
|
5056
5920
|
|
|
5057
|
-
// src/scene/clone-item.ts
|
|
5058
|
-
init_shape_builders();
|
|
5059
|
-
function cloneVectorSceneItemWithNewId(item) {
|
|
5060
|
-
const id = createShapeId();
|
|
5061
|
-
const copy = JSON.parse(JSON.stringify(item));
|
|
5062
|
-
let next = { ...copy, id };
|
|
5063
|
-
if (next.toolKind === "arrow" && next.line) {
|
|
5064
|
-
next = {
|
|
5065
|
-
...next,
|
|
5066
|
-
childrenSvg: buildArrowSvg(id, next.line, resolveStrokeStyle(next))
|
|
5067
|
-
};
|
|
5068
|
-
}
|
|
5069
|
-
if (next.toolKind === "text" && next.text !== void 0) {
|
|
5070
|
-
return rebuildItemSvg(next);
|
|
5071
|
-
}
|
|
5072
|
-
if (next.toolKind === "custom" && next.customInnerSvg && next.customIntrinsicSize) {
|
|
5073
|
-
return rebuildItemSvg(next);
|
|
5074
|
-
}
|
|
5075
|
-
return next;
|
|
5076
|
-
}
|
|
5077
|
-
function cloneVectorSceneItemsWithNewIds(items) {
|
|
5078
|
-
return items.map(cloneVectorSceneItemWithNewId);
|
|
5079
|
-
}
|
|
5080
|
-
|
|
5081
5921
|
// src/scene/scene.ts
|
|
5082
5922
|
var VectorScene = class {
|
|
5083
5923
|
items = [];
|
|
@@ -7673,9 +8513,7 @@ var VectorViewport = forwardRef(
|
|
|
7673
8513
|
return;
|
|
7674
8514
|
}
|
|
7675
8515
|
if (!e.shiftKey && cur.length > 0) {
|
|
7676
|
-
const selectedUnlockedItems = cur.map((id) => resolved.find((it) => it.id === id)).filter(
|
|
7677
|
-
(it) => it != null && !it.locked
|
|
7678
|
-
);
|
|
8516
|
+
const selectedUnlockedItems = cur.map((id) => resolved.find((it) => it.id === id)).filter((it) => it != null && !it.locked);
|
|
7679
8517
|
if (selectedUnlockedItems.some(
|
|
7680
8518
|
(it) => pointInSelectedItemBounds(it, worldX, worldY)
|
|
7681
8519
|
)) {
|
|
@@ -8757,110 +9595,7 @@ var VectorViewport = forwardRef(
|
|
|
8757
9595
|
}
|
|
8758
9596
|
);
|
|
8759
9597
|
VectorViewport.displayName = "VectorViewport";
|
|
8760
|
-
var DEFAULT_SHELL_STYLE = {
|
|
8761
|
-
position: "absolute",
|
|
8762
|
-
left: 12,
|
|
8763
|
-
bottom: 140,
|
|
8764
|
-
zIndex: 22
|
|
8765
|
-
};
|
|
8766
|
-
var layoutStyle = {
|
|
8767
|
-
display: "flex",
|
|
8768
|
-
flexDirection: "column",
|
|
8769
|
-
gap: 4,
|
|
8770
|
-
/* Let clicks pass through the flex gaps; buttons opt in below. */
|
|
8771
|
-
pointerEvents: "none"
|
|
8772
|
-
};
|
|
8773
|
-
var btnStyle2 = {
|
|
8774
|
-
pointerEvents: "auto",
|
|
8775
|
-
width: 36,
|
|
8776
|
-
height: 36,
|
|
8777
|
-
display: "inline-flex",
|
|
8778
|
-
alignItems: "center",
|
|
8779
|
-
justifyContent: "center",
|
|
8780
|
-
borderRadius: 8,
|
|
8781
|
-
border: "1px solid rgba(0,0,0,0.12)",
|
|
8782
|
-
background: "rgba(255,255,255,0.96)",
|
|
8783
|
-
boxShadow: "0 1px 3px rgba(0,0,0,0.08)",
|
|
8784
|
-
cursor: "pointer",
|
|
8785
|
-
fontSize: 18,
|
|
8786
|
-
lineHeight: 1,
|
|
8787
|
-
fontWeight: 600,
|
|
8788
|
-
color: "#18181b",
|
|
8789
|
-
padding: 0,
|
|
8790
|
-
outline: "none",
|
|
8791
|
-
WebkitTapHighlightColor: "transparent"
|
|
8792
|
-
};
|
|
8793
|
-
var labelStyle3 = {
|
|
8794
|
-
pointerEvents: "none",
|
|
8795
|
-
fontSize: 10,
|
|
8796
|
-
fontWeight: 600,
|
|
8797
|
-
color: "#52525b",
|
|
8798
|
-
textAlign: "center",
|
|
8799
|
-
userSelect: "none",
|
|
8800
|
-
padding: "2px 0"
|
|
8801
|
-
};
|
|
8802
|
-
var fieldsetReset = {
|
|
8803
|
-
border: "none",
|
|
8804
|
-
margin: 0,
|
|
8805
|
-
padding: 0,
|
|
8806
|
-
minWidth: 0
|
|
8807
|
-
};
|
|
8808
|
-
function ViewportZoomControls({
|
|
8809
|
-
zoomPercent,
|
|
8810
|
-
onZoomIn,
|
|
8811
|
-
onZoomOut,
|
|
8812
|
-
className = "",
|
|
8813
|
-
position,
|
|
8814
|
-
inset = 12,
|
|
8815
|
-
zIndex = 22,
|
|
8816
|
-
style
|
|
8817
|
-
}) {
|
|
8818
|
-
const anchorStyle = position !== void 0 ? getBoardPositionStyle(position, inset, zIndex) : DEFAULT_SHELL_STYLE;
|
|
8819
|
-
return /* @__PURE__ */ jsxs(
|
|
8820
|
-
"fieldset",
|
|
8821
|
-
{
|
|
8822
|
-
className,
|
|
8823
|
-
"data-position": position ?? "default",
|
|
8824
|
-
"aria-label": "Zoom controls",
|
|
8825
|
-
style: { ...anchorStyle, ...layoutStyle, ...fieldsetReset, ...style },
|
|
8826
|
-
children: [
|
|
8827
|
-
/* @__PURE__ */ jsx(
|
|
8828
|
-
"button",
|
|
8829
|
-
{
|
|
8830
|
-
type: "button",
|
|
8831
|
-
style: btnStyle2,
|
|
8832
|
-
"aria-label": "Zoom in",
|
|
8833
|
-
title: "Zoom in",
|
|
8834
|
-
onPointerDown: (e) => {
|
|
8835
|
-
if (e.pointerType === "mouse") e.preventDefault();
|
|
8836
|
-
},
|
|
8837
|
-
onClick: onZoomIn,
|
|
8838
|
-
children: "+"
|
|
8839
|
-
}
|
|
8840
|
-
),
|
|
8841
|
-
/* @__PURE__ */ jsx(
|
|
8842
|
-
"button",
|
|
8843
|
-
{
|
|
8844
|
-
type: "button",
|
|
8845
|
-
style: btnStyle2,
|
|
8846
|
-
"aria-label": "Zoom out",
|
|
8847
|
-
title: "Zoom out",
|
|
8848
|
-
onPointerDown: (e) => {
|
|
8849
|
-
if (e.pointerType === "mouse") e.preventDefault();
|
|
8850
|
-
},
|
|
8851
|
-
onClick: onZoomOut,
|
|
8852
|
-
children: "\u2212"
|
|
8853
|
-
}
|
|
8854
|
-
),
|
|
8855
|
-
/* @__PURE__ */ jsxs("span", { style: labelStyle3, "aria-hidden": true, children: [
|
|
8856
|
-
zoomPercent,
|
|
8857
|
-
"%"
|
|
8858
|
-
] })
|
|
8859
|
-
]
|
|
8860
|
-
}
|
|
8861
|
-
);
|
|
8862
|
-
}
|
|
8863
9598
|
|
|
8864
|
-
export { CanvuChromeContext, CanvuPluginContext, DEFAULT_OVERFLOW_TOOL_IDS, DEFAULT_VECTOR_CANVAS_STORAGE_KEY, DEFAULT_VECTOR_TOOLS, IconArrow, IconDraw, IconEllipse, IconHand, IconImage, IconLaser, IconLine, IconRect, IconSelect, IconText, NavMenu, ShapeContextMenu, VectorCanvas, VectorCanvasBody, VectorCanvasHeader, VectorCanvasMain, VectorCanvasRoot, VectorCanvasToolbar, VectorCanvasViewportSurface, VectorSelectionInspector, VectorToolbar, VectorViewport,
|
|
9599
|
+
export { CanvuChromeContext, CanvuPluginContext, DEFAULT_OVERFLOW_TOOL_IDS, DEFAULT_VECTOR_CANVAS_STORAGE_KEY, DEFAULT_VECTOR_TOOLS, IconArrow, IconDraw, IconEllipse, IconHand, IconImage, IconLaser, IconLine, IconRect, IconSelect, IconText, ImagesMenu, NavMenu, ShapeContextMenu, VectorCanvas, VectorCanvasBody, VectorCanvasHeader, VectorCanvasMain, VectorCanvasRoot, VectorCanvasToolbar, VectorCanvasViewportSurface, VectorSelectionInspector, VectorToolbar, VectorViewport, createCanvuPlugin, createIndexedDbPersistenceAdapter, createLocalStoragePersistenceAdapter, createNoopPersistenceAdapter, createToolPlugin, cursorForVectorToolId, getBoardPositionStyle, hydrateSceneItemsWithAssets, ingestAssetFilesToSceneItems, useCanvuChromeContext, useCanvuDocumentContext, useCanvuPluginContext, useCanvuPluginContribution, useCanvuResolvedTools, useCanvuViewportContext, useVectorCanvasDocument };
|
|
8865
9600
|
//# sourceMappingURL=react.js.map
|
|
8866
9601
|
//# sourceMappingURL=react.js.map
|