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/react.d.cts CHANGED
@@ -66,6 +66,11 @@ interface RenderOptions {
66
66
  projectType?: ProjectType;
67
67
  /** Override entry point detection. */
68
68
  entryPoint?: string;
69
+ /**
70
+ * Tailwind CSS handling. `'auto'` (default) loads Tailwind's Play CDN when the
71
+ * project is detected to use Tailwind; `true` forces it on; `false` disables it.
72
+ */
73
+ tailwind?: 'auto' | boolean;
69
74
  /** Glob patterns of files to include. */
70
75
  include?: string[];
71
76
  /** Glob patterns of files to exclude. */
@@ -125,6 +130,11 @@ interface DioramaProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onLoad' | '
125
130
  frame?: FrameStyle;
126
131
  /** Allow click-to-expand to fill viewport. Default: `false`. */
127
132
  expand?: boolean;
133
+ /**
134
+ * Tailwind CSS handling. `'auto'` (default) loads Tailwind's Play CDN when the
135
+ * project uses Tailwind; `true` forces it on; `false` disables it.
136
+ */
137
+ tailwind?: 'auto' | boolean;
128
138
  /** Called when rendering completes. */
129
139
  onLoad?: () => void;
130
140
  /** Called on error. */
package/dist/react.d.ts CHANGED
@@ -66,6 +66,11 @@ interface RenderOptions {
66
66
  projectType?: ProjectType;
67
67
  /** Override entry point detection. */
68
68
  entryPoint?: string;
69
+ /**
70
+ * Tailwind CSS handling. `'auto'` (default) loads Tailwind's Play CDN when the
71
+ * project is detected to use Tailwind; `true` forces it on; `false` disables it.
72
+ */
73
+ tailwind?: 'auto' | boolean;
69
74
  /** Glob patterns of files to include. */
70
75
  include?: string[];
71
76
  /** Glob patterns of files to exclude. */
@@ -125,6 +130,11 @@ interface DioramaProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onLoad' | '
125
130
  frame?: FrameStyle;
126
131
  /** Allow click-to-expand to fill viewport. Default: `false`. */
127
132
  expand?: boolean;
133
+ /**
134
+ * Tailwind CSS handling. `'auto'` (default) loads Tailwind's Play CDN when the
135
+ * project uses Tailwind; `true` forces it on; `false` disables it.
136
+ */
137
+ tailwind?: 'auto' | boolean;
128
138
  /** Called when rendering completes. */
129
139
  onLoad?: () => void;
130
140
  /** Called on error. */
package/dist/react.js CHANGED
@@ -624,6 +624,7 @@ function analyzeProject(project, overrideType, overrideEntry) {
624
624
  hasBareImports: hasBareImports(files),
625
625
  isVite
626
626
  });
627
+ const usesTailwind = usesTailwindCSS(files);
627
628
  return {
628
629
  type,
629
630
  entryPoint: htmlEntry,
@@ -632,7 +633,8 @@ function analyzeProject(project, overrideType, overrideEntry) {
632
633
  hasJSX,
633
634
  hasTypeScript,
634
635
  jsEntryPoint: jsEntry,
635
- isVite
636
+ isVite,
637
+ usesTailwind
636
638
  };
637
639
  }
638
640
  function detectProjectType(input) {
@@ -654,6 +656,17 @@ function hasBareImports(files) {
654
656
  }
655
657
  return false;
656
658
  }
659
+ function usesTailwindCSS(files) {
660
+ for (const [path, content] of files) {
661
+ if (/(?:^|\/)tailwind\.config\.(?:js|cjs|mjs|ts)$/.test(path)) {
662
+ return true;
663
+ }
664
+ if (path.endsWith(".css") && /@tailwind\b|@apply\b/.test(content)) {
665
+ return true;
666
+ }
667
+ }
668
+ return false;
669
+ }
657
670
 
658
671
  // src/core/sandbox.ts
659
672
  function buildErrorHTML(message) {
@@ -1738,20 +1751,25 @@ var ASSET_IMPORT_EXTENSIONS = {
1738
1751
  ".otf": "font/otf"
1739
1752
  };
1740
1753
  function assembleHTML(options) {
1741
- const { project, config, transformedFiles, cdnProvider } = options;
1754
+ const { project, config, transformedFiles, cdnProvider, tailwind = "auto" } = options;
1742
1755
  const files = transformedFiles ?? project.files;
1756
+ let result;
1743
1757
  switch (config.type) {
1744
1758
  case "static":
1745
- return assembleStatic(files, project, config);
1759
+ result = assembleStatic(files, project, config);
1760
+ break;
1746
1761
  case "static-esm":
1747
1762
  case "jsx":
1748
1763
  case "typescript":
1749
1764
  case "jsx-typescript":
1750
1765
  case "vite":
1751
- return assembleESM(files, project, config, cdnProvider);
1766
+ result = assembleESM(files, project, config, cdnProvider);
1767
+ break;
1752
1768
  default:
1753
1769
  throw new AssemblyError(`Unsupported project type: ${config.type}`);
1754
1770
  }
1771
+ result.html = applyTailwindRuntime(result.html, project, config, tailwind);
1772
+ return result;
1755
1773
  }
1756
1774
  function assembleStatic(files, project, config) {
1757
1775
  let html = files.get(config.entryPoint);
@@ -1821,6 +1839,7 @@ ${importMapJSON}
1821
1839
  );
1822
1840
  }
1823
1841
  }
1842
+ html = injectIntoHead(html, `<script>${HISTORY_GUARD_SCRIPT}</script>`);
1824
1843
  return { html, usesESM: true };
1825
1844
  }
