UNPKG

tldraw

Version:

A tiny little drawing editor.

198 lines (197 loc) • 6.07 kB
import { jsx, jsxs } from "react/jsx-runtime"; import { DefaultFontFamilies, openWindow, preventDefault, useEditor, useReactor, useValue } from "@tldraw/editor"; import classNames from "classnames"; import React, { useMemo } from "react"; import { renderHtmlFromRichText } from "../../utils/text/richText.mjs"; import { RichTextArea } from "../text/RichTextArea.mjs"; import { TEXT_PROPS } from "./default-shape-constants.mjs"; import { isLegacyAlign } from "./legacyProps.mjs"; import { useEditableRichText } from "./useEditableRichText.mjs"; const RichTextLabel = React.memo(function RichTextLabel2({ shapeId, type, richText, labelColor, font, fontSize, lineHeight, align, verticalAlign, wrap, isSelected, padding = 0, onKeyDown: handleKeyDownCustom, classNamePrefix, style, textWidth, textHeight, hasCustomTabBehavior, showTextOutline = true }) { const editor = useEditor(); const isDragging = React.useRef(false); const { rInput, isEmpty, isEditing, isReadyForEditing, ...editableTextRest } = useEditableRichText(shapeId, type, richText); const html = useMemo(() => { if (richText) { return renderHtmlFromRichText(editor, richText); } return void 0; }, [editor, richText]); const selectToolActive = useValue( "isSelectToolActive", () => editor.getCurrentToolId() === "select", [editor] ); useReactor( "isDragging", () => { editor.getInstanceState(); isDragging.current = editor.inputs.getIsDragging(); }, [editor] ); const legacyAlign = isLegacyAlign(align); const handlePointerDown = (e) => { if (e.target instanceof HTMLElement && (e.target.tagName === "A" || e.target.closest("a"))) { preventDefault(e); if (!selectToolActive) return; const link = e.target.closest("a")?.getAttribute("href") ?? ""; const handlePointerUp = (e2) => { if (e2.name !== "pointer_up" || !link) return; if (!isDragging.current) { openWindow(link, "_blank", false); } editor.off("event", handlePointerUp); }; editor.on("event", handlePointerUp); } }; if (!isEditing && isEmpty) return null; const cssPrefix = classNamePrefix || "tl-text"; return /* @__PURE__ */ jsx( "div", { className: classNames( `${cssPrefix}-label tl-text-wrapper tl-rich-text-wrapper`, showTextOutline ? "tl-text__outline" : "tl-text__no-outline" ), "aria-hidden": !isEditing, "data-font": font, "data-align": align, "data-hastext": !isEmpty, "data-isediting": isEditing, "data-textwrap": !!wrap, "data-isselected": isSelected, style: { justifyContent: align === "middle" || legacyAlign ? "center" : align, alignItems: verticalAlign === "middle" ? "center" : verticalAlign, padding, ...style }, children: /* @__PURE__ */ jsxs( "div", { className: `${cssPrefix}-label__inner tl-text-content__wrapper`, style: { fontSize, lineHeight: lineHeight.toString(), minHeight: Math.floor(fontSize * lineHeight) + "px", minWidth: Math.ceil(textWidth || 0), color: labelColor, width: textWidth ? Math.ceil(textWidth) : void 0, height: textHeight ? Math.ceil(textHeight) : void 0 }, children: [ /* @__PURE__ */ jsx("div", { className: `${cssPrefix} tl-text tl-text-content`, dir: "auto", children: richText && /* @__PURE__ */ jsx( "div", { className: "tl-rich-text", "data-is-select-tool-active": selectToolActive, dangerouslySetInnerHTML: { __html: html || "" }, onPointerDown: handlePointerDown, "data-is-ready-for-editing": isReadyForEditing } ) }), (isReadyForEditing || isSelected) && /* @__PURE__ */ jsx( RichTextArea, { ref: rInput, richText, isEditing, shapeId, ...editableTextRest, hasCustomTabBehavior, handleKeyDown: handleKeyDownCustom ?? editableTextRest.handleKeyDown } ) ] } ) } ); }); function RichTextSVG({ bounds, richText, fontSize, font, align, verticalAlign, wrap, labelColor, padding, showTextOutline = true }) { const editor = useEditor(); const html = renderHtmlFromRichText(editor, richText); const textAlign = align === "middle" ? "center" : align === "start" ? "start" : "end"; const justifyContent = align === "middle" ? "center" : align === "start" ? "flex-start" : "flex-end"; const alignItems = verticalAlign === "middle" ? "center" : verticalAlign === "start" ? "flex-start" : "flex-end"; const wrapperStyle = { display: "flex", fontFamily: DefaultFontFamilies[font], height: `100%`, justifyContent, alignItems, padding: `${padding}px` }; const style = { fontSize: `${fontSize}px`, wrap: wrap ? "wrap" : "nowrap", color: labelColor, lineHeight: TEXT_PROPS.lineHeight, textAlign, width: "100%", wordWrap: "break-word", overflowWrap: "break-word", whiteSpace: "pre-wrap", textShadow: showTextOutline ? "var(--tl-text-outline)" : "none", tabSize: "var(--tl-tab-size, 2)" }; return /* @__PURE__ */ jsx( "foreignObject", { x: bounds.minX, y: bounds.minY, width: bounds.w, height: bounds.h, className: classNames( "tl-export-embed-styles tl-rich-text tl-rich-text-svg", showTextOutline ? "tl-text__outline" : "tl-text__no-outline" ), children: /* @__PURE__ */ jsx("div", { style: wrapperStyle, children: /* @__PURE__ */ jsx("div", { dangerouslySetInnerHTML: { __html: html }, style }) }) } ); } export { RichTextLabel, RichTextSVG }; //# sourceMappingURL=RichTextLabel.mjs.map