canvu-react 0.3.38 → 0.3.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{asset-hydration-EtEuBwb7.d.cts → asset-hydration-B7yMDQE-.d.cts} +2 -2
- package/dist/{asset-hydration-DrTOgDdd.d.ts → asset-hydration-CbwQVAwh.d.ts} +2 -2
- package/dist/{camera-Di5R_Rwl.d.cts → camera-CVVG7z56.d.cts} +1 -1
- package/dist/{camera-AoTwBSoE.d.ts → camera-CoRYN_IV.d.ts} +1 -1
- package/dist/chatbot.d.cts +4 -4
- package/dist/chatbot.d.ts +4 -4
- package/dist/index.cjs +164 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +159 -16
- package/dist/index.js.map +1 -1
- package/dist/native.cjs +57 -14
- package/dist/native.cjs.map +1 -1
- package/dist/native.d.cts +2 -2
- package/dist/native.d.ts +2 -2
- package/dist/native.js +57 -14
- package/dist/native.js.map +1 -1
- package/dist/react.cjs +731 -258
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +10 -10
- package/dist/react.d.ts +10 -10
- package/dist/react.js +731 -258
- package/dist/react.js.map +1 -1
- package/dist/realtime.cjs +36 -0
- package/dist/realtime.cjs.map +1 -1
- package/dist/realtime.d.cts +6 -6
- package/dist/realtime.d.ts +6 -6
- package/dist/realtime.js +36 -0
- package/dist/realtime.js.map +1 -1
- package/dist/{shape-builders-CsbSRZnQ.d.cts → shape-builders-BAWu-PxX.d.cts} +46 -4
- package/dist/{shape-builders-CsSXKCcs.d.ts → shape-builders-ClKv9tz9.d.ts} +46 -4
- package/dist/tldraw.cjs +189 -78
- package/dist/tldraw.cjs.map +1 -1
- package/dist/tldraw.d.cts +1 -1
- package/dist/tldraw.d.ts +1 -1
- package/dist/tldraw.js +189 -78
- package/dist/tldraw.js.map +1 -1
- package/dist/{types-DWGk2_GZ.d.cts → types-BC9Xgfu6.d.cts} +20 -6
- package/dist/{types-Bnq2HtHQ.d.cts → types-BCCvY6ie.d.cts} +2 -0
- package/dist/{types-Bnq2HtHQ.d.ts → types-BCCvY6ie.d.ts} +2 -0
- package/dist/{types-B2Na677H.d.cts → types-BUPc2Zgw.d.cts} +1 -1
- package/dist/{types-zmUah-vP.d.ts → types-CYtq9Pr9.d.ts} +1 -1
- package/dist/{types-B6PAYKzx.d.ts → types-DlSVGX0w.d.ts} +20 -6
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { V as VectorSceneItem } from './types-
|
|
2
|
-
import {
|
|
1
|
+
import { V as VectorSceneItem } from './types-BCCvY6ie.cjs';
|
|
2
|
+
import { E as VectorViewportAssetStore } from './shape-builders-BAWu-PxX.cjs';
|
|
3
3
|
|
|
4
4
|
declare class IndexedDbImageStore {
|
|
5
5
|
private dbPromise;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { V as VectorSceneItem } from './types-
|
|
2
|
-
import {
|
|
1
|
+
import { V as VectorSceneItem } from './types-BCCvY6ie.js';
|
|
2
|
+
import { E as VectorViewportAssetStore } from './shape-builders-ClKv9tz9.js';
|
|
3
3
|
|
|
4
4
|
declare class IndexedDbImageStore {
|
|
5
5
|
private dbPromise;
|
package/dist/chatbot.d.cts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { C as CanvasPlugin } from './types-
|
|
2
|
+
import { C as CanvasPlugin } from './types-BC9Xgfu6.cjs';
|
|
3
3
|
import 'react';
|
|
4
|
-
import './types-
|
|
5
|
-
import './camera-
|
|
6
|
-
import './shape-builders-
|
|
4
|
+
import './types-BCCvY6ie.cjs';
|
|
5
|
+
import './camera-CVVG7z56.cjs';
|
|
6
|
+
import './shape-builders-BAWu-PxX.cjs';
|
|
7
7
|
|
|
8
8
|
type ChatbotPluginPanelProps = {
|
|
9
9
|
/**
|
package/dist/chatbot.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { C as CanvasPlugin } from './types-
|
|
2
|
+
import { C as CanvasPlugin } from './types-DlSVGX0w.js';
|
|
3
3
|
import 'react';
|
|
4
|
-
import './types-
|
|
5
|
-
import './camera-
|
|
6
|
-
import './shape-builders-
|
|
4
|
+
import './types-BCCvY6ie.js';
|
|
5
|
+
import './camera-CoRYN_IV.js';
|
|
6
|
+
import './shape-builders-ClKv9tz9.js';
|
|
7
7
|
|
|
8
8
|
type ChatbotPluginPanelProps = {
|
|
9
9
|
/**
|
package/dist/index.cjs
CHANGED
|
@@ -998,11 +998,14 @@ function escapeHtmlText(s) {
|
|
|
998
998
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
999
999
|
}
|
|
1000
1000
|
var DEFAULT_TEXT_FONT_SIZE = 18;
|
|
1001
|
+
var TEXT_FONT_FAMILY = "Inter, -apple-system, BlinkMacSystemFont, ui-sans-serif, system-ui, sans-serif";
|
|
1001
1002
|
var LINE_HEIGHT_RATIO = 22 / 18;
|
|
1002
|
-
var FIRST_LINE_BASELINE_RATIO =
|
|
1003
|
+
var FIRST_LINE_BASELINE_RATIO = 20 / 18;
|
|
1004
|
+
var EDIT_TOP_PAD_RATIO = 4 / 18;
|
|
1005
|
+
var BOTTOM_PAD_RATIO = 4 / 18;
|
|
1003
1006
|
var PLACEHOLDER = "Tap to type";
|
|
1004
1007
|
var MIN_TEXT_BOX_W = 40;
|
|
1005
|
-
var MIN_TEXT_BOX_H =
|
|
1008
|
+
var MIN_TEXT_BOX_H = 26;
|
|
1006
1009
|
var TEXT_PAD_X = 4;
|
|
1007
1010
|
var MAX_TEXT_MEASURE_CACHE_ENTRIES = 2e3;
|
|
1008
1011
|
var sharedMeasureContext;
|
|
@@ -1048,7 +1051,7 @@ function measureTextBoundsLocal(content, fontSize = DEFAULT_TEXT_FONT_SIZE) {
|
|
|
1048
1051
|
let maxInnerW = 0;
|
|
1049
1052
|
const ctx = getSharedMeasureContext();
|
|
1050
1053
|
if (ctx) {
|
|
1051
|
-
ctx.font = `${fontSize}px
|
|
1054
|
+
ctx.font = `${fontSize}px ${TEXT_FONT_FAMILY}`;
|
|
1052
1055
|
for (const line of lines) {
|
|
1053
1056
|
const toMeasure = trimmed.length === 0 ? PLACEHOLDER : line.length === 0 ? " " : line;
|
|
1054
1057
|
maxInnerW = Math.max(maxInnerW, ctx.measureText(toMeasure).width);
|
|
@@ -1064,22 +1067,22 @@ function measureTextBoundsLocal(content, fontSize = DEFAULT_TEXT_FONT_SIZE) {
|
|
|
1064
1067
|
const width = Math.max(minW, TEXT_PAD_X * 2 + maxInnerW);
|
|
1065
1068
|
const height = Math.max(
|
|
1066
1069
|
MIN_TEXT_BOX_H,
|
|
1067
|
-
baselineY + (lines.length - 1) * lh + Math.max(
|
|
1070
|
+
baselineY + (lines.length - 1) * lh + Math.max(4, fontSize * BOTTOM_PAD_RATIO)
|
|
1068
1071
|
);
|
|
1069
1072
|
const measured = { width, height };
|
|
1070
1073
|
cacheMeasuredBounds(cacheKey, measured);
|
|
1071
1074
|
return measured;
|
|
1072
1075
|
}
|
|
1073
|
-
function buildTextSvg(content, _width, _height, fillColor = "#
|
|
1076
|
+
function buildTextSvg(content, _width, _height, fillColor = "#1d1d1d", fontSize = DEFAULT_TEXT_FONT_SIZE) {
|
|
1074
1077
|
const lh = lineHeightFor(fontSize);
|
|
1075
1078
|
const y0 = firstLineBaselineY(fontSize);
|
|
1076
1079
|
const trimmed = content.trim();
|
|
1077
1080
|
if (trimmed.length === 0) {
|
|
1078
|
-
return `<text x="4" y="${y0}" font-size="${fontSize}" font-family="
|
|
1081
|
+
return `<text x="4" y="${y0}" font-size="${fontSize}" font-family="${TEXT_FONT_FAMILY}" fill="#94a3b8" font-style="italic">${escapeSvgTextContent(PLACEHOLDER)}</text>`;
|
|
1079
1082
|
}
|
|
1080
1083
|
const lines = content.split("\n");
|
|
1081
1084
|
if (lines.length === 1) {
|
|
1082
|
-
return `<text x="4" y="${y0}" font-size="${fontSize}" font-family="
|
|
1085
|
+
return `<text x="4" y="${y0}" font-size="${fontSize}" font-family="${TEXT_FONT_FAMILY}" fill="${fillColor}">${escapeSvgTextContent(lines[0] ?? "")}</text>`;
|
|
1083
1086
|
}
|
|
1084
1087
|
const parts = [];
|
|
1085
1088
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -1090,23 +1093,24 @@ function buildTextSvg(content, _width, _height, fillColor = "#2563eb", fontSize
|
|
|
1090
1093
|
parts.push(`<tspan x="4" dy="${lh}">${escapeSvgTextContent(line)}</tspan>`);
|
|
1091
1094
|
}
|
|
1092
1095
|
}
|
|
1093
|
-
return `<text x="4" y="${y0}" font-size="${fontSize}" font-family="
|
|
1096
|
+
return `<text x="4" y="${y0}" font-size="${fontSize}" font-family="${TEXT_FONT_FAMILY}" fill="${fillColor}">${parts.join("")}</text>`;
|
|
1094
1097
|
}
|
|
1095
|
-
function buildTextFixedBoundsSvg(content, width, height, fillColor = "#
|
|
1098
|
+
function buildTextFixedBoundsSvg(content, width, height, fillColor = "#1d1d1d", fontSize = DEFAULT_TEXT_FONT_SIZE) {
|
|
1096
1099
|
const w = Math.max(1, width);
|
|
1097
1100
|
const h = Math.max(1, height);
|
|
1098
1101
|
const lh = lineHeightFor(fontSize);
|
|
1099
1102
|
const trimmed = content.trim();
|
|
1103
|
+
const padTop = EDIT_TOP_PAD_RATIO * fontSize;
|
|
1100
1104
|
if (trimmed.length === 0) {
|
|
1101
|
-
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
|
|
1105
|
+
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>`;
|
|
1102
1106
|
}
|
|
1103
1107
|
const body = escapeHtmlText(content);
|
|
1104
|
-
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
|
|
1108
|
+
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>`;
|
|
1105
1109
|
}
|
|
1106
1110
|
|
|
1107
1111
|
// src/scene/shape-builders.ts
|
|
1108
1112
|
var DEFAULT_STROKE_STYLE = {
|
|
1109
|
-
stroke: "#
|
|
1113
|
+
stroke: "#1d1d1d",
|
|
1110
1114
|
strokeWidth: 2
|
|
1111
1115
|
};
|
|
1112
1116
|
var TOOL_FREEHAND_DEFAULTS = {
|
|
@@ -1163,7 +1167,8 @@ function resolveStrokeStyle(item) {
|
|
|
1163
1167
|
return {
|
|
1164
1168
|
stroke: item.stroke ?? DEFAULT_STROKE_STYLE.stroke,
|
|
1165
1169
|
strokeWidth: item.strokeWidth ?? DEFAULT_STROKE_STYLE.strokeWidth,
|
|
1166
|
-
strokeOpacity: item.strokeOpacity
|
|
1170
|
+
strokeOpacity: item.strokeOpacity,
|
|
1171
|
+
strokeDash: item.strokeDash
|
|
1167
1172
|
};
|
|
1168
1173
|
}
|
|
1169
1174
|
function strokeOpacityAttr(style) {
|
|
@@ -1492,6 +1497,30 @@ function buildDrawDotSvg(r, style = DEFAULT_STROKE_STYLE) {
|
|
|
1492
1497
|
const op = style.strokeOpacity != null ? ` fill-opacity="${style.strokeOpacity}"` : "";
|
|
1493
1498
|
return `<circle cx="${r}" cy="${r}" r="${r}" fill="${style.stroke}" shape-rendering="geometricPrecision"${op} />`;
|
|
1494
1499
|
}
|
|
1500
|
+
function dashArrayForDrawStroke(strokeWidth) {
|
|
1501
|
+
const dash = Math.max(strokeWidth * 1.8, 4);
|
|
1502
|
+
const gap = Math.max(strokeWidth * 1.4, 3);
|
|
1503
|
+
return `${dash} ${gap}`;
|
|
1504
|
+
}
|
|
1505
|
+
function buildSmoothedCenterlinePath(points) {
|
|
1506
|
+
if (points.length < 2) return null;
|
|
1507
|
+
const first = points[0];
|
|
1508
|
+
if (!first) return null;
|
|
1509
|
+
let d = `M ${first.x} ${first.y}`;
|
|
1510
|
+
for (let i = 1; i < points.length - 1; i++) {
|
|
1511
|
+
const a = points[i];
|
|
1512
|
+
const b = points[i + 1];
|
|
1513
|
+
if (!a || !b) continue;
|
|
1514
|
+
const midX = (a.x + b.x) / 2;
|
|
1515
|
+
const midY = (a.y + b.y) / 2;
|
|
1516
|
+
d += ` Q ${a.x} ${a.y} ${midX} ${midY}`;
|
|
1517
|
+
}
|
|
1518
|
+
const last = points[points.length - 1];
|
|
1519
|
+
if (last) {
|
|
1520
|
+
d += ` L ${last.x} ${last.y}`;
|
|
1521
|
+
}
|
|
1522
|
+
return d;
|
|
1523
|
+
}
|
|
1495
1524
|
function computeFreehandSvgPayload(pathPointsLocal, style, toolKind, strokeComplete = true) {
|
|
1496
1525
|
if (pathPointsLocal.length === 0) return null;
|
|
1497
1526
|
if (pathPointsLocal.length === 1) {
|
|
@@ -1506,6 +1535,18 @@ function computeFreehandSvgPayload(pathPointsLocal, style, toolKind, strokeCompl
|
|
|
1506
1535
|
fillOpacity: style.strokeOpacity
|
|
1507
1536
|
};
|
|
1508
1537
|
}
|
|
1538
|
+
if (style.strokeDash === "dashed" && (toolKind === "draw" || toolKind === "pencil")) {
|
|
1539
|
+
const d2 = buildSmoothedCenterlinePath(pathPointsLocal);
|
|
1540
|
+
if (!d2) return null;
|
|
1541
|
+
return {
|
|
1542
|
+
kind: "strokePath",
|
|
1543
|
+
d: d2,
|
|
1544
|
+
stroke: style.stroke,
|
|
1545
|
+
strokeWidth: style.strokeWidth,
|
|
1546
|
+
strokeOpacity: style.strokeOpacity,
|
|
1547
|
+
strokeDasharray: dashArrayForDrawStroke(style.strokeWidth)
|
|
1548
|
+
};
|
|
1549
|
+
}
|
|
1509
1550
|
const hasPressure = pathPointsLocal.some(
|
|
1510
1551
|
(p) => p.pressure != null && Number.isFinite(p.pressure)
|
|
1511
1552
|
);
|
|
@@ -1548,7 +1589,8 @@ function freehandPayloadToSvgString(payload) {
|
|
|
1548
1589
|
strokeWidth: payload.strokeWidth,
|
|
1549
1590
|
strokeOpacity: payload.strokeOpacity
|
|
1550
1591
|
});
|
|
1551
|
-
|
|
1592
|
+
const dash = payload.strokeDasharray ? ` stroke-dasharray="${payload.strokeDasharray}"` : "";
|
|
1593
|
+
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} />`;
|
|
1552
1594
|
}
|
|
1553
1595
|
function buildFreehandPathSvg(pathPointsLocal, style, toolKind, strokeComplete = true) {
|
|
1554
1596
|
const payload = computeFreehandSvgPayload(
|
|
@@ -1760,7 +1802,7 @@ function createDrawDotItem(id, worldX, worldY, radius, style) {
|
|
|
1760
1802
|
childrenSvg: ""
|
|
1761
1803
|
});
|
|
1762
1804
|
}
|
|
1763
|
-
function createTextItem(id, bounds, text = "", style) {
|
|
1805
|
+
function createTextItem(id, bounds, text = "", style, textFontSize) {
|
|
1764
1806
|
const r = normalizeRect(bounds);
|
|
1765
1807
|
const s = { ...DEFAULT_STROKE_STYLE, ...style };
|
|
1766
1808
|
return rebuildItemSvg({
|
|
@@ -1773,6 +1815,7 @@ function createTextItem(id, bounds, text = "", style) {
|
|
|
1773
1815
|
stroke: s.stroke,
|
|
1774
1816
|
strokeWidth: s.strokeWidth,
|
|
1775
1817
|
...s.strokeOpacity != null ? { strokeOpacity: s.strokeOpacity } : {},
|
|
1818
|
+
...textFontSize != null ? { textFontSize } : {},
|
|
1776
1819
|
childrenSvg: ""
|
|
1777
1820
|
});
|
|
1778
1821
|
}
|
|
@@ -1809,6 +1852,7 @@ function createFreehandStrokeItem(id, pointsWorld, toolKind, style) {
|
|
|
1809
1852
|
stroke: merged.stroke,
|
|
1810
1853
|
strokeWidth: merged.strokeWidth,
|
|
1811
1854
|
...merged.strokeOpacity != null ? { strokeOpacity: merged.strokeOpacity } : {},
|
|
1855
|
+
...merged.strokeDash != null ? { strokeDash: merged.strokeDash } : {},
|
|
1812
1856
|
pathPointsLocal,
|
|
1813
1857
|
childrenSvg: ""
|
|
1814
1858
|
});
|
|
@@ -2761,6 +2805,105 @@ function cloneVectorSceneItemsWithNewIds(items) {
|
|
|
2761
2805
|
return items.map(cloneVectorSceneItemWithNewId);
|
|
2762
2806
|
}
|
|
2763
2807
|
|
|
2808
|
+
// src/scene/link-item.ts
|
|
2809
|
+
var LINK_PLUGIN_KEY = "canvuLink";
|
|
2810
|
+
var DEFAULT_LINK_CARD_WIDTH = 360;
|
|
2811
|
+
var DEFAULT_LINK_CARD_HEIGHT = 132;
|
|
2812
|
+
var LINK_CARD_BORDER = "#e2e8f0";
|
|
2813
|
+
var LINK_CARD_ACCENT = "#2563eb";
|
|
2814
|
+
var LINK_CARD_TITLE_COLOR = "#0f172a";
|
|
2815
|
+
var LINK_CARD_TEXT_COLOR = "#475569";
|
|
2816
|
+
var clamp = (value, min, max) => Math.min(max, Math.max(min, value));
|
|
2817
|
+
var formatNumber = (value) => {
|
|
2818
|
+
const rounded = Math.round(value * 100) / 100;
|
|
2819
|
+
return Object.is(rounded, -0) ? "0" : String(rounded);
|
|
2820
|
+
};
|
|
2821
|
+
var escapeXmlAttribute = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
2822
|
+
var escapeHtmlText2 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
2823
|
+
var getLinkHostname = (href) => {
|
|
2824
|
+
try {
|
|
2825
|
+
return new URL(href).hostname.replace(/^www\./, "");
|
|
2826
|
+
} catch {
|
|
2827
|
+
return href;
|
|
2828
|
+
}
|
|
2829
|
+
};
|
|
2830
|
+
var buildLinkTextBand = (band) => {
|
|
2831
|
+
const lineHeight = band.fontSize * 1.3;
|
|
2832
|
+
const weight = band.fontWeight != null ? `font-weight:${band.fontWeight};` : "";
|
|
2833
|
+
const lineClampStyle = band.clampLines ? `display:-webkit-box;-webkit-line-clamp:${band.clampLines};-webkit-box-orient:vertical;` : "";
|
|
2834
|
+
return `<foreignObject x="${formatNumber(band.x)}" y="${formatNumber(band.y)}" width="${formatNumber(Math.max(1, band.width))}" height="${formatNumber(Math.max(1, band.height))}"><div xmlns="http://www.w3.org/1999/xhtml" style="box-sizing:border-box;width:100%;height:100%;margin:0;font-family:system-ui,sans-serif;font-size:${formatNumber(band.fontSize)}px;line-height:${formatNumber(lineHeight)}px;color:${band.color};overflow:hidden;word-break:break-word;${lineClampStyle}${weight}">${escapeHtmlText2(band.text)}</div></foreignObject>`;
|
|
2835
|
+
};
|
|
2836
|
+
function buildLinkCardSvg(width, height, link) {
|
|
2837
|
+
const cardWidth = Math.max(1, width);
|
|
2838
|
+
const cardHeight = Math.max(1, height);
|
|
2839
|
+
const padding = 14;
|
|
2840
|
+
const badgeSize = clamp(Math.min(72, cardHeight - padding * 2), 28, 96);
|
|
2841
|
+
const textX = padding + badgeSize + 14;
|
|
2842
|
+
const textWidth = Math.max(1, cardWidth - textX - padding);
|
|
2843
|
+
const hostname = getLinkHostname(link.href);
|
|
2844
|
+
const title = link.title?.trim() || hostname || "Link";
|
|
2845
|
+
const description = link.description?.trim() || link.href;
|
|
2846
|
+
const titleY = padding;
|
|
2847
|
+
const titleHeight = clamp(cardHeight * 0.22, 18, 28);
|
|
2848
|
+
const hostY = titleY + titleHeight + 2;
|
|
2849
|
+
const hostHeight = 16;
|
|
2850
|
+
const descY = hostY + hostHeight + 4;
|
|
2851
|
+
const descHeight = Math.max(1, cardHeight - descY - padding);
|
|
2852
|
+
const badge = link.favicon ? `<clipPath id="canvu-link-badge"><rect x="${formatNumber(padding)}" y="${formatNumber(padding)}" width="${formatNumber(badgeSize)}" height="${formatNumber(badgeSize)}" rx="12" /></clipPath>
|
|
2853
|
+
<rect x="${formatNumber(padding)}" y="${formatNumber(padding)}" width="${formatNumber(badgeSize)}" height="${formatNumber(badgeSize)}" rx="12" fill="#f8fafc" stroke="${LINK_CARD_BORDER}" stroke-width="1" />
|
|
2854
|
+
<image href="${escapeXmlAttribute(link.favicon)}" x="${formatNumber(padding)}" y="${formatNumber(padding)}" width="${formatNumber(badgeSize)}" height="${formatNumber(badgeSize)}" preserveAspectRatio="xMidYMid slice" clip-path="url(#canvu-link-badge)" />` : `<rect x="${formatNumber(padding)}" y="${formatNumber(padding)}" width="${formatNumber(badgeSize)}" height="${formatNumber(badgeSize)}" rx="12" fill="${LINK_CARD_ACCENT}" fill-opacity="0.1" stroke="${LINK_CARD_ACCENT}" stroke-opacity="0.3" stroke-width="1" />
|
|
2855
|
+
<g transform="translate(${formatNumber(padding + badgeSize / 2)},${formatNumber(padding + badgeSize / 2)})" stroke="${LINK_CARD_ACCENT}" stroke-width="2.4" stroke-linecap="round" fill="none">
|
|
2856
|
+
<path d="M-9 3 a6 6 0 0 1 0 -8 l4 -4 a6 6 0 0 1 8 8 l-2 2" />
|
|
2857
|
+
<path d="M9 -3 a6 6 0 0 1 0 8 l-4 4 a6 6 0 0 1 -8 -8 l2 -2" />
|
|
2858
|
+
</g>`;
|
|
2859
|
+
const externalIconX = cardWidth - padding - 16;
|
|
2860
|
+
const externalIcon = `<g transform="translate(${formatNumber(externalIconX)},${formatNumber(padding)})" stroke="${LINK_CARD_TEXT_COLOR}" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" fill="none">
|
|
2861
|
+
<path d="M6 1 H11 V6" />
|
|
2862
|
+
<path d="M11 1 L4.5 7.5" />
|
|
2863
|
+
<path d="M9 7 V10 a1 1 0 0 1 -1 1 H2 a1 1 0 0 1 -1 -1 V4 a1 1 0 0 1 1 -1 H5" />
|
|
2864
|
+
</g>`;
|
|
2865
|
+
return `
|
|
2866
|
+
<rect width="${formatNumber(cardWidth)}" height="${formatNumber(cardHeight)}" rx="16" fill="#ffffff" stroke="${LINK_CARD_BORDER}" stroke-width="1.5" />
|
|
2867
|
+
${badge}
|
|
2868
|
+
${externalIcon}
|
|
2869
|
+
${buildLinkTextBand({ x: textX, y: titleY, width: textWidth - 18, height: titleHeight, text: title, fontSize: 15, color: LINK_CARD_TITLE_COLOR, fontWeight: 700, clampLines: 1 })}
|
|
2870
|
+
${buildLinkTextBand({ x: textX, y: hostY, width: textWidth, height: hostHeight, text: hostname, fontSize: 12, color: LINK_CARD_ACCENT, clampLines: 1 })}
|
|
2871
|
+
${buildLinkTextBand({ x: textX, y: descY, width: textWidth, height: descHeight, text: description, fontSize: 12, color: LINK_CARD_TEXT_COLOR, clampLines: 2 })}
|
|
2872
|
+
`;
|
|
2873
|
+
}
|
|
2874
|
+
var isCanvuLinkData = (value) => {
|
|
2875
|
+
if (!value || typeof value !== "object") return false;
|
|
2876
|
+
const candidate = value;
|
|
2877
|
+
return typeof candidate.href === "string" && candidate.href.length > 0;
|
|
2878
|
+
};
|
|
2879
|
+
function getLinkData(item) {
|
|
2880
|
+
const entry = item.pluginData?.[LINK_PLUGIN_KEY];
|
|
2881
|
+
return isCanvuLinkData(entry) ? entry : null;
|
|
2882
|
+
}
|
|
2883
|
+
function isLinkItem(item) {
|
|
2884
|
+
return getLinkData(item) != null;
|
|
2885
|
+
}
|
|
2886
|
+
function createLinkItem(id, bounds, link) {
|
|
2887
|
+
const width = bounds.width || DEFAULT_LINK_CARD_WIDTH;
|
|
2888
|
+
const height = bounds.height || DEFAULT_LINK_CARD_HEIGHT;
|
|
2889
|
+
const item = createCustomShapeItem(
|
|
2890
|
+
id,
|
|
2891
|
+
{ ...bounds, width, height },
|
|
2892
|
+
{ render: (size) => buildLinkCardSvg(size.width, size.height, link) }
|
|
2893
|
+
);
|
|
2894
|
+
return {
|
|
2895
|
+
...item,
|
|
2896
|
+
pluginData: {
|
|
2897
|
+
...item.pluginData ?? {},
|
|
2898
|
+
[LINK_PLUGIN_KEY]: link
|
|
2899
|
+
}
|
|
2900
|
+
};
|
|
2901
|
+
}
|
|
2902
|
+
var DEFAULT_LINK_CARD_SIZE = {
|
|
2903
|
+
width: DEFAULT_LINK_CARD_WIDTH,
|
|
2904
|
+
height: DEFAULT_LINK_CARD_HEIGHT
|
|
2905
|
+
};
|
|
2906
|
+
|
|
2764
2907
|
// src/scene/managed-images.ts
|
|
2765
2908
|
var MANAGED_KEY = "managed";
|
|
2766
2909
|
var STACK_GAP_WORLD = 16;
|
|
@@ -2865,8 +3008,10 @@ var VectorScene = class {
|
|
|
2865
3008
|
|
|
2866
3009
|
exports.ARROW_BIND_SNAP_PX = ARROW_BIND_SNAP_PX;
|
|
2867
3010
|
exports.Camera2D = Camera2D;
|
|
3011
|
+
exports.DEFAULT_LINK_CARD_SIZE = DEFAULT_LINK_CARD_SIZE;
|
|
2868
3012
|
exports.DEFAULT_STROKE_STYLE = DEFAULT_STROKE_STYLE;
|
|
2869
3013
|
exports.DEFAULT_TEXT_FONT_SIZE = DEFAULT_TEXT_FONT_SIZE;
|
|
3014
|
+
exports.LINK_PLUGIN_KEY = LINK_PLUGIN_KEY;
|
|
2870
3015
|
exports.MANAGED_KEY = MANAGED_KEY;
|
|
2871
3016
|
exports.MAX_RASTER_EMBED_DIMENSION = MAX_RASTER_EMBED_DIMENSION;
|
|
2872
3017
|
exports.SvgVectorRenderer = SvgVectorRenderer;
|
|
@@ -2884,6 +3029,7 @@ exports.buildDrawDotSvg = buildDrawDotSvg;
|
|
|
2884
3029
|
exports.buildEllipseSvg = buildEllipseSvg;
|
|
2885
3030
|
exports.buildFreehandPathSvg = buildFreehandPathSvg;
|
|
2886
3031
|
exports.buildLineSvg = buildLineSvg;
|
|
3032
|
+
exports.buildLinkCardSvg = buildLinkCardSvg;
|
|
2887
3033
|
exports.buildRectSvg = buildRectSvg;
|
|
2888
3034
|
exports.buildTextSvg = buildTextSvg;
|
|
2889
3035
|
exports.cloneVectorSceneItemWithNewId = cloneVectorSceneItemWithNewId;
|
|
@@ -2899,6 +3045,7 @@ exports.createFreehandStrokeItem = createFreehandStrokeItem;
|
|
|
2899
3045
|
exports.createImageFromVectorTrace = createImageFromVectorTrace;
|
|
2900
3046
|
exports.createImageItem = createImageItem;
|
|
2901
3047
|
exports.createLineItem = createLineItem;
|
|
3048
|
+
exports.createLinkItem = createLinkItem;
|
|
2902
3049
|
exports.createRectangleItem = createRectangleItem;
|
|
2903
3050
|
exports.createShapeId = createShapeId;
|
|
2904
3051
|
exports.createTextItem = createTextItem;
|
|
@@ -2908,9 +3055,11 @@ exports.encodeCanvasToBlob = encodeCanvasToBlob;
|
|
|
2908
3055
|
exports.expandCustomShapeTemplate = expandCustomShapeTemplate;
|
|
2909
3056
|
exports.formatCameraTransform = formatCameraTransform;
|
|
2910
3057
|
exports.formatItemPlacementTransform = formatItemPlacementTransform;
|
|
3058
|
+
exports.getLinkData = getLinkData;
|
|
2911
3059
|
exports.hitTestWorldPoint = hitTestWorldPoint;
|
|
2912
3060
|
exports.hydrateSceneItemsWithAssets = hydrateSceneItemsWithAssets;
|
|
2913
3061
|
exports.isArrowBindTarget = isArrowBindTarget;
|
|
3062
|
+
exports.isLinkItem = isLinkItem;
|
|
2914
3063
|
exports.isManagedImage = isManagedImage;
|
|
2915
3064
|
exports.itemHitTestWorldPoint = itemHitTestWorldPoint;
|
|
2916
3065
|
exports.lineEndpointsToLocal = lineEndpointsToLocal;
|