diorama-js 0.1.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -85,6 +85,8 @@ interface ProjectConfig {
85
85
  jsEntryPoint?: string;
86
86
  /** Whether the project uses Vite as its build tool. */
87
87
  isVite: boolean;
88
+ /** Whether the project relies on Tailwind CSS (directives or a config file). */
89
+ usesTailwind?: boolean;
88
90
  }
89
91
  type CDNProviderName = 'esm.sh' | 'skypack' | 'unpkg';
90
92
  type CacheStrategy = 'normal' | 'aggressive';
@@ -141,6 +143,11 @@ interface RenderOptions {
141
143
  projectType?: ProjectType;
142
144
  /** Override entry point detection. */
143
145
  entryPoint?: string;
146
+ /**
147
+ * Tailwind CSS handling. `'auto'` (default) loads Tailwind's Play CDN when the
148
+ * project is detected to use Tailwind; `true` forces it on; `false` disables it.
149
+ */
150
+ tailwind?: 'auto' | boolean;
144
151
  /** Glob patterns of files to include. */
145
152
  include?: string[];
146
153
  /** Glob patterns of files to exclude. */
package/dist/index.d.ts CHANGED
@@ -85,6 +85,8 @@ interface ProjectConfig {
85
85
  jsEntryPoint?: string;
86
86
  /** Whether the project uses Vite as its build tool. */
87
87
  isVite: boolean;
88
+ /** Whether the project relies on Tailwind CSS (directives or a config file). */
89
+ usesTailwind?: boolean;
88
90
  }
89
91
  type CDNProviderName = 'esm.sh' | 'skypack' | 'unpkg';
90
92
  type CacheStrategy = 'normal' | 'aggressive';
@@ -141,6 +143,11 @@ interface RenderOptions {
141
143
  projectType?: ProjectType;
142
144
  /** Override entry point detection. */
143
145
  entryPoint?: string;
146
+ /**
147
+ * Tailwind CSS handling. `'auto'` (default) loads Tailwind's Play CDN when the
148
+ * project is detected to use Tailwind; `true` forces it on; `false` disables it.
149
+ */
150
+ tailwind?: 'auto' | boolean;
144
151
  /** Glob patterns of files to include. */
145
152
  include?: string[];
146
153
  /** Glob patterns of files to exclude. */
package/dist/index.js CHANGED
@@ -638,6 +638,7 @@ function analyzeProject(project, overrideType, overrideEntry) {
638
638
  hasBareImports: hasBareImports(files),
639
639
  isVite
640
640
  });
641
+ const usesTailwind = usesTailwindCSS(files);
641
642
  return {
642
643
  type,
643
644
  entryPoint: htmlEntry,
@@ -646,7 +647,8 @@ function analyzeProject(project, overrideType, overrideEntry) {
646
647
  hasJSX,
647
648
  hasTypeScript,
648
649
  jsEntryPoint: jsEntry,
649
- isVite
650
+ isVite,
651
+ usesTailwind
650
652
  };
651
653
  }
652
654
  function detectProjectType(input) {
@@ -668,6 +670,17 @@ function hasBareImports(files) {
668
670
  }
669
671
  return false;
670
672
  }
673
+ function usesTailwindCSS(files) {
674
+ for (const [path, content] of files) {
675
+ if (/(?:^|\/)tailwind\.config\.(?:js|cjs|mjs|ts)$/.test(path)) {
676
+ return true;
677
+ }
678
+ if (path.endsWith(".css") && /@tailwind\b|@apply\b/.test(content)) {
679
+ return true;
680
+ }
681
+ }
682
+ return false;
683
+ }
671
684
 
672
685
  // src/core/sandbox.ts
673
686
  function buildErrorHTML(message) {
@@ -1752,20 +1765,25 @@ var ASSET_IMPORT_EXTENSIONS = {
1752
1765
  ".otf": "font/otf"
1753
1766
  };
1754
1767
  function assembleHTML(options) {
1755
- const { project, config, transformedFiles, cdnProvider } = options;
1768
+ const { project, config, transformedFiles, cdnProvider, tailwind = "auto" } = options;
1756
1769
  const files = transformedFiles ?? project.files;
1770
+ let result;
1757
1771
  switch (config.type) {
1758
1772
  case "static":
1759
- return assembleStatic(files, project, config);
1773
+ result = assembleStatic(files, project, config);
1774
+ break;
1760
1775
  case "static-esm":
1761
1776
  case "jsx":
1762
1777
  case "typescript":
1763
1778
  case "jsx-typescript":
1764
1779
  case "vite":
1765
- return assembleESM(files, project, config, cdnProvider);
1780
+ result = assembleESM(files, project, config, cdnProvider);
1781
+ break;
1766
1782
  default:
1767
1783
  throw new AssemblyError(`Unsupported project type: ${config.type}`);
1768
1784
  }
1785
+ result.html = applyTailwindRuntime(result.html, project, config, tailwind);
1786
+ return result;
1769
1787
  }
1770
1788
  function assembleStatic(files, project, config) {
1771
1789
  let html = files.get(config.entryPoint);
@@ -1835,6 +1853,7 @@ ${importMapJSON}
1835
1853
  );
1836
1854
  }
1837
1855
  }
