tldraw
Version:
A tiny little drawing editor.
8 lines (7 loc) • 11.2 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../../../../src/lib/shapes/bookmark/BookmarkShapeUtil.tsx"],
"sourcesContent": ["import {\n\tBaseBoxShapeUtil,\n\tHTMLContainer,\n\tT,\n\tTLAssetId,\n\tTLBookmarkAsset,\n\tTLBookmarkShape,\n\tTLBookmarkShapeProps,\n\tbookmarkShapeMigrations,\n\tbookmarkShapeProps,\n\tlerp,\n\ttlenv,\n\ttoDomPrecision,\n\tuseEditor,\n\tuseSvgExportContext,\n} from '@tldraw/editor'\nimport classNames from 'classnames'\nimport { PointerEventHandler, useCallback, useState } from 'react'\nimport { convertCommonTitleHTMLEntities } from '../../utils/text/text'\nimport { HyperlinkButton } from '../shared/HyperlinkButton'\nimport { LINK_ICON } from '../shared/icons-editor'\nimport { getRotatedBoxShadow } from '../shared/rotated-box-shadow'\nimport {\n\tBOOKMARK_HEIGHT,\n\tBOOKMARK_WIDTH,\n\tgetHumanReadableAddress,\n\tsetBookmarkHeight,\n\tupdateBookmarkAssetOnUrlChange,\n} from './bookmarks'\n\n/** @public */\nexport class BookmarkShapeUtil extends BaseBoxShapeUtil<TLBookmarkShape> {\n\tstatic override type = 'bookmark' as const\n\tstatic override props = bookmarkShapeProps\n\tstatic override migrations = bookmarkShapeMigrations\n\n\toverride canResize() {\n\t\treturn false\n\t}\n\n\toverride hideSelectionBoundsFg() {\n\t\treturn true\n\t}\n\n\toverride getText(shape: TLBookmarkShape) {\n\t\treturn shape.props.url\n\t}\n\n\toverride getAriaDescriptor(shape: TLBookmarkShape) {\n\t\tconst asset = (\n\t\t\tshape.props.assetId ? this.editor.getAsset(shape.props.assetId) : null\n\t\t) as TLBookmarkAsset | null\n\n\t\tif (!asset?.props.title) return undefined\n\n\t\treturn (\n\t\t\tconvertCommonTitleHTMLEntities(asset.props.title) +\n\t\t\t(asset.props.description ? ', ' + asset.props.description : '')\n\t\t)\n\t}\n\n\toverride getDefaultProps(): TLBookmarkShape['props'] {\n\t\treturn {\n\t\t\turl: '',\n\t\t\tw: BOOKMARK_WIDTH,\n\t\t\th: BOOKMARK_HEIGHT,\n\t\t\tassetId: null,\n\t\t}\n\t}\n\n\toverride component(shape: TLBookmarkShape) {\n\t\tconst { assetId, url, h } = shape.props\n\t\tconst rotation = this.editor.getShapePageTransform(shape)!.rotation()\n\n\t\treturn <BookmarkShapeComponent assetId={assetId} url={url} h={h} rotation={rotation} />\n\t}\n\n\toverride indicator(shape: TLBookmarkShape) {\n\t\treturn <BookmarkIndicatorComponent w={shape.props.w} h={shape.props.h} />\n\t}\n\n\toverride useLegacyIndicator() {\n\t\treturn false\n\t}\n\n\toverride getIndicatorPath(shape: TLBookmarkShape): Path2D {\n\t\tconst path = new Path2D()\n\t\tpath.roundRect(0, 0, shape.props.w, shape.props.h, 6)\n\t\treturn path\n\t}\n\n\toverride onBeforeCreate(next: TLBookmarkShape) {\n\t\treturn setBookmarkHeight(this.editor, next)\n\t}\n\n\toverride onBeforeUpdate(prev: TLBookmarkShape, shape: TLBookmarkShape) {\n\t\tif (prev.props.url !== shape.props.url) {\n\t\t\tif (!T.linkUrl.isValid(shape.props.url)) {\n\t\t\t\treturn { ...shape, props: { ...shape.props, url: prev.props.url } }\n\t\t\t} else {\n\t\t\t\tupdateBookmarkAssetOnUrlChange(this.editor, shape)\n\t\t\t}\n\t\t}\n\n\t\tif (prev.props.assetId !== shape.props.assetId) {\n\t\t\treturn setBookmarkHeight(this.editor, shape)\n\t\t}\n\n\t\treturn undefined\n\t}\n\toverride getInterpolatedProps(\n\t\tstartShape: TLBookmarkShape,\n\t\tendShape: TLBookmarkShape,\n\t\tt: number\n\t): TLBookmarkShapeProps {\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\nexport function BookmarkIndicatorComponent({ w, h }: { w: number; h: number }) {\n\treturn <rect width={toDomPrecision(w)} height={toDomPrecision(h)} rx=\"6\" ry=\"6\" />\n}\n\nexport function BookmarkShapeComponent({\n\tassetId,\n\trotation,\n\turl,\n\th,\n\tshowImageContainer = true,\n}: {\n\tassetId: TLAssetId | null\n\trotation: number\n\th: number\n\turl: string\n\tshowImageContainer?: boolean\n}) {\n\tconst editor = useEditor()\n\n\tconst asset = assetId ? (editor.getAsset(assetId) as TLBookmarkAsset) : null\n\n\tconst isSafariExport = !!useSvgExportContext() && tlenv.isSafari\n\n\tconst address = getHumanReadableAddress(url)\n\n\tconst [isFaviconValid, setIsFaviconValid] = useState(true)\n\tconst onFaviconError = () => setIsFaviconValid(false)\n\n\tconst markAsHandledOnShiftKey = useCallback<PointerEventHandler>(\n\t\t(e) => {\n\t\t\tif (!editor.inputs.getShiftKey()) editor.markEventAsHandled(e)\n\t\t},\n\t\t[editor]\n\t)\n\n\treturn (\n\t\t<HTMLContainer>\n\t\t\t<div\n\t\t\t\tclassName={classNames(\n\t\t\t\t\t'tl-bookmark__container',\n\t\t\t\t\tisSafariExport && 'tl-bookmark__container--safariExport'\n\t\t\t\t)}\n\t\t\t\tstyle={{\n\t\t\t\t\tboxShadow: isSafariExport ? undefined : getRotatedBoxShadow(rotation),\n\t\t\t\t\tmaxHeight: h,\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{showImageContainer && (!asset || asset.props.image) && (\n\t\t\t\t\t<div className=\"tl-bookmark__image_container\">\n\t\t\t\t\t\t{asset ? (\n\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\tclassName=\"tl-bookmark__image\"\n\t\t\t\t\t\t\t\tdraggable={false}\n\t\t\t\t\t\t\t\treferrerPolicy=\"strict-origin-when-cross-origin\"\n\t\t\t\t\t\t\t\tsrc={asset?.props.image}\n\t\t\t\t\t\t\t\talt={asset?.props.title || ''}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<div className=\"tl-bookmark__placeholder\" />\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t{asset?.props.image && <HyperlinkButton url={url} />}\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t\t<div className=\"tl-bookmark__copy_container\">\n\t\t\t\t\t{asset?.props.title ? (\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\tclassName=\"tl-bookmark__link\"\n\t\t\t\t\t\t\thref={url || ''}\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\t\tdraggable={false}\n\t\t\t\t\t\t\tonPointerDown={markAsHandledOnShiftKey}\n\t\t\t\t\t\t\tonPointerUp={markAsHandledOnShiftKey}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<h2 className=\"tl-bookmark__heading\">\n\t\t\t\t\t\t\t\t{convertCommonTitleHTMLEntities(asset.props.title)}\n\t\t\t\t\t\t\t</h2>\n\t\t\t\t\t\t</a>\n\t\t\t\t\t) : null}\n\t\t\t\t\t{asset?.props.description && asset?.props.image ? (\n\t\t\t\t\t\t<p className=\"tl-bookmark__description\">{asset.props.description}</p>\n\t\t\t\t\t) : null}\n\t\t\t\t\t<a\n\t\t\t\t\t\tclassName=\"tl-bookmark__link\"\n\t\t\t\t\t\thref={url || ''}\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\tdraggable={false}\n\t\t\t\t\t\tonPointerDown={markAsHandledOnShiftKey}\n\t\t\t\t\t\tonPointerUp={markAsHandledOnShiftKey}\n\t\t\t\t\t>\n\t\t\t\t\t\t{isFaviconValid && asset?.props.favicon ? (\n\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\tclassName=\"tl-bookmark__favicon\"\n\t\t\t\t\t\t\t\tsrc={asset?.props.favicon}\n\t\t\t\t\t\t\t\treferrerPolicy=\"strict-origin-when-cross-origin\"\n\t\t\t\t\t\t\t\tonError={onFaviconError}\n\t\t\t\t\t\t\t\talt={`favicon of ${address}`}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tclassName=\"tl-hyperlink__icon\"\n\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\tmask: `url(\"${LINK_ICON}\") center 100% / 100% no-repeat`,\n\t\t\t\t\t\t\t\t\tWebkitMask: `url(\"${LINK_ICON}\") center 100% / 100% no-repeat`,\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t<span>{address}</span>\n\t\t\t\t\t</a>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</HTMLContainer>\n\t)\n}\n"],
"mappings": "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",
"names": []
}