{
  "version": 3,
  "sources": ["../../src/observe/index.ts", "../../src/internal/util.ts"],
  "sourcesContent": ["/**\n * [[include:src/observe/README.md]]\n *\n * @packageDocumentation\n * @module twind/observe\n */\n\nimport type { TW } from '../types'\nimport { tw as defaultTW } from '../index'\nimport { ensureMaxSize } from '../internal/util'\n\n/**\n * Options for {@link createObserver}.\n */\nexport interface ShimConfiguration {\n  /**\n   * Custom {@link twind.tw | tw} instance to use (default: {@link twind.tw}).\n   */\n  tw?: TW\n}\n\n/** Provides the ability to watch for changes being made to the DOM tree. */\nexport interface TwindObserver {\n  /**\n   * Stops observer from observing any mutations.\n   */\n  disconnect(): TwindObserver\n\n  /**\n   * Observe an additional element.\n   */\n  observe(target: Node): TwindObserver\n}\n\nconst caches = new WeakMap<TW, Map<string, string>>()\n\nconst getCache = (tw: TW): Map<string, string> => {\n  let rulesToClassCache = caches.get(tw)\n\n  if (!rulesToClassCache) {\n    rulesToClassCache = new Map<string, string>()\n    caches.set(tw, rulesToClassCache)\n  }\n\n  return rulesToClassCache\n}\n\n/**\n * Creates a new {@link TwindObserver}.\n *\n * @param options to use\n */\nexport const createObserver = ({ tw = defaultTW }: ShimConfiguration = {}): TwindObserver => {\n  const rulesToClassCache = getCache(tw)\n\n  const handleMutation = ({ target, addedNodes }: MinimalMutationRecord): void => {\n    // Not using target.classList.value (not supported in all browsers) or target.class (this is an SVGAnimatedString for svg)\n    const rules = (target as Element).getAttribute?.('class')\n\n    if (rules) {\n      let className = rulesToClassCache.get(rules)\n\n      if (!className) {\n        className = tw(rules)\n\n        // Remember the generated class name\n        rulesToClassCache.set(rules, className)\n\n        // Ensure the cache does not grow unlimited\n        ensureMaxSize(rulesToClassCache, 10000)\n      }\n\n      if (rules !== className) {\n        // Not using `target.className = ...` as that is read-only for SVGElements\n        // eslint-disable-next-line @typescript-eslint/no-extra-semi\n        ;(target as Element).setAttribute('class', className)\n      }\n    }\n\n    for (let index = addedNodes.length; index--; ) {\n      const node = addedNodes[index]\n\n      handleMutations([\n        {\n          target: node,\n          addedNodes: (node as Element).children || [],\n        },\n      ])\n    }\n  }\n\n  const handleMutations = (mutations: MinimalMutationRecord[]): void =>\n    mutations.forEach(handleMutation)\n\n  if (typeof MutationObserver === 'function') {\n    const observer = new MutationObserver(handleMutations)\n\n    return {\n      observe(target) {\n        handleMutations([{ target, addedNodes: [target] }])\n\n        observer.observe(target, {\n          attributes: true,\n          attributeFilter: ['class'],\n          subtree: true,\n          childList: true,\n        })\n\n        return this\n      },\n\n      disconnect() {\n        observer.disconnect()\n        return this\n      },\n    }\n  }\n\n  // Non-browser-like environment – return a no-op implementation\n  return {\n    observe() {\n      return this\n    },\n\n    disconnect() {\n      return this\n    },\n  }\n}\n\n/**\n * Creates a new {@link TwindObserver} and {@link TwindObserver.observe | start observing} the passed target element.\n * @param this to bind\n * @param target to shim\n * @param config to use\n */\nexport function observe(\n  this: ShimConfiguration | undefined | void,\n  target: Node,\n  config: ShimConfiguration | undefined | void = this,\n): TwindObserver {\n  return createObserver(config as ShimConfiguration | undefined).observe(target)\n}\n\n/**\n * Simplified MutationRecord which allows use to pass an\n * ArrayLike (compatible with Array and NodeList) `addedNodes` and\n * omit other properties we are not interested in.\n */\ninterface MinimalMutationRecord {\n  readonly addedNodes: ArrayLike<Node>\n  readonly target: Node\n}\n", "import type {\n  Context,\n  Hasher,\n  Falsy,\n  MaybeThunk,\n  CSSRules,\n  ThemeScreen,\n  ThemeScreenValue,\n} from '../types'\n\ninterface Includes {\n  (value: string, search: string): boolean\n  <T>(value: readonly T[], search: T): boolean\n}\n\nexport const includes: Includes = (value: string | readonly unknown[], search: unknown) =>\n  // eslint-disable-next-line no-implicit-coercion\n  !!~(value as string).indexOf(search as string)\n\nexport const join = (parts: readonly string[], separator = '-'): string => parts.join(separator)\n\nexport const joinTruthy = (parts: readonly (string | Falsy)[], separator?: string): string =>\n  join(parts.filter(Boolean) as string[], separator)\n\nexport const tail = <T extends string | readonly unknown[]>(array: T, startIndex = 1): T =>\n  array.slice(startIndex) as T\n\nexport const identity = <T>(value: T): T => value\n\nexport const noop = (): void => {\n  /* no-op */\n}\n\nexport const capitalize = (value: string): string => value[0].toUpperCase() + tail(value)\n\nexport const hyphenate = (value: string): string => value.replace(/[A-Z]/g, '-$&').toLowerCase()\n\nexport const evalThunk = <T>(value: MaybeThunk<T>, context: Context): T => {\n  while (typeof value === 'function') {\n    value = (value as (context: Context) => T)(context)\n  }\n\n  return value\n}\n\nexport const ensureMaxSize = <K, V>(map: Map<K, V>, max: number): void => {\n  // Ensure the cache does not grow unlimited\n  if (map.size > max) {\n    map.delete(map.keys().next().value)\n  }\n}\n\nexport const merge = (target: CSSRules, source: CSSRules, context: Context): CSSRules =>\n  source\n    ? Object.keys(source).reduce((target, key) => {\n        const value = evalThunk(source[key], context)\n\n        if (value && typeof value === 'object' && !Array.isArray(value)) {\n          target[key] = merge((target[key] || {}) as CSSRules, value as CSSRules, context)\n        } else {\n          // hyphenate target key only if key is property like (\\w-)\n          target[hyphenate(key)] = value\n        }\n\n        return target\n      }, target)\n    : target\n\nexport const escape =\n  (typeof CSS !== 'undefined' && CSS.escape) ||\n  // Simplified: escaping only special characters\n  // Needed for NodeJS and Edge <79 (https://caniuse.com/mdn-api_css_escape)\n  ((className: string): string => {\n    const firstCodeUnit = className.charCodeAt(0)\n    let firstChar = ''\n\n    // If the character is the first character and is in the range [0-9] (2xl, ...)\n    if (firstCodeUnit >= 0x0030 && firstCodeUnit <= 0x0039) {\n      // https://drafts.csswg.org/cssom/#escape-a-character-as-code-point\n      firstChar = '\\\\' + firstCodeUnit.toString(16) + ' '\n      className = tail(className)\n    }\n\n    // Simplifed escape testing only for chars that we know happen to be in tailwind directives\n    return firstChar + className.replace(/[!./:#]/g, '\\\\$&')\n  })\n\nexport const buildMediaQuery = (screen: ThemeScreen): string => {\n  if (!Array.isArray(screen)) {\n    screen = [screen as ThemeScreenValue]\n  }\n\n  return (\n    '@media ' +\n    join(\n      (screen as ThemeScreenValue[]).map((screen) => {\n        if (typeof screen === 'string') {\n          screen = { min: screen }\n        }\n\n        return (\n          (screen as { raw?: string }).raw ||\n          join(\n            Object.keys(screen).map(\n              (feature) => `(${feature}-width:${(screen as Record<string, string>)[feature]})`,\n            ),\n            ' and ',\n          )\n        )\n      }),\n      ',',\n    )\n  )\n}\n\n// Based on https://stackoverflow.com/a/52171480\nexport const cyrb32: Hasher = (value: string): string => {\n  let h = 9\n\n  for (let index = value.length; index--; ) {\n    h = Math.imul(h ^ value.charCodeAt(index), 0x5f356495)\n  }\n\n  return 'tw-' + ((h ^ (h >>> 9)) >>> 0).toString(36)\n}\n\n/**\n * Find the array index of where to add an element to keep it sorted.\n *\n * @returns The insertion index\n */\nexport const sortedInsertionIndex = (array: readonly number[], element: number): number => {\n  let high = array.length\n\n  // Theres only one option then\n  if (high === 0) return 0\n\n  // Find position by binary search\n  for (let low = 0; low < high; ) {\n    const pivot = (high + low) >> 1\n\n    // Less-Then-Equal to add new equal element after all existing equal elements (stable sort)\n    if (array[pivot] <= element) {\n      low = pivot + 1\n    } else {\n      high = pivot\n    }\n  }\n\n  return high\n}\n"],
  "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA,eAAgC;;;ACgBzB,IAAM,OAAO,CAAwC,OAAU,aAAa,MACjF,MAAM,MAAM;AAoBP,IAAM,gBAAgB,CAAO,KAAgB;AAElD,MAAI,IAAI,OAAO;AACb,QAAI,OAAO,IAAI,OAAO,OAAO;AAAA;AAAA;AAoB1B,IAAM,SACV,OAAO,QAAQ,eAAe,IAAI,UAGlC,EAAC;AACA,QAAM,gBAAgB,UAAU,WAAW;AAC3C,MAAI,YAAY;AAGhB,MAAI,iBAAiB,MAAU,iBAAiB;AAE9C,gBAAY,OAAO,cAAc,SAAS,MAAM;AAChD,gBAAY,KAAK;AAAA;AAInB,SAAO,YAAY,UAAU,QAAQ,YAAY;AAAA;;;ADlDrD,IAAM,SAAS,IAAI;AAEnB,IAAM,WAAW,CAAC;AAChB,MAAI,oBAAoB,OAAO,IAAI;AAEnC,MAAI,CAAC;AACH,wBAAoB,IAAI;AACxB,WAAO,IAAI,IAAI;AAAA;AAGjB,SAAO;AAAA;AAQF,IAAM,iBAAiB,CAAC,CAAE,KAAK,eAAiC;AACrE,QAAM,oBAAoB,SAAS;AAEnC,QAAM,iBAAiB,CAAC,CAAE,QAAQ;AAvDpC;AAyDI,UAAM,QAAS,aAAmB,iBAAnB,gCAAkC;AAEjD,QAAI;AACF,UAAI,YAAY,kBAAkB,IAAI;AAEtC,UAAI,CAAC;AACH,oBAAY,GAAG;AAGf,0BAAkB,IAAI,OAAO;AAG7B,sBAAc,mBAAmB;AAAA;AAGnC,UAAI,UAAU;AAGZ;AAAC,QAAC,OAAmB,aAAa,SAAS;AAAA;AAAA;AAI/C,aAAS,QAAQ,WAAW,QAAQ;AAClC,YAAM,OAAO,WAAW;AAExB,sBAAgB;AAAA,QACd;AAAA,UACE,QAAQ;AAAA,UACR,YAAa,KAAiB,YAAY;AAAA;AAAA;AAAA;AAAA;AAMlD,QAAM,kBAAkB,CAAC,cACvB,UAAU,QAAQ;AAEpB,MAAI,OAAO,qBAAqB;AAC9B,UAAM,WAAW,IAAI,iBAAiB;AAEtC,WAAO;AAAA,MACL,QAAQ;AACN,wBAAgB,CAAC,CAAE,QAAQ,YAAY,CAAC;AAExC,iBAAS,QAAQ,QAAQ;AAAA,UACvB,YAAY;AAAA,UACZ,iBAAiB,CAAC;AAAA,UAClB,SAAS;AAAA,UACT,WAAW;AAAA;AAGb,eAAO;AAAA;AAAA,MAGT;AACE,iBAAS;AACT,eAAO;AAAA;AAAA;AAAA;AAMb,SAAO;AAAA,IACL;AACE,aAAO;AAAA;AAAA,IAGT;AACE,aAAO;AAAA;AAAA;AAAA;AAWN,iBAEL,QACA,SAA+C;AAE/C,SAAO,eAAe,QAAyC,QAAQ;AAAA;",
  "names": []
}
