diorama-js 0.1.0 → 0.2.0
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.cjs +156 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +156 -15
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +159 -16
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +10 -0
- package/dist/react.d.ts +10 -0
- package/dist/react.js +159 -16
- package/dist/react.js.map +1 -1
- package/dist/svelte.cjs +157 -15
- package/dist/svelte.cjs.map +1 -1
- package/dist/svelte.d.cts +10 -0
- package/dist/svelte.d.ts +10 -0
- package/dist/svelte.js +157 -15
- package/dist/svelte.js.map +1 -1
- package/dist/vue.cjs +159 -16
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.d.cts +8 -0
- package/dist/vue.d.ts +8 -0
- package/dist/vue.js +159 -16
- package/dist/vue.js.map +1 -1
- package/package.json +1 -1
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) {
|
|
@@ -1508,6 +1521,18 @@ function getCDNProvider(name) {
|
|
|
1508
1521
|
return esmShProvider;
|
|
1509
1522
|
}
|
|
1510
1523
|
}
|
|
1524
|
+
function buildCSSURL(specifier, options = {}) {
|
|
1525
|
+
const { dependencies = {}, cdnProvider = "esm.sh" } = options;
|
|
1526
|
+
const clean = specifier.replace(/[?#].*$/, "");
|
|
1527
|
+
const { packageName, subpath } = parseSpecifier(clean);
|
|
1528
|
+
const version = dependencies[packageName];
|
|
1529
|
+
const ver = version ? `@${version}` : "";
|
|
1530
|
+
const sub = subpath ? `/${subpath}` : "";
|
|
1531
|
+
if (cdnProvider === "unpkg") {
|
|
1532
|
+
return `https://unpkg.com/${packageName}${ver}${sub}`;
|
|
1533
|
+
}
|
|
1534
|
+
return `https://esm.sh/${packageName}${ver}${sub}`;
|
|
1535
|
+
}
|
|
1511
1536
|
function rewriteImports(source, options = {}) {
|
|
1512
1537
|
const {
|
|
1513
1538
|
dependencies = {},
|
|
@@ -1521,6 +1546,9 @@ function rewriteImports(source, options = {}) {
|
|
|
1521
1546
|
if (raw.startsWith(".") || raw.startsWith("/") || /^https?:\/\//.test(raw)) {
|
|
1522
1547
|
return raw;
|
|
1523
1548
|
}
|
|
1549
|
+
if (/\.css(?:[?#]|$)/.test(raw)) {
|
|
1550
|
+
return raw;
|
|
1551
|
+
}
|
|
1524
1552
|
const { packageName, subpath } = parseSpecifier(raw);
|
|
1525
1553
|
if (NODE_BUILTINS.has(packageName) || NODE_BUILTINS.has(packageName.replace("node:", ""))) {
|
|
1526
1554
|
throw new NodeBuiltinError(packageName);
|
|
@@ -1723,20 +1751,25 @@ var ASSET_IMPORT_EXTENSIONS = {
|
|
|
1723
1751
|
".otf": "font/otf"
|
|
1724
1752
|
};
|
|
1725
1753
|
function assembleHTML(options) {
|
|
1726
|
-
const { project, config, transformedFiles } = options;
|
|
1754
|
+
const { project, config, transformedFiles, cdnProvider, tailwind = "auto" } = options;
|
|
1727
1755
|
const files = transformedFiles ?? project.files;
|
|
1756
|
+
let result;
|
|
1728
1757
|
switch (config.type) {
|
|
1729
1758
|
case "static":
|
|
1730
|
-
|
|
1759
|
+
result = assembleStatic(files, project, config);
|
|
1760
|
+
break;
|
|
1731
1761
|
case "static-esm":
|
|
1732
1762
|
case "jsx":
|
|
1733
1763
|
case "typescript":
|
|
1734
1764
|
case "jsx-typescript":
|
|
1735
1765
|
case "vite":
|
|
1736
|
-
|
|
1766
|
+
result = assembleESM(files, project, config, cdnProvider);
|
|
1767
|
+
break;
|
|
1737
1768
|
default:
|
|
1738
1769
|
throw new AssemblyError(`Unsupported project type: ${config.type}`);
|
|
1739
1770
|
}
|
|
1771
|
+
result.html = applyTailwindRuntime(result.html, project, config, tailwind);
|
|
1772
|
+
return result;
|
|
1740
1773
|
}
|
|
1741
1774
|
function assembleStatic(files, project, config) {
|
|
1742
1775
|
let html = files.get(config.entryPoint);
|
|
@@ -1750,10 +1783,13 @@ function assembleStatic(files, project, config) {
|
|
|
1750
1783
|
html = inlineAssets(html, project, config.entryPoint);
|
|
1751
1784
|
return { html, usesESM: false };
|
|
1752
1785
|
}
|
|
1753
|
-
function assembleESM(files, project, config) {
|
|
1786
|
+
function assembleESM(files, project, config, cdnProvider) {
|
|
1754
1787
|
const isGenerated = config.entryPoint === "__generated__/index.html";
|
|
1755
1788
|
rewriteAssetImports(files, project);
|
|
1756
|
-
const cssFromJS = extractCSSImports(files
|
|
1789
|
+
const { css: cssFromJS, links: cssLinks } = extractCSSImports(files, {
|
|
1790
|
+
dependencies: config.dependencies,
|
|
1791
|
+
cdnProvider
|
|
1792
|
+
});
|
|
1757
1793
|
if (config.isVite) {
|
|
1758
1794
|
injectImportMetaEnv(files);
|
|
1759
1795
|
}
|
|
@@ -1772,6 +1808,9 @@ function assembleESM(files, project, config) {
|
|
|
1772
1808
|
html = rewriteScriptSrcsToImportMap(html, config.entryPoint);
|
|
1773
1809
|
html = inlineAssets(html, project, config.entryPoint);
|
|
1774
1810
|
}
|
|
1811
|
+
for (const href of cssLinks) {
|
|
1812
|
+
html = injectIntoHead(html, `<link rel="stylesheet" href="${href}">`);
|
|
1813
|
+
}
|
|
1775
1814
|
if (cssFromJS) {
|
|
1776
1815
|
html = injectIntoHead(html, `<style>
|
|
1777
1816
|
${cssFromJS}
|
|
@@ -2021,20 +2060,32 @@ function rewriteAssetImports(files, project) {
|
|
|
2021
2060
|
}
|
|
2022
2061
|
}
|
|
2023
2062
|
}
|
|
2024
|
-
function extractCSSImports(files) {
|
|
2063
|
+
function extractCSSImports(files, options = {}) {
|
|
2025
2064
|
const cssChunks = [];
|
|
2026
|
-
const
|
|
2065
|
+
const links = [];
|
|
2066
|
+
const seenLinks = /* @__PURE__ */ new Set();
|
|
2067
|
+
const cssImportRe = /import\s+['"]([^'"]+\.css(?:[?#][^'"]*)?)['"]\s*;?/g;
|
|
2027
2068
|
for (const [path, content] of files) {
|
|
2028
2069
|
if (!/\.(js|ts|jsx|tsx|mjs)$/.test(path)) continue;
|
|
2029
2070
|
let modified = content;
|
|
2030
2071
|
let match;
|
|
2072
|
+
cssImportRe.lastIndex = 0;
|
|
2031
2073
|
while ((match = cssImportRe.exec(content)) !== null) {
|
|
2032
|
-
const
|
|
2033
|
-
const
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2074
|
+
const specifier = match[1];
|
|
2075
|
+
const bare = specifier.replace(/[?#].*$/, "");
|
|
2076
|
+
if (bare.startsWith(".") || bare.startsWith("/")) {
|
|
2077
|
+
const resolved = resolvePath(directoryOf(path), bare);
|
|
2078
|
+
const css = files.get(resolved);
|
|
2079
|
+
if (css) {
|
|
2080
|
+
cssChunks.push(`/* ${resolved} */
|
|
2037
2081
|
${css}`);
|
|
2082
|
+
}
|
|
2083
|
+
} else {
|
|
2084
|
+
const href = /^https?:\/\//.test(bare) ? bare : buildCSSURL(bare, options);
|
|
2085
|
+
if (!seenLinks.has(href)) {
|
|
2086
|
+
seenLinks.add(href);
|
|
2087
|
+
links.push(href);
|
|
2088
|
+
}
|
|
2038
2089
|
}
|
|
2039
2090
|
modified = modified.replace(match[0], "");
|
|
2040
2091
|
}
|
|
@@ -2042,7 +2093,95 @@ ${css}`);
|
|
|
2042
2093
|
files.set(path, modified);
|
|
2043
2094
|
}
|
|
2044
2095
|
}
|
|
2045
|
-
return cssChunks.join("\n\n");
|
|
2096
|
+
return { css: cssChunks.join("\n\n"), links };
|
|
2097
|
+
}
|
|
2098
|
+
var TAILWIND_DIRECTIVE_RE = /@tailwind\b|@apply\b/;
|
|
2099
|
+
var TAILWIND_CDN_URL = "https://cdn.tailwindcss.com";
|
|
2100
|
+
function hasTailwindDirectives(css) {
|
|
2101
|
+
return TAILWIND_DIRECTIVE_RE.test(css);
|
|
2102
|
+
}
|
|
2103
|
+
function applyTailwindRuntime(html, project, config, tailwind) {
|
|
2104
|
+
const enabled = tailwind === true || tailwind === "auto" && (config.usesTailwind ?? usesTailwindCSS(project.files));
|
|
2105
|
+
if (!enabled) return html;
|
|
2106
|
+
html = html.replace(
|
|
2107
|
+
/<style>([\s\S]*?)<\/style>/g,
|
|
2108
|
+
(match, css) => hasTailwindDirectives(css) ? `<style type="text/tailwindcss">${css}</style>` : match
|
|
2109
|
+
);
|
|
2110
|
+
let injection = `<script src="${TAILWIND_CDN_URL}"></script>`;
|
|
2111
|
+
const configObject = extractTailwindConfig(project.files);
|
|
2112
|
+
if (configObject) {
|
|
2113
|
+
injection += `
|
|
2114
|
+
<script>tailwind.config = ${configObject};</script>`;
|
|
2115
|
+
}
|
|
2116
|
+
return injectIntoHead(html, injection);
|
|
2117
|
+
}
|
|
2118
|
+
function extractTailwindConfig(files) {
|
|
2119
|
+
let source;
|
|
2120
|
+
for (const [path, content] of files) {
|
|
2121
|
+
if (/(?:^|\/)tailwind\.config\.(?:js|cjs|mjs|ts)$/.test(path)) {
|
|
2122
|
+
source = content;
|
|
2123
|
+
break;
|
|
2124
|
+
}
|
|
2125
|
+
}
|
|
2126
|
+
if (!source) return null;
|
|
2127
|
+
const object = extractBalancedObject(source);
|
|
2128
|
+
if (!object || !isSafeConfigObject(object)) return null;
|
|
2129
|
+
return object;
|
|
2130
|
+
}
|
|
2131
|
+
function extractBalancedObject(source) {
|
|
2132
|
+
const opener = source.match(/(?:export\s+default|module\.exports\s*=)\s*\{/);
|
|
2133
|
+
if (!opener || opener.index === void 0) return null;
|
|
2134
|
+
const start = opener.index + opener[0].length - 1;
|
|
2135
|
+
let depth = 0;
|
|
2136
|
+
let str = null;
|
|
2137
|
+
let lineComment = false;
|
|
2138
|
+
let blockComment = false;
|
|
2139
|
+
for (let i = start; i < source.length; i++) {
|
|
2140
|
+
const c = source[i];
|
|
2141
|
+
const n = source[i + 1];
|
|
2142
|
+
if (lineComment) {
|
|
2143
|
+
if (c === "\n") lineComment = false;
|
|
2144
|
+
continue;
|
|
2145
|
+
}
|
|
2146
|
+
if (blockComment) {
|
|
2147
|
+
if (c === "*" && n === "/") {
|
|
2148
|
+
blockComment = false;
|
|
2149
|
+
i++;
|
|
2150
|
+
}
|
|
2151
|
+
continue;
|
|
2152
|
+
}
|
|
2153
|
+
if (str) {
|
|
2154
|
+
if (c === "\\") {
|
|
2155
|
+
i++;
|
|
2156
|
+
continue;
|
|
2157
|
+
}
|
|
2158
|
+
if (c === str) str = null;
|
|
2159
|
+
continue;
|
|
2160
|
+
}
|
|
2161
|
+
if (c === "/" && n === "/") {
|
|
2162
|
+
lineComment = true;
|
|
2163
|
+
i++;
|
|
2164
|
+
continue;
|
|
2165
|
+
}
|
|
2166
|
+
if (c === "/" && n === "*") {
|
|
2167
|
+
blockComment = true;
|
|
2168
|
+
i++;
|
|
2169
|
+
continue;
|
|
2170
|
+
}
|
|
2171
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
2172
|
+
str = c;
|
|
2173
|
+
continue;
|
|
2174
|
+
}
|
|
2175
|
+
if (c === "{") depth++;
|
|
2176
|
+
else if (c === "}") {
|
|
2177
|
+
depth--;
|
|
2178
|
+
if (depth === 0) return source.slice(start, i + 1);
|
|
2179
|
+
}
|
|
2180
|
+
}
|
|
2181
|
+
return null;
|
|
2182
|
+
}
|
|
2183
|
+
function isSafeConfigObject(object) {
|
|
2184
|
+
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));
|
|
2046
2185
|
}
|
|
2047
2186
|
function injectImportMetaEnv(files) {
|
|
2048
2187
|
const shim = `if(!import.meta.env){Object.defineProperty(import.meta,'env',{value:{MODE:'production',BASE_URL:'/',PROD:true,DEV:false,SSR:false}});}`;
|
|
@@ -2153,7 +2292,9 @@ var Diorama = class {
|
|
|
2153
2292
|
const { html: html2, usesESM: usesESM2 } = assembleHTML({
|
|
2154
2293
|
project,
|
|
2155
2294
|
config,
|
|
2156
|
-
transformedFiles: files
|
|
2295
|
+
transformedFiles: files,
|
|
2296
|
+
cdnProvider: this.options.cdnProvider,
|
|
2297
|
+
tailwind: options.tailwind ?? "auto"
|
|
2157
2298
|
});
|
|
2158
2299
|
return { html: html2, usesESM: usesESM2, repoName: repoName2 };
|
|
2159
2300
|
};
|
|
@@ -2266,6 +2407,7 @@ var DioramaPreview = forwardRef(
|
|
|
2266
2407
|
height = "500px",
|
|
2267
2408
|
frame,
|
|
2268
2409
|
expand,
|
|
2410
|
+
tailwind,
|
|
2269
2411
|
onLoad,
|
|
2270
2412
|
onError,
|
|
2271
2413
|
options,
|
|
@@ -2292,6 +2434,7 @@ var DioramaPreview = forwardRef(
|
|
|
2292
2434
|
height,
|
|
2293
2435
|
frame,
|
|
2294
2436
|
expand,
|
|
2437
|
+
tailwind,
|
|
2295
2438
|
onLoad,
|
|
2296
2439
|
onError: (err) => {
|
|
2297
2440
|
onError?.(err);
|
|
@@ -2312,7 +2455,7 @@ var DioramaPreview = forwardRef(
|
|
|
2312
2455
|
instanceRef.current?.destroy();
|
|
2313
2456
|
instanceRef.current = null;
|
|
2314
2457
|
};
|
|
2315
|
-
}, [repo, branch, subdirectory, loading, placeholder, height, frame, expand]);
|
|
2458
|
+
}, [repo, branch, subdirectory, loading, placeholder, height, frame, expand, tailwind]);
|
|
2316
2459
|
const containerStyle = {
|
|
2317
2460
|
width: "100%",
|
|
2318
2461
|
minHeight: height,
|