@tenphi/tasty 0.0.0-snapshot.1d29633 → 0.0.0-snapshot.1f1c00a
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/README.md +152 -134
- package/dist/{babel-Cg-mJV_t.d.ts → babel-rZcEwPLM.d.ts} +2 -3
- package/dist/chunks/async-storage-CG5HnUT5.js +20 -0
- package/dist/chunks/async-storage-CG5HnUT5.js.map +1 -0
- package/dist/chunks/build-config-CL4eRu2z.js +42 -0
- package/dist/chunks/build-config-CL4eRu2z.js.map +1 -0
- package/dist/{collector-BMT05AmU.js → chunks/collector-D2ARGT2L.js} +21 -117
- package/dist/chunks/collector-D2ARGT2L.js.map +1 -0
- package/dist/chunks/config-engine-DEmmPPdp.js +272 -0
- package/dist/chunks/config-engine-DEmmPPdp.js.map +1 -0
- package/dist/chunks/css-definitions-DotDkIXt.js +876 -0
- package/dist/chunks/css-definitions-DotDkIXt.js.map +1 -0
- package/dist/chunks/css-resources-P7IBUUZs.js +142 -0
- package/dist/chunks/css-resources-P7IBUUZs.js.map +1 -0
- package/dist/chunks/debug-D8pg9RGI.js +502 -0
- package/dist/chunks/debug-D8pg9RGI.js.map +1 -0
- package/dist/chunks/dsl-DRhFWQzo.js +1378 -0
- package/dist/chunks/dsl-DRhFWQzo.js.map +1 -0
- package/dist/chunks/hydration-TRcz5vnk.js +41 -0
- package/dist/chunks/hydration-TRcz5vnk.js.map +1 -0
- package/dist/chunks/react-runtime-BpxlOTbO.js +562 -0
- package/dist/chunks/react-runtime-BpxlOTbO.js.map +1 -0
- package/dist/chunks/runtime-engine-CKFXUH-A.js +2416 -0
- package/dist/chunks/runtime-engine-CKFXUH-A.js.map +1 -0
- package/dist/chunks/runtime-state-BxaLhVdP.js +127 -0
- package/dist/chunks/runtime-state-BxaLhVdP.js.map +1 -0
- package/dist/{merge-styles-CkAcnd0Z.js → chunks/shared-utils-y-HjvPN4.js} +60 -55
- package/dist/chunks/shared-utils-y-HjvPN4.js.map +1 -0
- package/dist/chunks/style-engine-BBbBuSkT.js +5260 -0
- package/dist/chunks/style-engine-BBbBuSkT.js.map +1 -0
- package/dist/{css-writer-b02uBqNF.js → chunks/zero-engine-gJrKBRiw.js} +6 -121
- package/dist/chunks/zero-engine-gJrKBRiw.js.map +1 -0
- package/dist/{collector-BFuqdF2F.d.ts → collector-w4mBj5gd.d.ts} +23 -4
- package/dist/{config-DmFxnBxg.d.ts → config-CZWCzBr6.d.ts} +171 -72
- package/dist/core/index.d.ts +5 -5
- package/dist/core/index.js +9 -6
- package/dist/{index-D1nMkpUe.d.ts → index-G9JuwM9p.d.ts} +263 -247
- package/dist/index.d.ts +5 -5
- package/dist/index.js +11 -921
- package/dist/{merge-styles-Cx_6ySBv.d.ts → merge-styles-VXwJ0Frr.d.ts} +2 -3
- package/dist/ssr/astro-client.d.ts +1 -1
- package/dist/ssr/astro-client.js +1 -14
- package/dist/ssr/astro-client.js.map +1 -1
- package/dist/ssr/astro-middleware-extract-static.d.ts +10 -0
- package/dist/ssr/astro-middleware-extract-static.js +9 -0
- package/dist/ssr/astro-middleware-extract-static.js.map +1 -0
- package/dist/ssr/astro-middleware-extract.d.ts +10 -0
- package/dist/ssr/astro-middleware-extract.js +9 -0
- package/dist/ssr/astro-middleware-extract.js.map +1 -0
- package/dist/ssr/astro-middleware-static.d.ts +3 -2
- package/dist/ssr/astro-middleware-static.js +0 -11
- package/dist/ssr/astro-middleware-static.js.map +1 -1
- package/dist/ssr/astro-middleware.d.ts +3 -2
- package/dist/ssr/astro-middleware.js +0 -12
- package/dist/ssr/astro-middleware.js.map +1 -1
- package/dist/ssr/astro.d.ts +40 -6
- package/dist/ssr/astro.js +157 -93
- package/dist/ssr/astro.js.map +1 -1
- package/dist/ssr/index.d.ts +10 -11
- package/dist/ssr/index.js +4 -4
- package/dist/ssr/index.js.map +1 -1
- package/dist/ssr/next-config.d.ts +64 -0
- package/dist/ssr/next-config.js +128 -0
- package/dist/ssr/next-config.js.map +1 -0
- package/dist/ssr/next.d.ts +9 -8
- package/dist/ssr/next.js +29 -43
- package/dist/ssr/next.js.map +1 -1
- package/dist/static/index.d.ts +8 -9
- package/dist/static/index.js +4 -22
- package/dist/static/index.js.map +1 -1
- package/dist/static/inject.d.ts +1 -2
- package/dist/{index-LC3O3Jj4.d.ts → types-JEY8PVYP.d.ts} +862 -811
- package/dist/zero/babel.d.ts +1 -1
- package/dist/zero/babel.js +41 -107
- package/dist/zero/babel.js.map +1 -1
- package/dist/zero/index.d.ts +6 -7
- package/dist/zero/index.js +1 -1
- package/dist/zero/next.d.ts +3 -5
- package/dist/zero/next.js +0 -31
- package/dist/zero/next.js.map +1 -1
- package/docs/README.md +13 -8
- package/docs/adoption.md +56 -31
- package/docs/ai-agents.md +107 -80
- package/docs/comparison.md +69 -40
- package/docs/configuration.md +179 -114
- package/docs/debug.md +19 -7
- package/docs/design-system.md +41 -22
- package/docs/dsl.md +310 -201
- package/docs/getting-started.md +64 -41
- package/docs/injector.md +63 -26
- package/docs/methodology.md +44 -38
- package/docs/migration-v3.md +49 -49
- package/docs/pipeline.md +32 -8
- package/docs/plugins.md +38 -34
- package/docs/react-api.md +67 -44
- package/docs/runtime-benchmarks.md +388 -0
- package/docs/ssr.md +219 -61
- package/docs/styles.md +95 -18
- package/docs/tasty-static.md +138 -105
- package/package.json +104 -33
- package/dist/async-storage-DKK-wTD4.js +0 -44
- package/dist/async-storage-DKK-wTD4.js.map +0 -1
- package/dist/collector-BMT05AmU.js.map +0 -1
- package/dist/config-DF93rL3u.js +0 -12661
- package/dist/config-DF93rL3u.js.map +0 -1
- package/dist/context-CA8YKeMn.js +0 -24
- package/dist/context-CA8YKeMn.js.map +0 -1
- package/dist/core-B5ybnMP1.js +0 -1529
- package/dist/core-B5ybnMP1.js.map +0 -1
- package/dist/css-writer-b02uBqNF.js.map +0 -1
- package/dist/format-global-rules-DklyaXv-.js +0 -22
- package/dist/format-global-rules-DklyaXv-.js.map +0 -1
- package/dist/format-rules-Cs4e3M9m.js +0 -130
- package/dist/format-rules-Cs4e3M9m.js.map +0 -1
- package/dist/hydrate-aaUSNJZJ.js +0 -37
- package/dist/hydrate-aaUSNJZJ.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/keyframes-BedEzEXk.js +0 -424
- package/dist/keyframes-BedEzEXk.js.map +0 -1
- package/dist/merge-styles-CkAcnd0Z.js.map +0 -1
- package/dist/resolve-recipes-CiyLtJG9.js +0 -144
- package/dist/resolve-recipes-CiyLtJG9.js.map +0 -1
package/dist/ssr/index.d.ts
CHANGED
|
@@ -1,29 +1,28 @@
|
|
|
1
|
-
import { n as createServerStyleCollector, t as ServerStyleCollector } from "../collector-
|
|
2
|
-
|
|
1
|
+
import { i as ServerStyleArtifactKind, n as createServerStyleCollector, r as ServerStyleArtifact, t as ServerStyleCollector } from "../collector-w4mBj5gd.js";
|
|
3
2
|
//#region src/ssr/async-storage.d.ts
|
|
4
3
|
/**
|
|
5
4
|
* Run a function with a ServerStyleCollector bound to the current
|
|
6
5
|
* async context. All useStyles() calls within `fn` (and any async
|
|
7
6
|
* continuations) will find this collector via getSSRCollector().
|
|
8
7
|
*/
|
|
9
|
-
declare function runWithCollector<T>(collector: ServerStyleCollector, fn: () => T): T;
|
|
8
|
+
export declare function runWithCollector<T>(collector: ServerStyleCollector, fn: () => T): T;
|
|
10
9
|
/**
|
|
11
10
|
* Retrieve the ServerStyleCollector bound to the current async context.
|
|
12
11
|
* Returns null when called outside of runWithCollector() or on the client.
|
|
13
12
|
*/
|
|
14
|
-
declare function getSSRCollector(): ServerStyleCollector | null;
|
|
13
|
+
export declare function getSSRCollector(): ServerStyleCollector | null;
|
|
15
14
|
//#endregion
|
|
16
15
|
//#region src/ssr/hydrate.d.ts
|
|
17
16
|
/**
|
|
18
17
|
* Client-side cache hydration for SSR/RSC.
|
|
19
18
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
19
|
+
* Registers class names rendered on the server with the client injector. If
|
|
20
|
+
* the runtime is not initialized yet, registration is deferred until its first
|
|
21
|
+
* use. With hash-based naming, only the class name list needs to cross the
|
|
22
|
+
* wire — no cache keys or counters.
|
|
24
23
|
*/
|
|
25
24
|
/**
|
|
26
|
-
*
|
|
25
|
+
* Hydrate the client-side style registry from the server's class name list.
|
|
27
26
|
*
|
|
28
27
|
* Call this before ReactDOM.hydrateRoot() or ensure it runs before
|
|
29
28
|
* any tasty() component renders on the client.
|
|
@@ -31,7 +30,7 @@ declare function getSSRCollector(): ServerStyleCollector | null;
|
|
|
31
30
|
* When called without arguments, reads the class list from `window.__TASTY__`
|
|
32
31
|
* (populated by inline scripts emitted during SSR/RSC streaming).
|
|
33
32
|
*/
|
|
34
|
-
declare function hydrateTastyClasses(classes?: string[]): void;
|
|
33
|
+
export declare function hydrateTastyClasses(classes?: string[]): void;
|
|
35
34
|
//#endregion
|
|
36
|
-
export {
|
|
35
|
+
export { type ServerStyleArtifact, type ServerStyleArtifactKind, ServerStyleCollector, createServerStyleCollector };
|
|
37
36
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/ssr/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as createServerStyleCollector, t as ServerStyleCollector } from "../collector-
|
|
3
|
-
import { n as runWithCollector, t as getSSRCollector } from "../async-storage-
|
|
4
|
-
import { t as hydrateTastyClasses } from "../
|
|
1
|
+
import { r as registerSSRCollectorGetterGlobal } from "../chunks/runtime-state-BxaLhVdP.js";
|
|
2
|
+
import { n as createServerStyleCollector, t as ServerStyleCollector } from "../chunks/collector-D2ARGT2L.js";
|
|
3
|
+
import { n as runWithCollector, t as getSSRCollector } from "../chunks/async-storage-CG5HnUT5.js";
|
|
4
|
+
import { t as hydrateTastyClasses } from "../chunks/hydration-TRcz5vnk.js";
|
|
5
5
|
//#region src/ssr/index.ts
|
|
6
6
|
registerSSRCollectorGetterGlobal(getSSRCollector);
|
|
7
7
|
//#endregion
|
package/dist/ssr/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/ssr/index.ts"],"sourcesContent":["/**\n * SSR entry point for @tenphi/tasty.\n *\n * Provides the core SSR infrastructure: ServerStyleCollector,\n * AsyncLocalStorage integration, and cache hydration.\n *\n * Import from '@tenphi/tasty/ssr'.\n */\n\n// Core collector\nexport { ServerStyleCollector, createServerStyleCollector } from './collector';\n\n// AsyncLocalStorage integration for Astro / generic frameworks\nexport { runWithCollector, getSSRCollector } from './async-storage';\n\n// Client-side cache hydration\nexport { hydrateTastyClasses } from './hydrate';\n\n// Register the ALS getter so hooks can find the collector\n// without importing 'node:async_hooks' in the browser bundle.\n// Uses globalThis so the getter is visible across separate module graphs.\nimport { getSSRCollector } from './async-storage';\nimport { registerSSRCollectorGetterGlobal } from './ssr-collector-ref';\n\nregisterSSRCollectorGetterGlobal(getSSRCollector);\n"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/ssr/index.ts"],"sourcesContent":["/**\n * SSR entry point for @tenphi/tasty.\n *\n * Provides the core SSR infrastructure: ServerStyleCollector,\n * AsyncLocalStorage integration, and cache hydration.\n *\n * Import from '@tenphi/tasty/ssr'.\n */\n\n// Core collector\nexport { ServerStyleCollector, createServerStyleCollector } from './collector';\nexport type { ServerStyleArtifact, ServerStyleArtifactKind } from './collector';\n\n// AsyncLocalStorage integration for Astro / generic frameworks\nexport { runWithCollector, getSSRCollector } from './async-storage';\n\n// Client-side cache hydration\nexport { hydrateTastyClasses } from './hydrate';\n\n// Register the ALS getter so hooks can find the collector\n// without importing 'node:async_hooks' in the browser bundle.\n// Uses globalThis so the getter is visible across separate module graphs.\nimport { getSSRCollector } from './async-storage';\nimport { registerSSRCollectorGetterGlobal } from './ssr-collector-ref';\n\nregisterSSRCollectorGetterGlobal(getSSRCollector);\n"],"mappings":";;;;;AAyBA,iCAAiC,eAAe"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { t as TastyConfig } from "../config-CZWCzBr6.js";
|
|
2
|
+
//#region src/ssr/next-config.d.ts
|
|
3
|
+
interface NextConfig {
|
|
4
|
+
basePath?: string;
|
|
5
|
+
env?: Record<string, string | undefined>;
|
|
6
|
+
headers?: () => Promise<NextHeader[]>;
|
|
7
|
+
output?: string;
|
|
8
|
+
[key: string]: unknown;
|
|
9
|
+
}
|
|
10
|
+
interface NextHeader {
|
|
11
|
+
source: string;
|
|
12
|
+
headers: {
|
|
13
|
+
key: string;
|
|
14
|
+
value: string;
|
|
15
|
+
}[];
|
|
16
|
+
[key: string]: unknown;
|
|
17
|
+
}
|
|
18
|
+
export interface TastyNextOptions {
|
|
19
|
+
/**
|
|
20
|
+
* Next.js project directory. Useful when the build command runs from a
|
|
21
|
+
* monorepo root rather than the app directory.
|
|
22
|
+
*
|
|
23
|
+
* @default process.cwd()
|
|
24
|
+
*/
|
|
25
|
+
rootDir?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Tasty configuration used to generate the shared stylesheet.
|
|
28
|
+
* `config` takes precedence when both config sources are provided.
|
|
29
|
+
*/
|
|
30
|
+
config?: TastyConfig;
|
|
31
|
+
/**
|
|
32
|
+
* Project-relative path to a TypeScript/JavaScript module whose default
|
|
33
|
+
* export is a Tasty configuration object.
|
|
34
|
+
*
|
|
35
|
+
* @example './app/tasty.config.ts'
|
|
36
|
+
*/
|
|
37
|
+
configFile?: string;
|
|
38
|
+
/**
|
|
39
|
+
* Filesystem directory for generated stylesheets. When it is inside the
|
|
40
|
+
* project's `public` directory, its public URL is inferred automatically.
|
|
41
|
+
*
|
|
42
|
+
* @default 'public/_tasty'
|
|
43
|
+
*/
|
|
44
|
+
outputDir?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Root-relative URL path corresponding to `outputDir`. This is required
|
|
47
|
+
* when `outputDir` is outside the project's `public` directory.
|
|
48
|
+
* The Next.js `basePath` is prepended automatically.
|
|
49
|
+
*
|
|
50
|
+
* @default inferred from outputDir
|
|
51
|
+
* @example '/assets/tasty'
|
|
52
|
+
*/
|
|
53
|
+
publicPath?: string;
|
|
54
|
+
/** Whether to generate and register the shared stylesheet. @default true */
|
|
55
|
+
enabled?: boolean;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Add a cacheable, content-hashed stylesheet for Tasty configuration globals.
|
|
59
|
+
* Route-dependent component and hook styles continue to stream through
|
|
60
|
+
* `TastyRegistry` so App Router navigation and Suspense remain correct.
|
|
61
|
+
*/
|
|
62
|
+
export declare function withTastyNext(options: TastyNextOptions): (nextConfig?: NextConfig) => NextConfig;
|
|
63
|
+
//#endregion
|
|
64
|
+
//# sourceMappingURL=next-config.d.ts.map
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { L as DEFAULT_PROPERTIES, U as parseFunctionName, V as formatFunctionRule, a as formatPropertyCSS, b as formatFontFaceRule, h as formatCounterStyleRule, n as formatGlobalRules, t as createServerStyleArtifact, v as fontFaceContentHash } from "../chunks/css-definitions-DotDkIXt.js";
|
|
2
|
+
import { b as renderStyles } from "../chunks/style-engine-BBbBuSkT.js";
|
|
3
|
+
import { n as functionsForExtraction, r as resetZeroConfig, t as configureZero } from "../chunks/build-config-CL4eRu2z.js";
|
|
4
|
+
import { t as findUnsafeCSSResource } from "../chunks/css-resources-P7IBUUZs.js";
|
|
5
|
+
import { createHash } from "node:crypto";
|
|
6
|
+
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
7
|
+
import { createRequire } from "node:module";
|
|
8
|
+
import { isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
9
|
+
//#region src/ssr/next-config.ts
|
|
10
|
+
const ENV_KEY = "TASTY_NEXT_SHARED_CSS_HREF";
|
|
11
|
+
const packageRequire = createRequire(import.meta.url);
|
|
12
|
+
function loadConfig(projectDir, options) {
|
|
13
|
+
if (options.config) return options.config;
|
|
14
|
+
if (!options.configFile) throw new Error("[Tasty] withTastyNext() requires either `config` or `configFile`.");
|
|
15
|
+
const configPath = resolve(projectDir, options.configFile);
|
|
16
|
+
let jitiPath;
|
|
17
|
+
try {
|
|
18
|
+
jitiPath = packageRequire.resolve("jiti");
|
|
19
|
+
} catch (error) {
|
|
20
|
+
if (error instanceof Error && "code" in error && error.code === "MODULE_NOT_FOUND") throw new Error("[Tasty] `configFile` requires the optional `jiti` package. Install `jiti` or pass the imported config through `config` instead.", { cause: error });
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
const { createJiti } = packageRequire(jitiPath);
|
|
24
|
+
const loaded = createJiti(projectDir, { moduleCache: false })(configPath);
|
|
25
|
+
return loaded && typeof loaded === "object" && "default" in loaded ? loaded.default : loaded;
|
|
26
|
+
}
|
|
27
|
+
function collectSharedCSS(config) {
|
|
28
|
+
resetZeroConfig();
|
|
29
|
+
try {
|
|
30
|
+
const resolved = configureZero(config);
|
|
31
|
+
const { normalized } = resolved;
|
|
32
|
+
const artifacts = [];
|
|
33
|
+
const append = (kind, key, css) => {
|
|
34
|
+
if (!css) return;
|
|
35
|
+
artifacts.push(createServerStyleArtifact(kind, key, css, artifacts.length));
|
|
36
|
+
};
|
|
37
|
+
for (const [token, definition] of Object.entries({
|
|
38
|
+
...DEFAULT_PROPERTIES,
|
|
39
|
+
...normalized.properties
|
|
40
|
+
})) append("property", `__prop:${token}`, formatPropertyCSS(token, definition));
|
|
41
|
+
for (const [family, input] of Object.entries(normalized.fontFaces)) {
|
|
42
|
+
const descriptors = Array.isArray(input) ? input : [input];
|
|
43
|
+
for (const descriptor of descriptors) append("font-face", fontFaceContentHash(family, descriptor), formatFontFaceRule(family, descriptor));
|
|
44
|
+
}
|
|
45
|
+
for (const [name, descriptors] of Object.entries(normalized.counterStyles)) append("counter-style", name, formatCounterStyleRule(name, descriptors));
|
|
46
|
+
for (const [name, definition] of Object.entries(functionsForExtraction(resolved) ?? {})) append("function", parseFunctionName(name), formatFunctionRule(name, definition));
|
|
47
|
+
if (Object.keys(normalized.tokens).length > 0) {
|
|
48
|
+
const rules = renderStyles(normalized.tokens, ":root");
|
|
49
|
+
append("global", "__global:tokens", formatGlobalRules(rules));
|
|
50
|
+
}
|
|
51
|
+
for (const [selector, styles] of Object.entries(normalized.globalStyles)) {
|
|
52
|
+
if (Object.keys(styles).length === 0) continue;
|
|
53
|
+
const rules = renderStyles(styles, selector);
|
|
54
|
+
append("global", `__global:styles:${selector}`, formatGlobalRules(rules));
|
|
55
|
+
}
|
|
56
|
+
for (const artifact of artifacts) {
|
|
57
|
+
const unsafe = findUnsafeCSSResource(artifact.css, false);
|
|
58
|
+
if (unsafe) throw new Error(`[Tasty] Next.js shared CSS extraction cannot preserve page-relative CSS URL "${unsafe.url}" in ${artifact.kind} artifact ${artifact.id}. Use an absolute URL, a data URL, or a root-relative URL such as url(/path/to/asset).`);
|
|
59
|
+
}
|
|
60
|
+
return artifacts.map(({ css }) => css).join("\n");
|
|
61
|
+
} finally {
|
|
62
|
+
resetZeroConfig();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function inferPublicPath(projectDir, outputDir) {
|
|
66
|
+
const publicDir = resolve(projectDir, "public");
|
|
67
|
+
const relativePath = relative(publicDir, outputDir);
|
|
68
|
+
if (relativePath === ".." || relativePath.startsWith(`..${sep}`) || isAbsolute(relativePath)) throw new Error("[Tasty] `publicPath` is required when `outputDir` is outside the Next.js public directory.");
|
|
69
|
+
return `/${relativePath.split(sep).filter(Boolean).join("/")}`;
|
|
70
|
+
}
|
|
71
|
+
function normalizeURLPath(path, option) {
|
|
72
|
+
if (!path.startsWith("/") || path.startsWith("//") || path.includes("?") || path.includes("#") || path.includes("\\")) throw new Error(`[Tasty] \`${option}\` must be a root-relative URL path.`);
|
|
73
|
+
let end = path.length;
|
|
74
|
+
while (end > 0 && path[end - 1] === "/") end--;
|
|
75
|
+
return path.slice(0, end);
|
|
76
|
+
}
|
|
77
|
+
function writeSharedCSS(outputDir, css) {
|
|
78
|
+
mkdirSync(outputDir, { recursive: true });
|
|
79
|
+
const filename = `tasty.shared.${createHash("sha256").update(css).digest("hex").slice(0, 12)}.css`;
|
|
80
|
+
const outputPath = join(outputDir, filename);
|
|
81
|
+
let existing;
|
|
82
|
+
try {
|
|
83
|
+
existing = readFileSync(outputPath, "utf8");
|
|
84
|
+
} catch {}
|
|
85
|
+
if (existing !== css) writeFileSync(outputPath, css);
|
|
86
|
+
return filename;
|
|
87
|
+
}
|
|
88
|
+
function withTastyNext(options) {
|
|
89
|
+
return (nextConfig = {}) => {
|
|
90
|
+
if (options.enabled === false) return nextConfig;
|
|
91
|
+
const projectDir = resolve(process.cwd(), options.rootDir ?? ".");
|
|
92
|
+
const outputDir = resolve(projectDir, options.outputDir ?? "public/_tasty");
|
|
93
|
+
const publicPath = normalizeURLPath(options.publicPath ?? inferPublicPath(projectDir, outputDir), "publicPath");
|
|
94
|
+
const basePath = normalizeURLPath(nextConfig.basePath || "/", "basePath");
|
|
95
|
+
const css = collectSharedCSS(loadConfig(projectDir, options));
|
|
96
|
+
if (!css) return nextConfig;
|
|
97
|
+
const filename = writeSharedCSS(outputDir, css);
|
|
98
|
+
const href = `${basePath}${publicPath}/${filename}`;
|
|
99
|
+
const headerSource = `${publicPath}/${filename}`;
|
|
100
|
+
const existingEnv = nextConfig.env ?? {};
|
|
101
|
+
const existingHeaders = nextConfig.headers;
|
|
102
|
+
if (existingEnv[ENV_KEY] && existingEnv[ENV_KEY] !== href) throw new Error(`[Tasty] Next.js env key ${ENV_KEY} is reserved by withTastyNext().`);
|
|
103
|
+
const generatedConfig = {
|
|
104
|
+
...nextConfig,
|
|
105
|
+
env: {
|
|
106
|
+
...existingEnv,
|
|
107
|
+
[ENV_KEY]: href
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
if (nextConfig.output === "export") return generatedConfig;
|
|
111
|
+
return {
|
|
112
|
+
...generatedConfig,
|
|
113
|
+
async headers() {
|
|
114
|
+
return [...existingHeaders ? await existingHeaders() : [], {
|
|
115
|
+
source: headerSource,
|
|
116
|
+
headers: [{
|
|
117
|
+
key: "Cache-Control",
|
|
118
|
+
value: "public, max-age=31536000, immutable"
|
|
119
|
+
}]
|
|
120
|
+
}];
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
//#endregion
|
|
126
|
+
export { withTastyNext };
|
|
127
|
+
|
|
128
|
+
//# sourceMappingURL=next-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"next-config.js","names":[],"sources":["../../src/ssr/next-config.ts"],"sourcesContent":["/**\n * Next.js configuration wrapper for extracting Tasty's configured global CSS.\n *\n * Import this Node-only module from `next.config.ts`. The client-safe registry\n * remains available from `@tenphi/tasty/ssr/next`.\n */\n\nimport { createHash } from 'node:crypto';\nimport { mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { isAbsolute, join, relative, resolve, sep } from 'node:path';\nimport type { createJiti as createJitiType } from 'jiti';\n\nimport type { TastyConfig } from '../config';\nimport { formatCounterStyleRule } from '../counter-style';\nimport { fontFaceContentHash, formatFontFaceRule } from '../font-face';\nimport { formatFunctionRule, parseFunctionName } from '../functions';\nimport { renderStyles } from '../pipeline';\nimport type { StyleResult } from '../pipeline';\nimport { DEFAULT_PROPERTIES } from '../properties/defaults';\nimport {\n configureZero,\n functionsForExtraction,\n resetZeroConfig,\n} from '../zero/config';\nimport { createServerStyleArtifact } from './artifacts';\nimport type { ServerStyleArtifact, ServerStyleArtifactKind } from './artifacts';\nimport { findUnsafeCSSResource } from './css-resources';\nimport { formatGlobalRules } from './format-global-rules';\nimport { formatPropertyCSS } from './format-property';\n\nconst ENV_KEY = 'TASTY_NEXT_SHARED_CSS_HREF';\nconst packageRequire = createRequire(import.meta.url);\n\ninterface NextConfig {\n basePath?: string;\n env?: Record<string, string | undefined>;\n headers?: () => Promise<NextHeader[]>;\n output?: string;\n [key: string]: unknown;\n}\n\ninterface NextHeader {\n source: string;\n headers: { key: string; value: string }[];\n [key: string]: unknown;\n}\n\nexport interface TastyNextOptions {\n /**\n * Next.js project directory. Useful when the build command runs from a\n * monorepo root rather than the app directory.\n *\n * @default process.cwd()\n */\n rootDir?: string;\n\n /**\n * Tasty configuration used to generate the shared stylesheet.\n * `config` takes precedence when both config sources are provided.\n */\n config?: TastyConfig;\n\n /**\n * Project-relative path to a TypeScript/JavaScript module whose default\n * export is a Tasty configuration object.\n *\n * @example './app/tasty.config.ts'\n */\n configFile?: string;\n\n /**\n * Filesystem directory for generated stylesheets. When it is inside the\n * project's `public` directory, its public URL is inferred automatically.\n *\n * @default 'public/_tasty'\n */\n outputDir?: string;\n\n /**\n * Root-relative URL path corresponding to `outputDir`. This is required\n * when `outputDir` is outside the project's `public` directory.\n * The Next.js `basePath` is prepended automatically.\n *\n * @default inferred from outputDir\n * @example '/assets/tasty'\n */\n publicPath?: string;\n\n /** Whether to generate and register the shared stylesheet. @default true */\n enabled?: boolean;\n}\n\nfunction loadConfig(\n projectDir: string,\n options: TastyNextOptions,\n): TastyConfig {\n if (options.config) return options.config;\n if (!options.configFile) {\n throw new Error(\n '[Tasty] withTastyNext() requires either `config` or `configFile`.',\n );\n }\n\n const configPath = resolve(projectDir, options.configFile);\n let jitiPath: string;\n try {\n jitiPath = packageRequire.resolve('jiti');\n } catch (error) {\n if (\n error instanceof Error &&\n 'code' in error &&\n error.code === 'MODULE_NOT_FOUND'\n ) {\n throw new Error(\n '[Tasty] `configFile` requires the optional `jiti` package. Install `jiti` or pass the imported config through `config` instead.',\n { cause: error },\n );\n }\n throw error;\n }\n const { createJiti } = packageRequire(jitiPath) as {\n createJiti: typeof createJitiType;\n };\n const jiti = createJiti(projectDir, { moduleCache: false });\n const loaded = jiti(configPath) as TastyConfig | { default: TastyConfig };\n\n return loaded && typeof loaded === 'object' && 'default' in loaded\n ? loaded.default\n : loaded;\n}\n\nfunction collectSharedCSS(config: TastyConfig): string {\n resetZeroConfig();\n try {\n const resolved = configureZero(config);\n const { normalized } = resolved;\n const artifacts: ServerStyleArtifact[] = [];\n const append = (\n kind: ServerStyleArtifactKind,\n key: string,\n css: string,\n ) => {\n if (!css) return;\n\n artifacts.push(\n createServerStyleArtifact(kind, key, css, artifacts.length),\n );\n };\n\n for (const [token, definition] of Object.entries({\n ...DEFAULT_PROPERTIES,\n ...normalized.properties,\n })) {\n append(\n 'property',\n `__prop:${token}`,\n formatPropertyCSS(token, definition),\n );\n }\n\n for (const [family, input] of Object.entries(normalized.fontFaces)) {\n const descriptors = Array.isArray(input) ? input : [input];\n for (const descriptor of descriptors) {\n append(\n 'font-face',\n fontFaceContentHash(family, descriptor),\n formatFontFaceRule(family, descriptor),\n );\n }\n }\n\n for (const [name, descriptors] of Object.entries(\n normalized.counterStyles,\n )) {\n append('counter-style', name, formatCounterStyleRule(name, descriptors));\n }\n\n for (const [name, definition] of Object.entries(\n functionsForExtraction(resolved) ?? {},\n )) {\n append(\n 'function',\n parseFunctionName(name),\n formatFunctionRule(name, definition),\n );\n }\n\n if (Object.keys(normalized.tokens).length > 0) {\n const rules = renderStyles(normalized.tokens, ':root') as StyleResult[];\n append('global', '__global:tokens', formatGlobalRules(rules));\n }\n\n for (const [selector, styles] of Object.entries(normalized.globalStyles)) {\n if (Object.keys(styles).length === 0) continue;\n const rules = renderStyles(styles, selector) as StyleResult[];\n append('global', `__global:styles:${selector}`, formatGlobalRules(rules));\n }\n\n for (const artifact of artifacts) {\n const unsafe = findUnsafeCSSResource(artifact.css, false);\n if (unsafe) {\n throw new Error(\n `[Tasty] Next.js shared CSS extraction cannot preserve page-relative CSS URL \"${unsafe.url}\" in ${artifact.kind} artifact ${artifact.id}. Use an absolute URL, a data URL, or a root-relative URL such as url(/path/to/asset).`,\n );\n }\n }\n\n return artifacts.map(({ css }) => css).join('\\n');\n } finally {\n resetZeroConfig();\n }\n}\n\nfunction inferPublicPath(projectDir: string, outputDir: string): string {\n const publicDir = resolve(projectDir, 'public');\n const relativePath = relative(publicDir, outputDir);\n if (\n relativePath === '..' ||\n relativePath.startsWith(`..${sep}`) ||\n isAbsolute(relativePath)\n ) {\n throw new Error(\n '[Tasty] `publicPath` is required when `outputDir` is outside the Next.js public directory.',\n );\n }\n\n return `/${relativePath.split(sep).filter(Boolean).join('/')}`;\n}\n\nfunction normalizeURLPath(path: string, option: string): string {\n if (\n !path.startsWith('/') ||\n path.startsWith('//') ||\n path.includes('?') ||\n path.includes('#') ||\n path.includes('\\\\')\n ) {\n throw new Error(`[Tasty] \\`${option}\\` must be a root-relative URL path.`);\n }\n\n let end = path.length;\n while (end > 0 && path[end - 1] === '/') end--;\n return path.slice(0, end);\n}\n\nfunction writeSharedCSS(outputDir: string, css: string): string {\n mkdirSync(outputDir, { recursive: true });\n const hash = createHash('sha256').update(css).digest('hex').slice(0, 12);\n const filename = `tasty.shared.${hash}.css`;\n\n const outputPath = join(outputDir, filename);\n let existing: string | undefined;\n try {\n existing = readFileSync(outputPath, 'utf8');\n } catch {\n // The file does not exist yet (or is unreadable); write it below.\n }\n if (existing !== css) writeFileSync(outputPath, css);\n\n return filename;\n}\n\n/**\n * Add a cacheable, content-hashed stylesheet for Tasty configuration globals.\n * Route-dependent component and hook styles continue to stream through\n * `TastyRegistry` so App Router navigation and Suspense remain correct.\n */\nexport function withTastyNext(options: TastyNextOptions) {\n return (nextConfig: NextConfig = {}): NextConfig => {\n if (options.enabled === false) return nextConfig;\n\n const projectDir = resolve(process.cwd(), options.rootDir ?? '.');\n const outputDir = resolve(projectDir, options.outputDir ?? 'public/_tasty');\n const publicPath = normalizeURLPath(\n options.publicPath ?? inferPublicPath(projectDir, outputDir),\n 'publicPath',\n );\n const basePath = normalizeURLPath(nextConfig.basePath || '/', 'basePath');\n const css = collectSharedCSS(loadConfig(projectDir, options));\n\n if (!css) return nextConfig;\n\n const filename = writeSharedCSS(outputDir, css);\n const href = `${basePath}${publicPath}/${filename}`;\n const headerSource = `${publicPath}/${filename}`;\n const existingEnv = nextConfig.env ?? {};\n const existingHeaders = nextConfig.headers;\n if (existingEnv[ENV_KEY] && existingEnv[ENV_KEY] !== href) {\n throw new Error(\n `[Tasty] Next.js env key ${ENV_KEY} is reserved by withTastyNext().`,\n );\n }\n\n const generatedConfig: NextConfig = {\n ...nextConfig,\n env: {\n ...existingEnv,\n [ENV_KEY]: href,\n },\n };\n\n // `headers()` is not emitted by Next's static export. Avoid introducing an\n // unsupported-config warning; the content hash still makes the asset safe\n // for the static host to cache immutably.\n if (nextConfig.output === 'export') return generatedConfig;\n\n return {\n ...generatedConfig,\n async headers() {\n const headers = existingHeaders ? await existingHeaders() : [];\n return [\n ...headers,\n {\n source: headerSource,\n headers: [\n {\n key: 'Cache-Control',\n value: 'public, max-age=31536000, immutable',\n },\n ],\n },\n ];\n },\n };\n };\n}\n"],"mappings":"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"}
|
package/dist/ssr/next.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { t as ServerStyleCollector } from "../collector-
|
|
1
|
+
import { t as ServerStyleCollector } from "../collector-w4mBj5gd.js";
|
|
2
2
|
import { ReactNode } from "react";
|
|
3
|
-
|
|
4
3
|
//#region src/ssr/next.d.ts
|
|
5
|
-
interface TastyRegistryProps {
|
|
4
|
+
export interface TastyRegistryProps {
|
|
6
5
|
children: ReactNode;
|
|
7
6
|
/**
|
|
8
7
|
* Whether to embed the class-list script for client hydration.
|
|
@@ -11,6 +10,12 @@ interface TastyRegistryProps {
|
|
|
11
10
|
* in server-rendered `<style>` tags. Default: true.
|
|
12
11
|
*/
|
|
13
12
|
transferCache?: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* URL of a stylesheet containing Tasty's configured global CSS.
|
|
15
|
+
* `withTastyNext()` sets this automatically. Pass false to disable it for
|
|
16
|
+
* this registry, or a URL to use a manually generated stylesheet.
|
|
17
|
+
*/
|
|
18
|
+
sharedStylesheet?: string | false;
|
|
14
19
|
}
|
|
15
20
|
/**
|
|
16
21
|
* Next.js App Router registry for Tasty SSR.
|
|
@@ -36,10 +41,6 @@ interface TastyRegistryProps {
|
|
|
36
41
|
* }
|
|
37
42
|
* ```
|
|
38
43
|
*/
|
|
39
|
-
declare function TastyRegistry({
|
|
40
|
-
children,
|
|
41
|
-
transferCache
|
|
42
|
-
}: TastyRegistryProps): import("react").FunctionComponentElement<import("react").ProviderProps<ServerStyleCollector | null>>;
|
|
44
|
+
export declare function TastyRegistry({ children, transferCache, sharedStylesheet }: TastyRegistryProps): import("react").FunctionComponentElement<import("react").ProviderProps<ServerStyleCollector | null>>;
|
|
43
45
|
//#endregion
|
|
44
|
-
export { TastyRegistry, TastyRegistryProps };
|
|
45
46
|
//# sourceMappingURL=next.d.ts.map
|
package/dist/ssr/next.js
CHANGED
|
@@ -1,70 +1,56 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { n as
|
|
3
|
-
import {
|
|
4
|
-
import { t as
|
|
5
|
-
import { t as
|
|
6
|
-
import { t as hydrateTastyClasses } from "../hydrate-aaUSNJZJ.js";
|
|
2
|
+
import { n as registerSSRCollectorGetter, u as getRuntimeConfigState } from "../chunks/runtime-state-BxaLhVdP.js";
|
|
3
|
+
import { u as getTastySSRContext } from "../chunks/react-runtime-BpxlOTbO.js";
|
|
4
|
+
import { t as ServerStyleCollector } from "../chunks/collector-D2ARGT2L.js";
|
|
5
|
+
import { t as hydrateTastyClasses } from "../chunks/hydration-TRcz5vnk.js";
|
|
7
6
|
import { Fragment, createElement, useState } from "react";
|
|
8
7
|
import { useServerInsertedHTML } from "next/navigation";
|
|
9
8
|
//#region src/ssr/next.ts
|
|
10
|
-
/**
|
|
11
|
-
* Next.js integration for Tasty SSR.
|
|
12
|
-
*
|
|
13
|
-
* Provides TastyRegistry for App Router (streaming via useServerInsertedHTML).
|
|
14
|
-
*
|
|
15
|
-
* Import from '@tenphi/tasty/ssr/next'.
|
|
16
|
-
*/
|
|
17
9
|
if (typeof window !== "undefined") hydrateTastyClasses();
|
|
18
|
-
|
|
19
|
-
* Next.js App Router registry for Tasty SSR.
|
|
20
|
-
*
|
|
21
|
-
* Wraps the component tree with a ServerStyleCollector and flushes
|
|
22
|
-
* collected CSS into the HTML stream via useServerInsertedHTML.
|
|
23
|
-
*
|
|
24
|
-
* @example
|
|
25
|
-
* ```tsx
|
|
26
|
-
* // app/tasty-registry.tsx
|
|
27
|
-
* 'use client';
|
|
28
|
-
* import { TastyRegistry } from '@tenphi/tasty/ssr/next';
|
|
29
|
-
* export default function TastyStyleRegistry({ children }) {
|
|
30
|
-
* return <TastyRegistry>{children}</TastyRegistry>;
|
|
31
|
-
* }
|
|
32
|
-
*
|
|
33
|
-
* // app/layout.tsx
|
|
34
|
-
* import TastyStyleRegistry from './tasty-registry';
|
|
35
|
-
* export default function RootLayout({ children }) {
|
|
36
|
-
* return <html><body>
|
|
37
|
-
* <TastyStyleRegistry>{children}</TastyStyleRegistry>
|
|
38
|
-
* </body></html>;
|
|
39
|
-
* }
|
|
40
|
-
* ```
|
|
41
|
-
*/
|
|
42
|
-
function TastyRegistry({ children, transferCache = true }) {
|
|
10
|
+
function TastyRegistry({ children, transferCache = true, sharedStylesheet = process.env.TASTY_NEXT_SHARED_CSS_HREF }) {
|
|
43
11
|
const isClient = typeof window !== "undefined";
|
|
44
12
|
const [collector] = useState(() => {
|
|
45
13
|
if (isClient) return null;
|
|
46
14
|
const instance = new ServerStyleCollector();
|
|
47
15
|
registerSSRCollectorGetter(() => instance);
|
|
16
|
+
if (sharedStylesheet) {
|
|
17
|
+
instance.collectInternals();
|
|
18
|
+
instance.flushCSS();
|
|
19
|
+
}
|
|
48
20
|
return instance;
|
|
49
21
|
});
|
|
50
|
-
const
|
|
22
|
+
const [streamState] = useState(() => ({ sharedStylesheetFlushed: false }));
|
|
23
|
+
const nonce = getRuntimeConfigState()?.nonce;
|
|
51
24
|
useServerInsertedHTML(() => {
|
|
52
25
|
if (!collector) return null;
|
|
53
26
|
const css = collector.flushCSS();
|
|
54
27
|
const classNames = collector.getRenderedClassNames();
|
|
55
|
-
|
|
28
|
+
let linkEl = null;
|
|
29
|
+
if (sharedStylesheet && !streamState.sharedStylesheetFlushed) {
|
|
30
|
+
streamState.sharedStylesheetFlushed = true;
|
|
31
|
+
linkEl = createElement("link", {
|
|
32
|
+
key: "tasty-shared-styles",
|
|
33
|
+
rel: "stylesheet",
|
|
34
|
+
href: sharedStylesheet,
|
|
35
|
+
"data-tasty-ssr": "",
|
|
36
|
+
nonce
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
if (!css) return linkEl;
|
|
56
40
|
const styleEl = createElement("style", {
|
|
57
41
|
key: "tasty-ssr-styles",
|
|
58
42
|
"data-tasty-ssr": "",
|
|
59
43
|
nonce,
|
|
60
44
|
dangerouslySetInnerHTML: { __html: css }
|
|
61
45
|
});
|
|
62
|
-
if (!transferCache || classNames.length === 0) return styleEl;
|
|
63
|
-
|
|
46
|
+
if (!transferCache || classNames.length === 0) return linkEl ? createElement(Fragment, null, linkEl, styleEl) : styleEl;
|
|
47
|
+
const classListJSON = classNames.map((n) => `"${n}"`).join(",");
|
|
48
|
+
const scriptEl = createElement("script", {
|
|
64
49
|
key: "tasty-ssr-cache",
|
|
65
50
|
nonce,
|
|
66
|
-
dangerouslySetInnerHTML: { __html: `(window.__TASTY__=window.__TASTY__||[]).push(${
|
|
67
|
-
})
|
|
51
|
+
dangerouslySetInnerHTML: { __html: `(window.__TASTY__=window.__TASTY__||[]).push(${classListJSON})` }
|
|
52
|
+
});
|
|
53
|
+
return createElement(Fragment, null, linkEl, styleEl, scriptEl);
|
|
68
54
|
});
|
|
69
55
|
return createElement(getTastySSRContext().Provider, { value: collector }, children);
|
|
70
56
|
}
|
package/dist/ssr/next.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"next.js","names":[],"sources":["../../src/ssr/next.ts"],"sourcesContent":["/**\n * Next.js integration for Tasty SSR.\n *\n * Provides TastyRegistry for App Router (streaming via useServerInsertedHTML).\n *\n * Import from '@tenphi/tasty/ssr/next'.\n */\n\n'use client';\n\n/// <reference path=\"./next-navigation.d.ts\" />\n\nimport { createElement, Fragment, useState, type ReactNode } from 'react';\nimport { useServerInsertedHTML } from 'next/navigation';\n\nimport {
|
|
1
|
+
{"version":3,"file":"next.js","names":[],"sources":["../../src/ssr/next.ts"],"sourcesContent":["/**\n * Next.js integration for Tasty SSR.\n *\n * Provides TastyRegistry for App Router (streaming via useServerInsertedHTML).\n *\n * Import from '@tenphi/tasty/ssr/next'.\n */\n\n'use client';\n\n/// <reference path=\"./next-navigation.d.ts\" />\n\nimport { createElement, Fragment, useState, type ReactNode } from 'react';\nimport { useServerInsertedHTML } from 'next/navigation';\n\nimport { getRuntimeConfigState } from '../config-resources';\nimport { ServerStyleCollector } from './collector';\nimport { getTastySSRContext } from './context';\nimport { hydrateTastyClasses } from './hydrate';\nimport { registerSSRCollectorGetter } from './ssr-collector-ref';\n\n// Auto-hydrate on module load (client only).\n// Reads the class name list from `window.__TASTY__` populated by streaming scripts.\nif (typeof window !== 'undefined') {\n hydrateTastyClasses();\n}\n\nexport interface TastyRegistryProps {\n children: ReactNode;\n /**\n * Whether to embed the class-list script for client hydration.\n * Set to false to skip class transfer (e.g. for CSP restrictions).\n * Without it, client components may re-inject CSS that already exists\n * in server-rendered `<style>` tags. Default: true.\n */\n transferCache?: boolean;\n /**\n * URL of a stylesheet containing Tasty's configured global CSS.\n * `withTastyNext()` sets this automatically. Pass false to disable it for\n * this registry, or a URL to use a manually generated stylesheet.\n */\n sharedStylesheet?: string | false;\n}\n\n/**\n * Next.js App Router registry for Tasty SSR.\n *\n * Wraps the component tree with a ServerStyleCollector and flushes\n * collected CSS into the HTML stream via useServerInsertedHTML.\n *\n * @example\n * ```tsx\n * // app/tasty-registry.tsx\n * 'use client';\n * import { TastyRegistry } from '@tenphi/tasty/ssr/next';\n * export default function TastyStyleRegistry({ children }) {\n * return <TastyRegistry>{children}</TastyRegistry>;\n * }\n *\n * // app/layout.tsx\n * import TastyStyleRegistry from './tasty-registry';\n * export default function RootLayout({ children }) {\n * return <html><body>\n * <TastyStyleRegistry>{children}</TastyStyleRegistry>\n * </body></html>;\n * }\n * ```\n */\nexport function TastyRegistry({\n children,\n transferCache = true,\n sharedStylesheet = process.env.TASTY_NEXT_SHARED_CSS_HREF,\n}: TastyRegistryProps) {\n const isClient = typeof window !== 'undefined';\n\n const [collector] = useState(() => {\n if (isClient) return null;\n\n const instance = new ServerStyleCollector();\n\n registerSSRCollectorGetter(() => instance);\n\n // The generated stylesheet already contains configured global artifacts.\n // Mark that first batch as flushed so only request-specific styles stream.\n if (sharedStylesheet) {\n instance.collectInternals();\n instance.flushCSS();\n }\n\n return instance;\n });\n const [streamState] = useState(() => ({ sharedStylesheetFlushed: false }));\n const nonce = getRuntimeConfigState()?.nonce;\n\n useServerInsertedHTML(() => {\n if (!collector) return null;\n\n const css = collector.flushCSS();\n const classNames = collector.getRenderedClassNames();\n\n let linkEl = null;\n if (sharedStylesheet && !streamState.sharedStylesheetFlushed) {\n streamState.sharedStylesheetFlushed = true;\n linkEl = createElement('link', {\n key: 'tasty-shared-styles',\n rel: 'stylesheet',\n href: sharedStylesheet,\n 'data-tasty-ssr': '',\n nonce,\n });\n }\n\n if (!css) return linkEl;\n\n const styleEl = createElement('style', {\n key: 'tasty-ssr-styles',\n 'data-tasty-ssr': '',\n nonce,\n dangerouslySetInnerHTML: { __html: css },\n });\n\n if (!transferCache || classNames.length === 0) {\n return linkEl ? createElement(Fragment, null, linkEl, styleEl) : styleEl;\n }\n\n const classListJSON = classNames.map((n) => `\"${n}\"`).join(',');\n\n const scriptEl = createElement('script', {\n key: 'tasty-ssr-cache',\n nonce,\n dangerouslySetInnerHTML: {\n __html: `(window.__TASTY__=window.__TASTY__||[]).push(${classListJSON})`,\n },\n });\n\n return createElement(Fragment, null, linkEl, styleEl, scriptEl);\n });\n\n return createElement(\n getTastySSRContext().Provider,\n { value: collector },\n children,\n );\n}\n"],"mappings":";;;;;;;;AAuBA,IAAI,OAAO,WAAW,aACpB,oBAAoB;AA4CtB,SAAgB,cAAc,EAC5B,UACA,gBAAgB,MAChB,mBAAmB,QAAQ,IAAI,8BACV;CACrB,MAAM,WAAW,OAAO,WAAW;CAEnC,MAAM,CAAC,aAAa,eAAe;EACjC,IAAI,UAAU,OAAO;EAErB,MAAM,WAAW,IAAI,qBAAqB;EAE1C,iCAAiC,QAAQ;EAIzC,IAAI,kBAAkB;GACpB,SAAS,iBAAiB;GAC1B,SAAS,SAAS;EACpB;EAEA,OAAO;CACT,CAAC;CACD,MAAM,CAAC,eAAe,gBAAgB,EAAE,yBAAyB,MAAM,EAAE;CACzE,MAAM,QAAQ,sBAAsB,CAAC,EAAE;CAEvC,4BAA4B;EAC1B,IAAI,CAAC,WAAW,OAAO;EAEvB,MAAM,MAAM,UAAU,SAAS;EAC/B,MAAM,aAAa,UAAU,sBAAsB;EAEnD,IAAI,SAAS;EACb,IAAI,oBAAoB,CAAC,YAAY,yBAAyB;GAC5D,YAAY,0BAA0B;GACtC,SAAS,cAAc,QAAQ;IAC7B,KAAK;IACL,KAAK;IACL,MAAM;IACN,kBAAkB;IAClB;GACF,CAAC;EACH;EAEA,IAAI,CAAC,KAAK,OAAO;EAEjB,MAAM,UAAU,cAAc,SAAS;GACrC,KAAK;GACL,kBAAkB;GAClB;GACA,yBAAyB,EAAE,QAAQ,IAAI;EACzC,CAAC;EAED,IAAI,CAAC,iBAAiB,WAAW,WAAW,GAC1C,OAAO,SAAS,cAAc,UAAU,MAAM,QAAQ,OAAO,IAAI;EAGnE,MAAM,gBAAgB,WAAW,KAAK,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,GAAG;EAE9D,MAAM,WAAW,cAAc,UAAU;GACvC,KAAK;GACL;GACA,yBAAyB,EACvB,QAAQ,gDAAgD,cAAc,GACxE;EACF,CAAC;EAED,OAAO,cAAc,UAAU,MAAM,QAAQ,SAAS,QAAQ;CAChE,CAAC;CAED,OAAO,cACL,mBAAmB,CAAC,CAAC,UACrB,EAAE,OAAO,UAAU,GACnB,QACF;AACF"}
|
package/dist/static/index.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as mergeStyles } from "../merge-styles-
|
|
3
|
-
|
|
1
|
+
import { Y as Styles } from "../types-JEY8PVYP.js";
|
|
2
|
+
import { t as mergeStyles } from "../merge-styles-VXwJ0Frr.js";
|
|
4
3
|
//#region src/static/types.d.ts
|
|
5
4
|
/**
|
|
6
5
|
* Static style definition returned by tastyStatic().
|
|
@@ -40,11 +39,11 @@ interface StaticStyle {
|
|
|
40
39
|
* Create a StaticStyle object.
|
|
41
40
|
* Used internally by the Babel plugin to generate output.
|
|
42
41
|
*/
|
|
43
|
-
declare function createStaticStyle(className: string, styles: Styles): StaticStyle;
|
|
42
|
+
export declare function createStaticStyle(className: string, styles: Styles): StaticStyle;
|
|
44
43
|
/**
|
|
45
44
|
* Type guard to check if a value is a StaticStyle object.
|
|
46
45
|
*/
|
|
47
|
-
declare function isStaticStyle(value: unknown): value is StaticStyle;
|
|
46
|
+
export declare function isStaticStyle(value: unknown): value is StaticStyle;
|
|
48
47
|
//#endregion
|
|
49
48
|
//#region src/static/tastyStatic.d.ts
|
|
50
49
|
/**
|
|
@@ -62,7 +61,7 @@ declare function isStaticStyle(value: unknown): value is StaticStyle;
|
|
|
62
61
|
* <div className={button} /> // Works via toString()
|
|
63
62
|
* ```
|
|
64
63
|
*/
|
|
65
|
-
declare function tastyStatic(styles: Styles): StaticStyle;
|
|
64
|
+
export declare function tastyStatic(styles: Styles): StaticStyle;
|
|
66
65
|
/**
|
|
67
66
|
* Extend an existing StaticStyle with additional styles.
|
|
68
67
|
* Uses mergeStyles() internally for proper nested selector handling.
|
|
@@ -74,7 +73,7 @@ declare function tastyStatic(styles: Styles): StaticStyle;
|
|
|
74
73
|
* // After build: { className: 'ts8c4d2e', styles: {...merged...}, toString() }
|
|
75
74
|
* ```
|
|
76
75
|
*/
|
|
77
|
-
declare function tastyStatic(base: StaticStyle, styles: Styles): StaticStyle;
|
|
76
|
+
export declare function tastyStatic(base: StaticStyle, styles: Styles): StaticStyle;
|
|
78
77
|
/**
|
|
79
78
|
* Generate styles for a specific CSS selector.
|
|
80
79
|
* The call is completely removed after build transformation.
|
|
@@ -85,7 +84,7 @@ declare function tastyStatic(base: StaticStyle, styles: Styles): StaticStyle;
|
|
|
85
84
|
* // After build: (removed)
|
|
86
85
|
* ```
|
|
87
86
|
*/
|
|
88
|
-
declare function tastyStatic(selector: string, styles: Styles): void;
|
|
87
|
+
export declare function tastyStatic(selector: string, styles: Styles): void;
|
|
89
88
|
//#endregion
|
|
90
|
-
export { type StaticStyle, type Styles,
|
|
89
|
+
export { type StaticStyle, type Styles, mergeStyles };
|
|
91
90
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/static/index.js
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
import { t as mergeStyles } from "../
|
|
1
|
+
import { t as mergeStyles } from "../chunks/shared-utils-y-HjvPN4.js";
|
|
2
2
|
//#region src/static/types.ts
|
|
3
|
-
/**
|
|
4
|
-
* Create a StaticStyle object.
|
|
5
|
-
* Used internally by the Babel plugin to generate output.
|
|
6
|
-
*/
|
|
7
3
|
function createStaticStyle(className, styles) {
|
|
8
4
|
return {
|
|
9
5
|
className,
|
|
@@ -13,35 +9,21 @@ function createStaticStyle(className, styles) {
|
|
|
13
9
|
}
|
|
14
10
|
};
|
|
15
11
|
}
|
|
16
|
-
/**
|
|
17
|
-
* Type guard to check if a value is a StaticStyle object.
|
|
18
|
-
*/
|
|
19
12
|
function isStaticStyle(value) {
|
|
20
13
|
return typeof value === "object" && value !== null && "className" in value && "styles" in value && "toString" in value && typeof value.className === "string" && typeof value.styles === "object";
|
|
21
14
|
}
|
|
22
15
|
//#endregion
|
|
23
16
|
//#region src/static/tastyStatic.ts
|
|
24
|
-
/**
|
|
25
|
-
* Build-time only function for zero-runtime static site generation.
|
|
26
|
-
*
|
|
27
|
-
* This function is transformed by the Babel plugin:
|
|
28
|
-
* - `tastyStatic(styles)` → StaticStyle object with className
|
|
29
|
-
* - `tastyStatic(base, styles)` → StaticStyle object with merged styles
|
|
30
|
-
* - `tastyStatic(selector, styles)` → removed entirely
|
|
31
|
-
*
|
|
32
|
-
* At runtime (during development/build), this function returns a placeholder.
|
|
33
|
-
* In production, all calls are replaced/removed by the build plugin.
|
|
34
|
-
*/
|
|
35
17
|
function tastyStatic(stylesOrBaseOrSelector, styles) {
|
|
36
18
|
if (typeof stylesOrBaseOrSelector === "string") {
|
|
37
|
-
console.warn(`[Tasty] tastyStatic('${stylesOrBaseOrSelector}', styles) was called at runtime. This indicates the Babel plugin is not configured. Add @tenphi/tasty/babel-plugin to your Babel config.`);
|
|
19
|
+
if (process.env.NODE_ENV !== "production") console.warn(`[Tasty] tastyStatic('${stylesOrBaseOrSelector}', styles) was called at runtime. This indicates the Babel plugin is not configured. Add @tenphi/tasty/babel-plugin to your Babel config.`);
|
|
38
20
|
return;
|
|
39
21
|
}
|
|
40
22
|
if (isStaticStyle(stylesOrBaseOrSelector)) {
|
|
41
|
-
console.warn("[Tasty] tastyStatic(base, styles) was called at runtime. This indicates the Babel plugin is not configured. Add @tenphi/tasty/babel-plugin to your Babel config.");
|
|
23
|
+
if (process.env.NODE_ENV !== "production") console.warn("[Tasty] tastyStatic(base, styles) was called at runtime. This indicates the Babel plugin is not configured. Add @tenphi/tasty/babel-plugin to your Babel config.");
|
|
42
24
|
return createStaticStyle("__TASTY_STATIC_NOT_TRANSFORMED__", mergeStyles(stylesOrBaseOrSelector.styles, styles || {}));
|
|
43
25
|
}
|
|
44
|
-
console.warn("[Tasty] tastyStatic(styles) was called at runtime. This indicates the Babel plugin is not configured. Add @tenphi/tasty/babel-plugin to your Babel config.");
|
|
26
|
+
if (process.env.NODE_ENV !== "production") console.warn("[Tasty] tastyStatic(styles) was called at runtime. This indicates the Babel plugin is not configured. Add @tenphi/tasty/babel-plugin to your Babel config.");
|
|
45
27
|
return createStaticStyle("__TASTY_STATIC_NOT_TRANSFORMED__", stylesOrBaseOrSelector);
|
|
46
28
|
}
|
|
47
29
|
//#endregion
|
package/dist/static/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/static/types.ts","../../src/static/tastyStatic.ts"],"sourcesContent":["import type { Styles } from '../styles/types';\n\n/**\n * Static style definition returned by tastyStatic().\n *\n * Supports both explicit className access and implicit string coercion via toString().\n *\n * @example\n * ```typescript\n * const button = tastyStatic({ fill: '#blue' });\n *\n * // Both work in JSX:\n * <div className={button} /> // Uses toString()\n * <div className={button.className} /> // Explicit\n *\n * // Extension:\n * const primary = tastyStatic(button, { fill: '#purple' });\n * ```\n */\nexport interface StaticStyle {\n /**\n * Generated className(s) for use in JSX.\n * May contain multiple space-separated class names due to chunking.\n */\n className: string;\n\n /**\n * The original (or merged) styles object.\n * Available for extension via tastyStatic(base, overrides).\n */\n styles: Styles;\n\n /**\n * Returns className for implicit string coercion.\n * Enables `<div className={button} />` syntax.\n */\n toString(): string;\n}\n\n/**\n * Create a StaticStyle object.\n * Used internally by the Babel plugin to generate output.\n */\nexport function createStaticStyle(\n className: string,\n styles: Styles,\n): StaticStyle {\n return {\n className,\n styles,\n toString() {\n return this.className;\n },\n };\n}\n\n/**\n * Type guard to check if a value is a StaticStyle object.\n */\nexport function isStaticStyle(value: unknown): value is StaticStyle {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'className' in value &&\n 'styles' in value &&\n 'toString' in value &&\n typeof (value as StaticStyle).className === 'string' &&\n typeof (value as StaticStyle).styles === 'object'\n );\n}\n","import type { Styles } from '../styles/types';\nimport { mergeStyles } from '../utils/merge-styles';\n\nimport type { StaticStyle } from './types';\nimport { createStaticStyle, isStaticStyle } from './types';\n\n/**\n * Generate styles and return a StaticStyle object.\n * The object has `className`, `styles`, and `toString()`.\n *\n * @example\n * ```typescript\n * const button = tastyStatic({\n * fill: '#blue',\n * padding: '2x',\n * });\n * // After build: { className: 'ts3f2a1b', styles: {...}, toString() }\n *\n * <div className={button} /> // Works via toString()\n * ```\n */\nexport function tastyStatic(styles: Styles): StaticStyle;\n\n/**\n * Extend an existing StaticStyle with additional styles.\n * Uses mergeStyles() internally for proper nested selector handling.\n *\n * @example\n * ```typescript\n * const button = tastyStatic({ fill: '#blue' });\n * const primary = tastyStatic(button, { fill: '#purple' });\n * // After build: { className: 'ts8c4d2e', styles: {...merged...}, toString() }\n * ```\n */\nexport function tastyStatic(base: StaticStyle, styles: Styles): StaticStyle;\n\n/**\n * Generate styles for a specific CSS selector.\n * The call is completely removed after build transformation.\n *\n * @example\n * ```typescript\n * tastyStatic('.heading', { preset: 'h1', color: '#primary' });\n * // After build: (removed)\n * ```\n */\nexport function tastyStatic(selector: string, styles: Styles): void;\n\n/**\n * Build-time only function for zero-runtime static site generation.\n *\n * This function is transformed by the Babel plugin:\n * - `tastyStatic(styles)` → StaticStyle object with className\n * - `tastyStatic(base, styles)` → StaticStyle object with merged styles\n * - `tastyStatic(selector, styles)` → removed entirely\n *\n * At runtime (during development/build), this function returns a placeholder.\n * In production, all calls are replaced/removed by the build plugin.\n */\nexport function tastyStatic(\n stylesOrBaseOrSelector: Styles | StaticStyle | string,\n styles?: Styles,\n): StaticStyle | void {\n // This code only executes if the Babel plugin hasn't processed the file yet.\n // In a properly configured build, this function is never called at runtime.\n\n if (typeof stylesOrBaseOrSelector === 'string') {\n // Selector mode: tastyStatic(selector, styles)\n // The plugin will remove this call entirely\n if (process.env.NODE_ENV !== 'production') {\n console.warn(\n `[Tasty] tastyStatic('${stylesOrBaseOrSelector}', styles) was called at runtime. ` +\n 'This indicates the Babel plugin is not configured. ' +\n 'Add @tenphi/tasty/babel-plugin to your Babel config.',\n );\n }\n return; // void\n }\n\n if (isStaticStyle(stylesOrBaseOrSelector)) {\n // Extension mode: tastyStatic(base, styles)\n if (process.env.NODE_ENV !== 'production') {\n console.warn(\n '[Tasty] tastyStatic(base, styles) was called at runtime. ' +\n 'This indicates the Babel plugin is not configured. ' +\n 'Add @tenphi/tasty/babel-plugin to your Babel config.',\n );\n }\n // Merge styles for dev mode preview (won't have real classNames)\n const mergedStyles = mergeStyles(\n stylesOrBaseOrSelector.styles,\n styles || {},\n );\n return createStaticStyle('__TASTY_STATIC_NOT_TRANSFORMED__', mergedStyles);\n }\n\n // Styles mode: tastyStatic(styles)\n if (process.env.NODE_ENV !== 'production') {\n console.warn(\n '[Tasty] tastyStatic(styles) was called at runtime. ' +\n 'This indicates the Babel plugin is not configured. ' +\n 'Add @tenphi/tasty/babel-plugin to your Babel config.',\n );\n }\n\n // Return placeholder - styles won't be applied without the plugin\n return createStaticStyle(\n '__TASTY_STATIC_NOT_TRANSFORMED__',\n stylesOrBaseOrSelector,\n );\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/static/types.ts","../../src/static/tastyStatic.ts"],"sourcesContent":["import type { Styles } from '../styles/types';\n\n/**\n * Static style definition returned by tastyStatic().\n *\n * Supports both explicit className access and implicit string coercion via toString().\n *\n * @example\n * ```typescript\n * const button = tastyStatic({ fill: '#blue' });\n *\n * // Both work in JSX:\n * <div className={button} /> // Uses toString()\n * <div className={button.className} /> // Explicit\n *\n * // Extension:\n * const primary = tastyStatic(button, { fill: '#purple' });\n * ```\n */\nexport interface StaticStyle {\n /**\n * Generated className(s) for use in JSX.\n * May contain multiple space-separated class names due to chunking.\n */\n className: string;\n\n /**\n * The original (or merged) styles object.\n * Available for extension via tastyStatic(base, overrides).\n */\n styles: Styles;\n\n /**\n * Returns className for implicit string coercion.\n * Enables `<div className={button} />` syntax.\n */\n toString(): string;\n}\n\n/**\n * Create a StaticStyle object.\n * Used internally by the Babel plugin to generate output.\n */\nexport function createStaticStyle(\n className: string,\n styles: Styles,\n): StaticStyle {\n return {\n className,\n styles,\n toString() {\n return this.className;\n },\n };\n}\n\n/**\n * Type guard to check if a value is a StaticStyle object.\n */\nexport function isStaticStyle(value: unknown): value is StaticStyle {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'className' in value &&\n 'styles' in value &&\n 'toString' in value &&\n typeof (value as StaticStyle).className === 'string' &&\n typeof (value as StaticStyle).styles === 'object'\n );\n}\n","import type { Styles } from '../styles/types';\nimport { mergeStyles } from '../utils/merge-styles';\n\nimport type { StaticStyle } from './types';\nimport { createStaticStyle, isStaticStyle } from './types';\n\n/**\n * Generate styles and return a StaticStyle object.\n * The object has `className`, `styles`, and `toString()`.\n *\n * @example\n * ```typescript\n * const button = tastyStatic({\n * fill: '#blue',\n * padding: '2x',\n * });\n * // After build: { className: 'ts3f2a1b', styles: {...}, toString() }\n *\n * <div className={button} /> // Works via toString()\n * ```\n */\nexport function tastyStatic(styles: Styles): StaticStyle;\n\n/**\n * Extend an existing StaticStyle with additional styles.\n * Uses mergeStyles() internally for proper nested selector handling.\n *\n * @example\n * ```typescript\n * const button = tastyStatic({ fill: '#blue' });\n * const primary = tastyStatic(button, { fill: '#purple' });\n * // After build: { className: 'ts8c4d2e', styles: {...merged...}, toString() }\n * ```\n */\nexport function tastyStatic(base: StaticStyle, styles: Styles): StaticStyle;\n\n/**\n * Generate styles for a specific CSS selector.\n * The call is completely removed after build transformation.\n *\n * @example\n * ```typescript\n * tastyStatic('.heading', { preset: 'h1', color: '#primary' });\n * // After build: (removed)\n * ```\n */\nexport function tastyStatic(selector: string, styles: Styles): void;\n\n/**\n * Build-time only function for zero-runtime static site generation.\n *\n * This function is transformed by the Babel plugin:\n * - `tastyStatic(styles)` → StaticStyle object with className\n * - `tastyStatic(base, styles)` → StaticStyle object with merged styles\n * - `tastyStatic(selector, styles)` → removed entirely\n *\n * At runtime (during development/build), this function returns a placeholder.\n * In production, all calls are replaced/removed by the build plugin.\n */\nexport function tastyStatic(\n stylesOrBaseOrSelector: Styles | StaticStyle | string,\n styles?: Styles,\n): StaticStyle | void {\n // This code only executes if the Babel plugin hasn't processed the file yet.\n // In a properly configured build, this function is never called at runtime.\n\n if (typeof stylesOrBaseOrSelector === 'string') {\n // Selector mode: tastyStatic(selector, styles)\n // The plugin will remove this call entirely\n if (process.env.NODE_ENV !== 'production') {\n console.warn(\n `[Tasty] tastyStatic('${stylesOrBaseOrSelector}', styles) was called at runtime. ` +\n 'This indicates the Babel plugin is not configured. ' +\n 'Add @tenphi/tasty/babel-plugin to your Babel config.',\n );\n }\n return; // void\n }\n\n if (isStaticStyle(stylesOrBaseOrSelector)) {\n // Extension mode: tastyStatic(base, styles)\n if (process.env.NODE_ENV !== 'production') {\n console.warn(\n '[Tasty] tastyStatic(base, styles) was called at runtime. ' +\n 'This indicates the Babel plugin is not configured. ' +\n 'Add @tenphi/tasty/babel-plugin to your Babel config.',\n );\n }\n // Merge styles for dev mode preview (won't have real classNames)\n const mergedStyles = mergeStyles(\n stylesOrBaseOrSelector.styles,\n styles || {},\n );\n return createStaticStyle('__TASTY_STATIC_NOT_TRANSFORMED__', mergedStyles);\n }\n\n // Styles mode: tastyStatic(styles)\n if (process.env.NODE_ENV !== 'production') {\n console.warn(\n '[Tasty] tastyStatic(styles) was called at runtime. ' +\n 'This indicates the Babel plugin is not configured. ' +\n 'Add @tenphi/tasty/babel-plugin to your Babel config.',\n );\n }\n\n // Return placeholder - styles won't be applied without the plugin\n return createStaticStyle(\n '__TASTY_STATIC_NOT_TRANSFORMED__',\n stylesOrBaseOrSelector,\n );\n}\n"],"mappings":";;AA2CA,SAAgB,kBACd,WACA,QACa;CACb,OAAO;EACL;EACA;EACA,WAAW;GACT,OAAO,KAAK;EACd;CACF;AACF;AAKA,SAAgB,cAAc,OAAsC;CAClE,OACE,OAAO,UAAU,YACjB,UAAU,QACV,eAAe,SACf,YAAY,SACZ,cAAc,SACd,OAAQ,MAAsB,cAAc,YAC5C,OAAQ,MAAsB,WAAW;AAE7C;;;ACVA,SAAgB,YACd,wBACA,QACoB;CAIpB,IAAI,OAAO,2BAA2B,UAAU;EAG9C,IAAA,QAAA,IAAA,aAA6B,cAC3B,QAAQ,KACN,wBAAwB,uBAAuB,0IAGjD;EAEF;CACF;CAEA,IAAI,cAAc,sBAAsB,GAAG;EAEzC,IAAA,QAAA,IAAA,aAA6B,cAC3B,QAAQ,KACN,kKAGF;EAOF,OAAO,kBAAkB,oCAJJ,YACnB,uBAAuB,QACvB,UAAU,CAAC,CAEgD,CAAY;CAC3E;CAGA,IAAA,QAAA,IAAA,aAA6B,cAC3B,QAAQ,KACN,4JAGF;CAIF,OAAO,kBACL,oCACA,sBACF;AACF"}
|
package/dist/static/inject.d.ts
CHANGED