{
  "version": 3,
  "sources": ["../../../../src/plugins/ThemePlugin.ts"],
  "sourcesContent": ["//\n// Copyright 2022 DXOS.org\n//\n\n/* eslint-disable no-console */\n\nimport tailwindcssPostcss from '@tailwindcss/postcss';\nimport tailwindcssVite from '@tailwindcss/vite';\nimport autoprefixer from 'autoprefixer';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport postcssImport from 'postcss-import';\nimport postcssNesting from 'postcss-nesting';\nimport { type HtmlTagDescriptor, type Plugin, type UserConfig } from 'vite';\n\n/**\n * CSS cascade layer order.\n * Must be established before any stylesheets load so that Tailwind's own @layer declarations don't override our ordering. Exported so consuming\n */\nexport const LAYER_ORDER = [\n  'properties',\n  'theme',\n  'dx-tokens',\n  'user-tokens',\n  'base',\n  'tw-base',\n  'dx-base',\n  'components',\n  'tw-components',\n  'dx-components',\n  'utilities',\n] as const;\n\nconst ROOT = '../../../../';\n\nexport type ThemePluginOptions = {\n  srcCssPath?: string;\n  virtualFileId?: string;\n  verbose?: boolean;\n};\n\n/**\n * Vite plugin to configure theme.\n * Returns the official Tailwind Vite plugin (persistent incremental scanner) alongside the theme plugin.\n */\nexport const ThemePlugin = (options: ThemePluginOptions): Plugin[] => {\n  // Prefer source CSS if available (monorepo dev), fall back to dist for installed package.\n  const srcThemePath = resolve(import.meta.dirname, ROOT, 'src/main.css');\n  const distThemePath = resolve(import.meta.dirname, '../main.css');\n  const isMonorepo = existsSync(srcThemePath);\n\n  // Static assets shipped via \"files\": [\"src\"] in package.json.\n  // Both monorepo and installed package resolve to the same src/plugins/ directory.\n  const pluginsDir = resolve(import.meta.dirname, ROOT, 'src/plugins');\n  const darkModeScriptPath = resolve(pluginsDir, 'dark-mode.ts');\n  const mainCssPath = resolve(pluginsDir, 'main.css');\n\n  const config = {\n    srcCssPath: options.srcCssPath ?? (isMonorepo ? srcThemePath : distThemePath),\n    virtualFileId: options.virtualFileId ?? '@dxos-theme',\n    verbose: options.verbose,\n  };\n\n  if (process.env.DEBUG || options.verbose) {\n    console.log('ThemePlugin:\\n', JSON.stringify(config, null, 2));\n  }\n\n  // Trailing-edge debounce handle for theme CSS reloads (see `handleHotUpdate`).\n  let themeReloadTimer: ReturnType<typeof setTimeout> | undefined;\n\n  const themePlugin: Plugin = {\n    name: 'vite-plugin-dxos-ui-theme',\n    config: (): UserConfig => {\n      return {\n        server: {\n          watch: {\n            // Stop build outputs from driving HMR — they are the root of the\n            // `main.css` HMR storm.\n            //\n            // Tailwind's `@source` scanning (see `src/main.css`) registers its\n            // scanned source files as Vite watch dependencies of the compiled\n            // theme CSS. Tailwind's own scanner respects `.gitignore` (and the\n            // `@source not` directives), so it never *scans* `dist/`. BUT the\n            // scanner hands Vite a coarse `dir-dependency` glob — e.g.\n            // `{**/*.html,**/*.ts,**/*.tsx}` — and Vite re-expands that glob\n            // itself, ignoring only `node_modules` (not `.gitignore`, not the\n            // `@source not` negations). The re-expansion therefore sweeps in\n            // every `packages/*/dist/**/*.d.ts` (`.d.ts` matches `**/*.ts`),\n            // making each emitted declaration file a watch-dependency of\n            // `main.css`. A single package rebuild emits dozens of `.d.ts` in a\n            // tight burst, and each write re-invalidates the theme — 40+ HMR\n            // pings for `main.css` in one second, repeating on every rebuild.\n            //\n            // Ignoring build outputs in the watcher is also semantically\n            // correct: in dev the workspace resolves `@dxos/*` via the `source`\n            // export condition (see `vite-plugin-import-source`), so `dist/`\n            // is never consumed at runtime and its churn should never trigger\n            // HMR. Vite concatenates these patterns with its built-in ignores\n            // (`**/node_modules/**`, `**/.git/**`, …), so this is purely\n            // additive.\n            //\n            // `<root>/.claude/**` covers agent worktrees checked out under the\n            // repo root (`.claude/worktrees/<name>/packages/**`): they are full\n            // source copies, so the glob re-expansion above sweeps them in and\n            // every agent-side edit burst or checkout invalidates the theme in\n            // the user's dev server. The pattern is anchored at the resolved\n            // repo root (not `**/.claude/**`) because chokidar matches against\n            // absolute paths — a bare pattern would match *everything* when the\n            // dev server itself runs from inside a worktree whose path contains\n            // a `.claude` segment. `*.log` covers runtime log sinks (e.g.\n            // vite-plugin-log's `app.log` in the app root), which are appended\n            // continuously at runtime and must never feed back into the\n            // watcher.\n            ignored: ['**/dist/**', '**/out/**', '**/*.log', `${resolve(import.meta.dirname, ROOT, '.claude')}/**`],\n          },\n        },\n        css: {\n          postcss: {\n            plugins: [\n              // Handles @import statements in CSS.\n              postcssImport(),\n              // Processes CSS nesting syntax.\n              postcssNesting(),\n              // Resolves @reference/@apply in `.pcss` files (e.g. lit-grid, lit-ui), which the\n              // @tailwindcss/vite plugin skips — its transform filter only matches `.css`.\n              // Theme `.css` files are compiled by @tailwindcss/vite first (enforce: 'pre'),\n              // so this plugin's quick-bail check passes them through untouched.\n              tailwindcssPostcss(),\n              // Adds vendor prefixes.\n              autoprefixer,\n            ],\n          },\n        },\n      };\n    },\n    resolveId: (id) => {\n      if (id === config.virtualFileId) {\n        return config.srcCssPath;\n      }\n    },\n    hotUpdate({ type, file, modules }) {\n      // Direct edits to CSS (the theme source or its imports) keep Vite's\n      // default immediate update for instant feedback while authoring styles.\n      if (this.environment.name !== 'client' || type !== 'update' || file.endsWith('.css')) {\n        return;\n      }\n\n      // Every content file Tailwind scans is registered as a dependency of the\n      // theme CSS — Vite models it as a file-only entry node whose importer is\n      // `main.css` — so each source-file save invalidates `main.css` and\n      // re-runs the monorepo-wide Tailwind scan. During an edit wave that\n      // serializes one full scan per save. Drop the theme-dep entries from the\n      // update (the changed module itself still hot-updates immediately) and\n      // reload the theme CSS once on the trailing edge of a quiet window, so a\n      // wave costs at most one scan.\n      const isThemeDep = (mod: (typeof modules)[number]): boolean =>\n        mod.file === config.srcCssPath ||\n        (mod.id === null &&\n          mod.importers.size > 0 &&\n          [...mod.importers].every((importer) => importer.file === config.srcCssPath));\n      if (!modules.some(isThemeDep)) {\n        return;\n      }\n\n      const environment = this.environment;\n      clearTimeout(themeReloadTimer);\n      themeReloadTimer = setTimeout(() => {\n        for (const mod of environment.moduleGraph.getModulesByFile(config.srcCssPath) ?? []) {\n          environment.reloadModule(mod).catch(() => {\n            // Server may be mid-restart; the next edit reschedules the reload.\n          });\n        }\n      }, 300);\n\n      return modules.filter((mod) => !isThemeDep(mod));\n    },\n    transformIndexHtml: () => {\n      // Apply .dark class to <html> synchronously before any scripts run, so that\n      // the critical CSS html.dark rules apply on the very first paint.\n      const darkModeTag: HtmlTagDescriptor = {\n        tag: 'script',\n        attrs: { 'data-dxos-theme': '' },\n        injectTo: 'head-prepend',\n        children: readFileSync(darkModeScriptPath, 'utf-8'),\n      };\n\n      // Establish cascade layer order before any stylesheet loads.\n      const layersTag: HtmlTagDescriptor = {\n        tag: 'style',\n        attrs: { 'data-dxos-layers': '' },\n        children: `@layer ${LAYER_ORDER.join(', ')};`,\n        injectTo: 'head-prepend',\n      };\n\n      // Critical styles: font sizing, overscroll, color fallbacks.\n      // Loaded from critical.css to keep styles maintainable and out of index.html.\n      const criticalTag: HtmlTagDescriptor = {\n        tag: 'style',\n        attrs: { 'data-dxos-critical': '' },\n        injectTo: 'head-prepend',\n        children: readFileSync(mainCssPath, 'utf-8'),\n      };\n\n      return [darkModeTag, layersTag, criticalTag];\n    },\n  };\n\n  // The Tailwind Vite plugins are `enforce: 'pre'`, so they compile theme CSS (resolving\n  // `@import 'tailwindcss'`, @source, @plugin, @theme) before the postcss chain runs —\n  // postcss-import never sees the raw Tailwind directives. Scan roots come from the @source\n  // directives in main.css (relative to that file); no project-root base is needed.\n  return [...tailwindcssVite(), themePlugin];\n};\n"],
  "mappings": ";;;AAMA,OAAOA,wBAAwB;AAC/B,OAAOC,qBAAqB;AAC5B,OAAOC,kBAAkB;AACzB,SAASC,YAAYC,oBAAoB;AACzC,SAASC,eAAe;AACxB,OAAOC,mBAAmB;AAC1B,OAAOC,oBAAoB;AAOpB,IAAMC,cAAc;EACzB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF,IAAMC,OAAO;AAYN,IAAMC,cAAc,CAACC,YAAAA;AAE1B,QAAMC,eAAeP,QAAQ,YAAYQ,SAASJ,MAAM,cAAA;AACxD,QAAMK,gBAAgBT,QAAQ,YAAYQ,SAAS,aAAA;AACnD,QAAME,aAAaZ,WAAWS,YAAAA;AAI9B,QAAMI,aAAaX,QAAQ,YAAYQ,SAASJ,MAAM,aAAA;AACtD,QAAMQ,qBAAqBZ,QAAQW,YAAY,cAAA;AAC/C,QAAME,cAAcb,QAAQW,YAAY,UAAA;AAExC,QAAMG,SAAS;IACbC,YAAYT,QAAQS,eAAeL,aAAaH,eAAeE;IAC/DO,eAAeV,QAAQU,iBAAiB;IACxCC,SAASX,QAAQW;EACnB;AAEA,MAAIC,QAAQC,IAAIC,SAASd,QAAQW,SAAS;AACxCI,YAAQC,IAAI,kBAAkBC,KAAKC,UAAUV,QAAQ,MAAM,CAAA,CAAA;EAC7D;AAGA,MAAIW;AAEJ,QAAMC,cAAsB;IAC1BC,MAAM;IACNb,QAAQ,MAAA;AACN,aAAO;QACLc,QAAQ;UACNC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAsCLC,SAAS;cAAC;cAAc;cAAa;cAAY,GAAG9B,QAAQ,YAAYQ,SAASJ,MAAM,SAAA,CAAA;;UACzF;QACF;QACA2B,KAAK;UACHC,SAAS;YACPC,SAAS;;cAEPhC,cAAAA;;cAEAC,eAAAA;;;;;cAKAP,mBAAAA;;cAEAE;;UAEJ;QACF;MACF;IACF;IACAqC,WAAW,CAACC,OAAAA;AACV,UAAIA,OAAOrB,OAAOE,eAAe;AAC/B,eAAOF,OAAOC;MAChB;IACF;IACAqB,UAAU,EAAEC,MAAMC,MAAMC,QAAO,GAAE;AAG/B,UAAI,KAAKC,YAAYb,SAAS,YAAYU,SAAS,YAAYC,KAAKG,SAAS,MAAA,GAAS;AACpF;MACF;AAUA,YAAMC,aAAa,CAACC,QAClBA,IAAIL,SAASxB,OAAOC,cACnB4B,IAAIR,OAAO,QACVQ,IAAIC,UAAUC,OAAO,KACrB;WAAIF,IAAIC;QAAWE,MAAM,CAACC,aAAaA,SAAST,SAASxB,OAAOC,UAAU;AAC9E,UAAI,CAACwB,QAAQS,KAAKN,UAAAA,GAAa;AAC7B;MACF;AAEA,YAAMF,cAAc,KAAKA;AACzBS,mBAAaxB,gBAAAA;AACbA,yBAAmByB,WAAW,MAAA;AAC5B,mBAAWP,OAAOH,YAAYW,YAAYC,iBAAiBtC,OAAOC,UAAU,KAAK,CAAA,GAAI;AACnFyB,sBAAYa,aAAaV,GAAAA,EAAKW,MAAM,MAAA;UAEpC,CAAA;QACF;MACF,GAAG,GAAA;AAEH,aAAOf,QAAQgB,OAAO,CAACZ,QAAQ,CAACD,WAAWC,GAAAA,CAAAA;IAC7C;IACAa,oBAAoB,MAAA;AAGlB,YAAMC,cAAiC;QACrCC,KAAK;QACLC,OAAO;UAAE,mBAAmB;QAAG;QAC/BC,UAAU;QACVC,UAAU9D,aAAaa,oBAAoB,OAAA;MAC7C;AAGA,YAAMkD,YAA+B;QACnCJ,KAAK;QACLC,OAAO;UAAE,oBAAoB;QAAG;QAChCE,UAAU,UAAU1D,YAAY4D,KAAK,IAAA,CAAA;QACrCH,UAAU;MACZ;AAIA,YAAMI,cAAiC;QACrCN,KAAK;QACLC,OAAO;UAAE,sBAAsB;QAAG;QAClCC,UAAU;QACVC,UAAU9D,aAAac,aAAa,OAAA;MACtC;AAEA,aAAO;QAAC4C;QAAaK;QAAWE;;IAClC;EACF;AAMA,SAAO;OAAIpE,gBAAAA;IAAmB8B;;AAChC;",
  "names": ["tailwindcssPostcss", "tailwindcssVite", "autoprefixer", "existsSync", "readFileSync", "resolve", "postcssImport", "postcssNesting", "LAYER_ORDER", "ROOT", "ThemePlugin", "options", "srcThemePath", "dirname", "distThemePath", "isMonorepo", "pluginsDir", "darkModeScriptPath", "mainCssPath", "config", "srcCssPath", "virtualFileId", "verbose", "process", "env", "DEBUG", "console", "log", "JSON", "stringify", "themeReloadTimer", "themePlugin", "name", "server", "watch", "ignored", "css", "postcss", "plugins", "resolveId", "id", "hotUpdate", "type", "file", "modules", "environment", "endsWith", "isThemeDep", "mod", "importers", "size", "every", "importer", "some", "clearTimeout", "setTimeout", "moduleGraph", "getModulesByFile", "reloadModule", "catch", "filter", "transformIndexHtml", "darkModeTag", "tag", "attrs", "injectTo", "children", "layersTag", "join", "criticalTag"]
}