1826
1845
  function generateHTMLShell(files, config) {
@@ -2077,6 +2096,96 @@ ${css}`);
2077
2096
  }
2078
2097
  return { css: cssChunks.join("\n\n"), links };
2079
2098
  }
2099
+ var TAILWIND_DIRECTIVE_RE = /@tailwind\b|@apply\b/;
2100
+ var TAILWIND_CDN_URL = "https://cdn.tailwindcss.com";
2101
+ function hasTailwindDirectives(css) {
2102
+ return TAILWIND_DIRECTIVE_RE.test(css);
2103
+ }
2104
+ function applyTailwindRuntime(html, project, config, tailwind) {
2105
+ const enabled = tailwind === true || tailwind === "auto" && (config.usesTailwind ?? usesTailwindCSS(project.files));
2106
+ if (!enabled) return html;
2107
+ html = html.replace(
2108
+ /<style>([\s\S]*?)<\/style>/g,
2109
+ (match, css) => hasTailwindDirectives(css) ? `<style type="text/tailwindcss">${css}</style>` : match
2110
+ );
2111
+ let injection = "";
2112
+ const configObject = extractTailwindConfig(project.files);
2113
+ if (configObject) {
2114
+ injection += `<script>window.tailwind = { config: ${configObject} };</script>
2115
+ `;
2116
+ }
2117
+ injection += `<script src="${TAILWIND_CDN_URL}" defer></script>`;
2118
+ return injectIntoHead(html, injection);
2119
+ }
2120
+ function extractTailwindConfig(files) {
2121
+ let source;
2122
+ for (const [path, content] of files) {
2123
+ if (/(?:^|\/)tailwind\.config\.(?:js|cjs|mjs|ts)$/.test(path)) {
2124
+ source = content;
2125
+ break;
2126
+ }
2127
+ }
2128
+ if (!source) return null;
2129
+ const object = extractBalancedObject(source);
2130
+ if (!object || !isSafeConfigObject(object)) return null;
2131
+ return object;
2132
+ }
2133
+ function extractBalancedObject(source) {
2134
+ const opener = source.match(/(?:export\s+default|module\.exports\s*=)\s*\{/);
2135
+ if (!opener || opener.index === void 0) return null;
2136
+ const start = opener.index + opener[0].length - 1;
2137
+ let depth = 0;
2138
+ let str = null;
2139
+ let lineComment = false;
2140
+ let blockComment = false;
2141
+ for (let i = start; i < source.length; i++) {
2142
+ const c = source[i];
2143
+ const n = source[i + 1];
2144
+ if (lineComment) {
2145
+ if (c === "\n") lineComment = false;
2146
+ continue;
2147
+ }
2148
+ if (blockComment) {
2149
+ if (c === "*" && n === "/") {
2150
+ blockComment = false;
2151
+ i++;
2152
+ }
2153
+ continue;
2154
+ }
2155
+ if (str) {
2156
+ if (c === "\\") {
2157
+ i++;
2158
+ continue;
2159
+ }
2160
+ if (c === str) str = null;
2161
+ continue;
2162
+ }
2163
+ if (c === "/" && n === "/") {
2164
+ lineComment = true;
2165
+ i++;
2166
+ continue;
2167
+ }
2168
+ if (c === "/" && n === "*") {
2169
+ blockComment = true;
2170
+ i++;
2171
+ continue;
2172
+ }
2173
+ if (c === '"' || c === "'" || c === "`") {
2174
+ str = c;
2175
+ continue;
2176
+ }
2177
+ if (c === "{") depth++;
2178
+ else if (c === "}") {
2179
+ depth--;
2180
+ if (depth === 0) return source.slice(start, i + 1);
2181
+ }
2182
+ }
2183
+ return null;
2184
+ }
2185
+ function isSafeConfigObject(object) {
2186
+ 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));
2187
+ }
2188
+ 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){}";
2080
2189
  function injectImportMetaEnv(files) {
2081
2190
  const shim = `if(!import.meta.env){Object.defineProperty(import.meta,'env',{value:{MODE:'production',BASE_URL:'/',PROD:true,DEV:false,SSR:false}});}`;
2082
2191
  for (const [path, content] of files) {
@@ -2187,7 +2296,8 @@ var Diorama = class {
2187
2296
  project,
2188
2297
  config,
2189
2298
  transformedFiles: files,
2190
- cdnProvider: this.options.cdnProvider
2299
+ cdnProvider: this.options.cdnProvider,
2300
+ tailwind: options.tailwind ?? "auto"
2191
2301
  });
2192
2302
  return { html: html2, usesESM: usesESM2, repoName: repoName2 };
2193
2303
  };
@@ -2300,6 +2410,7 @@ var DioramaPreview = forwardRef(
2300
2410
  height = "500px",
2301
2411
  frame,
2302
2412
  expand,
2413
+ tailwind,
2303
2414
  onLoad,
2304
2415
  onError,
2305
2416
  options,
@@ -2326,6 +2437,7 @@ var DioramaPreview = forwardRef(
2326
2437
  height,
2327
2438
  frame,
2328
2439
  expand,
2440
+ tailwind,
2329
2441
  onLoad,
2330
2442
  onError: (err) => {
2331
2443
  onError?.(err);
@@ -2346,7 +2458,7 @@ var DioramaPreview = forwardRef(
2346
2458
  instanceRef.current?.destroy();
2347
2459
  instanceRef.current = null;
2348
2460
  };
2349
- }, [repo, branch, subdirectory, loading, placeholder, height, frame, expand]);
2461
+ }, [repo, branch, subdirectory, loading, placeholder, height, frame, expand, tailwind]);
2350
2462
  const containerStyle = {
2351
2463
  width: "100%",
2352
2464
  minHeight: height,