canvu-react 0.3.39 → 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-DowNdaOJ.d.cts → asset-hydration-B7yMDQE-.d.cts} +2 -2
- package/dist/{asset-hydration-DdFLdlqX.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 +59 -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 +59 -15
- 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 +699 -255
- 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 +699 -255
- 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-Dedcl6tw.d.cts → shape-builders-BAWu-PxX.d.cts} +7 -3
- package/dist/{shape-builders-C7bxJBGR.d.ts → shape-builders-ClKv9tz9.d.ts} +7 -3
- package/dist/tldraw.cjs +56 -14
- 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 +56 -14
- package/dist/tldraw.js.map +1 -1
- package/dist/{types-DUW61Tjy.d.cts → types-BC9Xgfu6.d.cts} +11 -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-BBb8KoyW.d.ts → types-DlSVGX0w.d.ts} +11 -6
- package/package.json +1 -1
package/dist/react.cjs
CHANGED
|
@@ -91,6 +91,12 @@ function lineHeightFor(fontSize) {
|
|
|
91
91
|
function firstLineBaselineY(fontSize) {
|
|
92
92
|
return fontSize * FIRST_LINE_BASELINE_RATIO;
|
|
93
93
|
}
|
|
94
|
+
function textBaselineYFor(fontSize) {
|
|
95
|
+
return firstLineBaselineY(fontSize);
|
|
96
|
+
}
|
|
97
|
+
function textLineHeightFor(fontSize) {
|
|
98
|
+
return lineHeightFor(fontSize);
|
|
99
|
+
}
|
|
94
100
|
function measureTextBoundsLocal(content, fontSize = DEFAULT_TEXT_FONT_SIZE) {
|
|
95
101
|
const cacheKey = textMeasureCacheKey(content, fontSize);
|
|
96
102
|
const cached = textMeasureCache.get(cacheKey);
|
|
@@ -104,7 +110,7 @@ function measureTextBoundsLocal(content, fontSize = DEFAULT_TEXT_FONT_SIZE) {
|
|
|
104
110
|
let maxInnerW = 0;
|
|
105
111
|
const ctx = getSharedMeasureContext();
|
|
106
112
|
if (ctx) {
|
|
107
|
-
ctx.font = `${fontSize}px
|
|
113
|
+
ctx.font = `${fontSize}px ${TEXT_FONT_FAMILY}`;
|
|
108
114
|
for (const line of lines) {
|
|
109
115
|
const toMeasure = trimmed.length === 0 ? PLACEHOLDER : line.length === 0 ? " " : line;
|
|
110
116
|
maxInnerW = Math.max(maxInnerW, ctx.measureText(toMeasure).width);
|
|
@@ -120,22 +126,22 @@ function measureTextBoundsLocal(content, fontSize = DEFAULT_TEXT_FONT_SIZE) {
|
|
|
120
126
|
const width = Math.max(minW, TEXT_PAD_X * 2 + maxInnerW);
|
|
121
127
|
const height = Math.max(
|
|
122
128
|
MIN_TEXT_BOX_H,
|
|
123
|
-
baselineY + (lines.length - 1) * lh + Math.max(
|
|
129
|
+
baselineY + (lines.length - 1) * lh + Math.max(4, fontSize * BOTTOM_PAD_RATIO)
|
|
124
130
|
);
|
|
125
131
|
const measured = { width, height };
|
|
126
132
|
cacheMeasuredBounds(cacheKey, measured);
|
|
127
133
|
return measured;
|
|
128
134
|
}
|
|
129
|
-
function buildTextSvg(content, _width, _height, fillColor = "#
|
|
135
|
+
function buildTextSvg(content, _width, _height, fillColor = "#1d1d1d", fontSize = DEFAULT_TEXT_FONT_SIZE) {
|
|
130
136
|
const lh = lineHeightFor(fontSize);
|
|
131
137
|
const y0 = firstLineBaselineY(fontSize);
|
|
132
138
|
const trimmed = content.trim();
|
|
133
139
|
if (trimmed.length === 0) {
|
|
134
|
-
return `<text x="4" y="${y0}" font-size="${fontSize}" font-family="
|
|
140
|
+
return `<text x="4" y="${y0}" font-size="${fontSize}" font-family="${TEXT_FONT_FAMILY}" fill="#94a3b8" font-style="italic">${escapeSvgTextContent(PLACEHOLDER)}</text>`;
|
|
135
141
|
}
|
|
136
142
|
const lines = content.split("\n");
|
|
137
143
|
if (lines.length === 1) {
|
|
138
|
-
return `<text x="4" y="${y0}" font-size="${fontSize}" font-family="
|
|
144
|
+
return `<text x="4" y="${y0}" font-size="${fontSize}" font-family="${TEXT_FONT_FAMILY}" fill="${fillColor}">${escapeSvgTextContent(lines[0] ?? "")}</text>`;
|
|
139
145
|
}
|
|
140
146
|
const parts = [];
|
|
141
147
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -146,28 +152,32 @@ function buildTextSvg(content, _width, _height, fillColor = "#2563eb", fontSize
|
|
|
146
152
|
parts.push(`<tspan x="4" dy="${lh}">${escapeSvgTextContent(line)}</tspan>`);
|
|
147
153
|
}
|
|
148
154
|
}
|
|
149
|
-
return `<text x="4" y="${y0}" font-size="${fontSize}" font-family="
|
|
155
|
+
return `<text x="4" y="${y0}" font-size="${fontSize}" font-family="${TEXT_FONT_FAMILY}" fill="${fillColor}">${parts.join("")}</text>`;
|
|
150
156
|
}
|
|
151
|
-
function buildTextFixedBoundsSvg(content, width, height, fillColor = "#
|
|
157
|
+
function buildTextFixedBoundsSvg(content, width, height, fillColor = "#1d1d1d", fontSize = DEFAULT_TEXT_FONT_SIZE) {
|
|
152
158
|
const w = Math.max(1, width);
|
|
153
159
|
const h = Math.max(1, height);
|
|
154
160
|
const lh = lineHeightFor(fontSize);
|
|
155
161
|
const trimmed = content.trim();
|
|
162
|
+
const padTop = EDIT_TOP_PAD_RATIO * fontSize;
|
|
156
163
|
if (trimmed.length === 0) {
|
|
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
|
|
164
|
+
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>`;
|
|
158
165
|
}
|
|
159
166
|
const body = escapeHtmlText(content);
|
|
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
|
|
167
|
+
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>`;
|
|
161
168
|
}
|
|
162
|
-
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;
|
|
169
|
+
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;
|
|
163
170
|
var init_text_svg = __esm({
|
|
164
171
|
"src/scene/text-svg.ts"() {
|
|
165
172
|
DEFAULT_TEXT_FONT_SIZE = 18;
|
|
173
|
+
TEXT_FONT_FAMILY = "Inter, -apple-system, BlinkMacSystemFont, ui-sans-serif, system-ui, sans-serif";
|
|
166
174
|
LINE_HEIGHT_RATIO = 22 / 18;
|
|
167
|
-
FIRST_LINE_BASELINE_RATIO =
|
|
175
|
+
FIRST_LINE_BASELINE_RATIO = 20 / 18;
|
|
176
|
+
EDIT_TOP_PAD_RATIO = 4 / 18;
|
|
177
|
+
BOTTOM_PAD_RATIO = 4 / 18;
|
|
168
178
|
PLACEHOLDER = "Tap to type";
|
|
169
179
|
MIN_TEXT_BOX_W = 40;
|
|
170
|
-
MIN_TEXT_BOX_H =
|
|
180
|
+
MIN_TEXT_BOX_H = 26;
|
|
171
181
|
TEXT_PAD_X = 4;
|
|
172
182
|
MAX_TEXT_MEASURE_CACHE_ENTRIES = 2e3;
|
|
173
183
|
textMeasureCache = /* @__PURE__ */ new Map();
|
|
@@ -280,7 +290,8 @@ function resolveStrokeStyle(item) {
|
|
|
280
290
|
return {
|
|
281
291
|
stroke: item.stroke ?? DEFAULT_STROKE_STYLE.stroke,
|
|
282
292
|
strokeWidth: item.strokeWidth ?? DEFAULT_STROKE_STYLE.strokeWidth,
|
|
283
|
-
strokeOpacity: item.strokeOpacity
|
|
293
|
+
strokeOpacity: item.strokeOpacity,
|
|
294
|
+
strokeDash: item.strokeDash
|
|
284
295
|
};
|
|
285
296
|
}
|
|
286
297
|
function strokeOpacityAttr(style) {
|
|
@@ -603,6 +614,30 @@ function buildDrawDotSvg(r, style = DEFAULT_STROKE_STYLE) {
|
|
|
603
614
|
const op = style.strokeOpacity != null ? ` fill-opacity="${style.strokeOpacity}"` : "";
|
|
604
615
|
return `<circle cx="${r}" cy="${r}" r="${r}" fill="${style.stroke}" shape-rendering="geometricPrecision"${op} />`;
|
|
605
616
|
}
|
|
617
|
+
function dashArrayForDrawStroke(strokeWidth) {
|
|
618
|
+
const dash = Math.max(strokeWidth * 1.8, 4);
|
|
619
|
+
const gap = Math.max(strokeWidth * 1.4, 3);
|
|
620
|
+
return `${dash} ${gap}`;
|
|
621
|
+
}
|
|
622
|
+
function buildSmoothedCenterlinePath(points) {
|
|
623
|
+
if (points.length < 2) return null;
|
|
624
|
+
const first = points[0];
|
|
625
|
+
if (!first) return null;
|
|
626
|
+
let d = `M ${first.x} ${first.y}`;
|
|
627
|
+
for (let i = 1; i < points.length - 1; i++) {
|
|
628
|
+
const a = points[i];
|
|
629
|
+
const b = points[i + 1];
|
|
630
|
+
if (!a || !b) continue;
|
|
631
|
+
const midX = (a.x + b.x) / 2;
|
|
632
|
+
const midY = (a.y + b.y) / 2;
|
|
633
|
+
d += ` Q ${a.x} ${a.y} ${midX} ${midY}`;
|
|
634
|
+
}
|
|
635
|
+
const last = points[points.length - 1];
|
|
636
|
+
if (last) {
|
|
637
|
+
d += ` L ${last.x} ${last.y}`;
|
|
638
|
+
}
|
|
639
|
+
return d;
|
|
640
|
+
}
|
|
606
641
|
function computeFreehandSvgPayload(pathPointsLocal, style, toolKind, strokeComplete = true) {
|
|
607
642
|
if (pathPointsLocal.length === 0) return null;
|
|
608
643
|
if (pathPointsLocal.length === 1) {
|
|
@@ -617,6 +652,18 @@ function computeFreehandSvgPayload(pathPointsLocal, style, toolKind, strokeCompl
|
|
|
617
652
|
fillOpacity: style.strokeOpacity
|
|
618
653
|
};
|
|
619
654
|
}
|
|
655
|
+
if (style.strokeDash === "dashed" && (toolKind === "draw" || toolKind === "pencil")) {
|
|
656
|
+
const d2 = buildSmoothedCenterlinePath(pathPointsLocal);
|
|
657
|
+
if (!d2) return null;
|
|
658
|
+
return {
|
|
659
|
+
kind: "strokePath",
|
|
660
|
+
d: d2,
|
|
661
|
+
stroke: style.stroke,
|
|
662
|
+
strokeWidth: style.strokeWidth,
|
|
663
|
+
strokeOpacity: style.strokeOpacity,
|
|
664
|
+
strokeDasharray: dashArrayForDrawStroke(style.strokeWidth)
|
|
665
|
+
};
|
|
666
|
+
}
|
|
620
667
|
const hasPressure = pathPointsLocal.some(
|
|
621
668
|
(p) => p.pressure != null && Number.isFinite(p.pressure)
|
|
622
669
|
);
|
|
@@ -659,7 +706,8 @@ function freehandPayloadToSvgString(payload) {
|
|
|
659
706
|
strokeWidth: payload.strokeWidth,
|
|
660
707
|
strokeOpacity: payload.strokeOpacity
|
|
661
708
|
});
|
|
662
|
-
|
|
709
|
+
const dash = payload.strokeDasharray ? ` stroke-dasharray="${payload.strokeDasharray}"` : "";
|
|
710
|
+
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} />`;
|
|
663
711
|
}
|
|
664
712
|
function buildFreehandPathSvg(pathPointsLocal, style, toolKind, strokeComplete = true) {
|
|
665
713
|
const payload = computeFreehandSvgPayload(
|
|
@@ -871,7 +919,7 @@ function createDrawDotItem(id, worldX, worldY, radius, style) {
|
|
|
871
919
|
childrenSvg: ""
|
|
872
920
|
});
|
|
873
921
|
}
|
|
874
|
-
function createTextItem(id, bounds, text = "", style) {
|
|
922
|
+
function createTextItem(id, bounds, text = "", style, textFontSize) {
|
|
875
923
|
const r = normalizeRect(bounds);
|
|
876
924
|
const s = { ...DEFAULT_STROKE_STYLE, ...style };
|
|
877
925
|
return rebuildItemSvg({
|
|
@@ -884,6 +932,7 @@ function createTextItem(id, bounds, text = "", style) {
|
|
|
884
932
|
stroke: s.stroke,
|
|
885
933
|
strokeWidth: s.strokeWidth,
|
|
886
934
|
...s.strokeOpacity != null ? { strokeOpacity: s.strokeOpacity } : {},
|
|
935
|
+
...textFontSize != null ? { textFontSize } : {},
|
|
887
936
|
childrenSvg: ""
|
|
888
937
|
});
|
|
889
938
|
}
|
|
@@ -920,6 +969,7 @@ function createFreehandStrokeItem(id, pointsWorld, toolKind, style) {
|
|
|
920
969
|
stroke: merged.stroke,
|
|
921
970
|
strokeWidth: merged.strokeWidth,
|
|
922
971
|
...merged.strokeOpacity != null ? { strokeOpacity: merged.strokeOpacity } : {},
|
|
972
|
+
...merged.strokeDash != null ? { strokeDash: merged.strokeDash } : {},
|
|
923
973
|
pathPointsLocal,
|
|
924
974
|
childrenSvg: ""
|
|
925
975
|
});
|
|
@@ -996,7 +1046,7 @@ var init_shape_builders = __esm({
|
|
|
996
1046
|
init_custom_shape();
|
|
997
1047
|
init_text_svg();
|
|
998
1048
|
DEFAULT_STROKE_STYLE = {
|
|
999
|
-
stroke: "#
|
|
1049
|
+
stroke: "#1d1d1d",
|
|
1000
1050
|
strokeWidth: 2
|
|
1001
1051
|
};
|
|
1002
1052
|
TOOL_FREEHAND_DEFAULTS = {
|
|
@@ -3488,33 +3538,416 @@ var DEFAULT_VECTOR_TOOLS = [
|
|
|
3488
3538
|
shortcutHint: "I"
|
|
3489
3539
|
}
|
|
3490
3540
|
];
|
|
3541
|
+
|
|
3542
|
+
// src/react/VectorSelectionInspector.tsx
|
|
3543
|
+
init_text_svg();
|
|
3491
3544
|
var shellLook = {
|
|
3492
3545
|
display: "flex",
|
|
3493
3546
|
flexDirection: "column",
|
|
3494
|
-
gap:
|
|
3495
|
-
minWidth:
|
|
3496
|
-
padding: "
|
|
3497
|
-
borderRadius:
|
|
3498
|
-
border: "1px solid rgba(0,0,0,0.
|
|
3499
|
-
background: "rgba(255,255,255,0.
|
|
3500
|
-
boxShadow: "0 1px 3px rgba(0,0,0,0.08)",
|
|
3547
|
+
gap: 10,
|
|
3548
|
+
minWidth: 200,
|
|
3549
|
+
padding: "12px 14px",
|
|
3550
|
+
borderRadius: 10,
|
|
3551
|
+
border: "1px solid rgba(0,0,0,0.1)",
|
|
3552
|
+
background: "rgba(255,255,255,0.97)",
|
|
3553
|
+
boxShadow: "0 4px 16px rgba(0,0,0,0.06), 0 1px 3px rgba(0,0,0,0.08)",
|
|
3501
3554
|
pointerEvents: "auto"
|
|
3502
3555
|
};
|
|
3503
|
-
var
|
|
3556
|
+
var sectionLabelStyle = {
|
|
3504
3557
|
display: "flex",
|
|
3505
3558
|
flexDirection: "column",
|
|
3506
|
-
gap:
|
|
3559
|
+
gap: 6,
|
|
3507
3560
|
fontSize: 11,
|
|
3508
3561
|
fontWeight: 600,
|
|
3509
|
-
color: "#52525b"
|
|
3562
|
+
color: "#52525b",
|
|
3563
|
+
letterSpacing: "0.02em",
|
|
3564
|
+
textTransform: "uppercase"
|
|
3510
3565
|
};
|
|
3566
|
+
var mixedHintStyle = {
|
|
3567
|
+
fontWeight: 400,
|
|
3568
|
+
color: "#a1a1aa",
|
|
3569
|
+
textTransform: "none",
|
|
3570
|
+
letterSpacing: 0
|
|
3571
|
+
};
|
|
3572
|
+
var TLDRAW_PALETTE = [
|
|
3573
|
+
{ name: "black", hex: "#1d1d1d" },
|
|
3574
|
+
{ name: "grey", hex: "#9fa8b2" },
|
|
3575
|
+
{ name: "light-violet", hex: "#e085f4" },
|
|
3576
|
+
{ name: "violet", hex: "#ae3ec9" },
|
|
3577
|
+
{ name: "blue", hex: "#4263eb" },
|
|
3578
|
+
{ name: "light-blue", hex: "#4dabf7" },
|
|
3579
|
+
{ name: "yellow", hex: "#ffc078" },
|
|
3580
|
+
{ name: "orange", hex: "#f76707" },
|
|
3581
|
+
{ name: "green", hex: "#099268" },
|
|
3582
|
+
{ name: "light-green", hex: "#40c057" },
|
|
3583
|
+
{ name: "light-red", hex: "#ff8787" },
|
|
3584
|
+
{ name: "red", hex: "#e03131" }
|
|
3585
|
+
];
|
|
3511
3586
|
function normalizeHex(stroke) {
|
|
3512
3587
|
if (/^#[0-9A-Fa-f]{6}$/.test(stroke)) return stroke;
|
|
3513
|
-
return "#
|
|
3588
|
+
return "#1d1d1d";
|
|
3589
|
+
}
|
|
3590
|
+
function hexesEqual(a, b) {
|
|
3591
|
+
return a.toLowerCase() === b.toLowerCase();
|
|
3514
3592
|
}
|
|
3515
3593
|
function isStylableKind(tk) {
|
|
3516
3594
|
return tk === "rect" || tk === "ellipse" || tk === "architectural-cloud" || tk === "line" || tk === "arrow" || tk === "draw" || tk === "pencil" || tk === "brush" || tk === "marker" || tk === "text";
|
|
3517
3595
|
}
|
|
3596
|
+
var FONT_SIZE_PRESETS = [
|
|
3597
|
+
{ label: "S", size: 14 },
|
|
3598
|
+
{ label: "M", size: 18 },
|
|
3599
|
+
{ label: "L", size: 28 },
|
|
3600
|
+
{ label: "XL", size: 44 }
|
|
3601
|
+
];
|
|
3602
|
+
function ColorSwatch({ color, selected, onSelect }) {
|
|
3603
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3604
|
+
"button",
|
|
3605
|
+
{
|
|
3606
|
+
type: "button",
|
|
3607
|
+
"aria-label": color.name,
|
|
3608
|
+
"aria-pressed": selected,
|
|
3609
|
+
onClick: onSelect,
|
|
3610
|
+
onPointerDown: (e) => {
|
|
3611
|
+
if (e.pointerType === "mouse") e.preventDefault();
|
|
3612
|
+
},
|
|
3613
|
+
style: {
|
|
3614
|
+
width: 24,
|
|
3615
|
+
height: 24,
|
|
3616
|
+
padding: 0,
|
|
3617
|
+
borderRadius: "50%",
|
|
3618
|
+
border: selected ? "2px solid #18181b" : "1px solid rgba(0,0,0,0.12)",
|
|
3619
|
+
background: color.hex,
|
|
3620
|
+
cursor: "pointer",
|
|
3621
|
+
outline: "none",
|
|
3622
|
+
boxShadow: selected ? "0 0 0 2px rgba(255,255,255,0.95) inset" : "none",
|
|
3623
|
+
transition: "transform 0.08s ease",
|
|
3624
|
+
transform: selected ? "scale(1.08)" : "scale(1)",
|
|
3625
|
+
WebkitTapHighlightColor: "transparent"
|
|
3626
|
+
}
|
|
3627
|
+
}
|
|
3628
|
+
);
|
|
3629
|
+
}
|
|
3630
|
+
function ColorPalette({ value, onChange }) {
|
|
3631
|
+
const [showCustom, setShowCustom] = react.useState(false);
|
|
3632
|
+
const normalized = normalizeHex(value);
|
|
3633
|
+
const inPalette = TLDRAW_PALETTE.some((c) => hexesEqual(c.hex, normalized));
|
|
3634
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3635
|
+
"div",
|
|
3636
|
+
{
|
|
3637
|
+
style: {
|
|
3638
|
+
display: "grid",
|
|
3639
|
+
gridTemplateColumns: "repeat(6, 24px)",
|
|
3640
|
+
gap: 6,
|
|
3641
|
+
rowGap: 6,
|
|
3642
|
+
alignItems: "center"
|
|
3643
|
+
},
|
|
3644
|
+
children: [
|
|
3645
|
+
TLDRAW_PALETTE.map((c) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3646
|
+
ColorSwatch,
|
|
3647
|
+
{
|
|
3648
|
+
color: c,
|
|
3649
|
+
selected: hexesEqual(c.hex, normalized),
|
|
3650
|
+
onSelect: () => onChange(c.hex)
|
|
3651
|
+
},
|
|
3652
|
+
c.name
|
|
3653
|
+
)),
|
|
3654
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3655
|
+
"button",
|
|
3656
|
+
{
|
|
3657
|
+
type: "button",
|
|
3658
|
+
"aria-label": "Cor personalizada",
|
|
3659
|
+
"aria-pressed": showCustom || !inPalette,
|
|
3660
|
+
onClick: () => setShowCustom((v) => !v),
|
|
3661
|
+
onPointerDown: (e) => {
|
|
3662
|
+
if (e.pointerType === "mouse") e.preventDefault();
|
|
3663
|
+
},
|
|
3664
|
+
style: {
|
|
3665
|
+
width: 24,
|
|
3666
|
+
height: 24,
|
|
3667
|
+
padding: 0,
|
|
3668
|
+
borderRadius: "50%",
|
|
3669
|
+
border: !inPalette || showCustom ? "2px solid #18181b" : "1px solid rgba(0,0,0,0.12)",
|
|
3670
|
+
background: "conic-gradient(from 0deg, #ff5757, #ffbd59, #59ff7e, #59ddff, #b259ff, #ff59c1, #ff5757)",
|
|
3671
|
+
cursor: "pointer",
|
|
3672
|
+
outline: "none",
|
|
3673
|
+
WebkitTapHighlightColor: "transparent"
|
|
3674
|
+
}
|
|
3675
|
+
}
|
|
3676
|
+
),
|
|
3677
|
+
showCustom || !inPalette ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3678
|
+
"label",
|
|
3679
|
+
{
|
|
3680
|
+
style: {
|
|
3681
|
+
gridColumn: "1 / -1",
|
|
3682
|
+
display: "flex",
|
|
3683
|
+
alignItems: "center",
|
|
3684
|
+
gap: 6,
|
|
3685
|
+
fontSize: 11,
|
|
3686
|
+
fontWeight: 500,
|
|
3687
|
+
color: "#71717a",
|
|
3688
|
+
textTransform: "none",
|
|
3689
|
+
letterSpacing: 0
|
|
3690
|
+
},
|
|
3691
|
+
children: [
|
|
3692
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3693
|
+
"input",
|
|
3694
|
+
{
|
|
3695
|
+
type: "color",
|
|
3696
|
+
value: normalized,
|
|
3697
|
+
onChange: (e) => onChange(e.target.value),
|
|
3698
|
+
style: {
|
|
3699
|
+
width: 28,
|
|
3700
|
+
height: 28,
|
|
3701
|
+
padding: 0,
|
|
3702
|
+
border: "1px solid rgba(0,0,0,0.12)",
|
|
3703
|
+
borderRadius: 6,
|
|
3704
|
+
cursor: "pointer",
|
|
3705
|
+
background: "transparent"
|
|
3706
|
+
}
|
|
3707
|
+
}
|
|
3708
|
+
),
|
|
3709
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontVariantNumeric: "tabular-nums" }, children: normalized.toUpperCase() })
|
|
3710
|
+
]
|
|
3711
|
+
}
|
|
3712
|
+
) : null
|
|
3713
|
+
]
|
|
3714
|
+
}
|
|
3715
|
+
);
|
|
3716
|
+
}
|
|
3717
|
+
function DashTabs({ value, onChange }) {
|
|
3718
|
+
const tabs = [
|
|
3719
|
+
{ id: "solid", label: "Cont\xEDnuo" },
|
|
3720
|
+
{ id: "dashed", label: "Tracejado" }
|
|
3721
|
+
];
|
|
3722
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3723
|
+
"div",
|
|
3724
|
+
{
|
|
3725
|
+
role: "radiogroup",
|
|
3726
|
+
"aria-label": "Estilo do tra\xE7o",
|
|
3727
|
+
style: {
|
|
3728
|
+
display: "flex",
|
|
3729
|
+
background: "rgba(24,24,27,0.06)",
|
|
3730
|
+
borderRadius: 7,
|
|
3731
|
+
padding: 2,
|
|
3732
|
+
gap: 2
|
|
3733
|
+
},
|
|
3734
|
+
children: tabs.map((t) => {
|
|
3735
|
+
const selected = value === t.id;
|
|
3736
|
+
return (
|
|
3737
|
+
// biome-ignore lint/a11y/useSemanticElements: styled segmented control needs button, not input[type=radio]
|
|
3738
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3739
|
+
"button",
|
|
3740
|
+
{
|
|
3741
|
+
type: "button",
|
|
3742
|
+
role: "radio",
|
|
3743
|
+
"aria-checked": selected,
|
|
3744
|
+
onClick: () => onChange(t.id),
|
|
3745
|
+
onPointerDown: (e) => {
|
|
3746
|
+
if (e.pointerType === "mouse") e.preventDefault();
|
|
3747
|
+
},
|
|
3748
|
+
style: {
|
|
3749
|
+
flex: 1,
|
|
3750
|
+
display: "inline-flex",
|
|
3751
|
+
alignItems: "center",
|
|
3752
|
+
justifyContent: "center",
|
|
3753
|
+
padding: "5px 8px",
|
|
3754
|
+
fontSize: 11,
|
|
3755
|
+
fontWeight: 600,
|
|
3756
|
+
color: selected ? "#18181b" : "#71717a",
|
|
3757
|
+
background: selected ? "#fff" : "transparent",
|
|
3758
|
+
borderRadius: 5,
|
|
3759
|
+
border: "none",
|
|
3760
|
+
cursor: "pointer",
|
|
3761
|
+
boxShadow: selected ? "0 1px 2px rgba(0,0,0,0.1)" : "none",
|
|
3762
|
+
outline: "none",
|
|
3763
|
+
WebkitTapHighlightColor: "transparent"
|
|
3764
|
+
},
|
|
3765
|
+
children: [
|
|
3766
|
+
/* @__PURE__ */ jsxRuntime.jsx(DashTabSwatch, { dashed: t.id === "dashed" }),
|
|
3767
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { marginLeft: 6 }, children: t.label })
|
|
3768
|
+
]
|
|
3769
|
+
},
|
|
3770
|
+
t.id
|
|
3771
|
+
)
|
|
3772
|
+
);
|
|
3773
|
+
})
|
|
3774
|
+
}
|
|
3775
|
+
);
|
|
3776
|
+
}
|
|
3777
|
+
function DashTabSwatch({ dashed }) {
|
|
3778
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3779
|
+
"svg",
|
|
3780
|
+
{
|
|
3781
|
+
width: 26,
|
|
3782
|
+
height: 6,
|
|
3783
|
+
"aria-hidden": true,
|
|
3784
|
+
style: { flexShrink: 0, display: "block" },
|
|
3785
|
+
children: [
|
|
3786
|
+
/* @__PURE__ */ jsxRuntime.jsx("title", { children: dashed ? "dashed" : "solid" }),
|
|
3787
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3788
|
+
"line",
|
|
3789
|
+
{
|
|
3790
|
+
x1: 1,
|
|
3791
|
+
y1: 3,
|
|
3792
|
+
x2: 25,
|
|
3793
|
+
y2: 3,
|
|
3794
|
+
stroke: "currentColor",
|
|
3795
|
+
strokeWidth: 2,
|
|
3796
|
+
strokeLinecap: "round",
|
|
3797
|
+
strokeDasharray: dashed ? "4 3" : void 0
|
|
3798
|
+
}
|
|
3799
|
+
)
|
|
3800
|
+
]
|
|
3801
|
+
}
|
|
3802
|
+
);
|
|
3803
|
+
}
|
|
3804
|
+
function FontSizeTabs({ value, onChange }) {
|
|
3805
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3806
|
+
"div",
|
|
3807
|
+
{
|
|
3808
|
+
role: "radiogroup",
|
|
3809
|
+
"aria-label": "Tamanho do texto",
|
|
3810
|
+
style: {
|
|
3811
|
+
display: "flex",
|
|
3812
|
+
background: "rgba(24,24,27,0.06)",
|
|
3813
|
+
borderRadius: 7,
|
|
3814
|
+
padding: 2,
|
|
3815
|
+
gap: 2
|
|
3816
|
+
},
|
|
3817
|
+
children: FONT_SIZE_PRESETS.map((p) => {
|
|
3818
|
+
const selected = Math.abs(value - p.size) < 0.5;
|
|
3819
|
+
return (
|
|
3820
|
+
// biome-ignore lint/a11y/useSemanticElements: styled segmented control needs button, not input[type=radio]
|
|
3821
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3822
|
+
"button",
|
|
3823
|
+
{
|
|
3824
|
+
type: "button",
|
|
3825
|
+
role: "radio",
|
|
3826
|
+
"aria-checked": selected,
|
|
3827
|
+
"aria-label": `${p.label} (${p.size}px)`,
|
|
3828
|
+
onClick: () => onChange(p.size),
|
|
3829
|
+
onPointerDown: (e) => {
|
|
3830
|
+
if (e.pointerType === "mouse") e.preventDefault();
|
|
3831
|
+
},
|
|
3832
|
+
style: {
|
|
3833
|
+
flex: 1,
|
|
3834
|
+
padding: "5px 0",
|
|
3835
|
+
fontSize: p.label === "XL" ? 14 : p.label === "L" ? 13 : 12,
|
|
3836
|
+
fontWeight: 700,
|
|
3837
|
+
color: selected ? "#18181b" : "#71717a",
|
|
3838
|
+
background: selected ? "#fff" : "transparent",
|
|
3839
|
+
borderRadius: 5,
|
|
3840
|
+
border: "none",
|
|
3841
|
+
cursor: "pointer",
|
|
3842
|
+
boxShadow: selected ? "0 1px 2px rgba(0,0,0,0.1)" : "none",
|
|
3843
|
+
outline: "none",
|
|
3844
|
+
WebkitTapHighlightColor: "transparent",
|
|
3845
|
+
lineHeight: 1
|
|
3846
|
+
},
|
|
3847
|
+
children: p.label
|
|
3848
|
+
},
|
|
3849
|
+
p.label
|
|
3850
|
+
)
|
|
3851
|
+
);
|
|
3852
|
+
})
|
|
3853
|
+
}
|
|
3854
|
+
);
|
|
3855
|
+
}
|
|
3856
|
+
function viewModelFromActiveTool(activeToolStyle) {
|
|
3857
|
+
const hex = normalizeHex(activeToolStyle.stroke);
|
|
3858
|
+
const strokeWidth = activeToolStyle.strokeWidth;
|
|
3859
|
+
const strokeOpacity = activeToolStyle.strokeOpacity ?? 1;
|
|
3860
|
+
const strokeDash = activeToolStyle.strokeDash === "dashed" ? "dashed" : "solid";
|
|
3861
|
+
const textFontSize = activeToolStyle.textFontSize ?? DEFAULT_TEXT_FONT_SIZE;
|
|
3862
|
+
const isText = activeToolStyle.toolKind === "text";
|
|
3863
|
+
const isDraw = activeToolStyle.toolKind === "draw";
|
|
3864
|
+
const isMarker = activeToolStyle.toolKind === "marker";
|
|
3865
|
+
const current = {
|
|
3866
|
+
stroke: hex,
|
|
3867
|
+
strokeWidth,
|
|
3868
|
+
...activeToolStyle.strokeOpacity != null ? { strokeOpacity: activeToolStyle.strokeOpacity } : {},
|
|
3869
|
+
...activeToolStyle.strokeDash != null ? { strokeDash: activeToolStyle.strokeDash } : {},
|
|
3870
|
+
...isText ? { textFontSize } : {}
|
|
3871
|
+
};
|
|
3872
|
+
return {
|
|
3873
|
+
label: activeToolStyle.label ?? "Estilo da ferramenta",
|
|
3874
|
+
count: 0,
|
|
3875
|
+
hex,
|
|
3876
|
+
strokeWidth,
|
|
3877
|
+
strokeOpacity,
|
|
3878
|
+
strokeDash,
|
|
3879
|
+
textFontSize,
|
|
3880
|
+
showStrokeWidth: !isText,
|
|
3881
|
+
showDash: isDraw,
|
|
3882
|
+
showFontSize: isText,
|
|
3883
|
+
showMarkerOpacity: isMarker,
|
|
3884
|
+
mixedStroke: false,
|
|
3885
|
+
mixedWidth: false,
|
|
3886
|
+
mixedDash: false,
|
|
3887
|
+
mixedFontSize: false,
|
|
3888
|
+
mixedOpacity: false,
|
|
3889
|
+
current
|
|
3890
|
+
};
|
|
3891
|
+
}
|
|
3892
|
+
function viewModelFromSelection(stylable) {
|
|
3893
|
+
const first = stylable[0];
|
|
3894
|
+
if (!first) return null;
|
|
3895
|
+
const hex = normalizeHex(first.stroke ?? "#1d1d1d");
|
|
3896
|
+
const strokeWidth = first.strokeWidth ?? 2;
|
|
3897
|
+
const allSameStroke = stylable.every(
|
|
3898
|
+
(it) => (it.stroke ?? "#1d1d1d") === (first.stroke ?? "#1d1d1d")
|
|
3899
|
+
);
|
|
3900
|
+
const allSameWidth = stylable.every(
|
|
3901
|
+
(it) => (it.strokeWidth ?? 2) === (first.strokeWidth ?? 2)
|
|
3902
|
+
);
|
|
3903
|
+
const draws = stylable.filter(
|
|
3904
|
+
(it) => it.toolKind === "draw" || it.toolKind === "pencil"
|
|
3905
|
+
);
|
|
3906
|
+
const showDash = draws.length > 0;
|
|
3907
|
+
const firstDraw = draws[0];
|
|
3908
|
+
const strokeDash = firstDraw?.strokeDash === "dashed" ? "dashed" : "solid";
|
|
3909
|
+
const allSameDash = draws.length === 0 || draws.every((it) => (it.strokeDash ?? "solid") === strokeDash);
|
|
3910
|
+
const markers = stylable.filter((it) => it.toolKind === "marker");
|
|
3911
|
+
const showMarkerOpacity = markers.length > 0;
|
|
3912
|
+
const firstMarker = markers[0];
|
|
3913
|
+
const strokeOpacity = firstMarker?.strokeOpacity ?? 1;
|
|
3914
|
+
const allSameOpacity = markers.length === 0 || markers.every(
|
|
3915
|
+
(it) => (it.strokeOpacity ?? 1) === (firstMarker?.strokeOpacity ?? 1)
|
|
3916
|
+
);
|
|
3917
|
+
const texts = stylable.filter((it) => it.toolKind === "text");
|
|
3918
|
+
const showFontSize = texts.length > 0;
|
|
3919
|
+
const firstText = texts[0];
|
|
3920
|
+
const textFontSize = firstText?.textFontSize ?? DEFAULT_TEXT_FONT_SIZE;
|
|
3921
|
+
const allSameFontSize = texts.length === 0 || texts.every(
|
|
3922
|
+
(it) => (it.textFontSize ?? DEFAULT_TEXT_FONT_SIZE) === textFontSize
|
|
3923
|
+
);
|
|
3924
|
+
const current = {
|
|
3925
|
+
stroke: hex,
|
|
3926
|
+
strokeWidth,
|
|
3927
|
+
...showMarkerOpacity ? { strokeOpacity } : {},
|
|
3928
|
+
...showDash ? { strokeDash } : {},
|
|
3929
|
+
...showFontSize ? { textFontSize } : {}
|
|
3930
|
+
};
|
|
3931
|
+
return {
|
|
3932
|
+
label: "Estilo da sele\xE7\xE3o",
|
|
3933
|
+
count: stylable.length,
|
|
3934
|
+
hex,
|
|
3935
|
+
strokeWidth,
|
|
3936
|
+
strokeOpacity,
|
|
3937
|
+
strokeDash,
|
|
3938
|
+
textFontSize,
|
|
3939
|
+
showStrokeWidth: true,
|
|
3940
|
+
showDash,
|
|
3941
|
+
showFontSize,
|
|
3942
|
+
showMarkerOpacity,
|
|
3943
|
+
mixedStroke: !allSameStroke,
|
|
3944
|
+
mixedWidth: !allSameWidth,
|
|
3945
|
+
mixedDash: !allSameDash,
|
|
3946
|
+
mixedFontSize: !allSameFontSize,
|
|
3947
|
+
mixedOpacity: !allSameOpacity,
|
|
3948
|
+
current
|
|
3949
|
+
};
|
|
3950
|
+
}
|
|
3518
3951
|
function VectorSelectionInspector({
|
|
3519
3952
|
items: itemsProp,
|
|
3520
3953
|
activeToolStyle: activeToolStyleProp,
|
|
@@ -3530,175 +3963,93 @@ function VectorSelectionInspector({
|
|
|
3530
3963
|
const activeToolStyle = activeToolStyleProp === void 0 ? ctx?.activeToolStyle ?? null : activeToolStyleProp;
|
|
3531
3964
|
const onChange = onChangeProp ?? ctx?.onSelectionStyleChange ?? null;
|
|
3532
3965
|
if (!onChange) return null;
|
|
3966
|
+
let vm = null;
|
|
3967
|
+
if (activeToolStyle) {
|
|
3968
|
+
vm = viewModelFromActiveTool(activeToolStyle);
|
|
3969
|
+
} else {
|
|
3970
|
+
const stylable = items.filter(
|
|
3971
|
+
(it) => !it.locked && it.toolKind && isStylableKind(it.toolKind)
|
|
3972
|
+
);
|
|
3973
|
+
if (stylable.length === 0) return null;
|
|
3974
|
+
vm = viewModelFromSelection(stylable);
|
|
3975
|
+
}
|
|
3976
|
+
if (!vm) return null;
|
|
3977
|
+
const apply = (changes) => onChange({ ...vm.current, ...changes });
|
|
3533
3978
|
const shell = {
|
|
3534
3979
|
...getBoardPositionStyle(position, inset, zIndex),
|
|
3535
3980
|
...shellLook,
|
|
3536
3981
|
...style
|
|
3537
3982
|
};
|
|
3538
|
-
|
|
3539
|
-
const stroke2 = activeToolStyle.stroke;
|
|
3540
|
-
const strokeWidth2 = activeToolStyle.strokeWidth;
|
|
3541
|
-
const hex2 = normalizeHex(stroke2);
|
|
3542
|
-
const showMarkerOpacity2 = activeToolStyle.toolKind === "marker";
|
|
3543
|
-
const opacityPct2 = Math.round((activeToolStyle.strokeOpacity ?? 1) * 100);
|
|
3544
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3545
|
-
"section",
|
|
3546
|
-
{
|
|
3547
|
-
"data-slot": "vector-selection-inspector",
|
|
3548
|
-
"data-position": position,
|
|
3549
|
-
className,
|
|
3550
|
-
"aria-label": activeToolStyle.label ?? "Estilo da ferramenta",
|
|
3551
|
-
style: shell,
|
|
3552
|
-
children: [
|
|
3553
|
-
/* @__PURE__ */ jsxRuntime.jsxs("label", { style: labelStyle2, children: [
|
|
3554
|
-
"Cor",
|
|
3555
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3556
|
-
"input",
|
|
3557
|
-
{
|
|
3558
|
-
type: "color",
|
|
3559
|
-
value: hex2,
|
|
3560
|
-
onChange: (e) => onChange({
|
|
3561
|
-
stroke: e.target.value,
|
|
3562
|
-
strokeWidth: strokeWidth2,
|
|
3563
|
-
...activeToolStyle.strokeOpacity != null ? { strokeOpacity: activeToolStyle.strokeOpacity } : {}
|
|
3564
|
-
}),
|
|
3565
|
-
style: {
|
|
3566
|
-
width: "100%",
|
|
3567
|
-
height: 32,
|
|
3568
|
-
padding: 0,
|
|
3569
|
-
border: "none",
|
|
3570
|
-
cursor: "pointer",
|
|
3571
|
-
background: "transparent"
|
|
3572
|
-
}
|
|
3573
|
-
}
|
|
3574
|
-
)
|
|
3575
|
-
] }),
|
|
3576
|
-
/* @__PURE__ */ jsxRuntime.jsxs("label", { style: labelStyle2, children: [
|
|
3577
|
-
"Grossura",
|
|
3578
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3579
|
-
"input",
|
|
3580
|
-
{
|
|
3581
|
-
type: "range",
|
|
3582
|
-
min: 1,
|
|
3583
|
-
max: 48,
|
|
3584
|
-
value: strokeWidth2,
|
|
3585
|
-
onChange: (e) => onChange({
|
|
3586
|
-
stroke: hex2,
|
|
3587
|
-
strokeWidth: Number(e.target.value),
|
|
3588
|
-
...activeToolStyle.strokeOpacity != null ? { strokeOpacity: activeToolStyle.strokeOpacity } : {}
|
|
3589
|
-
})
|
|
3590
|
-
}
|
|
3591
|
-
)
|
|
3592
|
-
] }),
|
|
3593
|
-
showMarkerOpacity2 && /* @__PURE__ */ jsxRuntime.jsxs("label", { style: labelStyle2, children: [
|
|
3594
|
-
"Opacidade (marcador)",
|
|
3595
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3596
|
-
"input",
|
|
3597
|
-
{
|
|
3598
|
-
type: "range",
|
|
3599
|
-
min: 10,
|
|
3600
|
-
max: 100,
|
|
3601
|
-
value: opacityPct2,
|
|
3602
|
-
onChange: (e) => {
|
|
3603
|
-
const v = Number(e.target.value) / 100;
|
|
3604
|
-
onChange({
|
|
3605
|
-
stroke: hex2,
|
|
3606
|
-
strokeWidth: strokeWidth2,
|
|
3607
|
-
strokeOpacity: v
|
|
3608
|
-
});
|
|
3609
|
-
}
|
|
3610
|
-
}
|
|
3611
|
-
),
|
|
3612
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontWeight: 500, color: "#71717a" }, children: [
|
|
3613
|
-
opacityPct2,
|
|
3614
|
-
"%"
|
|
3615
|
-
] })
|
|
3616
|
-
] })
|
|
3617
|
-
]
|
|
3618
|
-
}
|
|
3619
|
-
);
|
|
3620
|
-
}
|
|
3621
|
-
const stylable = items.filter(
|
|
3622
|
-
(it) => !it.locked && it.toolKind && isStylableKind(it.toolKind)
|
|
3623
|
-
);
|
|
3624
|
-
if (stylable.length === 0) return null;
|
|
3625
|
-
const first = stylable[0];
|
|
3626
|
-
if (!first) return null;
|
|
3627
|
-
const allSameStroke = stylable.every(
|
|
3628
|
-
(it) => (it.stroke ?? "#2563eb") === (first.stroke ?? "#2563eb")
|
|
3629
|
-
);
|
|
3630
|
-
const allSameWidth = stylable.every(
|
|
3631
|
-
(it) => (it.strokeWidth ?? 2) === (first.strokeWidth ?? 2)
|
|
3632
|
-
);
|
|
3633
|
-
const stroke = first.stroke ?? "#2563eb";
|
|
3634
|
-
const strokeWidth = first.strokeWidth ?? 2;
|
|
3635
|
-
const hex = normalizeHex(stroke);
|
|
3636
|
-
const markers = stylable.filter((it) => it.toolKind === "marker");
|
|
3637
|
-
const showMarkerOpacity = markers.length > 0;
|
|
3638
|
-
const firstMarker = markers[0];
|
|
3639
|
-
const allSameMarkerOpacity = markers.length > 0 && markers.every(
|
|
3640
|
-
(it) => (it.strokeOpacity ?? 1) === (firstMarker?.strokeOpacity ?? 1)
|
|
3641
|
-
);
|
|
3642
|
-
const opacityPct = firstMarker ? Math.round((firstMarker.strokeOpacity ?? 1) * 100) : 100;
|
|
3983
|
+
const opacityPct = Math.round(vm.strokeOpacity * 100);
|
|
3643
3984
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3644
3985
|
"section",
|
|
3645
3986
|
{
|
|
3646
3987
|
"data-slot": "vector-selection-inspector",
|
|
3647
3988
|
"data-position": position,
|
|
3648
3989
|
className,
|
|
3649
|
-
"aria-label":
|
|
3990
|
+
"aria-label": vm.label,
|
|
3650
3991
|
style: shell,
|
|
3651
3992
|
children: [
|
|
3652
|
-
|
|
3653
|
-
|
|
3993
|
+
vm.count > 1 ? /* @__PURE__ */ jsxRuntime.jsxs("p", { style: { margin: 0, fontSize: 11, color: "#71717a" }, children: [
|
|
3994
|
+
vm.count,
|
|
3654
3995
|
" objetos selecionados"
|
|
3655
|
-
] }),
|
|
3656
|
-
/* @__PURE__ */ jsxRuntime.jsxs("
|
|
3657
|
-
"
|
|
3658
|
-
|
|
3659
|
-
" "
|
|
3660
|
-
"(valores misturados \u2014 novo valor aplica a todos)"
|
|
3996
|
+
] }) : null,
|
|
3997
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { role: "group", "aria-label": "Cor", style: sectionLabelStyle, children: [
|
|
3998
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
3999
|
+
"Cor",
|
|
4000
|
+
vm.mixedStroke ? /* @__PURE__ */ jsxRuntime.jsx("span", { style: mixedHintStyle, children: " (valores misturados)" }) : null
|
|
3661
4001
|
] }),
|
|
3662
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3663
|
-
"input",
|
|
3664
|
-
{
|
|
3665
|
-
type: "color",
|
|
3666
|
-
value: hex,
|
|
3667
|
-
onChange: (e) => onChange({
|
|
3668
|
-
stroke: e.target.value,
|
|
3669
|
-
strokeWidth
|
|
3670
|
-
}),
|
|
3671
|
-
style: {
|
|
3672
|
-
width: "100%",
|
|
3673
|
-
height: 32,
|
|
3674
|
-
padding: 0,
|
|
3675
|
-
border: "none",
|
|
3676
|
-
cursor: "pointer",
|
|
3677
|
-
background: "transparent"
|
|
3678
|
-
}
|
|
3679
|
-
}
|
|
3680
|
-
)
|
|
4002
|
+
/* @__PURE__ */ jsxRuntime.jsx(ColorPalette, { value: vm.hex, onChange: (h) => apply({ stroke: h }) })
|
|
3681
4003
|
] }),
|
|
3682
|
-
/* @__PURE__ */ jsxRuntime.jsxs("label", { style:
|
|
4004
|
+
vm.showStrokeWidth ? /* @__PURE__ */ jsxRuntime.jsxs("label", { style: sectionLabelStyle, children: [
|
|
3683
4005
|
"Grossura",
|
|
3684
|
-
|
|
4006
|
+
vm.mixedWidth ? /* @__PURE__ */ jsxRuntime.jsx("span", { style: mixedHintStyle, children: " (misturado)" }) : null,
|
|
3685
4007
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3686
4008
|
"input",
|
|
3687
4009
|
{
|
|
3688
4010
|
type: "range",
|
|
3689
4011
|
min: 1,
|
|
3690
4012
|
max: 48,
|
|
3691
|
-
value: strokeWidth,
|
|
3692
|
-
onChange: (e) =>
|
|
3693
|
-
stroke: hex,
|
|
3694
|
-
strokeWidth: Number(e.target.value)
|
|
3695
|
-
})
|
|
4013
|
+
value: vm.strokeWidth,
|
|
4014
|
+
onChange: (e) => apply({ strokeWidth: Number(e.target.value) })
|
|
3696
4015
|
}
|
|
3697
4016
|
)
|
|
3698
|
-
] }),
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
4017
|
+
] }) : null,
|
|
4018
|
+
vm.showDash ? (
|
|
4019
|
+
// biome-ignore lint/a11y/useSemanticElements: fieldset would impose default browser styling that breaks the inspector layout
|
|
4020
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { role: "group", "aria-label": "Tra\xE7o", style: sectionLabelStyle, children: [
|
|
4021
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
4022
|
+
"Tra\xE7o",
|
|
4023
|
+
vm.mixedDash ? /* @__PURE__ */ jsxRuntime.jsx("span", { style: mixedHintStyle, children: " (misturado)" }) : null
|
|
4024
|
+
] }),
|
|
4025
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4026
|
+
DashTabs,
|
|
4027
|
+
{
|
|
4028
|
+
value: vm.strokeDash,
|
|
4029
|
+
onChange: (next) => apply({ strokeDash: next })
|
|
4030
|
+
}
|
|
4031
|
+
)
|
|
4032
|
+
] })
|
|
4033
|
+
) : null,
|
|
4034
|
+
vm.showFontSize ? (
|
|
4035
|
+
// biome-ignore lint/a11y/useSemanticElements: fieldset would impose default browser styling that breaks the inspector layout
|
|
4036
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { role: "group", "aria-label": "Tamanho", style: sectionLabelStyle, children: [
|
|
4037
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
4038
|
+
"Tamanho",
|
|
4039
|
+
vm.mixedFontSize ? /* @__PURE__ */ jsxRuntime.jsx("span", { style: mixedHintStyle, children: " (misturado)" }) : null
|
|
4040
|
+
] }),
|
|
4041
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4042
|
+
FontSizeTabs,
|
|
4043
|
+
{
|
|
4044
|
+
value: vm.textFontSize,
|
|
4045
|
+
onChange: (size) => apply({ textFontSize: size })
|
|
4046
|
+
}
|
|
4047
|
+
)
|
|
4048
|
+
] })
|
|
4049
|
+
) : null,
|
|
4050
|
+
vm.showMarkerOpacity ? /* @__PURE__ */ jsxRuntime.jsxs("label", { style: sectionLabelStyle, children: [
|
|
4051
|
+
"Opacidade",
|
|
4052
|
+
vm.mixedOpacity ? /* @__PURE__ */ jsxRuntime.jsx("span", { style: mixedHintStyle, children: " (misturado)" }) : null,
|
|
3702
4053
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3703
4054
|
"input",
|
|
3704
4055
|
{
|
|
@@ -3706,21 +4057,14 @@ function VectorSelectionInspector({
|
|
|
3706
4057
|
min: 10,
|
|
3707
4058
|
max: 100,
|
|
3708
4059
|
value: opacityPct,
|
|
3709
|
-
onChange: (e) => {
|
|
3710
|
-
const v = Number(e.target.value) / 100;
|
|
3711
|
-
onChange({
|
|
3712
|
-
stroke: hex,
|
|
3713
|
-
strokeWidth,
|
|
3714
|
-
strokeOpacity: v
|
|
3715
|
-
});
|
|
3716
|
-
}
|
|
4060
|
+
onChange: (e) => apply({ strokeOpacity: Number(e.target.value) / 100 })
|
|
3717
4061
|
}
|
|
3718
4062
|
),
|
|
3719
4063
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontWeight: 500, color: "#71717a" }, children: [
|
|
3720
4064
|
opacityPct,
|
|
3721
4065
|
"%"
|
|
3722
4066
|
] })
|
|
3723
|
-
] })
|
|
4067
|
+
] }) : null
|
|
3724
4068
|
]
|
|
3725
4069
|
}
|
|
3726
4070
|
);
|
|
@@ -4199,6 +4543,24 @@ function splitToolbarTools(tools, overflowIds) {
|
|
|
4199
4543
|
const overflow = overflowIds.map((id) => tools.find((t) => t.id === id)).filter((t) => Boolean(t));
|
|
4200
4544
|
return { primary, overflow };
|
|
4201
4545
|
}
|
|
4546
|
+
function usePromotedOverflowTool({
|
|
4547
|
+
overflowTools,
|
|
4548
|
+
selectedId,
|
|
4549
|
+
initialPromotedId
|
|
4550
|
+
}) {
|
|
4551
|
+
const [lastOverflowToolId, setLastOverflowToolId] = react.useState(() => {
|
|
4552
|
+
if (initialPromotedId == null) return null;
|
|
4553
|
+
return overflowTools.some((t) => t.id === initialPromotedId) ? initialPromotedId : null;
|
|
4554
|
+
});
|
|
4555
|
+
react.useEffect(() => {
|
|
4556
|
+
if (overflowTools.some((t) => t.id === selectedId)) {
|
|
4557
|
+
setLastOverflowToolId(selectedId);
|
|
4558
|
+
}
|
|
4559
|
+
}, [selectedId, overflowTools]);
|
|
4560
|
+
const promotedTool = lastOverflowToolId ? overflowTools.find((t) => t.id === lastOverflowToolId) : void 0;
|
|
4561
|
+
const remainingOverflowTools = promotedTool ? overflowTools.filter((t) => t.id !== promotedTool.id) : overflowTools;
|
|
4562
|
+
return { promotedTool, remainingOverflowTools };
|
|
4563
|
+
}
|
|
4202
4564
|
var icOverflow = { size: 18, strokeWidth: 2 };
|
|
4203
4565
|
function useOverflowDropdown() {
|
|
4204
4566
|
const [open, setOpen] = react.useState(false);
|
|
@@ -4733,6 +5095,15 @@ function VectorToolbarComponent({
|
|
|
4733
5095
|
const pluginContext = react.useContext(CanvuPluginContext);
|
|
4734
5096
|
const runtimeTools = pluginContext?.resolvedTools;
|
|
4735
5097
|
const resolvedTools = tools ?? runtimeTools ?? DEFAULT_VECTOR_TOOLS;
|
|
5098
|
+
const { primary: primaryTools, overflow: overflowTools } = splitToolbarTools(
|
|
5099
|
+
resolvedTools,
|
|
5100
|
+
overflowToolIds
|
|
5101
|
+
);
|
|
5102
|
+
const { promotedTool, remainingOverflowTools } = usePromotedOverflowTool({
|
|
5103
|
+
overflowTools,
|
|
5104
|
+
selectedId: value,
|
|
5105
|
+
initialPromotedId: overflowToolIds[0] ?? null
|
|
5106
|
+
});
|
|
4736
5107
|
if (typeof children === "function") {
|
|
4737
5108
|
const ctx = {
|
|
4738
5109
|
tools: resolvedTools,
|
|
@@ -4777,11 +5148,8 @@ function VectorToolbarComponent({
|
|
|
4777
5148
|
)
|
|
4778
5149
|
] });
|
|
4779
5150
|
}
|
|
4780
|
-
const { primary: primaryTools, overflow: overflowTools } = splitToolbarTools(
|
|
4781
|
-
resolvedTools,
|
|
4782
|
-
overflowToolIds
|
|
4783
|
-
);
|
|
4784
5151
|
const showOverflowMenu = overflowTools.length > 0;
|
|
5152
|
+
const showOverflowDropdown = remainingOverflowTools.length > 0;
|
|
4785
5153
|
const inlineCtx = {
|
|
4786
5154
|
selectedId: value,
|
|
4787
5155
|
selectTool: onChange,
|
|
@@ -4832,6 +5200,7 @@ function VectorToolbarComponent({
|
|
|
4832
5200
|
/* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, style: toolLockDividerStyle })
|
|
4833
5201
|
] }) : null,
|
|
4834
5202
|
primaryTools.map((tool) => renderInlineToolButton(tool, inlineCtx)),
|
|
5203
|
+
promotedTool ? renderInlineToolButton(promotedTool, inlineCtx) : null,
|
|
4835
5204
|
showOverflowMenu && orientation === "horizontal" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4836
5205
|
"span",
|
|
4837
5206
|
{
|
|
@@ -4840,10 +5209,10 @@ function VectorToolbarComponent({
|
|
|
4840
5209
|
style: overflowSpacerStyle
|
|
4841
5210
|
}
|
|
4842
5211
|
) : null,
|
|
4843
|
-
|
|
5212
|
+
showOverflowDropdown ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4844
5213
|
ToolbarOverflowMenu,
|
|
4845
5214
|
{
|
|
4846
|
-
tools:
|
|
5215
|
+
tools: remainingOverflowTools,
|
|
4847
5216
|
selectedId: value,
|
|
4848
5217
|
onSelect: onChange,
|
|
4849
5218
|
density,
|
|
@@ -6494,6 +6863,7 @@ var VectorScene = class {
|
|
|
6494
6863
|
|
|
6495
6864
|
// src/react/VectorViewport.tsx
|
|
6496
6865
|
init_shape_builders();
|
|
6866
|
+
init_text_svg();
|
|
6497
6867
|
|
|
6498
6868
|
// src/react/blob-url-lifecycle.ts
|
|
6499
6869
|
var SVG_BLOB_HREF_PATTERN = /\b(?:href|xlink:href)=["'](blob:[^"']+)["']/g;
|
|
@@ -6699,6 +7069,9 @@ function InteractionOverlay({
|
|
|
6699
7069
|
);
|
|
6700
7070
|
} else if (placementPreview.kind === "rect" || placementPreview.kind === "ellipse" || placementPreview.kind === "architectural-cloud") {
|
|
6701
7071
|
const r = normalizeRect(placementPreview.rect);
|
|
7072
|
+
const shapeStroke = previewStrokeStyle?.stroke ?? "#1d1d1d";
|
|
7073
|
+
const shapeWidth = previewStrokeStyle?.strokeWidth ?? 2;
|
|
7074
|
+
const shapeOpacity = previewStrokeStyle?.strokeOpacity;
|
|
6702
7075
|
preview = placementPreview.kind === "rect" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
6703
7076
|
"rect",
|
|
6704
7077
|
{
|
|
@@ -6706,11 +7079,11 @@ function InteractionOverlay({
|
|
|
6706
7079
|
y: r.y,
|
|
6707
7080
|
width: r.width,
|
|
6708
7081
|
height: r.height,
|
|
7082
|
+
rx: 4,
|
|
6709
7083
|
fill: "none",
|
|
6710
|
-
stroke:
|
|
6711
|
-
strokeWidth:
|
|
6712
|
-
|
|
6713
|
-
vectorEffect: "non-scaling-stroke"
|
|
7084
|
+
stroke: shapeStroke,
|
|
7085
|
+
strokeWidth: shapeWidth,
|
|
7086
|
+
strokeOpacity: shapeOpacity
|
|
6714
7087
|
}
|
|
6715
7088
|
) : placementPreview.kind === "ellipse" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
6716
7089
|
"ellipse",
|
|
@@ -6720,29 +7093,30 @@ function InteractionOverlay({
|
|
|
6720
7093
|
rx: r.width / 2,
|
|
6721
7094
|
ry: r.height / 2,
|
|
6722
7095
|
fill: "none",
|
|
6723
|
-
stroke:
|
|
6724
|
-
strokeWidth:
|
|
6725
|
-
|
|
6726
|
-
vectorEffect: "non-scaling-stroke"
|
|
7096
|
+
stroke: shapeStroke,
|
|
7097
|
+
strokeWidth: shapeWidth,
|
|
7098
|
+
strokeOpacity: shapeOpacity
|
|
6727
7099
|
}
|
|
6728
7100
|
) : /* @__PURE__ */ jsxRuntime.jsx("g", { transform: `translate(${r.x}, ${r.y})`, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
6729
7101
|
"path",
|
|
6730
7102
|
{
|
|
6731
|
-
d: buildArchitecturalCloudPathD(r.width, r.height,
|
|
7103
|
+
d: buildArchitecturalCloudPathD(r.width, r.height, shapeWidth),
|
|
6732
7104
|
fill: "none",
|
|
6733
|
-
stroke:
|
|
6734
|
-
strokeWidth:
|
|
6735
|
-
|
|
7105
|
+
stroke: shapeStroke,
|
|
7106
|
+
strokeWidth: shapeWidth,
|
|
7107
|
+
strokeOpacity: shapeOpacity,
|
|
6736
7108
|
strokeLinecap: "round",
|
|
6737
|
-
strokeLinejoin: "round"
|
|
6738
|
-
vectorEffect: "non-scaling-stroke"
|
|
7109
|
+
strokeLinejoin: "round"
|
|
6739
7110
|
}
|
|
6740
7111
|
) });
|
|
6741
7112
|
} else if (placementPreview.kind === "line" || placementPreview.kind === "arrow") {
|
|
6742
7113
|
const { start, end } = placementPreview;
|
|
7114
|
+
const shapeStroke = previewStrokeStyle?.stroke ?? "#1d1d1d";
|
|
7115
|
+
const shapeWidth = previewStrokeStyle?.strokeWidth ?? 2;
|
|
7116
|
+
const shapeOpacity = previewStrokeStyle?.strokeOpacity;
|
|
6743
7117
|
const geometry = placementPreview.kind === "arrow" ? computeStraightArrowGeometry(
|
|
6744
7118
|
{ x1: start.x, y1: start.y, x2: end.x, y2: end.y },
|
|
6745
|
-
|
|
7119
|
+
shapeWidth
|
|
6746
7120
|
) : null;
|
|
6747
7121
|
preview = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
6748
7122
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -6752,11 +7126,10 @@ function InteractionOverlay({
|
|
|
6752
7126
|
y1: start.y,
|
|
6753
7127
|
x2: geometry?.shaftEndX ?? end.x,
|
|
6754
7128
|
y2: geometry?.shaftEndY ?? end.y,
|
|
6755
|
-
stroke:
|
|
6756
|
-
strokeWidth:
|
|
6757
|
-
|
|
6758
|
-
strokeLinecap: "round"
|
|
6759
|
-
vectorEffect: "non-scaling-stroke"
|
|
7129
|
+
stroke: shapeStroke,
|
|
7130
|
+
strokeWidth: shapeWidth,
|
|
7131
|
+
strokeOpacity: shapeOpacity,
|
|
7132
|
+
strokeLinecap: "round"
|
|
6760
7133
|
}
|
|
6761
7134
|
),
|
|
6762
7135
|
placementPreview.kind === "arrow" && geometry ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -6764,10 +7137,9 @@ function InteractionOverlay({
|
|
|
6764
7137
|
{
|
|
6765
7138
|
d: `M ${geometry.headLeftX} ${geometry.headLeftY} L ${geometry.headTipX} ${geometry.headTipY} L ${geometry.headRightX} ${geometry.headRightY}`,
|
|
6766
7139
|
fill: "none",
|
|
6767
|
-
stroke:
|
|
6768
|
-
strokeWidth:
|
|
6769
|
-
strokeOpacity:
|
|
6770
|
-
strokeDasharray: dashPattern,
|
|
7140
|
+
stroke: shapeStroke,
|
|
7141
|
+
strokeWidth: shapeWidth,
|
|
7142
|
+
strokeOpacity: shapeOpacity,
|
|
6771
7143
|
strokeLinecap: "round",
|
|
6772
7144
|
strokeLinejoin: "round"
|
|
6773
7145
|
}
|
|
@@ -6781,7 +7153,8 @@ function InteractionOverlay({
|
|
|
6781
7153
|
const previewStyle = {
|
|
6782
7154
|
stroke: isLaser ? "#f43f5e" : previewStrokeStyle?.stroke ?? "#64748b",
|
|
6783
7155
|
strokeWidth: isLaser ? 4 : previewStrokeStyle?.strokeWidth ?? (tool === "marker" ? 16 : 3),
|
|
6784
|
-
...previewStrokeStyle?.strokeOpacity != null && !isLaser ? { strokeOpacity: previewStrokeStyle.strokeOpacity } : {}
|
|
7156
|
+
...previewStrokeStyle?.strokeOpacity != null && !isLaser ? { strokeOpacity: previewStrokeStyle.strokeOpacity } : {},
|
|
7157
|
+
...previewStrokeStyle?.strokeDash != null && !isLaser ? { strokeDash: previewStrokeStyle.strokeDash } : {}
|
|
6785
7158
|
};
|
|
6786
7159
|
const payload = computeFreehandSvgPayload(
|
|
6787
7160
|
raw,
|
|
@@ -6825,6 +7198,7 @@ function InteractionOverlay({
|
|
|
6825
7198
|
strokeOpacity: isLaser ? 0.85 : payload.strokeOpacity,
|
|
6826
7199
|
strokeLinecap: "round",
|
|
6827
7200
|
strokeLinejoin: "round",
|
|
7201
|
+
strokeDasharray: payload.strokeDasharray,
|
|
6828
7202
|
shapeRendering: "geometricPrecision"
|
|
6829
7203
|
}
|
|
6830
7204
|
);
|
|
@@ -7230,6 +7604,9 @@ function TextEditOverlay({
|
|
|
7230
7604
|
const fontSize = fsWorld * z;
|
|
7231
7605
|
const lineHeight = fsWorld * (22 / 18) * z;
|
|
7232
7606
|
const fixedBox = !!item.textFixedBounds;
|
|
7607
|
+
const padTop = EDIT_TOP_PAD_RATIO * fsWorld * z;
|
|
7608
|
+
const padX = 4 * z;
|
|
7609
|
+
const textColor = item.stroke ?? "#1d1d1d";
|
|
7233
7610
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
7234
7611
|
"div",
|
|
7235
7612
|
{
|
|
@@ -7260,14 +7637,14 @@ function TextEditOverlay({
|
|
|
7260
7637
|
width: "100%",
|
|
7261
7638
|
height: "100%",
|
|
7262
7639
|
margin: 0,
|
|
7263
|
-
padding:
|
|
7640
|
+
padding: `${padTop}px ${padX}px 0px ${padX}px`,
|
|
7264
7641
|
border: "none",
|
|
7265
7642
|
borderRadius: 0,
|
|
7266
7643
|
resize: "none",
|
|
7267
|
-
fontFamily:
|
|
7644
|
+
fontFamily: TEXT_FONT_FAMILY,
|
|
7268
7645
|
fontSize,
|
|
7269
7646
|
lineHeight: `${lineHeight}px`,
|
|
7270
|
-
color:
|
|
7647
|
+
color: textColor,
|
|
7271
7648
|
background: "transparent",
|
|
7272
7649
|
backgroundColor: "transparent",
|
|
7273
7650
|
outline: "none",
|
|
@@ -7275,7 +7652,6 @@ function TextEditOverlay({
|
|
|
7275
7652
|
appearance: "none",
|
|
7276
7653
|
WebkitAppearance: "none",
|
|
7277
7654
|
WebkitTapHighlightColor: "transparent",
|
|
7278
|
-
/* Auto-sized text: no soft wrap / scrollbar; fixed box: wrap like the SVG. */
|
|
7279
7655
|
whiteSpace: fixedBox ? "pre-wrap" : "pre",
|
|
7280
7656
|
overflow: fixedBox ? "auto" : "hidden",
|
|
7281
7657
|
overflowX: fixedBox ? "hidden" : "hidden",
|
|
@@ -7965,14 +8341,32 @@ var VectorViewport = react.forwardRef(
|
|
|
7965
8341
|
imageStoreRef.current = new IndexedDbImageStore();
|
|
7966
8342
|
}
|
|
7967
8343
|
const rememberedImageBlobHrefsRef = react.useRef(/* @__PURE__ */ new Set());
|
|
7968
|
-
const strokeStyleRef = react.useRef({
|
|
8344
|
+
const strokeStyleRef = react.useRef({
|
|
8345
|
+
...DEFAULT_STROKE_STYLE,
|
|
8346
|
+
textFontSize: DEFAULT_TEXT_FONT_SIZE
|
|
8347
|
+
});
|
|
7969
8348
|
const [strokeStyleState, setStrokeStyleState] = react.useState({
|
|
7970
|
-
...DEFAULT_STROKE_STYLE
|
|
8349
|
+
...DEFAULT_STROKE_STYLE,
|
|
8350
|
+
textFontSize: DEFAULT_TEXT_FONT_SIZE
|
|
7971
8351
|
});
|
|
7972
8352
|
const setCurrentStrokeStyle = react.useCallback((next) => {
|
|
7973
8353
|
strokeStyleRef.current = next;
|
|
7974
8354
|
setStrokeStyleState(next);
|
|
7975
8355
|
}, []);
|
|
8356
|
+
const patchCurrentStrokeStyle = react.useCallback(
|
|
8357
|
+
(patch) => {
|
|
8358
|
+
const merged = { ...strokeStyleRef.current };
|
|
8359
|
+
for (const key of Object.keys(patch)) {
|
|
8360
|
+
const v = patch[key];
|
|
8361
|
+
if (v !== void 0) {
|
|
8362
|
+
merged[key] = v;
|
|
8363
|
+
}
|
|
8364
|
+
}
|
|
8365
|
+
strokeStyleRef.current = merged;
|
|
8366
|
+
setStrokeStyleState(merged);
|
|
8367
|
+
},
|
|
8368
|
+
[]
|
|
8369
|
+
);
|
|
7976
8370
|
const progressiveQueueRef = react.useRef(/* @__PURE__ */ new Set());
|
|
7977
8371
|
react.useEffect(() => {
|
|
7978
8372
|
const store = imageStoreRef.current;
|
|
@@ -8121,10 +8515,11 @@ var VectorViewport = react.forwardRef(
|
|
|
8121
8515
|
change(
|
|
8122
8516
|
exists ? replaceItem(itemsRef.current, id, item) : [...itemsRef.current, item]
|
|
8123
8517
|
);
|
|
8124
|
-
|
|
8518
|
+
patchCurrentStrokeStyle({
|
|
8125
8519
|
stroke: item.stroke ?? DEFAULT_STROKE_STYLE.stroke,
|
|
8126
8520
|
strokeWidth: item.strokeWidth ?? DEFAULT_STROKE_STYLE.strokeWidth,
|
|
8127
|
-
|
|
8521
|
+
strokeOpacity: item.strokeOpacity,
|
|
8522
|
+
strokeDash: item.strokeDash
|
|
8128
8523
|
});
|
|
8129
8524
|
}
|
|
8130
8525
|
if (!shouldKeepToolForContinuousPenInput(args.tool, args.pointerType)) {
|
|
@@ -8132,8 +8527,8 @@ var VectorViewport = react.forwardRef(
|
|
|
8132
8527
|
}
|
|
8133
8528
|
},
|
|
8134
8529
|
[
|
|
8530
|
+
patchCurrentStrokeStyle,
|
|
8135
8531
|
requestAutoResetTool,
|
|
8136
|
-
setCurrentStrokeStyle,
|
|
8137
8532
|
shouldKeepToolForContinuousPenInput
|
|
8138
8533
|
]
|
|
8139
8534
|
);
|
|
@@ -8869,24 +9264,28 @@ var VectorViewport = react.forwardRef(
|
|
|
8869
9264
|
renderFrame();
|
|
8870
9265
|
}, [renderFrame]);
|
|
8871
9266
|
react.useEffect(() => {
|
|
9267
|
+
const current = strokeStyleRef.current;
|
|
8872
9268
|
if (toolId === "marker") {
|
|
8873
9269
|
setCurrentStrokeStyle({
|
|
8874
|
-
...
|
|
9270
|
+
...current,
|
|
8875
9271
|
...MARKER_TOOL_STYLE
|
|
8876
9272
|
});
|
|
8877
9273
|
return;
|
|
8878
9274
|
}
|
|
8879
|
-
const current = strokeStyleRef.current;
|
|
8880
9275
|
if (isDefaultMarkerToolStyle(current)) {
|
|
8881
9276
|
setCurrentStrokeStyle({
|
|
8882
9277
|
stroke: DEFAULT_STROKE_STYLE.stroke,
|
|
8883
|
-
strokeWidth: toolId === "draw" ? 10 : DEFAULT_STROKE_STYLE.strokeWidth
|
|
9278
|
+
strokeWidth: toolId === "draw" ? 10 : DEFAULT_STROKE_STYLE.strokeWidth,
|
|
9279
|
+
strokeDash: current.strokeDash,
|
|
9280
|
+
textFontSize: current.textFontSize
|
|
8884
9281
|
});
|
|
8885
9282
|
return;
|
|
8886
9283
|
}
|
|
8887
9284
|
setCurrentStrokeStyle({
|
|
8888
9285
|
stroke: current.stroke,
|
|
8889
|
-
strokeWidth: toolId === "draw" ? 10 : current.strokeWidth
|
|
9286
|
+
strokeWidth: toolId === "draw" ? 10 : current.strokeWidth,
|
|
9287
|
+
strokeDash: current.strokeDash,
|
|
9288
|
+
textFontSize: current.textFontSize
|
|
8890
9289
|
});
|
|
8891
9290
|
}, [setCurrentStrokeStyle, toolId]);
|
|
8892
9291
|
react.useEffect(() => {
|
|
@@ -8895,15 +9294,14 @@ var VectorViewport = react.forwardRef(
|
|
|
8895
9294
|
const it = items.find((i) => i.id === primaryId);
|
|
8896
9295
|
if (!it || it.locked) return;
|
|
8897
9296
|
if (it.toolKind === "image") return;
|
|
8898
|
-
|
|
9297
|
+
patchCurrentStrokeStyle({
|
|
8899
9298
|
stroke: it.stroke ?? DEFAULT_STROKE_STYLE.stroke,
|
|
8900
|
-
strokeWidth: it.strokeWidth ?? DEFAULT_STROKE_STYLE.strokeWidth
|
|
8901
|
-
|
|
8902
|
-
|
|
8903
|
-
|
|
8904
|
-
}
|
|
8905
|
-
|
|
8906
|
-
}, [effectiveSelectedIds, items, setCurrentStrokeStyle]);
|
|
9299
|
+
strokeWidth: it.strokeWidth ?? DEFAULT_STROKE_STYLE.strokeWidth,
|
|
9300
|
+
strokeOpacity: it.strokeOpacity,
|
|
9301
|
+
strokeDash: it.strokeDash,
|
|
9302
|
+
...it.toolKind === "text" && it.textFontSize != null ? { textFontSize: it.textFontSize } : {}
|
|
9303
|
+
});
|
|
9304
|
+
}, [effectiveSelectedIds, items, patchCurrentStrokeStyle]);
|
|
8907
9305
|
const handleSelectionStyleChange = react.useCallback(
|
|
8908
9306
|
(patch) => {
|
|
8909
9307
|
const change = onItemsChangeRef.current;
|
|
@@ -8919,25 +9317,15 @@ var VectorViewport = react.forwardRef(
|
|
|
8919
9317
|
nextList = replaceItem(nextList, id, out);
|
|
8920
9318
|
}
|
|
8921
9319
|
change(nextList);
|
|
8922
|
-
|
|
8923
|
-
...strokeStyleRef.current,
|
|
8924
|
-
stroke: patch.stroke,
|
|
8925
|
-
strokeWidth: patch.strokeWidth,
|
|
8926
|
-
...patch.strokeOpacity != null ? { strokeOpacity: patch.strokeOpacity } : {}
|
|
8927
|
-
});
|
|
9320
|
+
patchCurrentStrokeStyle(patch);
|
|
8928
9321
|
},
|
|
8929
|
-
[
|
|
9322
|
+
[patchCurrentStrokeStyle]
|
|
8930
9323
|
);
|
|
8931
9324
|
const handleActiveToolStyleChange = react.useCallback(
|
|
8932
9325
|
(patch) => {
|
|
8933
|
-
|
|
8934
|
-
setCurrentStrokeStyle({
|
|
8935
|
-
stroke: patch.stroke,
|
|
8936
|
-
strokeWidth: patch.strokeWidth,
|
|
8937
|
-
...patch.strokeOpacity != null ? { strokeOpacity: patch.strokeOpacity } : current.strokeOpacity != null ? { strokeOpacity: current.strokeOpacity } : {}
|
|
8938
|
-
});
|
|
9326
|
+
patchCurrentStrokeStyle(patch);
|
|
8939
9327
|
},
|
|
8940
|
-
[
|
|
9328
|
+
[patchCurrentStrokeStyle]
|
|
8941
9329
|
);
|
|
8942
9330
|
const commitTextEdit = react.useCallback(() => {
|
|
8943
9331
|
const id = editingTextIdRef.current;
|
|
@@ -10070,16 +10458,21 @@ var VectorViewport = react.forwardRef(
|
|
|
10070
10458
|
const id = createShapeId();
|
|
10071
10459
|
const { x: worldX, y: worldY } = st.startWorld;
|
|
10072
10460
|
if (st.tool === "text") {
|
|
10461
|
+
const fs = strokeStyleRef.current.textFontSize;
|
|
10462
|
+
const baseline = textBaselineYFor(fs);
|
|
10463
|
+
const lh = textLineHeightFor(fs);
|
|
10464
|
+
const minH = Math.max(26, baseline + Math.max(4, lh * 0.2));
|
|
10073
10465
|
const newItem = createTextItem(
|
|
10074
10466
|
id,
|
|
10075
10467
|
{
|
|
10076
10468
|
x: worldX - 4,
|
|
10077
|
-
y: worldY -
|
|
10469
|
+
y: worldY - baseline,
|
|
10078
10470
|
width: 160,
|
|
10079
|
-
height:
|
|
10471
|
+
height: minH
|
|
10080
10472
|
},
|
|
10081
10473
|
"",
|
|
10082
|
-
strokeStyleRef.current
|
|
10474
|
+
strokeStyleRef.current,
|
|
10475
|
+
fs
|
|
10083
10476
|
);
|
|
10084
10477
|
editingTextSnapshotRef.current = {
|
|
10085
10478
|
...newItem,
|
|
@@ -10230,12 +10623,63 @@ var VectorViewport = react.forwardRef(
|
|
|
10230
10623
|
return effectiveSelectedIds.map((id) => resolvedItems.find((i) => i.id === id)).filter((i) => i != null);
|
|
10231
10624
|
}, [effectiveSelectedIds, resolvedItems]);
|
|
10232
10625
|
const activeToolInspectorStyle = react.useMemo(() => {
|
|
10233
|
-
if (toolId
|
|
10234
|
-
|
|
10235
|
-
|
|
10236
|
-
|
|
10237
|
-
|
|
10238
|
-
|
|
10626
|
+
if (toolId === "draw") {
|
|
10627
|
+
return {
|
|
10628
|
+
toolKind: "draw",
|
|
10629
|
+
label: "Caneta",
|
|
10630
|
+
...strokeStyleState
|
|
10631
|
+
};
|
|
10632
|
+
}
|
|
10633
|
+
if (toolId === "marker") {
|
|
10634
|
+
return {
|
|
10635
|
+
toolKind: "marker",
|
|
10636
|
+
label: "Marcador",
|
|
10637
|
+
...strokeStyleState
|
|
10638
|
+
};
|
|
10639
|
+
}
|
|
10640
|
+
if (toolId === "text") {
|
|
10641
|
+
return {
|
|
10642
|
+
toolKind: "text",
|
|
10643
|
+
label: "Texto",
|
|
10644
|
+
...strokeStyleState
|
|
10645
|
+
};
|
|
10646
|
+
}
|
|
10647
|
+
if (toolId === "rect") {
|
|
10648
|
+
return {
|
|
10649
|
+
toolKind: "rect",
|
|
10650
|
+
label: "Ret\xE2ngulo",
|
|
10651
|
+
...strokeStyleState
|
|
10652
|
+
};
|
|
10653
|
+
}
|
|
10654
|
+
if (toolId === "ellipse") {
|
|
10655
|
+
return {
|
|
10656
|
+
toolKind: "ellipse",
|
|
10657
|
+
label: "Elipse",
|
|
10658
|
+
...strokeStyleState
|
|
10659
|
+
};
|
|
10660
|
+
}
|
|
10661
|
+
if (toolId === "architectural-cloud") {
|
|
10662
|
+
return {
|
|
10663
|
+
toolKind: "architectural-cloud",
|
|
10664
|
+
label: "Nuvem",
|
|
10665
|
+
...strokeStyleState
|
|
10666
|
+
};
|
|
10667
|
+
}
|
|
10668
|
+
if (toolId === "line") {
|
|
10669
|
+
return {
|
|
10670
|
+
toolKind: "line",
|
|
10671
|
+
label: "Linha",
|
|
10672
|
+
...strokeStyleState
|
|
10673
|
+
};
|
|
10674
|
+
}
|
|
10675
|
+
if (toolId === "arrow") {
|
|
10676
|
+
return {
|
|
10677
|
+
toolKind: "arrow",
|
|
10678
|
+
label: "Seta",
|
|
10679
|
+
...strokeStyleState
|
|
10680
|
+
};
|
|
10681
|
+
}
|
|
10682
|
+
return void 0;
|
|
10239
10683
|
}, [strokeStyleState, toolId]);
|
|
10240
10684
|
const eraserPreviewItemsForOverlay = react.useMemo(() => {
|
|
10241
10685
|
return eraserPreviewIds.map((id) => resolvedItems.find((i) => i.id === id)).filter((i) => i != null);
|