UNPKG

fabric

Version:

Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.

1 lines 32 kB
{"version":3,"file":"IText.min.mjs","names":[],"sources":["../../../../src/shapes/IText/IText.ts"],"sourcesContent":["import { Canvas } from '../../canvas/Canvas';\nimport type { ITextEvents } from './ITextBehavior';\nimport { ITextClickBehavior } from './ITextClickBehavior';\nimport {\n ctrlKeysMapDown,\n ctrlKeysMapUp,\n keysMap,\n keysMapRtl,\n} from './constants';\nimport type { TClassProperties, TFiller, TOptions } from '../../typedefs';\nimport { classRegistry } from '../../ClassRegistry';\nimport type { SerializedTextProps, TextProps } from '../Text/Text';\nimport {\n JUSTIFY,\n JUSTIFY_CENTER,\n JUSTIFY_LEFT,\n JUSTIFY_RIGHT,\n} from '../Text/constants';\nimport { CENTER, FILL, LEFT, RIGHT, RTL } from '../../constants';\nimport type { ObjectToCanvasElementOptions } from '../Object/Object';\nimport type { FabricObject } from '../Object/FabricObject';\nimport { createCanvasElementFor } from '../../util/misc/dom';\nimport { applyCanvasTransform } from '../../util/internals/applyCanvasTransform';\n\nexport type CursorBoundaries = {\n left: number;\n top: number;\n leftOffset: number;\n topOffset: number;\n};\n\nexport type CursorRenderingData = {\n color: string;\n opacity: number;\n left: number;\n top: number;\n width: number;\n height: number;\n};\n\n// Declare IText protected properties to workaround TS\nconst protectedDefaultValues = {\n _selectionDirection: null,\n _reSpace: /\\s|\\r?\\n/,\n inCompositionMode: false,\n};\n\nexport const iTextDefaultValues: Partial<TClassProperties<IText>> = {\n selectionStart: 0,\n selectionEnd: 0,\n selectionColor: 'rgba(17,119,255,0.3)',\n isEditing: false,\n editable: true,\n editingBorderColor: 'rgba(102,153,255,0.25)',\n cursorWidth: 2,\n cursorColor: '',\n cursorDelay: 1000,\n cursorDuration: 600,\n caching: true,\n hiddenTextareaContainer: null,\n keysMap,\n keysMapRtl,\n ctrlKeysMapDown,\n ctrlKeysMapUp,\n ...protectedDefaultValues,\n};\n\n// @TODO this is not complete\ninterface UniqueITextProps {\n selectionStart: number;\n selectionEnd: number;\n}\n\nexport interface SerializedITextProps\n extends SerializedTextProps, UniqueITextProps {}\n\nexport interface ITextProps extends TextProps, UniqueITextProps {}\n\n/**\n * @fires changed\n * @fires selection:changed\n * @fires editing:entered\n * @fires editing:exited\n * @fires dragstart\n * @fires drag drag event firing on the drag source\n * @fires dragend\n * @fires copy\n * @fires cut\n * @fires paste\n *\n * #### Supported key combinations\n * ```\n * Move cursor: left, right, up, down\n * Select character: shift + left, shift + right\n * Select text vertically: shift + up, shift + down\n * Move cursor by word: alt + left, alt + right\n * Select words: shift + alt + left, shift + alt + right\n * Move cursor to line start/end: cmd + left, cmd + right or home, end\n * Select till start/end of line: cmd + shift + left, cmd + shift + right or shift + home, shift + end\n * Jump to start/end of text: cmd + up, cmd + down\n * Select till start/end of text: cmd + shift + up, cmd + shift + down or shift + pgUp, shift + pgDown\n * Delete character: backspace\n * Delete word: alt + backspace\n * Delete line: cmd + backspace\n * Forward delete: delete\n * Copy text: ctrl/cmd + c\n * Paste text: ctrl/cmd + v\n * Cut text: ctrl/cmd + x\n * Select entire text: ctrl/cmd + a\n * Quit editing tab or esc\n * ```\n *\n * #### Supported mouse/touch combination\n * ```\n * Position cursor: click/touch\n * Create selection: click/touch & drag\n * Create selection: click & shift + click\n * Select word: double click\n * Select line: triple click\n * ```\n */\nexport class IText<\n Props extends TOptions<ITextProps> = Partial<ITextProps>,\n SProps extends SerializedITextProps = SerializedITextProps,\n EventSpec extends ITextEvents = ITextEvents,\n>\n extends ITextClickBehavior<Props, SProps, EventSpec>\n implements UniqueITextProps\n{\n /**\n * Index where text selection starts (or where cursor is when there is no selection)\n * @type Number\n */\n declare selectionStart: number;\n\n /**\n * Index where text selection ends\n * @type Number\n */\n declare selectionEnd: number;\n\n declare compositionStart: number;\n\n declare compositionEnd: number;\n\n /**\n * Color of text selection\n * @type String\n */\n declare selectionColor: string;\n\n /**\n * Indicates whether text is in editing mode\n * @type Boolean\n */\n declare isEditing: boolean;\n\n /**\n * Indicates whether a text can be edited\n * @type Boolean\n */\n declare editable: boolean;\n\n /**\n * Border color of text object while it's in editing mode\n * @type String\n */\n declare editingBorderColor: string;\n\n /**\n * Width of cursor (in px)\n * @type Number\n */\n declare cursorWidth: number;\n\n /**\n * Color of text cursor color in editing mode.\n * if not set (default) will take color from the text.\n * if set to a color value that fabric can understand, it will\n * be used instead of the color of the text at the current position.\n * @type String\n */\n declare cursorColor: string;\n\n /**\n * Delay between cursor blink (in ms)\n * @type Number\n */\n declare cursorDelay: number;\n\n /**\n * Duration of cursor fade in (in ms)\n * @type Number\n */\n declare cursorDuration: number;\n\n declare compositionColor: string;\n\n /**\n * Indicates whether internal text char widths can be cached\n * @type Boolean\n */\n declare caching: boolean;\n\n static ownDefaults = iTextDefaultValues;\n\n static getDefaults(): Record<string, any> {\n return { ...super.getDefaults(), ...IText.ownDefaults };\n }\n\n static type = 'IText';\n\n get type() {\n const type = super.type;\n // backward compatibility\n return type === 'itext' ? 'i-text' : type;\n }\n\n /**\n * Constructor\n * @param {String} text Text string\n * @param {Object} [options] Options object\n */\n constructor(text: string, options?: Props) {\n super(text, { ...IText.ownDefaults, ...options } as Props);\n this.initBehavior();\n }\n\n /**\n * While editing handle differently\n * @private\n * @param {string} key\n * @param {*} value\n */\n _set(key: string, value: any) {\n if (this.isEditing && this._savedProps && key in this._savedProps) {\n // @ts-expect-error irritating TS\n this._savedProps[key] = value;\n return this;\n }\n if (key === 'canvas') {\n this.canvas instanceof Canvas &&\n this.canvas.textEditingManager.remove(this);\n value instanceof Canvas && value.textEditingManager.add(this);\n }\n return super._set(key, value);\n }\n\n /**\n * Sets selection start (left boundary of a selection)\n * @param {Number} index Index to set selection start to\n */\n setSelectionStart(index: number) {\n index = Math.max(index, 0);\n this._updateAndFire('selectionStart', index);\n }\n\n /**\n * Sets selection end (right boundary of a selection)\n * @param {Number} index Index to set selection end to\n */\n setSelectionEnd(index: number) {\n index = Math.min(index, this.text.length);\n this._updateAndFire('selectionEnd', index);\n }\n\n /**\n * @private\n * @param {String} property 'selectionStart' or 'selectionEnd'\n * @param {Number} index new position of property\n */\n protected _updateAndFire(\n property: 'selectionStart' | 'selectionEnd',\n index: number,\n ) {\n if (this[property] !== index) {\n this._fireSelectionChanged();\n this[property] = index;\n }\n this._updateTextarea();\n }\n\n /**\n * Fires the even of selection changed\n * @private\n */\n _fireSelectionChanged() {\n this.fire('selection:changed');\n this.canvas && this.canvas.fire('text:selection:changed', { target: this });\n }\n\n /**\n * Initialize text dimensions. Render all text on given context\n * or on a offscreen canvas to get the text width with measureText.\n * Updates this.width and this.height with the proper values.\n * Does not return dimensions.\n * @private\n */\n initDimensions() {\n this.isEditing && this.initDelayedCursor();\n super.initDimensions();\n }\n\n /**\n * Gets style of a current selection/cursor (at the start position)\n * if startIndex or endIndex are not provided, selectionStart or selectionEnd will be used.\n * @param {Number} startIndex Start index to get styles at\n * @param {Number} endIndex End index to get styles at, if not specified selectionEnd or startIndex + 1\n * @param {Boolean} [complete] get full style or not\n * @return {Array} styles an array with one, zero or more Style objects\n */\n getSelectionStyles(\n startIndex: number = this.selectionStart || 0,\n endIndex: number = this.selectionEnd,\n complete?: boolean,\n ) {\n return super.getSelectionStyles(startIndex, endIndex, complete);\n }\n\n /**\n * Sets style of a current selection, if no selection exist, do not set anything.\n * @param {Object} [styles] Styles object\n * @param {Number} [startIndex] Start index to get styles at\n * @param {Number} [endIndex] End index to get styles at, if not specified selectionEnd or startIndex + 1\n */\n setSelectionStyles(\n styles: object,\n startIndex: number = this.selectionStart || 0,\n endIndex: number = this.selectionEnd,\n ) {\n return super.setSelectionStyles(styles, startIndex, endIndex);\n }\n\n /**\n * Returns 2d representation (lineIndex and charIndex) of cursor (or selection start)\n * @param {Number} [selectionStart] Optional index. When not given, current selectionStart is used.\n * @param {Boolean} [skipWrapping] consider the location for unwrapped lines. useful to manage styles.\n */\n get2DCursorLocation(\n selectionStart = this.selectionStart,\n skipWrapping?: boolean,\n ) {\n return super.get2DCursorLocation(selectionStart, skipWrapping);\n }\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n render(ctx: CanvasRenderingContext2D) {\n super.render(ctx);\n // clear the cursorOffsetCache, so we ensure to calculate once per renderCursor\n // the correct position but not at every cursor animation.\n this.cursorOffsetCache = {};\n this.renderCursorOrSelection();\n }\n\n /**\n * @override block cursor/selection logic while rendering the exported canvas\n * @todo this workaround should be replaced with a more robust solution\n */\n toCanvasElement(options?: ObjectToCanvasElementOptions): HTMLCanvasElement {\n const isEditing = this.isEditing;\n this.isEditing = false;\n const canvas = super.toCanvasElement(options);\n this.isEditing = isEditing;\n return canvas;\n }\n\n /**\n * Renders cursor or selection (depending on what exists)\n * it does on the contextTop. If contextTop is not available, do nothing.\n */\n renderCursorOrSelection() {\n if (!this.isEditing || !this.canvas) {\n return;\n }\n const ctx = this.clearContextTop(true);\n if (!ctx) {\n return;\n }\n const boundaries = this._getCursorBoundaries();\n\n const ancestors = this.findAncestorsWithClipPath();\n const hasAncestorsWithClipping = ancestors.length > 0;\n let drawingCtx: CanvasRenderingContext2D = ctx;\n let drawingCanvas: HTMLCanvasElement | undefined = undefined;\n if (hasAncestorsWithClipping) {\n // we have some clipPath, we need to draw the selection on an intermediate layer.\n drawingCanvas = createCanvasElementFor(ctx.canvas);\n drawingCtx = drawingCanvas.getContext('2d')!;\n applyCanvasTransform(drawingCtx, this.canvas);\n const m = this.calcTransformMatrix();\n drawingCtx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);\n }\n\n if (this.selectionStart === this.selectionEnd && !this.inCompositionMode) {\n this.renderCursor(drawingCtx, boundaries);\n } else {\n this.renderSelection(drawingCtx, boundaries);\n }\n\n if (hasAncestorsWithClipping) {\n // we need a neutral context.\n // this won't work for nested clippaths in which a clippath\n // has its own clippath\n for (const ancestor of ancestors) {\n const clipPath = ancestor.clipPath!;\n const clippingCanvas = createCanvasElementFor(ctx.canvas);\n const clippingCtx = clippingCanvas.getContext('2d')!;\n applyCanvasTransform(clippingCtx, this.canvas);\n // position the ctx in the center of the outer ancestor\n if (!clipPath.absolutePositioned) {\n const m = ancestor.calcTransformMatrix();\n clippingCtx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);\n }\n clipPath.transform(clippingCtx);\n // we assign an empty drawing context, we don't plan to have this working for nested clippaths for now\n clipPath.drawObject(clippingCtx, true, {});\n this.drawClipPathOnCache(drawingCtx, clipPath, clippingCanvas);\n }\n }\n\n if (hasAncestorsWithClipping) {\n ctx.setTransform(1, 0, 0, 1, 0, 0);\n ctx.drawImage(drawingCanvas!, 0, 0);\n }\n\n this.canvas.contextTopDirty = true;\n ctx.restore();\n }\n\n /**\n * Finds and returns an array of clip paths that are applied to the parent\n * group(s) of the current FabricObject instance. The object's hierarchy is\n * traversed upwards (from the current object towards the root of the canvas),\n * checking each parent object for the presence of a `clipPath` that is not\n * absolutely positioned.\n */\n findAncestorsWithClipPath(): FabricObject[] {\n const clipPathAncestors: FabricObject[] = [];\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n let obj: FabricObject | undefined = this;\n while (obj) {\n if (obj.clipPath) {\n clipPathAncestors.push(obj);\n }\n obj = obj.parent;\n }\n\n return clipPathAncestors;\n }\n\n /**\n * Returns cursor boundaries (left, top, leftOffset, topOffset)\n * left/top are left/top of entire text box\n * leftOffset/topOffset are offset from that left/top point of a text box\n * @private\n * @param {number} [index] index from start\n * @param {boolean} [skipCaching]\n */\n _getCursorBoundaries(\n index: number = this.selectionStart,\n skipCaching?: boolean,\n ): CursorBoundaries {\n const left = this._getLeftOffset(),\n top = this._getTopOffset(),\n offsets = this._getCursorBoundariesOffsets(index, skipCaching);\n return {\n left: left,\n top: top,\n leftOffset: offsets.left,\n topOffset: offsets.top,\n };\n }\n\n /**\n * Caches and returns cursor left/top offset relative to instance's center point\n * @private\n * @param {number} index index from start\n * @param {boolean} [skipCaching]\n */\n _getCursorBoundariesOffsets(\n index: number,\n skipCaching?: boolean,\n ): { left: number; top: number } {\n if (skipCaching) {\n return this.__getCursorBoundariesOffsets(index);\n }\n if (this.cursorOffsetCache && 'top' in this.cursorOffsetCache) {\n return this.cursorOffsetCache as { left: number; top: number };\n }\n return (this.cursorOffsetCache = this.__getCursorBoundariesOffsets(index));\n }\n\n /**\n * Calculates cursor left/top offset relative to instance's center point\n * @private\n * @param {number} index index from start\n */\n __getCursorBoundariesOffsets(index: number) {\n let topOffset = 0,\n leftOffset = 0;\n const { charIndex, lineIndex } = this.get2DCursorLocation(index);\n const { textAlign, direction } = this;\n for (let i = 0; i < lineIndex; i++) {\n topOffset += this.getHeightOfLine(i);\n }\n const lineLeftOffset = this._getLineLeftOffset(lineIndex);\n const bound = this.__charBounds[lineIndex][charIndex];\n bound && (leftOffset = bound.left);\n if (\n this.charSpacing !== 0 &&\n charIndex === this._textLines[lineIndex].length\n ) {\n leftOffset -= this._getWidthOfCharSpacing();\n }\n let left = lineLeftOffset + (leftOffset > 0 ? leftOffset : 0);\n\n if (direction === RTL) {\n if (\n textAlign === RIGHT ||\n textAlign === JUSTIFY ||\n textAlign === JUSTIFY_RIGHT\n ) {\n left *= -1;\n } else if (textAlign === LEFT || textAlign === JUSTIFY_LEFT) {\n left = lineLeftOffset - (leftOffset > 0 ? leftOffset : 0);\n } else if (textAlign === CENTER || textAlign === JUSTIFY_CENTER) {\n left = lineLeftOffset - (leftOffset > 0 ? leftOffset : 0);\n }\n }\n return {\n top: topOffset,\n left,\n };\n }\n\n /**\n * Renders cursor on context Top, outside the animation cycle, on request\n * Used for the drag/drop effect.\n * If contextTop is not available, do nothing.\n */\n renderCursorAt(selectionStart: number) {\n this._renderCursor(\n this.canvas!.contextTop,\n this._getCursorBoundaries(selectionStart, true),\n selectionStart,\n );\n }\n\n /**\n * Renders cursor\n * @param {Object} boundaries\n * @param {CanvasRenderingContext2D} ctx transformed context to draw on\n */\n renderCursor(ctx: CanvasRenderingContext2D, boundaries: CursorBoundaries) {\n this._renderCursor(ctx, boundaries, this.selectionStart);\n }\n\n /**\n * Return the data needed to render the cursor for given selection start\n * The left,top are relative to the object, while width and height are prescaled\n * to look think with canvas zoom and object scaling,\n * so they depend on canvas and object scaling\n */\n getCursorRenderingData(\n selectionStart: number = this.selectionStart,\n boundaries: CursorBoundaries = this._getCursorBoundaries(selectionStart),\n ): CursorRenderingData {\n const cursorLocation = this.get2DCursorLocation(selectionStart),\n lineIndex = cursorLocation.lineIndex,\n charIndex =\n cursorLocation.charIndex > 0 ? cursorLocation.charIndex - 1 : 0,\n charHeight = this.getValueOfPropertyAt(lineIndex, charIndex, 'fontSize'),\n multiplier = this.getObjectScaling().x * this.canvas!.getZoom(),\n cursorWidth = this.cursorWidth / multiplier,\n dy = this.getValueOfPropertyAt(lineIndex, charIndex, 'deltaY'),\n topOffset =\n boundaries.topOffset +\n ((1 - this._fontSizeFraction) * this.getHeightOfLine(lineIndex)) /\n this.lineHeight -\n charHeight * (1 - this._fontSizeFraction);\n\n return {\n color:\n this.cursorColor ||\n (this.getValueOfPropertyAt(lineIndex, charIndex, 'fill') as string),\n opacity: this._currentCursorOpacity,\n left: boundaries.left + boundaries.leftOffset - cursorWidth / 2,\n top: topOffset + boundaries.top + dy,\n width: cursorWidth,\n height: charHeight,\n };\n }\n\n /**\n * Render the cursor at the given selectionStart.\n * @param {CanvasRenderingContext2D} ctx transformed context to draw on\n */\n _renderCursor(\n ctx: CanvasRenderingContext2D,\n boundaries: CursorBoundaries,\n selectionStart: number,\n ) {\n const { color, opacity, left, top, width, height } =\n this.getCursorRenderingData(selectionStart, boundaries);\n ctx.fillStyle = color;\n ctx.globalAlpha = opacity;\n ctx.fillRect(left, top, width, height);\n }\n\n /**\n * Renders text selection\n * @param {Object} boundaries Object with left/top/leftOffset/topOffset\n * @param {CanvasRenderingContext2D} ctx transformed context to draw on\n */\n renderSelection(ctx: CanvasRenderingContext2D, boundaries: CursorBoundaries) {\n const selection = {\n selectionStart: this.inCompositionMode\n ? this.hiddenTextarea!.selectionStart\n : this.selectionStart,\n selectionEnd: this.inCompositionMode\n ? this.hiddenTextarea!.selectionEnd\n : this.selectionEnd,\n };\n this._renderSelection(ctx, selection, boundaries);\n }\n\n /**\n * Renders drag start text selection\n */\n renderDragSourceEffect() {\n const dragStartSelection =\n this.draggableTextDelegate.getDragStartSelection()!;\n this._renderSelection(\n this.canvas!.contextTop,\n dragStartSelection,\n this._getCursorBoundaries(dragStartSelection.selectionStart, true),\n );\n }\n\n renderDropTargetEffect(e: DragEvent) {\n const dragSelection = this.getSelectionStartFromPointer(e);\n this.renderCursorAt(dragSelection);\n }\n\n /**\n * Renders text selection\n * @private\n * @param {{ selectionStart: number, selectionEnd: number }} selection\n * @param {Object} boundaries Object with left/top/leftOffset/topOffset\n * @param {CanvasRenderingContext2D} ctx transformed context to draw on\n */\n _renderSelection(\n ctx: CanvasRenderingContext2D,\n selection: { selectionStart: number; selectionEnd: number },\n boundaries: CursorBoundaries,\n ) {\n const { textAlign, direction } = this;\n const selectionStart = selection.selectionStart,\n selectionEnd = selection.selectionEnd,\n isJustify = textAlign.includes(JUSTIFY),\n start = this.get2DCursorLocation(selectionStart),\n end = this.get2DCursorLocation(selectionEnd),\n startLine = start.lineIndex,\n endLine = end.lineIndex,\n startChar = start.charIndex < 0 ? 0 : start.charIndex,\n endChar = end.charIndex < 0 ? 0 : end.charIndex;\n\n for (let i = startLine; i <= endLine; i++) {\n const lineOffset = this._getLineLeftOffset(i) || 0;\n let lineHeight = this.getHeightOfLine(i),\n realLineHeight = 0,\n boxStart = 0,\n boxEnd = 0;\n\n if (i === startLine) {\n boxStart = this.__charBounds[startLine][startChar].left;\n }\n if (i >= startLine && i < endLine) {\n boxEnd =\n isJustify && !this.isEndOfWrapping(i)\n ? this.width\n : this.getLineWidth(i) || 5; // WTF is this 5?\n } else if (i === endLine) {\n if (endChar === 0) {\n boxEnd = this.__charBounds[endLine][endChar].left;\n } else {\n const charSpacing = this._getWidthOfCharSpacing();\n boxEnd =\n this.__charBounds[endLine][endChar - 1].left +\n this.__charBounds[endLine][endChar - 1].width -\n charSpacing;\n }\n }\n realLineHeight = lineHeight;\n if (this.lineHeight < 1 || (i === endLine && this.lineHeight > 1)) {\n lineHeight /= this.lineHeight;\n }\n let drawStart = boundaries.left + lineOffset + boxStart,\n drawHeight = lineHeight,\n extraTop = 0;\n const drawWidth = boxEnd - boxStart;\n if (this.inCompositionMode) {\n ctx.fillStyle = this.compositionColor || 'black';\n drawHeight = 1;\n extraTop = lineHeight;\n } else {\n ctx.fillStyle = this.selectionColor;\n }\n if (direction === RTL) {\n if (\n textAlign === RIGHT ||\n textAlign === JUSTIFY ||\n textAlign === JUSTIFY_RIGHT\n ) {\n drawStart = this.width - drawStart - drawWidth;\n } else if (textAlign === LEFT || textAlign === JUSTIFY_LEFT) {\n drawStart = boundaries.left + lineOffset - boxEnd;\n } else if (textAlign === CENTER || textAlign === JUSTIFY_CENTER) {\n drawStart = boundaries.left + lineOffset - boxEnd;\n }\n }\n ctx.fillRect(\n drawStart,\n boundaries.top + boundaries.topOffset + extraTop,\n drawWidth,\n drawHeight,\n );\n boundaries.topOffset += realLineHeight;\n }\n }\n\n /**\n * High level function to know the height of the cursor.\n * the currentChar is the one that precedes the cursor\n * Returns fontSize of char at the current cursor\n * Unused from the library, is for the end user\n * @return {Number} Character font size\n */\n getCurrentCharFontSize(): number {\n const cp = this._getCurrentCharIndex();\n return this.getValueOfPropertyAt(cp.l, cp.c, 'fontSize');\n }\n\n /**\n * High level function to know the color of the cursor.\n * the currentChar is the one that precedes the cursor\n * Returns color (fill) of char at the current cursor\n * if the text object has a pattern or gradient for filler, it will return that.\n * Unused by the library, is for the end user\n * @return {String | TFiller} Character color (fill)\n */\n getCurrentCharColor(): string | TFiller | null {\n const cp = this._getCurrentCharIndex();\n return this.getValueOfPropertyAt(cp.l, cp.c, FILL);\n }\n\n /**\n * Returns the cursor position for the getCurrent.. functions\n * @private\n */\n _getCurrentCharIndex() {\n const cursorPosition = this.get2DCursorLocation(this.selectionStart, true),\n charIndex =\n cursorPosition.charIndex > 0 ? cursorPosition.charIndex - 1 : 0;\n return { l: cursorPosition.lineIndex, c: charIndex };\n }\n\n dispose() {\n this.exitEditingImpl();\n this.draggableTextDelegate.dispose();\n super.dispose();\n }\n}\n\nclassRegistry.setClass(IText);\n// legacy\nclassRegistry.setClass(IText, 'i-text');\n"],"mappings":"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"}