@barocss/browser 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -1
- package/dist/cdn/barocss.js +187 -42
- package/dist/cdn/barocss.js.map +1 -1
- package/dist/cdn/barocss.umd.cjs +1 -1
- package/dist/cdn/barocss.umd.cjs.map +1 -1
- package/dist/index.d.ts +19 -1
- package/dist/index.es.js +153 -105
- package/dist/index.umd.js +5 -5
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -21,6 +21,8 @@ const runtime = getRuntime({
|
|
|
21
21
|
config: {
|
|
22
22
|
cssVarPrefix: 'tw', // share --tw-* composite variables with the Tailwind build
|
|
23
23
|
theme: { extend: shadcnTheme }, // use the shadcn :root tokens (primary, muted-foreground, ...)
|
|
24
|
+
darkMode: 'class', // dark: follows the page's dark class, not the OS setting
|
|
25
|
+
darkModeSelector: '.dark &', // mirrors shadcn v4's `@custom-variant dark (&:is(.dark *))`
|
|
24
26
|
// preflight: leave unset. The layered preflight (@layer base) is the default and should stay on.
|
|
25
27
|
},
|
|
26
28
|
});
|
|
@@ -31,10 +33,22 @@ preloadJsonRenderClasses(spec, runtime); // BEFORE mounting, so there is no uns
|
|
|
31
33
|
renderJsonUi(spec); // mount your json-render Renderer
|
|
32
34
|
```
|
|
33
35
|
|
|
34
|
-
The
|
|
36
|
+
The six settings: `skipExisting: true`, `cssVarPrefix: 'tw'`, `theme: { extend: shadcnTheme }`, `darkMode: 'class'` with `darkModeSelector` copied from the build, `preloadJsonRenderClasses(spec, runtime)` before mount, and the default layered preflight (don't set `preflight: false`).
|
|
37
|
+
|
|
38
|
+
**Dark mode:** set `darkModeSelector` to the selector inside your CSS's `@custom-variant dark (...)`, so runtime `dark:` classes switch at the same moment as the build's:
|
|
39
|
+
|
|
40
|
+
| build CSS | companion config |
|
|
41
|
+
|---|---|
|
|
42
|
+
| `@custom-variant dark (&:is(.dark *));` (shadcn v4) | `darkMode: 'class', darkModeSelector: '.dark &'` |
|
|
43
|
+
| `@custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *));` (e.g. AstroPaper) | `darkMode: 'class', darkModeSelector: '[data-theme=dark] &'` |
|
|
44
|
+
| no `@custom-variant dark` (OS setting) | leave `darkMode` unset (`'media'`) |
|
|
45
|
+
|
|
46
|
+
Don't use `darkMode: 'class'` without a selector here: it matches `.dark` on the same element only, so `<html class="dark">` does not switch runtime classes.
|
|
35
47
|
|
|
36
48
|
**Non-shadcn site theme:** put the site's own tokens in `theme.extend` (e.g. `colors: { brand: { 600: '#2563eb' } }`). Literal values are safe. Pointing a token at the build's own var name (`brand: { 600: 'var(--color-brand-600)' }`) is also fine: BaroCSS skips that self-referencing `:root` var, so the build's value wins and `bg-brand-600` still uses it.
|
|
37
49
|
|
|
50
|
+
**Custom utilities:** mirror each static `@utility name { ... }` from your CSS in `utilities`, so runtime content that reuses it (with variants and `!`) matches the build: `utilities: { 'max-w-app': { 'max-width': '72rem', 'margin-inline': 'auto' } }`. A name that equals a built-in extends it as `@utility` does in Tailwind 4: the built-in declarations come first, then yours, so a repeated property takes your value. Names must be plain class idents; invalid names or unsafe declarations are skipped. Functional `@utility name-*` is not supported.
|
|
51
|
+
|
|
38
52
|
**Verify it rendered** (DevTools console, after mount):
|
|
39
53
|
|
|
40
54
|
```js
|
|
@@ -45,6 +59,14 @@ document.querySelectorAll('style[id^="barocss-runtime"]').length; // > 0
|
|
|
45
59
|
|
|
46
60
|
**Browser support:** Chrome/Edge 85+, Safari/iOS 16.4+, Firefox 128+. The runtime needs CSS `@property`; composite utilities (shadows, rings, transforms, filters) may not render on older engines.
|
|
47
61
|
|
|
62
|
+
## Server-rendered pages (SSR)
|
|
63
|
+
|
|
64
|
+
> BaroCSS is JS-only: there is no CSS entry, so never `@import "@barocss/kit"` in CSS. `generateCssForHtml`/`ssrStyleTag` are available from `@barocss/server` 0.7.0.
|
|
65
|
+
>
|
|
66
|
+
> Use the same config as the server: `darkModeSelector` from the build's `@custom-variant dark`, `utilities` mirroring static `@utility` rules (functional `@utility name-*` unsupported), both `prefix: 'tw'` and `cssVarPrefix: 'tw'` for a `prefix(tw)` build, and literal values in `theme.extend` for your own theme (next to `shadcnTheme`).
|
|
67
|
+
|
|
68
|
+
The runtime adopts a `<style data-barocss-ssr>` sheet from `@barocss/server` (`ssrStyleTag(runtime.generateCssForHtml(html, { skip: buildCss }))`), but only one that is in `<head>` when the runtime starts (at construction or the first `observe()`). A marked sheet added later or placed in `<body>` is treated as an ordinary sheet. It never regenerates those classes and GC never reclaims them. Their rules move into the runtime's ordered partitions, so later client rules keep Tailwind's variant order. For the Next.js App Router and Astro recipe, see the [`@barocss/server` README](../barocss-server/README.md#recipe-ssr-with-a-tailwind-build-nextjs-app-router-astro).
|
|
69
|
+
|
|
48
70
|
## ✨ Key Features
|
|
49
71
|
|
|
50
72
|
- **🚀 Real-time DOM Detection** - Automatically detects and processes class changes
|
package/dist/cdn/barocss.js
CHANGED
|
@@ -178,8 +178,12 @@ function clearContextCaches(ctx) {
|
|
|
178
178
|
}
|
|
179
179
|
const utilityRegistry = [];
|
|
180
180
|
function registerUtility(util, ctx) {
|
|
181
|
-
|
|
182
|
-
|
|
181
|
+
const state = ctx && getContextState(ctx);
|
|
182
|
+
if (ctx && !state) throw new Error("Utility registration requires a context from createContext");
|
|
183
|
+
(state?.utilities || utilityRegistry).push(util);
|
|
184
|
+
if (ctx) {
|
|
185
|
+
clearContextCaches(ctx);
|
|
186
|
+
} else {
|
|
183
187
|
parseResultCache.clear();
|
|
184
188
|
utilityCache.clear();
|
|
185
189
|
}
|
|
@@ -273,7 +277,7 @@ function staticUtility(name, decls, opts, ctx) {
|
|
|
273
277
|
description: opts?.description,
|
|
274
278
|
category: opts?.category,
|
|
275
279
|
priority: opts?.priority
|
|
276
|
-
});
|
|
280
|
+
}, ctx);
|
|
277
281
|
}
|
|
278
282
|
function spacingKeyValue(ctx, key, negative) {
|
|
279
283
|
if (key === "px" || !/^[a-zA-Z][\w-]*$/.test(key) || ctx.theme("spacing", key) == null) return null;
|
|
@@ -374,7 +378,7 @@ function functionalUtility(opts, ctx) {
|
|
|
374
378
|
description: opts.description,
|
|
375
379
|
category: opts.category,
|
|
376
380
|
priority: opts.priority
|
|
377
|
-
});
|
|
381
|
+
}, ctx);
|
|
378
382
|
}
|
|
379
383
|
const MATH_FNS = /* @__PURE__ */ new Set(["calc", "min", "max", "clamp"]);
|
|
380
384
|
function expandThemeFunctions(value) {
|
|
@@ -493,14 +497,23 @@ function parseClassName(className, ctx) {
|
|
|
493
497
|
if (cache.has(className)) {
|
|
494
498
|
return cache.get(className);
|
|
495
499
|
}
|
|
496
|
-
let important = false;
|
|
497
500
|
let realClassName = className;
|
|
498
|
-
|
|
501
|
+
const classPrefix = ctx ? configuredClassPrefix(ctx) : "";
|
|
502
|
+
if (classPrefix) {
|
|
503
|
+
if (!className.startsWith(classPrefix + ":")) {
|
|
504
|
+
const none = { modifiers: [], utility: null };
|
|
505
|
+
cache.set(className, none);
|
|
506
|
+
return none;
|
|
507
|
+
}
|
|
508
|
+
realClassName = className.slice(classPrefix.length + 1);
|
|
509
|
+
}
|
|
510
|
+
let important = false;
|
|
511
|
+
if (realClassName.startsWith("!")) {
|
|
499
512
|
important = true;
|
|
500
|
-
realClassName =
|
|
501
|
-
} else if (
|
|
513
|
+
realClassName = realClassName.slice(1);
|
|
514
|
+
} else if (realClassName.length > 1 && realClassName.endsWith("!")) {
|
|
502
515
|
important = true;
|
|
503
|
-
realClassName =
|
|
516
|
+
realClassName = realClassName.slice(0, -1);
|
|
504
517
|
}
|
|
505
518
|
const tokens = tokenize(realClassName);
|
|
506
519
|
const result = parseTokens(tokens, ctx);
|
|
@@ -510,6 +523,10 @@ function parseClassName(className, ctx) {
|
|
|
510
523
|
cache.set(className, result);
|
|
511
524
|
return result;
|
|
512
525
|
}
|
|
526
|
+
function configuredClassPrefix(ctx) {
|
|
527
|
+
const configured = ctx.config("prefix");
|
|
528
|
+
return typeof configured === "string" && /^[a-z]+$/.test(configured) ? configured : "";
|
|
529
|
+
}
|
|
513
530
|
function parseTokens(tokens, ctx) {
|
|
514
531
|
const modifiers = [];
|
|
515
532
|
let utility = null;
|
|
@@ -1029,24 +1046,41 @@ function animationToCssVars(animations2) {
|
|
|
1029
1046
|
}
|
|
1030
1047
|
return result;
|
|
1031
1048
|
}
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1049
|
+
const COMMENT_OR_BLOCK = /\/\*|\*\/|[{};]/;
|
|
1050
|
+
function keyframesBlock(name, frames) {
|
|
1051
|
+
if (!name || COMMENT_OR_BLOCK.test(name) || /\s/.test(name) || !frames || typeof frames !== "object") return "";
|
|
1052
|
+
let body = "";
|
|
1053
|
+
for (const [step, props] of Object.entries(frames)) {
|
|
1054
|
+
if (COMMENT_OR_BLOCK.test(step) || !props || typeof props !== "object") return "";
|
|
1055
|
+
let decls = "";
|
|
1056
|
+
for (const [prop, value] of Object.entries(props)) {
|
|
1057
|
+
const v2 = String(value);
|
|
1058
|
+
if (COMMENT_OR_BLOCK.test(prop) || COMMENT_OR_BLOCK.test(v2)) return "";
|
|
1059
|
+
decls += ` ${prop}: ${v2};
|
|
1038
1060
|
`;
|
|
1039
|
-
for (const step in frames) {
|
|
1040
|
-
css += ` ${step} {`;
|
|
1041
|
-
const props = frames[step];
|
|
1042
|
-
for (const prop in props) {
|
|
1043
|
-
css += ` ${prop}: ${props[prop]};`;
|
|
1044
|
-
}
|
|
1045
|
-
css += " }\n";
|
|
1046
1061
|
}
|
|
1047
|
-
|
|
1062
|
+
body += ` ${step} {
|
|
1063
|
+
${decls} }
|
|
1064
|
+
`;
|
|
1065
|
+
}
|
|
1066
|
+
return `@keyframes ${name} {
|
|
1067
|
+
${body}}`;
|
|
1068
|
+
}
|
|
1069
|
+
function referencedKeyframes(css, ctx) {
|
|
1070
|
+
if (!css.includes("animation")) return [];
|
|
1071
|
+
const all = ctx.theme("keyframes");
|
|
1072
|
+
if (!all || typeof all !== "object") return [];
|
|
1073
|
+
const names = /* @__PURE__ */ new Set();
|
|
1074
|
+
for (const m of css.matchAll(/(?:^|[\s;{])animation(?:-name)?\s*:\s*([^;}]+)/g)) {
|
|
1075
|
+
const value = m[1].replace(/var\(--animate-([\w-]+)\)/g, (whole, key) => {
|
|
1076
|
+
const v2 = ctx.theme("animations", key) ?? ctx.theme("animation", key);
|
|
1077
|
+
return typeof v2 === "string" ? v2 : whole;
|
|
1078
|
+
});
|
|
1079
|
+
for (const word of value.split(/[\s,()]+/)) {
|
|
1080
|
+
if (word && Object.prototype.hasOwnProperty.call(all, word)) names.add(word);
|
|
1081
|
+
}
|
|
1048
1082
|
}
|
|
1049
|
-
return
|
|
1083
|
+
return [...names].map((n) => keyframesBlock(n, all[n])).filter(Boolean);
|
|
1050
1084
|
}
|
|
1051
1085
|
function transitionTimingFunctionToCssVars(transition) {
|
|
1052
1086
|
const result = {};
|
|
@@ -1114,7 +1148,7 @@ function themeToCssVarsAll(theme) {
|
|
|
1114
1148
|
...borderRadiusToCssVars(theme.borderRadius),
|
|
1115
1149
|
...zIndexToCssVars(theme.zIndex),
|
|
1116
1150
|
...opacityToCssVars(theme.opacity),
|
|
1117
|
-
...animationToCssVars(theme.animations),
|
|
1151
|
+
...animationToCssVars({ ...theme.animations, ...theme.animation }),
|
|
1118
1152
|
...transitionTimingFunctionToCssVars(theme.transitionTimingFunction),
|
|
1119
1153
|
...transitionDurationToCssVars(theme.transitionDuration),
|
|
1120
1154
|
...transitionDelayToCssVars(theme.transitionDelay),
|
|
@@ -1480,6 +1514,7 @@ function generateCssRules(classList, ctx, opts) {
|
|
|
1480
1514
|
const css = rootToCss([node]);
|
|
1481
1515
|
rootCssList.push(css);
|
|
1482
1516
|
}
|
|
1517
|
+
rootCssList.push(...referencedKeyframes(cssList.join("\n"), ctx));
|
|
1483
1518
|
return {
|
|
1484
1519
|
cls,
|
|
1485
1520
|
ast: allCleanAst,
|
|
@@ -2276,11 +2311,7 @@ const keyframes = {
|
|
|
2276
2311
|
}
|
|
2277
2312
|
},
|
|
2278
2313
|
ping: {
|
|
2279
|
-
"75%": {
|
|
2280
|
-
transform: "scale(2)",
|
|
2281
|
-
opacity: "0"
|
|
2282
|
-
},
|
|
2283
|
-
"100%": {
|
|
2314
|
+
"75%, 100%": {
|
|
2284
2315
|
transform: "scale(2)",
|
|
2285
2316
|
opacity: "0"
|
|
2286
2317
|
}
|
|
@@ -2290,14 +2321,15 @@ const keyframes = {
|
|
|
2290
2321
|
opacity: "0.5"
|
|
2291
2322
|
}
|
|
2292
2323
|
},
|
|
2324
|
+
// #274: Tailwind 4.1.13's frames (0%/100% share the up position; 50% is the floor).
|
|
2293
2325
|
bounce: {
|
|
2294
|
-
"0%": {
|
|
2326
|
+
"0%, 100%": {
|
|
2295
2327
|
transform: "translateY(-25%)",
|
|
2296
|
-
"animation-timing-function": "cubic-bezier(0.8,0,1,1)"
|
|
2328
|
+
"animation-timing-function": "cubic-bezier(0.8, 0, 1, 1)"
|
|
2297
2329
|
},
|
|
2298
|
-
"
|
|
2330
|
+
"50%": {
|
|
2299
2331
|
transform: "none",
|
|
2300
|
-
"animation-timing-function": "cubic-bezier(0,0,0.2,1)"
|
|
2332
|
+
"animation-timing-function": "cubic-bezier(0, 0, 0.2, 1)"
|
|
2301
2333
|
}
|
|
2302
2334
|
}
|
|
2303
2335
|
};
|
|
@@ -2372,6 +2404,48 @@ const defaultTheme = {
|
|
|
2372
2404
|
// Tailwind 4.1.13 --aspect-* (aspect-video → var(--aspect-video))
|
|
2373
2405
|
aspect: { video: "16 / 9" }
|
|
2374
2406
|
};
|
|
2407
|
+
const customUtilityName = /^[A-Za-z_][A-Za-z0-9_-]*$/;
|
|
2408
|
+
const customUtilityProp = /^(--[A-Za-z0-9_-]+|-?[A-Za-z][A-Za-z0-9-]*)$/;
|
|
2409
|
+
function validateCustomUtility(name, decls) {
|
|
2410
|
+
if (typeof name !== "string" || !customUtilityName.test(name)) return null;
|
|
2411
|
+
if (!decls || typeof decls !== "object" || Array.isArray(decls)) return null;
|
|
2412
|
+
const out = [];
|
|
2413
|
+
for (const [prop, raw] of Object.entries(decls)) {
|
|
2414
|
+
if (typeof raw !== "string" && typeof raw !== "number") return null;
|
|
2415
|
+
const value = String(raw).trim();
|
|
2416
|
+
if (!customUtilityProp.test(prop) || !value || !isStructureSafeValue(value) || hasCommentDelimiter(value)) return null;
|
|
2417
|
+
out.push([prop, value]);
|
|
2418
|
+
}
|
|
2419
|
+
return out.length ? out : null;
|
|
2420
|
+
}
|
|
2421
|
+
function registerCustomUtilities(ctx, utilities) {
|
|
2422
|
+
if (!utilities || typeof utilities !== "object" || Array.isArray(utilities)) return;
|
|
2423
|
+
const list = getUtility(ctx);
|
|
2424
|
+
const builtins = [...list];
|
|
2425
|
+
const before = list.length;
|
|
2426
|
+
for (const [name, decls] of Object.entries(utilities)) {
|
|
2427
|
+
const safe = validateCustomUtility(name, decls);
|
|
2428
|
+
if (!safe) {
|
|
2429
|
+
debugWarn(`[BAROCSS] Ignoring invalid custom utility "${name}"`);
|
|
2430
|
+
continue;
|
|
2431
|
+
}
|
|
2432
|
+
const shadowed = builtins.filter((u) => u.match(name));
|
|
2433
|
+
registerUtility({
|
|
2434
|
+
name,
|
|
2435
|
+
category: "custom",
|
|
2436
|
+
match: (className) => className === name,
|
|
2437
|
+
handler: (value, c, token) => {
|
|
2438
|
+
let base = [];
|
|
2439
|
+
for (const reg of shadowed) {
|
|
2440
|
+
base = reg.handler(value, c, token, reg) || [];
|
|
2441
|
+
if (base.length > 0) break;
|
|
2442
|
+
}
|
|
2443
|
+
return [...base, ...safe.map(([prop, v]) => decl(prop, v))];
|
|
2444
|
+
}
|
|
2445
|
+
}, ctx);
|
|
2446
|
+
}
|
|
2447
|
+
if (list.length > before) list.unshift(...list.splice(before));
|
|
2448
|
+
}
|
|
2375
2449
|
const preflightMinimalCSS = `
|
|
2376
2450
|
/* BaroCSS Preflight - Minimal Reset */
|
|
2377
2451
|
/* ================================= */
|
|
@@ -3254,9 +3328,7 @@ function resolveTheme(config) {
|
|
|
3254
3328
|
}
|
|
3255
3329
|
function themeToCssVars(theme) {
|
|
3256
3330
|
const vars = themeToCssVarsAll(theme);
|
|
3257
|
-
const result = toCssVarsBlock(vars
|
|
3258
|
-
${keyframesToCss(theme.keyframes || {})}
|
|
3259
|
-
`);
|
|
3331
|
+
const result = toCssVarsBlock(vars);
|
|
3260
3332
|
return result;
|
|
3261
3333
|
}
|
|
3262
3334
|
function createContext(configObj) {
|
|
@@ -3310,6 +3382,7 @@ function createContext(configObj) {
|
|
|
3310
3382
|
}
|
|
3311
3383
|
};
|
|
3312
3384
|
initializeContextState(ctx, getUtility(), getModifier());
|
|
3385
|
+
registerCustomUtilities(ctx, configObj.utilities);
|
|
3313
3386
|
return ctx;
|
|
3314
3387
|
}
|
|
3315
3388
|
function parseFraction(input) {
|
|
@@ -3907,10 +3980,12 @@ staticUtility("animate-bounce", [["animation", "var(--animate-bounce)"]], { cate
|
|
|
3907
3980
|
staticUtility("animate-none", [["animation", "none"]], { category: "transitions" });
|
|
3908
3981
|
functionalUtility({
|
|
3909
3982
|
name: "animate",
|
|
3910
|
-
|
|
3983
|
+
// #274: theme.animations (and Tailwind's theme.animation) names, e.g. theme.extend.animation.wiggle.
|
|
3984
|
+
themeKeys: ["animations", "animation"],
|
|
3911
3985
|
supportsArbitrary: true,
|
|
3912
3986
|
supportsCustomProperty: true,
|
|
3913
|
-
handle: (value, ctx, token) => {
|
|
3987
|
+
handle: (value, ctx, token, extra) => {
|
|
3988
|
+
if (extra?.realThemeValue) return [decl("animation", `var(--animate-${extra.realThemeValue})`)];
|
|
3914
3989
|
if (token.customProperty) {
|
|
3915
3990
|
return [decl("animation", `var(${value})`)];
|
|
3916
3991
|
}
|
|
@@ -9114,7 +9189,7 @@ class ChangeDetector {
|
|
|
9114
9189
|
function unescapeCssIdent(s) {
|
|
9115
9190
|
return s.replace(/\\([0-9a-fA-F]{1,6})\s?|\\(.)/g, (_m, hex, ch) => hex ? String.fromCodePoint(parseInt(hex, 16)) : ch);
|
|
9116
9191
|
}
|
|
9117
|
-
const LEADING_CLASS = /^\s
|
|
9192
|
+
const LEADING_CLASS = /^\s*(?::(?:where|is)\(\s*)?\.((?:\\[0-9a-fA-F]{1,6}\s?|\\.|[\w-]|[^\x00-\x7F])+)/;
|
|
9118
9193
|
function splitTopLevel(sel) {
|
|
9119
9194
|
const parts = [];
|
|
9120
9195
|
let depth = 0, start = 0;
|
|
@@ -9131,6 +9206,17 @@ function splitTopLevel(sel) {
|
|
|
9131
9206
|
parts.push(sel.slice(start));
|
|
9132
9207
|
return parts;
|
|
9133
9208
|
}
|
|
9209
|
+
function collectKeyframeNames(rules, out = /* @__PURE__ */ new Set()) {
|
|
9210
|
+
for (const rule2 of Array.from(rules)) {
|
|
9211
|
+
if (rule2.type === 7 && typeof rule2.name === "string") {
|
|
9212
|
+
out.add(rule2.name);
|
|
9213
|
+
continue;
|
|
9214
|
+
}
|
|
9215
|
+
const inner = rule2.cssRules;
|
|
9216
|
+
if (inner && inner.length) collectKeyframeNames(inner, out);
|
|
9217
|
+
}
|
|
9218
|
+
return out;
|
|
9219
|
+
}
|
|
9134
9220
|
function collectLeadingClasses(rules, out = /* @__PURE__ */ new Set()) {
|
|
9135
9221
|
for (const rule2 of Array.from(rules)) {
|
|
9136
9222
|
const selectorText = rule2.selectorText;
|
|
@@ -9254,6 +9340,7 @@ class ClassGc {
|
|
|
9254
9340
|
return { trackedClasses: this.counts.size, candidates: this.candidates.size };
|
|
9255
9341
|
}
|
|
9256
9342
|
}
|
|
9343
|
+
const SSR_STYLE_SELECTOR = "style[data-barocss-ssr]";
|
|
9257
9344
|
const LAYER_ORDER = "@layer theme, base, components, utilities;";
|
|
9258
9345
|
class BrowserRuntime {
|
|
9259
9346
|
constructor(options = {}) {
|
|
@@ -9261,10 +9348,14 @@ class BrowserRuntime {
|
|
|
9261
9348
|
this.rootCache = /* @__PURE__ */ new Set();
|
|
9262
9349
|
this.isDestroyed = false;
|
|
9263
9350
|
this.existing = null;
|
|
9351
|
+
this.existingKeyframes = /* @__PURE__ */ new Set();
|
|
9264
9352
|
this.existingSheetCount = -1;
|
|
9265
9353
|
this.pinned = /* @__PURE__ */ new Set();
|
|
9266
9354
|
this.gc = null;
|
|
9267
9355
|
this.reclaimedCount = 0;
|
|
9356
|
+
this.ssrRules = [];
|
|
9357
|
+
this.ssrClasses = /* @__PURE__ */ new Set();
|
|
9358
|
+
this.observedOnce = false;
|
|
9268
9359
|
this.getCategory = (cls) => parseClassName(cls, this.context).utility?.category;
|
|
9269
9360
|
const defaultConfig = {};
|
|
9270
9361
|
this.options = {
|
|
@@ -9303,6 +9394,44 @@ class BrowserRuntime {
|
|
|
9303
9394
|
console.log("[BrowserRuntime] init");
|
|
9304
9395
|
this.injectPreflightCSS();
|
|
9305
9396
|
this.ensureCssVars();
|
|
9397
|
+
this.adoptSsrSheets();
|
|
9398
|
+
}
|
|
9399
|
+
/**
|
|
9400
|
+
* #268: adopt the class rules of server-rendered `<style data-barocss-ssr>` sheets in <head>, at startup
|
|
9401
|
+
* (constructor and the first observe()). Each rule moves
|
|
9402
|
+
* (same task, so no paint in between) into the partition its class would get if generated here, at
|
|
9403
|
+
* its #254 sorted position, so a later client `sm:` rule lands before a server `lg:` rule. Its classes
|
|
9404
|
+
* are never regenerated and never reclaimed. `:root`, `@property` and `@keyframes` stay in the sheet.
|
|
9405
|
+
*/
|
|
9406
|
+
adoptSsrSheets() {
|
|
9407
|
+
if (typeof document === "undefined") return;
|
|
9408
|
+
const adopted = [];
|
|
9409
|
+
if (!document.head) return;
|
|
9410
|
+
for (const el of Array.from(document.head.querySelectorAll(`${SSR_STYLE_SELECTOR}:not([data-barocss-adopted])`))) {
|
|
9411
|
+
const sheet = el.sheet;
|
|
9412
|
+
if (!sheet) continue;
|
|
9413
|
+
el.setAttribute("data-barocss-adopted", "");
|
|
9414
|
+
const moved = [];
|
|
9415
|
+
for (let i = sheet.cssRules.length - 1; i >= 0; i--) {
|
|
9416
|
+
const rule2 = sheet.cssRules[i];
|
|
9417
|
+
const classes = collectLeadingClasses([rule2]);
|
|
9418
|
+
if (classes.size === 0) continue;
|
|
9419
|
+
classes.forEach((cls) => this.ssrClasses.add(cls));
|
|
9420
|
+
moved.unshift({ css: rule2.cssText, cls: classes.values().next().value });
|
|
9421
|
+
sheet.deleteRule(i);
|
|
9422
|
+
}
|
|
9423
|
+
adopted.push(...moved);
|
|
9424
|
+
}
|
|
9425
|
+
if (adopted.length === 0) return;
|
|
9426
|
+
this.ssrRules.push(...adopted);
|
|
9427
|
+
this.insertSsrRules(adopted);
|
|
9428
|
+
}
|
|
9429
|
+
insertSsrRules(rules) {
|
|
9430
|
+
for (const { css, cls } of rules) {
|
|
9431
|
+
const category = this.getCategory(cls);
|
|
9432
|
+
if (category) this.stylePartitionManager.addCategoryRule(css, category);
|
|
9433
|
+
else this.stylePartitionManager.addRule(css);
|
|
9434
|
+
}
|
|
9306
9435
|
}
|
|
9307
9436
|
injectPreflightCSS() {
|
|
9308
9437
|
const level = this.options.config.preflight ?? true;
|
|
@@ -9370,6 +9499,7 @@ ${preflightCSS}
|
|
|
9370
9499
|
results = [...existingResults, ...results];
|
|
9371
9500
|
results.forEach((result) => this.incrementalParser.markProcessed(result.cls));
|
|
9372
9501
|
}
|
|
9502
|
+
if (this.ssrClasses.size > 0) results = results.filter((result) => !this.ssrClasses.has(result.cls));
|
|
9373
9503
|
if (this.options.skipExisting && results.length > 0 && typeof document !== "undefined") {
|
|
9374
9504
|
const existing = this.getExistingClasses();
|
|
9375
9505
|
results = results.filter((result) => !existing.has(result.cls));
|
|
@@ -9377,6 +9507,7 @@ ${preflightCSS}
|
|
|
9377
9507
|
if (results.length === 0) return;
|
|
9378
9508
|
const cssRules = [];
|
|
9379
9509
|
const rootCssRules = [];
|
|
9510
|
+
const pageKeyframes = this.options.skipExisting && typeof document !== "undefined" ? (this.getExistingClasses(), this.existingKeyframes) : null;
|
|
9380
9511
|
for (const result of results) {
|
|
9381
9512
|
if (result.css && Array.isArray(result.cssList)) {
|
|
9382
9513
|
cssRules.push(result);
|
|
@@ -9384,6 +9515,10 @@ ${preflightCSS}
|
|
|
9384
9515
|
}
|
|
9385
9516
|
if (result.rootCss && Array.isArray(result.rootCssList)) {
|
|
9386
9517
|
for (const rootCss of result.rootCssList) {
|
|
9518
|
+
if (pageKeyframes?.size) {
|
|
9519
|
+
const kf = /^\s*@keyframes\s+([^\s{]+)/.exec(rootCss)?.[1];
|
|
9520
|
+
if (kf && pageKeyframes.has(kf)) continue;
|
|
9521
|
+
}
|
|
9387
9522
|
if (!this.rootCache.has(rootCss)) {
|
|
9388
9523
|
this.rootCache.add(rootCss);
|
|
9389
9524
|
rootCssRules.push(rootCss);
|
|
@@ -9404,12 +9539,12 @@ ${preflightCSS}
|
|
|
9404
9539
|
}
|
|
9405
9540
|
/** #269: a class that must never be reclaimed. */
|
|
9406
9541
|
isPermanent(cls) {
|
|
9407
|
-
if (this.pinned.has(cls)) return true;
|
|
9542
|
+
if (this.pinned.has(cls) || this.ssrClasses.has(cls)) return true;
|
|
9408
9543
|
if (typeof document === "undefined") return true;
|
|
9409
9544
|
return this.getExistingClasses().has(cls);
|
|
9410
9545
|
}
|
|
9411
9546
|
/**
|
|
9412
|
-
* #269: delete the generated rules of classes no live element uses. Root/@property rules stay
|
|
9547
|
+
* #269: delete the generated rules of classes no live element uses. Root/@property/@keyframes rules stay
|
|
9413
9548
|
* (they are shared and harmless); a rule text another cached class still emits is kept.
|
|
9414
9549
|
*/
|
|
9415
9550
|
reclaim(classes) {
|
|
@@ -9441,6 +9576,7 @@ ${preflightCSS}
|
|
|
9441
9576
|
});
|
|
9442
9577
|
if (this.existing && sheets.length === this.existingSheetCount) return this.existing;
|
|
9443
9578
|
const out = /* @__PURE__ */ new Set();
|
|
9579
|
+
const keyframes2 = /* @__PURE__ */ new Set();
|
|
9444
9580
|
for (const sheet of sheets) {
|
|
9445
9581
|
let rules;
|
|
9446
9582
|
try {
|
|
@@ -9449,7 +9585,9 @@ ${preflightCSS}
|
|
|
9449
9585
|
continue;
|
|
9450
9586
|
}
|
|
9451
9587
|
collectLeadingClasses(rules, out);
|
|
9588
|
+
collectKeyframeNames(rules, keyframes2);
|
|
9452
9589
|
}
|
|
9590
|
+
this.existingKeyframes = keyframes2;
|
|
9453
9591
|
this.existing = out;
|
|
9454
9592
|
this.existingSheetCount = sheets.length;
|
|
9455
9593
|
return out;
|
|
@@ -9458,6 +9596,10 @@ ${preflightCSS}
|
|
|
9458
9596
|
* MutationObserver instance method to automatically call addClass when class attributes change in DOM
|
|
9459
9597
|
*/
|
|
9460
9598
|
observe(root = document.body, options) {
|
|
9599
|
+
if (!this.observedOnce) {
|
|
9600
|
+
this.observedOnce = true;
|
|
9601
|
+
this.adoptSsrSheets();
|
|
9602
|
+
}
|
|
9461
9603
|
return this.changeDetector.observe(root, options);
|
|
9462
9604
|
}
|
|
9463
9605
|
normalizeClasses(classes) {
|
|
@@ -9509,6 +9651,7 @@ ${preflightCSS}
|
|
|
9509
9651
|
this.stylePartitionManager = new StylePartitionManager(this.getInsertionPoint(), this.options.maxRulesPerPartition, `${this.options.styleId}-partition`, this.getCategory);
|
|
9510
9652
|
this.injectPreflightCSS();
|
|
9511
9653
|
this.ensureCssVars();
|
|
9654
|
+
this.insertSsrRules(this.ssrRules);
|
|
9512
9655
|
}
|
|
9513
9656
|
reset() {
|
|
9514
9657
|
if (this.isDestroyed) return;
|
|
@@ -9519,6 +9662,7 @@ ${preflightCSS}
|
|
|
9519
9662
|
this.stylePartitionManager = new StylePartitionManager(this.getInsertionPoint(), this.options.maxRulesPerPartition, `${this.options.styleId}-partition`, this.getCategory);
|
|
9520
9663
|
this.injectPreflightCSS();
|
|
9521
9664
|
this.ensureCssVars();
|
|
9665
|
+
this.insertSsrRules(this.ssrRules);
|
|
9522
9666
|
}
|
|
9523
9667
|
updateConfig(newConfig) {
|
|
9524
9668
|
if (this.isDestroyed) return;
|
|
@@ -9661,6 +9805,7 @@ export {
|
|
|
9661
9805
|
BrowserRuntime,
|
|
9662
9806
|
ChangeDetector,
|
|
9663
9807
|
LAYER_ORDER,
|
|
9808
|
+
SSR_STYLE_SELECTOR,
|
|
9664
9809
|
StylePartitionManager,
|
|
9665
9810
|
baroBoot,
|
|
9666
9811
|
baroStart,
|