tldraw 4.1.0-canary.5d5610599458 → 4.1.0-canary.65769c249e0d
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-cjs/index.d.ts +15 -11
- package/dist-cjs/index.js +3 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/defaultEmbedDefinitions.js +2 -25
- package/dist-cjs/lib/defaultEmbedDefinitions.js.map +2 -2
- package/dist-cjs/lib/defaultExternalContentHandlers.js +8 -31
- package/dist-cjs/lib/defaultExternalContentHandlers.js.map +2 -2
- package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js +31 -101
- package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/bookmark/bookmarks.js +138 -0
- package/dist-cjs/lib/shapes/bookmark/bookmarks.js.map +7 -0
- package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js +25 -3
- package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js +9 -1
- package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js.map +2 -2
- package/dist-cjs/lib/ui/components/SharePanel/PeopleMenu.js +6 -2
- package/dist-cjs/lib/ui/components/SharePanel/PeopleMenu.js.map +2 -2
- package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js +1 -1
- package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js.map +1 -1
- package/dist-cjs/lib/ui/context/actions.js +23 -29
- package/dist-cjs/lib/ui/context/actions.js.map +2 -2
- package/dist-cjs/lib/ui/version.js +3 -3
- package/dist-cjs/lib/ui/version.js.map +1 -1
- package/dist-esm/index.d.mts +15 -11
- package/dist-esm/index.mjs +3 -1
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/defaultEmbedDefinitions.mjs +2 -25
- package/dist-esm/lib/defaultEmbedDefinitions.mjs.map +2 -2
- package/dist-esm/lib/defaultExternalContentHandlers.mjs +8 -31
- package/dist-esm/lib/defaultExternalContentHandlers.mjs.map +2 -2
- package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs +34 -101
- package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/bookmark/bookmarks.mjs +124 -0
- package/dist-esm/lib/shapes/bookmark/bookmarks.mjs.map +7 -0
- package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs +26 -3
- package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs +11 -2
- package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs.map +2 -2
- package/dist-esm/lib/ui/components/SharePanel/PeopleMenu.mjs +6 -2
- package/dist-esm/lib/ui/components/SharePanel/PeopleMenu.mjs.map +2 -2
- package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs +1 -1
- package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs.map +1 -1
- package/dist-esm/lib/ui/context/actions.mjs +23 -29
- package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
- package/dist-esm/lib/ui/version.mjs +3 -3
- package/dist-esm/lib/ui/version.mjs.map +1 -1
- package/package.json +3 -3
- package/src/index.ts +1 -0
- package/src/lib/defaultEmbedDefinitions.ts +2 -25
- package/src/lib/defaultExternalContentHandlers.ts +10 -35
- package/src/lib/shapes/bookmark/BookmarkShapeUtil.tsx +39 -133
- package/src/lib/shapes/bookmark/bookmarks.ts +170 -0
- package/src/lib/shapes/embed/EmbedShapeUtil.tsx +28 -2
- package/src/lib/tools/SelectTool/childStates/DraggingHandle.tsx +13 -1
- package/src/lib/ui/components/SharePanel/PeopleMenu.tsx +6 -2
- package/src/lib/ui/components/StylePanel/StylePanelButtonPicker.tsx +1 -1
- package/src/lib/ui/context/actions.tsx +27 -31
- package/src/lib/ui/version.ts +3 -3
- package/src/lib/utils/embeds/embeds.test.ts +16 -34
- package/src/test/bookmark-shapes.test.ts +129 -7
- package/src/test/customSnapping.test.tsx +55 -11
|
@@ -2,6 +2,7 @@ import { jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import {
|
|
3
3
|
BaseBoxShapeUtil,
|
|
4
4
|
HTMLContainer,
|
|
5
|
+
Rectangle2d,
|
|
5
6
|
embedShapeMigrations,
|
|
6
7
|
embedShapeProps,
|
|
7
8
|
lerp,
|
|
@@ -16,6 +17,8 @@ import {
|
|
|
16
17
|
embedShapePermissionDefaults
|
|
17
18
|
} from "../../defaultEmbedDefinitions.mjs";
|
|
18
19
|
import { getEmbedInfo } from "../../utils/embeds/embeds.mjs";
|
|
20
|
+
import { BookmarkIndicatorComponent, BookmarkShapeComponent } from "../bookmark/BookmarkShapeUtil.mjs";
|
|
21
|
+
import { BOOKMARK_JUST_URL_HEIGHT, BOOKMARK_WIDTH } from "../bookmark/bookmarks.mjs";
|
|
19
22
|
import { getRotatedBoxShadow } from "../shared/rotated-box-shadow.mjs";
|
|
20
23
|
const getSandboxPermissions = (permissions) => {
|
|
21
24
|
return Object.entries(permissions).filter(([_perm, isEnabled]) => isEnabled).map(([perm]) => perm).join(" ");
|
|
@@ -60,6 +63,17 @@ class EmbedShapeUtil extends BaseBoxShapeUtil {
|
|
|
60
63
|
url: ""
|
|
61
64
|
};
|
|
62
65
|
}
|
|
66
|
+
getGeometry(shape) {
|
|
67
|
+
const embedInfo = this.getEmbedDefinition(shape.props.url);
|
|
68
|
+
if (!embedInfo?.definition) {
|
|
69
|
+
return new Rectangle2d({
|
|
70
|
+
width: BOOKMARK_WIDTH,
|
|
71
|
+
height: BOOKMARK_JUST_URL_HEIGHT,
|
|
72
|
+
isFilled: true
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return super.getGeometry(shape);
|
|
76
|
+
}
|
|
63
77
|
isAspectRatioLocked(shape) {
|
|
64
78
|
const embedInfo = this.getEmbedDefinition(shape.props.url);
|
|
65
79
|
return embedInfo?.definition.isAspectRatioLocked ?? false;
|
|
@@ -158,11 +172,20 @@ class EmbedShapeUtil extends BaseBoxShapeUtil {
|
|
|
158
172
|
background: embedInfo?.definition.backgroundColor
|
|
159
173
|
}
|
|
160
174
|
}
|
|
161
|
-
) :
|
|
175
|
+
) : /* @__PURE__ */ jsx(
|
|
176
|
+
BookmarkShapeComponent,
|
|
177
|
+
{
|
|
178
|
+
url,
|
|
179
|
+
h,
|
|
180
|
+
rotation: pageRotation,
|
|
181
|
+
assetId: null,
|
|
182
|
+
showImageContainer: false
|
|
183
|
+
}
|
|
184
|
+
) });
|
|
162
185
|
}
|
|
163
186
|
indicator(shape) {
|
|
164
187
|
const embedInfo = this.getEmbedDefinition(shape.props.url);
|
|
165
|
-
return /* @__PURE__ */ jsx(
|
|
188
|
+
return embedInfo?.definition ? /* @__PURE__ */ jsx(
|
|
166
189
|
"rect",
|
|
167
190
|
{
|
|
168
191
|
width: toDomPrecision(shape.props.w),
|
|
@@ -170,7 +193,7 @@ class EmbedShapeUtil extends BaseBoxShapeUtil {
|
|
|
170
193
|
rx: embedInfo?.definition.overrideOutlineRadius ?? 8,
|
|
171
194
|
ry: embedInfo?.definition.overrideOutlineRadius ?? 8
|
|
172
195
|
}
|
|
173
|
-
);
|
|
196
|
+
) : /* @__PURE__ */ jsx(BookmarkIndicatorComponent, { w: BOOKMARK_WIDTH, h: BOOKMARK_JUST_URL_HEIGHT });
|
|
174
197
|
}
|
|
175
198
|
getInterpolatedProps(startShape, endShape, t) {
|
|
176
199
|
return {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/shapes/embed/EmbedShapeUtil.tsx"],
|
|
4
|
-
"sourcesContent": ["/* eslint-disable react-hooks/rules-of-hooks */\n\nimport {\n\tBaseBoxShapeUtil,\n\tHTMLContainer,\n\tTLEmbedShape,\n\tTLEmbedShapeProps,\n\tTLResizeInfo,\n\tembedShapeMigrations,\n\tembedShapeProps,\n\tlerp,\n\tresizeBox,\n\ttoDomPrecision,\n\tuseIsEditing,\n\tuseSvgExportContext,\n\tuseValue,\n} from '@tldraw/editor'\n\nimport {\n\tDEFAULT_EMBED_DEFINITIONS,\n\tEmbedDefinition,\n\tTLEmbedDefinition,\n\tTLEmbedShapePermissions,\n\tembedShapePermissionDefaults,\n} from '../../defaultEmbedDefinitions'\nimport { TLEmbedResult, getEmbedInfo } from '../../utils/embeds/embeds'\nimport { getRotatedBoxShadow } from '../shared/rotated-box-shadow'\n\nconst getSandboxPermissions = (permissions: TLEmbedShapePermissions) => {\n\treturn Object.entries(permissions)\n\t\t.filter(([_perm, isEnabled]) => isEnabled)\n\t\t.map(([perm]) => perm)\n\t\t.join(' ')\n}\n\n/** @public */\nexport class EmbedShapeUtil extends BaseBoxShapeUtil<TLEmbedShape> {\n\tstatic override type = 'embed' as const\n\tstatic override props = embedShapeProps\n\tstatic override migrations = embedShapeMigrations\n\tprivate static embedDefinitions: readonly EmbedDefinition[] = DEFAULT_EMBED_DEFINITIONS\n\n\tstatic setEmbedDefinitions(embedDefinitions: readonly TLEmbedDefinition[]) {\n\t\tEmbedShapeUtil.embedDefinitions = embedDefinitions\n\t}\n\n\tgetEmbedDefinitions(): readonly TLEmbedDefinition[] {\n\t\treturn EmbedShapeUtil.embedDefinitions\n\t}\n\n\tgetEmbedDefinition(url: string): TLEmbedResult {\n\t\treturn getEmbedInfo(EmbedShapeUtil.embedDefinitions, url)\n\t}\n\n\toverride getText(shape: TLEmbedShape) {\n\t\treturn shape.props.url\n\t}\n\n\toverride getAriaDescriptor(shape: TLEmbedShape) {\n\t\tconst embedInfo = this.getEmbedDefinition(shape.props.url)\n\t\treturn embedInfo?.definition.title\n\t}\n\n\toverride hideSelectionBoundsFg(shape: TLEmbedShape) {\n\t\treturn !this.canResize(shape)\n\t}\n\toverride canEdit() {\n\t\treturn true\n\t}\n\toverride canResize(shape: TLEmbedShape) {\n\t\treturn !!this.getEmbedDefinition(shape.props.url)?.definition?.doesResize\n\t}\n\toverride canEditInReadonly() {\n\t\treturn true\n\t}\n\n\toverride getDefaultProps(): TLEmbedShape['props'] {\n\t\treturn {\n\t\t\tw: 300,\n\t\t\th: 300,\n\t\t\turl: '',\n\t\t}\n\t}\n\n\toverride isAspectRatioLocked(shape: TLEmbedShape) {\n\t\tconst embedInfo = this.getEmbedDefinition(shape.props.url)\n\t\treturn embedInfo?.definition.isAspectRatioLocked ?? false\n\t}\n\n\toverride onResize(shape: TLEmbedShape, info: TLResizeInfo<TLEmbedShape>) {\n\t\tconst isAspectRatioLocked = this.isAspectRatioLocked(shape)\n\t\tconst embedInfo = this.getEmbedDefinition(shape.props.url)\n\t\tlet minWidth = embedInfo?.definition.minWidth ?? 200\n\t\tlet minHeight = embedInfo?.definition.minHeight ?? 200\n\t\tif (isAspectRatioLocked) {\n\t\t\t// Enforce aspect ratio\n\t\t\t// Neither the width or height can be less than 200\n\t\t\tconst aspectRatio = shape.props.w / shape.props.h\n\t\t\tif (aspectRatio > 1) {\n\t\t\t\t// Landscape\n\t\t\t\tminWidth *= aspectRatio\n\t\t\t} else {\n\t\t\t\t// Portrait\n\t\t\t\tminHeight /= aspectRatio\n\t\t\t}\n\t\t}\n\n\t\treturn resizeBox(shape, info, { minWidth, minHeight })\n\t}\n\n\toverride component(shape: TLEmbedShape) {\n\t\tconst svgExport = useSvgExportContext()\n\t\tconst { w, h, url } = shape.props\n\t\tconst isEditing = useIsEditing(shape.id)\n\n\t\tconst embedInfo = this.getEmbedDefinition(url)\n\n\t\tconst isHoveringWhileEditingSameShape = useValue(\n\t\t\t'is hovering',\n\t\t\t() => {\n\t\t\t\tconst { editingShapeId, hoveredShapeId } = this.editor.getCurrentPageState()\n\n\t\t\t\tif (editingShapeId && hoveredShapeId !== editingShapeId) {\n\t\t\t\t\tconst editingShape = this.editor.getShape(editingShapeId)\n\t\t\t\t\tif (editingShape && this.editor.isShapeOfType<TLEmbedShape>(editingShape, 'embed')) {\n\t\t\t\t\t\treturn true\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn false\n\t\t\t},\n\t\t\t[]\n\t\t)\n\n\t\tconst pageRotation = this.editor.getShapePageTransform(shape)!.rotation()\n\n\t\tif (svgExport) {\n\t\t\t// for SVG exports, we show a blank embed\n\t\t\treturn (\n\t\t\t\t<HTMLContainer className=\"tl-embed-container\" id={shape.id}>\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName=\"tl-embed\"\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\t\tboxShadow: getRotatedBoxShadow(pageRotation),\n\t\t\t\t\t\t\tborderRadius: embedInfo?.definition.overrideOutlineRadius ?? 8,\n\t\t\t\t\t\t\tbackground: embedInfo?.definition.backgroundColor ?? 'var(--tl-color-background)',\n\t\t\t\t\t\t\twidth: w,\n\t\t\t\t\t\t\theight: h,\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t</HTMLContainer>\n\t\t\t)\n\t\t}\n\n\t\tconst isInteractive = isEditing || isHoveringWhileEditingSameShape\n\n\t\t// Prevent nested embedding of tldraw\n\t\tconst isIframe =\n\t\t\ttypeof window !== 'undefined' && (window !== window.top || window.self !== window.parent)\n\t\tif (isIframe && embedInfo?.definition.type === 'tldraw') return null\n\n\t\tif (embedInfo?.definition.type === 'github_gist') {\n\t\t\tconst idFromGistUrl = embedInfo.url.split('/').pop()\n\t\t\tif (!idFromGistUrl) throw Error('No gist id!')\n\n\t\t\treturn (\n\t\t\t\t<HTMLContainer className=\"tl-embed-container\" id={shape.id}>\n\t\t\t\t\t<Gist\n\t\t\t\t\t\tid={idFromGistUrl}\n\t\t\t\t\t\twidth={toDomPrecision(w)!}\n\t\t\t\t\t\theight={toDomPrecision(h)!}\n\t\t\t\t\t\tisInteractive={isInteractive}\n\t\t\t\t\t\tpageRotation={pageRotation}\n\t\t\t\t\t/>\n\t\t\t\t</HTMLContainer>\n\t\t\t)\n\t\t}\n\n\t\tconst sandbox = getSandboxPermissions({\n\t\t\t...embedShapePermissionDefaults,\n\t\t\t...(embedInfo?.definition.overridePermissions ?? {}),\n\t\t})\n\n\t\treturn (\n\t\t\t<HTMLContainer className=\"tl-embed-container\" id={shape.id}>\n\t\t\t\t{embedInfo?.definition ? (\n\t\t\t\t\t<iframe\n\t\t\t\t\t\tclassName=\"tl-embed\"\n\t\t\t\t\t\tsandbox={sandbox}\n\t\t\t\t\t\tsrc={embedInfo.embedUrl}\n\t\t\t\t\t\twidth={toDomPrecision(w)}\n\t\t\t\t\t\theight={toDomPrecision(h)}\n\t\t\t\t\t\tdraggable={false}\n\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\t\t\t\tframeBorder=\"0\"\n\t\t\t\t\t\treferrerPolicy=\"no-referrer-when-downgrade\"\n\t\t\t\t\t\ttabIndex={isEditing ? 0 : -1}\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\t\tpointerEvents: isInteractive ? 'auto' : 'none',\n\t\t\t\t\t\t\t// Fix for safari <https://stackoverflow.com/a/49150908>\n\t\t\t\t\t\t\tzIndex: isInteractive ? '' : '-1',\n\t\t\t\t\t\t\tboxShadow: getRotatedBoxShadow(pageRotation),\n\t\t\t\t\t\t\tborderRadius: embedInfo?.definition.overrideOutlineRadius ?? 8,\n\t\t\t\t\t\t\tbackground: embedInfo?.definition.backgroundColor,\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t) : null}\n\t\t\t</HTMLContainer>\n\t\t)\n\t}\n\n\toverride indicator(shape: TLEmbedShape) {\n\t\tconst embedInfo = this.getEmbedDefinition(shape.props.url)\n\t\treturn (\n\t\t\t<rect\n\t\t\t\twidth={toDomPrecision(shape.props.w)}\n\t\t\t\theight={toDomPrecision(shape.props.h)}\n\t\t\t\trx={embedInfo?.definition.overrideOutlineRadius ?? 8}\n\t\t\t\try={embedInfo?.definition.overrideOutlineRadius ?? 8}\n\t\t\t/>\n\t\t)\n\t}\n\toverride getInterpolatedProps(\n\t\tstartShape: TLEmbedShape,\n\t\tendShape: TLEmbedShape,\n\t\tt: number\n\t): TLEmbedShapeProps {\n\t\treturn {\n\t\t\t...(t > 0.5 ? endShape.props : startShape.props),\n\t\t\tw: lerp(startShape.props.w, endShape.props.w, t),\n\t\t\th: lerp(startShape.props.h, endShape.props.h, t),\n\t\t}\n\t}\n}\n\nfunction Gist({\n\tid,\n\tisInteractive,\n\twidth,\n\theight,\n\tstyle,\n\tpageRotation,\n}: {\n\tid: string\n\tisInteractive: boolean\n\twidth: number\n\theight: number\n\tpageRotation: number\n\tstyle?: React.CSSProperties\n}) {\n\t// Security warning:\n\t// Gists allow adding .json extensions to the URL which return JSONP.\n\t// Furthermore, the JSONP can include callbacks that execute arbitrary JavaScript.\n\t// It _is_ sandboxed by the iframe but we still want to disable it nonetheless.\n\t// We restrict the id to only allow hexdecimal characters to prevent this.\n\t// Read more:\n\t// https://github.com/bhaveshk90/Content-Security-Policy-CSP-Bypass-Techniques\n\t// https://github.com/renniepak/CSPBypass\n\tif (!id.match(/^[0-9a-f]+$/)) throw Error('No gist id!')\n\n\treturn (\n\t\t<iframe\n\t\t\tclassName=\"tl-embed\"\n\t\t\tdraggable={false}\n\t\t\twidth={toDomPrecision(width)}\n\t\t\theight={toDomPrecision(height)}\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\tframeBorder=\"0\"\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\tscrolling=\"no\"\n\t\t\treferrerPolicy=\"no-referrer-when-downgrade\"\n\t\t\ttabIndex={isInteractive ? 0 : -1}\n\t\t\tstyle={{\n\t\t\t\t...style,\n\t\t\t\tpointerEvents: isInteractive ? 'all' : 'none',\n\t\t\t\t// Fix for safari <https://stackoverflow.com/a/49150908>\n\t\t\t\tzIndex: isInteractive ? '' : '-1',\n\t\t\t\tboxShadow: getRotatedBoxShadow(pageRotation),\n\t\t\t}}\n\t\t\tsrcDoc={`\n\t\t\t<html>\n\t\t\t\t<head>\n\t\t\t\t\t<base target=\"_blank\">\n\t\t\t\t</head>\n\t\t\t\t<body>\n\t\t\t\t\t<script src=${`https://gist.github.com/${id}.js`}></script>\n\t\t\t\t\t<style type=\"text/css\">\n\t\t\t\t\t\t* { margin: 0px; }\n\t\t\t\t\t\ttable { height: 100%; background-color: red; }\n\t\t\t\t\t\t.gist { background-color: none; height: 100%; }\n\t\t\t\t\t\t.gist .gist-file { height: calc(100vh - 2px); padding: 0px; display: grid; grid-template-rows: 1fr auto; }\n\t\t\t\t\t</style>\n\t\t\t\t</body>\n\t\t\t</html>`}\n\t\t/>\n\t)\n}\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["/* eslint-disable react-hooks/rules-of-hooks */\n\nimport {\n\tBaseBoxShapeUtil,\n\tHTMLContainer,\n\tRectangle2d,\n\tTLEmbedShape,\n\tTLEmbedShapeProps,\n\tTLResizeInfo,\n\tembedShapeMigrations,\n\tembedShapeProps,\n\tlerp,\n\tresizeBox,\n\ttoDomPrecision,\n\tuseIsEditing,\n\tuseSvgExportContext,\n\tuseValue,\n} from '@tldraw/editor'\n\nimport {\n\tDEFAULT_EMBED_DEFINITIONS,\n\tEmbedDefinition,\n\tTLEmbedDefinition,\n\tTLEmbedShapePermissions,\n\tembedShapePermissionDefaults,\n} from '../../defaultEmbedDefinitions'\nimport { TLEmbedResult, getEmbedInfo } from '../../utils/embeds/embeds'\nimport { BookmarkIndicatorComponent, BookmarkShapeComponent } from '../bookmark/BookmarkShapeUtil'\nimport { BOOKMARK_JUST_URL_HEIGHT, BOOKMARK_WIDTH } from '../bookmark/bookmarks'\nimport { getRotatedBoxShadow } from '../shared/rotated-box-shadow'\n\nconst getSandboxPermissions = (permissions: TLEmbedShapePermissions) => {\n\treturn Object.entries(permissions)\n\t\t.filter(([_perm, isEnabled]) => isEnabled)\n\t\t.map(([perm]) => perm)\n\t\t.join(' ')\n}\n\n/** @public */\nexport class EmbedShapeUtil extends BaseBoxShapeUtil<TLEmbedShape> {\n\tstatic override type = 'embed' as const\n\tstatic override props = embedShapeProps\n\tstatic override migrations = embedShapeMigrations\n\tprivate static embedDefinitions: readonly EmbedDefinition[] = DEFAULT_EMBED_DEFINITIONS\n\n\tstatic setEmbedDefinitions(embedDefinitions: readonly TLEmbedDefinition[]) {\n\t\tEmbedShapeUtil.embedDefinitions = embedDefinitions\n\t}\n\n\tgetEmbedDefinitions(): readonly TLEmbedDefinition[] {\n\t\treturn EmbedShapeUtil.embedDefinitions\n\t}\n\n\tgetEmbedDefinition(url: string): TLEmbedResult {\n\t\treturn getEmbedInfo(EmbedShapeUtil.embedDefinitions, url)\n\t}\n\n\toverride getText(shape: TLEmbedShape) {\n\t\treturn shape.props.url\n\t}\n\n\toverride getAriaDescriptor(shape: TLEmbedShape) {\n\t\tconst embedInfo = this.getEmbedDefinition(shape.props.url)\n\t\treturn embedInfo?.definition.title\n\t}\n\n\toverride hideSelectionBoundsFg(shape: TLEmbedShape) {\n\t\treturn !this.canResize(shape)\n\t}\n\toverride canEdit() {\n\t\treturn true\n\t}\n\toverride canResize(shape: TLEmbedShape) {\n\t\treturn !!this.getEmbedDefinition(shape.props.url)?.definition?.doesResize\n\t}\n\toverride canEditInReadonly() {\n\t\treturn true\n\t}\n\n\toverride getDefaultProps(): TLEmbedShape['props'] {\n\t\treturn {\n\t\t\tw: 300,\n\t\t\th: 300,\n\t\t\turl: '',\n\t\t}\n\t}\n\n\toverride getGeometry(shape: TLEmbedShape) {\n\t\tconst embedInfo = this.getEmbedDefinition(shape.props.url)\n\t\tif (!embedInfo?.definition) {\n\t\t\treturn new Rectangle2d({\n\t\t\t\twidth: BOOKMARK_WIDTH,\n\t\t\t\theight: BOOKMARK_JUST_URL_HEIGHT,\n\t\t\t\tisFilled: true,\n\t\t\t})\n\t\t}\n\t\treturn super.getGeometry(shape)\n\t}\n\n\toverride isAspectRatioLocked(shape: TLEmbedShape) {\n\t\tconst embedInfo = this.getEmbedDefinition(shape.props.url)\n\t\treturn embedInfo?.definition.isAspectRatioLocked ?? false\n\t}\n\n\toverride onResize(shape: TLEmbedShape, info: TLResizeInfo<TLEmbedShape>) {\n\t\tconst isAspectRatioLocked = this.isAspectRatioLocked(shape)\n\t\tconst embedInfo = this.getEmbedDefinition(shape.props.url)\n\t\tlet minWidth = embedInfo?.definition.minWidth ?? 200\n\t\tlet minHeight = embedInfo?.definition.minHeight ?? 200\n\t\tif (isAspectRatioLocked) {\n\t\t\t// Enforce aspect ratio\n\t\t\t// Neither the width or height can be less than 200\n\t\t\tconst aspectRatio = shape.props.w / shape.props.h\n\t\t\tif (aspectRatio > 1) {\n\t\t\t\t// Landscape\n\t\t\t\tminWidth *= aspectRatio\n\t\t\t} else {\n\t\t\t\t// Portrait\n\t\t\t\tminHeight /= aspectRatio\n\t\t\t}\n\t\t}\n\n\t\treturn resizeBox(shape, info, { minWidth, minHeight })\n\t}\n\n\toverride component(shape: TLEmbedShape) {\n\t\tconst svgExport = useSvgExportContext()\n\t\tconst { w, h, url } = shape.props\n\t\tconst isEditing = useIsEditing(shape.id)\n\n\t\tconst embedInfo = this.getEmbedDefinition(url)\n\n\t\tconst isHoveringWhileEditingSameShape = useValue(\n\t\t\t'is hovering',\n\t\t\t() => {\n\t\t\t\tconst { editingShapeId, hoveredShapeId } = this.editor.getCurrentPageState()\n\n\t\t\t\tif (editingShapeId && hoveredShapeId !== editingShapeId) {\n\t\t\t\t\tconst editingShape = this.editor.getShape(editingShapeId)\n\t\t\t\t\tif (editingShape && this.editor.isShapeOfType<TLEmbedShape>(editingShape, 'embed')) {\n\t\t\t\t\t\treturn true\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn false\n\t\t\t},\n\t\t\t[]\n\t\t)\n\n\t\tconst pageRotation = this.editor.getShapePageTransform(shape)!.rotation()\n\n\t\tif (svgExport) {\n\t\t\t// for SVG exports, we show a blank embed\n\t\t\treturn (\n\t\t\t\t<HTMLContainer className=\"tl-embed-container\" id={shape.id}>\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName=\"tl-embed\"\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\t\tboxShadow: getRotatedBoxShadow(pageRotation),\n\t\t\t\t\t\t\tborderRadius: embedInfo?.definition.overrideOutlineRadius ?? 8,\n\t\t\t\t\t\t\tbackground: embedInfo?.definition.backgroundColor ?? 'var(--tl-color-background)',\n\t\t\t\t\t\t\twidth: w,\n\t\t\t\t\t\t\theight: h,\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t</HTMLContainer>\n\t\t\t)\n\t\t}\n\n\t\tconst isInteractive = isEditing || isHoveringWhileEditingSameShape\n\n\t\t// Prevent nested embedding of tldraw\n\t\tconst isIframe =\n\t\t\ttypeof window !== 'undefined' && (window !== window.top || window.self !== window.parent)\n\t\tif (isIframe && embedInfo?.definition.type === 'tldraw') return null\n\n\t\tif (embedInfo?.definition.type === 'github_gist') {\n\t\t\tconst idFromGistUrl = embedInfo.url.split('/').pop()\n\t\t\tif (!idFromGistUrl) throw Error('No gist id!')\n\n\t\t\treturn (\n\t\t\t\t<HTMLContainer className=\"tl-embed-container\" id={shape.id}>\n\t\t\t\t\t<Gist\n\t\t\t\t\t\tid={idFromGistUrl}\n\t\t\t\t\t\twidth={toDomPrecision(w)!}\n\t\t\t\t\t\theight={toDomPrecision(h)!}\n\t\t\t\t\t\tisInteractive={isInteractive}\n\t\t\t\t\t\tpageRotation={pageRotation}\n\t\t\t\t\t/>\n\t\t\t\t</HTMLContainer>\n\t\t\t)\n\t\t}\n\n\t\tconst sandbox = getSandboxPermissions({\n\t\t\t...embedShapePermissionDefaults,\n\t\t\t...(embedInfo?.definition.overridePermissions ?? {}),\n\t\t})\n\n\t\treturn (\n\t\t\t<HTMLContainer className=\"tl-embed-container\" id={shape.id}>\n\t\t\t\t{embedInfo?.definition ? (\n\t\t\t\t\t<iframe\n\t\t\t\t\t\tclassName=\"tl-embed\"\n\t\t\t\t\t\tsandbox={sandbox}\n\t\t\t\t\t\tsrc={embedInfo.embedUrl}\n\t\t\t\t\t\twidth={toDomPrecision(w)}\n\t\t\t\t\t\theight={toDomPrecision(h)}\n\t\t\t\t\t\tdraggable={false}\n\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\t\t\t\tframeBorder=\"0\"\n\t\t\t\t\t\treferrerPolicy=\"no-referrer-when-downgrade\"\n\t\t\t\t\t\ttabIndex={isEditing ? 0 : -1}\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\t\tpointerEvents: isInteractive ? 'auto' : 'none',\n\t\t\t\t\t\t\t// Fix for safari <https://stackoverflow.com/a/49150908>\n\t\t\t\t\t\t\tzIndex: isInteractive ? '' : '-1',\n\t\t\t\t\t\t\tboxShadow: getRotatedBoxShadow(pageRotation),\n\t\t\t\t\t\t\tborderRadius: embedInfo?.definition.overrideOutlineRadius ?? 8,\n\t\t\t\t\t\t\tbackground: embedInfo?.definition.backgroundColor,\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t) : (\n\t\t\t\t\t<BookmarkShapeComponent\n\t\t\t\t\t\turl={url}\n\t\t\t\t\t\th={h}\n\t\t\t\t\t\trotation={pageRotation}\n\t\t\t\t\t\tassetId={null}\n\t\t\t\t\t\tshowImageContainer={false}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</HTMLContainer>\n\t\t)\n\t}\n\n\toverride indicator(shape: TLEmbedShape) {\n\t\tconst embedInfo = this.getEmbedDefinition(shape.props.url)\n\n\t\treturn embedInfo?.definition ? (\n\t\t\t<rect\n\t\t\t\twidth={toDomPrecision(shape.props.w)}\n\t\t\t\theight={toDomPrecision(shape.props.h)}\n\t\t\t\trx={embedInfo?.definition.overrideOutlineRadius ?? 8}\n\t\t\t\try={embedInfo?.definition.overrideOutlineRadius ?? 8}\n\t\t\t/>\n\t\t) : (\n\t\t\t<BookmarkIndicatorComponent w={BOOKMARK_WIDTH} h={BOOKMARK_JUST_URL_HEIGHT} />\n\t\t)\n\t}\n\toverride getInterpolatedProps(\n\t\tstartShape: TLEmbedShape,\n\t\tendShape: TLEmbedShape,\n\t\tt: number\n\t): TLEmbedShapeProps {\n\t\treturn {\n\t\t\t...(t > 0.5 ? endShape.props : startShape.props),\n\t\t\tw: lerp(startShape.props.w, endShape.props.w, t),\n\t\t\th: lerp(startShape.props.h, endShape.props.h, t),\n\t\t}\n\t}\n}\n\nfunction Gist({\n\tid,\n\tisInteractive,\n\twidth,\n\theight,\n\tstyle,\n\tpageRotation,\n}: {\n\tid: string\n\tisInteractive: boolean\n\twidth: number\n\theight: number\n\tpageRotation: number\n\tstyle?: React.CSSProperties\n}) {\n\t// Security warning:\n\t// Gists allow adding .json extensions to the URL which return JSONP.\n\t// Furthermore, the JSONP can include callbacks that execute arbitrary JavaScript.\n\t// It _is_ sandboxed by the iframe but we still want to disable it nonetheless.\n\t// We restrict the id to only allow hexdecimal characters to prevent this.\n\t// Read more:\n\t// https://github.com/bhaveshk90/Content-Security-Policy-CSP-Bypass-Techniques\n\t// https://github.com/renniepak/CSPBypass\n\tif (!id.match(/^[0-9a-f]+$/)) throw Error('No gist id!')\n\n\treturn (\n\t\t<iframe\n\t\t\tclassName=\"tl-embed\"\n\t\t\tdraggable={false}\n\t\t\twidth={toDomPrecision(width)}\n\t\t\theight={toDomPrecision(height)}\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\tframeBorder=\"0\"\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\tscrolling=\"no\"\n\t\t\treferrerPolicy=\"no-referrer-when-downgrade\"\n\t\t\ttabIndex={isInteractive ? 0 : -1}\n\t\t\tstyle={{\n\t\t\t\t...style,\n\t\t\t\tpointerEvents: isInteractive ? 'all' : 'none',\n\t\t\t\t// Fix for safari <https://stackoverflow.com/a/49150908>\n\t\t\t\tzIndex: isInteractive ? '' : '-1',\n\t\t\t\tboxShadow: getRotatedBoxShadow(pageRotation),\n\t\t\t}}\n\t\t\tsrcDoc={`\n\t\t\t<html>\n\t\t\t\t<head>\n\t\t\t\t\t<base target=\"_blank\">\n\t\t\t\t</head>\n\t\t\t\t<body>\n\t\t\t\t\t<script src=${`https://gist.github.com/${id}.js`}></script>\n\t\t\t\t\t<style type=\"text/css\">\n\t\t\t\t\t\t* { margin: 0px; }\n\t\t\t\t\t\ttable { height: 100%; background-color: red; }\n\t\t\t\t\t\t.gist { background-color: none; height: 100%; }\n\t\t\t\t\t\t.gist .gist-file { height: calc(100vh - 2px); padding: 0px; display: grid; grid-template-rows: 1fr auto; }\n\t\t\t\t\t</style>\n\t\t\t\t</body>\n\t\t\t</html>`}\n\t\t/>\n\t)\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -4,7 +4,8 @@ import {
|
|
|
4
4
|
kickoutOccludedShapes,
|
|
5
5
|
snapAngle,
|
|
6
6
|
sortByIndex,
|
|
7
|
-
structuredClone
|
|
7
|
+
structuredClone,
|
|
8
|
+
warnOnce
|
|
8
9
|
} from "@tldraw/editor";
|
|
9
10
|
import { clearArrowTargetState } from "../../../shapes/arrow/arrowTargetState.mjs";
|
|
10
11
|
import { getArrowBindings } from "../../../shapes/arrow/shared.mjs";
|
|
@@ -208,7 +209,15 @@ class DraggingHandle extends StateNode {
|
|
|
208
209
|
}
|
|
209
210
|
editor.snaps.clearIndicators();
|
|
210
211
|
let nextHandle = { ...initialHandle, x: point.x, y: point.y };
|
|
211
|
-
|
|
212
|
+
let canSnap = false;
|
|
213
|
+
if (initialHandle.canSnap && initialHandle.snapType) {
|
|
214
|
+
warnOnce(
|
|
215
|
+
"canSnap is deprecated. Cannot use both canSnap and snapType together - snapping disabled. Please use only snapType."
|
|
216
|
+
);
|
|
217
|
+
} else {
|
|
218
|
+
canSnap = initialHandle.canSnap || initialHandle.snapType !== void 0;
|
|
219
|
+
}
|
|
220
|
+
if (canSnap && (isSnapMode ? !ctrlKey : ctrlKey)) {
|
|
212
221
|
const pageTransform = editor.getShapePageTransform(shape.id);
|
|
213
222
|
if (!pageTransform) throw Error("Expected a page transform");
|
|
214
223
|
const snap = snaps.handles.snapHandle({ currentShapeId: shapeId, handle: nextHandle });
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/lib/tools/SelectTool/childStates/DraggingHandle.tsx"],
|
|
4
|
-
"sourcesContent": ["import {\n\tMat,\n\tStateNode,\n\tTLArrowShape,\n\tTLHandle,\n\tTLLineShape,\n\tTLPointerEventInfo,\n\tTLShapeId,\n\tTLShapePartial,\n\tVec,\n\tkickoutOccludedShapes,\n\tsnapAngle,\n\tsortByIndex,\n\tstructuredClone,\n} from '@tldraw/editor'\nimport { ArrowShapeUtil } from '../../../shapes/arrow/ArrowShapeUtil'\nimport { clearArrowTargetState } from '../../../shapes/arrow/arrowTargetState'\nimport { getArrowBindings } from '../../../shapes/arrow/shared'\n\nexport type DraggingHandleInfo = TLPointerEventInfo & {\n\tshape: TLArrowShape | TLLineShape\n\ttarget: 'handle'\n\tonInteractionEnd?: string\n\tisCreating?: boolean\n\tcreatingMarkId?: string\n}\n\nexport class DraggingHandle extends StateNode {\n\tstatic override id = 'dragging_handle'\n\n\tshapeId!: TLShapeId\n\tinitialHandle!: TLHandle\n\tinitialAdjacentHandle!: TLHandle | null\n\tinitialPagePoint!: Vec\n\n\tmarkId!: string\n\tinitialPageTransform!: Mat\n\tinitialPageRotation!: number\n\n\tinfo!: DraggingHandleInfo\n\n\tisPrecise = false\n\tisPreciseId: TLShapeId | null = null\n\tpointingId: TLShapeId | null = null\n\n\toverride onEnter(info: DraggingHandleInfo) {\n\t\tconst { shape, isCreating, creatingMarkId, handle } = info\n\t\tthis.info = info\n\t\tthis.parent.setCurrentToolIdMask(info.onInteractionEnd)\n\t\tthis.shapeId = shape.id\n\t\tthis.markId = ''\n\n\t\tif (isCreating) {\n\t\t\tif (creatingMarkId) {\n\t\t\t\tthis.markId = creatingMarkId\n\t\t\t} else {\n\t\t\t\t// handle legacy implicit `creating:{shapeId}` marks\n\t\t\t\tconst markId = this.editor.getMarkIdMatching(\n\t\t\t\t\t`creating:${this.editor.getOnlySelectedShapeId()}`\n\t\t\t\t)\n\t\t\t\tif (markId) {\n\t\t\t\t\tthis.markId = markId\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tthis.markId = this.editor.markHistoryStoppingPoint('dragging handle')\n\t\t}\n\n\t\tthis.initialHandle = structuredClone(handle)\n\n\t\tthis.initialPageTransform = this.editor.getShapePageTransform(shape)!\n\t\tthis.initialPageRotation = this.initialPageTransform.rotation()\n\t\tthis.initialPagePoint = this.editor.inputs.originPagePoint.clone()\n\n\t\tthis.editor.setCursor({ type: isCreating ? 'cross' : 'grabbing', rotation: 0 })\n\n\t\tconst handles = this.editor.getShapeHandles(shape)!.sort(sortByIndex)\n\t\tconst index = handles.findIndex((h) => h.id === info.handle.id)\n\n\t\t// Find the adjacent handle\n\t\tthis.initialAdjacentHandle = null\n\n\t\t// Start from the handle and work forward\n\t\tfor (let i = index + 1; i < handles.length; i++) {\n\t\t\tconst handle = handles[i]\n\t\t\tif (handle.type === 'vertex' && handle.id !== 'middle' && handle.id !== info.handle.id) {\n\t\t\t\tthis.initialAdjacentHandle = handle\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\t// If still no handle, start from the end and work backward\n\t\tif (!this.initialAdjacentHandle) {\n\t\t\tfor (let i = handles.length - 1; i >= 0; i--) {\n\t\t\t\tconst handle = handles[i]\n\t\t\t\tif (handle.type === 'vertex' && handle.id !== 'middle' && handle.id !== info.handle.id) {\n\t\t\t\t\tthis.initialAdjacentHandle = handle\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// <!-- Only relevant to arrows\n\t\tif (this.editor.isShapeOfType<TLArrowShape>(shape, 'arrow')) {\n\t\t\tconst initialBinding = getArrowBindings(this.editor, shape)[info.handle.id as 'start' | 'end']\n\n\t\t\tthis.isPrecise = false\n\n\t\t\tif (initialBinding) {\n\t\t\t\tthis.isPrecise = initialBinding.props.isPrecise\n\t\t\t\tif (this.isPrecise) {\n\t\t\t\t\tthis.isPreciseId = initialBinding.toId\n\t\t\t\t} else {\n\t\t\t\t\tthis.resetExactTimeout()\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// -->\n\n\t\t// Call onHandleDragStart callback\n\t\tconst handleDragInfo = {\n\t\t\thandle: this.initialHandle,\n\t\t\tisPrecise: this.isPrecise,\n\t\t\tisCreatingShape: !!this.info.isCreating,\n\t\t\tinitial: shape,\n\t\t}\n\t\tconst util = this.editor.getShapeUtil(shape)\n\t\tconst startChanges = util.onHandleDragStart?.(shape, handleDragInfo)\n\t\tif (startChanges) {\n\t\t\tthis.editor.updateShapes([{ ...startChanges, id: shape.id, type: shape.type }])\n\t\t}\n\n\t\tthis.update()\n\n\t\tthis.editor.select(this.shapeId)\n\t}\n\n\t// Only relevant to arrows\n\tprivate exactTimeout = -1\n\n\t// Only relevant to arrows\n\tprivate resetExactTimeout() {\n\t\tconst arrowUtil = this.editor.getShapeUtil<ArrowShapeUtil>('arrow')\n\t\tconst timeoutValue = arrowUtil.options.pointingPreciseTimeout\n\n\t\tif (this.exactTimeout !== -1) {\n\t\t\tthis.clearExactTimeout()\n\t\t}\n\n\t\tthis.exactTimeout = this.editor.timers.setTimeout(() => {\n\t\t\tif (this.getIsActive() && !this.isPrecise) {\n\t\t\t\tthis.isPrecise = true\n\t\t\t\tthis.isPreciseId = this.pointingId\n\t\t\t\tthis.update()\n\t\t\t}\n\t\t\tthis.exactTimeout = -1\n\t\t}, timeoutValue)\n\t}\n\n\t// Only relevant to arrows\n\tprivate clearExactTimeout() {\n\t\tif (this.exactTimeout !== -1) {\n\t\t\tclearTimeout(this.exactTimeout)\n\t\t\tthis.exactTimeout = -1\n\t\t}\n\t}\n\n\toverride onPointerMove() {\n\t\tthis.update()\n\t}\n\n\toverride onKeyDown() {\n\t\tthis.update()\n\t}\n\n\toverride onKeyUp() {\n\t\tthis.update()\n\t}\n\n\toverride onPointerUp() {\n\t\tthis.complete()\n\t}\n\n\toverride onComplete() {\n\t\tthis.update()\n\t\tthis.complete()\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\toverride onExit() {\n\t\tthis.parent.setCurrentToolIdMask(undefined)\n\t\tclearArrowTargetState(this.editor)\n\t\tthis.editor.snaps.clearIndicators()\n\n\t\tthis.editor.setCursor({ type: 'default', rotation: 0 })\n\t}\n\n\tprivate complete() {\n\t\tthis.editor.snaps.clearIndicators()\n\t\tkickoutOccludedShapes(this.editor, [this.shapeId])\n\n\t\t// Call onHandleDragEnd callback before state transitions\n\t\tconst shape = this.editor.getShape(this.shapeId)\n\t\tif (shape) {\n\t\t\tconst util = this.editor.getShapeUtil(shape)\n\t\t\tconst handleDragInfo = {\n\t\t\t\thandle: this.initialHandle,\n\t\t\t\tisPrecise: this.isPrecise,\n\t\t\t\tisCreatingShape: !!this.info.isCreating,\n\t\t\t\tinitial: this.info.shape,\n\t\t\t}\n\t\t\tconst endChanges = util.onHandleDragEnd?.(shape, handleDragInfo)\n\t\t\tif (endChanges) {\n\t\t\t\tthis.editor.updateShapes([{ ...endChanges, id: shape.id, type: shape.type }])\n\t\t\t}\n\t\t}\n\n\t\tconst { onInteractionEnd } = this.info\n\t\tif (this.editor.getInstanceState().isToolLocked && onInteractionEnd) {\n\t\t\t// Return to the tool that was active before this one,\n\t\t\t// but only if tool lock is turned on!\n\t\t\tthis.editor.setCurrentTool(onInteractionEnd, { shapeId: this.shapeId })\n\t\t\treturn\n\t\t}\n\n\t\tthis.parent.transition('idle')\n\t}\n\n\tprivate cancel() {\n\t\t// Call onHandleDragCancel callback before bailing to mark\n\t\tconst shape = this.editor.getShape(this.shapeId)\n\t\tif (shape) {\n\t\t\tconst util = this.editor.getShapeUtil(shape)\n\t\t\tconst handleDragInfo = {\n\t\t\t\thandle: this.initialHandle,\n\t\t\t\tisPrecise: this.isPrecise,\n\t\t\t\tisCreatingShape: !!this.info.isCreating,\n\t\t\t\tinitial: this.info.shape,\n\t\t\t}\n\t\t\tutil.onHandleDragCancel?.(shape, handleDragInfo)\n\t\t}\n\n\t\tthis.editor.bailToMark(this.markId)\n\t\tthis.editor.snaps.clearIndicators()\n\n\t\tconst { onInteractionEnd } = this.info\n\t\tif (onInteractionEnd) {\n\t\t\t// Return to the tool that was active before this one,\n\t\t\t// whether tool lock is turned on or not!\n\t\t\tthis.editor.setCurrentTool(onInteractionEnd, { shapeId: this.shapeId })\n\t\t\treturn\n\t\t}\n\n\t\tthis.parent.transition('idle')\n\t}\n\n\tprivate update() {\n\t\tconst { editor, shapeId, initialPagePoint } = this\n\t\tconst { initialHandle, initialPageRotation, initialAdjacentHandle } = this\n\t\tconst isSnapMode = this.editor.user.getIsSnapMode()\n\t\tconst {\n\t\t\tsnaps,\n\t\t\tinputs: { currentPagePoint, shiftKey, ctrlKey, altKey, pointerVelocity },\n\t\t} = editor\n\n\t\tconst initial = this.info.shape\n\n\t\tconst shape = editor.getShape(shapeId)\n\t\tif (!shape) return\n\t\tconst util = editor.getShapeUtil(shape)\n\n\t\tconst initialBinding = editor.isShapeOfType<TLArrowShape>(shape, 'arrow')\n\t\t\t? getArrowBindings(editor, shape)[initialHandle.id as 'start' | 'end']\n\t\t\t: undefined\n\n\t\tlet point = currentPagePoint\n\t\t\t.clone()\n\t\t\t.sub(initialPagePoint)\n\t\t\t.rot(-initialPageRotation)\n\t\t\t.add(initialHandle)\n\n\t\tif (shiftKey && initialAdjacentHandle && initialHandle.id !== 'middle') {\n\t\t\tconst angle = Vec.Angle(initialAdjacentHandle, point)\n\t\t\tconst snappedAngle = snapAngle(angle, 24)\n\t\t\tconst angleDifference = snappedAngle - angle\n\t\t\tpoint = Vec.RotWith(point, initialAdjacentHandle, angleDifference)\n\t\t}\n\n\t\t// Clear any existing snaps\n\t\teditor.snaps.clearIndicators()\n\n\t\tlet nextHandle = { ...initialHandle, x: point.x, y: point.y }\n\n\t\tif (initialHandle.canSnap && (isSnapMode ? !ctrlKey : ctrlKey)) {\n\t\t\t// We're snapping\n\t\t\tconst pageTransform = editor.getShapePageTransform(shape.id)\n\t\t\tif (!pageTransform) throw Error('Expected a page transform')\n\n\t\t\tconst snap = snaps.handles.snapHandle({ currentShapeId: shapeId, handle: nextHandle })\n\n\t\t\tif (snap) {\n\t\t\t\tsnap.nudge.rot(-editor.getShapeParentTransform(shape)!.rotation())\n\t\t\t\tpoint.add(snap.nudge)\n\t\t\t\tnextHandle = { ...initialHandle, x: point.x, y: point.y }\n\t\t\t}\n\t\t}\n\n\t\tconst changes = util.onHandleDrag?.(shape, {\n\t\t\thandle: nextHandle,\n\t\t\tisPrecise: this.isPrecise || altKey,\n\t\t\tisCreatingShape: !!this.info.isCreating,\n\t\t\tinitial: initial,\n\t\t})\n\n\t\tconst next: TLShapePartial<any> = { id: shape.id, type: shape.type, ...changes }\n\n\t\t// Arrows\n\t\tif (\n\t\t\tinitialHandle.type === 'vertex' &&\n\t\t\tthis.editor.isShapeOfType<TLArrowShape>(shape, 'arrow')\n\t\t) {\n\t\t\tconst bindingAfter = getArrowBindings(editor, shape)[initialHandle.id as 'start' | 'end']\n\n\t\t\tif (bindingAfter) {\n\t\t\t\tif (initialBinding?.toId !== bindingAfter.toId) {\n\t\t\t\t\tthis.pointingId = bindingAfter.toId\n\t\t\t\t\tthis.isPrecise = pointerVelocity.len() < 0.5 || altKey\n\t\t\t\t\tthis.isPreciseId = this.isPrecise ? bindingAfter.toId : null\n\t\t\t\t\tthis.resetExactTimeout()\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (initialBinding) {\n\t\t\t\t\tthis.pointingId = null\n\t\t\t\t\tthis.isPrecise = false\n\t\t\t\t\tthis.isPreciseId = null\n\t\t\t\t\tthis.resetExactTimeout()\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (changes) {\n\t\t\teditor.updateShapes([next])\n\t\t}\n\t}\n}\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["import {\n\tMat,\n\tStateNode,\n\tTLArrowShape,\n\tTLHandle,\n\tTLLineShape,\n\tTLPointerEventInfo,\n\tTLShapeId,\n\tTLShapePartial,\n\tVec,\n\tkickoutOccludedShapes,\n\tsnapAngle,\n\tsortByIndex,\n\tstructuredClone,\n\twarnOnce,\n} from '@tldraw/editor'\nimport { ArrowShapeUtil } from '../../../shapes/arrow/ArrowShapeUtil'\nimport { clearArrowTargetState } from '../../../shapes/arrow/arrowTargetState'\nimport { getArrowBindings } from '../../../shapes/arrow/shared'\n\nexport type DraggingHandleInfo = TLPointerEventInfo & {\n\tshape: TLArrowShape | TLLineShape\n\ttarget: 'handle'\n\tonInteractionEnd?: string\n\tisCreating?: boolean\n\tcreatingMarkId?: string\n}\n\nexport class DraggingHandle extends StateNode {\n\tstatic override id = 'dragging_handle'\n\n\tshapeId!: TLShapeId\n\tinitialHandle!: TLHandle\n\tinitialAdjacentHandle!: TLHandle | null\n\tinitialPagePoint!: Vec\n\n\tmarkId!: string\n\tinitialPageTransform!: Mat\n\tinitialPageRotation!: number\n\n\tinfo!: DraggingHandleInfo\n\n\tisPrecise = false\n\tisPreciseId: TLShapeId | null = null\n\tpointingId: TLShapeId | null = null\n\n\toverride onEnter(info: DraggingHandleInfo) {\n\t\tconst { shape, isCreating, creatingMarkId, handle } = info\n\t\tthis.info = info\n\t\tthis.parent.setCurrentToolIdMask(info.onInteractionEnd)\n\t\tthis.shapeId = shape.id\n\t\tthis.markId = ''\n\n\t\tif (isCreating) {\n\t\t\tif (creatingMarkId) {\n\t\t\t\tthis.markId = creatingMarkId\n\t\t\t} else {\n\t\t\t\t// handle legacy implicit `creating:{shapeId}` marks\n\t\t\t\tconst markId = this.editor.getMarkIdMatching(\n\t\t\t\t\t`creating:${this.editor.getOnlySelectedShapeId()}`\n\t\t\t\t)\n\t\t\t\tif (markId) {\n\t\t\t\t\tthis.markId = markId\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tthis.markId = this.editor.markHistoryStoppingPoint('dragging handle')\n\t\t}\n\n\t\tthis.initialHandle = structuredClone(handle)\n\n\t\tthis.initialPageTransform = this.editor.getShapePageTransform(shape)!\n\t\tthis.initialPageRotation = this.initialPageTransform.rotation()\n\t\tthis.initialPagePoint = this.editor.inputs.originPagePoint.clone()\n\n\t\tthis.editor.setCursor({ type: isCreating ? 'cross' : 'grabbing', rotation: 0 })\n\n\t\tconst handles = this.editor.getShapeHandles(shape)!.sort(sortByIndex)\n\t\tconst index = handles.findIndex((h) => h.id === info.handle.id)\n\n\t\t// Find the adjacent handle\n\t\tthis.initialAdjacentHandle = null\n\n\t\t// Start from the handle and work forward\n\t\tfor (let i = index + 1; i < handles.length; i++) {\n\t\t\tconst handle = handles[i]\n\t\t\tif (handle.type === 'vertex' && handle.id !== 'middle' && handle.id !== info.handle.id) {\n\t\t\t\tthis.initialAdjacentHandle = handle\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\t// If still no handle, start from the end and work backward\n\t\tif (!this.initialAdjacentHandle) {\n\t\t\tfor (let i = handles.length - 1; i >= 0; i--) {\n\t\t\t\tconst handle = handles[i]\n\t\t\t\tif (handle.type === 'vertex' && handle.id !== 'middle' && handle.id !== info.handle.id) {\n\t\t\t\t\tthis.initialAdjacentHandle = handle\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// <!-- Only relevant to arrows\n\t\tif (this.editor.isShapeOfType<TLArrowShape>(shape, 'arrow')) {\n\t\t\tconst initialBinding = getArrowBindings(this.editor, shape)[info.handle.id as 'start' | 'end']\n\n\t\t\tthis.isPrecise = false\n\n\t\t\tif (initialBinding) {\n\t\t\t\tthis.isPrecise = initialBinding.props.isPrecise\n\t\t\t\tif (this.isPrecise) {\n\t\t\t\t\tthis.isPreciseId = initialBinding.toId\n\t\t\t\t} else {\n\t\t\t\t\tthis.resetExactTimeout()\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// -->\n\n\t\t// Call onHandleDragStart callback\n\t\tconst handleDragInfo = {\n\t\t\thandle: this.initialHandle,\n\t\t\tisPrecise: this.isPrecise,\n\t\t\tisCreatingShape: !!this.info.isCreating,\n\t\t\tinitial: shape,\n\t\t}\n\t\tconst util = this.editor.getShapeUtil(shape)\n\t\tconst startChanges = util.onHandleDragStart?.(shape, handleDragInfo)\n\t\tif (startChanges) {\n\t\t\tthis.editor.updateShapes([{ ...startChanges, id: shape.id, type: shape.type }])\n\t\t}\n\n\t\tthis.update()\n\n\t\tthis.editor.select(this.shapeId)\n\t}\n\n\t// Only relevant to arrows\n\tprivate exactTimeout = -1\n\n\t// Only relevant to arrows\n\tprivate resetExactTimeout() {\n\t\tconst arrowUtil = this.editor.getShapeUtil<ArrowShapeUtil>('arrow')\n\t\tconst timeoutValue = arrowUtil.options.pointingPreciseTimeout\n\n\t\tif (this.exactTimeout !== -1) {\n\t\t\tthis.clearExactTimeout()\n\t\t}\n\n\t\tthis.exactTimeout = this.editor.timers.setTimeout(() => {\n\t\t\tif (this.getIsActive() && !this.isPrecise) {\n\t\t\t\tthis.isPrecise = true\n\t\t\t\tthis.isPreciseId = this.pointingId\n\t\t\t\tthis.update()\n\t\t\t}\n\t\t\tthis.exactTimeout = -1\n\t\t}, timeoutValue)\n\t}\n\n\t// Only relevant to arrows\n\tprivate clearExactTimeout() {\n\t\tif (this.exactTimeout !== -1) {\n\t\t\tclearTimeout(this.exactTimeout)\n\t\t\tthis.exactTimeout = -1\n\t\t}\n\t}\n\n\toverride onPointerMove() {\n\t\tthis.update()\n\t}\n\n\toverride onKeyDown() {\n\t\tthis.update()\n\t}\n\n\toverride onKeyUp() {\n\t\tthis.update()\n\t}\n\n\toverride onPointerUp() {\n\t\tthis.complete()\n\t}\n\n\toverride onComplete() {\n\t\tthis.update()\n\t\tthis.complete()\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\toverride onExit() {\n\t\tthis.parent.setCurrentToolIdMask(undefined)\n\t\tclearArrowTargetState(this.editor)\n\t\tthis.editor.snaps.clearIndicators()\n\n\t\tthis.editor.setCursor({ type: 'default', rotation: 0 })\n\t}\n\n\tprivate complete() {\n\t\tthis.editor.snaps.clearIndicators()\n\t\tkickoutOccludedShapes(this.editor, [this.shapeId])\n\n\t\t// Call onHandleDragEnd callback before state transitions\n\t\tconst shape = this.editor.getShape(this.shapeId)\n\t\tif (shape) {\n\t\t\tconst util = this.editor.getShapeUtil(shape)\n\t\t\tconst handleDragInfo = {\n\t\t\t\thandle: this.initialHandle,\n\t\t\t\tisPrecise: this.isPrecise,\n\t\t\t\tisCreatingShape: !!this.info.isCreating,\n\t\t\t\tinitial: this.info.shape,\n\t\t\t}\n\t\t\tconst endChanges = util.onHandleDragEnd?.(shape, handleDragInfo)\n\t\t\tif (endChanges) {\n\t\t\t\tthis.editor.updateShapes([{ ...endChanges, id: shape.id, type: shape.type }])\n\t\t\t}\n\t\t}\n\n\t\tconst { onInteractionEnd } = this.info\n\t\tif (this.editor.getInstanceState().isToolLocked && onInteractionEnd) {\n\t\t\t// Return to the tool that was active before this one,\n\t\t\t// but only if tool lock is turned on!\n\t\t\tthis.editor.setCurrentTool(onInteractionEnd, { shapeId: this.shapeId })\n\t\t\treturn\n\t\t}\n\n\t\tthis.parent.transition('idle')\n\t}\n\n\tprivate cancel() {\n\t\t// Call onHandleDragCancel callback before bailing to mark\n\t\tconst shape = this.editor.getShape(this.shapeId)\n\t\tif (shape) {\n\t\t\tconst util = this.editor.getShapeUtil(shape)\n\t\t\tconst handleDragInfo = {\n\t\t\t\thandle: this.initialHandle,\n\t\t\t\tisPrecise: this.isPrecise,\n\t\t\t\tisCreatingShape: !!this.info.isCreating,\n\t\t\t\tinitial: this.info.shape,\n\t\t\t}\n\t\t\tutil.onHandleDragCancel?.(shape, handleDragInfo)\n\t\t}\n\n\t\tthis.editor.bailToMark(this.markId)\n\t\tthis.editor.snaps.clearIndicators()\n\n\t\tconst { onInteractionEnd } = this.info\n\t\tif (onInteractionEnd) {\n\t\t\t// Return to the tool that was active before this one,\n\t\t\t// whether tool lock is turned on or not!\n\t\t\tthis.editor.setCurrentTool(onInteractionEnd, { shapeId: this.shapeId })\n\t\t\treturn\n\t\t}\n\n\t\tthis.parent.transition('idle')\n\t}\n\n\tprivate update() {\n\t\tconst { editor, shapeId, initialPagePoint } = this\n\t\tconst { initialHandle, initialPageRotation, initialAdjacentHandle } = this\n\t\tconst isSnapMode = this.editor.user.getIsSnapMode()\n\t\tconst {\n\t\t\tsnaps,\n\t\t\tinputs: { currentPagePoint, shiftKey, ctrlKey, altKey, pointerVelocity },\n\t\t} = editor\n\n\t\tconst initial = this.info.shape\n\n\t\tconst shape = editor.getShape(shapeId)\n\t\tif (!shape) return\n\t\tconst util = editor.getShapeUtil(shape)\n\n\t\tconst initialBinding = editor.isShapeOfType<TLArrowShape>(shape, 'arrow')\n\t\t\t? getArrowBindings(editor, shape)[initialHandle.id as 'start' | 'end']\n\t\t\t: undefined\n\n\t\tlet point = currentPagePoint\n\t\t\t.clone()\n\t\t\t.sub(initialPagePoint)\n\t\t\t.rot(-initialPageRotation)\n\t\t\t.add(initialHandle)\n\n\t\tif (shiftKey && initialAdjacentHandle && initialHandle.id !== 'middle') {\n\t\t\tconst angle = Vec.Angle(initialAdjacentHandle, point)\n\t\t\tconst snappedAngle = snapAngle(angle, 24)\n\t\t\tconst angleDifference = snappedAngle - angle\n\t\t\tpoint = Vec.RotWith(point, initialAdjacentHandle, angleDifference)\n\t\t}\n\n\t\t// Clear any existing snaps\n\t\teditor.snaps.clearIndicators()\n\n\t\tlet nextHandle = { ...initialHandle, x: point.x, y: point.y }\n\n\t\tlet canSnap = false\n\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\tif (initialHandle.canSnap && initialHandle.snapType) {\n\t\t\twarnOnce(\n\t\t\t\t'canSnap is deprecated. Cannot use both canSnap and snapType together - snapping disabled. Please use only snapType.'\n\t\t\t)\n\t\t} else {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\tcanSnap = initialHandle.canSnap || initialHandle.snapType !== undefined\n\t\t}\n\n\t\tif (canSnap && (isSnapMode ? !ctrlKey : ctrlKey)) {\n\t\t\t// We're snapping\n\t\t\tconst pageTransform = editor.getShapePageTransform(shape.id)\n\t\t\tif (!pageTransform) throw Error('Expected a page transform')\n\n\t\t\tconst snap = snaps.handles.snapHandle({ currentShapeId: shapeId, handle: nextHandle })\n\n\t\t\tif (snap) {\n\t\t\t\tsnap.nudge.rot(-editor.getShapeParentTransform(shape)!.rotation())\n\t\t\t\tpoint.add(snap.nudge)\n\t\t\t\tnextHandle = { ...initialHandle, x: point.x, y: point.y }\n\t\t\t}\n\t\t}\n\n\t\tconst changes = util.onHandleDrag?.(shape, {\n\t\t\thandle: nextHandle,\n\t\t\tisPrecise: this.isPrecise || altKey,\n\t\t\tisCreatingShape: !!this.info.isCreating,\n\t\t\tinitial: initial,\n\t\t})\n\n\t\tconst next: TLShapePartial<any> = { id: shape.id, type: shape.type, ...changes }\n\n\t\t// Arrows\n\t\tif (\n\t\t\tinitialHandle.type === 'vertex' &&\n\t\t\tthis.editor.isShapeOfType<TLArrowShape>(shape, 'arrow')\n\t\t) {\n\t\t\tconst bindingAfter = getArrowBindings(editor, shape)[initialHandle.id as 'start' | 'end']\n\n\t\t\tif (bindingAfter) {\n\t\t\t\tif (initialBinding?.toId !== bindingAfter.toId) {\n\t\t\t\t\tthis.pointingId = bindingAfter.toId\n\t\t\t\t\tthis.isPrecise = pointerVelocity.len() < 0.5 || altKey\n\t\t\t\t\tthis.isPreciseId = this.isPrecise ? bindingAfter.toId : null\n\t\t\t\t\tthis.resetExactTimeout()\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (initialBinding) {\n\t\t\t\t\tthis.pointingId = null\n\t\t\t\t\tthis.isPrecise = false\n\t\t\t\t\tthis.isPreciseId = null\n\t\t\t\t\tthis.resetExactTimeout()\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (changes) {\n\t\t\teditor.updateShapes([next])\n\t\t}\n\t}\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["handle"]
|
|
7
7
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useContainer, useEditor, usePeerIds, useValue } from "@tldraw/editor";
|
|
3
3
|
import { Popover as _Popover } from "radix-ui";
|
|
4
|
+
import { PORTRAIT_BREAKPOINT } from "../../constants.mjs";
|
|
5
|
+
import { useBreakpoint } from "../../context/breakpoints.mjs";
|
|
4
6
|
import { useMenuIsOpen } from "../../hooks/useMenuIsOpen.mjs";
|
|
5
7
|
import { useTranslation } from "../../hooks/useTranslation/useTranslation.mjs";
|
|
6
8
|
import { PeopleMenuAvatar } from "./PeopleMenuAvatar.mjs";
|
|
@@ -15,10 +17,12 @@ function PeopleMenu({ children }) {
|
|
|
15
17
|
const userColor = useValue("user", () => editor.user.getColor(), [editor]);
|
|
16
18
|
const userName = useValue("user", () => editor.user.getName(), [editor]);
|
|
17
19
|
const [isOpen, onOpenChange] = useMenuIsOpen("people menu");
|
|
20
|
+
const breakpoint = useBreakpoint();
|
|
21
|
+
const maxAvatars = breakpoint <= PORTRAIT_BREAKPOINT.MOBILE_XS ? 1 : 5;
|
|
18
22
|
if (!userIds.length) return null;
|
|
19
23
|
return /* @__PURE__ */ jsxs(_Popover.Root, { onOpenChange, open: isOpen, children: [
|
|
20
24
|
/* @__PURE__ */ jsx(_Popover.Trigger, { dir: "ltr", asChild: true, children: /* @__PURE__ */ jsx("button", { className: "tlui-people-menu__avatars-button", title: msg("people-menu.title"), children: /* @__PURE__ */ jsxs("div", { className: "tlui-people-menu__avatars", children: [
|
|
21
|
-
userIds.slice(-
|
|
25
|
+
userIds.slice(-maxAvatars).map((userId) => /* @__PURE__ */ jsx(PeopleMenuAvatar, { userId }, userId)),
|
|
22
26
|
userIds.length > 0 && /* @__PURE__ */ jsx(
|
|
23
27
|
"div",
|
|
24
28
|
{
|
|
@@ -29,7 +33,7 @@ function PeopleMenu({ children }) {
|
|
|
29
33
|
children: userName?.[0] ?? ""
|
|
30
34
|
}
|
|
31
35
|
),
|
|
32
|
-
userIds.length >
|
|
36
|
+
userIds.length > maxAvatars && /* @__PURE__ */ jsx(PeopleMenuMore, { count: userIds.length - maxAvatars })
|
|
33
37
|
] }) }) }),
|
|
34
38
|
/* @__PURE__ */ jsx(_Popover.Portal, { container, children: /* @__PURE__ */ jsx(
|
|
35
39
|
_Popover.Content,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/lib/ui/components/SharePanel/PeopleMenu.tsx"],
|
|
4
|
-
"sourcesContent": ["import { useContainer, useEditor, usePeerIds, useValue } from '@tldraw/editor'\nimport { Popover as _Popover } from 'radix-ui'\nimport { ReactNode } from 'react'\nimport { useMenuIsOpen } from '../../hooks/useMenuIsOpen'\nimport { useTranslation } from '../../hooks/useTranslation/useTranslation'\nimport { PeopleMenuAvatar } from './PeopleMenuAvatar'\nimport { PeopleMenuItem } from './PeopleMenuItem'\nimport { PeopleMenuMore } from './PeopleMenuMore'\nimport { UserPresenceEditor } from './UserPresenceEditor'\n\n/** @public */\nexport interface PeopleMenuProps {\n\tchildren?: ReactNode\n}\n\n/** @public @react */\nexport function PeopleMenu({ children }: PeopleMenuProps) {\n\tconst msg = useTranslation()\n\n\tconst container = useContainer()\n\tconst editor = useEditor()\n\n\tconst userIds = usePeerIds()\n\tconst userColor = useValue('user', () => editor.user.getColor(), [editor])\n\tconst userName = useValue('user', () => editor.user.getName(), [editor])\n\n\tconst [isOpen, onOpenChange] = useMenuIsOpen('people menu')\n\n\tif (!userIds.length) return null\n\n\treturn (\n\t\t<_Popover.Root onOpenChange={onOpenChange} open={isOpen}>\n\t\t\t<_Popover.Trigger dir=\"ltr\" asChild>\n\t\t\t\t<button className=\"tlui-people-menu__avatars-button\" title={msg('people-menu.title')}>\n\t\t\t\t\t<div className=\"tlui-people-menu__avatars\">\n\t\t\t\t\t\t{userIds.slice(-
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import { useContainer, useEditor, usePeerIds, useValue } from '@tldraw/editor'\nimport { Popover as _Popover } from 'radix-ui'\nimport { ReactNode } from 'react'\nimport { PORTRAIT_BREAKPOINT } from '../../constants'\nimport { useBreakpoint } from '../../context/breakpoints'\nimport { useMenuIsOpen } from '../../hooks/useMenuIsOpen'\nimport { useTranslation } from '../../hooks/useTranslation/useTranslation'\nimport { PeopleMenuAvatar } from './PeopleMenuAvatar'\nimport { PeopleMenuItem } from './PeopleMenuItem'\nimport { PeopleMenuMore } from './PeopleMenuMore'\nimport { UserPresenceEditor } from './UserPresenceEditor'\n\n/** @public */\nexport interface PeopleMenuProps {\n\tchildren?: ReactNode\n}\n\n/** @public @react */\nexport function PeopleMenu({ children }: PeopleMenuProps) {\n\tconst msg = useTranslation()\n\n\tconst container = useContainer()\n\tconst editor = useEditor()\n\n\tconst userIds = usePeerIds()\n\tconst userColor = useValue('user', () => editor.user.getColor(), [editor])\n\tconst userName = useValue('user', () => editor.user.getName(), [editor])\n\n\tconst [isOpen, onOpenChange] = useMenuIsOpen('people menu')\n\tconst breakpoint = useBreakpoint()\n\tconst maxAvatars = breakpoint <= PORTRAIT_BREAKPOINT.MOBILE_XS ? 1 : 5\n\n\tif (!userIds.length) return null\n\n\treturn (\n\t\t<_Popover.Root onOpenChange={onOpenChange} open={isOpen}>\n\t\t\t<_Popover.Trigger dir=\"ltr\" asChild>\n\t\t\t\t<button className=\"tlui-people-menu__avatars-button\" title={msg('people-menu.title')}>\n\t\t\t\t\t<div className=\"tlui-people-menu__avatars\">\n\t\t\t\t\t\t{userIds.slice(-maxAvatars).map((userId) => (\n\t\t\t\t\t\t\t<PeopleMenuAvatar key={userId} userId={userId} />\n\t\t\t\t\t\t))}\n\t\t\t\t\t\t{userIds.length > 0 && (\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tclassName=\"tlui-people-menu__avatar\"\n\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\tbackgroundColor: userColor,\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{userName?.[0] ?? ''}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t{userIds.length > maxAvatars && <PeopleMenuMore count={userIds.length - maxAvatars} />}\n\t\t\t\t\t</div>\n\t\t\t\t</button>\n\t\t\t</_Popover.Trigger>\n\t\t\t<_Popover.Portal container={container}>\n\t\t\t\t<_Popover.Content\n\t\t\t\t\tdir=\"ltr\"\n\t\t\t\t\tclassName=\"tlui-menu\"\n\t\t\t\t\tside=\"bottom\"\n\t\t\t\t\tsideOffset={2}\n\t\t\t\t\tcollisionPadding={4}\n\t\t\t\t>\n\t\t\t\t\t<div className=\"tlui-people-menu__wrapper\">\n\t\t\t\t\t\t<div className=\"tlui-people-menu__section\">\n\t\t\t\t\t\t\t<UserPresenceEditor />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t{userIds.length > 0 && (\n\t\t\t\t\t\t\t<div className=\"tlui-people-menu__section\">\n\t\t\t\t\t\t\t\t{userIds.map((userId) => {\n\t\t\t\t\t\t\t\t\treturn <PeopleMenuItem key={userId + '_presence'} userId={userId} />\n\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t{children}\n\t\t\t\t\t</div>\n\t\t\t\t</_Popover.Content>\n\t\t\t</_Popover.Portal>\n\t\t</_Popover.Root>\n\t)\n}\n"],
|
|
5
|
+
"mappings": "AAsCK,SAEE,KAFF;AAtCL,SAAS,cAAc,WAAW,YAAY,gBAAgB;AAC9D,SAAS,WAAW,gBAAgB;AAEpC,SAAS,2BAA2B;AACpC,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB;AAC9B,SAAS,sBAAsB;AAC/B,SAAS,wBAAwB;AACjC,SAAS,sBAAsB;AAC/B,SAAS,sBAAsB;AAC/B,SAAS,0BAA0B;AAQ5B,SAAS,WAAW,EAAE,SAAS,GAAoB;AACzD,QAAM,MAAM,eAAe;AAE3B,QAAM,YAAY,aAAa;AAC/B,QAAM,SAAS,UAAU;AAEzB,QAAM,UAAU,WAAW;AAC3B,QAAM,YAAY,SAAS,QAAQ,MAAM,OAAO,KAAK,SAAS,GAAG,CAAC,MAAM,CAAC;AACzE,QAAM,WAAW,SAAS,QAAQ,MAAM,OAAO,KAAK,QAAQ,GAAG,CAAC,MAAM,CAAC;AAEvE,QAAM,CAAC,QAAQ,YAAY,IAAI,cAAc,aAAa;AAC1D,QAAM,aAAa,cAAc;AACjC,QAAM,aAAa,cAAc,oBAAoB,YAAY,IAAI;AAErE,MAAI,CAAC,QAAQ,OAAQ,QAAO;AAE5B,SACC,qBAAC,SAAS,MAAT,EAAc,cAA4B,MAAM,QAChD;AAAA,wBAAC,SAAS,SAAT,EAAiB,KAAI,OAAM,SAAO,MAClC,8BAAC,YAAO,WAAU,oCAAmC,OAAO,IAAI,mBAAmB,GAClF,+BAAC,SAAI,WAAU,6BACb;AAAA,cAAQ,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,WAChC,oBAAC,oBAA8B,UAAR,MAAwB,CAC/C;AAAA,MACA,QAAQ,SAAS,KACjB;AAAA,QAAC;AAAA;AAAA,UACA,WAAU;AAAA,UACV,OAAO;AAAA,YACN,iBAAiB;AAAA,UAClB;AAAA,UAEC,qBAAW,CAAC,KAAK;AAAA;AAAA,MACnB;AAAA,MAEA,QAAQ,SAAS,cAAc,oBAAC,kBAAe,OAAO,QAAQ,SAAS,YAAY;AAAA,OACrF,GACD,GACD;AAAA,IACA,oBAAC,SAAS,QAAT,EAAgB,WAChB;AAAA,MAAC,SAAS;AAAA,MAAT;AAAA,QACA,KAAI;AAAA,QACJ,WAAU;AAAA,QACV,MAAK;AAAA,QACL,YAAY;AAAA,QACZ,kBAAkB;AAAA,QAElB,+BAAC,SAAI,WAAU,6BACd;AAAA,8BAAC,SAAI,WAAU,6BACd,8BAAC,sBAAmB,GACrB;AAAA,UACC,QAAQ,SAAS,KACjB,oBAAC,SAAI,WAAU,6BACb,kBAAQ,IAAI,CAAC,WAAW;AACxB,mBAAO,oBAAC,kBAA0C,UAAtB,SAAS,WAA6B;AAAA,UACnE,CAAC,GACF;AAAA,UAEA;AAAA,WACF;AAAA;AAAA,IACD,GACD;AAAA,KACD;AAEF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -91,7 +91,7 @@ const StylePanelButtonPicker = memo(function StylePanelButtonPicker2(props) {
|
|
|
91
91
|
{
|
|
92
92
|
"data-testid": `style.${uiType}`,
|
|
93
93
|
type: "single",
|
|
94
|
-
value: value.type === "shared" ? value.value :
|
|
94
|
+
value: value.type === "shared" ? value.value : null,
|
|
95
95
|
asChild: true,
|
|
96
96
|
children: /* @__PURE__ */ jsx(Layout, { children: items.map((item) => {
|
|
97
97
|
const isActive = value.type === "shared" && value.value === item.value;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/lib/ui/components/StylePanel/StylePanelButtonPicker.tsx"],
|
|
4
|
-
"sourcesContent": ["import {\n\tDefaultColorStyle,\n\tgetColorValue,\n\tSharedStyle,\n\tStyleProp,\n\tTLDefaultColorStyle,\n\tuseEditor,\n} from '@tldraw/editor'\nimport { memo, ReactElement, useMemo, useRef } from 'react'\nimport { useDefaultColorTheme } from '../../../shapes/shared/useDefaultColorTheme'\nimport { StyleValuesForUi } from '../../../styles'\nimport { PORTRAIT_BREAKPOINT } from '../../constants'\nimport { useBreakpoint } from '../../context/breakpoints'\nimport { TLUiTranslationKey } from '../../hooks/useTranslation/TLUiTranslationKey'\nimport { useTranslation } from '../../hooks/useTranslation/useTranslation'\nimport { TldrawUiButtonIcon } from '../primitives/Button/TldrawUiButtonIcon'\nimport {\n\tTldrawUiToolbar,\n\tTldrawUiToolbarToggleGroup,\n\tTldrawUiToolbarToggleItem,\n} from '../primitives/TldrawUiToolbar'\nimport { TldrawUiGrid, TldrawUiRow } from '../primitives/layout'\nimport { useStylePanelContext } from './StylePanelContext'\nimport { StylePanelSubheading } from './StylePanelSubheading'\n\n/** @public */\nexport interface StylePanelButtonPickerProps<T extends string> {\n\ttitle: string\n\tuiType: string\n\tstyle: StyleProp<T>\n\tvalue: SharedStyle<T>\n\titems: StyleValuesForUi<T>\n\tonValueChange?(style: StyleProp<T>, value: T): void\n\tonHistoryMark?(id: string): void\n}\n\n/** @public */\nexport const StylePanelButtonPicker = memo(function StylePanelButtonPicker<T extends string>(\n\tprops: StylePanelButtonPickerProps<T>\n) {\n\tconst ctx = useStylePanelContext()\n\n\tconst {\n\t\tuiType,\n\t\titems,\n\t\ttitle,\n\t\tstyle,\n\t\tvalue,\n\t\tonValueChange = ctx.onValueChange,\n\t\tonHistoryMark = ctx.onHistoryMark,\n\t} = props\n\tconst theme = useDefaultColorTheme()\n\tconst editor = useEditor()\n\tconst msg = useTranslation()\n\tconst breakpoint = useBreakpoint()\n\n\tconst rPointing = useRef(false)\n\tconst rPointingOriginalActiveElement = useRef<HTMLElement | null>(null)\n\n\tconst {\n\t\thandleButtonClick,\n\t\thandleButtonPointerDown,\n\t\thandleButtonPointerEnter,\n\t\thandleButtonPointerUp,\n\t} = useMemo(() => {\n\t\tconst handlePointerUp = () => {\n\t\t\trPointing.current = false\n\t\t\twindow.removeEventListener('pointerup', handlePointerUp)\n\n\t\t\t// This is fun little micro-optimization to make sure that the focus\n\t\t\t// is retained on a text label. That way, you can continue typing\n\t\t\t// after selecting a style.\n\t\t\tconst origActiveEl = rPointingOriginalActiveElement.current\n\t\t\tif (\n\t\t\t\torigActiveEl &&\n\t\t\t\t(['TEXTAREA', 'INPUT'].includes(origActiveEl.nodeName) || origActiveEl.isContentEditable)\n\t\t\t) {\n\t\t\t\torigActiveEl.focus()\n\t\t\t} else if (breakpoint >= PORTRAIT_BREAKPOINT.TABLET_SM) {\n\t\t\t\teditor.getContainer().focus()\n\t\t\t}\n\t\t\trPointingOriginalActiveElement.current = null\n\t\t}\n\n\t\tconst handleButtonClick = (e: React.PointerEvent<HTMLButtonElement>) => {\n\t\t\tconst { id } = e.currentTarget.dataset\n\t\t\tif (value.type === 'shared' && value.value === id) return\n\n\t\t\tonHistoryMark?.('point picker item')\n\t\t\tonValueChange(style, id as T)\n\t\t}\n\n\t\tconst handleButtonPointerDown = (e: React.PointerEvent<HTMLButtonElement>) => {\n\t\t\tconst { id } = e.currentTarget.dataset\n\n\t\t\tonHistoryMark?.('point picker item')\n\t\t\tonValueChange(style, id as T)\n\n\t\t\trPointing.current = true\n\t\t\trPointingOriginalActiveElement.current = document.activeElement as HTMLElement\n\t\t\twindow.addEventListener('pointerup', handlePointerUp) // see TLD-658\n\t\t}\n\n\t\tconst handleButtonPointerEnter = (e: React.PointerEvent<HTMLButtonElement>) => {\n\t\t\tif (!rPointing.current) return\n\n\t\t\tconst { id } = e.currentTarget.dataset\n\t\t\tonValueChange(style, id as T)\n\t\t}\n\n\t\tconst handleButtonPointerUp = (e: React.PointerEvent<HTMLButtonElement>) => {\n\t\t\tconst { id } = e.currentTarget.dataset\n\t\t\tif (value.type === 'shared' && value.value === id) return\n\n\t\t\tonValueChange(style, id as T)\n\t\t}\n\n\t\treturn {\n\t\t\thandleButtonClick,\n\t\t\thandleButtonPointerDown,\n\t\t\thandleButtonPointerEnter,\n\t\t\thandleButtonPointerUp,\n\t\t}\n\t}, [editor, breakpoint, value, onHistoryMark, onValueChange, style])\n\n\tconst Layout = items.length > 4 ? TldrawUiGrid : TldrawUiRow\n\n\treturn (\n\t\t<>\n\t\t\t{ctx.enhancedA11yMode && <StylePanelSubheading>{title}</StylePanelSubheading>}\n\t\t\t<TldrawUiToolbar label={title}>\n\t\t\t\t<TldrawUiToolbarToggleGroup\n\t\t\t\t\tdata-testid={`style.${uiType}`}\n\t\t\t\t\ttype=\"single\"\n\t\t\t\t\tvalue={value.type === 'shared' ? value.value :
|
|
4
|
+
"sourcesContent": ["import {\n\tDefaultColorStyle,\n\tgetColorValue,\n\tSharedStyle,\n\tStyleProp,\n\tTLDefaultColorStyle,\n\tuseEditor,\n} from '@tldraw/editor'\nimport { memo, ReactElement, useMemo, useRef } from 'react'\nimport { useDefaultColorTheme } from '../../../shapes/shared/useDefaultColorTheme'\nimport { StyleValuesForUi } from '../../../styles'\nimport { PORTRAIT_BREAKPOINT } from '../../constants'\nimport { useBreakpoint } from '../../context/breakpoints'\nimport { TLUiTranslationKey } from '../../hooks/useTranslation/TLUiTranslationKey'\nimport { useTranslation } from '../../hooks/useTranslation/useTranslation'\nimport { TldrawUiButtonIcon } from '../primitives/Button/TldrawUiButtonIcon'\nimport {\n\tTldrawUiToolbar,\n\tTldrawUiToolbarToggleGroup,\n\tTldrawUiToolbarToggleItem,\n} from '../primitives/TldrawUiToolbar'\nimport { TldrawUiGrid, TldrawUiRow } from '../primitives/layout'\nimport { useStylePanelContext } from './StylePanelContext'\nimport { StylePanelSubheading } from './StylePanelSubheading'\n\n/** @public */\nexport interface StylePanelButtonPickerProps<T extends string> {\n\ttitle: string\n\tuiType: string\n\tstyle: StyleProp<T>\n\tvalue: SharedStyle<T>\n\titems: StyleValuesForUi<T>\n\tonValueChange?(style: StyleProp<T>, value: T): void\n\tonHistoryMark?(id: string): void\n}\n\n/** @public */\nexport const StylePanelButtonPicker = memo(function StylePanelButtonPicker<T extends string>(\n\tprops: StylePanelButtonPickerProps<T>\n) {\n\tconst ctx = useStylePanelContext()\n\n\tconst {\n\t\tuiType,\n\t\titems,\n\t\ttitle,\n\t\tstyle,\n\t\tvalue,\n\t\tonValueChange = ctx.onValueChange,\n\t\tonHistoryMark = ctx.onHistoryMark,\n\t} = props\n\tconst theme = useDefaultColorTheme()\n\tconst editor = useEditor()\n\tconst msg = useTranslation()\n\tconst breakpoint = useBreakpoint()\n\n\tconst rPointing = useRef(false)\n\tconst rPointingOriginalActiveElement = useRef<HTMLElement | null>(null)\n\n\tconst {\n\t\thandleButtonClick,\n\t\thandleButtonPointerDown,\n\t\thandleButtonPointerEnter,\n\t\thandleButtonPointerUp,\n\t} = useMemo(() => {\n\t\tconst handlePointerUp = () => {\n\t\t\trPointing.current = false\n\t\t\twindow.removeEventListener('pointerup', handlePointerUp)\n\n\t\t\t// This is fun little micro-optimization to make sure that the focus\n\t\t\t// is retained on a text label. That way, you can continue typing\n\t\t\t// after selecting a style.\n\t\t\tconst origActiveEl = rPointingOriginalActiveElement.current\n\t\t\tif (\n\t\t\t\torigActiveEl &&\n\t\t\t\t(['TEXTAREA', 'INPUT'].includes(origActiveEl.nodeName) || origActiveEl.isContentEditable)\n\t\t\t) {\n\t\t\t\torigActiveEl.focus()\n\t\t\t} else if (breakpoint >= PORTRAIT_BREAKPOINT.TABLET_SM) {\n\t\t\t\teditor.getContainer().focus()\n\t\t\t}\n\t\t\trPointingOriginalActiveElement.current = null\n\t\t}\n\n\t\tconst handleButtonClick = (e: React.PointerEvent<HTMLButtonElement>) => {\n\t\t\tconst { id } = e.currentTarget.dataset\n\t\t\tif (value.type === 'shared' && value.value === id) return\n\n\t\t\tonHistoryMark?.('point picker item')\n\t\t\tonValueChange(style, id as T)\n\t\t}\n\n\t\tconst handleButtonPointerDown = (e: React.PointerEvent<HTMLButtonElement>) => {\n\t\t\tconst { id } = e.currentTarget.dataset\n\n\t\t\tonHistoryMark?.('point picker item')\n\t\t\tonValueChange(style, id as T)\n\n\t\t\trPointing.current = true\n\t\t\trPointingOriginalActiveElement.current = document.activeElement as HTMLElement\n\t\t\twindow.addEventListener('pointerup', handlePointerUp) // see TLD-658\n\t\t}\n\n\t\tconst handleButtonPointerEnter = (e: React.PointerEvent<HTMLButtonElement>) => {\n\t\t\tif (!rPointing.current) return\n\n\t\t\tconst { id } = e.currentTarget.dataset\n\t\t\tonValueChange(style, id as T)\n\t\t}\n\n\t\tconst handleButtonPointerUp = (e: React.PointerEvent<HTMLButtonElement>) => {\n\t\t\tconst { id } = e.currentTarget.dataset\n\t\t\tif (value.type === 'shared' && value.value === id) return\n\n\t\t\tonValueChange(style, id as T)\n\t\t}\n\n\t\treturn {\n\t\t\thandleButtonClick,\n\t\t\thandleButtonPointerDown,\n\t\t\thandleButtonPointerEnter,\n\t\t\thandleButtonPointerUp,\n\t\t}\n\t}, [editor, breakpoint, value, onHistoryMark, onValueChange, style])\n\n\tconst Layout = items.length > 4 ? TldrawUiGrid : TldrawUiRow\n\n\treturn (\n\t\t<>\n\t\t\t{ctx.enhancedA11yMode && <StylePanelSubheading>{title}</StylePanelSubheading>}\n\t\t\t<TldrawUiToolbar label={title}>\n\t\t\t\t<TldrawUiToolbarToggleGroup\n\t\t\t\t\tdata-testid={`style.${uiType}`}\n\t\t\t\t\ttype=\"single\"\n\t\t\t\t\tvalue={value.type === 'shared' ? value.value : null}\n\t\t\t\t\tasChild\n\t\t\t\t>\n\t\t\t\t\t<Layout>\n\t\t\t\t\t\t{items.map((item) => {\n\t\t\t\t\t\t\tconst isActive = value.type === 'shared' && value.value === item.value\n\t\t\t\t\t\t\tconst label =\n\t\t\t\t\t\t\t\ttitle + ' \u2014 ' + msg(`${uiType}-style.${item.value}` as TLUiTranslationKey)\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<TldrawUiToolbarToggleItem\n\t\t\t\t\t\t\t\t\ttype=\"icon\"\n\t\t\t\t\t\t\t\t\tkey={item.value}\n\t\t\t\t\t\t\t\t\tdata-id={item.value}\n\t\t\t\t\t\t\t\t\tdata-testid={`style.${uiType}.${item.value}`}\n\t\t\t\t\t\t\t\t\taria-label={label + (isActive ? ` (${msg('style-panel.selected')})` : '')}\n\t\t\t\t\t\t\t\t\ttooltip={\n\t\t\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t\t\t<div>{label}</div>\n\t\t\t\t\t\t\t\t\t\t\t{isActive ? <div>({msg('style-panel.selected')})</div> : null}\n\t\t\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tvalue={item.value}\n\t\t\t\t\t\t\t\t\tdata-state={value.type === 'shared' && value.value === item.value ? 'on' : 'off'}\n\t\t\t\t\t\t\t\t\tdata-isactive={isActive}\n\t\t\t\t\t\t\t\t\ttitle={label}\n\t\t\t\t\t\t\t\t\tstyle={\n\t\t\t\t\t\t\t\t\t\tstyle === (DefaultColorStyle as StyleProp<unknown>)\n\t\t\t\t\t\t\t\t\t\t\t? { color: getColorValue(theme, item.value as TLDefaultColorStyle, 'solid') }\n\t\t\t\t\t\t\t\t\t\t\t: undefined\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tonPointerEnter={handleButtonPointerEnter}\n\t\t\t\t\t\t\t\t\tonPointerDown={handleButtonPointerDown}\n\t\t\t\t\t\t\t\t\tonPointerUp={handleButtonPointerUp}\n\t\t\t\t\t\t\t\t\tonClick={handleButtonClick}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<TldrawUiButtonIcon icon={item.icon} />\n\t\t\t\t\t\t\t\t</TldrawUiToolbarToggleItem>\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t})}\n\t\t\t\t\t</Layout>\n\t\t\t\t</TldrawUiToolbarToggleGroup>\n\t\t\t</TldrawUiToolbar>\n\t\t</>\n\t)\n}) as <T extends string>(props: StylePanelButtonPickerProps<T>) => ReactElement\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": ["StylePanelButtonPicker", "handleButtonClick", "handleButtonPointerDown", "handleButtonPointerEnter", "handleButtonPointerUp"]
|
|
7
7
|
}
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
useMaybeEditor
|
|
15
15
|
} from "@tldraw/editor";
|
|
16
16
|
import * as React from "react";
|
|
17
|
+
import { createBookmarkFromUrl } from "../../shapes/bookmark/bookmarks.mjs";
|
|
17
18
|
import { fitFrameToContent, removeFrame } from "../../utils/frames/frames.mjs";
|
|
18
19
|
import { generateShapeAnnouncementMessage } from "../components/A11y.mjs";
|
|
19
20
|
import { EditLinkDialog } from "../components/EditLinkDialog.mjs";
|
|
@@ -309,38 +310,31 @@ function ActionsProvider({ overrides, children }) {
|
|
|
309
310
|
{
|
|
310
311
|
id: "convert-to-bookmark",
|
|
311
312
|
label: "action.convert-to-bookmark",
|
|
312
|
-
onSelect(source) {
|
|
313
|
+
async onSelect(source) {
|
|
313
314
|
if (!canApplySelectionAction()) return;
|
|
314
315
|
if (mustGoBackToSelectToolFirst()) return;
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
type: "bookmark",
|
|
330
|
-
rotation: shape.rotation,
|
|
331
|
-
x: newPos.x,
|
|
332
|
-
y: newPos.y,
|
|
333
|
-
opacity: 1,
|
|
334
|
-
props: {
|
|
335
|
-
url: shape.props.url
|
|
316
|
+
trackEvent("convert-to-bookmark", { source });
|
|
317
|
+
const shapes = editor.getSelectedShapes();
|
|
318
|
+
const markId = editor.markHistoryStoppingPoint("convert shapes to bookmark");
|
|
319
|
+
const creationPromises = [];
|
|
320
|
+
for (const shape of shapes) {
|
|
321
|
+
if (!shape || !editor.isShapeOfType(shape, "embed") || !shape.props.url)
|
|
322
|
+
continue;
|
|
323
|
+
const center = editor.getShapePageBounds(shape)?.center;
|
|
324
|
+
if (!center) continue;
|
|
325
|
+
editor.deleteShapes([shape.id]);
|
|
326
|
+
creationPromises.push(
|
|
327
|
+
createBookmarkFromUrl(editor, { url: shape.props.url, center }).then((res) => {
|
|
328
|
+
if (!res.ok) {
|
|
329
|
+
throw new Error(res.error);
|
|
336
330
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
editor.
|
|
343
|
-
|
|
331
|
+
return res;
|
|
332
|
+
})
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
await Promise.all(creationPromises).catch((error) => {
|
|
336
|
+
editor.bailToMark(markId);
|
|
337
|
+
console.error(error);
|
|
344
338
|
});
|
|
345
339
|
}
|
|
346
340
|
},
|