{"version":3,"file":"Textbox.mjs","names":[],"sources":["../../../src/shapes/Textbox.ts"],"sourcesContent":["import type { TClassProperties, TOptions } from '../typedefs';\nimport { IText } from './IText/IText';\nimport { classRegistry } from '../ClassRegistry';\nimport { createTextboxDefaultControls } from '../controls/commonControls';\nimport { JUSTIFY } from './Text/constants';\nimport type { TextStyleDeclaration } from './Text/StyledText';\nimport type { SerializedITextProps, ITextProps } from './IText/IText';\nimport type { ITextEvents } from './IText/ITextBehavior';\nimport type { TextLinesInfo } from './Text/Text';\nimport type { Control } from '../controls/Control';\n\n// @TODO: Many things here are configuration related and shouldn't be on the class nor prototype\n// regexes, list of properties that are not suppose to change by instances, magic consts.\n// this will be a separated effort\nexport const textboxDefaultValues: Partial<TClassProperties<Textbox>> = {\n  minWidth: 20,\n  dynamicMinWidth: 2,\n  lockScalingFlip: true,\n  noScaleCache: false,\n  _wordJoiners: /[ \\t\\r]/,\n  splitByGrapheme: false,\n};\n\nexport type GraphemeData = {\n  wordsData: {\n    word: string[];\n    width: number;\n  }[][];\n  largestWordWidth: number;\n};\n\nexport type StyleMap = Record<string, { line: number; offset: number }>;\n\n// @TODO this is not complete\ninterface UniqueTextboxProps {\n  minWidth: number;\n  splitByGrapheme: boolean;\n  dynamicMinWidth: number;\n  _wordJoiners: RegExp;\n}\n\nexport interface SerializedTextboxProps\n  extends\n    SerializedITextProps,\n    Pick<UniqueTextboxProps, 'minWidth' | 'splitByGrapheme'> {}\n\nexport interface TextboxProps extends ITextProps, UniqueTextboxProps {}\n\n/**\n * Textbox class, based on IText, allows the user to resize the text rectangle\n * and wraps lines automatically. Textboxes have their Y scaling locked, the\n * user can only change width. Height is adjusted automatically based on the\n * wrapping of lines.\n */\nexport class Textbox<\n  Props extends TOptions<TextboxProps> = Partial<TextboxProps>,\n  SProps extends SerializedTextboxProps = SerializedTextboxProps,\n  EventSpec extends ITextEvents = ITextEvents,\n>\n  extends IText<Props, SProps, EventSpec>\n  implements UniqueTextboxProps\n{\n  /**\n   * Minimum width of textbox, in pixels.\n   * @type Number\n   */\n  declare minWidth: number;\n\n  /**\n   * Minimum calculated width of a textbox, in pixels.\n   * fixed to 2 so that an empty textbox cannot go to 0\n   * and is still selectable without text.\n   * @type Number\n   */\n  declare dynamicMinWidth: number;\n\n  /**\n   * Use this boolean property in order to split strings that have no white space concept.\n   * this is a cheap way to help with chinese/japanese\n   * @type Boolean\n   * @since 2.6.0\n   */\n  declare splitByGrapheme: boolean;\n\n  declare _wordJoiners: RegExp;\n\n  declare _styleMap: StyleMap;\n\n  declare isWrapping: boolean;\n\n  static type = 'Textbox';\n\n  static textLayoutProperties = [...IText.textLayoutProperties, 'width'];\n\n  static ownDefaults = textboxDefaultValues;\n\n  static getDefaults(): Record<string, any> {\n    return {\n      ...super.getDefaults(),\n      ...Textbox.ownDefaults,\n    };\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, { ...Textbox.ownDefaults, ...options } as Props);\n  }\n\n  /**\n   * Creates the default control object.\n   * If you prefer to have on instance of controls shared among all objects\n   * make this function return an empty object and add controls to the ownDefaults object\n   */\n  static createControls(): { controls: Record<string, Control> } {\n    return { controls: createTextboxDefaultControls() };\n  }\n\n  /**\n   * Unlike superclass's version of this function, Textbox does not update\n   * its width.\n   * @private\n   * @override\n   */\n  initDimensions() {\n    if (!this.initialized) {\n      return;\n    }\n    this.isEditing && this.initDelayedCursor();\n    this._clearCache();\n    // clear dynamicMinWidth as it will be different after we re-wrap line\n    this.dynamicMinWidth = 0;\n    // wrap lines\n    this._styleMap = this._generateStyleMap(this._splitText());\n    // if after wrapping, the width is smaller than dynamicMinWidth, change the width and re-wrap\n    if (this.dynamicMinWidth > this.width) {\n      this._set('width', this.dynamicMinWidth);\n    }\n    if (this.textAlign.includes(JUSTIFY)) {\n      // once text is measured we need to make space fatter to make justified text.\n      this.enlargeSpaces();\n    }\n    // clear cache and re-calculate height\n    this.height = this.calcTextHeight();\n  }\n\n  /**\n   * Generate an object that translates the style object so that it is\n   * broken up by visual lines (new lines and automatic wrapping).\n   * The original text styles object is broken up by actual lines (new lines only),\n   * which is only sufficient for Text / IText\n   * @private\n   */\n  _generateStyleMap(textInfo: TextLinesInfo): StyleMap {\n    let realLineCount = 0,\n      realLineCharCount = 0,\n      charCount = 0;\n    const map: StyleMap = {};\n\n    for (let i = 0; i < textInfo.graphemeLines.length; i++) {\n      if (textInfo.graphemeText[charCount] === '\\n' && i > 0) {\n        realLineCharCount = 0;\n        charCount++;\n        realLineCount++;\n      } else if (\n        !this.splitByGrapheme &&\n        this._reSpaceAndTab.test(textInfo.graphemeText[charCount]) &&\n        i > 0\n      ) {\n        // this case deals with space's that are removed from end of lines when wrapping\n        realLineCharCount++;\n        charCount++;\n      }\n\n      map[i] = { line: realLineCount, offset: realLineCharCount };\n\n      charCount += textInfo.graphemeLines[i].length;\n      realLineCharCount += textInfo.graphemeLines[i].length;\n    }\n\n    return map;\n  }\n\n  /**\n   * Returns true if object has a style property or has it on a specified line\n   * @param {Number} lineIndex\n   * @return {Boolean}\n   */\n  styleHas(property: keyof TextStyleDeclaration, lineIndex: number): boolean {\n    if (this._styleMap && !this.isWrapping) {\n      const map = this._styleMap[lineIndex];\n      if (map) {\n        lineIndex = map.line;\n      }\n    }\n    return super.styleHas(property, lineIndex);\n  }\n\n  /**\n   * Returns true if object has no styling or no styling in a line\n   * @param {Number} lineIndex , lineIndex is on wrapped lines.\n   * @return {Boolean}\n   */\n  isEmptyStyles(lineIndex: number): boolean {\n    if (!this.styles) {\n      return true;\n    }\n    let offset = 0,\n      nextLineIndex = lineIndex + 1,\n      nextOffset: number,\n      shouldLimit = false;\n    const map = this._styleMap[lineIndex],\n      mapNextLine = this._styleMap[lineIndex + 1];\n    if (map) {\n      lineIndex = map.line;\n      offset = map.offset;\n    }\n    if (mapNextLine) {\n      nextLineIndex = mapNextLine.line;\n      shouldLimit = nextLineIndex === lineIndex;\n      nextOffset = mapNextLine.offset;\n    }\n    const obj =\n      typeof lineIndex === 'undefined'\n        ? this.styles\n        : { line: this.styles[lineIndex] };\n    for (const p1 in obj) {\n      for (const p2 in obj[p1]) {\n        const p2Number = parseInt(p2, 10);\n        if (p2Number >= offset && (!shouldLimit || p2Number < nextOffset!)) {\n          for (const p3 in obj[p1][p2]) {\n            return false;\n          }\n        }\n      }\n    }\n    return true;\n  }\n\n  /**\n   * @protected\n   * @param {Number} lineIndex\n   * @param {Number} charIndex\n   * @return {TextStyleDeclaration} a style object reference to the existing one or a new empty object when undefined\n   */\n  _getStyleDeclaration(\n    lineIndex: number,\n    charIndex: number,\n  ): TextStyleDeclaration {\n    if (this._styleMap && !this.isWrapping) {\n      const map = this._styleMap[lineIndex];\n      if (!map) {\n        return {};\n      }\n      lineIndex = map.line;\n      charIndex = map.offset + charIndex;\n    }\n    return super._getStyleDeclaration(lineIndex, charIndex);\n  }\n\n  /**\n   * @param {Number} lineIndex\n   * @param {Number} charIndex\n   * @param {Object} style\n   * @private\n   */\n  protected _setStyleDeclaration(\n    lineIndex: number,\n    charIndex: number,\n    style: object,\n  ) {\n    const map = this._styleMap[lineIndex];\n    super._setStyleDeclaration(map.line, map.offset + charIndex, style);\n  }\n\n  /**\n   * @param {Number} lineIndex\n   * @param {Number} charIndex\n   * @private\n   */\n  protected _deleteStyleDeclaration(lineIndex: number, charIndex: number) {\n    const map = this._styleMap[lineIndex];\n    super._deleteStyleDeclaration(map.line, map.offset + charIndex);\n  }\n\n  /**\n   * probably broken need a fix\n   * Returns the real style line that correspond to the wrapped lineIndex line\n   * Used just to verify if the line does exist or not.\n   * @param {Number} lineIndex\n   * @returns {Boolean} if the line exists or not\n   * @private\n   */\n  protected _getLineStyle(lineIndex: number): boolean {\n    const map = this._styleMap[lineIndex];\n    return !!this.styles[map.line];\n  }\n\n  /**\n   * Set the line style to an empty object so that is initialized\n   * @param {Number} lineIndex\n   * @param {Object} style\n   * @private\n   */\n  protected _setLineStyle(lineIndex: number) {\n    const map = this._styleMap[lineIndex];\n    super._setLineStyle(map.line);\n  }\n\n  /**\n   * Wraps text using the 'width' property of Textbox. First this function\n   * splits text on newlines, so we preserve newlines entered by the user.\n   * Then it wraps each line using the width of the Textbox by calling\n   * _wrapLine().\n   * @param {Array} lines The string array of text that is split into lines\n   * @param {Number} desiredWidth width you want to wrap to\n   * @returns {Array} Array of lines\n   */\n  _wrapText(lines: string[], desiredWidth: number): string[][] {\n    this.isWrapping = true;\n    // extract all thewords and the widths to optimally wrap lines.\n    const data = this.getGraphemeDataForRender(lines);\n    const wrapped: string[][] = [];\n    for (let i = 0; i < data.wordsData.length; i++) {\n      wrapped.push(...this._wrapLine(i, desiredWidth, data));\n    }\n    this.isWrapping = false;\n    return wrapped;\n  }\n\n  /**\n   * For each line of text terminated by an hard line stop,\n   * measure each word width and extract the largest word from all.\n   * The returned words here are the one that at the end will be rendered.\n   * @param {string[]} lines the lines we need to measure\n   *\n   */\n  getGraphemeDataForRender(lines: string[]): GraphemeData {\n    const splitByGrapheme = this.splitByGrapheme,\n      infix = splitByGrapheme ? '' : ' ';\n\n    let largestWordWidth = 0;\n\n    const data = lines.map((line, lineIndex) => {\n      let offset = 0;\n      const wordsOrGraphemes = splitByGrapheme\n        ? this.graphemeSplit(line)\n        : this.wordSplit(line);\n\n      if (wordsOrGraphemes.length === 0) {\n        return [{ word: [], width: 0 }];\n      }\n\n      return wordsOrGraphemes.map((word: string) => {\n        // if using splitByGrapheme words are already in graphemes.\n        const graphemeArray = splitByGrapheme\n          ? [word]\n          : this.graphemeSplit(word);\n        const width = this._measureWord(graphemeArray, lineIndex, offset);\n        largestWordWidth = Math.max(width, largestWordWidth);\n        offset += graphemeArray.length + infix.length;\n        return { word: graphemeArray, width };\n      });\n    });\n\n    return {\n      wordsData: data,\n      largestWordWidth,\n    };\n  }\n\n  /**\n   * Helper function to measure a string of text, given its lineIndex and charIndex offset\n   * It gets called when charBounds are not available yet.\n   * Override if necessary\n   * Use with {@link Textbox#wordSplit}\n   *\n   * @param {CanvasRenderingContext2D} ctx\n   * @param {String} text\n   * @param {number} lineIndex\n   * @param {number} charOffset\n   * @returns {number}\n   */\n  _measureWord(word: string[], lineIndex: number, charOffset = 0): number {\n    let width = 0,\n      prevGrapheme;\n    const skipLeft = true;\n    for (let i = 0, len = word.length; i < len; i++) {\n      const box = this._getGraphemeBox(\n        word[i],\n        lineIndex,\n        i + charOffset,\n        prevGrapheme,\n        skipLeft,\n      );\n      width += box.kernedWidth;\n      prevGrapheme = word[i];\n    }\n    return width;\n  }\n\n  /**\n   * Override this method to customize word splitting\n   * Use with {@link Textbox#_measureWord}\n   * @param {string} value\n   * @returns {string[]} array of words\n   */\n  wordSplit(value: string): string[] {\n    return value.split(this._wordJoiners);\n  }\n\n  /**\n   * Wraps a line of text using the width of the Textbox as desiredWidth\n   * and leveraging the known width o words from GraphemeData\n   * @private\n   * @param {Number} lineIndex\n   * @param {Number} desiredWidth width you want to wrap the line to\n   * @param {GraphemeData} graphemeData an object containing all the lines' words width.\n   * @param {Number} reservedSpace space to remove from wrapping for custom functionalities\n   * @returns {Array} Array of line(s) into which the given text is wrapped\n   * to.\n   */\n  _wrapLine(\n    lineIndex: number,\n    desiredWidth: number,\n    { largestWordWidth, wordsData }: GraphemeData,\n    reservedSpace = 0,\n  ): string[][] {\n    const additionalSpace = this._getWidthOfCharSpacing(),\n      splitByGrapheme = this.splitByGrapheme,\n      graphemeLines = [],\n      infix = splitByGrapheme ? '' : ' ';\n\n    let lineWidth = 0,\n      line: string[] = [],\n      // spaces in different languages?\n      offset = 0,\n      infixWidth = 0,\n      lineJustStarted = true;\n\n    desiredWidth -= reservedSpace;\n\n    const maxWidth = Math.max(\n      desiredWidth,\n      largestWordWidth,\n      this.dynamicMinWidth,\n    );\n    // layout words\n    const data = wordsData[lineIndex];\n    offset = 0;\n    let i;\n    for (i = 0; i < data.length; i++) {\n      const { word, width: wordWidth } = data[i];\n      offset += word.length;\n\n      lineWidth += infixWidth + wordWidth - additionalSpace;\n      if (lineWidth > maxWidth && !lineJustStarted) {\n        graphemeLines.push(line);\n        line = [];\n        lineWidth = wordWidth;\n        lineJustStarted = true;\n      } else {\n        lineWidth += additionalSpace;\n      }\n\n      if (!lineJustStarted && !splitByGrapheme) {\n        line.push(infix);\n      }\n      line = line.concat(word);\n\n      infixWidth = splitByGrapheme\n        ? 0\n        : this._measureWord([infix], lineIndex, offset);\n      offset++;\n      lineJustStarted = false;\n    }\n\n    i && graphemeLines.push(line);\n\n    // TODO: this code is probably not necessary anymore.\n    // it can be moved out of this function since largestWordWidth is now\n    // known in advance\n    if (largestWordWidth + reservedSpace > this.dynamicMinWidth) {\n      this.dynamicMinWidth = largestWordWidth - additionalSpace + reservedSpace;\n    }\n    return graphemeLines;\n  }\n\n  /**\n   * Detect if the text line is ended with an hard break\n   * text and itext do not have wrapping, return false\n   * @param {Number} lineIndex text to split\n   * @return {Boolean}\n   */\n  isEndOfWrapping(lineIndex: number): boolean {\n    if (!this._styleMap[lineIndex + 1]) {\n      // is last line, return true;\n      return true;\n    }\n    if (this._styleMap[lineIndex + 1].line !== this._styleMap[lineIndex].line) {\n      // this is last line before a line break, return true;\n      return true;\n    }\n    return false;\n  }\n\n  /**\n   * Detect if a line has a linebreak and so we need to account for it when moving\n   * and counting style.\n   * This is important only for splitByGrapheme at the end of wrapping.\n   * If we are not wrapping the offset is always 1\n   * @return Number\n   */\n  missingNewlineOffset(lineIndex: number, skipWrapping?: boolean): 0 | 1 {\n    if (this.splitByGrapheme && !skipWrapping) {\n      return this.isEndOfWrapping(lineIndex) ? 1 : 0;\n    }\n    return 1;\n  }\n\n  /**\n   * Gets lines of text to render in the Textbox. This function calculates\n   * text wrapping on the fly every time it is called.\n   * @param {String} text text to split\n   * @returns {Array} Array of lines in the Textbox.\n   * @override\n   */\n  _splitTextIntoLines(text: string) {\n    const newText = super._splitTextIntoLines(text),\n      graphemeLines = this._wrapText(newText.lines, this.width),\n      lines = new Array(graphemeLines.length);\n    for (let i = 0; i < graphemeLines.length; i++) {\n      lines[i] = graphemeLines[i].join('');\n    }\n    newText.lines = lines;\n    newText.graphemeLines = graphemeLines;\n    return newText;\n  }\n\n  getMinWidth() {\n    return Math.max(this.minWidth, this.dynamicMinWidth);\n  }\n\n  _removeExtraneousStyles() {\n    const linesToKeep = new Map();\n    for (const prop in this._styleMap) {\n      const propNumber = parseInt(prop, 10);\n      if (this._textLines[propNumber]) {\n        const lineIndex = this._styleMap[prop].line;\n        linesToKeep.set(`${lineIndex}`, true);\n      }\n    }\n    for (const prop in this.styles) {\n      if (!linesToKeep.has(prop)) {\n        delete this.styles[prop];\n      }\n    }\n  }\n\n  /**\n   * Returns object representation of an instance\n   * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n   * @return {Object} object representation of an instance\n   */\n  toObject<\n    T extends Omit<Props & TClassProperties<this>, keyof SProps>,\n    K extends keyof T = never,\n  >(propertiesToInclude: K[] = []): Pick<T, K> & SProps {\n    return super.toObject<T, K>([\n      'minWidth',\n      'splitByGrapheme',\n      ...propertiesToInclude,\n    ] as K[]);\n  }\n}\n\nclassRegistry.setClass(Textbox);\n"],"mappings":"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"}