{"version":3,"file":"react-spectrum.cjs","sources":["../src/utils/arraysEqual.ts","../src/utils/getRandomInRange.ts","../src/utils/getWords.ts","../src/DrawLine.tsx","../src/usePrevious.tsx","../src/Spectrum.tsx"],"sourcesContent":["function arraysEqual(\n  a: Array<string | number>,\n  b: Array<string | number>,\n): boolean {\n  if (a === b) return true;\n  if (a == null || b == null) return false;\n  if (a.length !== b.length) return false;\n\n  const sortedA = [...a].sort();\n  const sortedB = [...b].sort();\n  for (let i = 0; i < sortedA.length; i += 1) {\n    if (sortedA[i] !== sortedB[i]) return false;\n  }\n\n  return true;\n}\n\nexport default arraysEqual;\n","function getRandomInRange(min: number, max: number): number {\n  const mn = Math.ceil(min);\n  const mx = Math.floor(max);\n\n  return Math.floor(Math.random() * (mx - mn + 1)) + mn;\n}\n\nexport default getRandomInRange;\n","import getRandomInRange from './getRandomInRange';\n\nconst getWords = ({\n  width,\n  colors,\n  wordWidths,\n  wordDistances,\n  truncate,\n}: {\n  width: number;\n  colors: Array<string>;\n  wordWidths: Array<number>;\n  wordDistances: Array<number>;\n  truncate: boolean;\n}): Array<{ width: number; distance: number; background: string }> => {\n  const minWordWidth = Math.min(...wordWidths);\n  const maxWordsPerLine = Math.floor(width / minWordWidth);\n  const wordForLine = getRandomInRange(\n    Math.max(\n      0,\n      truncate ? 1 : maxWordsPerLine - Math.floor(maxWordsPerLine / 2),\n    ),\n    truncate ? Math.floor(maxWordsPerLine / 2) : maxWordsPerLine,\n  );\n\n  const words = [];\n  let totalWidth = 0;\n  for (let i = 0; i < wordForLine; i += 1) {\n    const wordWidth = wordWidths[getRandomInRange(0, wordWidths.length - 1)];\n    let wordDistance =\n      wordDistances[getRandomInRange(0, wordDistances.length - 1)];\n\n    const totalWidthWithoutDistance = totalWidth + wordWidth;\n    totalWidth = totalWidthWithoutDistance + wordDistance;\n\n    // If we can just fit the word without margin, push it by resetting margin\n    const fitWord = totalWidthWithoutDistance <= width && totalWidth > width;\n    const fitWordWithDistance = totalWidth <= width;\n\n    if (fitWord || fitWordWithDistance) {\n      // If we are fitting the word, assume that it's the last word\n      // so, reset it's distance\n      if (fitWord && !fitWordWithDistance) {\n        wordDistance = 0;\n      }\n\n      const background = colors[getRandomInRange(0, colors.length - 1)];\n      words.push({ width: wordWidth, distance: wordDistance, background });\n\n      // If we are fitting the word, it's the last word\n      if (fitWord && !fitWordWithDistance) {\n        break;\n      }\n    } else {\n      // If we cannot fit the word into the line\n      // clear the margin of the last word\n      const [last] = [...words].reverse();\n      if (last) {\n        last.distance = 0;\n      }\n      break;\n    }\n  }\n\n  return words;\n};\n\nexport default getWords;\n","import * as React from 'react';\nimport arraysEqual from './utils/arraysEqual';\nimport getWords from './utils/getWords';\nimport usePrevious from './usePrevious';\nimport { RenderWordProps } from './Spectrum';\n\ninterface DrawLineProps {\n  width: number;\n  colors: Array<string>;\n  wordWidths: Array<number>;\n  wordDistances: Array<number>;\n  truncate: boolean;\n  wordHeight: number;\n  wordRadius: number;\n  lineDistance: number;\n  renderWord: React.FC<RenderWordProps>;\n}\n\nconst DrawLine = ({\n  width,\n  colors,\n  wordWidths,\n  wordDistances,\n  wordHeight,\n  wordRadius,\n  lineDistance,\n  truncate,\n  renderWord,\n}: DrawLineProps): React.ReactElement => {\n  const previous = usePrevious({\n    width,\n    colors,\n    wordWidths,\n    wordDistances,\n    wordHeight,\n    wordRadius,\n    lineDistance,\n    truncate,\n    renderWord,\n  });\n  const [words, setWords] = React.useState(() =>\n    getWords({\n      width,\n      colors,\n      wordWidths,\n      wordDistances,\n      truncate,\n    }),\n  );\n\n  React.useEffect(() => {\n    // Handle props update on the runtime\n    // Memo isn't helping here as props contains array\n    // whose reference might change on every re-render\n    if (\n      previous &&\n      (previous.width !== width ||\n        previous.wordHeight !== wordHeight ||\n        previous.wordRadius !== wordRadius ||\n        previous.lineDistance !== lineDistance ||\n        previous.truncate !== truncate ||\n        !arraysEqual(previous.wordWidths, wordWidths) ||\n        !arraysEqual(previous.wordDistances, wordDistances) ||\n        !arraysEqual(previous.colors, colors))\n    ) {\n      const newWords = getWords({\n        width,\n        colors,\n        wordWidths,\n        wordDistances,\n        truncate,\n      });\n\n      setWords(newWords);\n    }\n  }, [\n    previous,\n    width,\n    colors,\n    wordWidths,\n    wordDistances,\n    truncate,\n    wordHeight,\n    wordRadius,\n    lineDistance,\n  ]);\n  return (\n    <>\n      {words.map(({ width: w, distance, background }, i) => {\n        const style = {\n          width: w,\n          marginRight: distance,\n          height: wordHeight,\n          background,\n          display: 'inline-block',\n          borderRadius: wordRadius,\n          marginBottom: lineDistance,\n        };\n\n        // Ensure only synchronous results are rendered\n        const node = renderWord({ key: i, style });\n        if (node instanceof Promise) {\n          throw new Error(\"`renderWord` must be synchronous function and not return a Promise.\");\n        }\n        return node;\n      })}\n    </>\n  );\n};\n\nexport default React.memo(DrawLine);\n","import * as React from 'react';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction usePrevious(value: any): any {\n  const ref = React.useRef(null);\n\n  React.useEffect(() => {\n    ref.current = value;\n  });\n\n  return ref.current;\n}\n\nexport default usePrevious;\n","import * as React from 'react';\nimport DrawLine from './DrawLine';\n\nexport interface RenderWordProps {\n  key: number;\n  style: React.CSSProperties;\n}\n\ntype SpectrumProps = {\n  /**\n   * Width of the placeholder container\n   */\n  width?: number;\n  /**\n   * Possible colors of words, will be picked randomly\n   */\n  colors?: Array<string>;\n  /**\n   * Possible widths of words, will be picked randomly\n   */\n  wordWidths?: Array<number>;\n  /**\n   * Possible distance between words, will be picked randomly\n   */\n  wordDistances?: Array<number>;\n  /**\n   * Height of every word placeholder\n   */\n  wordHeight?: number;\n  /**\n   * Border radius of every word\n   */\n  wordRadius?: number;\n  /**\n   * Distance(margin) between the lines\n   */\n  lineDistance?: number;\n  /**\n   * Lines per paragraph\n   * if there are multiple paragraphs, all of them will have same number of lines\n   */\n  linesPerParagraph?: number;\n  /**\n   * Number of paragraphs in the placeholder\n   */\n  paragraphs?: number;\n  /**\n   * Distance(margin) between the paragraphs\n   */\n  paragraphDistance?: number;\n  /**\n   * Show less words in the last line for more natural feel\n   */\n  truncateLastLine?: boolean;\n  /**\n   * Render word with customizations\n   */\n  renderWord?: React.FC<RenderWordProps>;\n};\n\nconst Spectrum = ({\n  width = 500,\n  colors = ['#eee'],\n  wordWidths = [30, 60, 90, 120, 150],\n  wordDistances = [4, 8, 12],\n  wordHeight = 12,\n  wordRadius = 20,\n  linesPerParagraph = 8,\n  lineDistance = 12,\n  paragraphs = 1,\n  paragraphDistance = 24,\n  truncateLastLine = true,\n  renderWord = ({ key, style }: RenderWordProps): React.ReactElement => (\n    <span key={key} style={style} />\n  ),\n}: SpectrumProps): React.ReactElement => {\n  return (\n    <>\n      {new Array(paragraphs).fill(true).map((_, i) => {\n        const lines = new Array(linesPerParagraph).fill(true).map((__, j) => (\n          <div data-line={j} key={j}>\n            <DrawLine\n              width={width}\n              colors={colors}\n              wordWidths={wordWidths}\n              wordDistances={wordDistances}\n              wordHeight={wordHeight}\n              wordRadius={wordRadius}\n              lineDistance={lineDistance}\n              truncate={truncateLastLine ? j === linesPerParagraph - 1 : false}\n              renderWord={renderWord}\n            />\n          </div>\n        ));\n\n        return (\n          <div\n            data-paragraph={i}\n            key={i}\n            style={{\n              marginBottom: paragraphDistance,\n              fontSize: 0,\n            }}>\n            {lines}\n          </div>\n        );\n      })}\n    </>\n  );\n};\n\nexport default React.memo(Spectrum);\n"],"names":["arraysEqual","a","b","length","sortedA","sort","sortedB","i","getRandomInRange","min","max","mn","Math","ceil","mx","floor","random","getWords","width","colors","wordWidths","wordDistances","truncate","minWordWidth","maxWordsPerLine","wordForLine","words","totalWidth","wordWidth","wordDistance","totalWidthWithoutDistance","fitWord","fitWordWithDistance","last","reverse","distance","background","push","DrawLine$1","React","memo","wordHeight","wordRadius","lineDistance","renderWord","previous","value","ref","useRef","useEffect","current","usePrevious","setWords","useState","newWords","_jsx","jsx","_Fragment","Fragment","children","map","w","node","key","style","marginRight","height","display","borderRadius","marginBottom","Promise","Error","Spectrum$1","linesPerParagraph","paragraphs","paragraphDistance","truncateLastLine","Array","fill","_","lines","__","j","DrawLine","fontSize"],"mappings":"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"}