canvu-react 0.4.6 → 0.4.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/native.cjs +471 -100
- package/dist/native.cjs.map +1 -1
- package/dist/native.d.cts +32 -3
- package/dist/native.d.ts +32 -3
- package/dist/native.js +473 -104
- package/dist/native.js.map +1 -1
- package/package.json +1 -1
package/dist/native.cjs
CHANGED
|
@@ -899,6 +899,25 @@ function buildRasterImageChildrenSvg(dataUrl, intrinsic, bounds) {
|
|
|
899
899
|
const ty = (r.height - ih * s) / 2;
|
|
900
900
|
return `<g transform="translate(${tx}, ${ty}) scale(${s})"><image href="${href}" x="0" y="0" width="${iw}" height="${ih}" /></g>`;
|
|
901
901
|
}
|
|
902
|
+
function createImageItem(id, bounds, imageRasterHref, imageIntrinsicSize) {
|
|
903
|
+
const r = normalizeRect(bounds);
|
|
904
|
+
const iw = Math.max(1e-6, imageIntrinsicSize.width);
|
|
905
|
+
const ih = Math.max(1e-6, imageIntrinsicSize.height);
|
|
906
|
+
return {
|
|
907
|
+
id,
|
|
908
|
+
x: r.x,
|
|
909
|
+
y: r.y,
|
|
910
|
+
bounds: { ...r },
|
|
911
|
+
toolKind: "image",
|
|
912
|
+
imageRasterHref,
|
|
913
|
+
imageIntrinsicSize: { width: iw, height: ih },
|
|
914
|
+
childrenSvg: buildRasterImageChildrenSvg(
|
|
915
|
+
imageRasterHref,
|
|
916
|
+
{ width: iw, height: ih },
|
|
917
|
+
r
|
|
918
|
+
)
|
|
919
|
+
};
|
|
920
|
+
}
|
|
902
921
|
|
|
903
922
|
// src/math/item-transform.ts
|
|
904
923
|
function getItemRotationRad(item) {
|
|
@@ -1287,6 +1306,9 @@ function SvgNodeItem({ node }) {
|
|
|
1287
1306
|
}
|
|
1288
1307
|
);
|
|
1289
1308
|
}
|
|
1309
|
+
case "image": {
|
|
1310
|
+
return /* @__PURE__ */ jsxRuntime.jsx(SvgImageNodeItem, { node });
|
|
1311
|
+
}
|
|
1290
1312
|
case "g": {
|
|
1291
1313
|
const transform = node.transform ? parseSvgTransform(node.transform) : void 0;
|
|
1292
1314
|
return /* @__PURE__ */ jsxRuntime.jsx(reactNativeSkia.Group, { transform, children: node.children.map((child, i) => /* @__PURE__ */ jsxRuntime.jsx(SvgNodeItem, { node: child }, i)) });
|
|
@@ -1298,6 +1320,23 @@ function SvgNodeItem({ node }) {
|
|
|
1298
1320
|
return null;
|
|
1299
1321
|
}
|
|
1300
1322
|
}
|
|
1323
|
+
function SvgImageNodeItem({
|
|
1324
|
+
node
|
|
1325
|
+
}) {
|
|
1326
|
+
const image = reactNativeSkia.useImage(node.href);
|
|
1327
|
+
if (!image) return null;
|
|
1328
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1329
|
+
reactNativeSkia.Image,
|
|
1330
|
+
{
|
|
1331
|
+
image,
|
|
1332
|
+
x: toNum(node.x),
|
|
1333
|
+
y: toNum(node.y),
|
|
1334
|
+
width: toNum(node.width),
|
|
1335
|
+
height: toNum(node.height),
|
|
1336
|
+
fit: "contain"
|
|
1337
|
+
}
|
|
1338
|
+
);
|
|
1339
|
+
}
|
|
1301
1340
|
function polygonPointsToPath(points) {
|
|
1302
1341
|
const nums = points.split(/[\s,]+/).filter(Boolean).map(Number);
|
|
1303
1342
|
if (nums.length < 4) return "";
|
|
@@ -2200,146 +2239,353 @@ function NativeSceneRenderer({
|
|
|
2200
2239
|
if (width <= 0 || height <= 0) return null;
|
|
2201
2240
|
return /* @__PURE__ */ jsxRuntime.jsx(reactNativeSkia.Canvas, { style: { width, height }, children: /* @__PURE__ */ jsxRuntime.jsx(reactNativeSkia.Group, { transform: cameraTransform, children: visible.map((item) => /* @__PURE__ */ jsxRuntime.jsx(MemoShape, { item }, item.id)) }) });
|
|
2202
2241
|
}
|
|
2242
|
+
var DEFAULT_NATIVE_OVERFLOW_TOOL_IDS = [
|
|
2243
|
+
"rect",
|
|
2244
|
+
"ellipse",
|
|
2245
|
+
"architectural-cloud",
|
|
2246
|
+
"line",
|
|
2247
|
+
"marker",
|
|
2248
|
+
"laser",
|
|
2249
|
+
"image"
|
|
2250
|
+
];
|
|
2203
2251
|
var DEFAULT_NATIVE_VECTOR_TOOLS = [
|
|
2204
|
-
{ id: "hand", label: "Hand", shortLabel: "H" },
|
|
2205
|
-
{ id: "select", label: "Select", shortLabel: "V" },
|
|
2206
|
-
{ id: "
|
|
2207
|
-
{ id: "
|
|
2208
|
-
{
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
{ id: "
|
|
2252
|
+
{ id: "hand", label: "Hand", shortcutHint: "H", shortLabel: "H" },
|
|
2253
|
+
{ id: "select", label: "Select", shortcutHint: "V", shortLabel: "V" },
|
|
2254
|
+
{ id: "rect", label: "Rectangle", shortcutHint: "R", shortLabel: "R" },
|
|
2255
|
+
{ id: "ellipse", label: "Ellipse", shortcutHint: "O", shortLabel: "O" },
|
|
2256
|
+
{
|
|
2257
|
+
id: "architectural-cloud",
|
|
2258
|
+
label: "Nuvem arquitetural",
|
|
2259
|
+
tooltipLabel: "Architectural cloud",
|
|
2260
|
+
shortcutHint: "C",
|
|
2261
|
+
shortLabel: "C"
|
|
2262
|
+
},
|
|
2263
|
+
{ id: "line", label: "Line", shortcutHint: "L", shortLabel: "L" },
|
|
2264
|
+
{ id: "arrow", label: "Arrow", shortcutHint: "A", shortLabel: "A" },
|
|
2265
|
+
{
|
|
2266
|
+
id: "draw",
|
|
2267
|
+
label: "Desenhar",
|
|
2268
|
+
tooltipLabel: "Draw",
|
|
2269
|
+
shortcutHint: "D",
|
|
2270
|
+
shortLabel: "D"
|
|
2271
|
+
},
|
|
2272
|
+
{
|
|
2273
|
+
id: "marker",
|
|
2274
|
+
label: "Realce",
|
|
2275
|
+
tooltipLabel: "Highlighter",
|
|
2276
|
+
shortcutHint: "M",
|
|
2277
|
+
shortLabel: "M"
|
|
2278
|
+
},
|
|
2279
|
+
{ id: "laser", label: "Laser", shortcutHint: "K", shortLabel: "K" },
|
|
2280
|
+
{
|
|
2281
|
+
id: "eraser",
|
|
2282
|
+
label: "Borracha",
|
|
2283
|
+
tooltipLabel: "Eraser",
|
|
2284
|
+
shortcutHint: "E",
|
|
2285
|
+
shortLabel: "E"
|
|
2286
|
+
},
|
|
2287
|
+
{ id: "text", label: "Text", shortcutHint: "T", shortLabel: "T" },
|
|
2288
|
+
{ id: "image", label: "File", shortcutHint: "I", shortLabel: "I" }
|
|
2216
2289
|
];
|
|
2290
|
+
function splitToolbarTools(tools, overflowToolIds) {
|
|
2291
|
+
const overflowIds = new Set(overflowToolIds);
|
|
2292
|
+
if (overflowIds.size === 0) return { primary: tools, overflow: [] };
|
|
2293
|
+
return {
|
|
2294
|
+
primary: tools.filter((tool) => !overflowIds.has(tool.id)),
|
|
2295
|
+
overflow: tools.filter((tool) => overflowIds.has(tool.id))
|
|
2296
|
+
};
|
|
2297
|
+
}
|
|
2298
|
+
function getPromotedOverflowTool(input) {
|
|
2299
|
+
const selectedOverflowTool = input.overflowTools.find((tool) => tool.id === input.selectedId) ?? null;
|
|
2300
|
+
const fallbackTool = input.overflowTools.find((tool) => tool.id === input.initialPromotedId) ?? input.overflowTools[0] ?? null;
|
|
2301
|
+
const promotedTool = selectedOverflowTool ?? fallbackTool;
|
|
2302
|
+
if (!promotedTool) {
|
|
2303
|
+
return { promotedTool: null, remainingOverflowTools: input.overflowTools };
|
|
2304
|
+
}
|
|
2305
|
+
return {
|
|
2306
|
+
promotedTool,
|
|
2307
|
+
remainingOverflowTools: input.overflowTools.filter(
|
|
2308
|
+
(tool) => tool.id !== promotedTool.id
|
|
2309
|
+
)
|
|
2310
|
+
};
|
|
2311
|
+
}
|
|
2312
|
+
function tooltipTextForTool(tool) {
|
|
2313
|
+
const name = tool.tooltipLabel ?? tool.label;
|
|
2314
|
+
return tool.shortcutHint ? `${name} - ${tool.shortcutHint}` : name;
|
|
2315
|
+
}
|
|
2217
2316
|
function NativeVectorToolbar({
|
|
2218
2317
|
value,
|
|
2219
2318
|
onChange,
|
|
2220
2319
|
tools = DEFAULT_NATIVE_VECTOR_TOOLS,
|
|
2320
|
+
overflowToolIds = DEFAULT_NATIVE_OVERFLOW_TOOL_IDS,
|
|
2321
|
+
overflowMenuAccessibilityLabel = "More tools",
|
|
2221
2322
|
disabled = false,
|
|
2222
2323
|
disabledToolIds = [],
|
|
2324
|
+
showToolLockToggle = true,
|
|
2325
|
+
toolLocked = false,
|
|
2326
|
+
onToolLockedChange,
|
|
2327
|
+
density = "compact",
|
|
2223
2328
|
accessibilityLabel = "Canvas tools",
|
|
2224
2329
|
style,
|
|
2225
2330
|
contentContainerStyle,
|
|
2331
|
+
overflowPanelStyle,
|
|
2226
2332
|
toolButtonStyle,
|
|
2227
2333
|
activeToolButtonStyle,
|
|
2228
2334
|
toolLabelStyle,
|
|
2229
2335
|
activeToolLabelStyle,
|
|
2230
2336
|
renderToolIcon,
|
|
2337
|
+
renderToolLockIcon,
|
|
2338
|
+
renderOverflowIcon,
|
|
2339
|
+
renderOverflowChevronIcon,
|
|
2231
2340
|
renderToolButton
|
|
2232
2341
|
}) {
|
|
2342
|
+
const [overflowOpen, setOverflowOpen] = react.useState(false);
|
|
2233
2343
|
const disabledIds = react.useMemo(() => new Set(disabledToolIds), [disabledToolIds]);
|
|
2234
|
-
|
|
2235
|
-
|
|
2344
|
+
const { primary: primaryTools, overflow: overflowTools } = react.useMemo(
|
|
2345
|
+
() => splitToolbarTools(tools, overflowToolIds),
|
|
2346
|
+
[tools, overflowToolIds]
|
|
2347
|
+
);
|
|
2348
|
+
const { promotedTool, remainingOverflowTools } = react.useMemo(
|
|
2349
|
+
() => getPromotedOverflowTool({
|
|
2350
|
+
overflowTools,
|
|
2351
|
+
selectedId: value,
|
|
2352
|
+
initialPromotedId: overflowToolIds[0] ?? null
|
|
2353
|
+
}),
|
|
2354
|
+
[overflowTools, overflowToolIds, value]
|
|
2355
|
+
);
|
|
2356
|
+
const activeOverflowTool = overflowTools.find((tool) => tool.id === value) ?? null;
|
|
2357
|
+
const toolbarTools = promotedTool !== null ? [...primaryTools, promotedTool] : primaryTools;
|
|
2358
|
+
const showOverflowMenu = remainingOverflowTools.length > 0;
|
|
2359
|
+
const toolLockDisabled = disabled || !onToolLockedChange;
|
|
2360
|
+
const toggleToolLock = () => onToolLockedChange?.(!toolLocked);
|
|
2361
|
+
const toggleOverflow = () => setOverflowOpen((open) => !open);
|
|
2362
|
+
const overflowRenderInput = {
|
|
2363
|
+
open: overflowOpen,
|
|
2364
|
+
activeTool: activeOverflowTool,
|
|
2365
|
+
disabled,
|
|
2366
|
+
foregroundColor: "#18181b",
|
|
2367
|
+
onToggle: toggleOverflow
|
|
2368
|
+
};
|
|
2369
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2370
|
+
reactNative.View,
|
|
2236
2371
|
{
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
children:
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
const foregroundColor = selected ? "#fafaf9" : "#18181b";
|
|
2244
|
-
const onSelect = () => {
|
|
2245
|
-
if (!toolDisabled) {
|
|
2246
|
-
onChange(tool.id);
|
|
2247
|
-
}
|
|
2248
|
-
};
|
|
2249
|
-
const input = {
|
|
2250
|
-
tool,
|
|
2251
|
-
selected,
|
|
2252
|
-
disabled: toolDisabled,
|
|
2253
|
-
foregroundColor,
|
|
2254
|
-
onSelect
|
|
2255
|
-
};
|
|
2256
|
-
if (renderToolButton) {
|
|
2257
|
-
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { children: renderToolButton(input) }, tool.id);
|
|
2258
|
-
}
|
|
2259
|
-
const icon = renderToolIcon?.(input) ?? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2260
|
-
reactNative.Text,
|
|
2372
|
+
accessibilityLabel,
|
|
2373
|
+
style: [styles.shell, style],
|
|
2374
|
+
pointerEvents: "box-none",
|
|
2375
|
+
children: [
|
|
2376
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2377
|
+
reactNative.ScrollView,
|
|
2261
2378
|
{
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
children: tool.shortLabel ?? tool.label.slice(0, 1).toUpperCase()
|
|
2269
|
-
}
|
|
2270
|
-
);
|
|
2271
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2272
|
-
reactNative.Pressable,
|
|
2273
|
-
{
|
|
2274
|
-
accessibilityLabel: tool.accessibilityLabel ?? tool.label,
|
|
2275
|
-
accessibilityRole: "button",
|
|
2276
|
-
accessibilityState: { selected, disabled: toolDisabled },
|
|
2277
|
-
disabled: toolDisabled,
|
|
2278
|
-
onPress: onSelect,
|
|
2279
|
-
style: ({ pressed }) => [
|
|
2280
|
-
styles.toolButton,
|
|
2281
|
-
toolButtonStyle,
|
|
2282
|
-
selected ? styles.activeToolButton : void 0,
|
|
2283
|
-
selected ? activeToolButtonStyle : void 0,
|
|
2284
|
-
pressed && !toolDisabled ? styles.pressedToolButton : void 0,
|
|
2285
|
-
toolDisabled ? styles.disabledToolButton : void 0
|
|
2379
|
+
horizontal: true,
|
|
2380
|
+
showsHorizontalScrollIndicator: false,
|
|
2381
|
+
contentContainerStyle: [
|
|
2382
|
+
styles.content,
|
|
2383
|
+
density === "comfortable" ? styles.comfortableContent : void 0,
|
|
2384
|
+
contentContainerStyle
|
|
2286
2385
|
],
|
|
2287
2386
|
children: [
|
|
2288
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2289
|
-
|
|
2290
|
-
|
|
2387
|
+
showToolLockToggle ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2388
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2389
|
+
reactNative.Pressable,
|
|
2390
|
+
{
|
|
2391
|
+
accessibilityLabel: toolLocked ? "Unlock tool" : "Lock tool",
|
|
2392
|
+
accessibilityRole: "button",
|
|
2393
|
+
accessibilityState: {
|
|
2394
|
+
checked: toolLocked,
|
|
2395
|
+
disabled: toolLockDisabled
|
|
2396
|
+
},
|
|
2397
|
+
disabled: toolLockDisabled,
|
|
2398
|
+
onPress: toggleToolLock,
|
|
2399
|
+
style: ({ pressed }) => [
|
|
2400
|
+
styles.toolButton,
|
|
2401
|
+
density === "comfortable" ? styles.comfortableToolButton : void 0,
|
|
2402
|
+
toolLocked ? styles.activeToolButton : void 0,
|
|
2403
|
+
pressed && !toolLockDisabled ? styles.pressedToolButton : void 0,
|
|
2404
|
+
toolLockDisabled ? styles.disabledToolButton : void 0
|
|
2405
|
+
],
|
|
2406
|
+
children: renderToolLockIcon?.({
|
|
2407
|
+
locked: toolLocked,
|
|
2408
|
+
disabled: toolLockDisabled,
|
|
2409
|
+
foregroundColor: "#18181b",
|
|
2410
|
+
onToggle: toggleToolLock
|
|
2411
|
+
}) ?? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.lockGlyph, children: toolLocked ? "L" : "U" })
|
|
2412
|
+
}
|
|
2413
|
+
),
|
|
2414
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles.toolLockDivider })
|
|
2415
|
+
] }) : null,
|
|
2416
|
+
toolbarTools.map(
|
|
2417
|
+
(tool) => renderNativeToolButton({
|
|
2418
|
+
tool,
|
|
2419
|
+
value,
|
|
2420
|
+
onChange,
|
|
2421
|
+
disabled,
|
|
2422
|
+
disabledIds,
|
|
2423
|
+
density,
|
|
2424
|
+
toolButtonStyle,
|
|
2425
|
+
activeToolButtonStyle,
|
|
2426
|
+
toolLabelStyle,
|
|
2427
|
+
activeToolLabelStyle,
|
|
2428
|
+
renderToolIcon,
|
|
2429
|
+
renderToolButton
|
|
2430
|
+
})
|
|
2431
|
+
),
|
|
2432
|
+
showOverflowMenu ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles.overflowSpacer }) : null,
|
|
2433
|
+
showOverflowMenu ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2434
|
+
reactNative.Pressable,
|
|
2291
2435
|
{
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2436
|
+
accessibilityLabel: activeOverflowTool ? `${overflowMenuAccessibilityLabel}: ${activeOverflowTool.accessibilityLabel ?? activeOverflowTool.label}` : overflowMenuAccessibilityLabel,
|
|
2437
|
+
accessibilityRole: "button",
|
|
2438
|
+
accessibilityState: {
|
|
2439
|
+
expanded: overflowOpen,
|
|
2440
|
+
selected: overflowOpen || activeOverflowTool !== null,
|
|
2441
|
+
disabled
|
|
2442
|
+
},
|
|
2443
|
+
disabled,
|
|
2444
|
+
onPress: toggleOverflow,
|
|
2445
|
+
style: ({ pressed }) => [
|
|
2446
|
+
styles.overflowTrigger,
|
|
2447
|
+
overflowOpen || activeOverflowTool ? styles.activeToolButton : void 0,
|
|
2448
|
+
pressed && !disabled ? styles.pressedToolButton : void 0,
|
|
2449
|
+
disabled ? styles.disabledToolButton : void 0
|
|
2298
2450
|
],
|
|
2299
|
-
children:
|
|
2451
|
+
children: [
|
|
2452
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles.iconSlot, children: activeOverflowTool ? renderToolIcon?.({
|
|
2453
|
+
tool: activeOverflowTool,
|
|
2454
|
+
selected: true,
|
|
2455
|
+
disabled,
|
|
2456
|
+
foregroundColor: "#18181b",
|
|
2457
|
+
onSelect: () => onChange(activeOverflowTool.id)
|
|
2458
|
+
}) ?? renderNativeToolFallback(activeOverflowTool, "#18181b") : renderOverflowIcon?.(overflowRenderInput) ?? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.shapesGlyph, children: "S" }) }),
|
|
2459
|
+
renderOverflowChevronIcon?.(overflowRenderInput) ?? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles.chevronGlyph, children: overflowOpen ? "^" : "v" })
|
|
2460
|
+
]
|
|
2300
2461
|
}
|
|
2301
|
-
)
|
|
2462
|
+
) : null
|
|
2302
2463
|
]
|
|
2303
|
-
}
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2464
|
+
}
|
|
2465
|
+
),
|
|
2466
|
+
overflowOpen && showOverflowMenu ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles.overflowPanel, overflowPanelStyle], children: remainingOverflowTools.map(
|
|
2467
|
+
(tool) => renderNativeToolButton({
|
|
2468
|
+
tool,
|
|
2469
|
+
value,
|
|
2470
|
+
onChange: (toolId) => {
|
|
2471
|
+
setOverflowOpen(false);
|
|
2472
|
+
onChange(toolId);
|
|
2473
|
+
},
|
|
2474
|
+
disabled,
|
|
2475
|
+
disabledIds,
|
|
2476
|
+
density: "compact",
|
|
2477
|
+
toolButtonStyle: styles.overflowToolButton,
|
|
2478
|
+
activeToolButtonStyle,
|
|
2479
|
+
toolLabelStyle,
|
|
2480
|
+
activeToolLabelStyle,
|
|
2481
|
+
renderToolIcon,
|
|
2482
|
+
renderToolButton
|
|
2483
|
+
})
|
|
2484
|
+
) }) : null
|
|
2485
|
+
]
|
|
2486
|
+
}
|
|
2487
|
+
);
|
|
2488
|
+
}
|
|
2489
|
+
function renderNativeToolButton(input) {
|
|
2490
|
+
const selected = input.tool.id === input.value;
|
|
2491
|
+
const toolDisabled = input.disabled || input.tool.disabled || input.disabledIds.has(input.tool.id);
|
|
2492
|
+
const foregroundColor = "#18181b";
|
|
2493
|
+
const onSelect = () => {
|
|
2494
|
+
if (!toolDisabled) {
|
|
2495
|
+
input.onChange(input.tool.id);
|
|
2307
2496
|
}
|
|
2308
|
-
|
|
2497
|
+
};
|
|
2498
|
+
const renderInput = {
|
|
2499
|
+
tool: input.tool,
|
|
2500
|
+
selected,
|
|
2501
|
+
disabled: toolDisabled,
|
|
2502
|
+
foregroundColor,
|
|
2503
|
+
onSelect
|
|
2504
|
+
};
|
|
2505
|
+
if (input.renderToolButton) {
|
|
2506
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { children: input.renderToolButton(renderInput) }, input.tool.id);
|
|
2507
|
+
}
|
|
2508
|
+
const icon = input.renderToolIcon?.(renderInput) ?? renderNativeToolFallback(input.tool, foregroundColor, input.toolLabelStyle);
|
|
2509
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2510
|
+
reactNative.Pressable,
|
|
2511
|
+
{
|
|
2512
|
+
accessibilityLabel: input.tool.accessibilityLabel ?? tooltipTextForTool(input.tool),
|
|
2513
|
+
accessibilityRole: "button",
|
|
2514
|
+
accessibilityState: { selected, disabled: toolDisabled },
|
|
2515
|
+
disabled: toolDisabled,
|
|
2516
|
+
onPress: onSelect,
|
|
2517
|
+
style: ({ pressed }) => [
|
|
2518
|
+
styles.toolButton,
|
|
2519
|
+
input.density === "comfortable" ? styles.comfortableToolButton : void 0,
|
|
2520
|
+
input.toolButtonStyle,
|
|
2521
|
+
selected ? styles.activeToolButton : void 0,
|
|
2522
|
+
selected ? input.activeToolButtonStyle : void 0,
|
|
2523
|
+
pressed && !toolDisabled ? styles.pressedToolButton : void 0,
|
|
2524
|
+
toolDisabled ? styles.disabledToolButton : void 0
|
|
2525
|
+
],
|
|
2526
|
+
children: [
|
|
2527
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles.iconSlot, children: icon }),
|
|
2528
|
+
input.density === "comfortable" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2529
|
+
reactNative.Text,
|
|
2530
|
+
{
|
|
2531
|
+
numberOfLines: 1,
|
|
2532
|
+
style: [
|
|
2533
|
+
styles.toolLabel,
|
|
2534
|
+
{ color: foregroundColor },
|
|
2535
|
+
input.toolLabelStyle,
|
|
2536
|
+
selected ? input.activeToolLabelStyle : void 0
|
|
2537
|
+
],
|
|
2538
|
+
children: input.tool.label
|
|
2539
|
+
}
|
|
2540
|
+
) : null
|
|
2541
|
+
]
|
|
2542
|
+
},
|
|
2543
|
+
input.tool.id
|
|
2544
|
+
);
|
|
2545
|
+
}
|
|
2546
|
+
function renderNativeToolFallback(tool, foregroundColor, toolLabelStyle) {
|
|
2547
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.shortLabel, { color: foregroundColor }, toolLabelStyle], children: tool.shortLabel ?? tool.label.slice(0, 1).toUpperCase() });
|
|
2309
2548
|
}
|
|
2310
2549
|
var styles = reactNative.StyleSheet.create({
|
|
2311
2550
|
shell: {
|
|
2312
|
-
borderRadius:
|
|
2551
|
+
borderRadius: 8,
|
|
2313
2552
|
borderWidth: reactNative.StyleSheet.hairlineWidth,
|
|
2314
|
-
borderColor: "rgba(
|
|
2315
|
-
backgroundColor: "rgba(255, 255, 255, 0.
|
|
2553
|
+
borderColor: "rgba(0, 0, 0, 0.12)",
|
|
2554
|
+
backgroundColor: "rgba(255, 255, 255, 0.95)",
|
|
2316
2555
|
shadowColor: "#18181b",
|
|
2317
|
-
shadowOpacity: 0.
|
|
2318
|
-
shadowRadius:
|
|
2319
|
-
shadowOffset: { width: 0, height:
|
|
2320
|
-
elevation:
|
|
2556
|
+
shadowOpacity: 0.08,
|
|
2557
|
+
shadowRadius: 3,
|
|
2558
|
+
shadowOffset: { width: 0, height: 1 },
|
|
2559
|
+
elevation: 3
|
|
2321
2560
|
},
|
|
2322
2561
|
content: {
|
|
2323
2562
|
alignItems: "center",
|
|
2324
|
-
gap:
|
|
2325
|
-
paddingHorizontal:
|
|
2563
|
+
gap: 4,
|
|
2564
|
+
paddingHorizontal: 8,
|
|
2326
2565
|
paddingVertical: 6
|
|
2327
2566
|
},
|
|
2567
|
+
comfortableContent: {
|
|
2568
|
+
gap: 6
|
|
2569
|
+
},
|
|
2328
2570
|
toolButton: {
|
|
2329
|
-
minWidth:
|
|
2330
|
-
height:
|
|
2571
|
+
minWidth: 40,
|
|
2572
|
+
height: 40,
|
|
2331
2573
|
alignItems: "center",
|
|
2332
2574
|
justifyContent: "center",
|
|
2333
|
-
gap:
|
|
2334
|
-
borderRadius:
|
|
2575
|
+
gap: 2,
|
|
2576
|
+
borderRadius: 6,
|
|
2335
2577
|
paddingHorizontal: 8,
|
|
2336
2578
|
borderWidth: reactNative.StyleSheet.hairlineWidth,
|
|
2337
2579
|
borderColor: "transparent",
|
|
2338
2580
|
backgroundColor: "transparent"
|
|
2339
2581
|
},
|
|
2582
|
+
comfortableToolButton: {
|
|
2583
|
+
minWidth: 56,
|
|
2584
|
+
height: 48
|
|
2585
|
+
},
|
|
2340
2586
|
activeToolButton: {
|
|
2341
|
-
borderColor: "rgba(24, 24, 27, 0.
|
|
2342
|
-
backgroundColor: "
|
|
2587
|
+
borderColor: "rgba(24, 24, 27, 0.28)",
|
|
2588
|
+
backgroundColor: "rgba(24, 24, 27, 0.1)"
|
|
2343
2589
|
},
|
|
2344
2590
|
pressedToolButton: {
|
|
2345
2591
|
backgroundColor: "rgba(24, 24, 27, 0.08)"
|
|
@@ -2363,6 +2609,76 @@ var styles = reactNative.StyleSheet.create({
|
|
|
2363
2609
|
fontSize: 10,
|
|
2364
2610
|
fontWeight: "600",
|
|
2365
2611
|
lineHeight: 12
|
|
2612
|
+
},
|
|
2613
|
+
toolLockDivider: {
|
|
2614
|
+
width: reactNative.StyleSheet.hairlineWidth,
|
|
2615
|
+
alignSelf: "stretch",
|
|
2616
|
+
backgroundColor: "rgba(24, 24, 27, 0.14)",
|
|
2617
|
+
marginHorizontal: 6,
|
|
2618
|
+
marginVertical: 4
|
|
2619
|
+
},
|
|
2620
|
+
lockGlyph: {
|
|
2621
|
+
color: "#18181b",
|
|
2622
|
+
fontSize: 13,
|
|
2623
|
+
fontWeight: "700",
|
|
2624
|
+
lineHeight: 16
|
|
2625
|
+
},
|
|
2626
|
+
overflowSpacer: {
|
|
2627
|
+
minWidth: 8,
|
|
2628
|
+
flexGrow: 1
|
|
2629
|
+
},
|
|
2630
|
+
overflowTrigger: {
|
|
2631
|
+
minWidth: 48,
|
|
2632
|
+
height: 40,
|
|
2633
|
+
flexDirection: "row",
|
|
2634
|
+
alignItems: "center",
|
|
2635
|
+
justifyContent: "center",
|
|
2636
|
+
gap: 4,
|
|
2637
|
+
borderRadius: 6,
|
|
2638
|
+
paddingHorizontal: 8,
|
|
2639
|
+
borderWidth: reactNative.StyleSheet.hairlineWidth,
|
|
2640
|
+
borderColor: "transparent",
|
|
2641
|
+
backgroundColor: "transparent"
|
|
2642
|
+
},
|
|
2643
|
+
overflowPanel: {
|
|
2644
|
+
position: "absolute",
|
|
2645
|
+
right: 8,
|
|
2646
|
+
bottom: 52,
|
|
2647
|
+
width: 148,
|
|
2648
|
+
flexDirection: "row",
|
|
2649
|
+
flexWrap: "wrap",
|
|
2650
|
+
gap: 6,
|
|
2651
|
+
padding: 10,
|
|
2652
|
+
borderRadius: 10,
|
|
2653
|
+
borderWidth: reactNative.StyleSheet.hairlineWidth,
|
|
2654
|
+
borderColor: "rgba(0, 0, 0, 0.1)",
|
|
2655
|
+
backgroundColor: "rgba(255, 255, 255, 0.98)",
|
|
2656
|
+
shadowColor: "#18181b",
|
|
2657
|
+
shadowOpacity: 0.12,
|
|
2658
|
+
shadowRadius: 24,
|
|
2659
|
+
shadowOffset: { width: 0, height: -4 },
|
|
2660
|
+
elevation: 8
|
|
2661
|
+
},
|
|
2662
|
+
overflowToolButton: {
|
|
2663
|
+
width: 40,
|
|
2664
|
+
minWidth: 40,
|
|
2665
|
+
height: 40,
|
|
2666
|
+
paddingHorizontal: 0,
|
|
2667
|
+
borderRadius: 8,
|
|
2668
|
+
backgroundColor: "rgba(24, 24, 27, 0.05)"
|
|
2669
|
+
},
|
|
2670
|
+
shapesGlyph: {
|
|
2671
|
+
color: "#18181b",
|
|
2672
|
+
fontSize: 17,
|
|
2673
|
+
fontWeight: "700",
|
|
2674
|
+
lineHeight: 20
|
|
2675
|
+
},
|
|
2676
|
+
chevronGlyph: {
|
|
2677
|
+
color: "#18181b",
|
|
2678
|
+
fontSize: 13,
|
|
2679
|
+
fontWeight: "700",
|
|
2680
|
+
lineHeight: 16,
|
|
2681
|
+
opacity: 0.75
|
|
2366
2682
|
}
|
|
2367
2683
|
});
|
|
2368
2684
|
|
|
@@ -2614,9 +2930,11 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
2614
2930
|
items,
|
|
2615
2931
|
selectedIds = [],
|
|
2616
2932
|
toolId = "hand",
|
|
2933
|
+
toolLocked = false,
|
|
2617
2934
|
interactive = false,
|
|
2618
2935
|
onSelectionChange,
|
|
2619
2936
|
onItemsChange,
|
|
2937
|
+
onToolChangeRequest,
|
|
2620
2938
|
onCameraChange,
|
|
2621
2939
|
toolbar
|
|
2622
2940
|
}, ref) {
|
|
@@ -2624,6 +2942,10 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
2624
2942
|
const cameraRef = react.useRef(null);
|
|
2625
2943
|
const toolIdRef = react.useRef(toolId);
|
|
2626
2944
|
toolIdRef.current = toolId;
|
|
2945
|
+
const toolLockedRef = react.useRef(toolLocked);
|
|
2946
|
+
toolLockedRef.current = toolLocked;
|
|
2947
|
+
const onToolChangeRequestRef = react.useRef(onToolChangeRequest);
|
|
2948
|
+
onToolChangeRequestRef.current = onToolChangeRequest;
|
|
2627
2949
|
const onCameraChangeRef = react.useRef(onCameraChange);
|
|
2628
2950
|
onCameraChangeRef.current = onCameraChange;
|
|
2629
2951
|
const onItemsChangeRef = react.useRef(onItemsChange);
|
|
@@ -2639,8 +2961,23 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
2639
2961
|
null
|
|
2640
2962
|
);
|
|
2641
2963
|
const [eraserTrail, setEraserTrail] = react.useState([]);
|
|
2964
|
+
const [laserTrail, setLaserTrail] = react.useState([]);
|
|
2965
|
+
const laserClearTimerRef = react.useRef(null);
|
|
2966
|
+
react.useEffect(
|
|
2967
|
+
() => () => {
|
|
2968
|
+
if (laserClearTimerRef.current) {
|
|
2969
|
+
clearTimeout(laserClearTimerRef.current);
|
|
2970
|
+
}
|
|
2971
|
+
},
|
|
2972
|
+
[]
|
|
2973
|
+
);
|
|
2642
2974
|
const [eraserPreviewIds, setEraserPreviewIds] = react.useState([]);
|
|
2643
2975
|
const eraserPreviewIdSetRef = react.useRef(/* @__PURE__ */ new Set());
|
|
2976
|
+
const requestSelectToolAfterUse = react.useCallback(() => {
|
|
2977
|
+
if (!toolLockedRef.current) {
|
|
2978
|
+
onToolChangeRequestRef.current?.("select");
|
|
2979
|
+
}
|
|
2980
|
+
}, []);
|
|
2644
2981
|
if (!cameraRef.current) {
|
|
2645
2982
|
cameraRef.current = new Camera2D({ minZoom: 0.05, maxZoom: 32 });
|
|
2646
2983
|
}
|
|
@@ -2735,12 +3072,19 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
2735
3072
|
}
|
|
2736
3073
|
return;
|
|
2737
3074
|
}
|
|
2738
|
-
if (tool === "draw" || tool === "marker") {
|
|
3075
|
+
if (tool === "draw" || tool === "marker" || tool === "laser") {
|
|
2739
3076
|
dragStateRef.current = {
|
|
2740
3077
|
kind: "draw",
|
|
2741
3078
|
tool,
|
|
2742
3079
|
points: [{ x: worldX, y: worldY }]
|
|
2743
3080
|
};
|
|
3081
|
+
if (tool === "laser") {
|
|
3082
|
+
if (laserClearTimerRef.current) {
|
|
3083
|
+
clearTimeout(laserClearTimerRef.current);
|
|
3084
|
+
laserClearTimerRef.current = null;
|
|
3085
|
+
}
|
|
3086
|
+
setLaserTrail([{ x: worldX, y: worldY }]);
|
|
3087
|
+
}
|
|
2744
3088
|
return;
|
|
2745
3089
|
}
|
|
2746
3090
|
if (tool === "eraser") {
|
|
@@ -2841,11 +3185,15 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
2841
3185
|
if (Math.hypot(dx, dy) > 0.5 / cam.zoom) {
|
|
2842
3186
|
pts.push({ x: worldX, y: worldY });
|
|
2843
3187
|
}
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
3188
|
+
if (st.tool === "laser") {
|
|
3189
|
+
setLaserTrail([...pts]);
|
|
3190
|
+
} else {
|
|
3191
|
+
setPlacementPreview({
|
|
3192
|
+
kind: "stroke",
|
|
3193
|
+
tool: st.tool,
|
|
3194
|
+
points: [...pts]
|
|
3195
|
+
});
|
|
3196
|
+
}
|
|
2849
3197
|
return;
|
|
2850
3198
|
}
|
|
2851
3199
|
if (st.kind === "move") {
|
|
@@ -2913,6 +3261,17 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
2913
3261
|
if (st.kind === "draw") {
|
|
2914
3262
|
dragStateRef.current = { kind: "idle" };
|
|
2915
3263
|
setPlacementPreview(null);
|
|
3264
|
+
if (st.tool === "laser") {
|
|
3265
|
+
if (laserClearTimerRef.current) {
|
|
3266
|
+
clearTimeout(laserClearTimerRef.current);
|
|
3267
|
+
}
|
|
3268
|
+
laserClearTimerRef.current = setTimeout(() => {
|
|
3269
|
+
setLaserTrail([]);
|
|
3270
|
+
laserClearTimerRef.current = null;
|
|
3271
|
+
}, 650);
|
|
3272
|
+
requestSelectToolAfterUse();
|
|
3273
|
+
return;
|
|
3274
|
+
}
|
|
2916
3275
|
if (st.points.length < 1) return;
|
|
2917
3276
|
const change = onItemsChangeRef.current;
|
|
2918
3277
|
if (!change) return;
|
|
@@ -2921,6 +3280,7 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
2921
3280
|
if (item) {
|
|
2922
3281
|
change([...itemsRef.current, item]);
|
|
2923
3282
|
}
|
|
3283
|
+
requestSelectToolAfterUse();
|
|
2924
3284
|
return;
|
|
2925
3285
|
}
|
|
2926
3286
|
if (st.kind === "move") {
|
|
@@ -2958,6 +3318,7 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
2958
3318
|
setEraserPreviewIds([]);
|
|
2959
3319
|
setEraserTrail([]);
|
|
2960
3320
|
dragStateRef.current = { kind: "idle" };
|
|
3321
|
+
requestSelectToolAfterUse();
|
|
2961
3322
|
return;
|
|
2962
3323
|
}
|
|
2963
3324
|
if (st.kind === "place") {
|
|
@@ -2995,21 +3356,25 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
2995
3356
|
if (st.tool === "rect") {
|
|
2996
3357
|
change([...itemsRef.current, createRectangleItem(id, raw)]);
|
|
2997
3358
|
onSelectionChangeRef.current?.([id]);
|
|
3359
|
+
requestSelectToolAfterUse();
|
|
2998
3360
|
return;
|
|
2999
3361
|
}
|
|
3000
3362
|
if (st.tool === "ellipse") {
|
|
3001
3363
|
change([...itemsRef.current, createEllipseItem(id, raw)]);
|
|
3002
3364
|
onSelectionChangeRef.current?.([id]);
|
|
3365
|
+
requestSelectToolAfterUse();
|
|
3003
3366
|
return;
|
|
3004
3367
|
}
|
|
3005
3368
|
if (st.tool === "architectural-cloud") {
|
|
3006
3369
|
change([...itemsRef.current, createArchitecturalCloudItem(id, raw)]);
|
|
3007
3370
|
onSelectionChangeRef.current?.([id]);
|
|
3371
|
+
requestSelectToolAfterUse();
|
|
3008
3372
|
return;
|
|
3009
3373
|
}
|
|
3010
3374
|
const line = lineEndpointsToLocal(br, lineStart, lineEnd);
|
|
3011
3375
|
change([...itemsRef.current, createLineItem(id, br, line, st.tool)]);
|
|
3012
3376
|
onSelectionChangeRef.current?.([id]);
|
|
3377
|
+
requestSelectToolAfterUse();
|
|
3013
3378
|
return;
|
|
3014
3379
|
}
|
|
3015
3380
|
if (st.kind === "tap") {
|
|
@@ -3035,6 +3400,7 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
3035
3400
|
);
|
|
3036
3401
|
change([...itemsRef.current, item]);
|
|
3037
3402
|
onSelectionChangeRef.current?.([id]);
|
|
3403
|
+
requestSelectToolAfterUse();
|
|
3038
3404
|
}
|
|
3039
3405
|
if (st.tool === "note") {
|
|
3040
3406
|
const id = createShapeId();
|
|
@@ -3053,6 +3419,7 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
3053
3419
|
};
|
|
3054
3420
|
change([...itemsRef.current, note]);
|
|
3055
3421
|
onSelectionChangeRef.current?.([id]);
|
|
3422
|
+
requestSelectToolAfterUse();
|
|
3056
3423
|
}
|
|
3057
3424
|
return;
|
|
3058
3425
|
}
|
|
@@ -3063,9 +3430,10 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
3063
3430
|
lastPanPoint.current = null;
|
|
3064
3431
|
dragStateRef.current = { kind: "idle" };
|
|
3065
3432
|
setPlacementPreview(null);
|
|
3433
|
+
setLaserTrail([]);
|
|
3066
3434
|
}
|
|
3067
3435
|
}),
|
|
3068
|
-
[screenToWorld, requestRender, interactive]
|
|
3436
|
+
[screenToWorld, requestRender, requestSelectToolAfterUse, interactive]
|
|
3069
3437
|
);
|
|
3070
3438
|
react.useImperativeHandle(
|
|
3071
3439
|
ref,
|
|
@@ -3113,6 +3481,7 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
3113
3481
|
selectedItems,
|
|
3114
3482
|
showResizeHandles,
|
|
3115
3483
|
placementPreview,
|
|
3484
|
+
laserTrail,
|
|
3116
3485
|
eraserTrail,
|
|
3117
3486
|
eraserPreviewItems: items.filter(
|
|
3118
3487
|
(it) => eraserPreviewIds.includes(it.id)
|
|
@@ -3140,6 +3509,7 @@ var NativeVectorViewport = react.forwardRef(function NativeVectorViewport2({
|
|
|
3140
3509
|
);
|
|
3141
3510
|
});
|
|
3142
3511
|
|
|
3512
|
+
exports.DEFAULT_NATIVE_OVERFLOW_TOOL_IDS = DEFAULT_NATIVE_OVERFLOW_TOOL_IDS;
|
|
3143
3513
|
exports.DEFAULT_NATIVE_VECTOR_TOOLS = DEFAULT_NATIVE_VECTOR_TOOLS;
|
|
3144
3514
|
exports.NativeInteractionOverlay = NativeInteractionOverlay;
|
|
3145
3515
|
exports.NativeSceneRenderer = NativeSceneRenderer;
|
|
@@ -3147,6 +3517,7 @@ exports.NativeShapeRenderer = NativeShapeRenderer;
|
|
|
3147
3517
|
exports.NativeVectorToolbar = NativeVectorToolbar;
|
|
3148
3518
|
exports.NativeVectorViewport = NativeVectorViewport;
|
|
3149
3519
|
exports.createFreehandStrokeItem = createFreehandStrokeItem;
|
|
3520
|
+
exports.createImageItem = createImageItem;
|
|
3150
3521
|
exports.createShapeId = createShapeId;
|
|
3151
3522
|
exports.parseSvgFragment = parseSvgFragment;
|
|
3152
3523
|
//# sourceMappingURL=native.cjs.map
|