1856
+ html = injectIntoHead(html, `<script>${HISTORY_GUARD_SCRIPT}</script>`);
1838
1857
  return { html, usesESM: true };
1839
1858
  }
1840
1859
  function generateHTMLShell(files, config) {
@@ -2091,6 +2110,96 @@ ${css}`);
2091
2110
  }
2092
2111
  return { css: cssChunks.join("\n\n"), links };
2093
2112
  }
2113
+ var TAILWIND_DIRECTIVE_RE = /@tailwind\b|@apply\b/;
2114
+ var TAILWIND_CDN_URL = "https://cdn.tailwindcss.com";
2115
+ function hasTailwindDirectives(css) {
2116
+ return TAILWIND_DIRECTIVE_RE.test(css);
2117
+ }
2118
+ function applyTailwindRuntime(html, project, config, tailwind) {
2119
+ const enabled = tailwind === true || tailwind === "auto" && (config.usesTailwind ?? usesTailwindCSS(project.files));
2120
+ if (!enabled) return html;
2121
+ html = html.replace(
2122
+ /<style>([\s\S]*?)<\/style>/g,
2123
+ (match, css) => hasTailwindDirectives(css) ? `<style type="text/tailwindcss">${css}</style>` : match
2124
+ );
2125
+ let injection = "";
2126
+ const configObject = extractTailwindConfig(project.files);
2127
+ if (configObject) {
2128
+ injection += `<script>window.tailwind = { config: ${configObject} };</script>
2129
+ `;
2130
+ }
2131
+ injection += `<script src="${TAILWIND_CDN_URL}" defer></script>`;
2132
+ return injectIntoHead(html, injection);
2133
+ }
2134
+ function extractTailwindConfig(files) {
2135
+ let source;
2136
+ for (const [path, content] of files) {
2137
+ if (/(?:^|\/)tailwind\.config\.(?:js|cjs|mjs|ts)$/.test(path)) {
2138
+ source = content;
2139
+ break;
2140
+ }
2141
+ }
2142
+ if (!source) return null;
2143
+ const object = extractBalancedObject(source);
2144
+ if (!object || !isSafeConfigObject(object)) return null;
2145
+ return object;
2146
+ }
2147
+ function extractBalancedObject(source) {
2148
+ const opener = source.match(/(?:export\s+default|module\.exports\s*=)\s*\{/);
2149
+ if (!opener || opener.index === void 0) return null;
2150
+ const start = opener.index + opener[0].length - 1;
2151
+ let depth = 0;
2152
+ let str = null;
2153
+ let lineComment = false;
2154
+ let blockComment = false;
2155
+ for (let i = start; i < source.length; i++) {
2156
+ const c = source[i];
2157
+ const n = source[i + 1];
2158
+ if (lineComment) {
2159
+ if (c === "\n") lineComment = false;
2160
+ continue;
2161
+ }
2162
+ if (blockComment) {
2163
+ if (c === "*" && n === "/") {
2164
+ blockComment = false;
2165
+ i++;
2166
+ }
2167
+ continue;
2168
+ }
2169
+ if (str) {
2170
+ if (c === "\\") {
2171
+ i++;
2172
+ continue;
2173
+ }
2174
+ if (c === str) str = null;
2175
+ continue;
2176
+ }
2177
+ if (c === "/" && n === "/") {
2178
+ lineComment = true;
2179
+ i++;
2180
+ continue;
2181
+ }
2182
+ if (c === "/" && n === "*") {
2183
+ blockComment = true;
2184
+ i++;
2185
+ continue;
2186
+ }
2187
+ if (c === '"' || c === "'" || c === "`") {
2188
+ str = c;
2189
+ continue;
2190
+ }
2191
+ if (c === "{") depth++;
2192
+ else if (c === "}") {
2193
+ depth--;
2194
+ if (depth === 0) return source.slice(start, i + 1);
2195
+ }
2196
+ }
2197
+ return null;
2198
+ }
2199
+ function isSafeConfigObject(object) {
2200
+ return !(/\brequire\s*\(/.test(object) || /\bimport\b/.test(object) || /=>/.test(object) || /\bfunction\b/.test(object) || /`/.test(object) || /\bprocess\b/.test(object) || /\b__dirname\b|\b__filename\b/.test(object));
2201
+ }
2202
+ var HISTORY_GUARD_SCRIPT = "try{for(const m of ['pushState','replaceState']){const orig=history[m].bind(history);history[m]=function(state,title,url){try{return orig(state,title,url);}catch(e){try{return orig(state,title);}catch(e2){}}};}}catch(e){}";
2094
2203
  function injectImportMetaEnv(files) {
2095
2204
  const shim = `if(!import.meta.env){Object.defineProperty(import.meta,'env',{value:{MODE:'production',BASE_URL:'/',PROD:true,DEV:false,SSR:false}});}`;
2096
2205
  for (const [path, content] of files) {
@@ -2201,7 +2310,8 @@ var Diorama = class {
2201
2310
  project,
2202
2311
  config,
2203
2312
  transformedFiles: files,
2204
- cdnProvider: this.options.cdnProvider
2313
+ cdnProvider: this.options.cdnProvider,
2314
+ tailwind: options.tailwind ?? "auto"
2205
2315
  });
2206
2316
  return { html: html2, usesESM: usesESM2, repoName: repoName2 };
2207
2317
  };