tempest-react-sdk 0.59.0 → 0.61.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.
@@ -0,0 +1,5 @@
1
+ let e=require("node:path"),t=require("node:fs/promises"),n=require("node:fs"),r=require("node:url");var i=`tempest-react-sdk/styles/auto.css`,a=`\0tempest-styles/auto.css`,o=/^tempest-react-sdk(\/(charts|editor|br|icons))?$/,s=/\.[cm]?[jt]sx?$/,c=new Set([`node_modules`,`dist`,`build`,`coverage`]);function l(e){let t=new Set;for(let n of e.matchAll(/\bimport\s+(type\s+)?([^;'"]*?)\s+from\s*["']([^"']+)["']/g)){let[,e,r,i]=n;if(!o.test(i??``)||e)continue;if(/^\s*\*\s+as\s/.test(r??``))return null;let a=/\{([^}]*)\}/.exec(r??``);if(a)for(let e of(a[1]??``).split(`,`)){let n=e.trim();if(!n||n.startsWith(`type `))continue;let r=n.split(/\s+as\s+/)[0]?.trim();r&&t.add(r)}}return[...t]}function u(e,t,n=`scoped`){let r=`/* Generated by tempestStyles() — the CSS this app actually uses. */
2
+ `,i=n===`global`?[t.core]:n===`scoped`?[`tokens.css`,`scoped.css`]:[`tokens.css`];if(e===null)return`${r}${(n===`global`?[`../styles.css`]:[...i,`../styles.css`]).map(e=>`@import "tempest-react-sdk/styles/${e}";`).join(`
3
+ `)}\n`;let a=new Set;for(let n of e)for(let e of t.components[n]??[])a.add(e);return`${r}${[...i,...[...a].sort()].map(e=>`@import "tempest-react-sdk/styles/${e}";`).join(`
4
+ `)}\n`}async function d(n,r){let i=[],a;try{a=await(0,t.readdir)(n,{withFileTypes:!0})}catch{return i}for(let t of a)if(t.isDirectory()){if(r.has(t.name)||t.name.startsWith(`.`))continue;i.push(...await d((0,e.join)(n,t.name),r))}else t.isFile()&&s.test(t.name)&&i.push((0,e.join)(n,t.name));return i}function f(t){let i=(0,e.join)(`tempest-react-sdk`,`dist`,`styles`,`manifest.json`),a=[],o=(0,e.resolve)(t);for(;;){a.push((0,e.join)(o,`node_modules`,i));let t=(0,e.dirname)(o);if(t===o)break;o=t}a.push((0,e.join)((0,e.dirname)((0,r.fileURLToPath)({}.url)),`..`,`styles`,`manifest.json`));for(let e of a)try{return JSON.parse((0,n.readFileSync)(e,`utf8`))}catch{continue}throw Error(`tempestStyles(): tempest-react-sdk/dist/styles/manifest.json not found — the installed SDK predates it. Upgrade, or drop the plugin and import tempest-react-sdk/styles.css.`)}function p(n={}){let{dir:r=`src`,include:i=[],skipDirs:o,reset:s=`scoped`}=n,p=new Set(o??c),m=process.cwd(),h=[...i],g=async()=>{let n=new Set(i);for(let i of await d((0,e.resolve)(m,r),p)){let e;try{e=await(0,t.readFile)(i,`utf8`)}catch{continue}let r=l(e);if(r===null){h=null;return}for(let e of r)n.add(e)}h=[...n]};return{name:`tempest-styles`,enforce:`pre`,configResolved(e){m=e.root??m},async buildStart(){await g()},resolveId(e){return e===`tempest-react-sdk/styles/auto.css`?a:null},load(e){return e===a?u(h,f(m),s):null}}}exports.TEMPEST_STYLES_ID=i,exports.buildStyleEntry=u,exports.scanStyleImports=l,exports.tempestStyles=p;
5
+ //# sourceMappingURL=tempest-styles.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tempest-styles.cjs","names":[],"sources":["../../src/vite/tempest-styles.ts"],"sourcesContent":["import { readdir, readFile } from \"node:fs/promises\";\nimport { readFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport type { TempestVitePlugin } from \"./tempest-pwa-manifest\";\n\n/** The stylesheet id an app imports to get exactly the CSS it uses. */\nexport const TEMPEST_STYLES_ID = \"tempest-react-sdk/styles/auto.css\";\n\nconst RESOLVED_ID = \"\\0tempest-styles/auto.css\";\n\n/** Package subpaths whose exports are components with stylesheets. */\nconst SDK_SPECIFIER = /^tempest-react-sdk(\\/(charts|editor|br|icons))?$/;\n\nconst SOURCE_FILE = /\\.[cm]?[jt]sx?$/;\nconst SKIP_DIRS = new Set([\"node_modules\", \"dist\", \"build\", \"coverage\"]);\n\n/**\n * How much of the reset an app takes.\n *\n * The components are written against the reset — `.tempest_button` assumes\n * `button { background: none; border: 0; padding: 0 }`, every width assumes\n * `box-sizing: border-box` — so `\"none\"` is not \"unstyled document, styled\n * components\": it is components missing their box model. It exists for the app\n * that already ships an equivalent reset of its own.\n */\nexport type ResetMode = \"scoped\" | \"global\" | \"none\";\n\n/** Shape of `dist/styles/manifest.json`. */\nexport interface StyleManifest {\n /** The foundation sheet — tokens and reset together, the pre-split default. */\n core: string;\n /** Public export name → the stylesheets it needs, transitive closure included. */\n components: Record<string, readonly string[]>;\n}\n\nexport interface TempestStylesOptions {\n /** Directory to scan, relative to the Vite root. Default: `\"src\"`. */\n dir?: string;\n /**\n * Which reset to emit alongside the tokens. Default: `\"scoped\"`.\n *\n * `\"scoped\"` confines the reset to `:where([class*=\"tempest_\"])`, so components\n * keep the normalisation they are written against and the app keeps `html`,\n * `body` and `#root`. `\"global\"` is the pre-split behaviour, correct when the\n * SDK owns the whole page. `\"none\"` emits tokens only.\n */\n reset?: ResetMode;\n /**\n * Extra export names to style even when the scan cannot see them — a component\n * reached only through a namespace import, or rendered by a sibling package.\n */\n include?: readonly string[];\n /** Directory names to skip. Default: `node_modules`, `dist`, `build`, `coverage`. */\n skipDirs?: readonly string[];\n}\n\n/**\n * Collect the SDK export names a source file imports.\n *\n * Reads the import specifier rather than the JSX, because a bare `<Button>` in the\n * markup says nothing about where it came from — the app may well define its own.\n * Type-only bindings are dropped: they are erased before any component renders, so\n * paying for their CSS would be paying for nothing.\n *\n * @param code - File contents.\n * @returns The imported names, or `null` when the file namespace-imports the SDK\n * and the set therefore cannot be known.\n */\nexport function scanStyleImports(code: string): string[] | null {\n const names = new Set<string>();\n\n for (const match of code.matchAll(\n /\\bimport\\s+(type\\s+)?([^;'\"]*?)\\s+from\\s*[\"']([^\"']+)[\"']/g,\n )) {\n const [, typeOnly, clause, specifier] = match;\n if (!SDK_SPECIFIER.test(specifier ?? \"\")) continue;\n if (typeOnly) continue;\n if (/^\\s*\\*\\s+as\\s/.test(clause ?? \"\")) return null;\n\n const braces = /\\{([^}]*)\\}/.exec(clause ?? \"\");\n if (!braces) continue;\n for (const part of (braces[1] ?? \"\").split(\",\")) {\n const binding = part.trim();\n if (!binding || binding.startsWith(\"type \")) continue;\n const name = binding.split(/\\s+as\\s+/)[0]?.trim();\n if (name) names.add(name);\n }\n }\n return [...names];\n}\n\n/**\n * Build the stylesheet for a set of export names.\n *\n * Emits `@import` statements rather than inlined rules so Vite's own CSS pipeline\n * resolves, deduplicates and minifies them — the same treatment a hand-written\n * list of imports gets, which is what this replaces.\n *\n * @param names - Export names the app imports, or `null` to take everything.\n * @param manifest - The published style manifest.\n * @returns CSS source.\n */\nexport function buildStyleEntry(\n names: readonly string[] | null,\n manifest: StyleManifest,\n reset: ResetMode = \"scoped\",\n): string {\n const banner = \"/* Generated by tempestStyles() — the CSS this app actually uses. */\\n\";\n const foundation =\n reset === \"global\"\n ? [manifest.core]\n : reset === \"scoped\"\n ? [\"tokens.css\", \"scoped.css\"]\n : [\"tokens.css\"];\n\n if (names === null) {\n const whole = reset === \"global\" ? [\"../styles.css\"] : [...foundation, \"../styles.css\"];\n return `${banner}${whole.map((sheet) => `@import \"tempest-react-sdk/styles/${sheet}\";`).join(\"\\n\")}\\n`;\n }\n\n const sheets = new Set<string>();\n for (const name of names) {\n for (const sheet of manifest.components[name] ?? []) sheets.add(sheet);\n }\n const lines = [...foundation, ...[...sheets].sort()].map(\n (sheet) => `@import \"tempest-react-sdk/styles/${sheet}\";`,\n );\n return `${banner}${lines.join(\"\\n\")}\\n`;\n}\n\n/**\n * Walk a directory and collect every source file path.\n *\n * @param dir - Absolute directory to walk.\n * @param skip - Directory names to skip.\n * @returns Absolute file paths.\n */\nasync function collectSourceFiles(dir: string, skip: ReadonlySet<string>): Promise<string[]> {\n const out: string[] = [];\n let entries;\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch {\n return out;\n }\n for (const entry of entries) {\n if (entry.isDirectory()) {\n if (skip.has(entry.name) || entry.name.startsWith(\".\")) continue;\n out.push(...(await collectSourceFiles(join(dir, entry.name), skip)));\n } else if (entry.isFile() && SOURCE_FILE.test(entry.name)) {\n out.push(join(dir, entry.name));\n }\n }\n return out;\n}\n\n/**\n * Read the style manifest the installed package ships.\n *\n * Resolved by walking the filesystem rather than through `createRequire`, which\n * does not survive the trip: Vite bundles `vite.config.ts` into a temporary module\n * before running it, and in that bundle the `node:module` namespace import comes\n * back without the function — `(0, a.createRequire) is not a function`, at load\n * time, inside the build. The same rewrite is why `import.meta.url` is only the\n * fallback here and the app's `node_modules` is tried first.\n *\n * @param root - The Vite root, where the walk for `node_modules` starts.\n * @returns The manifest.\n * @throws If no installed copy carries one — an SDK older than the manifest.\n */\nfunction readManifest(root: string): StyleManifest {\n const relative = join(\"tempest-react-sdk\", \"dist\", \"styles\", \"manifest.json\");\n const candidates: string[] = [];\n\n let dir = resolve(root);\n for (;;) {\n candidates.push(join(dir, \"node_modules\", relative));\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n candidates.push(join(dirname(fileURLToPath(import.meta.url)), \"..\", \"styles\", \"manifest.json\"));\n\n for (const candidate of candidates) {\n try {\n return JSON.parse(readFileSync(candidate, \"utf8\")) as StyleManifest;\n } catch {\n continue;\n }\n }\n throw new Error(\n \"tempestStyles(): tempest-react-sdk/dist/styles/manifest.json not found — \" +\n \"the installed SDK predates it. Upgrade, or drop the plugin and import \" +\n \"tempest-react-sdk/styles.css.\",\n );\n}\n\n/**\n * Import only the SDK stylesheets your app can actually reach.\n *\n * `styles.css` carries every component the SDK ships — measured at 236.71 kB raw\n * against the 38.94 kB an app mounting twelve of them can reach. The per-component\n * sheets under `styles/` have always closed that gap, but by hand: the app lists\n * them and keeps the list honest as it grows. This plugin makes the list the build's\n * problem, resolving it from the imports the source already writes.\n *\n * The closure matters more than the scan. A component pays for the CSS of every SDK\n * component it renders internally, so `<DataTable>` alone needs six sheets and\n * `<AIChat>` seven — a hand-kept list of one sheet per component the app names is\n * wrong in a way that only shows up as an unstyled child.\n *\n * The reset is the other half, and the half that breaks apps. `styles.css` claims\n * `html`, `body` and `#root`; an app with its own layout that imports it loses its\n * document surface, and an app that drops the import loses the box model its\n * components are written against — components render unstyled, which is what the\n * \"just remove the import\" fix actually costs. The default `reset: \"scoped\"` is the\n * third option: the same normalisation, confined to\n * `:where([class*=\"tempest_\"])`, so it reaches inside a Tempest component and\n * nowhere else.\n *\n * `tempest-react-sdk/styles/auto.css` is a real file, so it resolves without the\n * plugin too — to the complete sheet. Dropping the plugin costs bytes, never\n * correctness.\n *\n * @param options - Scan configuration.\n * @returns The Vite plugin.\n *\n * @example\n * // vite.config.ts\n * import { createViteConfig, tempestStyles } from \"tempest-react-sdk/vite\";\n *\n * export default createViteConfig({ plugins: [tempestStyles()] });\n *\n * @example\n * // src/main.tsx — the one import, instead of a maintained list\n * import \"tempest-react-sdk/styles/auto.css\";\n */\nexport function tempestStyles(options: TempestStylesOptions = {}): TempestVitePlugin {\n const { dir = \"src\", include = [], skipDirs, reset = \"scoped\" } = options;\n const skip = new Set<string>(skipDirs ?? SKIP_DIRS);\n let root = process.cwd();\n let names: string[] | null = [...include];\n\n /**\n * Rescan the source tree, keeping the explicitly included names.\n *\n * @tempest-limits empty-catch — the scan races the editor and the file system:\n * a file listed a moment ago can be renamed, deleted, or held by another process\n * by the time it is read. An unreadable file contributes no names and the build\n * continues; failing the whole scan would break `vite dev` over a temp file that\n * no longer exists.\n */\n const rescan = async (): Promise<void> => {\n const found = new Set<string>(include);\n for (const file of await collectSourceFiles(resolve(root, dir), skip)) {\n let code: string;\n try {\n code = await readFile(file, \"utf8\");\n } catch {\n continue;\n }\n const scanned = scanStyleImports(code);\n if (scanned === null) {\n names = null;\n return;\n }\n for (const name of scanned) found.add(name);\n }\n names = [...found];\n };\n\n return {\n name: \"tempest-styles\",\n enforce: \"pre\",\n\n configResolved(config: { root?: string }) {\n root = config.root ?? root;\n },\n\n async buildStart() {\n await rescan();\n },\n\n resolveId(id: string) {\n return id === TEMPEST_STYLES_ID ? RESOLVED_ID : null;\n },\n\n load(id: string) {\n return id === RESOLVED_ID ? buildStyleEntry(names, readManifest(root), reset) : null;\n },\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,103 @@
1
+ import { dirname as e, join as t, resolve as n } from "node:path";
2
+ import { readFile as r, readdir as i } from "node:fs/promises";
3
+ import { readFileSync as a } from "node:fs";
4
+ import { fileURLToPath as o } from "node:url";
5
+ //#region src/vite/tempest-styles.ts
6
+ var s = "tempest-react-sdk/styles/auto.css", c = "\0tempest-styles/auto.css", l = /^tempest-react-sdk(\/(charts|editor|br|icons))?$/, u = /\.[cm]?[jt]sx?$/, d = /* @__PURE__ */ new Set([
7
+ "node_modules",
8
+ "dist",
9
+ "build",
10
+ "coverage"
11
+ ]);
12
+ function f(e) {
13
+ let t = /* @__PURE__ */ new Set();
14
+ for (let n of e.matchAll(/\bimport\s+(type\s+)?([^;'"]*?)\s+from\s*["']([^"']+)["']/g)) {
15
+ let [, e, r, i] = n;
16
+ if (!l.test(i ?? "") || e) continue;
17
+ if (/^\s*\*\s+as\s/.test(r ?? "")) return null;
18
+ let a = /\{([^}]*)\}/.exec(r ?? "");
19
+ if (a) for (let e of (a[1] ?? "").split(",")) {
20
+ let n = e.trim();
21
+ if (!n || n.startsWith("type ")) continue;
22
+ let r = n.split(/\s+as\s+/)[0]?.trim();
23
+ r && t.add(r);
24
+ }
25
+ }
26
+ return [...t];
27
+ }
28
+ function p(e, t, n = "scoped") {
29
+ let r = "/* Generated by tempestStyles() — the CSS this app actually uses. */\n", i = n === "global" ? [t.core] : n === "scoped" ? ["tokens.css", "scoped.css"] : ["tokens.css"];
30
+ if (e === null) return `${r}${(n === "global" ? ["../styles.css"] : [...i, "../styles.css"]).map((e) => `@import "tempest-react-sdk/styles/${e}";`).join("\n")}\n`;
31
+ let a = /* @__PURE__ */ new Set();
32
+ for (let n of e) for (let e of t.components[n] ?? []) a.add(e);
33
+ return `${r}${[...i, ...[...a].sort()].map((e) => `@import "tempest-react-sdk/styles/${e}";`).join("\n")}\n`;
34
+ }
35
+ async function m(e, n) {
36
+ let r = [], a;
37
+ try {
38
+ a = await i(e, { withFileTypes: !0 });
39
+ } catch {
40
+ return r;
41
+ }
42
+ for (let i of a) if (i.isDirectory()) {
43
+ if (n.has(i.name) || i.name.startsWith(".")) continue;
44
+ r.push(...await m(t(e, i.name), n));
45
+ } else i.isFile() && u.test(i.name) && r.push(t(e, i.name));
46
+ return r;
47
+ }
48
+ function h(r) {
49
+ let i = t("tempest-react-sdk", "dist", "styles", "manifest.json"), s = [], c = n(r);
50
+ for (;;) {
51
+ s.push(t(c, "node_modules", i));
52
+ let n = e(c);
53
+ if (n === c) break;
54
+ c = n;
55
+ }
56
+ s.push(t(e(o(import.meta.url)), "..", "styles", "manifest.json"));
57
+ for (let e of s) try {
58
+ return JSON.parse(a(e, "utf8"));
59
+ } catch {
60
+ continue;
61
+ }
62
+ throw Error("tempestStyles(): tempest-react-sdk/dist/styles/manifest.json not found — the installed SDK predates it. Upgrade, or drop the plugin and import tempest-react-sdk/styles.css.");
63
+ }
64
+ function g(e = {}) {
65
+ let { dir: t = "src", include: i = [], skipDirs: a, reset: o = "scoped" } = e, s = new Set(a ?? d), l = process.cwd(), u = [...i], g = async () => {
66
+ let e = new Set(i);
67
+ for (let i of await m(n(l, t), s)) {
68
+ let t;
69
+ try {
70
+ t = await r(i, "utf8");
71
+ } catch {
72
+ continue;
73
+ }
74
+ let n = f(t);
75
+ if (n === null) {
76
+ u = null;
77
+ return;
78
+ }
79
+ for (let t of n) e.add(t);
80
+ }
81
+ u = [...e];
82
+ };
83
+ return {
84
+ name: "tempest-styles",
85
+ enforce: "pre",
86
+ configResolved(e) {
87
+ l = e.root ?? l;
88
+ },
89
+ async buildStart() {
90
+ await g();
91
+ },
92
+ resolveId(e) {
93
+ return e === "tempest-react-sdk/styles/auto.css" ? c : null;
94
+ },
95
+ load(e) {
96
+ return e === c ? p(u, h(l), o) : null;
97
+ }
98
+ };
99
+ }
100
+ //#endregion
101
+ export { s as TEMPEST_STYLES_ID, p as buildStyleEntry, f as scanStyleImports, g as tempestStyles };
102
+
103
+ //# sourceMappingURL=tempest-styles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tempest-styles.js","names":[],"sources":["../../src/vite/tempest-styles.ts"],"sourcesContent":["import { readdir, readFile } from \"node:fs/promises\";\nimport { readFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport type { TempestVitePlugin } from \"./tempest-pwa-manifest\";\n\n/** The stylesheet id an app imports to get exactly the CSS it uses. */\nexport const TEMPEST_STYLES_ID = \"tempest-react-sdk/styles/auto.css\";\n\nconst RESOLVED_ID = \"\\0tempest-styles/auto.css\";\n\n/** Package subpaths whose exports are components with stylesheets. */\nconst SDK_SPECIFIER = /^tempest-react-sdk(\\/(charts|editor|br|icons))?$/;\n\nconst SOURCE_FILE = /\\.[cm]?[jt]sx?$/;\nconst SKIP_DIRS = new Set([\"node_modules\", \"dist\", \"build\", \"coverage\"]);\n\n/**\n * How much of the reset an app takes.\n *\n * The components are written against the reset — `.tempest_button` assumes\n * `button { background: none; border: 0; padding: 0 }`, every width assumes\n * `box-sizing: border-box` — so `\"none\"` is not \"unstyled document, styled\n * components\": it is components missing their box model. It exists for the app\n * that already ships an equivalent reset of its own.\n */\nexport type ResetMode = \"scoped\" | \"global\" | \"none\";\n\n/** Shape of `dist/styles/manifest.json`. */\nexport interface StyleManifest {\n /** The foundation sheet — tokens and reset together, the pre-split default. */\n core: string;\n /** Public export name → the stylesheets it needs, transitive closure included. */\n components: Record<string, readonly string[]>;\n}\n\nexport interface TempestStylesOptions {\n /** Directory to scan, relative to the Vite root. Default: `\"src\"`. */\n dir?: string;\n /**\n * Which reset to emit alongside the tokens. Default: `\"scoped\"`.\n *\n * `\"scoped\"` confines the reset to `:where([class*=\"tempest_\"])`, so components\n * keep the normalisation they are written against and the app keeps `html`,\n * `body` and `#root`. `\"global\"` is the pre-split behaviour, correct when the\n * SDK owns the whole page. `\"none\"` emits tokens only.\n */\n reset?: ResetMode;\n /**\n * Extra export names to style even when the scan cannot see them — a component\n * reached only through a namespace import, or rendered by a sibling package.\n */\n include?: readonly string[];\n /** Directory names to skip. Default: `node_modules`, `dist`, `build`, `coverage`. */\n skipDirs?: readonly string[];\n}\n\n/**\n * Collect the SDK export names a source file imports.\n *\n * Reads the import specifier rather than the JSX, because a bare `<Button>` in the\n * markup says nothing about where it came from — the app may well define its own.\n * Type-only bindings are dropped: they are erased before any component renders, so\n * paying for their CSS would be paying for nothing.\n *\n * @param code - File contents.\n * @returns The imported names, or `null` when the file namespace-imports the SDK\n * and the set therefore cannot be known.\n */\nexport function scanStyleImports(code: string): string[] | null {\n const names = new Set<string>();\n\n for (const match of code.matchAll(\n /\\bimport\\s+(type\\s+)?([^;'\"]*?)\\s+from\\s*[\"']([^\"']+)[\"']/g,\n )) {\n const [, typeOnly, clause, specifier] = match;\n if (!SDK_SPECIFIER.test(specifier ?? \"\")) continue;\n if (typeOnly) continue;\n if (/^\\s*\\*\\s+as\\s/.test(clause ?? \"\")) return null;\n\n const braces = /\\{([^}]*)\\}/.exec(clause ?? \"\");\n if (!braces) continue;\n for (const part of (braces[1] ?? \"\").split(\",\")) {\n const binding = part.trim();\n if (!binding || binding.startsWith(\"type \")) continue;\n const name = binding.split(/\\s+as\\s+/)[0]?.trim();\n if (name) names.add(name);\n }\n }\n return [...names];\n}\n\n/**\n * Build the stylesheet for a set of export names.\n *\n * Emits `@import` statements rather than inlined rules so Vite's own CSS pipeline\n * resolves, deduplicates and minifies them — the same treatment a hand-written\n * list of imports gets, which is what this replaces.\n *\n * @param names - Export names the app imports, or `null` to take everything.\n * @param manifest - The published style manifest.\n * @returns CSS source.\n */\nexport function buildStyleEntry(\n names: readonly string[] | null,\n manifest: StyleManifest,\n reset: ResetMode = \"scoped\",\n): string {\n const banner = \"/* Generated by tempestStyles() — the CSS this app actually uses. */\\n\";\n const foundation =\n reset === \"global\"\n ? [manifest.core]\n : reset === \"scoped\"\n ? [\"tokens.css\", \"scoped.css\"]\n : [\"tokens.css\"];\n\n if (names === null) {\n const whole = reset === \"global\" ? [\"../styles.css\"] : [...foundation, \"../styles.css\"];\n return `${banner}${whole.map((sheet) => `@import \"tempest-react-sdk/styles/${sheet}\";`).join(\"\\n\")}\\n`;\n }\n\n const sheets = new Set<string>();\n for (const name of names) {\n for (const sheet of manifest.components[name] ?? []) sheets.add(sheet);\n }\n const lines = [...foundation, ...[...sheets].sort()].map(\n (sheet) => `@import \"tempest-react-sdk/styles/${sheet}\";`,\n );\n return `${banner}${lines.join(\"\\n\")}\\n`;\n}\n\n/**\n * Walk a directory and collect every source file path.\n *\n * @param dir - Absolute directory to walk.\n * @param skip - Directory names to skip.\n * @returns Absolute file paths.\n */\nasync function collectSourceFiles(dir: string, skip: ReadonlySet<string>): Promise<string[]> {\n const out: string[] = [];\n let entries;\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch {\n return out;\n }\n for (const entry of entries) {\n if (entry.isDirectory()) {\n if (skip.has(entry.name) || entry.name.startsWith(\".\")) continue;\n out.push(...(await collectSourceFiles(join(dir, entry.name), skip)));\n } else if (entry.isFile() && SOURCE_FILE.test(entry.name)) {\n out.push(join(dir, entry.name));\n }\n }\n return out;\n}\n\n/**\n * Read the style manifest the installed package ships.\n *\n * Resolved by walking the filesystem rather than through `createRequire`, which\n * does not survive the trip: Vite bundles `vite.config.ts` into a temporary module\n * before running it, and in that bundle the `node:module` namespace import comes\n * back without the function — `(0, a.createRequire) is not a function`, at load\n * time, inside the build. The same rewrite is why `import.meta.url` is only the\n * fallback here and the app's `node_modules` is tried first.\n *\n * @param root - The Vite root, where the walk for `node_modules` starts.\n * @returns The manifest.\n * @throws If no installed copy carries one — an SDK older than the manifest.\n */\nfunction readManifest(root: string): StyleManifest {\n const relative = join(\"tempest-react-sdk\", \"dist\", \"styles\", \"manifest.json\");\n const candidates: string[] = [];\n\n let dir = resolve(root);\n for (;;) {\n candidates.push(join(dir, \"node_modules\", relative));\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n candidates.push(join(dirname(fileURLToPath(import.meta.url)), \"..\", \"styles\", \"manifest.json\"));\n\n for (const candidate of candidates) {\n try {\n return JSON.parse(readFileSync(candidate, \"utf8\")) as StyleManifest;\n } catch {\n continue;\n }\n }\n throw new Error(\n \"tempestStyles(): tempest-react-sdk/dist/styles/manifest.json not found — \" +\n \"the installed SDK predates it. Upgrade, or drop the plugin and import \" +\n \"tempest-react-sdk/styles.css.\",\n );\n}\n\n/**\n * Import only the SDK stylesheets your app can actually reach.\n *\n * `styles.css` carries every component the SDK ships — measured at 236.71 kB raw\n * against the 38.94 kB an app mounting twelve of them can reach. The per-component\n * sheets under `styles/` have always closed that gap, but by hand: the app lists\n * them and keeps the list honest as it grows. This plugin makes the list the build's\n * problem, resolving it from the imports the source already writes.\n *\n * The closure matters more than the scan. A component pays for the CSS of every SDK\n * component it renders internally, so `<DataTable>` alone needs six sheets and\n * `<AIChat>` seven — a hand-kept list of one sheet per component the app names is\n * wrong in a way that only shows up as an unstyled child.\n *\n * The reset is the other half, and the half that breaks apps. `styles.css` claims\n * `html`, `body` and `#root`; an app with its own layout that imports it loses its\n * document surface, and an app that drops the import loses the box model its\n * components are written against — components render unstyled, which is what the\n * \"just remove the import\" fix actually costs. The default `reset: \"scoped\"` is the\n * third option: the same normalisation, confined to\n * `:where([class*=\"tempest_\"])`, so it reaches inside a Tempest component and\n * nowhere else.\n *\n * `tempest-react-sdk/styles/auto.css` is a real file, so it resolves without the\n * plugin too — to the complete sheet. Dropping the plugin costs bytes, never\n * correctness.\n *\n * @param options - Scan configuration.\n * @returns The Vite plugin.\n *\n * @example\n * // vite.config.ts\n * import { createViteConfig, tempestStyles } from \"tempest-react-sdk/vite\";\n *\n * export default createViteConfig({ plugins: [tempestStyles()] });\n *\n * @example\n * // src/main.tsx — the one import, instead of a maintained list\n * import \"tempest-react-sdk/styles/auto.css\";\n */\nexport function tempestStyles(options: TempestStylesOptions = {}): TempestVitePlugin {\n const { dir = \"src\", include = [], skipDirs, reset = \"scoped\" } = options;\n const skip = new Set<string>(skipDirs ?? SKIP_DIRS);\n let root = process.cwd();\n let names: string[] | null = [...include];\n\n /**\n * Rescan the source tree, keeping the explicitly included names.\n *\n * @tempest-limits empty-catch — the scan races the editor and the file system:\n * a file listed a moment ago can be renamed, deleted, or held by another process\n * by the time it is read. An unreadable file contributes no names and the build\n * continues; failing the whole scan would break `vite dev` over a temp file that\n * no longer exists.\n */\n const rescan = async (): Promise<void> => {\n const found = new Set<string>(include);\n for (const file of await collectSourceFiles(resolve(root, dir), skip)) {\n let code: string;\n try {\n code = await readFile(file, \"utf8\");\n } catch {\n continue;\n }\n const scanned = scanStyleImports(code);\n if (scanned === null) {\n names = null;\n return;\n }\n for (const name of scanned) found.add(name);\n }\n names = [...found];\n };\n\n return {\n name: \"tempest-styles\",\n enforce: \"pre\",\n\n configResolved(config: { root?: string }) {\n root = config.root ?? root;\n },\n\n async buildStart() {\n await rescan();\n },\n\n resolveId(id: string) {\n return id === TEMPEST_STYLES_ID ? RESOLVED_ID : null;\n },\n\n load(id: string) {\n return id === RESOLVED_ID ? buildStyleEntry(names, readManifest(root), reset) : null;\n },\n };\n}\n"],"mappings":"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"}
package/dist/vite.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./vite/tempest-icons.cjs"),t=require("./vite/create-vite-config.cjs"),n=require("./vite/tempest-pwa-manifest.cjs"),r=require("./vite/tempest-pwa-icons.cjs"),i=require("./vite/tempest-pwa-dev-sw.cjs");exports.createViteConfig=t.createViteConfig,exports.tempestIcons=e.tempestIcons,exports.tempestPwaDevSw=i.tempestPwaDevSw,exports.tempestPwaIcons=r.tempestPwaIcons,exports.tempestPwaManifest=n.tempestPwaManifest;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./vite/tempest-icons.cjs"),t=require("./vite/create-vite-config.cjs"),n=require("./vite/tempest-pwa-manifest.cjs"),r=require("./vite/tempest-pwa-icons.cjs"),i=require("./vite/tempest-pwa-dev-sw.cjs"),a=require("./vite/tempest-styles.cjs");exports.createViteConfig=t.createViteConfig,exports.tempestIcons=e.tempestIcons,exports.tempestPwaDevSw=i.tempestPwaDevSw,exports.tempestPwaIcons=r.tempestPwaIcons,exports.tempestPwaManifest=n.tempestPwaManifest,exports.tempestStyles=a.tempestStyles;
package/dist/vite.d.ts CHANGED
@@ -69,6 +69,25 @@ export declare interface CreateViteConfigOptions {
69
69
  */
70
70
  export declare type ProxyEntry = string | Record<string, unknown>;
71
71
 
72
+ /**
73
+ * How much of the reset an app takes.
74
+ *
75
+ * The components are written against the reset — `.tempest_button` assumes
76
+ * `button { background: none; border: 0; padding: 0 }`, every width assumes
77
+ * `box-sizing: border-box` — so `"none"` is not "unstyled document, styled
78
+ * components": it is components missing their box model. It exists for the app
79
+ * that already ships an equivalent reset of its own.
80
+ */
81
+ export declare type ResetMode = "scoped" | "global" | "none";
82
+
83
+ /** Shape of `dist/styles/manifest.json`. */
84
+ export declare interface StyleManifest {
85
+ /** The foundation sheet — tokens and reset together, the pre-split default. */
86
+ core: string;
87
+ /** Public export name → the stylesheets it needs, transitive closure included. */
88
+ components: Record<string, readonly string[]>;
89
+ }
90
+
72
91
  /**
73
92
  * Generate a static icon registry from the slugs your source mentions.
74
93
  *
@@ -250,6 +269,69 @@ export declare interface TempestPwaManifestOptions {
250
269
  appShell?: string | false;
251
270
  }
252
271
 
272
+ /**
273
+ * Import only the SDK stylesheets your app can actually reach.
274
+ *
275
+ * `styles.css` carries every component the SDK ships — measured at 236.71 kB raw
276
+ * against the 38.94 kB an app mounting twelve of them can reach. The per-component
277
+ * sheets under `styles/` have always closed that gap, but by hand: the app lists
278
+ * them and keeps the list honest as it grows. This plugin makes the list the build's
279
+ * problem, resolving it from the imports the source already writes.
280
+ *
281
+ * The closure matters more than the scan. A component pays for the CSS of every SDK
282
+ * component it renders internally, so `<DataTable>` alone needs six sheets and
283
+ * `<AIChat>` seven — a hand-kept list of one sheet per component the app names is
284
+ * wrong in a way that only shows up as an unstyled child.
285
+ *
286
+ * The reset is the other half, and the half that breaks apps. `styles.css` claims
287
+ * `html`, `body` and `#root`; an app with its own layout that imports it loses its
288
+ * document surface, and an app that drops the import loses the box model its
289
+ * components are written against — components render unstyled, which is what the
290
+ * "just remove the import" fix actually costs. The default `reset: "scoped"` is the
291
+ * third option: the same normalisation, confined to
292
+ * `:where([class*="tempest_"])`, so it reaches inside a Tempest component and
293
+ * nowhere else.
294
+ *
295
+ * `tempest-react-sdk/styles/auto.css` is a real file, so it resolves without the
296
+ * plugin too — to the complete sheet. Dropping the plugin costs bytes, never
297
+ * correctness.
298
+ *
299
+ * @param options - Scan configuration.
300
+ * @returns The Vite plugin.
301
+ *
302
+ * @example
303
+ * // vite.config.ts
304
+ * import { createViteConfig, tempestStyles } from "tempest-react-sdk/vite";
305
+ *
306
+ * export default createViteConfig({ plugins: [tempestStyles()] });
307
+ *
308
+ * @example
309
+ * // src/main.tsx — the one import, instead of a maintained list
310
+ * import "tempest-react-sdk/styles/auto.css";
311
+ */
312
+ export declare function tempestStyles(options?: TempestStylesOptions): TempestVitePlugin;
313
+
314
+ export declare interface TempestStylesOptions {
315
+ /** Directory to scan, relative to the Vite root. Default: `"src"`. */
316
+ dir?: string;
317
+ /**
318
+ * Which reset to emit alongside the tokens. Default: `"scoped"`.
319
+ *
320
+ * `"scoped"` confines the reset to `:where([class*="tempest_"])`, so components
321
+ * keep the normalisation they are written against and the app keeps `html`,
322
+ * `body` and `#root`. `"global"` is the pre-split behaviour, correct when the
323
+ * SDK owns the whole page. `"none"` emits tokens only.
324
+ */
325
+ reset?: ResetMode;
326
+ /**
327
+ * Extra export names to style even when the scan cannot see them — a component
328
+ * reached only through a namespace import, or rendered by a sibling package.
329
+ */
330
+ include?: readonly string[];
331
+ /** Directory names to skip. Default: `node_modules`, `dist`, `build`, `coverage`. */
332
+ skipDirs?: readonly string[];
333
+ }
334
+
253
335
  /**
254
336
  * The resulting Vite config object. Typed loosely so the SDK's published
255
337
  * declarations stay free of `vite`'s internal types; assign it straight to a
package/dist/vite.js CHANGED
@@ -3,4 +3,5 @@ import { createViteConfig as t } from "./vite/create-vite-config.js";
3
3
  import { tempestPwaManifest as n } from "./vite/tempest-pwa-manifest.js";
4
4
  import { tempestPwaIcons as r } from "./vite/tempest-pwa-icons.js";
5
5
  import { tempestPwaDevSw as i } from "./vite/tempest-pwa-dev-sw.js";
6
- export { t as createViteConfig, e as tempestIcons, i as tempestPwaDevSw, r as tempestPwaIcons, n as tempestPwaManifest };
6
+ import { tempestStyles as a } from "./vite/tempest-styles.js";
7
+ export { t as createViteConfig, e as tempestIcons, i as tempestPwaDevSw, r as tempestPwaIcons, n as tempestPwaManifest, a as tempestStyles };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tempest-react-sdk",
3
- "version": "0.59.0",
3
+ "version": "0.61.0",
4
4
  "description": "SDK público da Tempest com componentes, hooks e integrações para projetos React.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -102,12 +102,13 @@
102
102
  },
103
103
  "./styles.css": "./dist/styles.css",
104
104
  "./styles/*.css": "./dist/styles/*.css",
105
+ "./styles/manifest.json": "./dist/styles/manifest.json",
105
106
  "./package.json": "./package.json",
106
107
  "./utilities.css": "./dist/utilities.css"
107
108
  },
108
109
  "scripts": {
109
110
  "dev": "vite build --watch",
110
- "build": "tsc -b tsconfig.build.json && node --max-old-space-size=6144 ./node_modules/vite/bin/vite.js build && node scripts/copy-css-assets.mjs && node scripts/split-css.mjs",
111
+ "build": "node scripts/gen-scoped-reset.mjs && tsc -b tsconfig.build.json && node --max-old-space-size=6144 ./node_modules/vite/bin/vite.js build && node scripts/split-css.mjs && node scripts/gen-style-manifest.mjs && node scripts/copy-css-assets.mjs",
111
112
  "postbuild": "node scripts/check-dist-guards.mjs",
112
113
  "typecheck": "tsc -b tsconfig.json --noEmit",
113
114
  "lint": "eslint .",