canvu-react 0.3.38 → 0.3.40
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/{asset-hydration-EtEuBwb7.d.cts → asset-hydration-B7yMDQE-.d.cts} +2 -2
- package/dist/{asset-hydration-DrTOgDdd.d.ts → asset-hydration-CbwQVAwh.d.ts} +2 -2
- package/dist/{camera-Di5R_Rwl.d.cts → camera-CVVG7z56.d.cts} +1 -1
- package/dist/{camera-AoTwBSoE.d.ts → camera-CoRYN_IV.d.ts} +1 -1
- package/dist/chatbot.d.cts +4 -4
- package/dist/chatbot.d.ts +4 -4
- package/dist/index.cjs +164 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +159 -16
- package/dist/index.js.map +1 -1
- package/dist/native.cjs +57 -14
- package/dist/native.cjs.map +1 -1
- package/dist/native.d.cts +2 -2
- package/dist/native.d.ts +2 -2
- package/dist/native.js +57 -14
- package/dist/native.js.map +1 -1
- package/dist/react.cjs +731 -258
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +10 -10
- package/dist/react.d.ts +10 -10
- package/dist/react.js +731 -258
- package/dist/react.js.map +1 -1
- package/dist/realtime.cjs +36 -0
- package/dist/realtime.cjs.map +1 -1
- package/dist/realtime.d.cts +6 -6
- package/dist/realtime.d.ts +6 -6
- package/dist/realtime.js +36 -0
- package/dist/realtime.js.map +1 -1
- package/dist/{shape-builders-CsbSRZnQ.d.cts → shape-builders-BAWu-PxX.d.cts} +46 -4
- package/dist/{shape-builders-CsSXKCcs.d.ts → shape-builders-ClKv9tz9.d.ts} +46 -4
- package/dist/tldraw.cjs +189 -78
- package/dist/tldraw.cjs.map +1 -1
- package/dist/tldraw.d.cts +1 -1
- package/dist/tldraw.d.ts +1 -1
- package/dist/tldraw.js +189 -78
- package/dist/tldraw.js.map +1 -1
- package/dist/{types-DWGk2_GZ.d.cts → types-BC9Xgfu6.d.cts} +20 -6
- package/dist/{types-Bnq2HtHQ.d.cts → types-BCCvY6ie.d.cts} +2 -0
- package/dist/{types-Bnq2HtHQ.d.ts → types-BCCvY6ie.d.ts} +2 -0
- package/dist/{types-B2Na677H.d.cts → types-BUPc2Zgw.d.cts} +1 -1
- package/dist/{types-zmUah-vP.d.ts → types-CYtq9Pr9.d.ts} +1 -1
- package/dist/{types-B6PAYKzx.d.ts → types-DlSVGX0w.d.ts} +20 -6
- package/package.json +1 -1
package/dist/react.js
CHANGED
|
@@ -84,6 +84,12 @@ function lineHeightFor(fontSize) {
|
|
|
84
84
|
function firstLineBaselineY(fontSize) {
|
|
85
85
|
return fontSize * FIRST_LINE_BASELINE_RATIO;
|
|
86
86
|
}
|
|
87
|
+
function textBaselineYFor(fontSize) {
|
|
88
|
+
return firstLineBaselineY(fontSize);
|
|
89
|
+
}
|
|
90
|
+
function textLineHeightFor(fontSize) {
|
|
91
|
+
return lineHeightFor(fontSize);
|
|
92
|
+
}
|
|
87
93
|
function measureTextBoundsLocal(content, fontSize = DEFAULT_TEXT_FONT_SIZE) {
|
|
88
94
|
const cacheKey = textMeasureCacheKey(content, fontSize);
|
|
89
95
|
const cached = textMeasureCache.get(cacheKey);
|
|
@@ -97,7 +103,7 @@ function measureTextBoundsLocal(content, fontSize = DEFAULT_TEXT_FONT_SIZE) {
|
|
|
97
103
|
let maxInnerW = 0;
|
|
98
104
|
const ctx = getSharedMeasureContext();
|
|
99
105
|
if (ctx) {
|
|
100
|
-
ctx.font = `${fontSize}px
|
|
106
|
+
ctx.font = `${fontSize}px ${TEXT_FONT_FAMILY}`;
|
|
101
107
|
for (const line of lines) {
|
|
102
108
|
const toMeasure = trimmed.length === 0 ? PLACEHOLDER : line.length === 0 ? " " : line;
|
|
103
109
|
maxInnerW = Math.max(maxInnerW, ctx.measureText(toMeasure).width);
|
|
@@ -113,22 +119,22 @@ function measureTextBoundsLocal(content, fontSize = DEFAULT_TEXT_FONT_SIZE) {
|
|
|
113
119
|
const width = Math.max(minW, TEXT_PAD_X * 2 + maxInnerW);
|
|
114
120
|
const height = Math.max(
|
|
115
121
|
MIN_TEXT_BOX_H,
|
|
116
|
-
baselineY + (lines.length - 1) * lh + Math.max(
|
|
122
|
+
baselineY + (lines.length - 1) * lh + Math.max(4, fontSize * BOTTOM_PAD_RATIO)
|
|
117
123
|
);
|
|
118
124
|
const measured = { width, height };
|
|
119
125
|
cacheMeasuredBounds(cacheKey, measured);
|
|
120
126
|
return measured;
|
|
121
127
|
}
|
|
122
|
-
function buildTextSvg(content, _width, _height, fillColor = "#
|
|
128
|
+
function buildTextSvg(content, _width, _height, fillColor = "#1d1d1d", fontSize = DEFAULT_TEXT_FONT_SIZE) {
|
|
123
129
|
const lh = lineHeightFor(fontSize);
|
|
124
130
|
const y0 = firstLineBaselineY(fontSize);
|
|
125
131
|
const trimmed = content.trim();
|
|
126
132
|
if (trimmed.length === 0) {
|
|
127
|
-
return `<text x="4" y="${y0}" font-size="${fontSize}" font-family="
|
|
133
|
+
return `<text x="4" y="${y0}" font-size="${fontSize}" font-family="${TEXT_FONT_FAMILY}" fill="#94a3b8" font-style="italic">${escapeSvgTextContent(PLACEHOLDER)}</text>`;
|
|
128
134
|
}
|
|
129
135
|
const lines = content.split("\n");
|
|
130
136
|
if (lines.length === 1) {
|
|
131
|
-
return `<text x="4" y="${y0}" font-size="${fontSize}" font-family="
|
|
137
|
+
return `<text x="4" y="${y0}" font-size="${fontSize}" font-family="${TEXT_FONT_FAMILY}" fill="${fillColor}">${escapeSvgTextContent(lines[0] ?? "")}</text>`;
|
|
132
138
|
}
|
|
133
139
|
const parts = [];
|
|
134
140
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -139,28 +145,32 @@ function buildTextSvg(content, _width, _height, fillColor = "#2563eb", fontSize
|
|
|
139
145
|
parts.push(`<tspan x="4" dy="${lh}">${escapeSvgTextContent(line)}</tspan>`);
|
|
140
146
|
}
|
|
141
147
|
}
|
|
142
|
-
return `<text x="4" y="${y0}" font-size="${fontSize}" font-family="
|
|
148
|
+
return `<text x="4" y="${y0}" font-size="${fontSize}" font-family="${TEXT_FONT_FAMILY}" fill="${fillColor}">${parts.join("")}</text>`;
|
|
143
149
|
}
|
|
144
|
-
function buildTextFixedBoundsSvg(content, width, height, fillColor = "#
|
|
150
|
+
function buildTextFixedBoundsSvg(content, width, height, fillColor = "#1d1d1d", fontSize = DEFAULT_TEXT_FONT_SIZE) {
|
|
145
151
|
const w = Math.max(1, width);
|
|
146
152
|
const h = Math.max(1, height);
|
|
147
153
|
const lh = lineHeightFor(fontSize);
|
|
148
154
|
const trimmed = content.trim();
|
|
155
|
+
const padTop = EDIT_TOP_PAD_RATIO * fontSize;
|
|
149
156
|
if (trimmed.length === 0) {
|
|
150
|
-
return `<foreignObject width="${w}" height="${h}"><div xmlns="http://www.w3.org/1999/xhtml" style="box-sizing:border-box;width:100%;height:100%;margin:0;padding
|
|
157
|
+
return `<foreignObject width="${w}" height="${h}"><div xmlns="http://www.w3.org/1999/xhtml" style="box-sizing:border-box;width:100%;height:100%;margin:0;padding:${padTop}px 4px 0 4px;font-size:${fontSize}px;line-height:${lh}px;font-family:${TEXT_FONT_FAMILY};white-space:pre-wrap;word-wrap:break-word;overflow:hidden;color:#94a3b8;font-style:italic">${escapeHtmlText(PLACEHOLDER)}</div></foreignObject>`;
|
|
151
158
|
}
|
|
152
159
|
const body = escapeHtmlText(content);
|
|
153
|
-
return `<foreignObject width="${w}" height="${h}"><div xmlns="http://www.w3.org/1999/xhtml" style="box-sizing:border-box;width:100%;height:100%;margin:0;padding
|
|
160
|
+
return `<foreignObject width="${w}" height="${h}"><div xmlns="http://www.w3.org/1999/xhtml" style="box-sizing:border-box;width:100%;height:100%;margin:0;padding:${padTop}px 4px 0 4px;font-size:${fontSize}px;line-height:${lh}px;font-family:${TEXT_FONT_FAMILY};white-space:pre-wrap;word-wrap:break-word;overflow:hidden;color:${fillColor}">${body}</div></foreignObject>`;
|
|
154
161
|
}
|
|
155
|
-
var DEFAULT_TEXT_FONT_SIZE, LINE_HEIGHT_RATIO, FIRST_LINE_BASELINE_RATIO, PLACEHOLDER, MIN_TEXT_BOX_W, MIN_TEXT_BOX_H, TEXT_PAD_X, MAX_TEXT_MEASURE_CACHE_ENTRIES, sharedMeasureContext, textMeasureCache;
|
|
162
|
+
var DEFAULT_TEXT_FONT_SIZE, TEXT_FONT_FAMILY, LINE_HEIGHT_RATIO, FIRST_LINE_BASELINE_RATIO, EDIT_TOP_PAD_RATIO, BOTTOM_PAD_RATIO, PLACEHOLDER, MIN_TEXT_BOX_W, MIN_TEXT_BOX_H, TEXT_PAD_X, MAX_TEXT_MEASURE_CACHE_ENTRIES, sharedMeasureContext, textMeasureCache;
|
|
156
163
|
var init_text_svg = __esm({
|
|
157
164
|
"src/scene/text-svg.ts"() {
|
|
158
165
|
DEFAULT_TEXT_FONT_SIZE = 18;
|
|
166
|
+
TEXT_FONT_FAMILY = "Inter, -apple-system, BlinkMacSystemFont, ui-sans-serif, system-ui, sans-serif";
|
|
159
167
|
LINE_HEIGHT_RATIO = 22 / 18;
|
|
160
|
-
FIRST_LINE_BASELINE_RATIO =
|
|
168
|
+
FIRST_LINE_BASELINE_RATIO = 20 / 18;
|
|
169
|
+
EDIT_TOP_PAD_RATIO = 4 / 18;
|
|
170
|
+
BOTTOM_PAD_RATIO = 4 / 18;
|
|
161
171
|
PLACEHOLDER = "Tap to type";
|
|
162
172
|
MIN_TEXT_BOX_W = 40;
|
|
163
|
-
MIN_TEXT_BOX_H =
|
|
173
|
+
MIN_TEXT_BOX_H = 26;
|
|
164
174
|
TEXT_PAD_X = 4;
|
|
165
175
|
MAX_TEXT_MEASURE_CACHE_ENTRIES = 2e3;
|
|
166
176
|
textMeasureCache = /* @__PURE__ */ new Map();
|
|
@@ -273,7 +283,8 @@ function resolveStrokeStyle(item) {
|
|
|
273
283
|
return {
|
|
274
284
|
stroke: item.stroke ?? DEFAULT_STROKE_STYLE.stroke,
|
|
275
285
|
strokeWidth: item.strokeWidth ?? DEFAULT_STROKE_STYLE.strokeWidth,
|
|
276
|
-
strokeOpacity: item.strokeOpacity
|
|
286
|
+
strokeOpacity: item.strokeOpacity,
|
|
287
|
+
strokeDash: item.strokeDash
|
|
277
288
|
};
|
|
278
289
|
}
|
|
279
290
|
function strokeOpacityAttr(style) {
|
|
@@ -596,6 +607,30 @@ function buildDrawDotSvg(r, style = DEFAULT_STROKE_STYLE) {
|
|
|
596
607
|
const op = style.strokeOpacity != null ? ` fill-opacity="${style.strokeOpacity}"` : "";
|
|
597
608
|
return `<circle cx="${r}" cy="${r}" r="${r}" fill="${style.stroke}" shape-rendering="geometricPrecision"${op} />`;
|
|
598
609
|
}
|
|
610
|
+
function dashArrayForDrawStroke(strokeWidth) {
|
|
611
|
+
const dash = Math.max(strokeWidth * 1.8, 4);
|
|
612
|
+
const gap = Math.max(strokeWidth * 1.4, 3);
|
|
613
|
+
return `${dash} ${gap}`;
|
|
614
|
+
}
|
|
615
|
+
function buildSmoothedCenterlinePath(points) {
|
|
616
|
+
if (points.length < 2) return null;
|
|
617
|
+
const first = points[0];
|
|
618
|
+
if (!first) return null;
|
|
619
|
+
let d = `M ${first.x} ${first.y}`;
|
|
620
|
+
for (let i = 1; i < points.length - 1; i++) {
|
|
621
|
+
const a = points[i];
|
|
622
|
+
const b = points[i + 1];
|
|
623
|
+
if (!a || !b) continue;
|
|
624
|
+
const midX = (a.x + b.x) / 2;
|
|
625
|
+
const midY = (a.y + b.y) / 2;
|
|
626
|
+
d += ` Q ${a.x} ${a.y} ${midX} ${midY}`;
|
|
627
|
+
}
|
|
628
|
+
const last = points[points.length - 1];
|
|
629
|
+
if (last) {
|
|
630
|
+
d += ` L ${last.x} ${last.y}`;
|
|
631
|
+
}
|
|
632
|
+
return d;
|
|
633
|
+
}
|
|
599
634
|
function computeFreehandSvgPayload(pathPointsLocal, style, toolKind, strokeComplete = true) {
|
|
600
635
|
if (pathPointsLocal.length === 0) return null;
|
|
601
636
|
if (pathPointsLocal.length === 1) {
|
|
@@ -610,6 +645,18 @@ function computeFreehandSvgPayload(pathPointsLocal, style, toolKind, strokeCompl
|
|
|
610
645
|
fillOpacity: style.strokeOpacity
|
|
611
646
|
};
|
|
612
647
|
}
|
|
648
|
+
if (style.strokeDash === "dashed" && (toolKind === "draw" || toolKind === "pencil")) {
|
|
649
|
+
const d2 = buildSmoothedCenterlinePath(pathPointsLocal);
|
|
650
|
+
if (!d2) return null;
|
|
651
|
+
return {
|
|
652
|
+
kind: "strokePath",
|
|
653
|
+
d: d2,
|
|
654
|
+
stroke: style.stroke,
|
|
655
|
+
strokeWidth: style.strokeWidth,
|
|
656
|
+
strokeOpacity: style.strokeOpacity,
|
|
657
|
+
strokeDasharray: dashArrayForDrawStroke(style.strokeWidth)
|
|
658
|
+
};
|
|
659
|
+
}
|
|
613
660
|
const hasPressure = pathPointsLocal.some(
|
|
614
661
|
(p) => p.pressure != null && Number.isFinite(p.pressure)
|
|
615
662
|
);
|
|
@@ -652,7 +699,8 @@ function freehandPayloadToSvgString(payload) {
|
|
|
652
699
|
strokeWidth: payload.strokeWidth,
|
|
653
700
|
strokeOpacity: payload.strokeOpacity
|
|
654
701
|
});
|
|
655
|
-
|
|
702
|
+
const dash = payload.strokeDasharray ? ` stroke-dasharray="${payload.strokeDasharray}"` : "";
|
|
703
|
+
return `<path d="${payload.d}" fill="none" stroke="${payload.stroke}" stroke-width="${payload.strokeWidth}" stroke-linecap="round" stroke-linejoin="round" shape-rendering="geometricPrecision"${op}${dash} />`;
|
|
656
704
|
}
|
|
657
705
|
function buildFreehandPathSvg(pathPointsLocal, style, toolKind, strokeComplete = true) {
|
|
658
706
|
const payload = computeFreehandSvgPayload(
|
|
@@ -864,7 +912,7 @@ function createDrawDotItem(id, worldX, worldY, radius, style) {
|
|
|
864
912
|
childrenSvg: ""
|
|
865
913
|
});
|
|
866
914
|
}
|
|
867
|
-
function createTextItem(id, bounds, text = "", style) {
|
|
915
|
+
function createTextItem(id, bounds, text = "", style, textFontSize) {
|
|
868
916
|
const r = normalizeRect(bounds);
|
|
869
917
|
const s = { ...DEFAULT_STROKE_STYLE, ...style };
|
|
870
918
|
return rebuildItemSvg({
|
|
@@ -877,6 +925,7 @@ function createTextItem(id, bounds, text = "", style) {
|
|
|
877
925
|
stroke: s.stroke,
|
|
878
926
|
strokeWidth: s.strokeWidth,
|
|
879
927
|
...s.strokeOpacity != null ? { strokeOpacity: s.strokeOpacity } : {},
|
|
928
|
+
...textFontSize != null ? { textFontSize } : {},
|
|
880
929
|
childrenSvg: ""
|
|
881
930
|
});
|
|
882
931
|
}
|
|
@@ -913,6 +962,7 @@ function createFreehandStrokeItem(id, pointsWorld, toolKind, style) {
|
|
|
913
962
|
stroke: merged.stroke,
|
|
914
963
|
strokeWidth: merged.strokeWidth,
|
|
915
964
|
...merged.strokeOpacity != null ? { strokeOpacity: merged.strokeOpacity } : {},
|
|
965
|
+
...merged.strokeDash != null ? { strokeDash: merged.strokeDash } : {},
|
|
916
966
|
pathPointsLocal,
|
|
917
967
|
childrenSvg: ""
|
|
918
968
|
});
|
|
@@ -989,7 +1039,7 @@ var init_shape_builders = __esm({
|
|
|
989
1039
|
init_custom_shape();
|
|
990
1040
|
init_text_svg();
|
|
991
1041
|
DEFAULT_STROKE_STYLE = {
|
|
992
|
-
stroke: "#
|
|
1042
|
+
stroke: "#1d1d1d",
|
|
993
1043
|
strokeWidth: 2
|
|
994
1044
|
};
|
|
995
1045
|
TOOL_FREEHAND_DEFAULTS = {
|
|
@@ -3481,33 +3531,416 @@ var DEFAULT_VECTOR_TOOLS = [
|
|
|
3481
3531
|
shortcutHint: "I"
|
|
3482
3532
|
}
|
|
3483
3533
|
];
|
|
3534
|
+
|
|
3535
|
+
// src/react/VectorSelectionInspector.tsx
|
|
3536
|
+
init_text_svg();
|
|
3484
3537
|
var shellLook = {
|
|
3485
3538
|
display: "flex",
|
|
3486
3539
|
flexDirection: "column",
|
|
3487
|
-
gap:
|
|
3488
|
-
minWidth:
|
|
3489
|
-
padding: "
|
|
3490
|
-
borderRadius:
|
|
3491
|
-
border: "1px solid rgba(0,0,0,0.
|
|
3492
|
-
background: "rgba(255,255,255,0.
|
|
3493
|
-
boxShadow: "0 1px 3px rgba(0,0,0,0.08)",
|
|
3540
|
+
gap: 10,
|
|
3541
|
+
minWidth: 200,
|
|
3542
|
+
padding: "12px 14px",
|
|
3543
|
+
borderRadius: 10,
|
|
3544
|
+
border: "1px solid rgba(0,0,0,0.1)",
|
|
3545
|
+
background: "rgba(255,255,255,0.97)",
|
|
3546
|
+
boxShadow: "0 4px 16px rgba(0,0,0,0.06), 0 1px 3px rgba(0,0,0,0.08)",
|
|
3494
3547
|
pointerEvents: "auto"
|
|
3495
3548
|
};
|
|
3496
|
-
var
|
|
3549
|
+
var sectionLabelStyle = {
|
|
3497
3550
|
display: "flex",
|
|
3498
3551
|
flexDirection: "column",
|
|
3499
|
-
gap:
|
|
3552
|
+
gap: 6,
|
|
3500
3553
|
fontSize: 11,
|
|
3501
3554
|
fontWeight: 600,
|
|
3502
|
-
color: "#52525b"
|
|
3555
|
+
color: "#52525b",
|
|
3556
|
+
letterSpacing: "0.02em",
|
|
3557
|
+
textTransform: "uppercase"
|
|
3558
|
+
};
|
|
3559
|
+
var mixedHintStyle = {
|
|
3560
|
+
fontWeight: 400,
|
|
3561
|
+
color: "#a1a1aa",
|
|
3562
|
+
textTransform: "none",
|
|
3563
|
+
letterSpacing: 0
|
|
3503
3564
|
};
|
|
3565
|
+
var TLDRAW_PALETTE = [
|
|
3566
|
+
{ name: "black", hex: "#1d1d1d" },
|
|
3567
|
+
{ name: "grey", hex: "#9fa8b2" },
|
|
3568
|
+
{ name: "light-violet", hex: "#e085f4" },
|
|
3569
|
+
{ name: "violet", hex: "#ae3ec9" },
|
|
3570
|
+
{ name: "blue", hex: "#4263eb" },
|
|
3571
|
+
{ name: "light-blue", hex: "#4dabf7" },
|
|
3572
|
+
{ name: "yellow", hex: "#ffc078" },
|
|
3573
|
+
{ name: "orange", hex: "#f76707" },
|
|
3574
|
+
{ name: "green", hex: "#099268" },
|
|
3575
|
+
{ name: "light-green", hex: "#40c057" },
|
|
3576
|
+
{ name: "light-red", hex: "#ff8787" },
|
|
3577
|
+
{ name: "red", hex: "#e03131" }
|
|
3578
|
+
];
|
|
3504
3579
|
function normalizeHex(stroke) {
|
|
3505
3580
|
if (/^#[0-9A-Fa-f]{6}$/.test(stroke)) return stroke;
|
|
3506
|
-
return "#
|
|
3581
|
+
return "#1d1d1d";
|
|
3582
|
+
}
|
|
3583
|
+
function hexesEqual(a, b) {
|
|
3584
|
+
return a.toLowerCase() === b.toLowerCase();
|
|
3507
3585
|
}
|
|
3508
3586
|
function isStylableKind(tk) {
|
|
3509
3587
|
return tk === "rect" || tk === "ellipse" || tk === "architectural-cloud" || tk === "line" || tk === "arrow" || tk === "draw" || tk === "pencil" || tk === "brush" || tk === "marker" || tk === "text";
|
|
3510
3588
|
}
|
|
3589
|
+
var FONT_SIZE_PRESETS = [
|
|
3590
|
+
{ label: "S", size: 14 },
|
|
3591
|
+
{ label: "M", size: 18 },
|
|
3592
|
+
{ label: "L", size: 28 },
|
|
3593
|
+
{ label: "XL", size: 44 }
|
|
3594
|
+
];
|
|
3595
|
+
function ColorSwatch({ color, selected, onSelect }) {
|
|
3596
|
+
return /* @__PURE__ */ jsx(
|
|
3597
|
+
"button",
|
|
3598
|
+
{
|
|
3599
|
+
type: "button",
|
|
3600
|
+
"aria-label": color.name,
|
|
3601
|
+
"aria-pressed": selected,
|
|
3602
|
+
onClick: onSelect,
|
|
3603
|
+
onPointerDown: (e) => {
|
|
3604
|
+
if (e.pointerType === "mouse") e.preventDefault();
|
|
3605
|
+
},
|
|
3606
|
+
style: {
|
|
3607
|
+
width: 24,
|
|
3608
|
+
height: 24,
|
|
3609
|
+
padding: 0,
|
|
3610
|
+
borderRadius: "50%",
|
|
3611
|
+
border: selected ? "2px solid #18181b" : "1px solid rgba(0,0,0,0.12)",
|
|
3612
|
+
background: color.hex,
|
|
3613
|
+
cursor: "pointer",
|
|
3614
|
+
outline: "none",
|
|
3615
|
+
boxShadow: selected ? "0 0 0 2px rgba(255,255,255,0.95) inset" : "none",
|
|
3616
|
+
transition: "transform 0.08s ease",
|
|
3617
|
+
transform: selected ? "scale(1.08)" : "scale(1)",
|
|
3618
|
+
WebkitTapHighlightColor: "transparent"
|
|
3619
|
+
}
|
|
3620
|
+
}
|
|
3621
|
+
);
|
|
3622
|
+
}
|
|
3623
|
+
function ColorPalette({ value, onChange }) {
|
|
3624
|
+
const [showCustom, setShowCustom] = useState(false);
|
|
3625
|
+
const normalized = normalizeHex(value);
|
|
3626
|
+
const inPalette = TLDRAW_PALETTE.some((c) => hexesEqual(c.hex, normalized));
|
|
3627
|
+
return /* @__PURE__ */ jsxs(
|
|
3628
|
+
"div",
|
|
3629
|
+
{
|
|
3630
|
+
style: {
|
|
3631
|
+
display: "grid",
|
|
3632
|
+
gridTemplateColumns: "repeat(6, 24px)",
|
|
3633
|
+
gap: 6,
|
|
3634
|
+
rowGap: 6,
|
|
3635
|
+
alignItems: "center"
|
|
3636
|
+
},
|
|
3637
|
+
children: [
|
|
3638
|
+
TLDRAW_PALETTE.map((c) => /* @__PURE__ */ jsx(
|
|
3639
|
+
ColorSwatch,
|
|
3640
|
+
{
|
|
3641
|
+
color: c,
|
|
3642
|
+
selected: hexesEqual(c.hex, normalized),
|
|
3643
|
+
onSelect: () => onChange(c.hex)
|
|
3644
|
+
},
|
|
3645
|
+
c.name
|
|
3646
|
+
)),
|
|
3647
|
+
/* @__PURE__ */ jsx(
|
|
3648
|
+
"button",
|
|
3649
|
+
{
|
|
3650
|
+
type: "button",
|
|
3651
|
+
"aria-label": "Cor personalizada",
|
|
3652
|
+
"aria-pressed": showCustom || !inPalette,
|
|
3653
|
+
onClick: () => setShowCustom((v) => !v),
|
|
3654
|
+
onPointerDown: (e) => {
|
|
3655
|
+
if (e.pointerType === "mouse") e.preventDefault();
|
|
3656
|
+
},
|
|
3657
|
+
style: {
|
|
3658
|
+
width: 24,
|
|
3659
|
+
height: 24,
|
|
3660
|
+
padding: 0,
|
|
3661
|
+
borderRadius: "50%",
|
|
3662
|
+
border: !inPalette || showCustom ? "2px solid #18181b" : "1px solid rgba(0,0,0,0.12)",
|
|
3663
|
+
background: "conic-gradient(from 0deg, #ff5757, #ffbd59, #59ff7e, #59ddff, #b259ff, #ff59c1, #ff5757)",
|
|
3664
|
+
cursor: "pointer",
|
|
3665
|
+
outline: "none",
|
|
3666
|
+
WebkitTapHighlightColor: "transparent"
|
|
3667
|
+
}
|
|
3668
|
+
}
|
|
3669
|
+
),
|
|
3670
|
+
showCustom || !inPalette ? /* @__PURE__ */ jsxs(
|
|
3671
|
+
"label",
|
|
3672
|
+
{
|
|
3673
|
+
style: {
|
|
3674
|
+
gridColumn: "1 / -1",
|
|
3675
|
+
display: "flex",
|
|
3676
|
+
alignItems: "center",
|
|
3677
|
+
gap: 6,
|
|
3678
|
+
fontSize: 11,
|
|
3679
|
+
fontWeight: 500,
|
|
3680
|
+
color: "#71717a",
|
|
3681
|
+
textTransform: "none",
|
|
3682
|
+
letterSpacing: 0
|
|
3683
|
+
},
|
|
3684
|
+
children: [
|
|
3685
|
+
/* @__PURE__ */ jsx(
|
|
3686
|
+
"input",
|
|
3687
|
+
{
|
|
3688
|
+
type: "color",
|
|
3689
|
+
value: normalized,
|
|
3690
|
+
onChange: (e) => onChange(e.target.value),
|
|
3691
|
+
style: {
|
|
3692
|
+
width: 28,
|
|
3693
|
+
height: 28,
|
|
3694
|
+
padding: 0,
|
|
3695
|
+
border: "1px solid rgba(0,0,0,0.12)",
|
|
3696
|
+
borderRadius: 6,
|
|
3697
|
+
cursor: "pointer",
|
|
3698
|
+
background: "transparent"
|
|
3699
|
+
}
|
|
3700
|
+
}
|
|
3701
|
+
),
|
|
3702
|
+
/* @__PURE__ */ jsx("span", { style: { fontVariantNumeric: "tabular-nums" }, children: normalized.toUpperCase() })
|
|
3703
|
+
]
|
|
3704
|
+
}
|
|
3705
|
+
) : null
|
|
3706
|
+
]
|
|
3707
|
+
}
|
|
3708
|
+
);
|
|
3709
|
+
}
|
|
3710
|
+
function DashTabs({ value, onChange }) {
|
|
3711
|
+
const tabs = [
|
|
3712
|
+
{ id: "solid", label: "Cont\xEDnuo" },
|
|
3713
|
+
{ id: "dashed", label: "Tracejado" }
|
|
3714
|
+
];
|
|
3715
|
+
return /* @__PURE__ */ jsx(
|
|
3716
|
+
"div",
|
|
3717
|
+
{
|
|
3718
|
+
role: "radiogroup",
|
|
3719
|
+
"aria-label": "Estilo do tra\xE7o",
|
|
3720
|
+
style: {
|
|
3721
|
+
display: "flex",
|
|
3722
|
+
background: "rgba(24,24,27,0.06)",
|
|
3723
|
+
borderRadius: 7,
|
|
3724
|
+
padding: 2,
|
|
3725
|
+
gap: 2
|
|
3726
|
+
},
|
|
3727
|
+
children: tabs.map((t) => {
|
|
3728
|
+
const selected = value === t.id;
|
|
3729
|
+
return (
|
|
3730
|
+
// biome-ignore lint/a11y/useSemanticElements: styled segmented control needs button, not input[type=radio]
|
|
3731
|
+
/* @__PURE__ */ jsxs(
|
|
3732
|
+
"button",
|
|
3733
|
+
{
|
|
3734
|
+
type: "button",
|
|
3735
|
+
role: "radio",
|
|
3736
|
+
"aria-checked": selected,
|
|
3737
|
+
onClick: () => onChange(t.id),
|
|
3738
|
+
onPointerDown: (e) => {
|
|
3739
|
+
if (e.pointerType === "mouse") e.preventDefault();
|
|
3740
|
+
},
|
|
3741
|
+
style: {
|
|
3742
|
+
flex: 1,
|
|
3743
|
+
display: "inline-flex",
|
|
3744
|
+
alignItems: "center",
|
|
3745
|
+
justifyContent: "center",
|
|
3746
|
+
padding: "5px 8px",
|
|
3747
|
+
fontSize: 11,
|
|
3748
|
+
fontWeight: 600,
|
|
3749
|
+
color: selected ? "#18181b" : "#71717a",
|
|
3750
|
+
background: selected ? "#fff" : "transparent",
|
|
3751
|
+
borderRadius: 5,
|
|
3752
|
+
border: "none",
|
|
3753
|
+
cursor: "pointer",
|
|
3754
|
+
boxShadow: selected ? "0 1px 2px rgba(0,0,0,0.1)" : "none",
|
|
3755
|
+
outline: "none",
|
|
3756
|
+
WebkitTapHighlightColor: "transparent"
|
|
3757
|
+
},
|
|
3758
|
+
children: [
|
|
3759
|
+
/* @__PURE__ */ jsx(DashTabSwatch, { dashed: t.id === "dashed" }),
|
|
3760
|
+
/* @__PURE__ */ jsx("span", { style: { marginLeft: 6 }, children: t.label })
|
|
3761
|
+
]
|
|
3762
|
+
},
|
|
3763
|
+
t.id
|
|
3764
|
+
)
|
|
3765
|
+
);
|
|
3766
|
+
})
|
|
3767
|
+
}
|
|
3768
|
+
);
|
|
3769
|
+
}
|
|
3770
|
+
function DashTabSwatch({ dashed }) {
|
|
3771
|
+
return /* @__PURE__ */ jsxs(
|
|
3772
|
+
"svg",
|
|
3773
|
+
{
|
|
3774
|
+
width: 26,
|
|
3775
|
+
height: 6,
|
|
3776
|
+
"aria-hidden": true,
|
|
3777
|
+
style: { flexShrink: 0, display: "block" },
|
|
3778
|
+
children: [
|
|
3779
|
+
/* @__PURE__ */ jsx("title", { children: dashed ? "dashed" : "solid" }),
|
|
3780
|
+
/* @__PURE__ */ jsx(
|
|
3781
|
+
"line",
|
|
3782
|
+
{
|
|
3783
|
+
x1: 1,
|
|
3784
|
+
y1: 3,
|
|
3785
|
+
x2: 25,
|
|
3786
|
+
y2: 3,
|
|
3787
|
+
stroke: "currentColor",
|
|
3788
|
+
strokeWidth: 2,
|
|
3789
|
+
strokeLinecap: "round",
|
|
3790
|
+
strokeDasharray: dashed ? "4 3" : void 0
|
|
3791
|
+
}
|
|
3792
|
+
)
|
|
3793
|
+
]
|
|
3794
|
+
}
|
|
3795
|
+
);
|
|
3796
|
+
}
|
|
3797
|
+
function FontSizeTabs({ value, onChange }) {
|
|
3798
|
+
return /* @__PURE__ */ jsx(
|
|
3799
|
+
"div",
|
|
3800
|
+
{
|
|
3801
|
+
role: "radiogroup",
|
|
3802
|
+
"aria-label": "Tamanho do texto",
|
|
3803
|
+
style: {
|
|
3804
|
+
display: "flex",
|
|
3805
|
+
background: "rgba(24,24,27,0.06)",
|
|
3806
|
+
borderRadius: 7,
|
|
3807
|
+
padding: 2,
|
|
3808
|
+
gap: 2
|
|
3809
|
+
},
|
|
3810
|
+
children: FONT_SIZE_PRESETS.map((p) => {
|
|
3811
|
+
const selected = Math.abs(value - p.size) < 0.5;
|
|
3812
|
+
return (
|
|
3813
|
+
// biome-ignore lint/a11y/useSemanticElements: styled segmented control needs button, not input[type=radio]
|
|
3814
|
+
/* @__PURE__ */ jsx(
|
|
3815
|
+
"button",
|
|
3816
|
+
{
|
|
3817
|
+
type: "button",
|
|
3818
|
+
role: "radio",
|
|
3819
|
+
"aria-checked": selected,
|
|
3820
|
+
"aria-label": `${p.label} (${p.size}px)`,
|
|
3821
|
+
onClick: () => onChange(p.size),
|
|
3822
|
+
onPointerDown: (e) => {
|
|
3823
|
+
if (e.pointerType === "mouse") e.preventDefault();
|
|
3824
|
+
},
|
|
3825
|
+
style: {
|
|
3826
|
+
flex: 1,
|
|
3827
|
+
padding: "5px 0",
|
|
3828
|
+
fontSize: p.label === "XL" ? 14 : p.label === "L" ? 13 : 12,
|
|
3829
|
+
fontWeight: 700,
|
|
3830
|
+
color: selected ? "#18181b" : "#71717a",
|
|
3831
|
+
background: selected ? "#fff" : "transparent",
|
|
3832
|
+
borderRadius: 5,
|
|
3833
|
+
border: "none",
|
|
3834
|
+
cursor: "pointer",
|
|
3835
|
+
boxShadow: selected ? "0 1px 2px rgba(0,0,0,0.1)" : "none",
|
|
3836
|
+
outline: "none",
|
|
3837
|
+
WebkitTapHighlightColor: "transparent",
|
|
3838
|
+
lineHeight: 1
|
|
3839
|
+
},
|
|
3840
|
+
children: p.label
|
|
3841
|
+
},
|
|
3842
|
+
p.label
|
|
3843
|
+
)
|
|
3844
|
+
);
|
|
3845
|
+
})
|
|
3846
|
+
}
|
|
3847
|
+
);
|
|
3848
|
+
}
|
|
3849
|
+
function viewModelFromActiveTool(activeToolStyle) {
|
|
3850
|
+
const hex = normalizeHex(activeToolStyle.stroke);
|
|
3851
|
+
const strokeWidth = activeToolStyle.strokeWidth;
|
|
3852
|
+
const strokeOpacity = activeToolStyle.strokeOpacity ?? 1;
|
|
3853
|
+
const strokeDash = activeToolStyle.strokeDash === "dashed" ? "dashed" : "solid";
|
|
3854
|
+
const textFontSize = activeToolStyle.textFontSize ?? DEFAULT_TEXT_FONT_SIZE;
|
|
3855
|
+
const isText = activeToolStyle.toolKind === "text";
|
|
3856
|
+
const isDraw = activeToolStyle.toolKind === "draw";
|
|
3857
|
+
const isMarker = activeToolStyle.toolKind === "marker";
|
|
3858
|
+
const current = {
|
|
3859
|
+
stroke: hex,
|
|
3860
|
+
strokeWidth,
|
|
3861
|
+
...activeToolStyle.strokeOpacity != null ? { strokeOpacity: activeToolStyle.strokeOpacity } : {},
|
|
3862
|
+
...activeToolStyle.strokeDash != null ? { strokeDash: activeToolStyle.strokeDash } : {},
|
|
3863
|
+
...isText ? { textFontSize } : {}
|
|
3864
|
+
};
|
|
3865
|
+
return {
|
|
3866
|
+
label: activeToolStyle.label ?? "Estilo da ferramenta",
|
|
3867
|
+
count: 0,
|
|
3868
|
+
hex,
|
|
3869
|
+
strokeWidth,
|
|
3870
|
+
strokeOpacity,
|
|
3871
|
+
strokeDash,
|
|
3872
|
+
textFontSize,
|
|
3873
|
+
showStrokeWidth: !isText,
|
|
3874
|
+
showDash: isDraw,
|
|
3875
|
+
showFontSize: isText,
|
|
3876
|
+
showMarkerOpacity: isMarker,
|
|
3877
|
+
mixedStroke: false,
|
|
3878
|
+
mixedWidth: false,
|
|
3879
|
+
mixedDash: false,
|
|
3880
|
+
mixedFontSize: false,
|
|
3881
|
+
mixedOpacity: false,
|
|
3882
|
+
current
|
|
3883
|
+
};
|
|
3884
|
+
}
|
|
3885
|
+
function viewModelFromSelection(stylable) {
|
|
3886
|
+
const first = stylable[0];
|
|
3887
|
+
if (!first) return null;
|
|
3888
|
+
const hex = normalizeHex(first.stroke ?? "#1d1d1d");
|
|
3889
|
+
const strokeWidth = first.strokeWidth ?? 2;
|
|
3890
|
+
const allSameStroke = stylable.every(
|
|
3891
|
+
(it) => (it.stroke ?? "#1d1d1d") === (first.stroke ?? "#1d1d1d")
|
|
3892
|
+
);
|
|
3893
|
+
const allSameWidth = stylable.every(
|
|
3894
|
+
(it) => (it.strokeWidth ?? 2) === (first.strokeWidth ?? 2)
|
|
3895
|
+
);
|
|
3896
|
+
const draws = stylable.filter(
|
|
3897
|
+
(it) => it.toolKind === "draw" || it.toolKind === "pencil"
|
|
3898
|
+
);
|
|
3899
|
+
const showDash = draws.length > 0;
|
|
3900
|
+
const firstDraw = draws[0];
|
|
3901
|
+
const strokeDash = firstDraw?.strokeDash === "dashed" ? "dashed" : "solid";
|
|
3902
|
+
const allSameDash = draws.length === 0 || draws.every((it) => (it.strokeDash ?? "solid") === strokeDash);
|
|
3903
|
+
const markers = stylable.filter((it) => it.toolKind === "marker");
|
|
3904
|
+
const showMarkerOpacity = markers.length > 0;
|
|
3905
|
+
const firstMarker = markers[0];
|
|
3906
|
+
const strokeOpacity = firstMarker?.strokeOpacity ?? 1;
|
|
3907
|
+
const allSameOpacity = markers.length === 0 || markers.every(
|
|
3908
|
+
(it) => (it.strokeOpacity ?? 1) === (firstMarker?.strokeOpacity ?? 1)
|
|
3909
|
+
);
|
|
3910
|
+
const texts = stylable.filter((it) => it.toolKind === "text");
|
|
3911
|
+
const showFontSize = texts.length > 0;
|
|
3912
|
+
const firstText = texts[0];
|
|
3913
|
+
const textFontSize = firstText?.textFontSize ?? DEFAULT_TEXT_FONT_SIZE;
|
|
3914
|
+
const allSameFontSize = texts.length === 0 || texts.every(
|
|
3915
|
+
(it) => (it.textFontSize ?? DEFAULT_TEXT_FONT_SIZE) === textFontSize
|
|
3916
|
+
);
|
|
3917
|
+
const current = {
|
|
3918
|
+
stroke: hex,
|
|
3919
|
+
strokeWidth,
|
|
3920
|
+
...showMarkerOpacity ? { strokeOpacity } : {},
|
|
3921
|
+
...showDash ? { strokeDash } : {},
|
|
3922
|
+
...showFontSize ? { textFontSize } : {}
|
|
3923
|
+
};
|
|
3924
|
+
return {
|
|
3925
|
+
label: "Estilo da sele\xE7\xE3o",
|
|
3926
|
+
count: stylable.length,
|
|
3927
|
+
hex,
|
|
3928
|
+
strokeWidth,
|
|
3929
|
+
strokeOpacity,
|
|
3930
|
+
strokeDash,
|
|
3931
|
+
textFontSize,
|
|
3932
|
+
showStrokeWidth: true,
|
|
3933
|
+
showDash,
|
|
3934
|
+
showFontSize,
|
|
3935
|
+
showMarkerOpacity,
|
|
3936
|
+
mixedStroke: !allSameStroke,
|
|
3937
|
+
mixedWidth: !allSameWidth,
|
|
3938
|
+
mixedDash: !allSameDash,
|
|
3939
|
+
mixedFontSize: !allSameFontSize,
|
|
3940
|
+
mixedOpacity: !allSameOpacity,
|
|
3941
|
+
current
|
|
3942
|
+
};
|
|
3943
|
+
}
|
|
3511
3944
|
function VectorSelectionInspector({
|
|
3512
3945
|
items: itemsProp,
|
|
3513
3946
|
activeToolStyle: activeToolStyleProp,
|
|
@@ -3523,175 +3956,93 @@ function VectorSelectionInspector({
|
|
|
3523
3956
|
const activeToolStyle = activeToolStyleProp === void 0 ? ctx?.activeToolStyle ?? null : activeToolStyleProp;
|
|
3524
3957
|
const onChange = onChangeProp ?? ctx?.onSelectionStyleChange ?? null;
|
|
3525
3958
|
if (!onChange) return null;
|
|
3959
|
+
let vm = null;
|
|
3960
|
+
if (activeToolStyle) {
|
|
3961
|
+
vm = viewModelFromActiveTool(activeToolStyle);
|
|
3962
|
+
} else {
|
|
3963
|
+
const stylable = items.filter(
|
|
3964
|
+
(it) => !it.locked && it.toolKind && isStylableKind(it.toolKind)
|
|
3965
|
+
);
|
|
3966
|
+
if (stylable.length === 0) return null;
|
|
3967
|
+
vm = viewModelFromSelection(stylable);
|
|
3968
|
+
}
|
|
3969
|
+
if (!vm) return null;
|
|
3970
|
+
const apply = (changes) => onChange({ ...vm.current, ...changes });
|
|
3526
3971
|
const shell = {
|
|
3527
3972
|
...getBoardPositionStyle(position, inset, zIndex),
|
|
3528
3973
|
...shellLook,
|
|
3529
3974
|
...style
|
|
3530
3975
|
};
|
|
3531
|
-
|
|
3532
|
-
const stroke2 = activeToolStyle.stroke;
|
|
3533
|
-
const strokeWidth2 = activeToolStyle.strokeWidth;
|
|
3534
|
-
const hex2 = normalizeHex(stroke2);
|
|
3535
|
-
const showMarkerOpacity2 = activeToolStyle.toolKind === "marker";
|
|
3536
|
-
const opacityPct2 = Math.round((activeToolStyle.strokeOpacity ?? 1) * 100);
|
|
3537
|
-
return /* @__PURE__ */ jsxs(
|
|
3538
|
-
"section",
|
|
3539
|
-
{
|
|
3540
|
-
"data-slot": "vector-selection-inspector",
|
|
3541
|
-
"data-position": position,
|
|
3542
|
-
className,
|
|
3543
|
-
"aria-label": activeToolStyle.label ?? "Estilo da ferramenta",
|
|
3544
|
-
style: shell,
|
|
3545
|
-
children: [
|
|
3546
|
-
/* @__PURE__ */ jsxs("label", { style: labelStyle2, children: [
|
|
3547
|
-
"Cor",
|
|
3548
|
-
/* @__PURE__ */ jsx(
|
|
3549
|
-
"input",
|
|
3550
|
-
{
|
|
3551
|
-
type: "color",
|
|
3552
|
-
value: hex2,
|
|
3553
|
-
onChange: (e) => onChange({
|
|
3554
|
-
stroke: e.target.value,
|
|
3555
|
-
strokeWidth: strokeWidth2,
|
|
3556
|
-
...activeToolStyle.strokeOpacity != null ? { strokeOpacity: activeToolStyle.strokeOpacity } : {}
|
|
3557
|
-
}),
|
|
3558
|
-
style: {
|
|
3559
|
-
width: "100%",
|
|
3560
|
-
height: 32,
|
|
3561
|
-
padding: 0,
|
|
3562
|
-
border: "none",
|
|
3563
|
-
cursor: "pointer",
|
|
3564
|
-
background: "transparent"
|
|
3565
|
-
}
|
|
3566
|
-
}
|
|
3567
|
-
)
|
|
3568
|
-
] }),
|
|
3569
|
-
/* @__PURE__ */ jsxs("label", { style: labelStyle2, children: [
|
|
3570
|
-
"Grossura",
|
|
3571
|
-
/* @__PURE__ */ jsx(
|
|
3572
|
-
"input",
|
|
3573
|
-
{
|
|
3574
|
-
type: "range",
|
|
3575
|
-
min: 1,
|
|
3576
|
-
max: 48,
|
|
3577
|
-
value: strokeWidth2,
|
|
3578
|
-
onChange: (e) => onChange({
|
|
3579
|
-
stroke: hex2,
|
|
3580
|
-
strokeWidth: Number(e.target.value),
|
|
3581
|
-
...activeToolStyle.strokeOpacity != null ? { strokeOpacity: activeToolStyle.strokeOpacity } : {}
|
|
3582
|
-
})
|
|
3583
|
-
}
|
|
3584
|
-
)
|
|
3585
|
-
] }),
|
|
3586
|
-
showMarkerOpacity2 && /* @__PURE__ */ jsxs("label", { style: labelStyle2, children: [
|
|
3587
|
-
"Opacidade (marcador)",
|
|
3588
|
-
/* @__PURE__ */ jsx(
|
|
3589
|
-
"input",
|
|
3590
|
-
{
|
|
3591
|
-
type: "range",
|
|
3592
|
-
min: 10,
|
|
3593
|
-
max: 100,
|
|
3594
|
-
value: opacityPct2,
|
|
3595
|
-
onChange: (e) => {
|
|
3596
|
-
const v = Number(e.target.value) / 100;
|
|
3597
|
-
onChange({
|
|
3598
|
-
stroke: hex2,
|
|
3599
|
-
strokeWidth: strokeWidth2,
|
|
3600
|
-
strokeOpacity: v
|
|
3601
|
-
});
|
|
3602
|
-
}
|
|
3603
|
-
}
|
|
3604
|
-
),
|
|
3605
|
-
/* @__PURE__ */ jsxs("span", { style: { fontWeight: 500, color: "#71717a" }, children: [
|
|
3606
|
-
opacityPct2,
|
|
3607
|
-
"%"
|
|
3608
|
-
] })
|
|
3609
|
-
] })
|
|
3610
|
-
]
|
|
3611
|
-
}
|
|
3612
|
-
);
|
|
3613
|
-
}
|
|
3614
|
-
const stylable = items.filter(
|
|
3615
|
-
(it) => !it.locked && it.toolKind && isStylableKind(it.toolKind)
|
|
3616
|
-
);
|
|
3617
|
-
if (stylable.length === 0) return null;
|
|
3618
|
-
const first = stylable[0];
|
|
3619
|
-
if (!first) return null;
|
|
3620
|
-
const allSameStroke = stylable.every(
|
|
3621
|
-
(it) => (it.stroke ?? "#2563eb") === (first.stroke ?? "#2563eb")
|
|
3622
|
-
);
|
|
3623
|
-
const allSameWidth = stylable.every(
|
|
3624
|
-
(it) => (it.strokeWidth ?? 2) === (first.strokeWidth ?? 2)
|
|
3625
|
-
);
|
|
3626
|
-
const stroke = first.stroke ?? "#2563eb";
|
|
3627
|
-
const strokeWidth = first.strokeWidth ?? 2;
|
|
3628
|
-
const hex = normalizeHex(stroke);
|
|
3629
|
-
const markers = stylable.filter((it) => it.toolKind === "marker");
|
|
3630
|
-
const showMarkerOpacity = markers.length > 0;
|
|
3631
|
-
const firstMarker = markers[0];
|
|
3632
|
-
const allSameMarkerOpacity = markers.length > 0 && markers.every(
|
|
3633
|
-
(it) => (it.strokeOpacity ?? 1) === (firstMarker?.strokeOpacity ?? 1)
|
|
3634
|
-
);
|
|
3635
|
-
const opacityPct = firstMarker ? Math.round((firstMarker.strokeOpacity ?? 1) * 100) : 100;
|
|
3976
|
+
const opacityPct = Math.round(vm.strokeOpacity * 100);
|
|
3636
3977
|
return /* @__PURE__ */ jsxs(
|
|
3637
3978
|
"section",
|
|
3638
3979
|
{
|
|
3639
3980
|
"data-slot": "vector-selection-inspector",
|
|
3640
3981
|
"data-position": position,
|
|
3641
3982
|
className,
|
|
3642
|
-
"aria-label":
|
|
3983
|
+
"aria-label": vm.label,
|
|
3643
3984
|
style: shell,
|
|
3644
3985
|
children: [
|
|
3645
|
-
|
|
3646
|
-
|
|
3986
|
+
vm.count > 1 ? /* @__PURE__ */ jsxs("p", { style: { margin: 0, fontSize: 11, color: "#71717a" }, children: [
|
|
3987
|
+
vm.count,
|
|
3647
3988
|
" objetos selecionados"
|
|
3648
|
-
] }),
|
|
3649
|
-
/* @__PURE__ */ jsxs("
|
|
3650
|
-
"
|
|
3651
|
-
|
|
3652
|
-
" "
|
|
3653
|
-
"(valores misturados \u2014 novo valor aplica a todos)"
|
|
3989
|
+
] }) : null,
|
|
3990
|
+
/* @__PURE__ */ jsxs("div", { role: "group", "aria-label": "Cor", style: sectionLabelStyle, children: [
|
|
3991
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
3992
|
+
"Cor",
|
|
3993
|
+
vm.mixedStroke ? /* @__PURE__ */ jsx("span", { style: mixedHintStyle, children: " (valores misturados)" }) : null
|
|
3654
3994
|
] }),
|
|
3655
|
-
/* @__PURE__ */ jsx(
|
|
3656
|
-
"input",
|
|
3657
|
-
{
|
|
3658
|
-
type: "color",
|
|
3659
|
-
value: hex,
|
|
3660
|
-
onChange: (e) => onChange({
|
|
3661
|
-
stroke: e.target.value,
|
|
3662
|
-
strokeWidth
|
|
3663
|
-
}),
|
|
3664
|
-
style: {
|
|
3665
|
-
width: "100%",
|
|
3666
|
-
height: 32,
|
|
3667
|
-
padding: 0,
|
|
3668
|
-
border: "none",
|
|
3669
|
-
cursor: "pointer",
|
|
3670
|
-
background: "transparent"
|
|
3671
|
-
}
|
|
3672
|
-
}
|
|
3673
|
-
)
|
|
3995
|
+
/* @__PURE__ */ jsx(ColorPalette, { value: vm.hex, onChange: (h) => apply({ stroke: h }) })
|
|
3674
3996
|
] }),
|
|
3675
|
-
/* @__PURE__ */ jsxs("label", { style:
|
|
3997
|
+
vm.showStrokeWidth ? /* @__PURE__ */ jsxs("label", { style: sectionLabelStyle, children: [
|
|
3676
3998
|
"Grossura",
|
|
3677
|
-
|
|
3999
|
+
vm.mixedWidth ? /* @__PURE__ */ jsx("span", { style: mixedHintStyle, children: " (misturado)" }) : null,
|
|
3678
4000
|
/* @__PURE__ */ jsx(
|
|
3679
4001
|
"input",
|
|
3680
4002
|
{
|
|
3681
4003
|
type: "range",
|
|
3682
4004
|
min: 1,
|
|
3683
4005
|
max: 48,
|
|
3684
|
-
value: strokeWidth,
|
|
3685
|
-
onChange: (e) =>
|
|
3686
|
-
stroke: hex,
|
|
3687
|
-
strokeWidth: Number(e.target.value)
|
|
3688
|
-
})
|
|
4006
|
+
value: vm.strokeWidth,
|
|
4007
|
+
onChange: (e) => apply({ strokeWidth: Number(e.target.value) })
|
|
3689
4008
|
}
|
|
3690
4009
|
)
|
|
3691
|
-
] }),
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
4010
|
+
] }) : null,
|
|
4011
|
+
vm.showDash ? (
|
|
4012
|
+
// biome-ignore lint/a11y/useSemanticElements: fieldset would impose default browser styling that breaks the inspector layout
|
|
4013
|
+
/* @__PURE__ */ jsxs("div", { role: "group", "aria-label": "Tra\xE7o", style: sectionLabelStyle, children: [
|
|
4014
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
4015
|
+
"Tra\xE7o",
|
|
4016
|
+
vm.mixedDash ? /* @__PURE__ */ jsx("span", { style: mixedHintStyle, children: " (misturado)" }) : null
|
|
4017
|
+
] }),
|
|
4018
|
+
/* @__PURE__ */ jsx(
|
|
4019
|
+
DashTabs,
|
|
4020
|
+
{
|
|
4021
|
+
value: vm.strokeDash,
|
|
4022
|
+
onChange: (next) => apply({ strokeDash: next })
|
|
4023
|
+
}
|
|
4024
|
+
)
|
|
4025
|
+
] })
|
|
4026
|
+
) : null,
|
|
4027
|
+
vm.showFontSize ? (
|
|
4028
|
+
// biome-ignore lint/a11y/useSemanticElements: fieldset would impose default browser styling that breaks the inspector layout
|
|
4029
|
+
/* @__PURE__ */ jsxs("div", { role: "group", "aria-label": "Tamanho", style: sectionLabelStyle, children: [
|
|
4030
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
4031
|
+
"Tamanho",
|
|
4032
|
+
vm.mixedFontSize ? /* @__PURE__ */ jsx("span", { style: mixedHintStyle, children: " (misturado)" }) : null
|
|
4033
|
+
] }),
|
|
4034
|
+
/* @__PURE__ */ jsx(
|
|
4035
|
+
FontSizeTabs,
|
|
4036
|
+
{
|
|
4037
|
+
value: vm.textFontSize,
|
|
4038
|
+
onChange: (size) => apply({ textFontSize: size })
|
|
4039
|
+
}
|
|
4040
|
+
)
|
|
4041
|
+
] })
|
|
4042
|
+
) : null,
|
|
4043
|
+
vm.showMarkerOpacity ? /* @__PURE__ */ jsxs("label", { style: sectionLabelStyle, children: [
|
|
4044
|
+
"Opacidade",
|
|
4045
|
+
vm.mixedOpacity ? /* @__PURE__ */ jsx("span", { style: mixedHintStyle, children: " (misturado)" }) : null,
|
|
3695
4046
|
/* @__PURE__ */ jsx(
|
|
3696
4047
|
"input",
|
|
3697
4048
|
{
|
|
@@ -3699,21 +4050,14 @@ function VectorSelectionInspector({
|
|
|
3699
4050
|
min: 10,
|
|
3700
4051
|
max: 100,
|
|
3701
4052
|
value: opacityPct,
|
|
3702
|
-
onChange: (e) => {
|
|
3703
|
-
const v = Number(e.target.value) / 100;
|
|
3704
|
-
onChange({
|
|
3705
|
-
stroke: hex,
|
|
3706
|
-
strokeWidth,
|
|
3707
|
-
strokeOpacity: v
|
|
3708
|
-
});
|
|
3709
|
-
}
|
|
4053
|
+
onChange: (e) => apply({ strokeOpacity: Number(e.target.value) / 100 })
|
|
3710
4054
|
}
|
|
3711
4055
|
),
|
|
3712
4056
|
/* @__PURE__ */ jsxs("span", { style: { fontWeight: 500, color: "#71717a" }, children: [
|
|
3713
4057
|
opacityPct,
|
|
3714
4058
|
"%"
|
|
3715
4059
|
] })
|
|
3716
|
-
] })
|
|
4060
|
+
] }) : null
|
|
3717
4061
|
]
|
|
3718
4062
|
}
|
|
3719
4063
|
);
|
|
@@ -4192,6 +4536,24 @@ function splitToolbarTools(tools, overflowIds) {
|
|
|
4192
4536
|
const overflow = overflowIds.map((id) => tools.find((t) => t.id === id)).filter((t) => Boolean(t));
|
|
4193
4537
|
return { primary, overflow };
|
|
4194
4538
|
}
|
|
4539
|
+
function usePromotedOverflowTool({
|
|
4540
|
+
overflowTools,
|
|
4541
|
+
selectedId,
|
|
4542
|
+
initialPromotedId
|
|
4543
|
+
}) {
|
|
4544
|
+
const [lastOverflowToolId, setLastOverflowToolId] = useState(() => {
|
|
4545
|
+
if (initialPromotedId == null) return null;
|
|
4546
|
+
return overflowTools.some((t) => t.id === initialPromotedId) ? initialPromotedId : null;
|
|
4547
|
+
});
|
|
4548
|
+
useEffect(() => {
|
|
4549
|
+
if (overflowTools.some((t) => t.id === selectedId)) {
|
|
4550
|
+
setLastOverflowToolId(selectedId);
|
|
4551
|
+
}
|
|
4552
|
+
}, [selectedId, overflowTools]);
|
|
4553
|
+
const promotedTool = lastOverflowToolId ? overflowTools.find((t) => t.id === lastOverflowToolId) : void 0;
|
|
4554
|
+
const remainingOverflowTools = promotedTool ? overflowTools.filter((t) => t.id !== promotedTool.id) : overflowTools;
|
|
4555
|
+
return { promotedTool, remainingOverflowTools };
|
|
4556
|
+
}
|
|
4195
4557
|
var icOverflow = { size: 18, strokeWidth: 2 };
|
|
4196
4558
|
function useOverflowDropdown() {
|
|
4197
4559
|
const [open, setOpen] = useState(false);
|
|
@@ -4726,6 +5088,15 @@ function VectorToolbarComponent({
|
|
|
4726
5088
|
const pluginContext = useContext(CanvuPluginContext);
|
|
4727
5089
|
const runtimeTools = pluginContext?.resolvedTools;
|
|
4728
5090
|
const resolvedTools = tools ?? runtimeTools ?? DEFAULT_VECTOR_TOOLS;
|
|
5091
|
+
const { primary: primaryTools, overflow: overflowTools } = splitToolbarTools(
|
|
5092
|
+
resolvedTools,
|
|
5093
|
+
overflowToolIds
|
|
5094
|
+
);
|
|
5095
|
+
const { promotedTool, remainingOverflowTools } = usePromotedOverflowTool({
|
|
5096
|
+
overflowTools,
|
|
5097
|
+
selectedId: value,
|
|
5098
|
+
initialPromotedId: overflowToolIds[0] ?? null
|
|
5099
|
+
});
|
|
4729
5100
|
if (typeof children === "function") {
|
|
4730
5101
|
const ctx = {
|
|
4731
5102
|
tools: resolvedTools,
|
|
@@ -4770,11 +5141,8 @@ function VectorToolbarComponent({
|
|
|
4770
5141
|
)
|
|
4771
5142
|
] });
|
|
4772
5143
|
}
|
|
4773
|
-
const { primary: primaryTools, overflow: overflowTools } = splitToolbarTools(
|
|
4774
|
-
resolvedTools,
|
|
4775
|
-
overflowToolIds
|
|
4776
|
-
);
|
|
4777
5144
|
const showOverflowMenu = overflowTools.length > 0;
|
|
5145
|
+
const showOverflowDropdown = remainingOverflowTools.length > 0;
|
|
4778
5146
|
const inlineCtx = {
|
|
4779
5147
|
selectedId: value,
|
|
4780
5148
|
selectTool: onChange,
|
|
@@ -4825,6 +5193,7 @@ function VectorToolbarComponent({
|
|
|
4825
5193
|
/* @__PURE__ */ jsx("span", { "aria-hidden": true, style: toolLockDividerStyle })
|
|
4826
5194
|
] }) : null,
|
|
4827
5195
|
primaryTools.map((tool) => renderInlineToolButton(tool, inlineCtx)),
|
|
5196
|
+
promotedTool ? renderInlineToolButton(promotedTool, inlineCtx) : null,
|
|
4828
5197
|
showOverflowMenu && orientation === "horizontal" ? /* @__PURE__ */ jsx(
|
|
4829
5198
|
"span",
|
|
4830
5199
|
{
|
|
@@ -4833,10 +5202,10 @@ function VectorToolbarComponent({
|
|
|
4833
5202
|
style: overflowSpacerStyle
|
|
4834
5203
|
}
|
|
4835
5204
|
) : null,
|
|
4836
|
-
|
|
5205
|
+
showOverflowDropdown ? /* @__PURE__ */ jsx(
|
|
4837
5206
|
ToolbarOverflowMenu,
|
|
4838
5207
|
{
|
|
4839
|
-
tools:
|
|
5208
|
+
tools: remainingOverflowTools,
|
|
4840
5209
|
selectedId: value,
|
|
4841
5210
|
onSelect: onChange,
|
|
4842
5211
|
density,
|
|
@@ -6456,6 +6825,18 @@ var SvgVectorRenderer = class {
|
|
|
6456
6825
|
}
|
|
6457
6826
|
};
|
|
6458
6827
|
|
|
6828
|
+
// src/scene/link-item.ts
|
|
6829
|
+
var LINK_PLUGIN_KEY = "canvuLink";
|
|
6830
|
+
var isCanvuLinkData = (value) => {
|
|
6831
|
+
if (!value || typeof value !== "object") return false;
|
|
6832
|
+
const candidate = value;
|
|
6833
|
+
return typeof candidate.href === "string" && candidate.href.length > 0;
|
|
6834
|
+
};
|
|
6835
|
+
function getLinkData(item) {
|
|
6836
|
+
const entry = item.pluginData?.[LINK_PLUGIN_KEY];
|
|
6837
|
+
return isCanvuLinkData(entry) ? entry : null;
|
|
6838
|
+
}
|
|
6839
|
+
|
|
6459
6840
|
// src/scene/scene.ts
|
|
6460
6841
|
var VectorScene = class {
|
|
6461
6842
|
items = [];
|
|
@@ -6475,6 +6856,7 @@ var VectorScene = class {
|
|
|
6475
6856
|
|
|
6476
6857
|
// src/react/VectorViewport.tsx
|
|
6477
6858
|
init_shape_builders();
|
|
6859
|
+
init_text_svg();
|
|
6478
6860
|
|
|
6479
6861
|
// src/react/blob-url-lifecycle.ts
|
|
6480
6862
|
var SVG_BLOB_HREF_PATTERN = /\b(?:href|xlink:href)=["'](blob:[^"']+)["']/g;
|
|
@@ -6680,6 +7062,9 @@ function InteractionOverlay({
|
|
|
6680
7062
|
);
|
|
6681
7063
|
} else if (placementPreview.kind === "rect" || placementPreview.kind === "ellipse" || placementPreview.kind === "architectural-cloud") {
|
|
6682
7064
|
const r = normalizeRect(placementPreview.rect);
|
|
7065
|
+
const shapeStroke = previewStrokeStyle?.stroke ?? "#1d1d1d";
|
|
7066
|
+
const shapeWidth = previewStrokeStyle?.strokeWidth ?? 2;
|
|
7067
|
+
const shapeOpacity = previewStrokeStyle?.strokeOpacity;
|
|
6683
7068
|
preview = placementPreview.kind === "rect" ? /* @__PURE__ */ jsx(
|
|
6684
7069
|
"rect",
|
|
6685
7070
|
{
|
|
@@ -6687,11 +7072,11 @@ function InteractionOverlay({
|
|
|
6687
7072
|
y: r.y,
|
|
6688
7073
|
width: r.width,
|
|
6689
7074
|
height: r.height,
|
|
7075
|
+
rx: 4,
|
|
6690
7076
|
fill: "none",
|
|
6691
|
-
stroke:
|
|
6692
|
-
strokeWidth:
|
|
6693
|
-
|
|
6694
|
-
vectorEffect: "non-scaling-stroke"
|
|
7077
|
+
stroke: shapeStroke,
|
|
7078
|
+
strokeWidth: shapeWidth,
|
|
7079
|
+
strokeOpacity: shapeOpacity
|
|
6695
7080
|
}
|
|
6696
7081
|
) : placementPreview.kind === "ellipse" ? /* @__PURE__ */ jsx(
|
|
6697
7082
|
"ellipse",
|
|
@@ -6701,29 +7086,30 @@ function InteractionOverlay({
|
|
|
6701
7086
|
rx: r.width / 2,
|
|
6702
7087
|
ry: r.height / 2,
|
|
6703
7088
|
fill: "none",
|
|
6704
|
-
stroke:
|
|
6705
|
-
strokeWidth:
|
|
6706
|
-
|
|
6707
|
-
vectorEffect: "non-scaling-stroke"
|
|
7089
|
+
stroke: shapeStroke,
|
|
7090
|
+
strokeWidth: shapeWidth,
|
|
7091
|
+
strokeOpacity: shapeOpacity
|
|
6708
7092
|
}
|
|
6709
7093
|
) : /* @__PURE__ */ jsx("g", { transform: `translate(${r.x}, ${r.y})`, children: /* @__PURE__ */ jsx(
|
|
6710
7094
|
"path",
|
|
6711
7095
|
{
|
|
6712
|
-
d: buildArchitecturalCloudPathD(r.width, r.height,
|
|
7096
|
+
d: buildArchitecturalCloudPathD(r.width, r.height, shapeWidth),
|
|
6713
7097
|
fill: "none",
|
|
6714
|
-
stroke:
|
|
6715
|
-
strokeWidth:
|
|
6716
|
-
|
|
7098
|
+
stroke: shapeStroke,
|
|
7099
|
+
strokeWidth: shapeWidth,
|
|
7100
|
+
strokeOpacity: shapeOpacity,
|
|
6717
7101
|
strokeLinecap: "round",
|
|
6718
|
-
strokeLinejoin: "round"
|
|
6719
|
-
vectorEffect: "non-scaling-stroke"
|
|
7102
|
+
strokeLinejoin: "round"
|
|
6720
7103
|
}
|
|
6721
7104
|
) });
|
|
6722
7105
|
} else if (placementPreview.kind === "line" || placementPreview.kind === "arrow") {
|
|
6723
7106
|
const { start, end } = placementPreview;
|
|
7107
|
+
const shapeStroke = previewStrokeStyle?.stroke ?? "#1d1d1d";
|
|
7108
|
+
const shapeWidth = previewStrokeStyle?.strokeWidth ?? 2;
|
|
7109
|
+
const shapeOpacity = previewStrokeStyle?.strokeOpacity;
|
|
6724
7110
|
const geometry = placementPreview.kind === "arrow" ? computeStraightArrowGeometry(
|
|
6725
7111
|
{ x1: start.x, y1: start.y, x2: end.x, y2: end.y },
|
|
6726
|
-
|
|
7112
|
+
shapeWidth
|
|
6727
7113
|
) : null;
|
|
6728
7114
|
preview = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6729
7115
|
/* @__PURE__ */ jsx(
|
|
@@ -6733,11 +7119,10 @@ function InteractionOverlay({
|
|
|
6733
7119
|
y1: start.y,
|
|
6734
7120
|
x2: geometry?.shaftEndX ?? end.x,
|
|
6735
7121
|
y2: geometry?.shaftEndY ?? end.y,
|
|
6736
|
-
stroke:
|
|
6737
|
-
strokeWidth:
|
|
6738
|
-
|
|
6739
|
-
strokeLinecap: "round"
|
|
6740
|
-
vectorEffect: "non-scaling-stroke"
|
|
7122
|
+
stroke: shapeStroke,
|
|
7123
|
+
strokeWidth: shapeWidth,
|
|
7124
|
+
strokeOpacity: shapeOpacity,
|
|
7125
|
+
strokeLinecap: "round"
|
|
6741
7126
|
}
|
|
6742
7127
|
),
|
|
6743
7128
|
placementPreview.kind === "arrow" && geometry ? /* @__PURE__ */ jsx(
|
|
@@ -6745,10 +7130,9 @@ function InteractionOverlay({
|
|
|
6745
7130
|
{
|
|
6746
7131
|
d: `M ${geometry.headLeftX} ${geometry.headLeftY} L ${geometry.headTipX} ${geometry.headTipY} L ${geometry.headRightX} ${geometry.headRightY}`,
|
|
6747
7132
|
fill: "none",
|
|
6748
|
-
stroke:
|
|
6749
|
-
strokeWidth:
|
|
6750
|
-
strokeOpacity:
|
|
6751
|
-
strokeDasharray: dashPattern,
|
|
7133
|
+
stroke: shapeStroke,
|
|
7134
|
+
strokeWidth: shapeWidth,
|
|
7135
|
+
strokeOpacity: shapeOpacity,
|
|
6752
7136
|
strokeLinecap: "round",
|
|
6753
7137
|
strokeLinejoin: "round"
|
|
6754
7138
|
}
|
|
@@ -6762,7 +7146,8 @@ function InteractionOverlay({
|
|
|
6762
7146
|
const previewStyle = {
|
|
6763
7147
|
stroke: isLaser ? "#f43f5e" : previewStrokeStyle?.stroke ?? "#64748b",
|
|
6764
7148
|
strokeWidth: isLaser ? 4 : previewStrokeStyle?.strokeWidth ?? (tool === "marker" ? 16 : 3),
|
|
6765
|
-
...previewStrokeStyle?.strokeOpacity != null && !isLaser ? { strokeOpacity: previewStrokeStyle.strokeOpacity } : {}
|
|
7149
|
+
...previewStrokeStyle?.strokeOpacity != null && !isLaser ? { strokeOpacity: previewStrokeStyle.strokeOpacity } : {},
|
|
7150
|
+
...previewStrokeStyle?.strokeDash != null && !isLaser ? { strokeDash: previewStrokeStyle.strokeDash } : {}
|
|
6766
7151
|
};
|
|
6767
7152
|
const payload = computeFreehandSvgPayload(
|
|
6768
7153
|
raw,
|
|
@@ -6806,6 +7191,7 @@ function InteractionOverlay({
|
|
|
6806
7191
|
strokeOpacity: isLaser ? 0.85 : payload.strokeOpacity,
|
|
6807
7192
|
strokeLinecap: "round",
|
|
6808
7193
|
strokeLinejoin: "round",
|
|
7194
|
+
strokeDasharray: payload.strokeDasharray,
|
|
6809
7195
|
shapeRendering: "geometricPrecision"
|
|
6810
7196
|
}
|
|
6811
7197
|
);
|
|
@@ -7211,6 +7597,9 @@ function TextEditOverlay({
|
|
|
7211
7597
|
const fontSize = fsWorld * z;
|
|
7212
7598
|
const lineHeight = fsWorld * (22 / 18) * z;
|
|
7213
7599
|
const fixedBox = !!item.textFixedBounds;
|
|
7600
|
+
const padTop = EDIT_TOP_PAD_RATIO * fsWorld * z;
|
|
7601
|
+
const padX = 4 * z;
|
|
7602
|
+
const textColor = item.stroke ?? "#1d1d1d";
|
|
7214
7603
|
return /* @__PURE__ */ jsx(
|
|
7215
7604
|
"div",
|
|
7216
7605
|
{
|
|
@@ -7241,14 +7630,14 @@ function TextEditOverlay({
|
|
|
7241
7630
|
width: "100%",
|
|
7242
7631
|
height: "100%",
|
|
7243
7632
|
margin: 0,
|
|
7244
|
-
padding:
|
|
7633
|
+
padding: `${padTop}px ${padX}px 0px ${padX}px`,
|
|
7245
7634
|
border: "none",
|
|
7246
7635
|
borderRadius: 0,
|
|
7247
7636
|
resize: "none",
|
|
7248
|
-
fontFamily:
|
|
7637
|
+
fontFamily: TEXT_FONT_FAMILY,
|
|
7249
7638
|
fontSize,
|
|
7250
7639
|
lineHeight: `${lineHeight}px`,
|
|
7251
|
-
color:
|
|
7640
|
+
color: textColor,
|
|
7252
7641
|
background: "transparent",
|
|
7253
7642
|
backgroundColor: "transparent",
|
|
7254
7643
|
outline: "none",
|
|
@@ -7256,7 +7645,6 @@ function TextEditOverlay({
|
|
|
7256
7645
|
appearance: "none",
|
|
7257
7646
|
WebkitAppearance: "none",
|
|
7258
7647
|
WebkitTapHighlightColor: "transparent",
|
|
7259
|
-
/* Auto-sized text: no soft wrap / scrollbar; fixed box: wrap like the SVG. */
|
|
7260
7648
|
whiteSpace: fixedBox ? "pre-wrap" : "pre",
|
|
7261
7649
|
overflow: fixedBox ? "auto" : "hidden",
|
|
7262
7650
|
overflowX: fixedBox ? "hidden" : "hidden",
|
|
@@ -7632,6 +8020,7 @@ var VectorViewport = forwardRef(
|
|
|
7632
8020
|
selectedIds: selectedIdsProp,
|
|
7633
8021
|
onSelectionChange,
|
|
7634
8022
|
onItemsChange: consumerOnItemsChange,
|
|
8023
|
+
onActivateLink,
|
|
7635
8024
|
onWorldPointerDown: consumerOnWorldPointerDown,
|
|
7636
8025
|
toolbar,
|
|
7637
8026
|
navMenu,
|
|
@@ -7812,6 +8201,8 @@ var VectorViewport = forwardRef(
|
|
|
7812
8201
|
const itemsRef = useRef(items);
|
|
7813
8202
|
const onWorldPointerDownRef = useRef(onWorldPointerDown);
|
|
7814
8203
|
const onItemsChangeRef = useRef(onItemsChange);
|
|
8204
|
+
const onActivateLinkRef = useRef(onActivateLink);
|
|
8205
|
+
onActivateLinkRef.current = onActivateLink;
|
|
7815
8206
|
const assetStoreRef = useRef(assetStore);
|
|
7816
8207
|
assetStoreRef.current = assetStore;
|
|
7817
8208
|
const customPlacementRef = useRef(customPlacement);
|
|
@@ -7943,14 +8334,32 @@ var VectorViewport = forwardRef(
|
|
|
7943
8334
|
imageStoreRef.current = new IndexedDbImageStore();
|
|
7944
8335
|
}
|
|
7945
8336
|
const rememberedImageBlobHrefsRef = useRef(/* @__PURE__ */ new Set());
|
|
7946
|
-
const strokeStyleRef = useRef({
|
|
8337
|
+
const strokeStyleRef = useRef({
|
|
8338
|
+
...DEFAULT_STROKE_STYLE,
|
|
8339
|
+
textFontSize: DEFAULT_TEXT_FONT_SIZE
|
|
8340
|
+
});
|
|
7947
8341
|
const [strokeStyleState, setStrokeStyleState] = useState({
|
|
7948
|
-
...DEFAULT_STROKE_STYLE
|
|
8342
|
+
...DEFAULT_STROKE_STYLE,
|
|
8343
|
+
textFontSize: DEFAULT_TEXT_FONT_SIZE
|
|
7949
8344
|
});
|
|
7950
8345
|
const setCurrentStrokeStyle = useCallback((next) => {
|
|
7951
8346
|
strokeStyleRef.current = next;
|
|
7952
8347
|
setStrokeStyleState(next);
|
|
7953
8348
|
}, []);
|
|
8349
|
+
const patchCurrentStrokeStyle = useCallback(
|
|
8350
|
+
(patch) => {
|
|
8351
|
+
const merged = { ...strokeStyleRef.current };
|
|
8352
|
+
for (const key of Object.keys(patch)) {
|
|
8353
|
+
const v = patch[key];
|
|
8354
|
+
if (v !== void 0) {
|
|
8355
|
+
merged[key] = v;
|
|
8356
|
+
}
|
|
8357
|
+
}
|
|
8358
|
+
strokeStyleRef.current = merged;
|
|
8359
|
+
setStrokeStyleState(merged);
|
|
8360
|
+
},
|
|
8361
|
+
[]
|
|
8362
|
+
);
|
|
7954
8363
|
const progressiveQueueRef = useRef(/* @__PURE__ */ new Set());
|
|
7955
8364
|
useEffect(() => {
|
|
7956
8365
|
const store = imageStoreRef.current;
|
|
@@ -8099,10 +8508,11 @@ var VectorViewport = forwardRef(
|
|
|
8099
8508
|
change(
|
|
8100
8509
|
exists ? replaceItem(itemsRef.current, id, item) : [...itemsRef.current, item]
|
|
8101
8510
|
);
|
|
8102
|
-
|
|
8511
|
+
patchCurrentStrokeStyle({
|
|
8103
8512
|
stroke: item.stroke ?? DEFAULT_STROKE_STYLE.stroke,
|
|
8104
8513
|
strokeWidth: item.strokeWidth ?? DEFAULT_STROKE_STYLE.strokeWidth,
|
|
8105
|
-
|
|
8514
|
+
strokeOpacity: item.strokeOpacity,
|
|
8515
|
+
strokeDash: item.strokeDash
|
|
8106
8516
|
});
|
|
8107
8517
|
}
|
|
8108
8518
|
if (!shouldKeepToolForContinuousPenInput(args.tool, args.pointerType)) {
|
|
@@ -8110,8 +8520,8 @@ var VectorViewport = forwardRef(
|
|
|
8110
8520
|
}
|
|
8111
8521
|
},
|
|
8112
8522
|
[
|
|
8523
|
+
patchCurrentStrokeStyle,
|
|
8113
8524
|
requestAutoResetTool,
|
|
8114
|
-
setCurrentStrokeStyle,
|
|
8115
8525
|
shouldKeepToolForContinuousPenInput
|
|
8116
8526
|
]
|
|
8117
8527
|
);
|
|
@@ -8847,24 +9257,28 @@ var VectorViewport = forwardRef(
|
|
|
8847
9257
|
renderFrame();
|
|
8848
9258
|
}, [renderFrame]);
|
|
8849
9259
|
useEffect(() => {
|
|
9260
|
+
const current = strokeStyleRef.current;
|
|
8850
9261
|
if (toolId === "marker") {
|
|
8851
9262
|
setCurrentStrokeStyle({
|
|
8852
|
-
...
|
|
9263
|
+
...current,
|
|
8853
9264
|
...MARKER_TOOL_STYLE
|
|
8854
9265
|
});
|
|
8855
9266
|
return;
|
|
8856
9267
|
}
|
|
8857
|
-
const current = strokeStyleRef.current;
|
|
8858
9268
|
if (isDefaultMarkerToolStyle(current)) {
|
|
8859
9269
|
setCurrentStrokeStyle({
|
|
8860
9270
|
stroke: DEFAULT_STROKE_STYLE.stroke,
|
|
8861
|
-
strokeWidth: toolId === "draw" ? 10 : DEFAULT_STROKE_STYLE.strokeWidth
|
|
9271
|
+
strokeWidth: toolId === "draw" ? 10 : DEFAULT_STROKE_STYLE.strokeWidth,
|
|
9272
|
+
strokeDash: current.strokeDash,
|
|
9273
|
+
textFontSize: current.textFontSize
|
|
8862
9274
|
});
|
|
8863
9275
|
return;
|
|
8864
9276
|
}
|
|
8865
9277
|
setCurrentStrokeStyle({
|
|
8866
9278
|
stroke: current.stroke,
|
|
8867
|
-
strokeWidth: toolId === "draw" ? 10 : current.strokeWidth
|
|
9279
|
+
strokeWidth: toolId === "draw" ? 10 : current.strokeWidth,
|
|
9280
|
+
strokeDash: current.strokeDash,
|
|
9281
|
+
textFontSize: current.textFontSize
|
|
8868
9282
|
});
|
|
8869
9283
|
}, [setCurrentStrokeStyle, toolId]);
|
|
8870
9284
|
useEffect(() => {
|
|
@@ -8873,15 +9287,14 @@ var VectorViewport = forwardRef(
|
|
|
8873
9287
|
const it = items.find((i) => i.id === primaryId);
|
|
8874
9288
|
if (!it || it.locked) return;
|
|
8875
9289
|
if (it.toolKind === "image") return;
|
|
8876
|
-
|
|
9290
|
+
patchCurrentStrokeStyle({
|
|
8877
9291
|
stroke: it.stroke ?? DEFAULT_STROKE_STYLE.stroke,
|
|
8878
|
-
strokeWidth: it.strokeWidth ?? DEFAULT_STROKE_STYLE.strokeWidth
|
|
8879
|
-
|
|
8880
|
-
|
|
8881
|
-
|
|
8882
|
-
}
|
|
8883
|
-
|
|
8884
|
-
}, [effectiveSelectedIds, items, setCurrentStrokeStyle]);
|
|
9292
|
+
strokeWidth: it.strokeWidth ?? DEFAULT_STROKE_STYLE.strokeWidth,
|
|
9293
|
+
strokeOpacity: it.strokeOpacity,
|
|
9294
|
+
strokeDash: it.strokeDash,
|
|
9295
|
+
...it.toolKind === "text" && it.textFontSize != null ? { textFontSize: it.textFontSize } : {}
|
|
9296
|
+
});
|
|
9297
|
+
}, [effectiveSelectedIds, items, patchCurrentStrokeStyle]);
|
|
8885
9298
|
const handleSelectionStyleChange = useCallback(
|
|
8886
9299
|
(patch) => {
|
|
8887
9300
|
const change = onItemsChangeRef.current;
|
|
@@ -8897,25 +9310,15 @@ var VectorViewport = forwardRef(
|
|
|
8897
9310
|
nextList = replaceItem(nextList, id, out);
|
|
8898
9311
|
}
|
|
8899
9312
|
change(nextList);
|
|
8900
|
-
|
|
8901
|
-
...strokeStyleRef.current,
|
|
8902
|
-
stroke: patch.stroke,
|
|
8903
|
-
strokeWidth: patch.strokeWidth,
|
|
8904
|
-
...patch.strokeOpacity != null ? { strokeOpacity: patch.strokeOpacity } : {}
|
|
8905
|
-
});
|
|
9313
|
+
patchCurrentStrokeStyle(patch);
|
|
8906
9314
|
},
|
|
8907
|
-
[
|
|
9315
|
+
[patchCurrentStrokeStyle]
|
|
8908
9316
|
);
|
|
8909
9317
|
const handleActiveToolStyleChange = useCallback(
|
|
8910
9318
|
(patch) => {
|
|
8911
|
-
|
|
8912
|
-
setCurrentStrokeStyle({
|
|
8913
|
-
stroke: patch.stroke,
|
|
8914
|
-
strokeWidth: patch.strokeWidth,
|
|
8915
|
-
...patch.strokeOpacity != null ? { strokeOpacity: patch.strokeOpacity } : current.strokeOpacity != null ? { strokeOpacity: current.strokeOpacity } : {}
|
|
8916
|
-
});
|
|
9319
|
+
patchCurrentStrokeStyle(patch);
|
|
8917
9320
|
},
|
|
8918
|
-
[
|
|
9321
|
+
[patchCurrentStrokeStyle]
|
|
8919
9322
|
);
|
|
8920
9323
|
const commitTextEdit = useCallback(() => {
|
|
8921
9324
|
const id = editingTextIdRef.current;
|
|
@@ -9087,13 +9490,27 @@ var VectorViewport = forwardRef(
|
|
|
9087
9490
|
);
|
|
9088
9491
|
const handleOverlayDoubleClick = useCallback(
|
|
9089
9492
|
(e) => {
|
|
9090
|
-
if (!interactiveRef.current || !onItemsChangeRef.current) return;
|
|
9091
|
-
if (toolIdRef.current !== "select") return;
|
|
9092
|
-
e.preventDefault();
|
|
9093
9493
|
const cam = cameraRef.current;
|
|
9094
9494
|
if (!cam) return;
|
|
9095
9495
|
const { worldX, worldY } = screenToWorld(e.clientX, e.clientY);
|
|
9096
9496
|
const lineHitWorld = 10 / cam.zoom;
|
|
9497
|
+
const linkHit = hitTestWorldPoint(resolvedItemsRef.current, worldX, worldY, {
|
|
9498
|
+
lineHitWorld,
|
|
9499
|
+
ignoreLocked: false
|
|
9500
|
+
});
|
|
9501
|
+
const link = linkHit ? getLinkData(linkHit) : null;
|
|
9502
|
+
if (linkHit && link) {
|
|
9503
|
+
e.preventDefault();
|
|
9504
|
+
if (onActivateLinkRef.current) {
|
|
9505
|
+
onActivateLinkRef.current({ link, item: linkHit });
|
|
9506
|
+
} else if (typeof window !== "undefined" && typeof window.open === "function") {
|
|
9507
|
+
window.open(link.href, "_blank", "noopener,noreferrer");
|
|
9508
|
+
}
|
|
9509
|
+
return;
|
|
9510
|
+
}
|
|
9511
|
+
if (!interactiveRef.current || !onItemsChangeRef.current) return;
|
|
9512
|
+
if (toolIdRef.current !== "select") return;
|
|
9513
|
+
e.preventDefault();
|
|
9097
9514
|
const hit = hitTestWorldPoint(resolvedItemsRef.current, worldX, worldY, {
|
|
9098
9515
|
lineHitWorld,
|
|
9099
9516
|
ignoreLocked: true
|
|
@@ -10034,16 +10451,21 @@ var VectorViewport = forwardRef(
|
|
|
10034
10451
|
const id = createShapeId();
|
|
10035
10452
|
const { x: worldX, y: worldY } = st.startWorld;
|
|
10036
10453
|
if (st.tool === "text") {
|
|
10454
|
+
const fs = strokeStyleRef.current.textFontSize;
|
|
10455
|
+
const baseline = textBaselineYFor(fs);
|
|
10456
|
+
const lh = textLineHeightFor(fs);
|
|
10457
|
+
const minH = Math.max(26, baseline + Math.max(4, lh * 0.2));
|
|
10037
10458
|
const newItem = createTextItem(
|
|
10038
10459
|
id,
|
|
10039
10460
|
{
|
|
10040
10461
|
x: worldX - 4,
|
|
10041
|
-
y: worldY -
|
|
10462
|
+
y: worldY - baseline,
|
|
10042
10463
|
width: 160,
|
|
10043
|
-
height:
|
|
10464
|
+
height: minH
|
|
10044
10465
|
},
|
|
10045
10466
|
"",
|
|
10046
|
-
strokeStyleRef.current
|
|
10467
|
+
strokeStyleRef.current,
|
|
10468
|
+
fs
|
|
10047
10469
|
);
|
|
10048
10470
|
editingTextSnapshotRef.current = {
|
|
10049
10471
|
...newItem,
|
|
@@ -10194,12 +10616,63 @@ var VectorViewport = forwardRef(
|
|
|
10194
10616
|
return effectiveSelectedIds.map((id) => resolvedItems.find((i) => i.id === id)).filter((i) => i != null);
|
|
10195
10617
|
}, [effectiveSelectedIds, resolvedItems]);
|
|
10196
10618
|
const activeToolInspectorStyle = useMemo(() => {
|
|
10197
|
-
if (toolId
|
|
10198
|
-
|
|
10199
|
-
|
|
10200
|
-
|
|
10201
|
-
|
|
10202
|
-
|
|
10619
|
+
if (toolId === "draw") {
|
|
10620
|
+
return {
|
|
10621
|
+
toolKind: "draw",
|
|
10622
|
+
label: "Caneta",
|
|
10623
|
+
...strokeStyleState
|
|
10624
|
+
};
|
|
10625
|
+
}
|
|
10626
|
+
if (toolId === "marker") {
|
|
10627
|
+
return {
|
|
10628
|
+
toolKind: "marker",
|
|
10629
|
+
label: "Marcador",
|
|
10630
|
+
...strokeStyleState
|
|
10631
|
+
};
|
|
10632
|
+
}
|
|
10633
|
+
if (toolId === "text") {
|
|
10634
|
+
return {
|
|
10635
|
+
toolKind: "text",
|
|
10636
|
+
label: "Texto",
|
|
10637
|
+
...strokeStyleState
|
|
10638
|
+
};
|
|
10639
|
+
}
|
|
10640
|
+
if (toolId === "rect") {
|
|
10641
|
+
return {
|
|
10642
|
+
toolKind: "rect",
|
|
10643
|
+
label: "Ret\xE2ngulo",
|
|
10644
|
+
...strokeStyleState
|
|
10645
|
+
};
|
|
10646
|
+
}
|
|
10647
|
+
if (toolId === "ellipse") {
|
|
10648
|
+
return {
|
|
10649
|
+
toolKind: "ellipse",
|
|
10650
|
+
label: "Elipse",
|
|
10651
|
+
...strokeStyleState
|
|
10652
|
+
};
|
|
10653
|
+
}
|
|
10654
|
+
if (toolId === "architectural-cloud") {
|
|
10655
|
+
return {
|
|
10656
|
+
toolKind: "architectural-cloud",
|
|
10657
|
+
label: "Nuvem",
|
|
10658
|
+
...strokeStyleState
|
|
10659
|
+
};
|
|
10660
|
+
}
|
|
10661
|
+
if (toolId === "line") {
|
|
10662
|
+
return {
|
|
10663
|
+
toolKind: "line",
|
|
10664
|
+
label: "Linha",
|
|
10665
|
+
...strokeStyleState
|
|
10666
|
+
};
|
|
10667
|
+
}
|
|
10668
|
+
if (toolId === "arrow") {
|
|
10669
|
+
return {
|
|
10670
|
+
toolKind: "arrow",
|
|
10671
|
+
label: "Seta",
|
|
10672
|
+
...strokeStyleState
|
|
10673
|
+
};
|
|
10674
|
+
}
|
|
10675
|
+
return void 0;
|
|
10203
10676
|
}, [strokeStyleState, toolId]);
|
|
10204
10677
|
const eraserPreviewItemsForOverlay = useMemo(() => {
|
|
10205
10678
|
return eraserPreviewIds.map((id) => resolvedItems.find((i) => i.id === id)).filter((i) => i != null);
|