{"version":3,"file":"shave.cjs","names":[],"sources":["../src/shave.ts"],"sourcesContent":["export type Link = {\n  [key: string]: string | number | boolean\n}\n\nexport type Opts = {\n  character?: string\n  classname?: string\n  spaces?: boolean\n  charclassname?: string\n  link?: Link\n  delimiter?: string\n}\n\ntype ShaveTarget = string | ArrayLike<Node> | Node\n\nfunction generateArrayOfNodes(target: ShaveTarget): Array<Node> {\n  if (typeof target === 'string') {\n    return [...document.querySelectorAll(target)]\n  }\n  if ('length' in target) return Array.from(target)\n  return [target]\n}\n\nfunction assignLinkAttributes(element: HTMLElement, link: Link): void {\n  Object.entries(link).forEach(([property, value]) => {\n    if (property === 'className') {\n      element.className = String(value)\n      return\n    }\n    if (property === 'textContent') {\n      element.textContent = String(value)\n      return\n    }\n    element.setAttribute(property, String(value))\n  })\n}\n\nexport default function shave(target: ShaveTarget, maxHeight: number, opts: Opts = {}): void {\n  if (typeof maxHeight === 'undefined' || isNaN(maxHeight)) {\n    throw Error('maxHeight is required')\n  }\n  const els = generateArrayOfNodes(target)\n\n  if (!els.length) {\n    return\n  }\n\n  const {\n    character = '…',\n    classname = 'js-shave',\n    spaces: initialSpaces = true,\n    charclassname = 'js-shave-char',\n    link = {},\n    delimiter,\n  } = opts\n\n  /**\n   * @notes\n   * the initialSpaces + spaces variable definition below fixes\n   * a previous bug where spaces being a boolean type wasn't clear\n   * meaning people were using (a string, in example—which is truthy)\n   * hence, doing it this way is a non-breaking change\n   */\n  const spaces = typeof initialSpaces === 'boolean' ? initialSpaces : true\n\n  /**\n   * @notes\n   * - create a span or anchor element and assign properties to it\n   * - JSON.stringify is used to support IE8+\n   * - if link.href is not provided, link object properties are ignored\n   */\n  const isLink = link && JSON.stringify(link) !== '{}' && link.href\n  const shavedTextElType = isLink ? 'a' : 'span'\n\n  for (let i = 0; i < els.length; i += 1) {\n    const el = els[i] as HTMLElement\n    const styles = el.style\n    const span = el.querySelector('.' + classname)\n    const textProp = el.textContent === undefined ? 'innerText' : 'textContent'\n    if (span) {\n      const shavedCharacter = el.querySelector('.' + charclassname)\n      if (shavedCharacter) el.removeChild(shavedCharacter)\n      el[textProp] = el[textProp] // eslint-disable-line\n    }\n\n    const fullText = el[textProp] || ''\n    let words: string | string[]\n\n    if (!delimiter) words = spaces ? fullText.split(' ') : fullText\n    else words = fullText.split(delimiter)\n\n    if (words.length < 2) continue\n\n    const heightStyle = styles.height\n    styles.height = 'auto'\n    const maxHeightStyle = styles.maxHeight\n    styles.maxHeight = 'none'\n\n    if (el.offsetHeight <= maxHeight) {\n      styles.height = heightStyle\n      styles.maxHeight = maxHeightStyle\n      continue\n    }\n\n    const textContent = isLink && link.textContent ? link.textContent : character\n    const shavedTextEl = document.createElement(shavedTextElType)\n    shavedTextEl.className = charclassname\n    shavedTextEl.textContent = String(textContent)\n\n    if (isLink) {\n      assignLinkAttributes(shavedTextEl, link)\n      shavedTextEl.classList.add(charclassname)\n    }\n\n    let max = words.length - 1\n    let min = 0\n    let pivot\n    while (min < max) {\n      pivot = (min + max + 1) >> 1 // eslint-disable-line no-bitwise\n      const wordItems = words.slice(0, pivot)\n      el[textProp] = updateTextProp(delimiter, spaces, wordItems)\n      el.insertAdjacentElement('beforeend', shavedTextEl)\n      if (el.offsetHeight > maxHeight) {\n        max = pivot - 1\n      } else {\n        min = pivot\n      }\n    }\n    const wordeItems = words.slice(0, max)\n    el[textProp] = updateTextProp(delimiter, spaces, wordeItems)\n    el.insertAdjacentElement('beforeend', shavedTextEl)\n    const diffItems = words.slice(max)\n    const isArray = Array.isArray(diffItems)\n    let diff = ''\n    if (delimiter && isArray) diff = delimiter + diffItems.join(delimiter)\n    else if (spaces && isArray) diff = ' ' + diffItems.join(' ')\n    else if (isArray) diff = diffItems.join('')\n    else diff = diffItems\n    const shavedText = document.createTextNode(diff)\n    const elWithShavedText = document.createElement('span')\n    elWithShavedText.classList.add(classname)\n    elWithShavedText.style.display = 'none'\n    elWithShavedText.appendChild(shavedText)\n    el.insertAdjacentElement('beforeend', elWithShavedText)\n    styles.height = heightStyle\n    styles.maxHeight = maxHeightStyle\n  }\n}\n\nexport function updateTextProp(delimiter: string | undefined, spaces: boolean, wordItems: string | string[]): string {\n  const isArray = Array.isArray(wordItems)\n  if (delimiter && isArray) return wordItems.join(delimiter)\n  if (spaces && isArray) return wordItems.join(' ')\n  if (isArray) return wordItems.join('')\n  return wordItems\n}\n"],"mappings":";;;;;;;+FAeA,SAAS,EAAqB,EAAkC,CAK9D,OAJI,OAAO,GAAW,SACb,CAAC,GAAG,SAAS,iBAAiB,CAAM,CAAC,EAE1C,WAAY,EAAe,MAAM,KAAK,CAAM,EACzC,CAAC,CAAM,CAChB,CAEA,SAAS,EAAqB,EAAsB,EAAkB,CACpE,OAAO,QAAQ,CAAI,CAAC,CAAC,SAAS,CAAC,EAAU,KAAW,CAClD,GAAI,IAAa,YAAa,CAC5B,EAAQ,UAAY,OAAO,CAAK,EAChC,MACF,CACA,GAAI,IAAa,cAAe,CAC9B,EAAQ,YAAc,OAAO,CAAK,EAClC,MACF,CACA,EAAQ,aAAa,EAAU,OAAO,CAAK,CAAC,CAC9C,CAAC,CACH,CAEA,SAAwB,EAAM,EAAqB,EAAmB,EAAa,CAAC,EAAS,CAC3F,GAAW,IAAc,QAAe,MAAM,CAAS,EACrD,MAAM,MAAM,uBAAuB,EAErC,IAAM,EAAM,EAAqB,CAAM,EAEvC,GAAI,CAAC,EAAI,OACP,OAGF,GAAM,CACJ,YAAY,IACZ,YAAY,WACZ,OAAQ,EAAgB,GACxB,gBAAgB,gBAChB,OAAO,CAAC,EACR,aACE,EASE,EAAS,OAAO,GAAkB,WAAY,EAQ9C,EAAS,GAAQ,KAAK,UAAU,CAAI,IAAM,MAAQ,EAAK,KACvD,EAAmB,EAAS,IAAM,OAExC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAI,OAAQ,GAAK,EAAG,CACtC,IAAM,EAAK,EAAI,GACT,EAAS,EAAG,MACZ,EAAO,EAAG,cAAc,IAAM,CAAS,EACvC,EAAW,EAAG,cAAgB,IAAA,GAAY,YAAc,cAC9D,GAAI,EAAM,CACR,IAAM,EAAkB,EAAG,cAAc,IAAM,CAAa,EACxD,GAAiB,EAAG,YAAY,CAAe,EACnD,EAAG,GAAY,EAAG,EACpB,CAEA,IAAM,EAAW,EAAG,IAAa,GAC7B,EAKJ,GAHA,AAAgB,EAAX,EACQ,EAAS,MAAM,CAAS,EADb,EAAS,EAAS,MAAM,GAAG,EAAI,EAGnD,EAAM,OAAS,EAAG,SAEtB,IAAM,EAAc,EAAO,OAC3B,EAAO,OAAS,OAChB,IAAM,EAAiB,EAAO,UAG9B,GAFA,EAAO,UAAY,OAEf,EAAG,cAAgB,EAAW,CAChC,EAAO,OAAS,EAChB,EAAO,UAAY,EACnB,QACF,CAEA,IAAM,EAAc,GAAU,EAAK,YAAc,EAAK,YAAc,EAC9D,EAAe,SAAS,cAAc,CAAgB,EAC5D,EAAa,UAAY,EACzB,EAAa,YAAc,OAAO,CAAW,EAEzC,IACF,EAAqB,EAAc,CAAI,EACvC,EAAa,UAAU,IAAI,CAAa,GAG1C,IAAI,EAAM,EAAM,OAAS,EACrB,EAAM,EACN,EACJ,KAAO,EAAM,GACX,EAAS,EAAM,EAAM,GAAM,EAE3B,EAAG,GAAY,EAAe,EAAW,EADvB,EAAM,MAAM,EAAG,CACgB,CAAS,EAC1D,EAAG,sBAAsB,YAAa,CAAY,EAC9C,EAAG,aAAe,EACpB,EAAM,EAAQ,EAEd,EAAM,EAIV,EAAG,GAAY,EAAe,EAAW,EADtB,EAAM,MAAM,EAAG,CACe,CAAU,EAC3D,EAAG,sBAAsB,YAAa,CAAY,EAClD,IAAM,EAAY,EAAM,MAAM,CAAG,EAC3B,EAAU,MAAM,QAAQ,CAAS,EACnC,EAAO,GACX,AAGK,EAHD,GAAa,EAAgB,EAAY,EAAU,KAAK,CAAS,EAC5D,GAAU,EAAgB,IAAM,EAAU,KAAK,GAAG,EAClD,EAAgB,EAAU,KAAK,EAAE,EAC9B,EACZ,IAAM,EAAa,SAAS,eAAe,CAAI,EACzC,EAAmB,SAAS,cAAc,MAAM,EACtD,EAAiB,UAAU,IAAI,CAAS,EACxC,EAAiB,MAAM,QAAU,OACjC,EAAiB,YAAY,CAAU,EACvC,EAAG,sBAAsB,YAAa,CAAgB,EACtD,EAAO,OAAS,EAChB,EAAO,UAAY,CACrB,CACF,CAEA,SAAgB,EAAe,EAA+B,EAAiB,EAAsC,CACnH,IAAM,EAAU,MAAM,QAAQ,CAAS,EAIvC,OAHI,GAAa,EAAgB,EAAU,KAAK,CAAS,EACrD,GAAU,EAAgB,EAAU,KAAK,GAAG,EAC5C,EAAgB,EAAU,KAAK,EAAE,EAC9B,CACT"}