@nasser-sw/fabric 7.0.0-beta1 → 7.0.1-beta1
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/index.js +416 -55
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/index.min.mjs +1 -1
- package/dist/index.min.mjs.map +1 -1
- package/dist/index.mjs +416 -55
- package/dist/index.mjs.map +1 -1
- package/dist/index.node.cjs +416 -55
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.mjs +416 -55
- package/dist/index.node.mjs.map +1 -1
- package/dist/src/shapes/Textbox.d.ts +13 -0
- package/dist/src/shapes/Textbox.d.ts.map +1 -1
- package/dist/src/shapes/Textbox.min.mjs +1 -1
- package/dist/src/shapes/Textbox.min.mjs.map +1 -1
- package/dist/src/shapes/Textbox.mjs +168 -0
- package/dist/src/shapes/Textbox.mjs.map +1 -1
- package/dist/src/text/overlayEditor.d.ts +8 -0
- package/dist/src/text/overlayEditor.d.ts.map +1 -1
- package/dist/src/text/overlayEditor.min.mjs +1 -1
- package/dist/src/text/overlayEditor.min.mjs.map +1 -1
- package/dist/src/text/overlayEditor.mjs +248 -55
- package/dist/src/text/overlayEditor.mjs.map +1 -1
- package/dist-extensions/src/shapes/Textbox.d.ts +13 -0
- package/dist-extensions/src/shapes/Textbox.d.ts.map +1 -1
- package/dist-extensions/src/text/overlayEditor.d.ts +8 -0
- package/dist-extensions/src/text/overlayEditor.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/shapes/Textbox.ts +119 -0
- package/src/text/overlayEditor.ts +354 -96
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Textbox.mjs","sources":["../../../src/shapes/Textbox.ts"],"sourcesContent":["import type { TClassProperties, TOptions } from '../typedefs';\r\nimport { IText } from './IText/IText';\r\nimport { classRegistry } from '../ClassRegistry';\r\nimport { createTextboxDefaultControls } from '../controls/commonControls';\r\nimport { JUSTIFY } from './Text/constants';\r\nimport type { TextStyleDeclaration } from './Text/StyledText';\r\nimport type { SerializedITextProps, ITextProps } from './IText/IText';\r\nimport type { ITextEvents } from './IText/ITextBehavior';\r\nimport type { TextLinesInfo } from './Text/Text';\r\nimport type { Control } from '../controls/Control';\r\nimport { layoutText } from '../text/layout';\r\n\r\n// @TODO: Many things here are configuration related and shouldn't be on the class nor prototype\r\n// regexes, list of properties that are not suppose to change by instances, magic consts.\r\n// this will be a separated effort\r\nexport const textboxDefaultValues: Partial<TClassProperties<Textbox>> = {\r\n minWidth: 20,\r\n dynamicMinWidth: 2,\r\n lockScalingFlip: true,\r\n noScaleCache: false,\r\n _wordJoiners: /[ \\t\\r]/,\r\n splitByGrapheme: false,\r\n};\r\n\r\nexport type GraphemeData = {\r\n wordsData: {\r\n word: string[];\r\n width: number;\r\n }[][];\r\n largestWordWidth: number;\r\n};\r\n\r\nexport type StyleMap = Record<string, { line: number; offset: number }>;\r\n\r\n// @TODO this is not complete\r\ninterface UniqueTextboxProps {\r\n minWidth: number;\r\n splitByGrapheme: boolean;\r\n dynamicMinWidth: number;\r\n _wordJoiners: RegExp;\r\n}\r\n\r\nexport interface SerializedTextboxProps\r\n extends SerializedITextProps,\r\n Pick<UniqueTextboxProps, 'minWidth' | 'splitByGrapheme'> {}\r\n\r\nexport interface TextboxProps extends ITextProps, UniqueTextboxProps {}\r\n\r\n/**\r\n * Textbox class, based on IText, allows the user to resize the text rectangle\r\n * and wraps lines automatically. Textboxes have their Y scaling locked, the\r\n * user can only change width. Height is adjusted automatically based on the\r\n * wrapping of lines.\r\n */\r\nexport class Textbox<\r\n Props extends TOptions<TextboxProps> = Partial<TextboxProps>,\r\n SProps extends SerializedTextboxProps = SerializedTextboxProps,\r\n EventSpec extends ITextEvents = ITextEvents,\r\n >\r\n extends IText<Props, SProps, EventSpec>\r\n implements UniqueTextboxProps\r\n{\r\n /**\r\n * Minimum width of textbox, in pixels.\r\n * @type Number\r\n */\r\n declare minWidth: number;\r\n\r\n /**\r\n * Minimum calculated width of a textbox, in pixels.\r\n * fixed to 2 so that an empty textbox cannot go to 0\r\n * and is still selectable without text.\r\n * @type Number\r\n */\r\n declare dynamicMinWidth: number;\r\n\r\n /**\r\n * Use this boolean property in order to split strings that have no white space concept.\r\n * this is a cheap way to help with chinese/japanese\r\n * @type Boolean\r\n * @since 2.6.0\r\n */\r\n declare splitByGrapheme: boolean;\r\n\r\n declare _wordJoiners: RegExp;\r\n\r\n declare _styleMap: StyleMap;\r\n\r\n declare isWrapping: boolean;\r\n\r\n static type = 'Textbox';\r\n\r\n static textLayoutProperties = [...IText.textLayoutProperties, 'width'];\r\n\r\n static ownDefaults = textboxDefaultValues;\r\n\r\n static getDefaults(): Record<string, any> {\r\n return {\r\n ...super.getDefaults(),\r\n ...Textbox.ownDefaults,\r\n };\r\n }\r\n\r\n /**\r\n * Constructor\r\n * @param {String} text Text string\r\n * @param {Object} [options] Options object\r\n */\r\n constructor(text: string, options?: Props) {\r\n super(text, { ...Textbox.ownDefaults, ...options } as Props);\r\n }\r\n\r\n /**\r\n * Creates the default control object.\r\n * If you prefer to have on instance of controls shared among all objects\r\n * make this function return an empty object and add controls to the ownDefaults object\r\n */\r\n static createControls(): { controls: Record<string, Control> } {\r\n return { controls: createTextboxDefaultControls() };\r\n }\r\n\r\n /**\r\n * Unlike superclass's version of this function, Textbox does not update\r\n * its width.\r\n * @private\r\n * @override\r\n */\r\n initDimensions() {\r\n if (!this.initialized) {\r\n return;\r\n }\r\n \r\n // Use advanced layout if enabled\r\n if (this.enableAdvancedLayout) {\r\n return this.initDimensionsAdvanced();\r\n }\r\n \r\n this.isEditing && this.initDelayedCursor();\r\n this._clearCache();\r\n // clear dynamicMinWidth as it will be different after we re-wrap line\r\n this.dynamicMinWidth = 0;\r\n // wrap lines\r\n this._styleMap = this._generateStyleMap(this._splitText());\r\n // if after wrapping, the width is smaller than dynamicMinWidth, change the width and re-wrap\r\n if (this.dynamicMinWidth > this.width) {\r\n this._set('width', this.dynamicMinWidth);\r\n }\r\n if (this.textAlign.includes(JUSTIFY)) {\r\n // once text is measured we need to make space fatter to make justified text.\r\n this.enlargeSpaces();\r\n }\r\n // clear cache and re-calculate height\r\n this.height = this.calcTextHeight();\r\n }\r\n\r\n /**\r\n * Advanced dimensions calculation using new layout engine\r\n * @private\r\n */\r\n initDimensionsAdvanced() {\r\n if (!this.initialized) {\r\n return;\r\n }\r\n \r\n this.isEditing && this.initDelayedCursor();\r\n this._clearCache();\r\n this.dynamicMinWidth = 0;\r\n \r\n // Use new layout engine\r\n const layout = layoutText({\r\n text: this.text,\r\n width: this.width,\r\n height: this.height,\r\n wrap: this.wrap || 'word',\r\n align: (this as any)._mapTextAlignToAlign(this.textAlign),\r\n ellipsis: this.ellipsis || false,\r\n fontSize: this.fontSize,\r\n lineHeight: this.lineHeight,\r\n letterSpacing: this.letterSpacing || 0,\r\n charSpacing: this.charSpacing,\r\n direction: this.direction === 'inherit' ? 'ltr' : this.direction,\r\n fontFamily: this.fontFamily,\r\n fontStyle: this.fontStyle,\r\n fontWeight: this.fontWeight,\r\n verticalAlign: this.verticalAlign || 'top',\r\n });\r\n \r\n // Update dynamic minimum width based on layout\r\n if (layout.lines.length > 0) {\r\n const maxLineWidth = Math.max(...layout.lines.map(line => line.width));\r\n this.dynamicMinWidth = Math.max(this.minWidth, maxLineWidth);\r\n }\r\n \r\n // Adjust width if needed (preserving Textbox behavior)\r\n if (this.dynamicMinWidth > this.width) {\r\n this._set('width', this.dynamicMinWidth);\r\n // Re-layout with new width\r\n const newLayout = layoutText({\r\n ...(this as any)._getAdvancedLayoutOptions(),\r\n width: this.width,\r\n });\r\n this.height = newLayout.totalHeight;\r\n (this as any)._convertLayoutToLegacyFormat(newLayout);\r\n } else {\r\n this.height = layout.totalHeight;\r\n (this as any)._convertLayoutToLegacyFormat(layout);\r\n }\r\n \r\n // Generate style map for compatibility\r\n this._styleMap = this._generateStyleMapFromLayout(layout);\r\n this.dirty = true;\r\n }\r\n\r\n /**\r\n * Generate style map from new layout format\r\n * @private\r\n */\r\n _generateStyleMapFromLayout(layout: any): StyleMap {\r\n const map: StyleMap = {};\r\n let realLineCount = 0;\r\n let charCount = 0;\r\n\r\n layout.lines.forEach((line: any, i: number) => {\r\n if (line.text.includes('\\n') && i > 0) {\r\n realLineCount++;\r\n }\r\n \r\n map[i] = { line: realLineCount, offset: 0 };\r\n charCount += line.graphemes.length;\r\n \r\n if (i < layout.lines.length - 1) {\r\n charCount += 1; // newline character\r\n }\r\n });\r\n\r\n return map;\r\n }\r\n\r\n /**\r\n * Generate an object that translates the style object so that it is\r\n * broken up by visual lines (new lines and automatic wrapping).\r\n * The original text styles object is broken up by actual lines (new lines only),\r\n * which is only sufficient for Text / IText\r\n * @private\r\n */\r\n _generateStyleMap(textInfo: TextLinesInfo): StyleMap {\r\n let realLineCount = 0,\r\n realLineCharCount = 0,\r\n charCount = 0;\r\n const map: StyleMap = {};\r\n\r\n for (let i = 0; i < textInfo.graphemeLines.length; i++) {\r\n if (textInfo.graphemeText[charCount] === '\\n' && i > 0) {\r\n realLineCharCount = 0;\r\n charCount++;\r\n realLineCount++;\r\n } else if (\r\n !this.splitByGrapheme &&\r\n this._reSpaceAndTab.test(textInfo.graphemeText[charCount]) &&\r\n i > 0\r\n ) {\r\n // this case deals with space's that are removed from end of lines when wrapping\r\n realLineCharCount++;\r\n charCount++;\r\n }\r\n\r\n map[i] = { line: realLineCount, offset: realLineCharCount };\r\n\r\n charCount += textInfo.graphemeLines[i].length;\r\n realLineCharCount += textInfo.graphemeLines[i].length;\r\n }\r\n\r\n return map;\r\n }\r\n\r\n /**\r\n * Returns true if object has a style property or has it on a specified line\r\n * @param {Number} lineIndex\r\n * @return {Boolean}\r\n */\r\n styleHas(property: keyof TextStyleDeclaration, lineIndex: number): boolean {\r\n if (this._styleMap && !this.isWrapping) {\r\n const map = this._styleMap[lineIndex];\r\n if (map) {\r\n lineIndex = map.line;\r\n }\r\n }\r\n return super.styleHas(property, lineIndex);\r\n }\r\n\r\n /**\r\n * Returns true if object has no styling or no styling in a line\r\n * @param {Number} lineIndex , lineIndex is on wrapped lines.\r\n * @return {Boolean}\r\n */\r\n isEmptyStyles(lineIndex: number): boolean {\r\n if (!this.styles) {\r\n return true;\r\n }\r\n let offset = 0,\r\n nextLineIndex = lineIndex + 1,\r\n nextOffset: number,\r\n shouldLimit = false;\r\n const map = this._styleMap[lineIndex],\r\n mapNextLine = this._styleMap[lineIndex + 1];\r\n if (map) {\r\n lineIndex = map.line;\r\n offset = map.offset;\r\n }\r\n if (mapNextLine) {\r\n nextLineIndex = mapNextLine.line;\r\n shouldLimit = nextLineIndex === lineIndex;\r\n nextOffset = mapNextLine.offset;\r\n }\r\n const obj =\r\n typeof lineIndex === 'undefined'\r\n ? this.styles\r\n : { line: this.styles[lineIndex] };\r\n for (const p1 in obj) {\r\n for (const p2 in obj[p1]) {\r\n const p2Number = parseInt(p2, 10);\r\n if (p2Number >= offset && (!shouldLimit || p2Number < nextOffset!)) {\r\n for (const p3 in obj[p1][p2]) {\r\n return false;\r\n }\r\n }\r\n }\r\n }\r\n return true;\r\n }\r\n\r\n /**\r\n * @protected\r\n * @param {Number} lineIndex\r\n * @param {Number} charIndex\r\n * @return {TextStyleDeclaration} a style object reference to the existing one or a new empty object when undefined\r\n */\r\n _getStyleDeclaration(\r\n lineIndex: number,\r\n charIndex: number,\r\n ): TextStyleDeclaration {\r\n if (this._styleMap && !this.isWrapping) {\r\n const map = this._styleMap[lineIndex];\r\n if (!map) {\r\n return {};\r\n }\r\n lineIndex = map.line;\r\n charIndex = map.offset + charIndex;\r\n }\r\n return super._getStyleDeclaration(lineIndex, charIndex);\r\n }\r\n\r\n /**\r\n * @param {Number} lineIndex\r\n * @param {Number} charIndex\r\n * @param {Object} style\r\n * @private\r\n */\r\n protected _setStyleDeclaration(\r\n lineIndex: number,\r\n charIndex: number,\r\n style: object,\r\n ) {\r\n const map = this._styleMap[lineIndex];\r\n super._setStyleDeclaration(map.line, map.offset + charIndex, style);\r\n }\r\n\r\n /**\r\n * @param {Number} lineIndex\r\n * @param {Number} charIndex\r\n * @private\r\n */\r\n protected _deleteStyleDeclaration(lineIndex: number, charIndex: number) {\r\n const map = this._styleMap[lineIndex];\r\n super._deleteStyleDeclaration(map.line, map.offset + charIndex);\r\n }\r\n\r\n /**\r\n * probably broken need a fix\r\n * Returns the real style line that correspond to the wrapped lineIndex line\r\n * Used just to verify if the line does exist or not.\r\n * @param {Number} lineIndex\r\n * @returns {Boolean} if the line exists or not\r\n * @private\r\n */\r\n protected _getLineStyle(lineIndex: number): boolean {\r\n const map = this._styleMap[lineIndex];\r\n return !!this.styles[map.line];\r\n }\r\n\r\n /**\r\n * Set the line style to an empty object so that is initialized\r\n * @param {Number} lineIndex\r\n * @param {Object} style\r\n * @private\r\n */\r\n protected _setLineStyle(lineIndex: number) {\r\n const map = this._styleMap[lineIndex];\r\n super._setLineStyle(map.line);\r\n }\r\n\r\n /**\r\n * Wraps text using the 'width' property of Textbox. First this function\r\n * splits text on newlines, so we preserve newlines entered by the user.\r\n * Then it wraps each line using the width of the Textbox by calling\r\n * _wrapLine().\r\n * @param {Array} lines The string array of text that is split into lines\r\n * @param {Number} desiredWidth width you want to wrap to\r\n * @returns {Array} Array of lines\r\n */\r\n _wrapText(lines: string[], desiredWidth: number): string[][] {\r\n this.isWrapping = true;\r\n // extract all thewords and the widths to optimally wrap lines.\r\n const data = this.getGraphemeDataForRender(lines);\r\n const wrapped: string[][] = [];\r\n for (let i = 0; i < data.wordsData.length; i++) {\r\n wrapped.push(...this._wrapLine(i, desiredWidth, data));\r\n }\r\n this.isWrapping = false;\r\n return wrapped;\r\n }\r\n\r\n /**\r\n * For each line of text terminated by an hard line stop,\r\n * measure each word width and extract the largest word from all.\r\n * The returned words here are the one that at the end will be rendered.\r\n * @param {string[]} lines the lines we need to measure\r\n *\r\n */\r\n getGraphemeDataForRender(lines: string[]): GraphemeData {\r\n const splitByGrapheme = this.splitByGrapheme,\r\n infix = splitByGrapheme ? '' : ' ';\r\n\r\n let largestWordWidth = 0;\r\n\r\n const data = lines.map((line, lineIndex) => {\r\n let offset = 0;\r\n const wordsOrGraphemes = splitByGrapheme\r\n ? this.graphemeSplit(line)\r\n : this.wordSplit(line);\r\n\r\n if (wordsOrGraphemes.length === 0) {\r\n return [{ word: [], width: 0 }];\r\n }\r\n\r\n return wordsOrGraphemes.map((word: string) => {\r\n // if using splitByGrapheme words are already in graphemes.\r\n const graphemeArray = splitByGrapheme\r\n ? [word]\r\n : this.graphemeSplit(word);\r\n const width = this._measureWord(graphemeArray, lineIndex, offset);\r\n largestWordWidth = Math.max(width, largestWordWidth);\r\n offset += graphemeArray.length + infix.length;\r\n return { word: graphemeArray, width };\r\n });\r\n });\r\n\r\n return {\r\n wordsData: data,\r\n largestWordWidth,\r\n };\r\n }\r\n\r\n /**\r\n * Helper function to measure a string of text, given its lineIndex and charIndex offset\r\n * It gets called when charBounds are not available yet.\r\n * Override if necessary\r\n * Use with {@link Textbox#wordSplit}\r\n *\r\n * @param {CanvasRenderingContext2D} ctx\r\n * @param {String} text\r\n * @param {number} lineIndex\r\n * @param {number} charOffset\r\n * @returns {number}\r\n */\r\n _measureWord(word: string[], lineIndex: number, charOffset = 0): number {\r\n let width = 0,\r\n prevGrapheme;\r\n const skipLeft = true;\r\n for (let i = 0, len = word.length; i < len; i++) {\r\n const box = this._getGraphemeBox(\r\n word[i],\r\n lineIndex,\r\n i + charOffset,\r\n prevGrapheme,\r\n skipLeft,\r\n );\r\n width += box.kernedWidth;\r\n prevGrapheme = word[i];\r\n }\r\n return width;\r\n }\r\n\r\n /**\r\n * Override this method to customize word splitting\r\n * Use with {@link Textbox#_measureWord}\r\n * @param {string} value\r\n * @returns {string[]} array of words\r\n */\r\n wordSplit(value: string): string[] {\r\n return value.split(this._wordJoiners);\r\n }\r\n\r\n /**\r\n * Wraps a line of text using the width of the Textbox as desiredWidth\r\n * and leveraging the known width o words from GraphemeData\r\n * @private\r\n * @param {Number} lineIndex\r\n * @param {Number} desiredWidth width you want to wrap the line to\r\n * @param {GraphemeData} graphemeData an object containing all the lines' words width.\r\n * @param {Number} reservedSpace space to remove from wrapping for custom functionalities\r\n * @returns {Array} Array of line(s) into which the given text is wrapped\r\n * to.\r\n */\r\n _wrapLine(\r\n lineIndex: number,\r\n desiredWidth: number,\r\n { largestWordWidth, wordsData }: GraphemeData,\r\n reservedSpace = 0,\r\n ): string[][] {\r\n const additionalSpace = this._getWidthOfCharSpacing(),\r\n splitByGrapheme = this.splitByGrapheme,\r\n graphemeLines = [],\r\n infix = splitByGrapheme ? '' : ' ';\r\n\r\n let lineWidth = 0,\r\n line: string[] = [],\r\n // spaces in different languages?\r\n offset = 0,\r\n infixWidth = 0,\r\n lineJustStarted = true;\r\n\r\n desiredWidth -= reservedSpace;\r\n\r\n const maxWidth = Math.max(\r\n desiredWidth,\r\n largestWordWidth,\r\n this.dynamicMinWidth,\r\n );\r\n // layout words\r\n const data = wordsData[lineIndex];\r\n offset = 0;\r\n let i;\r\n for (i = 0; i < data.length; i++) {\r\n const { word, width: wordWidth } = data[i];\r\n offset += word.length;\r\n\r\n lineWidth += infixWidth + wordWidth - additionalSpace;\r\n if (lineWidth > maxWidth && !lineJustStarted) {\r\n graphemeLines.push(line);\r\n line = [];\r\n lineWidth = wordWidth;\r\n lineJustStarted = true;\r\n } else {\r\n lineWidth += additionalSpace;\r\n }\r\n\r\n if (!lineJustStarted && !splitByGrapheme) {\r\n line.push(infix);\r\n }\r\n line = line.concat(word);\r\n\r\n infixWidth = splitByGrapheme\r\n ? 0\r\n : this._measureWord([infix], lineIndex, offset);\r\n offset++;\r\n lineJustStarted = false;\r\n }\r\n\r\n i && graphemeLines.push(line);\r\n\r\n // TODO: this code is probably not necessary anymore.\r\n // it can be moved out of this function since largestWordWidth is now\r\n // known in advance\r\n if (largestWordWidth + reservedSpace > this.dynamicMinWidth) {\r\n this.dynamicMinWidth = largestWordWidth - additionalSpace + reservedSpace;\r\n }\r\n return graphemeLines;\r\n }\r\n\r\n /**\r\n * Detect if the text line is ended with an hard break\r\n * text and itext do not have wrapping, return false\r\n * @param {Number} lineIndex text to split\r\n * @return {Boolean}\r\n */\r\n isEndOfWrapping(lineIndex: number): boolean {\r\n if (!this._styleMap[lineIndex + 1]) {\r\n // is last line, return true;\r\n return true;\r\n }\r\n if (this._styleMap[lineIndex + 1].line !== this._styleMap[lineIndex].line) {\r\n // this is last line before a line break, return true;\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Detect if a line has a linebreak and so we need to account for it when moving\r\n * and counting style.\r\n * This is important only for splitByGrapheme at the end of wrapping.\r\n * If we are not wrapping the offset is always 1\r\n * @return Number\r\n */\r\n missingNewlineOffset(lineIndex: number, skipWrapping?: boolean): 0 | 1 {\r\n if (this.splitByGrapheme && !skipWrapping) {\r\n return this.isEndOfWrapping(lineIndex) ? 1 : 0;\r\n }\r\n return 1;\r\n }\r\n\r\n /**\r\n * Gets lines of text to render in the Textbox. This function calculates\r\n * text wrapping on the fly every time it is called.\r\n * @param {String} text text to split\r\n * @returns {Array} Array of lines in the Textbox.\r\n * @override\r\n */\r\n _splitTextIntoLines(text: string) {\r\n const newText = super._splitTextIntoLines(text),\r\n graphemeLines = this._wrapText(newText.lines, this.width),\r\n lines = new Array(graphemeLines.length);\r\n for (let i = 0; i < graphemeLines.length; i++) {\r\n lines[i] = graphemeLines[i].join('');\r\n }\r\n newText.lines = lines;\r\n newText.graphemeLines = graphemeLines;\r\n return newText;\r\n }\r\n\r\n getMinWidth() {\r\n return Math.max(this.minWidth, this.dynamicMinWidth);\r\n }\r\n\r\n _removeExtraneousStyles() {\r\n const linesToKeep = new Map();\r\n for (const prop in this._styleMap) {\r\n const propNumber = parseInt(prop, 10);\r\n if (this._textLines[propNumber]) {\r\n const lineIndex = this._styleMap[prop].line;\r\n linesToKeep.set(`${lineIndex}`, true);\r\n }\r\n }\r\n for (const prop in this.styles) {\r\n if (!linesToKeep.has(prop)) {\r\n delete this.styles[prop];\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Returns object representation of an instance\r\n * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\r\n * @return {Object} object representation of an instance\r\n */\r\n toObject<\r\n T extends Omit<Props & TClassProperties<this>, keyof SProps>,\r\n K extends keyof T = never,\r\n >(propertiesToInclude: K[] = []): Pick<T, K> & SProps {\r\n return super.toObject<T, K>([\r\n 'minWidth',\r\n 'splitByGrapheme',\r\n ...propertiesToInclude,\r\n ] as K[]);\r\n }\r\n}\r\n\r\nclassRegistry.setClass(Textbox);\r\n"],"names":["textboxDefaultValues","minWidth","dynamicMinWidth","lockScalingFlip","noScaleCache","_wordJoiners","splitByGrapheme","Textbox","IText","getDefaults","ownDefaults","constructor","text","options","createControls","controls","createTextboxDefaultControls","initDimensions","initialized","enableAdvancedLayout","initDimensionsAdvanced","isEditing","initDelayedCursor","_clearCache","_styleMap","_generateStyleMap","_splitText","width","_set","textAlign","includes","JUSTIFY","enlargeSpaces","height","calcTextHeight","layout","layoutText","wrap","align","_mapTextAlignToAlign","ellipsis","fontSize","lineHeight","letterSpacing","charSpacing","direction","fontFamily","fontStyle","fontWeight","verticalAlign","lines","length","maxLineWidth","Math","max","map","line","newLayout","_getAdvancedLayoutOptions","totalHeight","_convertLayoutToLegacyFormat","_generateStyleMapFromLayout","dirty","realLineCount","charCount","forEach","i","offset","graphemes","textInfo","realLineCharCount","graphemeLines","graphemeText","_reSpaceAndTab","test","styleHas","property","lineIndex","isWrapping","isEmptyStyles","styles","nextLineIndex","nextOffset","shouldLimit","mapNextLine","obj","p1","p2","p2Number","parseInt","p3","_getStyleDeclaration","charIndex","_setStyleDeclaration","style","_deleteStyleDeclaration","_getLineStyle","_setLineStyle","_wrapText","desiredWidth","data","getGraphemeDataForRender","wrapped","wordsData","push","_wrapLine","infix","largestWordWidth","wordsOrGraphemes","graphemeSplit","wordSplit","word","graphemeArray","_measureWord","charOffset","arguments","undefined","prevGrapheme","skipLeft","len","box","_getGraphemeBox","kernedWidth","value","split","_ref","reservedSpace","additionalSpace","_getWidthOfCharSpacing","lineWidth","infixWidth","lineJustStarted","maxWidth","wordWidth","concat","isEndOfWrapping","missingNewlineOffset","skipWrapping","_splitTextIntoLines","newText","Array","join","getMinWidth","_removeExtraneousStyles","linesToKeep","Map","prop","propNumber","_textLines","set","has","toObject","propertiesToInclude","_defineProperty","textLayoutProperties","classRegistry","setClass"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Textbox.mjs","sources":["../../../src/shapes/Textbox.ts"],"sourcesContent":["import type { TClassProperties, TOptions } from '../typedefs';\r\nimport { IText } from './IText/IText';\r\nimport { classRegistry } from '../ClassRegistry';\r\nimport { createTextboxDefaultControls } from '../controls/commonControls';\r\nimport { JUSTIFY } from './Text/constants';\r\nimport type { TextStyleDeclaration } from './Text/StyledText';\r\nimport type { SerializedITextProps, ITextProps } from './IText/IText';\r\nimport type { ITextEvents } from './IText/ITextBehavior';\r\nimport type { TextLinesInfo } from './Text/Text';\r\nimport type { Control } from '../controls/Control';\r\nimport { layoutText } from '../text/layout';\r\n\r\n// @TODO: Many things here are configuration related and shouldn't be on the class nor prototype\r\n// regexes, list of properties that are not suppose to change by instances, magic consts.\r\n// this will be a separated effort\r\nexport const textboxDefaultValues: Partial<TClassProperties<Textbox>> = {\r\n minWidth: 20,\r\n dynamicMinWidth: 2,\r\n lockScalingFlip: true,\r\n noScaleCache: false,\r\n _wordJoiners: /[ \\t\\r]/,\r\n splitByGrapheme: false,\r\n};\r\n\r\nexport type GraphemeData = {\r\n wordsData: {\r\n word: string[];\r\n width: number;\r\n }[][];\r\n largestWordWidth: number;\r\n};\r\n\r\nexport type StyleMap = Record<string, { line: number; offset: number }>;\r\n\r\n// @TODO this is not complete\r\ninterface UniqueTextboxProps {\r\n minWidth: number;\r\n splitByGrapheme: boolean;\r\n dynamicMinWidth: number;\r\n _wordJoiners: RegExp;\r\n}\r\n\r\nexport interface SerializedTextboxProps\r\n extends SerializedITextProps,\r\n Pick<UniqueTextboxProps, 'minWidth' | 'splitByGrapheme'> {}\r\n\r\nexport interface TextboxProps extends ITextProps, UniqueTextboxProps {}\r\n\r\n/**\r\n * Textbox class, based on IText, allows the user to resize the text rectangle\r\n * and wraps lines automatically. Textboxes have their Y scaling locked, the\r\n * user can only change width. Height is adjusted automatically based on the\r\n * wrapping of lines.\r\n */\r\nexport class Textbox<\r\n Props extends TOptions<TextboxProps> = Partial<TextboxProps>,\r\n SProps extends SerializedTextboxProps = SerializedTextboxProps,\r\n EventSpec extends ITextEvents = ITextEvents,\r\n >\r\n extends IText<Props, SProps, EventSpec>\r\n implements UniqueTextboxProps\r\n{\r\n /**\r\n * Minimum width of textbox, in pixels.\r\n * @type Number\r\n */\r\n declare minWidth: number;\r\n\r\n /**\r\n * Minimum calculated width of a textbox, in pixels.\r\n * fixed to 2 so that an empty textbox cannot go to 0\r\n * and is still selectable without text.\r\n * @type Number\r\n */\r\n declare dynamicMinWidth: number;\r\n\r\n /**\r\n * Use this boolean property in order to split strings that have no white space concept.\r\n * this is a cheap way to help with chinese/japanese\r\n * @type Boolean\r\n * @since 2.6.0\r\n */\r\n declare splitByGrapheme: boolean;\r\n\r\n declare _wordJoiners: RegExp;\r\n\r\n declare _styleMap: StyleMap;\r\n\r\n declare isWrapping: boolean;\r\n\r\n static type = 'Textbox';\r\n\r\n static textLayoutProperties = [...IText.textLayoutProperties, 'width'];\r\n\r\n static ownDefaults = textboxDefaultValues;\r\n\r\n static getDefaults(): Record<string, any> {\r\n return {\r\n ...super.getDefaults(),\r\n ...Textbox.ownDefaults,\r\n };\r\n }\r\n\r\n /**\r\n * Constructor\r\n * @param {String} text Text string\r\n * @param {Object} [options] Options object\r\n */\r\n constructor(text: string, options?: Props) {\r\n super(text, { ...Textbox.ownDefaults, ...options } as Props);\r\n this.initializeEventListeners();\r\n }\r\n\r\n /**\r\n * Creates the default control object.\r\n * If you prefer to have on instance of controls shared among all objects\r\n * make this function return an empty object and add controls to the ownDefaults object\r\n */\r\n static createControls(): { controls: Record<string, Control> } {\r\n return { controls: createTextboxDefaultControls() };\r\n }\r\n\r\n /**\r\n * Unlike superclass's version of this function, Textbox does not update\r\n * its width.\r\n * @private\r\n * @override\r\n */\r\n initDimensions() {\r\n if (!this.initialized) {\r\n return;\r\n }\r\n \r\n // Use advanced layout if enabled\r\n if (this.enableAdvancedLayout) {\r\n return this.initDimensionsAdvanced();\r\n }\r\n \r\n this.isEditing && this.initDelayedCursor();\r\n this._clearCache();\r\n // clear dynamicMinWidth as it will be different after we re-wrap line\r\n this.dynamicMinWidth = 0;\r\n // wrap lines\r\n this._styleMap = this._generateStyleMap(this._splitText());\r\n // if after wrapping, the width is smaller than dynamicMinWidth, change the width and re-wrap\r\n if (this.dynamicMinWidth > this.width) {\r\n this._set('width', this.dynamicMinWidth);\r\n }\r\n if (this.textAlign.includes(JUSTIFY)) {\r\n // once text is measured we need to make space fatter to make justified text.\r\n this.enlargeSpaces();\r\n }\r\n // clear cache and re-calculate height\r\n this.height = this.calcTextHeight();\r\n }\r\n\r\n /**\r\n * Advanced dimensions calculation using new layout engine\r\n * @private\r\n */\r\n initDimensionsAdvanced() {\r\n if (!this.initialized) {\r\n return;\r\n }\r\n \r\n this.isEditing && this.initDelayedCursor();\r\n this._clearCache();\r\n this.dynamicMinWidth = 0;\r\n \r\n // Use new layout engine\r\n const layout = layoutText({\r\n text: this.text,\r\n width: this.width,\r\n height: this.height,\r\n wrap: this.wrap || 'word',\r\n align: (this as any)._mapTextAlignToAlign(this.textAlign),\r\n ellipsis: this.ellipsis || false,\r\n fontSize: this.fontSize,\r\n lineHeight: this.lineHeight,\r\n letterSpacing: this.letterSpacing || 0,\r\n charSpacing: this.charSpacing,\r\n direction: this.direction === 'inherit' ? 'ltr' : this.direction,\r\n fontFamily: this.fontFamily,\r\n fontStyle: this.fontStyle,\r\n fontWeight: this.fontWeight,\r\n verticalAlign: this.verticalAlign || 'top',\r\n });\r\n \r\n // Update dynamic minimum width based on layout\r\n if (layout.lines.length > 0) {\r\n const maxLineWidth = Math.max(...layout.lines.map(line => line.width));\r\n this.dynamicMinWidth = Math.max(this.minWidth, maxLineWidth);\r\n }\r\n \r\n // Adjust width if needed (preserving Textbox behavior)\r\n if (this.dynamicMinWidth > this.width) {\r\n this._set('width', this.dynamicMinWidth);\r\n // Re-layout with new width\r\n const newLayout = layoutText({\r\n ...(this as any)._getAdvancedLayoutOptions(),\r\n width: this.width,\r\n });\r\n this.height = newLayout.totalHeight;\r\n (this as any)._convertLayoutToLegacyFormat(newLayout);\r\n } else {\r\n this.height = layout.totalHeight;\r\n (this as any)._convertLayoutToLegacyFormat(layout);\r\n }\r\n \r\n // Generate style map for compatibility\r\n this._styleMap = this._generateStyleMapFromLayout(layout);\r\n this.dirty = true;\r\n }\r\n\r\n /**\r\n * Generate style map from new layout format\r\n * @private\r\n */\r\n _generateStyleMapFromLayout(layout: any): StyleMap {\r\n const map: StyleMap = {};\r\n let realLineCount = 0;\r\n let charCount = 0;\r\n\r\n layout.lines.forEach((line: any, i: number) => {\r\n if (line.text.includes('\\n') && i > 0) {\r\n realLineCount++;\r\n }\r\n \r\n map[i] = { line: realLineCount, offset: 0 };\r\n charCount += line.graphemes.length;\r\n \r\n if (i < layout.lines.length - 1) {\r\n charCount += 1; // newline character\r\n }\r\n });\r\n\r\n return map;\r\n }\r\n\r\n /**\r\n * Generate an object that translates the style object so that it is\r\n * broken up by visual lines (new lines and automatic wrapping).\r\n * The original text styles object is broken up by actual lines (new lines only),\r\n * which is only sufficient for Text / IText\r\n * @private\r\n */\r\n _generateStyleMap(textInfo: TextLinesInfo): StyleMap {\r\n let realLineCount = 0,\r\n realLineCharCount = 0,\r\n charCount = 0;\r\n const map: StyleMap = {};\r\n\r\n for (let i = 0; i < textInfo.graphemeLines.length; i++) {\r\n if (textInfo.graphemeText[charCount] === '\\n' && i > 0) {\r\n realLineCharCount = 0;\r\n charCount++;\r\n realLineCount++;\r\n } else if (\r\n !this.splitByGrapheme &&\r\n this._reSpaceAndTab.test(textInfo.graphemeText[charCount]) &&\r\n i > 0\r\n ) {\r\n // this case deals with space's that are removed from end of lines when wrapping\r\n realLineCharCount++;\r\n charCount++;\r\n }\r\n\r\n map[i] = { line: realLineCount, offset: realLineCharCount };\r\n\r\n charCount += textInfo.graphemeLines[i].length;\r\n realLineCharCount += textInfo.graphemeLines[i].length;\r\n }\r\n\r\n return map;\r\n }\r\n\r\n /**\r\n * Returns true if object has a style property or has it on a specified line\r\n * @param {Number} lineIndex\r\n * @return {Boolean}\r\n */\r\n styleHas(property: keyof TextStyleDeclaration, lineIndex: number): boolean {\r\n if (this._styleMap && !this.isWrapping) {\r\n const map = this._styleMap[lineIndex];\r\n if (map) {\r\n lineIndex = map.line;\r\n }\r\n }\r\n return super.styleHas(property, lineIndex);\r\n }\r\n\r\n /**\r\n * Returns true if object has no styling or no styling in a line\r\n * @param {Number} lineIndex , lineIndex is on wrapped lines.\r\n * @return {Boolean}\r\n */\r\n isEmptyStyles(lineIndex: number): boolean {\r\n if (!this.styles) {\r\n return true;\r\n }\r\n let offset = 0,\r\n nextLineIndex = lineIndex + 1,\r\n nextOffset: number,\r\n shouldLimit = false;\r\n const map = this._styleMap[lineIndex],\r\n mapNextLine = this._styleMap[lineIndex + 1];\r\n if (map) {\r\n lineIndex = map.line;\r\n offset = map.offset;\r\n }\r\n if (mapNextLine) {\r\n nextLineIndex = mapNextLine.line;\r\n shouldLimit = nextLineIndex === lineIndex;\r\n nextOffset = mapNextLine.offset;\r\n }\r\n const obj =\r\n typeof lineIndex === 'undefined'\r\n ? this.styles\r\n : { line: this.styles[lineIndex] };\r\n for (const p1 in obj) {\r\n for (const p2 in obj[p1]) {\r\n const p2Number = parseInt(p2, 10);\r\n if (p2Number >= offset && (!shouldLimit || p2Number < nextOffset!)) {\r\n for (const p3 in obj[p1][p2]) {\r\n return false;\r\n }\r\n }\r\n }\r\n }\r\n return true;\r\n }\r\n\r\n /**\r\n * @protected\r\n * @param {Number} lineIndex\r\n * @param {Number} charIndex\r\n * @return {TextStyleDeclaration} a style object reference to the existing one or a new empty object when undefined\r\n */\r\n _getStyleDeclaration(\r\n lineIndex: number,\r\n charIndex: number,\r\n ): TextStyleDeclaration {\r\n if (this._styleMap && !this.isWrapping) {\r\n const map = this._styleMap[lineIndex];\r\n if (!map) {\r\n return {};\r\n }\r\n lineIndex = map.line;\r\n charIndex = map.offset + charIndex;\r\n }\r\n return super._getStyleDeclaration(lineIndex, charIndex);\r\n }\r\n\r\n /**\r\n * @param {Number} lineIndex\r\n * @param {Number} charIndex\r\n * @param {Object} style\r\n * @private\r\n */\r\n protected _setStyleDeclaration(\r\n lineIndex: number,\r\n charIndex: number,\r\n style: object,\r\n ) {\r\n const map = this._styleMap[lineIndex];\r\n super._setStyleDeclaration(map.line, map.offset + charIndex, style);\r\n }\r\n\r\n /**\r\n * @param {Number} lineIndex\r\n * @param {Number} charIndex\r\n * @private\r\n */\r\n protected _deleteStyleDeclaration(lineIndex: number, charIndex: number) {\r\n const map = this._styleMap[lineIndex];\r\n super._deleteStyleDeclaration(map.line, map.offset + charIndex);\r\n }\r\n\r\n /**\r\n * probably broken need a fix\r\n * Returns the real style line that correspond to the wrapped lineIndex line\r\n * Used just to verify if the line does exist or not.\r\n * @param {Number} lineIndex\r\n * @returns {Boolean} if the line exists or not\r\n * @private\r\n */\r\n protected _getLineStyle(lineIndex: number): boolean {\r\n const map = this._styleMap[lineIndex];\r\n return !!this.styles[map.line];\r\n }\r\n\r\n /**\r\n * Set the line style to an empty object so that is initialized\r\n * @param {Number} lineIndex\r\n * @param {Object} style\r\n * @private\r\n */\r\n protected _setLineStyle(lineIndex: number) {\r\n const map = this._styleMap[lineIndex];\r\n super._setLineStyle(map.line);\r\n }\r\n\r\n /**\r\n * Wraps text using the 'width' property of Textbox. First this function\r\n * splits text on newlines, so we preserve newlines entered by the user.\r\n * Then it wraps each line using the width of the Textbox by calling\r\n * _wrapLine().\r\n * @param {Array} lines The string array of text that is split into lines\r\n * @param {Number} desiredWidth width you want to wrap to\r\n * @returns {Array} Array of lines\r\n */\r\n _wrapText(lines: string[], desiredWidth: number): string[][] {\r\n this.isWrapping = true;\r\n // extract all thewords and the widths to optimally wrap lines.\r\n const data = this.getGraphemeDataForRender(lines);\r\n const wrapped: string[][] = [];\r\n for (let i = 0; i < data.wordsData.length; i++) {\r\n wrapped.push(...this._wrapLine(i, desiredWidth, data));\r\n }\r\n this.isWrapping = false;\r\n return wrapped;\r\n }\r\n\r\n /**\r\n * For each line of text terminated by an hard line stop,\r\n * measure each word width and extract the largest word from all.\r\n * The returned words here are the one that at the end will be rendered.\r\n * @param {string[]} lines the lines we need to measure\r\n *\r\n */\r\n getGraphemeDataForRender(lines: string[]): GraphemeData {\r\n const splitByGrapheme = this.splitByGrapheme,\r\n infix = splitByGrapheme ? '' : ' ';\r\n\r\n let largestWordWidth = 0;\r\n\r\n const data = lines.map((line, lineIndex) => {\r\n let offset = 0;\r\n const wordsOrGraphemes = splitByGrapheme\r\n ? this.graphemeSplit(line)\r\n : this.wordSplit(line);\r\n\r\n if (wordsOrGraphemes.length === 0) {\r\n return [{ word: [], width: 0 }];\r\n }\r\n\r\n return wordsOrGraphemes.map((word: string) => {\r\n // if using splitByGrapheme words are already in graphemes.\r\n const graphemeArray = splitByGrapheme\r\n ? [word]\r\n : this.graphemeSplit(word);\r\n const width = this._measureWord(graphemeArray, lineIndex, offset);\r\n largestWordWidth = Math.max(width, largestWordWidth);\r\n offset += graphemeArray.length + infix.length;\r\n return { word: graphemeArray, width };\r\n });\r\n });\r\n\r\n return {\r\n wordsData: data,\r\n largestWordWidth,\r\n };\r\n }\r\n\r\n /**\r\n * Helper function to measure a string of text, given its lineIndex and charIndex offset\r\n * It gets called when charBounds are not available yet.\r\n * Override if necessary\r\n * Use with {@link Textbox#wordSplit}\r\n *\r\n * @param {CanvasRenderingContext2D} ctx\r\n * @param {String} text\r\n * @param {number} lineIndex\r\n * @param {number} charOffset\r\n * @returns {number}\r\n */\r\n _measureWord(word: string[], lineIndex: number, charOffset = 0): number {\r\n let width = 0,\r\n prevGrapheme;\r\n const skipLeft = true;\r\n for (let i = 0, len = word.length; i < len; i++) {\r\n const box = this._getGraphemeBox(\r\n word[i],\r\n lineIndex,\r\n i + charOffset,\r\n prevGrapheme,\r\n skipLeft,\r\n );\r\n width += box.kernedWidth;\r\n prevGrapheme = word[i];\r\n }\r\n return width;\r\n }\r\n\r\n /**\r\n * Override this method to customize word splitting\r\n * Use with {@link Textbox#_measureWord}\r\n * @param {string} value\r\n * @returns {string[]} array of words\r\n */\r\n wordSplit(value: string): string[] {\r\n return value.split(this._wordJoiners);\r\n }\r\n\r\n /**\r\n * Wraps a line of text using the width of the Textbox as desiredWidth\r\n * and leveraging the known width o words from GraphemeData\r\n * @private\r\n * @param {Number} lineIndex\r\n * @param {Number} desiredWidth width you want to wrap the line to\r\n * @param {GraphemeData} graphemeData an object containing all the lines' words width.\r\n * @param {Number} reservedSpace space to remove from wrapping for custom functionalities\r\n * @returns {Array} Array of line(s) into which the given text is wrapped\r\n * to.\r\n */\r\n _wrapLine(\r\n lineIndex: number,\r\n desiredWidth: number,\r\n { largestWordWidth, wordsData }: GraphemeData,\r\n reservedSpace = 0,\r\n ): string[][] {\r\n const additionalSpace = this._getWidthOfCharSpacing(),\r\n splitByGrapheme = this.splitByGrapheme,\r\n graphemeLines = [],\r\n infix = splitByGrapheme ? '' : ' ';\r\n\r\n let lineWidth = 0,\r\n line: string[] = [],\r\n // spaces in different languages?\r\n offset = 0,\r\n infixWidth = 0,\r\n lineJustStarted = true;\r\n\r\n desiredWidth -= reservedSpace;\r\n\r\n const maxWidth = Math.max(\r\n desiredWidth,\r\n largestWordWidth,\r\n this.dynamicMinWidth,\r\n );\r\n // layout words\r\n const data = wordsData[lineIndex];\r\n offset = 0;\r\n let i;\r\n for (i = 0; i < data.length; i++) {\r\n const { word, width: wordWidth } = data[i];\r\n offset += word.length;\r\n\r\n lineWidth += infixWidth + wordWidth - additionalSpace;\r\n if (lineWidth > maxWidth && !lineJustStarted) {\r\n graphemeLines.push(line);\r\n line = [];\r\n lineWidth = wordWidth;\r\n lineJustStarted = true;\r\n } else {\r\n lineWidth += additionalSpace;\r\n }\r\n\r\n if (!lineJustStarted && !splitByGrapheme) {\r\n line.push(infix);\r\n }\r\n line = line.concat(word);\r\n\r\n infixWidth = splitByGrapheme\r\n ? 0\r\n : this._measureWord([infix], lineIndex, offset);\r\n offset++;\r\n lineJustStarted = false;\r\n }\r\n\r\n i && graphemeLines.push(line);\r\n\r\n // TODO: this code is probably not necessary anymore.\r\n // it can be moved out of this function since largestWordWidth is now\r\n // known in advance\r\n if (largestWordWidth + reservedSpace > this.dynamicMinWidth) {\r\n this.dynamicMinWidth = largestWordWidth - additionalSpace + reservedSpace;\r\n }\r\n return graphemeLines;\r\n }\r\n\r\n /**\r\n * Detect if the text line is ended with an hard break\r\n * text and itext do not have wrapping, return false\r\n * @param {Number} lineIndex text to split\r\n * @return {Boolean}\r\n */\r\n isEndOfWrapping(lineIndex: number): boolean {\r\n if (!this._styleMap[lineIndex + 1]) {\r\n // is last line, return true;\r\n return true;\r\n }\r\n if (this._styleMap[lineIndex + 1].line !== this._styleMap[lineIndex].line) {\r\n // this is last line before a line break, return true;\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Detect if a line has a linebreak and so we need to account for it when moving\r\n * and counting style.\r\n * This is important only for splitByGrapheme at the end of wrapping.\r\n * If we are not wrapping the offset is always 1\r\n * @return Number\r\n */\r\n missingNewlineOffset(lineIndex: number, skipWrapping?: boolean): 0 | 1 {\r\n if (this.splitByGrapheme && !skipWrapping) {\r\n return this.isEndOfWrapping(lineIndex) ? 1 : 0;\r\n }\r\n return 1;\r\n }\r\n\r\n /**\r\n * Gets lines of text to render in the Textbox. This function calculates\r\n * text wrapping on the fly every time it is called.\r\n * @param {String} text text to split\r\n * @returns {Array} Array of lines in the Textbox.\r\n * @override\r\n */\r\n _splitTextIntoLines(text: string) {\r\n const newText = super._splitTextIntoLines(text),\r\n graphemeLines = this._wrapText(newText.lines, this.width),\r\n lines = new Array(graphemeLines.length);\r\n for (let i = 0; i < graphemeLines.length; i++) {\r\n lines[i] = graphemeLines[i].join('');\r\n }\r\n newText.lines = lines;\r\n newText.graphemeLines = graphemeLines;\r\n return newText;\r\n }\r\n\r\n getMinWidth() {\r\n return Math.max(this.minWidth, this.dynamicMinWidth);\r\n }\r\n\r\n _removeExtraneousStyles() {\r\n const linesToKeep = new Map();\r\n for (const prop in this._styleMap) {\r\n const propNumber = parseInt(prop, 10);\r\n if (this._textLines[propNumber]) {\r\n const lineIndex = this._styleMap[prop].line;\r\n linesToKeep.set(`${lineIndex}`, true);\r\n }\r\n }\r\n for (const prop in this.styles) {\r\n if (!linesToKeep.has(prop)) {\r\n delete this.styles[prop];\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Initialize event listeners for safety snap functionality\r\n * @private\r\n */\r\n private initializeEventListeners(): void {\r\n // Track which side is being used for resize to handle position compensation\r\n let resizeOrigin: 'left' | 'right' | null = null;\r\n \r\n // Detect resize origin during resizing\r\n this.on('resizing', (e: any) => {\r\n // Check transform origin to determine which side is being resized\r\n console.log('🔍 Resize event data:', e);\r\n if (e.transform) {\r\n const { originX, originY } = e.transform;\r\n console.log('🔍 Transform origins:', { originX, originY });\r\n // originX tells us which side is the anchor - opposite side is being dragged\r\n resizeOrigin = originX === 'right' ? 'left' : originX === 'left' ? 'right' : null;\r\n console.log('🎯 Setting resizeOrigin to:', resizeOrigin);\r\n } else if (e.originX) {\r\n const { originX, originY } = e;\r\n console.log('🔍 Event origins:', { originX, originY });\r\n resizeOrigin = originX === 'right' ? 'left' : originX === 'left' ? 'right' : null;\r\n console.log('🎯 Setting resizeOrigin to:', resizeOrigin);\r\n }\r\n });\r\n \r\n // Only trigger safety snap after resize is complete (not during)\r\n // Use 'modified' event which fires after user releases the mouse\r\n this.on('modified', () => {\r\n const currentResizeOrigin = resizeOrigin; // Capture the value before reset\r\n console.log('✅ Modified event fired - resize complete, triggering safety snap', { resizeOrigin: currentResizeOrigin });\r\n // Small delay to ensure text layout is updated\r\n setTimeout(() => this.safetySnapWidth(currentResizeOrigin), 10);\r\n resizeOrigin = null; // Reset after capturing\r\n });\r\n \r\n // Also listen to canvas-level modified event as backup\r\n this.canvas?.on('object:modified', (e) => {\r\n if (e.target === this) {\r\n const currentResizeOrigin = resizeOrigin; // Capture the value before reset\r\n console.log('✅ Canvas object:modified fired for this textbox');\r\n setTimeout(() => this.safetySnapWidth(currentResizeOrigin), 10);\r\n resizeOrigin = null; // Reset after capturing\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Safety snap to prevent glyph clipping after manual resize.\r\n * Similar to Polotno - checks if any glyphs are too close to edges\r\n * and automatically expands width if needed.\r\n * @private\r\n * @param resizeOrigin - Which side was used for resizing ('left' or 'right')\r\n */\r\n private safetySnapWidth(resizeOrigin?: 'left' | 'right' | null): void {\r\n console.log('🔍 safetySnapWidth called', { \r\n isWrapping: this.isWrapping, \r\n hasTextLines: !!this._textLines,\r\n lineCount: this._textLines?.length || 0,\r\n currentWidth: this.width,\r\n type: this.type,\r\n text: this.text\r\n });\r\n \r\n // For Textbox objects, we always want to check for clipping regardless of isWrapping flag\r\n if (!this._textLines || this.type.toLowerCase() !== 'textbox' || this._textLines.length === 0) {\r\n console.log('❌ Early return - missing requirements', {\r\n hasTextLines: !!this._textLines,\r\n typeMatch: this.type.toLowerCase() === 'textbox',\r\n actualType: this.type,\r\n hasLines: this._textLines?.length > 0\r\n });\r\n return;\r\n }\r\n \r\n const lineCount = this._textLines.length;\r\n if (lineCount === 0) return;\r\n\r\n // Check all lines, not just the last one\r\n let maxActualLineWidth = 0; // Actual measured width without buffers\r\n let maxRequiredWidth = 0; // Width including RTL buffer\r\n \r\n for (let i = 0; i < lineCount; i++) {\r\n const lineText = this._textLines[i].join(''); // Convert grapheme array to string\r\n const lineWidth = this.getLineWidth(i);\r\n maxActualLineWidth = Math.max(maxActualLineWidth, lineWidth);\r\n \r\n // RTL detection - regex for Arabic, Hebrew, and other RTL characters\r\n const rtlRegex = /[\\u0590-\\u05FF\\u0600-\\u06FF\\u0750-\\u077F\\uFB50-\\uFDFF\\uFE70-\\uFEFF]/;\r\n if (rtlRegex.test(lineText)) {\r\n // Add minimal RTL compensation buffer - just enough to prevent clipping\r\n const rtlBuffer = (this.fontSize || 16) * 0.15; // 15% of font size (much smaller)\r\n maxRequiredWidth = Math.max(maxRequiredWidth, lineWidth + rtlBuffer);\r\n } else {\r\n maxRequiredWidth = Math.max(maxRequiredWidth, lineWidth);\r\n }\r\n }\r\n\r\n // Safety margin - how close glyphs can get before we snap\r\n const safetyThreshold = 2; // px - very subtle trigger\r\n \r\n if (maxRequiredWidth > this.width - safetyThreshold) {\r\n // Set width to exactly what's needed + minimal safety margin\r\n const newWidth = maxRequiredWidth + 1; // Add just 1px safety margin\r\n console.log(`Safety snap: ${this.width.toFixed(0)}px -> ${newWidth.toFixed(0)}px`, {\r\n maxActualLineWidth: maxActualLineWidth.toFixed(1),\r\n maxRequiredWidth: maxRequiredWidth.toFixed(1),\r\n difference: (newWidth - this.width).toFixed(1)\r\n });\r\n \r\n // Store original position before width change\r\n const originalLeft = this.left;\r\n const originalTop = this.top;\r\n const widthIncrease = newWidth - this.width;\r\n \r\n // Change width \r\n this.set('width', newWidth);\r\n \r\n // Force text layout recalculation\r\n this.initDimensions();\r\n \r\n // Only compensate position when resizing from left handle\r\n // Right handle resize doesn't shift the text position\r\n if (resizeOrigin === 'left') {\r\n console.log('🔧 Compensating for left-side resize', {\r\n originalLeft,\r\n widthIncrease,\r\n newLeft: originalLeft - widthIncrease\r\n });\r\n // When resizing from left, the expansion pushes text right\r\n // Compensate by moving the textbox left by the width increase\r\n this.set({\r\n 'left': originalLeft - widthIncrease,\r\n 'top': originalTop\r\n });\r\n } else {\r\n console.log('✅ Right-side resize, no compensation needed');\r\n }\r\n \r\n this.setCoords();\r\n \r\n // Also refresh the overlay editor if it exists\r\n if ((this as any).__overlayEditor) {\r\n setTimeout(() => {\r\n (this as any).__overlayEditor.refresh();\r\n }, 0);\r\n }\r\n \r\n this.canvas?.requestRenderAll();\r\n }\r\n }\r\n\r\n /**\r\n * Returns object representation of an instance\r\n * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\r\n * @return {Object} object representation of an instance\r\n */\r\n toObject<\r\n T extends Omit<Props & TClassProperties<this>, keyof SProps>,\r\n K extends keyof T = never,\r\n >(propertiesToInclude: K[] = []): Pick<T, K> & SProps {\r\n return super.toObject<T, K>([\r\n 'minWidth',\r\n 'splitByGrapheme',\r\n ...propertiesToInclude,\r\n ] as K[]);\r\n }\r\n}\r\n\r\nclassRegistry.setClass(Textbox);\r\n"],"names":["textboxDefaultValues","minWidth","dynamicMinWidth","lockScalingFlip","noScaleCache","_wordJoiners","splitByGrapheme","Textbox","IText","getDefaults","ownDefaults","constructor","text","options","initializeEventListeners","createControls","controls","createTextboxDefaultControls","initDimensions","initialized","enableAdvancedLayout","initDimensionsAdvanced","isEditing","initDelayedCursor","_clearCache","_styleMap","_generateStyleMap","_splitText","width","_set","textAlign","includes","JUSTIFY","enlargeSpaces","height","calcTextHeight","layout","layoutText","wrap","align","_mapTextAlignToAlign","ellipsis","fontSize","lineHeight","letterSpacing","charSpacing","direction","fontFamily","fontStyle","fontWeight","verticalAlign","lines","length","maxLineWidth","Math","max","map","line","newLayout","_getAdvancedLayoutOptions","totalHeight","_convertLayoutToLegacyFormat","_generateStyleMapFromLayout","dirty","realLineCount","charCount","forEach","i","offset","graphemes","textInfo","realLineCharCount","graphemeLines","graphemeText","_reSpaceAndTab","test","styleHas","property","lineIndex","isWrapping","isEmptyStyles","styles","nextLineIndex","nextOffset","shouldLimit","mapNextLine","obj","p1","p2","p2Number","parseInt","p3","_getStyleDeclaration","charIndex","_setStyleDeclaration","style","_deleteStyleDeclaration","_getLineStyle","_setLineStyle","_wrapText","desiredWidth","data","getGraphemeDataForRender","wrapped","wordsData","push","_wrapLine","infix","largestWordWidth","wordsOrGraphemes","graphemeSplit","wordSplit","word","graphemeArray","_measureWord","charOffset","arguments","undefined","prevGrapheme","skipLeft","len","box","_getGraphemeBox","kernedWidth","value","split","_ref","reservedSpace","additionalSpace","_getWidthOfCharSpacing","lineWidth","infixWidth","lineJustStarted","maxWidth","wordWidth","concat","isEndOfWrapping","missingNewlineOffset","skipWrapping","_splitTextIntoLines","newText","Array","join","getMinWidth","_removeExtraneousStyles","linesToKeep","Map","prop","propNumber","_textLines","set","has","_this$canvas","resizeOrigin","on","e","console","log","transform","originX","originY","currentResizeOrigin","setTimeout","safetySnapWidth","canvas","target","_this$_textLines","hasTextLines","lineCount","currentWidth","type","toLowerCase","_this$_textLines2","typeMatch","actualType","hasLines","maxActualLineWidth","maxRequiredWidth","lineText","getLineWidth","rtlRegex","rtlBuffer","safetyThreshold","_this$canvas2","newWidth","toFixed","difference","originalLeft","left","originalTop","top","widthIncrease","newLeft","setCoords","__overlayEditor","refresh","requestRenderAll","toObject","propertiesToInclude","_defineProperty","textLayoutProperties","classRegistry","setClass"],"mappings":"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"}
|
|
@@ -68,6 +68,14 @@ export declare class OverlayEditor {
|
|
|
68
68
|
*/
|
|
69
69
|
private firstStrongDir;
|
|
70
70
|
private applyOverlayStyle;
|
|
71
|
+
/**
|
|
72
|
+
* Debug method to compare textarea and canvas object bounding boxes
|
|
73
|
+
*/
|
|
74
|
+
private debugBoundingBoxComparison;
|
|
75
|
+
/**
|
|
76
|
+
* Debug method to compare text wrapping between textarea and Fabric text object
|
|
77
|
+
*/
|
|
78
|
+
private debugTextWrapping;
|
|
71
79
|
/**
|
|
72
80
|
* Focus the textarea and position cursor at end
|
|
73
81
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"overlayEditor.d.ts","sourceRoot":"","sources":["../../../src/text/overlayEditor.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAKjD,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,UAAU,GAAG,KAAK,GAAG,OAAO,CAAC;IACrC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAC,CAAyB;IAC1C,OAAO,CAAC,QAAQ,CAAC,CAAa;IAG9B,OAAO,CAAC,aAAa,CAUnB;gBAEU,OAAO,EAAE,oBAAoB;IAoBzC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAa1B;;OAEG;IACH,OAAO,CAAC,gBAAgB;
|
|
1
|
+
{"version":3,"file":"overlayEditor.d.ts","sourceRoot":"","sources":["../../../src/text/overlayEditor.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAKjD,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,UAAU,GAAG,KAAK,GAAG,OAAO,CAAC;IACrC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAC,CAAyB;IAC1C,OAAO,CAAC,QAAQ,CAAC,CAAa;IAG9B,OAAO,CAAC,aAAa,CAUnB;gBAEU,OAAO,EAAE,oBAAoB;IAoBzC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAa1B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IA0DxB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAwB5B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAsB5B;;OAEG;IACH,OAAO,CAAC,cAAc;IAItB;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAmC1B;;OAEG;IACH,OAAO,CAAC,eAAe;IAIvB;;OAEG;IACH,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,iBAAiB;IA8GzB;;OAEG;IACH,OAAO,CAAC,0BAA0B;IAiGlC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA2GzB;;OAEG;IACH,OAAO,CAAC,aAAa;IAuCrB;;OAEG;IACI,OAAO,IAAI,IAAI;IAMtB;;OAEG;IACI,OAAO,CAAC,MAAM,GAAE,OAAc,GAAG,IAAI;IAgD5C,OAAO,CAAC,WAAW;IAiBnB,OAAO,CAAC,kBAAkB;IAqC1B,OAAO,CAAC,aAAa;IA2BrB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,sBAAsB;IAI9B,OAAO,CAAC,oBAAoB;IAK5B,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,eAAe;IAMvB;;OAEG;IACH,OAAO,CAAC,4BAA4B;IA8BpC;;OAEG;IACH,OAAO,CAAC,8BAA8B;CAavC;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,UAAU,GAAG,KAAK,GAAG,OAAO,EACpC,OAAO,CAAC,EAAE;IACR,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB,GACA,aAAa,CAsBf;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG,KAAK,GAAG,OAAO,GAAG,OAAO,CAE7E"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{defineProperty as t}from"../../_virtual/_rollupPluginBabelHelpers.min.mjs";import{transformPoint as e}from"../util/misc/matrix.min.mjs";class s{constructor(e){t(this,"canvas",void 0),t(this,"target",void 0),t(this,"container",void 0),t(this,"textarea",void 0),t(this,"hostDiv",void 0),t(this,"isDestroyed",!1),t(this,"isComposing",!1),t(this,"lastText",void 0),t(this,"onCommit",void 0),t(this,"onCancel",void 0),t(this,"boundHandlers",{onInput:this.handleInput.bind(this),onKeyDown:this.handleKeyDown.bind(this),onBlur:this.handleBlur.bind(this),onCompositionStart:this.handleCompositionStart.bind(this),onCompositionEnd:this.handleCompositionEnd.bind(this),onAfterRender:this.handleAfterRender.bind(this),onMouseWheel:this.handleMouseWheel.bind(this),onFocus:this.handleFocus.bind(this),onMouseDown:this.handleMouseDown.bind(this)}),this.canvas=e.canvas,this.target=e.target,this.onCommit=e.onCommit,this.onCancel=e.onCancel,this.lastText=this.target.text||"",this.container=this.getCanvasContainer(),this.createOverlayDOM(),this.attachEventListeners(),this.refresh(),this.focusTextarea()}getCanvasContainer(){const t=this.canvas.upperCanvasEl.parentElement;if(!t)throw new Error("Canvas must be mounted in DOM to use overlay editing");return t.style.position="relative",t}createOverlayDOM(){this.hostDiv=document.createElement("div"),this.hostDiv.style.position="absolute",this.hostDiv.style.pointerEvents="none",this.hostDiv.style.zIndex="1000",this.hostDiv.style.transformOrigin="left top",this.textarea=document.createElement("textarea"),this.textarea.style.position="absolute",this.textarea.style.left="0",this.textarea.style.top="0",this.textarea.style.margin="0",this.textarea.style.resize="none",this.textarea.style.pointerEvents="auto";const t=/[\u0600-\u06FF\u0750-\u077F\uFB50-\uFDFF\uFE70-\uFEFF]/.test(this.target.text||""),e="ltr"===this.target.direction;this.textarea.style.unicodeBidi=t&&e?"embed":"plaintext",this.textarea.style.caretColor="auto",this.textarea.style.border="none",this.textarea.style.padding="0",this.textarea.style.background="transparent",this.textarea.style.outline="none",this.textarea.style.overflow="hidden",this.textarea.style.whiteSpace="pre-wrap",this.textarea.style.wordBreak="normal",this.textarea.style.overflowWrap="break-word",this.textarea.style.userSelect="text",this.textarea.style.textTransform="none",this.textarea.style.opacity="1",this.textarea.value=this.target.text||"",this.hostDiv.appendChild(this.textarea),document.body.appendChild(this.hostDiv)}attachEventListeners(){this.textarea.addEventListener("input",this.boundHandlers.onInput),this.textarea.addEventListener("keydown",this.boundHandlers.onKeyDown),this.textarea.addEventListener("blur",this.boundHandlers.onBlur),this.textarea.addEventListener("compositionstart",this.boundHandlers.onCompositionStart),this.textarea.addEventListener("compositionend",this.boundHandlers.onCompositionEnd),this.textarea.addEventListener("focus",this.boundHandlers.onFocus),this.canvas.on("after:render",this.boundHandlers.onAfterRender),this.canvas.on("mouse:wheel",this.boundHandlers.onMouseWheel),this.canvas.on("mouse:down",this.boundHandlers.onMouseDown),this.setupViewportChangeDetection()}removeEventListeners(){this.textarea.removeEventListener("input",this.boundHandlers.onInput),this.textarea.removeEventListener("keydown",this.boundHandlers.onKeyDown),this.textarea.removeEventListener("blur",this.boundHandlers.onBlur),this.textarea.removeEventListener("compositionstart",this.boundHandlers.onCompositionStart),this.textarea.removeEventListener("compositionend",this.boundHandlers.onCompositionEnd),this.textarea.removeEventListener("focus",this.boundHandlers.onFocus),this.canvas.off("after:render",this.boundHandlers.onAfterRender),this.canvas.off("mouse:wheel",this.boundHandlers.onMouseWheel),this.canvas.off("mouse:down",this.boundHandlers.onMouseDown),this.restoreViewportChangeDetection()}updatePosition(){this.applyOverlayStyle()}updateObjectBounds(){if(this.isDestroyed)return;const t=this.target,e=this.canvas.getZoom();parseFloat(this.hostDiv.style.width);const s=parseFloat(this.hostDiv.style.height)/e;Math.abs(s-t.height)>1&&(t.height=s,t.setCoords(),this.canvas.requestRenderAll())}letterSpacingPx(t,e){return t/1e3*e}firstStrongDir(t){return/[\u0590-\u05FF\u0600-\u06FF\u0750-\u077F\uFB50-\uFDFF\uFE70-\uFEFF]/.test(t)?"rtl":"ltr"}applyOverlayStyle(){var t,s;const i=this.target,a=this.canvas;i.setCoords();const o=i.aCoords;console.log("BEFORE EDIT:"),console.log(" target.width =",i.width),console.log(" target.height =",i.height),console.log(" target.getScaledWidth() =",i.getScaledWidth()),console.log(" target.getScaledHeight() =",i.getScaledHeight()),console.log(" target.padding =",i.padding);const n=a.upperCanvasEl.getBoundingClientRect(),r=window.scrollX||window.pageXOffset,h=window.scrollY||window.pageYOffset,l=a.getZoom(),d=a.viewportTransform,c=i.padding||0,v=c*(i.scaleX||1)*l,g=c*(i.scaleY||1)*l,u=e({x:o.tl.x,y:o.tl.y},d),p=n.left+r+u.x,y=n.top+h+u.y,x=i.width*(i.scaleX||1)*l,m=i.height*(i.scaleY||1)*l;console.log("WIDTH CALCULATION:"),console.log(" target.width =",i.width),console.log(" scaledWidth =",i.getScaledWidth()),console.log(" zoom =",l),console.log(" final width =",x),this.hostDiv.style.position="absolute",this.hostDiv.style.left=`${p}px`,this.hostDiv.style.top=`${y}px`,this.hostDiv.style.width=`${x}px`,this.hostDiv.style.height=`${m}px`,this.hostDiv.style.overflow="hidden",i.angle?(this.hostDiv.style.transform=`rotate(${i.angle}deg)`,this.hostDiv.style.transformOrigin="top left"):(this.hostDiv.style.transform="",this.hostDiv.style.transformOrigin="");const f=null!==(t=i.fontSize)&&void 0!==t?t:16,w=i.scaleX||1,b=f*w*l,C=i.lineHeight||1.16,D=v>0?`calc(100% - ${2*v}px)`:"100%",E=g>0?`calc(100% - ${2*g}px)`:"100%";this.textarea.style.width=D,this.textarea.style.height=E,this.textarea.style.padding=`${g}px ${v}px`,this.textarea.style.fontSize=`${b}px`,this.textarea.style.lineHeight=String(C),this.textarea.style.fontFamily=i.fontFamily||"Arial",this.textarea.style.fontWeight=String(i.fontWeight||"normal"),this.textarea.style.fontStyle=i.fontStyle||"normal",this.textarea.style.textAlign=i.textAlign||"left",this.textarea.style.color=(null===(s=i.fill)||void 0===s?void 0:s.toString())||"#000",this.textarea.style.letterSpacing=(i.charSpacing||0)/1e3+"em",this.textarea.style.direction=i.direction||this.firstStrongDir(this.textarea.value||""),this.textarea.style.fontVariant="normal",this.textarea.style.fontStretch="normal",this.textarea.style.textRendering="auto",this.textarea.style.fontKerning="auto",this.textarea.style.boxSizing="content-box",this.textarea.style.margin="0",this.textarea.style.border="none",this.textarea.style.outline="none",this.textarea.style.background="transparent",this.textarea.style.wordWrap="break-word",this.textarea.style.whiteSpace="pre-wrap",console.log("TEXTAREA AFTER SETUP:"),console.log(" textarea width =",this.textarea.style.width),console.log(" textarea height =",this.textarea.style.height),console.log(" textarea padding =",this.textarea.style.padding),console.log(" paddingX =",v,"paddingY =",g),console.log(" baseFontSize =",f),console.log(" scaleX =",w),console.log(" zoom =",l),console.log(" finalFontSize =",b),console.log(" fabricLineHeight =",C)}focusTextarea(){this.target.opacity=.01,this.target.selected=!0,this.target.isEditing=!1,this.target.set({hasControls:!0,hasBorders:!0,selectable:!0,lockMovementX:!1,lockMovementY:!1}),this.canvas.setActiveObject(this.target),this.canvas.requestRenderAll(),this.target.setCoords(),this.applyOverlayStyle(),this.textarea.focus(),this.textarea.setSelectionRange(this.textarea.value.length,this.textarea.value.length),this.canvas.setActiveObject(this.target),this.canvas.requestRenderAll()}refresh(){this.isDestroyed||this.updatePosition()}destroy(){let t=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];if(!this.isDestroyed){if(this.isDestroyed=!0,this.removeEventListeners(),this.target.__overlayEditor===this&&(this.target.__overlayEditor=void 0,void 0!==this.target.__overlayOriginalOpacity&&(this.target.opacity=this.target.__overlayOriginalOpacity,delete this.target.__overlayOriginalOpacity)),this.hostDiv.parentNode&&this.hostDiv.parentNode.removeChild(this.hostDiv),t&&!this.isComposing){const t=this.textarea.value;this.onCommit&&this.onCommit(t)}else!t&&this.onCancel&&this.onCancel();setTimeout(()=>{this.canvas.upperCanvasEl.style.cursor="",this.canvas.setCursor(this.canvas.defaultCursor)},0),this.canvas.requestRenderAll()}}handleInput(){this.isComposing||this.target.text===this.textarea.value||(this.target.text=this.textarea.value,this.autoResizeTextarea(),this.target.selected=!0,this.target.isEditing=!1,this.canvas.setActiveObject(this.target),this.canvas.requestRenderAll())}autoResizeTextarea(){const t=parseFloat(window.getComputedStyle(this.textarea).height);this.textarea.style.height="auto";const e=this.textarea.scrollHeight,s=Math.max(e+8,25),i=Math.abs(s-t)>2;this.textarea.style.height=`${s}px`,this.hostDiv.style.height=`${s}px`,i&&this.updateObjectBounds()}handleKeyDown(t){"Escape"===t.key?(t.preventDefault(),this.destroy(!1)):(t.ctrlKey||t.metaKey)&&"Enter"===t.key&&(t.preventDefault(),this.destroy(!0))}handleFocus(){}handleBlur(){this.isComposing||this.destroy(!0)}handleCompositionStart(){this.isComposing=!0}handleCompositionEnd(){this.isComposing=!1,this.handleInput()}handleAfterRender(){this.refresh()}handleMouseWheel(){this.refresh()}handleMouseDown(t){t.target!==this.target&&this.destroy(!0)}setupViewportChangeDetection(){this.canvas.__originalSetZoom=this.canvas.setZoom,this.canvas.__originalSetViewportTransform=this.canvas.setViewportTransform,this.canvas.__overlayEditor=this;const t=this.canvas.setZoom.bind(this.canvas);this.canvas.setZoom=e=>{const s=t(e);return this.canvas.__overlayEditor&&!this.isDestroyed&&this.refresh(),s};const e=this.canvas.setViewportTransform.bind(this.canvas);this.canvas.setViewportTransform=t=>{const s=e(t);return this.canvas.__overlayEditor&&!this.isDestroyed&&this.refresh(),s}}restoreViewportChangeDetection(){this.canvas.__originalSetZoom&&(this.canvas.setZoom=this.canvas.__originalSetZoom,delete this.canvas.__originalSetZoom),this.canvas.__originalSetViewportTransform&&(this.canvas.setViewportTransform=this.canvas.__originalSetViewportTransform,delete this.canvas.__originalSetViewportTransform),delete this.canvas.__overlayEditor}}function i(t,e,i){e.__overlayEditor&&e.__overlayEditor.destroy(!1),e.__overlayOriginalOpacity=e.opacity;const a=new s({canvas:t,target:e,onCommit:null==i?void 0:i.onCommit,onCancel:null==i?void 0:i.onCancel});return e.__overlayEditor=a,a}export{s as OverlayEditor,i as enterTextOverlayEdit};
|
|
1
|
+
import{defineProperty as t}from"../../_virtual/_rollupPluginBabelHelpers.min.mjs";import{transformPoint as e}from"../util/misc/matrix.min.mjs";class s{constructor(e){t(this,"canvas",void 0),t(this,"target",void 0),t(this,"container",void 0),t(this,"textarea",void 0),t(this,"hostDiv",void 0),t(this,"isDestroyed",!1),t(this,"isComposing",!1),t(this,"lastText",void 0),t(this,"onCommit",void 0),t(this,"onCancel",void 0),t(this,"boundHandlers",{onInput:this.handleInput.bind(this),onKeyDown:this.handleKeyDown.bind(this),onBlur:this.handleBlur.bind(this),onCompositionStart:this.handleCompositionStart.bind(this),onCompositionEnd:this.handleCompositionEnd.bind(this),onAfterRender:this.handleAfterRender.bind(this),onMouseWheel:this.handleMouseWheel.bind(this),onFocus:this.handleFocus.bind(this),onMouseDown:this.handleMouseDown.bind(this)}),this.canvas=e.canvas,this.target=e.target,this.onCommit=e.onCommit,this.onCancel=e.onCancel,this.lastText=this.target.text||"",this.container=this.getCanvasContainer(),this.createOverlayDOM(),this.attachEventListeners(),this.refresh(),this.focusTextarea()}getCanvasContainer(){const t=this.canvas.upperCanvasEl.parentElement;if(!t)throw new Error("Canvas must be mounted in DOM to use overlay editing");return t.style.position="relative",t}createOverlayDOM(){this.hostDiv=document.createElement("div"),this.hostDiv.style.position="absolute",this.hostDiv.style.pointerEvents="none",this.hostDiv.style.zIndex="1000",this.hostDiv.style.transformOrigin="left top",this.textarea=document.createElement("textarea"),this.textarea.style.position="absolute",this.textarea.style.left="0",this.textarea.style.top="0",this.textarea.style.margin="0",this.textarea.style.resize="none",this.textarea.style.pointerEvents="auto";const t=/[\u0600-\u06FF\u0750-\u077F\uFB50-\uFDFF\uFE70-\uFEFF]/.test(this.target.text||""),e=/[a-zA-Z]/.test(this.target.text||""),s="ltr"===this.target.direction;this.textarea.style.unicodeBidi=t&&e&&s||t&&s?"embed":"plaintext",this.textarea.style.caretColor="auto",this.textarea.style.border="none",this.textarea.style.padding="0",this.textarea.style.background="transparent",this.textarea.style.outline="none",this.textarea.style.overflow="hidden",this.textarea.style.whiteSpace="pre-wrap",this.textarea.style.wordBreak="normal",this.textarea.style.overflowWrap="break-word",this.textarea.style.userSelect="text",this.textarea.style.textTransform="none",this.textarea.style.opacity="1",this.textarea.value=this.target.text||"",this.hostDiv.appendChild(this.textarea),document.body.appendChild(this.hostDiv)}attachEventListeners(){this.textarea.addEventListener("input",this.boundHandlers.onInput),this.textarea.addEventListener("keydown",this.boundHandlers.onKeyDown),this.textarea.addEventListener("blur",this.boundHandlers.onBlur),this.textarea.addEventListener("compositionstart",this.boundHandlers.onCompositionStart),this.textarea.addEventListener("compositionend",this.boundHandlers.onCompositionEnd),this.textarea.addEventListener("focus",this.boundHandlers.onFocus),this.canvas.on("after:render",this.boundHandlers.onAfterRender),this.canvas.on("mouse:wheel",this.boundHandlers.onMouseWheel),this.canvas.on("mouse:down",this.boundHandlers.onMouseDown),this.setupViewportChangeDetection()}removeEventListeners(){this.textarea.removeEventListener("input",this.boundHandlers.onInput),this.textarea.removeEventListener("keydown",this.boundHandlers.onKeyDown),this.textarea.removeEventListener("blur",this.boundHandlers.onBlur),this.textarea.removeEventListener("compositionstart",this.boundHandlers.onCompositionStart),this.textarea.removeEventListener("compositionend",this.boundHandlers.onCompositionEnd),this.textarea.removeEventListener("focus",this.boundHandlers.onFocus),this.canvas.off("after:render",this.boundHandlers.onAfterRender),this.canvas.off("mouse:wheel",this.boundHandlers.onMouseWheel),this.canvas.off("mouse:down",this.boundHandlers.onMouseDown),this.restoreViewportChangeDetection()}updatePosition(){this.applyOverlayStyle()}updateObjectBounds(){if(this.isDestroyed)return;const t=this.target,e=this.canvas.getZoom();parseFloat(this.hostDiv.style.width);const s=parseFloat(this.hostDiv.style.height)/e;Math.abs(s-t.height)>.5&&(t.height,t.height=s,t.setCoords(),t.dirty=!0,this.canvas.requestRenderAll(),requestAnimationFrame(()=>{this.isDestroyed||(this.applyOverlayStyle(),console.log("📐 Height changed - rechecking alignment after repositioning:"))}))}letterSpacingPx(t,e){return t/1e3*e}firstStrongDir(t){return/[\u0590-\u05FF\u0600-\u06FF\u0750-\u077F\uFB50-\uFDFF\uFE70-\uFEFF]/.test(t)?"rtl":"ltr"}applyOverlayStyle(){var t,s;const o=this.target,i=this.canvas;o.setCoords();const a=o.aCoords,n=i.upperCanvasEl.getBoundingClientRect(),r=window.scrollX||window.pageXOffset,h=window.scrollY||window.pageYOffset,l=i.getZoom(),d=i.viewportTransform,c=o.padding||0,g=c*(o.scaleX||1)*l,u=c*(o.scaleY||1)*l,p=e({x:a.tl.x,y:a.tl.y},d),v=n.left+r+p.x,y=n.top+h+p.y,f=o.getBoundingRect(),x=Math.round(f.width*l),m=Math.round(f.height*l);this.hostDiv.style.position="absolute",this.hostDiv.style.left=`${v}px`,this.hostDiv.style.top=`${y}px`,this.hostDiv.style.width=`${x}px`,this.hostDiv.style.height=`${m}px`,this.hostDiv.style.overflow="hidden",o.angle?(this.hostDiv.style.transform=`rotate(${o.angle}deg)`,this.hostDiv.style.transformOrigin="top left"):(this.hostDiv.style.transform="",this.hostDiv.style.transformOrigin="");const w=(null!==(t=o.fontSize)&&void 0!==t?t:16)*(o.scaleX||1)*l,D=o.lineHeight||1.16;this.textarea.style.boxSizing="border-box",this.textarea.style.width=`${x}px`,this.textarea.style.height="100%",this.textarea.style.padding=`${u}px ${g}px`;const b=(o.charSpacing||0)/1e3*w;this.textarea.style.fontSize=`${w}px`,this.textarea.style.lineHeight=String(D),this.textarea.style.fontFamily=o.fontFamily||"Arial",this.textarea.style.fontWeight=String(o.fontWeight||"normal"),this.textarea.style.fontStyle=o.fontStyle||"normal",this.textarea.style.textAlign=o.textAlign||"left",this.textarea.style.color=(null===(s=o.fill)||void 0===s?void 0:s.toString())||"#000",this.textarea.style.letterSpacing=`${b}px`,this.textarea.style.direction=o.direction||this.firstStrongDir(this.textarea.value||""),this.textarea.style.fontVariant="normal",this.textarea.style.fontStretch="normal",this.textarea.style.textRendering="optimizeLegibility",this.textarea.style.fontKerning="normal",this.textarea.style.fontFeatureSettings="normal",this.textarea.style.fontVariationSettings="normal",this.textarea.style.margin="0",this.textarea.style.border="none",this.textarea.style.outline="none",this.textarea.style.background="transparent",this.textarea.style.overflowWrap="break-word",this.textarea.style.whiteSpace="pre-wrap",this.textarea.style.hyphens="none",this.textarea.style.webkitFontSmoothing="antialiased",this.textarea.style.mozOsxFontSmoothing="grayscale",this.debugBoundingBoxComparison(),this.debugTextWrapping()}debugBoundingBoxComparison(){const t=this.target,e=this.canvas,s=e.getZoom(),o=this.textarea.getBoundingClientRect(),i=this.hostDiv.getBoundingClientRect(),a=t.getBoundingRect(),n=e.upperCanvasEl.getBoundingClientRect(),r=e.viewportTransform,h=n.left+a.left*s+r[4],l=n.top+a.top*s+r[5],d=a.width*s,c=a.height*s;console.log("🔍 BOUNDING BOX COMPARISON:"),console.log("📦 Textarea Rect:",{left:Math.round(100*o.left)/100,top:Math.round(100*o.top)/100,width:Math.round(100*o.width)/100,height:Math.round(100*o.height)/100}),console.log("📦 Host Div Rect:",{left:Math.round(100*i.left)/100,top:Math.round(100*i.top)/100,width:Math.round(100*i.width)/100,height:Math.round(100*i.height)/100}),console.log("📦 Canvas Object Bounds (screen):",{left:Math.round(100*h)/100,top:Math.round(100*l)/100,width:Math.round(100*d)/100,height:Math.round(100*c)/100}),console.log("📦 Canvas Object Bounds (canvas):",a);const g={leftDiff:Math.round(100*(i.left-h))/100,topDiff:Math.round(100*(i.top-l))/100,widthDiff:Math.round(100*(i.width-d))/100,heightDiff:Math.round(100*(i.height-c))/100},u={leftDiff:Math.round(100*(o.left-h))/100,topDiff:Math.round(100*(o.top-l))/100,widthDiff:Math.round(100*(o.width-d))/100,heightDiff:Math.round(100*(o.height-c))/100};console.log("📏 Host Div vs Canvas Object Diff:",g),console.log("📏 Textarea vs Canvas Object Diff:",u);const p=Math.abs(g.leftDiff)<2&&Math.abs(g.topDiff)<2&&Math.abs(g.widthDiff)<2&&Math.abs(g.heightDiff)<2,v=Math.abs(u.leftDiff)<2&&Math.abs(u.topDiff)<2&&Math.abs(u.widthDiff)<2&&Math.abs(u.heightDiff)<2;console.log(p?"✅ Host Div ALIGNED with canvas object":"❌ Host Div MISALIGNED with canvas object"),console.log(v?"✅ Textarea ALIGNED with canvas object":"❌ Textarea MISALIGNED with canvas object"),console.log("🔍 Zoom:",s,"Viewport Transform:",r),console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")}debugTextWrapping(){const t=this.target,e=this.textarea.value;console.log("📝 TEXT WRAPPING COMPARISON:"),console.log("📄 Text Content:",`"${e}"`),console.log("📄 Text Length:",e.length);const s=e.split("\n");console.log("📄 Explicit Lines (\\n):",s.length),s.forEach((t,e)=>{console.log(` Line ${e+1}: "${t}" (${t.length} chars)`)});const o=window.getComputedStyle(this.textarea);console.log("📐 Textarea Wrapping Styles:"),console.log(" width:",o.width),console.log(" fontSize:",o.fontSize),console.log(" fontFamily:",o.fontFamily),console.log(" fontWeight:",o.fontWeight),console.log(" letterSpacing:",o.letterSpacing),console.log(" lineHeight:",o.lineHeight),console.log(" whiteSpace:",o.whiteSpace),console.log(" wordWrap:",o.wordWrap),console.log(" overflowWrap:",o.overflowWrap),console.log(" direction:",o.direction),console.log(" textAlign:",o.textAlign),console.log("📐 Fabric Text Object Properties:"),console.log(" width:",t.width),console.log(" fontSize:",t.fontSize),console.log(" fontFamily:",t.fontFamily),console.log(" fontWeight:",t.fontWeight),console.log(" charSpacing:",t.charSpacing),console.log(" lineHeight:",t.lineHeight),console.log(" direction:",t.direction),console.log(" textAlign:",t.textAlign),console.log(" scaleX:",t.scaleX),console.log(" scaleY:",t.scaleY);const i=this.target.getBoundingRect().width,a=parseFloat(window.getComputedStyle(this.textarea).width)/this.canvas.getZoom(),n=Math.abs(a-i);console.log("📏 Effective Width Comparison:"),console.log(" Textarea Effective Width:",a),console.log(" Fabric Effective Width:",i),console.log(" Width Difference:",n.toFixed(2)+"px"),console.log(n<1?"✅ Widths MATCH for wrapping":"❌ Width MISMATCH may cause different wrapping");const r=/[\u0590-\u05FF\u0600-\u06FF\u0750-\u077F\uFB50-\uFDFF\uFE70-\uFEFF]/.test(e),h=/[\u0590-\u06FF]/.test(e)&&/[a-zA-Z]/.test(e);console.log("🌍 Text Direction Analysis:"),console.log(" Has RTL characters:",r),console.log(" Has mixed Bidi text:",h),console.log(" Textarea direction:",o.direction),console.log(" Fabric direction:",t.direction||"auto"),console.log(" Textarea unicodeBidi:",o.unicodeBidi);const l=this.textarea.scrollHeight,d=parseFloat(o.lineHeight)||1.2*parseFloat(o.fontSize),c=Math.round(l/d);console.log("📊 Line Count Analysis:"),console.log(" Textarea scrollHeight:",l),console.log(" Textarea lineHeight:",d),console.log(" Estimated rendered lines:",c),console.log(" Explicit line breaks:",s.length),c>s.length?(console.log("🔄 Text wrapping detected in textarea"),console.log(" Wrapped lines:",c-s.length)):console.log("📏 No text wrapping in textarea"),console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")}focusTextarea(){this.target.opacity=.01,this.target.selected=!0,this.target.isEditing=!1,this.target.set({hasControls:!0,hasBorders:!0,selectable:!0,lockMovementX:!1,lockMovementY:!1}),this.canvas.setActiveObject(this.target),this.canvas.requestRenderAll(),this.target.setCoords(),this.applyOverlayStyle(),this.textarea.focus(),this.textarea.setSelectionRange(this.textarea.value.length,this.textarea.value.length),this.canvas.setActiveObject(this.target),this.canvas.requestRenderAll()}refresh(){this.isDestroyed||this.updatePosition()}destroy(){let t=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];if(!this.isDestroyed){if(this.isDestroyed=!0,this.removeEventListeners(),this.target.__overlayEditor===this&&(this.target.__overlayEditor=void 0,void 0!==this.target.__overlayOriginalOpacity&&(this.target.opacity=this.target.__overlayOriginalOpacity,delete this.target.__overlayOriginalOpacity)),this.hostDiv.parentNode&&this.hostDiv.parentNode.removeChild(this.hostDiv),t&&!this.isComposing){const t=this.textarea.value;this.onCommit&&this.onCommit(t)}else!t&&this.onCancel&&this.onCancel();setTimeout(()=>{this.canvas.upperCanvasEl.style.cursor="",this.canvas.setCursor(this.canvas.defaultCursor)},0),this.canvas.requestRenderAll()}}handleInput(){this.isComposing||this.target.text===this.textarea.value||(this.target.text=this.textarea.value,this.autoResizeTextarea(),this.target.selected=!0,this.target.isEditing=!1,this.canvas.setActiveObject(this.target),this.canvas.requestRenderAll())}autoResizeTextarea(){const t=this.textarea.scrollTop,e=parseFloat(this.hostDiv.style.height||"0");this.textarea.style.height="1px";const s=this.textarea.scrollHeight+2;Math.abs(s-e)>1?(this.textarea.style.height=`${s}px`,this.hostDiv.style.height=`${s}px`,this.updateObjectBounds()):this.textarea.style.height=this.hostDiv.style.height,this.textarea.scrollTop=t}handleKeyDown(t){"Escape"===t.key?(t.preventDefault(),this.destroy(!1)):(t.ctrlKey||t.metaKey)&&"Enter"===t.key?(t.preventDefault(),this.destroy(!0)):"Enter"!==t.key&&"Backspace"!==t.key&&"Delete"!==t.key||(requestAnimationFrame(()=>{this.isDestroyed||this.autoResizeTextarea()}),setTimeout(()=>{this.isDestroyed||this.autoResizeTextarea()},10))}handleFocus(){}handleBlur(){this.isComposing||this.destroy(!0)}handleCompositionStart(){this.isComposing=!0}handleCompositionEnd(){this.isComposing=!1,this.handleInput()}handleAfterRender(){this.refresh()}handleMouseWheel(){this.refresh()}handleMouseDown(t){t.target!==this.target&&this.destroy(!0)}setupViewportChangeDetection(){this.canvas.__originalSetZoom=this.canvas.setZoom,this.canvas.__originalSetViewportTransform=this.canvas.setViewportTransform,this.canvas.__overlayEditor=this;const t=this.canvas.setZoom.bind(this.canvas);this.canvas.setZoom=e=>{const s=t(e);return this.canvas.__overlayEditor&&!this.isDestroyed&&this.refresh(),s};const e=this.canvas.setViewportTransform.bind(this.canvas);this.canvas.setViewportTransform=t=>{const s=e(t);return this.canvas.__overlayEditor&&!this.isDestroyed&&this.refresh(),s}}restoreViewportChangeDetection(){this.canvas.__originalSetZoom&&(this.canvas.setZoom=this.canvas.__originalSetZoom,delete this.canvas.__originalSetZoom),this.canvas.__originalSetViewportTransform&&(this.canvas.setViewportTransform=this.canvas.__originalSetViewportTransform,delete this.canvas.__originalSetViewportTransform),delete this.canvas.__overlayEditor}}function o(t,e,o){e.__overlayEditor&&e.__overlayEditor.destroy(!1),e.__overlayOriginalOpacity=e.opacity;const i=new s({canvas:t,target:e,onCommit:null==o?void 0:o.onCommit,onCancel:null==o?void 0:o.onCancel});return e.__overlayEditor=i,i}export{s as OverlayEditor,o as enterTextOverlayEdit};
|
|
2
2
|
//# sourceMappingURL=overlayEditor.min.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"overlayEditor.min.mjs","sources":["../../../src/text/overlayEditor.ts"],"sourcesContent":["/**\r\n * Canva/Polotno-style Overlay Text Editor\r\n *\r\n * Provides seamless inline text editing using an HTML textarea overlay\r\n * that matches canvas text positioning, styling, and transformations.\r\n */\r\n\r\nimport type { Canvas } from '../canvas/Canvas';\r\nimport type { FabricText } from '../shapes/Text/Text';\r\nimport type { IText } from '../shapes/IText/IText';\r\nimport type { Textbox } from '../shapes/Textbox';\r\nimport type { TPointerEventInfo } from '../EventTypeDefs';\r\nimport type { TMat2D } from '../typedefs';\r\nimport { transformPoint } from '../util/misc/matrix';\r\n\r\nexport interface OverlayEditorOptions {\r\n canvas: Canvas;\r\n target: FabricText | IText | Textbox;\r\n onCommit?: (text: string) => void;\r\n onCancel?: () => void;\r\n}\r\n\r\nexport interface ScreenTransform {\r\n translateX: number;\r\n translateY: number;\r\n scaleX: number;\r\n scaleY: number;\r\n angle: number; // in radians\r\n}\r\n\r\nexport class OverlayEditor {\r\n private canvas: Canvas;\r\n private target: FabricText | IText | Textbox;\r\n private container: HTMLElement;\r\n private textarea: HTMLTextAreaElement;\r\n private hostDiv: HTMLDivElement;\r\n private isDestroyed = false;\r\n private isComposing = false;\r\n private lastText: string;\r\n private onCommit?: (text: string) => void;\r\n private onCancel?: () => void;\r\n\r\n // Bound event handlers for cleanup\r\n private boundHandlers = {\r\n onInput: this.handleInput.bind(this),\r\n onKeyDown: this.handleKeyDown.bind(this),\r\n onBlur: this.handleBlur.bind(this),\r\n onCompositionStart: this.handleCompositionStart.bind(this),\r\n onCompositionEnd: this.handleCompositionEnd.bind(this),\r\n onAfterRender: this.handleAfterRender.bind(this),\r\n onMouseWheel: this.handleMouseWheel.bind(this),\r\n onFocus: this.handleFocus.bind(this),\r\n onMouseDown: this.handleMouseDown.bind(this),\r\n };\r\n\r\n constructor(options: OverlayEditorOptions) {\r\n this.canvas = options.canvas;\r\n this.target = options.target;\r\n this.onCommit = options.onCommit;\r\n this.onCancel = options.onCancel;\r\n this.lastText = this.target.text || '';\r\n\r\n this.container = this.getCanvasContainer();\r\n this.createOverlayDOM();\r\n this.attachEventListeners();\r\n this.refresh();\r\n this.focusTextarea();\r\n\r\n // Note: Don't manage object cursors since IText manages all cursors in _saveEditingProps/_restoreEditingProps\r\n // The IText editing system handles hoverCursor, moveCursor, and canvas cursors properly\r\n\r\n // Note: Canvas cursors are handled by IText's _saveEditingProps/_restoreEditingProps\r\n // We don't need to save/restore them here as it would conflict with IText's restoration\r\n }\r\n\r\n /**\r\n * Get the container element for the overlay (parent of upperCanvasEl)\r\n */\r\n private getCanvasContainer(): HTMLElement {\r\n const upperCanvas = this.canvas.upperCanvasEl;\r\n const container = upperCanvas.parentElement;\r\n if (!container) {\r\n throw new Error('Canvas must be mounted in DOM to use overlay editing');\r\n }\r\n \r\n // Ensure the container is positioned for absolute overlay positioning\r\n container.style.position = 'relative';\r\n \r\n return container;\r\n }\r\n\r\n /**\r\n * Create the overlay DOM structure\r\n */\r\n private createOverlayDOM(): void {\r\n // Host div for positioning and overflow control\r\n this.hostDiv = document.createElement('div');\r\n this.hostDiv.style.position = 'absolute';\r\n this.hostDiv.style.pointerEvents = 'none';\r\n this.hostDiv.style.zIndex = '1000';\r\n this.hostDiv.style.transformOrigin = 'left top';\r\n\r\n // Textarea for actual text input\r\n this.textarea = document.createElement('textarea');\r\n this.textarea.style.position = 'absolute';\r\n this.textarea.style.left = '0';\r\n this.textarea.style.top = '0';\r\n this.textarea.style.margin = '0';\r\n this.textarea.style.resize = 'none';\r\n this.textarea.style.pointerEvents = 'auto';\r\n // Set appropriate unicodeBidi based on content and direction\r\n const hasArabicText = /[\\u0600-\\u06FF\\u0750-\\u077F\\uFB50-\\uFDFF\\uFE70-\\uFEFF]/.test(this.target.text || '');\r\n const isLTRDirection = (this.target as any).direction === 'ltr';\r\n \r\n if (hasArabicText && isLTRDirection) {\r\n // For Arabic text in LTR mode, use embed to preserve shaping while respecting direction\r\n this.textarea.style.unicodeBidi = 'embed';\r\n } else {\r\n // Default to plaintext for natural text flow\r\n this.textarea.style.unicodeBidi = 'plaintext';\r\n }\r\n this.textarea.style.caretColor = 'auto';\r\n\r\n // Polotno-like base\r\n this.textarea.style.border = 'none';\r\n this.textarea.style.padding = '0';\r\n this.textarea.style.background = 'transparent'; // Transparent so Fabric text shows through\r\n this.textarea.style.outline = 'none';\r\n this.textarea.style.overflow = 'hidden'; // Prevent scrollbars\r\n this.textarea.style.whiteSpace = 'pre-wrap';\r\n this.textarea.style.wordBreak = 'normal';\r\n this.textarea.style.overflowWrap = 'break-word';\r\n this.textarea.style.userSelect = 'text';\r\n this.textarea.style.textTransform = 'none';\r\n\r\n // Start visible - we'll handle transitions differently\r\n this.textarea.style.opacity = '1';\r\n\r\n // Set initial text\r\n this.textarea.value = this.target.text || '';\r\n\r\n this.hostDiv.appendChild(this.textarea);\r\n document.body.appendChild(this.hostDiv);\r\n }\r\n\r\n /**\r\n * Attach all event listeners\r\n */\r\n private attachEventListeners(): void {\r\n // Textarea events\r\n this.textarea.addEventListener('input', this.boundHandlers.onInput);\r\n this.textarea.addEventListener('keydown', this.boundHandlers.onKeyDown);\r\n this.textarea.addEventListener('blur', this.boundHandlers.onBlur);\r\n this.textarea.addEventListener(\r\n 'compositionstart',\r\n this.boundHandlers.onCompositionStart,\r\n );\r\n this.textarea.addEventListener(\r\n 'compositionend',\r\n this.boundHandlers.onCompositionEnd,\r\n );\r\n this.textarea.addEventListener('focus', this.boundHandlers.onFocus);\r\n\r\n // Canvas events for synchronization\r\n this.canvas.on('after:render', this.boundHandlers.onAfterRender);\r\n this.canvas.on('mouse:wheel', this.boundHandlers.onMouseWheel);\r\n this.canvas.on('mouse:down', this.boundHandlers.onMouseDown);\r\n \r\n // Store original methods to detect viewport changes\r\n this.setupViewportChangeDetection();\r\n }\r\n\r\n /**\r\n * Remove all event listeners\r\n */\r\n private removeEventListeners(): void {\r\n this.textarea.removeEventListener('input', this.boundHandlers.onInput);\r\n this.textarea.removeEventListener('keydown', this.boundHandlers.onKeyDown);\r\n this.textarea.removeEventListener('blur', this.boundHandlers.onBlur);\r\n this.textarea.removeEventListener(\r\n 'compositionstart',\r\n this.boundHandlers.onCompositionStart,\r\n );\r\n this.textarea.removeEventListener(\r\n 'compositionend',\r\n this.boundHandlers.onCompositionEnd,\r\n );\r\n this.textarea.removeEventListener('focus', this.boundHandlers.onFocus);\r\n\r\n this.canvas.off('after:render', this.boundHandlers.onAfterRender);\r\n this.canvas.off('mouse:wheel', this.boundHandlers.onMouseWheel);\r\n this.canvas.off('mouse:down', this.boundHandlers.onMouseDown);\r\n \r\n // Restore original methods\r\n this.restoreViewportChangeDetection();\r\n }\r\n\r\n /**\r\n * Simple method to refresh positioning when canvas changes\r\n */\r\n private updatePosition(): void {\r\n this.applyOverlayStyle();\r\n }\r\n\r\n /**\r\n * Update the Fabric object bounds to match current textarea size\r\n * This ensures Fabric.js selection controls follow the growing textbox\r\n */\r\n private updateObjectBounds(): void {\r\n if (this.isDestroyed) return;\r\n\r\n const target = this.target;\r\n const zoom = this.canvas.getZoom();\r\n \r\n // Get current textbox dimensions from the host div (in canvas coordinates)\r\n const currentWidth = parseFloat(this.hostDiv.style.width) / zoom;\r\n const currentHeight = parseFloat(this.hostDiv.style.height) / zoom;\r\n \r\n // Only update if there's a meaningful change (avoid float precision issues)\r\n const heightDiff = Math.abs(currentHeight - target.height);\r\n const threshold = 1; // 1px threshold to avoid micro-changes\r\n \r\n if (heightDiff > threshold) {\r\n target.height = currentHeight;\r\n target.setCoords(); // Update control positions\r\n this.canvas.requestRenderAll(); // Re-render to show updated selection\r\n }\r\n }\r\n\r\n /**\r\n * Convert Fabric charSpacing (1/1000 em) to CSS letter-spacing (px)\r\n */\r\n private letterSpacingPx(charSpacing: number, fontSize: number): number {\r\n return (charSpacing / 1000) * fontSize;\r\n }\r\n\r\n /**\r\n * Detect text direction using first strong directional character\r\n */\r\n private firstStrongDir(text: string): 'ltr' | 'rtl' {\r\n // Hebrew: \\u0590-\\u05FF, Arabic: \\u0600-\\u06FF, \\u0750-\\u077F, \\uFB50-\\uFDFF, \\uFE70-\\uFEFF\r\n const rtlRegex =\r\n /[\\u0590-\\u05FF\\u0600-\\u06FF\\u0750-\\u077F\\uFB50-\\uFDFF\\uFE70-\\uFEFF]/;\r\n return rtlRegex.test(text) ? 'rtl' : 'ltr';\r\n }\r\n\r\n private applyOverlayStyle(): void {\r\n const target = this.target;\r\n const canvas = this.canvas;\r\n\r\n // 1. Freshen object's transformations - use aCoords like rtl-test.html\r\n target.setCoords();\r\n const aCoords = target.aCoords;\r\n \r\n // DEBUG: Log dimensions before edit\r\n console.log('BEFORE EDIT:');\r\n console.log(' target.width =', (target as any).width);\r\n console.log(' target.height =', target.height);\r\n console.log(' target.getScaledWidth() =', target.getScaledWidth());\r\n console.log(' target.getScaledHeight() =', target.getScaledHeight());\r\n console.log(' target.padding =', (target as any).padding);\r\n \r\n // 2. Get canvas position and scroll offsets (like rtl-test.html)\r\n const canvasEl = canvas.upperCanvasEl;\r\n const canvasRect = canvasEl.getBoundingClientRect();\r\n const scrollX = window.scrollX || window.pageXOffset;\r\n const scrollY = window.scrollY || window.pageYOffset;\r\n\r\n // 3. Position and dimensions accounting for Fabric Textbox padding and viewport transform\r\n const zoom = canvas.getZoom();\r\n const vpt = canvas.viewportTransform;\r\n const padding = (target as any).padding || 0;\r\n const paddingX = padding * (target.scaleX || 1) * zoom;\r\n const paddingY = padding * (target.scaleY || 1) * zoom;\r\n\r\n // Transform object's top-left corner coordinates to screen coordinates using viewport transform\r\n // aCoords.tl already accounts for object positioning and scaling, just need viewport transform\r\n const screenPoint = transformPoint({ x: aCoords.tl.x, y: aCoords.tl.y }, vpt);\r\n \r\n const left = canvasRect.left + scrollX + screenPoint.x;\r\n const top = canvasRect.top + scrollY + screenPoint.y;\r\n\r\n // 4. Get dimensions with zoom scaling - use target.width for text wrapping, scaled height for container\r\n const width = (target as any).width * (target.scaleX || 1) * zoom; // Account for object scale and viewport zoom\r\n const height = target.height * (target.scaleY || 1) * zoom;\r\n \r\n console.log('WIDTH CALCULATION:');\r\n console.log(' target.width =', (target as any).width);\r\n console.log(' scaledWidth =', target.getScaledWidth());\r\n console.log(' zoom =', zoom);\r\n console.log(' final width =', width);\r\n\r\n // 5. Apply styles to host DIV - absolute positioning like rtl-test.html\r\n this.hostDiv.style.position = 'absolute';\r\n this.hostDiv.style.left = `${left}px`;\r\n this.hostDiv.style.top = `${top}px`;\r\n this.hostDiv.style.width = `${width}px`;\r\n this.hostDiv.style.height = `${height}px`;\r\n this.hostDiv.style.overflow = 'hidden'; // Prevent scrollbars in host div\r\n // Apply rotation matching Fabric.js object transformation\r\n if (target.angle) {\r\n this.hostDiv.style.transform = `rotate(${target.angle}deg)`;\r\n this.hostDiv.style.transformOrigin = 'top left'; // Match Fabric Textbox behavior\r\n } else {\r\n this.hostDiv.style.transform = '';\r\n this.hostDiv.style.transformOrigin = '';\r\n }\r\n\r\n // 6. Style the textarea - match Fabric's exact rendering with padding\r\n const baseFontSize = (target.fontSize ?? 16);\r\n // Use scaleX for font scaling to match Fabric text scaling exactly\r\n const scaleX = target.scaleX || 1;\r\n const finalFontSize = baseFontSize * scaleX * zoom;\r\n const fabricLineHeight = target.lineHeight || 1.16;\r\n // Apply padding and dimensions to textarea\r\n const textareaWidth = paddingX > 0 ? `calc(100% - ${2 * paddingX}px)` : '100%';\r\n const textareaHeight = paddingY > 0 ? `calc(100% - ${2 * paddingY}px)` : '100%';\r\n \r\n this.textarea.style.width = textareaWidth;\r\n this.textarea.style.height = textareaHeight;\r\n this.textarea.style.padding = `${paddingY}px ${paddingX}px`;\r\n \r\n this.textarea.style.fontSize = `${finalFontSize}px`;\r\n this.textarea.style.lineHeight = String(fabricLineHeight); // Use unit-less multiplier\r\n this.textarea.style.fontFamily = target.fontFamily || 'Arial';\r\n this.textarea.style.fontWeight = String(target.fontWeight || 'normal');\r\n this.textarea.style.fontStyle = target.fontStyle || 'normal';\r\n this.textarea.style.textAlign = (target as any).textAlign || 'left';\r\n this.textarea.style.color = target.fill?.toString() || '#000';\r\n this.textarea.style.letterSpacing = `${((target.charSpacing || 0) / 1000)}em`;\r\n this.textarea.style.direction = (target as any).direction || this.firstStrongDir(this.textarea.value || '');\r\n \r\n // Ensure consistent font rendering between Fabric and CSS\r\n this.textarea.style.fontVariant = 'normal';\r\n this.textarea.style.fontStretch = 'normal';\r\n this.textarea.style.textRendering = 'auto';\r\n this.textarea.style.fontKerning = 'auto';\r\n this.textarea.style.boxSizing = 'content-box'; // Padding is added outside width/height\r\n this.textarea.style.margin = '0';\r\n this.textarea.style.border = 'none';\r\n this.textarea.style.outline = 'none';\r\n this.textarea.style.background = 'transparent';\r\n this.textarea.style.wordWrap = 'break-word';\r\n this.textarea.style.whiteSpace = 'pre-wrap';\r\n \r\n // DEBUG: Log final textarea dimensions\r\n console.log('TEXTAREA AFTER SETUP:');\r\n console.log(' textarea width =', this.textarea.style.width);\r\n console.log(' textarea height =', this.textarea.style.height);\r\n console.log(' textarea padding =', this.textarea.style.padding);\r\n console.log(' paddingX =', paddingX, 'paddingY =', paddingY);\r\n console.log(' baseFontSize =', baseFontSize);\r\n console.log(' scaleX =', scaleX);\r\n console.log(' zoom =', zoom);\r\n console.log(' finalFontSize =', finalFontSize);\r\n console.log(' fabricLineHeight =', fabricLineHeight);\r\n\r\n // Initial bounds are set correctly by Fabric.js - don't force update here\r\n\r\n \r\n }\r\n\r\n /**\r\n * Focus the textarea and position cursor at end\r\n */\r\n private focusTextarea(): void {\r\n \r\n\r\n // For overlay editing, we want to keep the object in \"selection mode\" not \"editing mode\"\r\n // This means keeping selected=true and isEditing=false to show boundaries\r\n \r\n // Hide the text content only (not the entire object)\r\n this.target.opacity = 0.01; // Nearly transparent but not fully hidden\r\n \r\n // Ensure object stays selected to show boundaries\r\n (this.target as any).selected = true;\r\n (this.target as any).isEditing = false; // Override any editing state\r\n \r\n // Make sure controls are enabled and movement is allowed during overlay editing\r\n this.target.set({\r\n hasControls: true,\r\n hasBorders: true,\r\n selectable: true,\r\n lockMovementX: false,\r\n lockMovementY: false\r\n });\r\n \r\n // Keep as active object\r\n this.canvas.setActiveObject(this.target);\r\n \r\n this.canvas.requestRenderAll();\r\n this.target.setCoords();\r\n this.applyOverlayStyle();\r\n\r\n \r\n\r\n this.textarea.focus();\r\n this.textarea.setSelectionRange(\r\n this.textarea.value.length,\r\n this.textarea.value.length,\r\n );\r\n \r\n // Ensure the object stays selected even after textarea focus\r\n this.canvas.setActiveObject(this.target);\r\n this.canvas.requestRenderAll();\r\n }\r\n\r\n /**\r\n * Refresh overlay positioning and styling\r\n */\r\n public refresh(): void {\r\n if (this.isDestroyed) return;\r\n this.updatePosition();\r\n // Don't update object bounds on every refresh - only when textarea actually resizes\r\n }\r\n\r\n /**\r\n * Destroy the overlay editor\r\n */\r\n public destroy(commit: boolean = true): void {\r\n if (this.isDestroyed) return;\r\n this.isDestroyed = true;\r\n\r\n this.removeEventListeners();\r\n\r\n // Restore target visibility before handling commit/cancel\r\n if ((this.target as any).__overlayEditor === this) {\r\n (this.target as any).__overlayEditor = undefined;\r\n\r\n // Restore original opacity\r\n if ((this.target as any).__overlayOriginalOpacity !== undefined) {\r\n this.target.opacity = (this.target as any).__overlayOriginalOpacity;\r\n delete (this.target as any).__overlayOriginalOpacity;\r\n }\r\n }\r\n\r\n // Remove DOM first\r\n if (this.hostDiv.parentNode) {\r\n this.hostDiv.parentNode.removeChild(this.hostDiv);\r\n }\r\n\r\n // Handle commit/cancel after restoring visibility\r\n if (commit && !this.isComposing) {\r\n const finalText = this.textarea.value;\r\n if (this.onCommit) {\r\n this.onCommit(finalText);\r\n }\r\n } else if (!commit && this.onCancel) {\r\n this.onCancel();\r\n }\r\n\r\n // Note: Don't restore object cursors since IText manages all cursors in _restoreEditingProps\r\n // Let the IText editing system handle proper restoration of all cursor properties\r\n\r\n // Note: Canvas cursors are restored by IText's _restoreEditingProps method\r\n // Force a cursor refresh by triggering _setCursorFromEvent\r\n setTimeout(() => {\r\n this.canvas.upperCanvasEl.style.cursor = '';\r\n // Trigger cursor refresh on next mouse move\r\n this.canvas.setCursor(this.canvas.defaultCursor);\r\n }, 0);\r\n\r\n // Request canvas re-render\r\n this.canvas.requestRenderAll();\r\n }\r\n\r\n // Event handlers\r\n private handleInput(): void {\r\n if (!this.isComposing && this.target.text !== this.textarea.value) {\r\n // Live update target text\r\n this.target.text = this.textarea.value;\r\n\r\n // Auto-resize textarea to match new content\r\n this.autoResizeTextarea();\r\n\r\n // Ensure object stays in selection mode (not editing mode) to show controls\r\n (this.target as any).selected = true;\r\n (this.target as any).isEditing = false;\r\n this.canvas.setActiveObject(this.target);\r\n this.canvas.requestRenderAll();\r\n }\r\n }\r\n\r\n private autoResizeTextarea(): void {\r\n // Allow both vertical growth and shrinking; host width stays fixed\r\n const oldHeight = parseFloat(window.getComputedStyle(this.textarea).height);\r\n \r\n // Reset height to measure actual needed height\r\n this.textarea.style.height = 'auto';\r\n const scrollHeight = this.textarea.scrollHeight;\r\n \r\n // Add extra padding to prevent text clipping (especially for line height)\r\n const lineHeightBuffer = 8; // Extra space to prevent clipping\r\n const newHeight = Math.max(scrollHeight + lineHeightBuffer, 25); // Minimum height with buffer\r\n const heightChanged = Math.abs(newHeight - oldHeight) > 2; // Only if meaningful change\r\n \r\n this.textarea.style.height = `${newHeight}px`;\r\n this.hostDiv.style.height = `${newHeight}px`; // Match exactly\r\n \r\n // Only update object bounds if height actually changed\r\n if (heightChanged) {\r\n this.updateObjectBounds();\r\n }\r\n }\r\n\r\n private handleKeyDown(e: KeyboardEvent): void {\r\n if (e.key === 'Escape') {\r\n e.preventDefault();\r\n this.destroy(false); // Cancel\r\n } else if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {\r\n e.preventDefault();\r\n this.destroy(true); // Commit\r\n }\r\n }\r\n\r\n private handleFocus(): void {\r\n // Focus handler - could be used for future enhancements\r\n }\r\n\r\n private handleBlur(): void {\r\n // Commit on blur unless we're in composition mode\r\n if (!this.isComposing) {\r\n this.destroy(true);\r\n }\r\n }\r\n\r\n private handleCompositionStart(): void {\r\n this.isComposing = true;\r\n }\r\n\r\n private handleCompositionEnd(): void {\r\n this.isComposing = false;\r\n this.handleInput(); // Update text after composition\r\n }\r\n\r\n private handleAfterRender(): void {\r\n this.refresh();\r\n }\r\n\r\n private handleMouseWheel(): void {\r\n this.refresh();\r\n }\r\n\r\n private handleMouseDown(e: TPointerEventInfo): void {\r\n if (e.target !== this.target) {\r\n this.destroy(true);\r\n }\r\n }\r\n\r\n /**\r\n * Setup detection for viewport changes (zoom/pan)\r\n */\r\n private setupViewportChangeDetection(): void {\r\n // Store original methods\r\n (this.canvas as any).__originalSetZoom = this.canvas.setZoom;\r\n (this.canvas as any).__originalSetViewportTransform = this.canvas.setViewportTransform;\r\n (this.canvas as any).__overlayEditor = this;\r\n \r\n // Override setZoom to detect zoom changes\r\n const originalSetZoom = this.canvas.setZoom.bind(this.canvas);\r\n this.canvas.setZoom = (value: number) => {\r\n const result = originalSetZoom(value);\r\n if ((this.canvas as any).__overlayEditor && !this.isDestroyed) {\r\n this.refresh();\r\n }\r\n return result;\r\n };\r\n \r\n // Override setViewportTransform to detect pan changes\r\n const originalSetViewportTransform = this.canvas.setViewportTransform.bind(this.canvas);\r\n this.canvas.setViewportTransform = (vpt: TMat2D) => {\r\n const result = originalSetViewportTransform(vpt);\r\n if ((this.canvas as any).__overlayEditor && !this.isDestroyed) {\r\n this.refresh();\r\n }\r\n return result;\r\n };\r\n }\r\n \r\n /**\r\n * Restore original viewport methods\r\n */\r\n private restoreViewportChangeDetection(): void {\r\n if ((this.canvas as any).__originalSetZoom) {\r\n this.canvas.setZoom = (this.canvas as any).__originalSetZoom;\r\n delete (this.canvas as any).__originalSetZoom;\r\n }\r\n if ((this.canvas as any).__originalSetViewportTransform) {\r\n this.canvas.setViewportTransform = (this.canvas as any).__originalSetViewportTransform;\r\n delete (this.canvas as any).__originalSetViewportTransform;\r\n }\r\n delete (this.canvas as any).__overlayEditor;\r\n }\r\n\r\n \r\n}\r\n\r\n/**\r\n * Enter overlay text editing mode for a text object\r\n */\r\nexport function enterTextOverlayEdit(\r\n canvas: Canvas,\r\n target: FabricText | IText | Textbox,\r\n options?: {\r\n onCommit?: (text: string) => void;\r\n onCancel?: () => void;\r\n },\r\n): OverlayEditor {\r\n // If already in overlay editing, destroy existing editor first\r\n if ((target as any).__overlayEditor) {\r\n (target as any).__overlayEditor.destroy(false);\r\n }\r\n\r\n // Store original opacity so we can restore it later\r\n (target as any).__overlayOriginalOpacity = target.opacity;\r\n\r\n const editor = new OverlayEditor({\r\n canvas,\r\n target,\r\n onCommit: options?.onCommit,\r\n onCancel: options?.onCancel,\r\n });\r\n\r\n // We no longer change fill, so no need to store it\r\n \r\n // Store reference on target for cleanup\r\n (target as any).__overlayEditor = editor;\r\n\r\n return editor;\r\n}\r\n\r\n/**\r\n * Check if a text object is currently being edited with overlay editor\r\n */\r\nexport function isInOverlayEdit(target: FabricText | IText | Textbox): boolean {\r\n return !!(target as any).__overlayEditor?.isActive;\r\n}\r\n"],"names":["OverlayEditor","constructor","options","_defineProperty","this","onInput","handleInput","bind","onKeyDown","handleKeyDown","onBlur","handleBlur","onCompositionStart","handleCompositionStart","onCompositionEnd","handleCompositionEnd","onAfterRender","handleAfterRender","onMouseWheel","handleMouseWheel","onFocus","handleFocus","onMouseDown","handleMouseDown","canvas","target","onCommit","onCancel","lastText","text","container","getCanvasContainer","createOverlayDOM","attachEventListeners","refresh","focusTextarea","upperCanvasEl","parentElement","Error","style","position","hostDiv","document","createElement","pointerEvents","zIndex","transformOrigin","textarea","left","top","margin","resize","hasArabicText","test","isLTRDirection","direction","unicodeBidi","caretColor","border","padding","background","outline","overflow","whiteSpace","wordBreak","overflowWrap","userSelect","textTransform","opacity","value","appendChild","body","addEventListener","boundHandlers","on","setupViewportChangeDetection","removeEventListeners","removeEventListener","off","restoreViewportChangeDetection","updatePosition","applyOverlayStyle","updateObjectBounds","isDestroyed","zoom","getZoom","parseFloat","width","currentHeight","height","Math","abs","setCoords","requestRenderAll","letterSpacingPx","charSpacing","fontSize","firstStrongDir","_target$fontSize","_target$fill","aCoords","console","log","getScaledWidth","getScaledHeight","canvasRect","getBoundingClientRect","scrollX","window","pageXOffset","scrollY","pageYOffset","vpt","viewportTransform","paddingX","scaleX","paddingY","scaleY","screenPoint","transformPoint","x","tl","y","angle","transform","baseFontSize","finalFontSize","fabricLineHeight","lineHeight","textareaWidth","textareaHeight","String","fontFamily","fontWeight","fontStyle","textAlign","color","fill","toString","letterSpacing","fontVariant","fontStretch","textRendering","fontKerning","boxSizing","wordWrap","selected","isEditing","set","hasControls","hasBorders","selectable","lockMovementX","lockMovementY","setActiveObject","focus","setSelectionRange","length","destroy","commit","arguments","undefined","__overlayEditor","__overlayOriginalOpacity","parentNode","removeChild","isComposing","finalText","setTimeout","cursor","setCursor","defaultCursor","autoResizeTextarea","oldHeight","getComputedStyle","scrollHeight","newHeight","max","heightChanged","e","key","preventDefault","ctrlKey","metaKey","__originalSetZoom","setZoom","__originalSetViewportTransform","setViewportTransform","originalSetZoom","result","originalSetViewportTransform","enterTextOverlayEdit","editor"],"mappings":"+IA8BO,MAAMA,EAyBXC,WAAAA,CAAYC,GAA+BC,EAAAC,KAAA,cAAA,GAAAD,EAAAC,KAAA,cAAA,GAAAD,EAAAC,KAAA,iBAAA,GAAAD,EAAAC,KAAA,gBAAA,GAAAD,EAAAC,KAAA,eAAA,GAAAD,sBAnBrB,GAAKA,sBACL,GAAKA,EAAAC,KAAA,gBAAA,GAAAD,EAAAC,KAAA,gBAAA,GAAAD,EAAAC,KAAA,gBAAA,GAK3BD,EAAAC,KAAA,gBACwB,CACtBC,QAASD,KAAKE,YAAYC,KAAKH,MAC/BI,UAAWJ,KAAKK,cAAcF,KAAKH,MACnCM,OAAQN,KAAKO,WAAWJ,KAAKH,MAC7BQ,mBAAoBR,KAAKS,uBAAuBN,KAAKH,MACrDU,iBAAkBV,KAAKW,qBAAqBR,KAAKH,MACjDY,cAAeZ,KAAKa,kBAAkBV,KAAKH,MAC3Cc,aAAcd,KAAKe,iBAAiBZ,KAAKH,MACzCgB,QAAShB,KAAKiB,YAAYd,KAAKH,MAC/BkB,YAAalB,KAAKmB,gBAAgBhB,KAAKH,QAIvCA,KAAKoB,OAAStB,EAAQsB,OACtBpB,KAAKqB,OAASvB,EAAQuB,OACtBrB,KAAKsB,SAAWxB,EAAQwB,SACxBtB,KAAKuB,SAAWzB,EAAQyB,SACxBvB,KAAKwB,SAAWxB,KAAKqB,OAAOI,MAAQ,GAEpCzB,KAAK0B,UAAY1B,KAAK2B,qBACtB3B,KAAK4B,mBACL5B,KAAK6B,uBACL7B,KAAK8B,UACL9B,KAAK+B,eAOP,CAKQJ,kBAAAA,GACN,MACMD,EADc1B,KAAKoB,OAAOY,cACFC,cAC9B,IAAKP,EACH,MAAM,IAAIQ,MAAM,wDAMlB,OAFAR,EAAUS,MAAMC,SAAW,WAEpBV,CACT,CAKQE,gBAAAA,GAEN5B,KAAKqC,QAAUC,SAASC,cAAc,OACtCvC,KAAKqC,QAAQF,MAAMC,SAAW,WAC9BpC,KAAKqC,QAAQF,MAAMK,cAAgB,OACnCxC,KAAKqC,QAAQF,MAAMM,OAAS,OAC5BzC,KAAKqC,QAAQF,MAAMO,gBAAkB,WAGrC1C,KAAK2C,SAAWL,SAASC,cAAc,YACvCvC,KAAK2C,SAASR,MAAMC,SAAW,WAC/BpC,KAAK2C,SAASR,MAAMS,KAAO,IAC3B5C,KAAK2C,SAASR,MAAMU,IAAM,IAC1B7C,KAAK2C,SAASR,MAAMW,OAAS,IAC7B9C,KAAK2C,SAASR,MAAMY,OAAS,OAC7B/C,KAAK2C,SAASR,MAAMK,cAAgB,OAEpC,MAAMQ,EAAgB,yDAAyDC,KAAKjD,KAAKqB,OAAOI,MAAQ,IAClGyB,EAAoD,QAAlClD,KAAKqB,OAAe8B,UAI1CnD,KAAK2C,SAASR,MAAMiB,YAFlBJ,GAAiBE,EAEe,QAGA,YAEpClD,KAAK2C,SAASR,MAAMkB,WAAa,OAGjCrD,KAAK2C,SAASR,MAAMmB,OAAS,OAC7BtD,KAAK2C,SAASR,MAAMoB,QAAU,IAC9BvD,KAAK2C,SAASR,MAAMqB,WAAa,cACjCxD,KAAK2C,SAASR,MAAMsB,QAAU,OAC9BzD,KAAK2C,SAASR,MAAMuB,SAAW,SAC/B1D,KAAK2C,SAASR,MAAMwB,WAAa,WACjC3D,KAAK2C,SAASR,MAAMyB,UAAY,SAChC5D,KAAK2C,SAASR,MAAM0B,aAAe,aACnC7D,KAAK2C,SAASR,MAAM2B,WAAa,OACjC9D,KAAK2C,SAASR,MAAM4B,cAAgB,OAGpC/D,KAAK2C,SAASR,MAAM6B,QAAU,IAG9BhE,KAAK2C,SAASsB,MAAQjE,KAAKqB,OAAOI,MAAQ,GAE1CzB,KAAKqC,QAAQ6B,YAAYlE,KAAK2C,UAC9BL,SAAS6B,KAAKD,YAAYlE,KAAKqC,QACjC,CAKQR,oBAAAA,GAEN7B,KAAK2C,SAASyB,iBAAiB,QAASpE,KAAKqE,cAAcpE,SAC3DD,KAAK2C,SAASyB,iBAAiB,UAAWpE,KAAKqE,cAAcjE,WAC7DJ,KAAK2C,SAASyB,iBAAiB,OAAQpE,KAAKqE,cAAc/D,QAC1DN,KAAK2C,SAASyB,iBACZ,mBACApE,KAAKqE,cAAc7D,oBAErBR,KAAK2C,SAASyB,iBACZ,iBACApE,KAAKqE,cAAc3D,kBAErBV,KAAK2C,SAASyB,iBAAiB,QAASpE,KAAKqE,cAAcrD,SAG3DhB,KAAKoB,OAAOkD,GAAG,eAAgBtE,KAAKqE,cAAczD,eAClDZ,KAAKoB,OAAOkD,GAAG,cAAetE,KAAKqE,cAAcvD,cACjDd,KAAKoB,OAAOkD,GAAG,aAActE,KAAKqE,cAAcnD,aAGhDlB,KAAKuE,8BACP,CAKQC,oBAAAA,GACNxE,KAAK2C,SAAS8B,oBAAoB,QAASzE,KAAKqE,cAAcpE,SAC9DD,KAAK2C,SAAS8B,oBAAoB,UAAWzE,KAAKqE,cAAcjE,WAChEJ,KAAK2C,SAAS8B,oBAAoB,OAAQzE,KAAKqE,cAAc/D,QAC7DN,KAAK2C,SAAS8B,oBACZ,mBACAzE,KAAKqE,cAAc7D,oBAErBR,KAAK2C,SAAS8B,oBACZ,iBACAzE,KAAKqE,cAAc3D,kBAErBV,KAAK2C,SAAS8B,oBAAoB,QAASzE,KAAKqE,cAAcrD,SAE9DhB,KAAKoB,OAAOsD,IAAI,eAAgB1E,KAAKqE,cAAczD,eACnDZ,KAAKoB,OAAOsD,IAAI,cAAe1E,KAAKqE,cAAcvD,cAClDd,KAAKoB,OAAOsD,IAAI,aAAc1E,KAAKqE,cAAcnD,aAGjDlB,KAAK2E,gCACP,CAKQC,cAAAA,GACN5E,KAAK6E,mBACP,CAMQC,kBAAAA,GACN,GAAI9E,KAAK+E,YAAa,OAEtB,MAAM1D,EAASrB,KAAKqB,OACd2D,EAAOhF,KAAKoB,OAAO6D,UAGJC,WAAWlF,KAAKqC,QAAQF,MAAMgD,OACnD,MAAMC,EAAgBF,WAAWlF,KAAKqC,QAAQF,MAAMkD,QAAUL,EAG3CM,KAAKC,IAAIH,EAAgB/D,EAAOgE,QACjC,IAGhBhE,EAAOgE,OAASD,EAChB/D,EAAOmE,YACPxF,KAAKoB,OAAOqE,mBAEhB,CAKQC,eAAAA,CAAgBC,EAAqBC,GAC3C,OAAQD,EAAc,IAAQC,CAChC,CAKQC,cAAAA,CAAepE,GAIrB,MADE,sEACcwB,KAAKxB,GAAQ,MAAQ,KACvC,CAEQoD,iBAAAA,GAA0B,IAAAiB,EAAAC,EAChC,MAAM1E,EAASrB,KAAKqB,OACdD,EAASpB,KAAKoB,OAGpBC,EAAOmE,YACP,MAAMQ,EAAU3E,EAAO2E,QAGvBC,QAAQC,IAAI,gBACZD,QAAQC,IAAI,mBAAqB7E,EAAe8D,OAChDc,QAAQC,IAAI,oBAAqB7E,EAAOgE,QACxCY,QAAQC,IAAI,8BAA+B7E,EAAO8E,kBAClDF,QAAQC,IAAI,+BAAgC7E,EAAO+E,mBACnDH,QAAQC,IAAI,qBAAuB7E,EAAekC,SAGlD,MACM8C,EADWjF,EAAOY,cACIsE,wBACtBC,EAAUC,OAAOD,SAAWC,OAAOC,YACnCC,EAAUF,OAAOE,SAAWF,OAAOG,YAGnC3B,EAAO5D,EAAO6D,UACd2B,EAAMxF,EAAOyF,kBACbtD,EAAWlC,EAAekC,SAAW,EACrCuD,EAAWvD,GAAWlC,EAAO0F,QAAU,GAAK/B,EAC5CgC,EAAWzD,GAAWlC,EAAO4F,QAAU,GAAKjC,EAI5CkC,EAAcC,EAAe,CAAEC,EAAGpB,EAAQqB,GAAGD,EAAGE,EAAGtB,EAAQqB,GAAGC,GAAKV,GAEnEhE,EAAOyD,EAAWzD,KAAO2D,EAAUW,EAAYE,EAC/CvE,EAAMwD,EAAWxD,IAAM6D,EAAUQ,EAAYI,EAG7CnC,EAAS9D,EAAe8D,OAAS9D,EAAO0F,QAAU,GAAK/B,EACvDK,EAAShE,EAAOgE,QAAUhE,EAAO4F,QAAU,GAAKjC,EAEtDiB,QAAQC,IAAI,sBACZD,QAAQC,IAAI,mBAAqB7E,EAAe8D,OAChDc,QAAQC,IAAI,kBAAmB7E,EAAO8E,kBACtCF,QAAQC,IAAI,WAAYlB,GACxBiB,QAAQC,IAAI,kBAAmBf,GAG/BnF,KAAKqC,QAAQF,MAAMC,SAAW,WAC9BpC,KAAKqC,QAAQF,MAAMS,KAAO,GAAGA,MAC7B5C,KAAKqC,QAAQF,MAAMU,IAAM,GAAGA,MAC5B7C,KAAKqC,QAAQF,MAAMgD,MAAQ,GAAGA,MAC9BnF,KAAKqC,QAAQF,MAAMkD,OAAS,GAAGA,MAC/BrF,KAAKqC,QAAQF,MAAMuB,SAAW,SAE1BrC,EAAOkG,OACTvH,KAAKqC,QAAQF,MAAMqF,UAAY,UAAUnG,EAAOkG,YAChDvH,KAAKqC,QAAQF,MAAMO,gBAAkB,aAErC1C,KAAKqC,QAAQF,MAAMqF,UAAY,GAC/BxH,KAAKqC,QAAQF,MAAMO,gBAAkB,IAIvC,MAAM+E,EAA+B,QAAnB3B,EAAIzE,EAAOuE,gBAAQ,IAAAE,EAAAA,EAAI,GAEnCiB,EAAS1F,EAAO0F,QAAU,EAC1BW,EAAgBD,EAAeV,EAAS/B,EACxC2C,EAAmBtG,EAAOuG,YAAc,KAExCC,EAAgBf,EAAW,EAAI,eAAe,EAAIA,OAAgB,OAClEgB,EAAiBd,EAAW,EAAI,eAAe,EAAIA,OAAgB,OAEzEhH,KAAK2C,SAASR,MAAMgD,MAAQ0C,EAC5B7H,KAAK2C,SAASR,MAAMkD,OAASyC,EAC7B9H,KAAK2C,SAASR,MAAMoB,QAAU,GAAGyD,OAAcF,MAE/C9G,KAAK2C,SAASR,MAAMyD,SAAW,GAAG8B,MAClC1H,KAAK2C,SAASR,MAAMyF,WAAaG,OAAOJ,GACxC3H,KAAK2C,SAASR,MAAM6F,WAAa3G,EAAO2G,YAAc,QACtDhI,KAAK2C,SAASR,MAAM8F,WAAaF,OAAO1G,EAAO4G,YAAc,UAC7DjI,KAAK2C,SAASR,MAAM+F,UAAY7G,EAAO6G,WAAa,SACpDlI,KAAK2C,SAASR,MAAMgG,UAAa9G,EAAe8G,WAAa,OAC7DnI,KAAK2C,SAASR,MAAMiG,OAAmB,QAAXrC,EAAA1E,EAAOgH,YAAI,IAAAtC,OAAA,EAAXA,EAAauC,aAAc,OACvDtI,KAAK2C,SAASR,MAAMoG,eAAqBlH,EAAOsE,aAAe,GAAK,IAAhC,KACpC3F,KAAK2C,SAASR,MAAMgB,UAAa9B,EAAe8B,WAAanD,KAAK6F,eAAe7F,KAAK2C,SAASsB,OAAS,IAGxGjE,KAAK2C,SAASR,MAAMqG,YAAc,SAClCxI,KAAK2C,SAASR,MAAMsG,YAAc,SAClCzI,KAAK2C,SAASR,MAAMuG,cAAgB,OACpC1I,KAAK2C,SAASR,MAAMwG,YAAc,OAClC3I,KAAK2C,SAASR,MAAMyG,UAAY,cAChC5I,KAAK2C,SAASR,MAAMW,OAAS,IAC7B9C,KAAK2C,SAASR,MAAMmB,OAAS,OAC7BtD,KAAK2C,SAASR,MAAMsB,QAAU,OAC9BzD,KAAK2C,SAASR,MAAMqB,WAAa,cACjCxD,KAAK2C,SAASR,MAAM0G,SAAW,aAC/B7I,KAAK2C,SAASR,MAAMwB,WAAa,WAGjCsC,QAAQC,IAAI,yBACZD,QAAQC,IAAI,qBAAsBlG,KAAK2C,SAASR,MAAMgD,OACtDc,QAAQC,IAAI,sBAAuBlG,KAAK2C,SAASR,MAAMkD,QACvDY,QAAQC,IAAI,uBAAwBlG,KAAK2C,SAASR,MAAMoB,SACxD0C,QAAQC,IAAI,eAAgBY,EAAU,aAAcE,GACpDf,QAAQC,IAAI,mBAAoBuB,GAChCxB,QAAQC,IAAI,aAAca,GAC1Bd,QAAQC,IAAI,WAAYlB,GACxBiB,QAAQC,IAAI,oBAAqBwB,GACjCzB,QAAQC,IAAI,uBAAwByB,EAKtC,CAKQ5F,aAAAA,GAON/B,KAAKqB,OAAO2C,QAAU,IAGrBhE,KAAKqB,OAAeyH,UAAW,EAC/B9I,KAAKqB,OAAe0H,WAAY,EAGjC/I,KAAKqB,OAAO2H,IAAI,CACdC,aAAa,EACbC,YAAY,EACZC,YAAY,EACZC,eAAe,EACfC,eAAe,IAIjBrJ,KAAKoB,OAAOkI,gBAAgBtJ,KAAKqB,QAEjCrB,KAAKoB,OAAOqE,mBACZzF,KAAKqB,OAAOmE,YACZxF,KAAK6E,oBAIL7E,KAAK2C,SAAS4G,QACdvJ,KAAK2C,SAAS6G,kBACZxJ,KAAK2C,SAASsB,MAAMwF,OACpBzJ,KAAK2C,SAASsB,MAAMwF,QAItBzJ,KAAKoB,OAAOkI,gBAAgBtJ,KAAKqB,QACjCrB,KAAKoB,OAAOqE,kBACd,CAKO3D,OAAAA,GACD9B,KAAK+E,aACT/E,KAAK4E,gBAEP,CAKO8E,OAAAA,GAAsC,IAA9BC,IAAeC,UAAAH,OAAA,QAAAI,IAAAD,UAAA,KAAAA,UAAA,GAC5B,IAAI5J,KAAK+E,YAAT,CAsBA,GArBA/E,KAAK+E,aAAc,EAEnB/E,KAAKwE,uBAGAxE,KAAKqB,OAAeyI,kBAAoB9J,OAC1CA,KAAKqB,OAAeyI,qBAAkBD,OAGeA,IAAjD7J,KAAKqB,OAAe0I,2BACvB/J,KAAKqB,OAAO2C,QAAWhE,KAAKqB,OAAe0I,gCACnC/J,KAAKqB,OAAe0I,2BAK5B/J,KAAKqC,QAAQ2H,YACfhK,KAAKqC,QAAQ2H,WAAWC,YAAYjK,KAAKqC,SAIvCsH,IAAW3J,KAAKkK,YAAa,CAC/B,MAAMC,EAAYnK,KAAK2C,SAASsB,MAC5BjE,KAAKsB,UACPtB,KAAKsB,SAAS6I,EAElB,MAAYR,GAAU3J,KAAKuB,UACzBvB,KAAKuB,WAQP6I,WAAW,KACTpK,KAAKoB,OAAOY,cAAcG,MAAMkI,OAAS,GAEzCrK,KAAKoB,OAAOkJ,UAAUtK,KAAKoB,OAAOmJ,gBACjC,GAGHvK,KAAKoB,OAAOqE,kBA3CU,CA4CxB,CAGQvF,WAAAA,GACDF,KAAKkK,aAAelK,KAAKqB,OAAOI,OAASzB,KAAK2C,SAASsB,QAE1DjE,KAAKqB,OAAOI,KAAOzB,KAAK2C,SAASsB,MAGjCjE,KAAKwK,qBAGJxK,KAAKqB,OAAeyH,UAAW,EAC/B9I,KAAKqB,OAAe0H,WAAY,EACjC/I,KAAKoB,OAAOkI,gBAAgBtJ,KAAKqB,QACjCrB,KAAKoB,OAAOqE,mBAEhB,CAEQ+E,kBAAAA,GAEN,MAAMC,EAAYvF,WAAWsB,OAAOkE,iBAAiB1K,KAAK2C,UAAU0C,QAGpErF,KAAK2C,SAASR,MAAMkD,OAAS,OAC7B,MAAMsF,EAAe3K,KAAK2C,SAASgI,aAI7BC,EAAYtF,KAAKuF,IAAIF,EADF,EACmC,IACtDG,EAAgBxF,KAAKC,IAAIqF,EAAYH,GAAa,EAExDzK,KAAK2C,SAASR,MAAMkD,OAAS,GAAGuF,MAChC5K,KAAKqC,QAAQF,MAAMkD,OAAS,GAAGuF,MAG3BE,GACF9K,KAAK8E,oBAET,CAEQzE,aAAAA,CAAc0K,GACN,WAAVA,EAAEC,KACJD,EAAEE,iBACFjL,KAAK0J,SAAQ,KACHqB,EAAEG,SAAWH,EAAEI,UAAsB,UAAVJ,EAAEC,MACvCD,EAAEE,iBACFjL,KAAK0J,SAAQ,GAEjB,CAEQzI,WAAAA,GACN,CAGMV,UAAAA,GAEDP,KAAKkK,aACRlK,KAAK0J,SAAQ,EAEjB,CAEQjJ,sBAAAA,GACNT,KAAKkK,aAAc,CACrB,CAEQvJ,oBAAAA,GACNX,KAAKkK,aAAc,EACnBlK,KAAKE,aACP,CAEQW,iBAAAA,GACNb,KAAK8B,SACP,CAEQf,gBAAAA,GACNf,KAAK8B,SACP,CAEQX,eAAAA,CAAgB4J,GAClBA,EAAE1J,SAAWrB,KAAKqB,QACpBrB,KAAK0J,SAAQ,EAEjB,CAKQnF,4BAAAA,GAELvE,KAAKoB,OAAegK,kBAAoBpL,KAAKoB,OAAOiK,QACpDrL,KAAKoB,OAAekK,+BAAiCtL,KAAKoB,OAAOmK,qBACjEvL,KAAKoB,OAAe0I,gBAAkB9J,KAGvC,MAAMwL,EAAkBxL,KAAKoB,OAAOiK,QAAQlL,KAAKH,KAAKoB,QACtDpB,KAAKoB,OAAOiK,QAAWpH,IACrB,MAAMwH,EAASD,EAAgBvH,GAI/B,OAHKjE,KAAKoB,OAAe0I,kBAAoB9J,KAAK+E,aAChD/E,KAAK8B,UAEA2J,GAIT,MAAMC,EAA+B1L,KAAKoB,OAAOmK,qBAAqBpL,KAAKH,KAAKoB,QAChFpB,KAAKoB,OAAOmK,qBAAwB3E,IAClC,MAAM6E,EAASC,EAA6B9E,GAI5C,OAHK5G,KAAKoB,OAAe0I,kBAAoB9J,KAAK+E,aAChD/E,KAAK8B,UAEA2J,EAEX,CAKQ9G,8BAAAA,GACD3E,KAAKoB,OAAegK,oBACvBpL,KAAKoB,OAAOiK,QAAWrL,KAAKoB,OAAegK,yBACnCpL,KAAKoB,OAAegK,mBAEzBpL,KAAKoB,OAAekK,iCACvBtL,KAAKoB,OAAOmK,qBAAwBvL,KAAKoB,OAAekK,sCAChDtL,KAAKoB,OAAekK,uCAEtBtL,KAAKoB,OAAe0I,eAC9B,EAQK,SAAS6B,EACdvK,EACAC,EACAvB,GAMKuB,EAAeyI,iBACjBzI,EAAeyI,gBAAgBJ,SAAQ,GAIzCrI,EAAe0I,yBAA2B1I,EAAO2C,QAElD,MAAM4H,EAAS,IAAIhM,EAAc,CAC/BwB,SACAC,SACAC,SAAUxB,aAAO,EAAPA,EAASwB,SACnBC,SAAUzB,aAAO,EAAPA,EAASyB,WAQrB,OAFCF,EAAeyI,gBAAkB8B,EAE3BA,CACT"}
|
|
1
|
+
{"version":3,"file":"overlayEditor.min.mjs","sources":["../../../src/text/overlayEditor.ts"],"sourcesContent":["/**\r\n * Canva/Polotno-style Overlay Text Editor\r\n *\r\n * Provides seamless inline text editing using an HTML textarea overlay\r\n * that matches canvas text positioning, styling, and transformations.\r\n */\r\n\r\nimport type { Canvas } from '../canvas/Canvas';\r\nimport type { FabricText } from '../shapes/Text/Text';\r\nimport type { IText } from '../shapes/IText/IText';\r\nimport type { Textbox } from '../shapes/Textbox';\r\nimport type { TPointerEventInfo } from '../EventTypeDefs';\r\nimport type { TMat2D } from '../typedefs';\r\nimport { transformPoint } from '../util/misc/matrix';\r\n\r\nexport interface OverlayEditorOptions {\r\n canvas: Canvas;\r\n target: FabricText | IText | Textbox;\r\n onCommit?: (text: string) => void;\r\n onCancel?: () => void;\r\n}\r\n\r\nexport interface ScreenTransform {\r\n translateX: number;\r\n translateY: number;\r\n scaleX: number;\r\n scaleY: number;\r\n angle: number; // in radians\r\n}\r\n\r\nexport class OverlayEditor {\r\n private canvas: Canvas;\r\n private target: FabricText | IText | Textbox;\r\n private container: HTMLElement;\r\n private textarea: HTMLTextAreaElement;\r\n private hostDiv: HTMLDivElement;\r\n private isDestroyed = false;\r\n private isComposing = false;\r\n private lastText: string;\r\n private onCommit?: (text: string) => void;\r\n private onCancel?: () => void;\r\n\r\n // Bound event handlers for cleanup\r\n private boundHandlers = {\r\n onInput: this.handleInput.bind(this),\r\n onKeyDown: this.handleKeyDown.bind(this),\r\n onBlur: this.handleBlur.bind(this),\r\n onCompositionStart: this.handleCompositionStart.bind(this),\r\n onCompositionEnd: this.handleCompositionEnd.bind(this),\r\n onAfterRender: this.handleAfterRender.bind(this),\r\n onMouseWheel: this.handleMouseWheel.bind(this),\r\n onFocus: this.handleFocus.bind(this),\r\n onMouseDown: this.handleMouseDown.bind(this),\r\n };\r\n\r\n constructor(options: OverlayEditorOptions) {\r\n this.canvas = options.canvas;\r\n this.target = options.target;\r\n this.onCommit = options.onCommit;\r\n this.onCancel = options.onCancel;\r\n this.lastText = this.target.text || '';\r\n\r\n this.container = this.getCanvasContainer();\r\n this.createOverlayDOM();\r\n this.attachEventListeners();\r\n this.refresh();\r\n this.focusTextarea();\r\n\r\n // Note: Don't manage object cursors since IText manages all cursors in _saveEditingProps/_restoreEditingProps\r\n // The IText editing system handles hoverCursor, moveCursor, and canvas cursors properly\r\n\r\n // Note: Canvas cursors are handled by IText's _saveEditingProps/_restoreEditingProps\r\n // We don't need to save/restore them here as it would conflict with IText's restoration\r\n }\r\n\r\n /**\r\n * Get the container element for the overlay (parent of upperCanvasEl)\r\n */\r\n private getCanvasContainer(): HTMLElement {\r\n const upperCanvas = this.canvas.upperCanvasEl;\r\n const container = upperCanvas.parentElement;\r\n if (!container) {\r\n throw new Error('Canvas must be mounted in DOM to use overlay editing');\r\n }\r\n\r\n // Ensure the container is positioned for absolute overlay positioning\r\n container.style.position = 'relative';\r\n\r\n return container;\r\n }\r\n\r\n /**\r\n * Create the overlay DOM structure\r\n */\r\n private createOverlayDOM(): void {\r\n // Host div for positioning and overflow control\r\n this.hostDiv = document.createElement('div');\r\n this.hostDiv.style.position = 'absolute';\r\n this.hostDiv.style.pointerEvents = 'none';\r\n this.hostDiv.style.zIndex = '1000';\r\n this.hostDiv.style.transformOrigin = 'left top';\r\n\r\n // Textarea for actual text input\r\n this.textarea = document.createElement('textarea');\r\n this.textarea.style.position = 'absolute';\r\n this.textarea.style.left = '0';\r\n this.textarea.style.top = '0';\r\n this.textarea.style.margin = '0';\r\n this.textarea.style.resize = 'none';\r\n this.textarea.style.pointerEvents = 'auto';\r\n // Set appropriate unicodeBidi based on content and direction\r\n const hasArabicText =\r\n /[\\u0600-\\u06FF\\u0750-\\u077F\\uFB50-\\uFDFF\\uFE70-\\uFEFF]/.test(\r\n this.target.text || '',\r\n );\r\n const hasLatinText = /[a-zA-Z]/.test(this.target.text || '');\r\n const isLTRDirection = (this.target as any).direction === 'ltr';\r\n\r\n if (hasArabicText && hasLatinText && isLTRDirection) {\r\n // For mixed Arabic/Latin text in LTR mode, use embed for consistent line wrapping\r\n this.textarea.style.unicodeBidi = 'embed';\r\n } else if (hasArabicText && isLTRDirection) {\r\n // For Arabic text in LTR mode, use embed to preserve shaping while respecting direction\r\n this.textarea.style.unicodeBidi = 'embed';\r\n } else {\r\n // Default to plaintext for natural text flow\r\n this.textarea.style.unicodeBidi = 'plaintext';\r\n }\r\n this.textarea.style.caretColor = 'auto';\r\n\r\n // Polotno-like base\r\n this.textarea.style.border = 'none';\r\n this.textarea.style.padding = '0';\r\n this.textarea.style.background = 'transparent'; // Transparent so Fabric text shows through\r\n this.textarea.style.outline = 'none';\r\n this.textarea.style.overflow = 'hidden'; // Prevent scrollbars\r\n this.textarea.style.whiteSpace = 'pre-wrap';\r\n this.textarea.style.wordBreak = 'normal';\r\n this.textarea.style.overflowWrap = 'break-word';\r\n this.textarea.style.userSelect = 'text';\r\n this.textarea.style.textTransform = 'none';\r\n\r\n // Start visible - we'll handle transitions differently\r\n this.textarea.style.opacity = '1';\r\n\r\n // Set initial text\r\n this.textarea.value = this.target.text || '';\r\n\r\n this.hostDiv.appendChild(this.textarea);\r\n document.body.appendChild(this.hostDiv);\r\n }\r\n\r\n /**\r\n * Attach all event listeners\r\n */\r\n private attachEventListeners(): void {\r\n // Textarea events\r\n this.textarea.addEventListener('input', this.boundHandlers.onInput);\r\n this.textarea.addEventListener('keydown', this.boundHandlers.onKeyDown);\r\n this.textarea.addEventListener('blur', this.boundHandlers.onBlur);\r\n this.textarea.addEventListener(\r\n 'compositionstart',\r\n this.boundHandlers.onCompositionStart,\r\n );\r\n this.textarea.addEventListener(\r\n 'compositionend',\r\n this.boundHandlers.onCompositionEnd,\r\n );\r\n this.textarea.addEventListener('focus', this.boundHandlers.onFocus);\r\n\r\n // Canvas events for synchronization\r\n this.canvas.on('after:render', this.boundHandlers.onAfterRender);\r\n this.canvas.on('mouse:wheel', this.boundHandlers.onMouseWheel);\r\n this.canvas.on('mouse:down', this.boundHandlers.onMouseDown);\r\n\r\n // Store original methods to detect viewport changes\r\n this.setupViewportChangeDetection();\r\n }\r\n\r\n /**\r\n * Remove all event listeners\r\n */\r\n private removeEventListeners(): void {\r\n this.textarea.removeEventListener('input', this.boundHandlers.onInput);\r\n this.textarea.removeEventListener('keydown', this.boundHandlers.onKeyDown);\r\n this.textarea.removeEventListener('blur', this.boundHandlers.onBlur);\r\n this.textarea.removeEventListener(\r\n 'compositionstart',\r\n this.boundHandlers.onCompositionStart,\r\n );\r\n this.textarea.removeEventListener(\r\n 'compositionend',\r\n this.boundHandlers.onCompositionEnd,\r\n );\r\n this.textarea.removeEventListener('focus', this.boundHandlers.onFocus);\r\n\r\n this.canvas.off('after:render', this.boundHandlers.onAfterRender);\r\n this.canvas.off('mouse:wheel', this.boundHandlers.onMouseWheel);\r\n this.canvas.off('mouse:down', this.boundHandlers.onMouseDown);\r\n\r\n // Restore original methods\r\n this.restoreViewportChangeDetection();\r\n }\r\n\r\n /**\r\n * Simple method to refresh positioning when canvas changes\r\n */\r\n private updatePosition(): void {\r\n this.applyOverlayStyle();\r\n }\r\n\r\n /**\r\n * Update the Fabric object bounds to match current textarea size\r\n * This ensures Fabric.js selection controls follow the growing textbox\r\n */\r\n private updateObjectBounds(): void {\r\n if (this.isDestroyed) return;\r\n\r\n const target = this.target;\r\n const zoom = this.canvas.getZoom();\r\n\r\n // Get current textbox dimensions from the host div (in canvas coordinates)\r\n const currentWidth = parseFloat(this.hostDiv.style.width) / zoom;\r\n const currentHeight = parseFloat(this.hostDiv.style.height) / zoom;\r\n\r\n // Always update height for responsive controls (especially important for line deletion)\r\n const heightDiff = Math.abs(currentHeight - target.height);\r\n const threshold = 0.5; // Lower threshold for better responsiveness to line changes\r\n\r\n if (heightDiff > threshold) {\r\n const oldHeight = target.height;\r\n target.height = currentHeight;\r\n target.setCoords(); // Update control positions\r\n\r\n // Force dirty to ensure proper re-rendering\r\n target.dirty = true;\r\n this.canvas.requestRenderAll(); // Re-render to show updated selection\r\n\r\n // IMPORTANT: Reposition overlay after height change\r\n requestAnimationFrame(() => {\r\n if (!this.isDestroyed) {\r\n this.applyOverlayStyle();\r\n console.log(\r\n '📐 Height changed - rechecking alignment after repositioning:',\r\n );\r\n }\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Convert Fabric charSpacing (1/1000 em) to CSS letter-spacing (px)\r\n */\r\n private letterSpacingPx(charSpacing: number, fontSize: number): number {\r\n return (charSpacing / 1000) * fontSize;\r\n }\r\n\r\n /**\r\n * Detect text direction using first strong directional character\r\n */\r\n private firstStrongDir(text: string): 'ltr' | 'rtl' {\r\n // Hebrew: \\u0590-\\u05FF, Arabic: \\u0600-\\u06FF, \\u0750-\\u077F, \\uFB50-\\uFDFF, \\uFE70-\\uFEFF\r\n const rtlRegex =\r\n /[\\u0590-\\u05FF\\u0600-\\u06FF\\u0750-\\u077F\\uFB50-\\uFDFF\\uFE70-\\uFEFF]/;\r\n return rtlRegex.test(text) ? 'rtl' : 'ltr';\r\n }\r\n\r\n private applyOverlayStyle(): void {\r\n const target = this.target;\r\n const canvas = this.canvas;\r\n\r\n // 1. Freshen object's transformations - use aCoords like rtl-test.html\r\n target.setCoords();\r\n const aCoords = target.aCoords;\r\n\r\n // 2. Get canvas position and scroll offsets (like rtl-test.html)\r\n const canvasEl = canvas.upperCanvasEl;\r\n const canvasRect = canvasEl.getBoundingClientRect();\r\n const scrollX = window.scrollX || window.pageXOffset;\r\n const scrollY = window.scrollY || window.pageYOffset;\r\n\r\n // 3. Position and dimensions accounting for Fabric Textbox padding and viewport transform\r\n const zoom = canvas.getZoom();\r\n const vpt = canvas.viewportTransform;\r\n const padding = (target as any).padding || 0;\r\n const paddingX = padding * (target.scaleX || 1) * zoom;\r\n const paddingY = padding * (target.scaleY || 1) * zoom;\r\n\r\n // Transform object's top-left corner coordinates to screen coordinates using viewport transform\r\n // aCoords.tl already accounts for object positioning and scaling, just need viewport transform\r\n const screenPoint = transformPoint(\r\n { x: aCoords.tl.x, y: aCoords.tl.y },\r\n vpt,\r\n );\r\n\r\n const left = canvasRect.left + scrollX + screenPoint.x;\r\n const top = canvasRect.top + scrollY + screenPoint.y;\r\n\r\n // 4. Calculate the precise width and height for the container\r\n // **THE FIX:** Use getBoundingRect() for BOTH width and height.\r\n // This is the most reliable measure of the object's final rendered dimensions.\r\n const objectBounds = target.getBoundingRect();\r\n const width = Math.round(objectBounds.width * zoom);\r\n const height = Math.round(objectBounds.height * zoom);\r\n\r\n // 5. Apply styles to host DIV - absolute positioning like rtl-test.html\r\n this.hostDiv.style.position = 'absolute';\r\n this.hostDiv.style.left = `${left}px`;\r\n this.hostDiv.style.top = `${top}px`;\r\n this.hostDiv.style.width = `${width}px`;\r\n this.hostDiv.style.height = `${height}px`;\r\n this.hostDiv.style.overflow = 'hidden'; // Prevent scrollbars in host div\r\n // Apply rotation matching Fabric.js object transformation\r\n if (target.angle) {\r\n this.hostDiv.style.transform = `rotate(${target.angle}deg)`;\r\n this.hostDiv.style.transformOrigin = 'top left'; // Match Fabric Textbox behavior\r\n } else {\r\n this.hostDiv.style.transform = '';\r\n this.hostDiv.style.transformOrigin = '';\r\n }\r\n\r\n // 6. Style the textarea - match Fabric's exact rendering with padding\r\n const baseFontSize = target.fontSize ?? 16;\r\n // Use scaleX for font scaling to match Fabric text scaling exactly\r\n const scaleX = target.scaleX || 1;\r\n const finalFontSize = baseFontSize * scaleX * zoom;\r\n const fabricLineHeight = target.lineHeight || 1.16;\r\n // **THE FIX:** Use 'border-box' so the width property includes padding.\r\n // This makes alignment much easier and more reliable.\r\n this.textarea.style.boxSizing = 'border-box';\r\n\r\n // **THE FIX:** Set the textarea width to be IDENTICAL to the host div's width.\r\n // The padding will now be correctly contained *inside* this width.\r\n this.textarea.style.width = `${width}px`;\r\n this.textarea.style.height = '100%'; // Let hostDiv control height\r\n this.textarea.style.padding = `${paddingY}px ${paddingX}px`;\r\n\r\n // Apply all other font and text styles to match Fabric\r\n const letterSpacingPx = ((target.charSpacing || 0) / 1000) * finalFontSize;\r\n\r\n this.textarea.style.fontSize = `${finalFontSize}px`;\r\n this.textarea.style.lineHeight = String(fabricLineHeight);\r\n this.textarea.style.fontFamily = target.fontFamily || 'Arial';\r\n this.textarea.style.fontWeight = String(target.fontWeight || 'normal');\r\n this.textarea.style.fontStyle = target.fontStyle || 'normal';\r\n this.textarea.style.textAlign = (target as any).textAlign || 'left';\r\n this.textarea.style.color = target.fill?.toString() || '#000';\r\n this.textarea.style.letterSpacing = `${letterSpacingPx}px`;\r\n this.textarea.style.direction =\r\n (target as any).direction ||\r\n this.firstStrongDir(this.textarea.value || '');\r\n this.textarea.style.fontVariant = 'normal';\r\n this.textarea.style.fontStretch = 'normal';\r\n this.textarea.style.textRendering = 'optimizeLegibility';\r\n this.textarea.style.fontKerning = 'normal';\r\n this.textarea.style.fontFeatureSettings = 'normal';\r\n this.textarea.style.fontVariationSettings = 'normal';\r\n this.textarea.style.margin = '0';\r\n this.textarea.style.border = 'none';\r\n this.textarea.style.outline = 'none';\r\n this.textarea.style.background = 'transparent';\r\n this.textarea.style.overflowWrap = 'break-word';\r\n this.textarea.style.whiteSpace = 'pre-wrap';\r\n this.textarea.style.hyphens = 'none';\r\n \r\n (this.textarea.style as any).webkitFontSmoothing = 'antialiased';\r\n (this.textarea.style as any).mozOsxFontSmoothing = 'grayscale';\r\n\r\n // Debug: Compare textarea and canvas object bounding boxes\r\n this.debugBoundingBoxComparison();\r\n\r\n // Debug: Compare text wrapping behavior\r\n this.debugTextWrapping();\r\n\r\n // Initial bounds are set correctly by Fabric.js - don't force update here\r\n }\r\n\r\n /**\r\n * Debug method to compare textarea and canvas object bounding boxes\r\n */\r\n private debugBoundingBoxComparison(): void {\r\n const target = this.target;\r\n const canvas = this.canvas;\r\n const zoom = canvas.getZoom();\r\n\r\n // Get textarea bounding box (in screen coordinates)\r\n const textareaRect = this.textarea.getBoundingClientRect();\r\n const hostRect = this.hostDiv.getBoundingClientRect();\r\n\r\n // Get canvas object bounding box (in screen coordinates)\r\n const canvasBounds = target.getBoundingRect();\r\n const canvasRect = canvas.upperCanvasEl.getBoundingClientRect();\r\n\r\n // Convert canvas object bounds to screen coordinates\r\n const vpt = canvas.viewportTransform;\r\n const screenObjectBounds = {\r\n left: canvasRect.left + canvasBounds.left * zoom + vpt[4],\r\n top: canvasRect.top + canvasBounds.top * zoom + vpt[5],\r\n width: canvasBounds.width * zoom,\r\n height: canvasBounds.height * zoom,\r\n };\r\n\r\n console.log('🔍 BOUNDING BOX COMPARISON:');\r\n console.log('📦 Textarea Rect:', {\r\n left: Math.round(textareaRect.left * 100) / 100,\r\n top: Math.round(textareaRect.top * 100) / 100,\r\n width: Math.round(textareaRect.width * 100) / 100,\r\n height: Math.round(textareaRect.height * 100) / 100,\r\n });\r\n console.log('📦 Host Div Rect:', {\r\n left: Math.round(hostRect.left * 100) / 100,\r\n top: Math.round(hostRect.top * 100) / 100,\r\n width: Math.round(hostRect.width * 100) / 100,\r\n height: Math.round(hostRect.height * 100) / 100,\r\n });\r\n console.log('📦 Canvas Object Bounds (screen):', {\r\n left: Math.round(screenObjectBounds.left * 100) / 100,\r\n top: Math.round(screenObjectBounds.top * 100) / 100,\r\n width: Math.round(screenObjectBounds.width * 100) / 100,\r\n height: Math.round(screenObjectBounds.height * 100) / 100,\r\n });\r\n console.log('📦 Canvas Object Bounds (canvas):', canvasBounds);\r\n\r\n // Calculate differences\r\n const hostVsObject = {\r\n leftDiff:\r\n Math.round((hostRect.left - screenObjectBounds.left) * 100) / 100,\r\n topDiff: Math.round((hostRect.top - screenObjectBounds.top) * 100) / 100,\r\n widthDiff:\r\n Math.round((hostRect.width - screenObjectBounds.width) * 100) / 100,\r\n heightDiff:\r\n Math.round((hostRect.height - screenObjectBounds.height) * 100) / 100,\r\n };\r\n\r\n const textareaVsObject = {\r\n leftDiff:\r\n Math.round((textareaRect.left - screenObjectBounds.left) * 100) / 100,\r\n topDiff:\r\n Math.round((textareaRect.top - screenObjectBounds.top) * 100) / 100,\r\n widthDiff:\r\n Math.round((textareaRect.width - screenObjectBounds.width) * 100) / 100,\r\n heightDiff:\r\n Math.round((textareaRect.height - screenObjectBounds.height) * 100) /\r\n 100,\r\n };\r\n\r\n console.log('📏 Host Div vs Canvas Object Diff:', hostVsObject);\r\n console.log('📏 Textarea vs Canvas Object Diff:', textareaVsObject);\r\n\r\n // Check if they're aligned (within 2px tolerance)\r\n const tolerance = 2;\r\n const hostAligned =\r\n Math.abs(hostVsObject.leftDiff) < tolerance &&\r\n Math.abs(hostVsObject.topDiff) < tolerance &&\r\n Math.abs(hostVsObject.widthDiff) < tolerance &&\r\n Math.abs(hostVsObject.heightDiff) < tolerance;\r\n\r\n const textareaAligned =\r\n Math.abs(textareaVsObject.leftDiff) < tolerance &&\r\n Math.abs(textareaVsObject.topDiff) < tolerance &&\r\n Math.abs(textareaVsObject.widthDiff) < tolerance &&\r\n Math.abs(textareaVsObject.heightDiff) < tolerance;\r\n\r\n console.log(\r\n hostAligned\r\n ? '✅ Host Div ALIGNED with canvas object'\r\n : '❌ Host Div MISALIGNED with canvas object',\r\n );\r\n console.log(\r\n textareaAligned\r\n ? '✅ Textarea ALIGNED with canvas object'\r\n : '❌ Textarea MISALIGNED with canvas object',\r\n );\r\n console.log('🔍 Zoom:', zoom, 'Viewport Transform:', vpt);\r\n console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');\r\n }\r\n\r\n /**\r\n * Debug method to compare text wrapping between textarea and Fabric text object\r\n */\r\n private debugTextWrapping(): void {\r\n const target = this.target;\r\n const text = this.textarea.value;\r\n\r\n console.log('📝 TEXT WRAPPING COMPARISON:');\r\n console.log('📄 Text Content:', `\"${text}\"`);\r\n console.log('📄 Text Length:', text.length);\r\n\r\n // Analyze line breaks\r\n const explicitLines = text.split('\\n');\r\n console.log('📄 Explicit Lines (\\\\n):', explicitLines.length);\r\n explicitLines.forEach((line, i) => {\r\n console.log(` Line ${i + 1}: \"${line}\" (${line.length} chars)`);\r\n });\r\n\r\n // Get textarea computed styles for wrapping analysis\r\n const textareaStyles = window.getComputedStyle(this.textarea);\r\n console.log('📐 Textarea Wrapping Styles:');\r\n console.log(' width:', textareaStyles.width);\r\n console.log(' fontSize:', textareaStyles.fontSize);\r\n console.log(' fontFamily:', textareaStyles.fontFamily);\r\n console.log(' fontWeight:', textareaStyles.fontWeight);\r\n console.log(' letterSpacing:', textareaStyles.letterSpacing);\r\n console.log(' lineHeight:', textareaStyles.lineHeight);\r\n console.log(' whiteSpace:', textareaStyles.whiteSpace);\r\n console.log(' wordWrap:', textareaStyles.wordWrap);\r\n console.log(' overflowWrap:', textareaStyles.overflowWrap);\r\n console.log(' direction:', textareaStyles.direction);\r\n console.log(' textAlign:', textareaStyles.textAlign);\r\n\r\n // Get Fabric text object properties for comparison\r\n console.log('📐 Fabric Text Object Properties:');\r\n console.log(' width:', (target as any).width);\r\n console.log(' fontSize:', target.fontSize);\r\n console.log(' fontFamily:', target.fontFamily);\r\n console.log(' fontWeight:', target.fontWeight);\r\n console.log(' charSpacing:', target.charSpacing);\r\n console.log(' lineHeight:', target.lineHeight);\r\n console.log(' direction:', (target as any).direction);\r\n console.log(' textAlign:', (target as any).textAlign);\r\n console.log(' scaleX:', target.scaleX);\r\n console.log(' scaleY:', target.scaleY);\r\n\r\n // Calculate effective dimensions for comparison - use actual rendered width\r\n // **THE FIX:** Use getBoundingRect to get the *actual rendered width* of the Fabric object.\r\n const fabricEffectiveWidth = this.target.getBoundingRect().width;\r\n // Use the exact width set on textarea for comparison\r\n const textareaComputedWidth = parseFloat(\r\n window.getComputedStyle(this.textarea).width,\r\n );\r\n const textareaEffectiveWidth =\r\n textareaComputedWidth / this.canvas.getZoom();\r\n const widthDiff = Math.abs(textareaEffectiveWidth - fabricEffectiveWidth);\r\n\r\n console.log('📏 Effective Width Comparison:');\r\n console.log(' Textarea Effective Width:', textareaEffectiveWidth);\r\n console.log(' Fabric Effective Width:', fabricEffectiveWidth);\r\n console.log(' Width Difference:', widthDiff.toFixed(2) + 'px');\r\n console.log(\r\n widthDiff < 1\r\n ? '✅ Widths MATCH for wrapping'\r\n : '❌ Width MISMATCH may cause different wrapping',\r\n );\r\n\r\n // Check text direction and bidi handling\r\n const hasRTLText =\r\n /[\\u0590-\\u05FF\\u0600-\\u06FF\\u0750-\\u077F\\uFB50-\\uFDFF\\uFE70-\\uFEFF]/.test(\r\n text,\r\n );\r\n const hasBidiText = /[\\u0590-\\u06FF]/.test(text) && /[a-zA-Z]/.test(text);\r\n\r\n console.log('🌍 Text Direction Analysis:');\r\n console.log(' Has RTL characters:', hasRTLText);\r\n console.log(' Has mixed Bidi text:', hasBidiText);\r\n console.log(' Textarea direction:', textareaStyles.direction);\r\n console.log(' Fabric direction:', (target as any).direction || 'auto');\r\n console.log(' Textarea unicodeBidi:', textareaStyles.unicodeBidi);\r\n\r\n // Measure actual rendered line count\r\n const textareaScrollHeight = this.textarea.scrollHeight;\r\n const textareaLineHeight =\r\n parseFloat(textareaStyles.lineHeight) ||\r\n parseFloat(textareaStyles.fontSize) * 1.2;\r\n const estimatedTextareaLines = Math.round(\r\n textareaScrollHeight / textareaLineHeight,\r\n );\r\n\r\n console.log('📊 Line Count Analysis:');\r\n console.log(' Textarea scrollHeight:', textareaScrollHeight);\r\n console.log(' Textarea lineHeight:', textareaLineHeight);\r\n console.log(' Estimated rendered lines:', estimatedTextareaLines);\r\n console.log(' Explicit line breaks:', explicitLines.length);\r\n\r\n if (estimatedTextareaLines > explicitLines.length) {\r\n console.log('🔄 Text wrapping detected in textarea');\r\n console.log(\r\n ' Wrapped lines:',\r\n estimatedTextareaLines - explicitLines.length,\r\n );\r\n } else {\r\n console.log('📏 No text wrapping in textarea');\r\n }\r\n\r\n console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');\r\n }\r\n\r\n\r\n /**\r\n * Focus the textarea and position cursor at end\r\n */\r\n private focusTextarea(): void {\r\n // For overlay editing, we want to keep the object in \"selection mode\" not \"editing mode\"\r\n // This means keeping selected=true and isEditing=false to show boundaries\r\n\r\n // Hide the text content only (not the entire object)\r\n this.target.opacity = 0.01; // Nearly transparent but not fully hidden\r\n\r\n // Ensure object stays selected to show boundaries\r\n (this.target as any).selected = true;\r\n (this.target as any).isEditing = false; // Override any editing state\r\n\r\n // Make sure controls are enabled and movement is allowed during overlay editing\r\n this.target.set({\r\n hasControls: true,\r\n hasBorders: true,\r\n selectable: true,\r\n lockMovementX: false,\r\n lockMovementY: false,\r\n });\r\n\r\n // Keep as active object\r\n this.canvas.setActiveObject(this.target);\r\n\r\n this.canvas.requestRenderAll();\r\n this.target.setCoords();\r\n this.applyOverlayStyle();\r\n\r\n this.textarea.focus();\r\n\r\n this.textarea.setSelectionRange(\r\n this.textarea.value.length,\r\n this.textarea.value.length,\r\n );\r\n\r\n // Ensure the object stays selected even after textarea focus\r\n this.canvas.setActiveObject(this.target);\r\n this.canvas.requestRenderAll();\r\n }\r\n\r\n /**\r\n * Refresh overlay positioning and styling\r\n */\r\n public refresh(): void {\r\n if (this.isDestroyed) return;\r\n this.updatePosition();\r\n // Don't update object bounds on every refresh - only when textarea actually resizes\r\n }\r\n\r\n /**\r\n * Destroy the overlay editor\r\n */\r\n public destroy(commit: boolean = true): void {\r\n if (this.isDestroyed) return;\r\n this.isDestroyed = true;\r\n\r\n this.removeEventListeners();\r\n\r\n // Restore target visibility before handling commit/cancel\r\n if ((this.target as any).__overlayEditor === this) {\r\n (this.target as any).__overlayEditor = undefined;\r\n\r\n // Restore original opacity\r\n if ((this.target as any).__overlayOriginalOpacity !== undefined) {\r\n this.target.opacity = (this.target as any).__overlayOriginalOpacity;\r\n delete (this.target as any).__overlayOriginalOpacity;\r\n }\r\n }\r\n\r\n // Remove DOM first\r\n if (this.hostDiv.parentNode) {\r\n this.hostDiv.parentNode.removeChild(this.hostDiv);\r\n }\r\n\r\n // Handle commit/cancel after restoring visibility\r\n if (commit && !this.isComposing) {\r\n const finalText = this.textarea.value;\r\n if (this.onCommit) {\r\n this.onCommit(finalText);\r\n }\r\n } else if (!commit && this.onCancel) {\r\n this.onCancel();\r\n }\r\n\r\n // Note: Don't restore object cursors since IText manages all cursors in _restoreEditingProps\r\n // Let the IText editing system handle proper restoration of all cursor properties\r\n\r\n // Note: Canvas cursors are restored by IText's _restoreEditingProps method\r\n // Force a cursor refresh by triggering _setCursorFromEvent\r\n setTimeout(() => {\r\n this.canvas.upperCanvasEl.style.cursor = '';\r\n // Trigger cursor refresh on next mouse move\r\n this.canvas.setCursor(this.canvas.defaultCursor);\r\n }, 0);\r\n\r\n // Request canvas re-render\r\n this.canvas.requestRenderAll();\r\n }\r\n\r\n // Event handlers\r\n private handleInput(): void {\r\n if (!this.isComposing && this.target.text !== this.textarea.value) {\r\n // Live update target text\r\n this.target.text = this.textarea.value;\r\n\r\n\r\n // Auto-resize textarea to match new content\r\n this.autoResizeTextarea();\r\n\r\n // Ensure object stays in selection mode (not editing mode) to show controls\r\n (this.target as any).selected = true;\r\n (this.target as any).isEditing = false;\r\n this.canvas.setActiveObject(this.target);\r\n this.canvas.requestRenderAll();\r\n }\r\n }\r\n\r\n private autoResizeTextarea(): void {\r\n // Store the scroll position and the container's old height for comparison.\r\n const scrollTop = this.textarea.scrollTop;\r\n const oldHeight = parseFloat(this.hostDiv.style.height || '0');\r\n\r\n // 1. **Force a reliable reflow.**\r\n // First, reset the textarea's height to a minimal value. This is the crucial step\r\n // that forces the browser to recalculate the content's height from scratch,\r\n // ignoring the hostDiv's larger, stale height.\r\n this.textarea.style.height = '1px';\r\n\r\n // 2. Read the now-accurate scrollHeight. This value reflects the minimum\r\n // height required for the content, whether it's single or multi-line.\r\n const scrollHeight = this.textarea.scrollHeight;\r\n\r\n // A small buffer for rendering consistency across browsers.\r\n const buffer = 2;\r\n const newHeight = scrollHeight + buffer;\r\n\r\n // Check if the height has changed significantly.\r\n const heightChanged = Math.abs(newHeight - oldHeight) > 1;\r\n\r\n // 4. Only update heights and object bounds if there was a change.\r\n if (heightChanged) {\r\n this.textarea.style.height = `${newHeight}px`;\r\n this.hostDiv.style.height = `${newHeight}px`;\r\n this.updateObjectBounds();\r\n } else {\r\n // If no significant change, ensure the textarea's height matches the container\r\n // to prevent any minor visual misalignment.\r\n this.textarea.style.height = this.hostDiv.style.height;\r\n }\r\n\r\n // 5. Restore the original scroll position.\r\n this.textarea.scrollTop = scrollTop;\r\n }\r\n\r\n private handleKeyDown(e: KeyboardEvent): void {\r\n if (e.key === 'Escape') {\r\n e.preventDefault();\r\n this.destroy(false); // Cancel\r\n } else if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {\r\n e.preventDefault();\r\n this.destroy(true); // Commit\r\n } else if (\r\n e.key === 'Enter' ||\r\n e.key === 'Backspace' ||\r\n e.key === 'Delete'\r\n ) {\r\n // For keys that might change the height, schedule a resize check\r\n // Use both immediate and delayed checks to catch all scenarios\r\n requestAnimationFrame(() => {\r\n if (!this.isDestroyed) {\r\n this.autoResizeTextarea();\r\n }\r\n });\r\n setTimeout(() => {\r\n if (!this.isDestroyed) {\r\n this.autoResizeTextarea();\r\n }\r\n }, 10); // Small delay to ensure DOM is updated\r\n }\r\n }\r\n\r\n private handleFocus(): void {\r\n // Focus handler - could be used for future enhancements\r\n }\r\n\r\n private handleBlur(): void {\r\n // Commit on blur unless we're in composition mode\r\n if (!this.isComposing) {\r\n this.destroy(true);\r\n }\r\n }\r\n\r\n private handleCompositionStart(): void {\r\n this.isComposing = true;\r\n }\r\n\r\n private handleCompositionEnd(): void {\r\n this.isComposing = false;\r\n this.handleInput(); // Update text after composition\r\n }\r\n\r\n private handleAfterRender(): void {\r\n this.refresh();\r\n }\r\n\r\n private handleMouseWheel(): void {\r\n this.refresh();\r\n }\r\n\r\n private handleMouseDown(e: TPointerEventInfo): void {\r\n if (e.target !== this.target) {\r\n this.destroy(true);\r\n }\r\n }\r\n\r\n /**\r\n * Setup detection for viewport changes (zoom/pan)\r\n */\r\n private setupViewportChangeDetection(): void {\r\n // Store original methods\r\n (this.canvas as any).__originalSetZoom = this.canvas.setZoom;\r\n (this.canvas as any).__originalSetViewportTransform =\r\n this.canvas.setViewportTransform;\r\n (this.canvas as any).__overlayEditor = this;\r\n\r\n // Override setZoom to detect zoom changes\r\n const originalSetZoom = this.canvas.setZoom.bind(this.canvas);\r\n this.canvas.setZoom = (value: number) => {\r\n const result = originalSetZoom(value);\r\n if ((this.canvas as any).__overlayEditor && !this.isDestroyed) {\r\n this.refresh();\r\n }\r\n return result;\r\n };\r\n\r\n // Override setViewportTransform to detect pan changes\r\n const originalSetViewportTransform = this.canvas.setViewportTransform.bind(\r\n this.canvas,\r\n );\r\n this.canvas.setViewportTransform = (vpt: TMat2D) => {\r\n const result = originalSetViewportTransform(vpt);\r\n if ((this.canvas as any).__overlayEditor && !this.isDestroyed) {\r\n this.refresh();\r\n }\r\n return result;\r\n };\r\n }\r\n\r\n /**\r\n * Restore original viewport methods\r\n */\r\n private restoreViewportChangeDetection(): void {\r\n if ((this.canvas as any).__originalSetZoom) {\r\n this.canvas.setZoom = (this.canvas as any).__originalSetZoom;\r\n delete (this.canvas as any).__originalSetZoom;\r\n }\r\n if ((this.canvas as any).__originalSetViewportTransform) {\r\n this.canvas.setViewportTransform = (\r\n this.canvas as any\r\n ).__originalSetViewportTransform;\r\n delete (this.canvas as any).__originalSetViewportTransform;\r\n }\r\n delete (this.canvas as any).__overlayEditor;\r\n }\r\n}\r\n\r\n/**\r\n * Enter overlay text editing mode for a text object\r\n */\r\nexport function enterTextOverlayEdit(\r\n canvas: Canvas,\r\n target: FabricText | IText | Textbox,\r\n options?: {\r\n onCommit?: (text: string) => void;\r\n onCancel?: () => void;\r\n },\r\n): OverlayEditor {\r\n // If already in overlay editing, destroy existing editor first\r\n if ((target as any).__overlayEditor) {\r\n (target as any).__overlayEditor.destroy(false);\r\n }\r\n\r\n // Store original opacity so we can restore it later\r\n (target as any).__overlayOriginalOpacity = target.opacity;\r\n\r\n const editor = new OverlayEditor({\r\n canvas,\r\n target,\r\n onCommit: options?.onCommit,\r\n onCancel: options?.onCancel,\r\n });\r\n\r\n // We no longer change fill, so no need to store it\r\n\r\n // Store reference on target for cleanup\r\n (target as any).__overlayEditor = editor;\r\n\r\n return editor;\r\n}\r\n\r\n/**\r\n * Check if a text object is currently being edited with overlay editor\r\n */\r\nexport function isInOverlayEdit(target: FabricText | IText | Textbox): boolean {\r\n return !!(target as any).__overlayEditor?.isActive;\r\n}\r\n"],"names":["OverlayEditor","constructor","options","_defineProperty","this","onInput","handleInput","bind","onKeyDown","handleKeyDown","onBlur","handleBlur","onCompositionStart","handleCompositionStart","onCompositionEnd","handleCompositionEnd","onAfterRender","handleAfterRender","onMouseWheel","handleMouseWheel","onFocus","handleFocus","onMouseDown","handleMouseDown","canvas","target","onCommit","onCancel","lastText","text","container","getCanvasContainer","createOverlayDOM","attachEventListeners","refresh","focusTextarea","upperCanvasEl","parentElement","Error","style","position","hostDiv","document","createElement","pointerEvents","zIndex","transformOrigin","textarea","left","top","margin","resize","hasArabicText","test","hasLatinText","isLTRDirection","direction","unicodeBidi","caretColor","border","padding","background","outline","overflow","whiteSpace","wordBreak","overflowWrap","userSelect","textTransform","opacity","value","appendChild","body","addEventListener","boundHandlers","on","setupViewportChangeDetection","removeEventListeners","removeEventListener","off","restoreViewportChangeDetection","updatePosition","applyOverlayStyle","updateObjectBounds","isDestroyed","zoom","getZoom","parseFloat","width","currentHeight","height","Math","abs","setCoords","dirty","requestRenderAll","requestAnimationFrame","console","log","letterSpacingPx","charSpacing","fontSize","firstStrongDir","_target$fontSize","_target$fill","aCoords","canvasRect","getBoundingClientRect","scrollX","window","pageXOffset","scrollY","pageYOffset","vpt","viewportTransform","paddingX","scaleX","paddingY","scaleY","screenPoint","transformPoint","x","tl","y","objectBounds","getBoundingRect","round","angle","transform","finalFontSize","fabricLineHeight","lineHeight","boxSizing","String","fontFamily","fontWeight","fontStyle","textAlign","color","fill","toString","letterSpacing","fontVariant","fontStretch","textRendering","fontKerning","fontFeatureSettings","fontVariationSettings","hyphens","webkitFontSmoothing","mozOsxFontSmoothing","debugBoundingBoxComparison","debugTextWrapping","textareaRect","hostRect","canvasBounds","screenObjectBounds","hostVsObject","leftDiff","topDiff","widthDiff","heightDiff","textareaVsObject","hostAligned","textareaAligned","length","explicitLines","split","forEach","line","i","textareaStyles","getComputedStyle","wordWrap","fabricEffectiveWidth","textareaEffectiveWidth","toFixed","hasRTLText","hasBidiText","textareaScrollHeight","scrollHeight","textareaLineHeight","estimatedTextareaLines","selected","isEditing","set","hasControls","hasBorders","selectable","lockMovementX","lockMovementY","setActiveObject","focus","setSelectionRange","destroy","commit","arguments","undefined","__overlayEditor","__overlayOriginalOpacity","parentNode","removeChild","isComposing","finalText","setTimeout","cursor","setCursor","defaultCursor","autoResizeTextarea","scrollTop","oldHeight","newHeight","e","key","preventDefault","ctrlKey","metaKey","__originalSetZoom","setZoom","__originalSetViewportTransform","setViewportTransform","originalSetZoom","result","originalSetViewportTransform","enterTextOverlayEdit","editor"],"mappings":"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"}
|