@barocss/kit 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -251,6 +251,7 @@ function getUtility(ctx) {
251
251
  const modifierRegistry = [];
252
252
  function staticModifier(name, selectors, options = {}, ctx) {
253
253
  registerModifier({
254
+ name,
254
255
  match: (mod) => mod === name,
255
256
  modifySelector: ({ ..._rest }) => {
256
257
  return selectors.map((sel) => ({
@@ -557,14 +558,23 @@ function parseClassName(className, ctx) {
557
558
  if (cache.has(className)) {
558
559
  return cache.get(className);
559
560
  }
560
- let important = false;
561
561
  let realClassName = className;
562
- if (className.startsWith("!")) {
562
+ const classPrefix = ctx ? configuredClassPrefix(ctx) : "";
563
+ if (classPrefix) {
564
+ if (!className.startsWith(classPrefix + ":")) {
565
+ const none = { modifiers: [], utility: null };
566
+ cache.set(className, none);
567
+ return none;
568
+ }
569
+ realClassName = className.slice(classPrefix.length + 1);
570
+ }
571
+ let important = false;
572
+ if (realClassName.startsWith("!")) {
563
573
  important = true;
564
- realClassName = className.slice(1);
565
- } else if (className.length > 1 && className.endsWith("!")) {
574
+ realClassName = realClassName.slice(1);
575
+ } else if (realClassName.length > 1 && realClassName.endsWith("!")) {
566
576
  important = true;
567
- realClassName = className.slice(0, -1);
577
+ realClassName = realClassName.slice(0, -1);
568
578
  }
569
579
  const tokens = tokenize(realClassName);
570
580
  const result = parseTokens(tokens, ctx);
@@ -574,6 +584,10 @@ function parseClassName(className, ctx) {
574
584
  cache.set(className, result);
575
585
  return result;
576
586
  }
587
+ function configuredClassPrefix(ctx) {
588
+ const configured = ctx.config("prefix");
589
+ return typeof configured === "string" && /^[a-z]+$/.test(configured) ? configured : "";
590
+ }
577
591
  function parseTokens(tokens, ctx) {
578
592
  const modifiers = [];
579
593
  let utility = null;
@@ -1097,24 +1111,41 @@ function animationToCssVars(animations) {
1097
1111
  }
1098
1112
  return result;
1099
1113
  }
1100
- function keyframesToCss(keyframes) {
1101
- if (!keyframes) return "";
1102
- let css = "";
1103
- for (const name in keyframes) {
1104
- const frames = keyframes[name];
1105
- css += `@keyframes ${name} {
1114
+ const COMMENT_OR_BLOCK = /\/\*|\*\/|[{};]/;
1115
+ function keyframesBlock(name, frames) {
1116
+ if (!name || COMMENT_OR_BLOCK.test(name) || /\s/.test(name) || !frames || typeof frames !== "object") return "";
1117
+ let body = "";
1118
+ for (const [step, props] of Object.entries(frames)) {
1119
+ if (COMMENT_OR_BLOCK.test(step) || !props || typeof props !== "object") return "";
1120
+ let decls = "";
1121
+ for (const [prop, value] of Object.entries(props)) {
1122
+ const v2 = String(value);
1123
+ if (COMMENT_OR_BLOCK.test(prop) || COMMENT_OR_BLOCK.test(v2)) return "";
1124
+ decls += ` ${prop}: ${v2};
1106
1125
  `;
1107
- for (const step in frames) {
1108
- css += ` ${step} {`;
1109
- const props = frames[step];
1110
- for (const prop in props) {
1111
- css += ` ${prop}: ${props[prop]};`;
1112
- }
1113
- css += " }\n";
1114
1126
  }
1115
- css += "}\n";
1127
+ body += ` ${step} {
1128
+ ${decls} }
1129
+ `;
1130
+ }
1131
+ return `@keyframes ${name} {
1132
+ ${body}}`;
1133
+ }
1134
+ function referencedKeyframes(css, ctx) {
1135
+ if (!css.includes("animation")) return [];
1136
+ const all = ctx.theme("keyframes");
1137
+ if (!all || typeof all !== "object") return [];
1138
+ const names = /* @__PURE__ */ new Set();
1139
+ for (const m of css.matchAll(/(?:^|[\s;{])animation(?:-name)?\s*:\s*([^;}]+)/g)) {
1140
+ const value = m[1].replace(/var\(--animate-([\w-]+)\)/g, (whole, key) => {
1141
+ const v2 = ctx.theme("animations", key) ?? ctx.theme("animation", key);
1142
+ return typeof v2 === "string" ? v2 : whole;
1143
+ });
1144
+ for (const word of value.split(/[\s,()]+/)) {
1145
+ if (word && Object.prototype.hasOwnProperty.call(all, word)) names.add(word);
1146
+ }
1116
1147
  }
1117
- return css;
1148
+ return [...names].map((n) => keyframesBlock(n, all[n])).filter(Boolean);
1118
1149
  }
1119
1150
  function transitionTimingFunctionToCssVars(transition) {
1120
1151
  const result = {};
@@ -1182,11 +1213,13 @@ function themeToCssVarsAll(theme) {
1182
1213
  ...borderRadiusToCssVars(theme.borderRadius),
1183
1214
  ...zIndexToCssVars(theme.zIndex),
1184
1215
  ...opacityToCssVars(theme.opacity),
1185
- ...animationToCssVars(theme.animations),
1216
+ ...animationToCssVars({ ...theme.animations, ...theme.animation }),
1186
1217
  ...transitionTimingFunctionToCssVars(theme.transitionTimingFunction),
1187
1218
  ...transitionDurationToCssVars(theme.transitionDuration),
1188
1219
  ...transitionDelayToCssVars(theme.transitionDelay),
1189
1220
  ...blurToCssVars(theme.blur),
1221
+ ...Object.fromEntries(Object.entries(theme.textShadow ?? {}).map(([k, v2]) => [`--text-shadow-${escapeKey(k)}`, v2])),
1222
+ ...Object.fromEntries(Object.entries(theme.dropShadow ?? {}).map(([k, v2]) => [`--drop-shadow-${escapeKey(k)}`, v2])),
1190
1223
  ...Object.fromEntries(Object.entries(theme.aspect ?? {}).map(([k, v2]) => [`--aspect-${escapeKey(k)}`, v2]))
1191
1224
  // keyframes handled separately
1192
1225
  };
@@ -1552,7 +1585,11 @@ function generateCss(classList, ctx, opts) {
1552
1585
  }
1553
1586
  return result;
1554
1587
  }).join(opts?.minify ? "" : "\n");
1555
- const rootRules = [...new Set(allAtRootNodes.filter((node) => node.type === "at-rule").map((node) => rootToCss([node], { minify: opts?.minify })))];
1588
+ const rootRules = [.../* @__PURE__ */ new Set([
1589
+ ...allAtRootNodes.filter((node) => node.type === "at-rule").map((node) => rootToCss([node], { minify: opts?.minify })),
1590
+ // #274: the @keyframes the class rules reference, once per sheet.
1591
+ ...referencedKeyframes(results, ctx)
1592
+ ])];
1556
1593
  const rootDeclarations = [...new Set(allAtRootNodes.filter((node) => node.type === "decl").map((node) => rootToCss([node], { minify: opts?.minify })).filter((decl2) => decl2 !== ""))];
1557
1594
  const rootCss = [
1558
1595
  ...rootRules,
@@ -1610,6 +1647,7 @@ function generateCssRules(classList, ctx, opts) {
1610
1647
  const css = rootToCss([node]);
1611
1648
  rootCssList.push(css);
1612
1649
  }
1650
+ rootCssList.push(...referencedKeyframes(cssList.join("\n"), ctx));
1613
1651
  return {
1614
1652
  cls,
1615
1653
  ast: allCleanAst,
@@ -1900,6 +1938,48 @@ class IncrementalParser {
1900
1938
  return Array.from(this.processedClasses);
1901
1939
  }
1902
1940
  }
1941
+ const customUtilityName = /^[A-Za-z_][A-Za-z0-9_-]*$/;
1942
+ const customUtilityProp = /^(--[A-Za-z0-9_-]+|-?[A-Za-z][A-Za-z0-9-]*)$/;
1943
+ function validateCustomUtility(name, decls) {
1944
+ if (typeof name !== "string" || !customUtilityName.test(name)) return null;
1945
+ if (!decls || typeof decls !== "object" || Array.isArray(decls)) return null;
1946
+ const out = [];
1947
+ for (const [prop, raw2] of Object.entries(decls)) {
1948
+ if (typeof raw2 !== "string" && typeof raw2 !== "number") return null;
1949
+ const value = String(raw2).trim();
1950
+ if (!customUtilityProp.test(prop) || !value || !isStructureSafeValue(value) || hasCommentDelimiter(value)) return null;
1951
+ out.push([prop, value]);
1952
+ }
1953
+ return out.length ? out : null;
1954
+ }
1955
+ function registerCustomUtilities(ctx, utilities) {
1956
+ if (!utilities || typeof utilities !== "object" || Array.isArray(utilities)) return;
1957
+ const list = getUtility(ctx);
1958
+ const builtins = [...list];
1959
+ const before = list.length;
1960
+ for (const [name, decls] of Object.entries(utilities)) {
1961
+ const safe = validateCustomUtility(name, decls);
1962
+ if (!safe) {
1963
+ debugWarn(`[BAROCSS] Ignoring invalid custom utility "${name}"`);
1964
+ continue;
1965
+ }
1966
+ const shadowed = builtins.filter((u) => u.match(name));
1967
+ registerUtility({
1968
+ name,
1969
+ category: "custom",
1970
+ match: (className) => className === name,
1971
+ handler: (value, c, token) => {
1972
+ let base = [];
1973
+ for (const reg of shadowed) {
1974
+ base = reg.handler(value, c, token, reg) || [];
1975
+ if (base.length > 0) break;
1976
+ }
1977
+ return [...base, ...safe.map(([prop, v]) => decl(prop, v))];
1978
+ }
1979
+ }, ctx);
1980
+ }
1981
+ if (list.length > before) list.unshift(...list.splice(before));
1982
+ }
1903
1983
  const preflightMinimalCSS = `
1904
1984
  /* BaroCSS Preflight - Minimal Reset */
1905
1985
  /* ================================= */
@@ -2031,7 +2111,7 @@ html {
2031
2111
  line-height: 1.15;
2032
2112
  -webkit-text-size-adjust: 100%;
2033
2113
  /* Tailwind 4.1.13 root font (app --default-font-family / --font-sans win) */
2034
- font-family: var(--default-font-family, var(--font-sans, ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'));
2114
+ font-family: var(--default-font-family, var(--font-sans, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', 'Noto Sans', Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'));
2035
2115
  font-feature-settings: var(--default-font-feature-settings, normal);
2036
2116
  font-variation-settings: var(--default-font-variation-settings, normal);
2037
2117
  }
@@ -2334,7 +2414,7 @@ html {
2334
2414
  -webkit-text-size-adjust: 100%;
2335
2415
  -ms-text-size-adjust: 100%;
2336
2416
  /* Tailwind 4.1.13 root font (app --default-font-family / --font-sans win) */
2337
- font-family: var(--default-font-family, var(--font-sans, ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'));
2417
+ font-family: var(--default-font-family, var(--font-sans, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', 'Noto Sans', Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'));
2338
2418
  font-feature-settings: var(--default-font-feature-settings, normal);
2339
2419
  font-variation-settings: var(--default-font-variation-settings, normal);
2340
2420
  }
@@ -2685,7 +2765,6 @@ function getPreflightCSS(level = true) {
2685
2765
  return "";
2686
2766
  }
2687
2767
  const defaultConfig = {
2688
- prefix: "barocss-",
2689
2768
  darkMode: "media"
2690
2769
  // same as default
2691
2770
  };
@@ -2787,9 +2866,7 @@ function resolveTheme(config) {
2787
2866
  }
2788
2867
  function themeToCssVars(theme) {
2789
2868
  const vars = themeToCssVarsAll(theme);
2790
- const result = toCssVarsBlock(vars, `
2791
- ${keyframesToCss(theme.keyframes || {})}
2792
- `);
2869
+ const result = toCssVarsBlock(vars);
2793
2870
  return result;
2794
2871
  }
2795
2872
  function createContext(configObj) {
@@ -2843,6 +2920,7 @@ function createContext(configObj) {
2843
2920
  }
2844
2921
  };
2845
2922
  initializeContextState(ctx, getUtility(), getModifier());
2923
+ registerCustomUtilities(ctx, configObj.utilities);
2846
2924
  return ctx;
2847
2925
  }
2848
2926
  function jsonToAst(input, ctx) {
@@ -3415,6 +3493,9 @@ staticUtility("snap-both", [["scroll-snap-type", "both var(--baro-scroll-snap-st
3415
3493
  staticUtility("snap-mandatory", [["--baro-scroll-snap-strictness", "mandatory"]], { category: "interactivity" });
3416
3494
  staticUtility("snap-proximity", [["--baro-scroll-snap-strictness", "proximity"]], { category: "interactivity" });
3417
3495
  [
3496
+ ["mbs", "scroll-margin-block-start"],
3497
+ // #311 (Tailwind 4.3), before `mb`
3498
+ ["mbe", "scroll-margin-block-end"],
3418
3499
  ["mt", "scroll-margin-top"],
3419
3500
  ["mr", "scroll-margin-right"],
3420
3501
  ["mb", "scroll-margin-bottom"],
@@ -3425,6 +3506,8 @@ staticUtility("snap-proximity", [["--baro-scroll-snap-strictness", "proximity"]]
3425
3506
  ["me", "scroll-margin-inline-end"],
3426
3507
  ["m", "scroll-margin"]
3427
3508
  ].forEach(([name, prop]) => {
3509
+ staticUtility(`scroll-${name}-px`, [[prop, "1px"]], { category: "interactivity" });
3510
+ staticUtility(`-scroll-${name}-px`, [[prop, "-1px"]], { category: "interactivity" });
3428
3511
  functionalUtility({
3429
3512
  name: `scroll-${name}`,
3430
3513
  spacingKeys: true,
@@ -3443,6 +3526,9 @@ staticUtility("snap-proximity", [["--baro-scroll-snap-strictness", "proximity"]]
3443
3526
  });
3444
3527
  });
3445
3528
  [
3529
+ ["pbs", "scroll-padding-block-start"],
3530
+ // #311 (Tailwind 4.3), before `pb`
3531
+ ["pbe", "scroll-padding-block-end"],
3446
3532
  ["pt", "scroll-padding-top"],
3447
3533
  ["pr", "scroll-padding-right"],
3448
3534
  ["pb", "scroll-padding-bottom"],
@@ -3459,13 +3545,15 @@ staticUtility("snap-proximity", [["--baro-scroll-snap-strictness", "proximity"]]
3459
3545
  prop,
3460
3546
  supportsArbitrary: true,
3461
3547
  supportsCustomProperty: true,
3548
+ handleBareValue: ({ value }) => value === "px" ? "1px" : /^(\d|\.\d)/.test(value) ? value : null,
3462
3549
  handle: (value, _ctx, token, _extra) => {
3463
- if (parseNumber(value) || token.negative) {
3550
+ if (token.negative) return [];
3551
+ if (parseNumber(value)) {
3464
3552
  return [decl(prop, `calc(var(--spacing) * ${value})`)];
3465
3553
  }
3466
3554
  return [decl(prop, value)];
3467
3555
  },
3468
- handleCustomProperty: (value) => [decl(prop, `var(${value})`)],
3556
+ handleCustomProperty: (value, _ctx, token) => token.negative ? [] : [decl(prop, `var(${value})`)],
3469
3557
  description: `scroll-${name} utility (static, arbitrary, custom property supported)`,
3470
3558
  category: "interactivity"
3471
3559
  });
@@ -3496,6 +3584,40 @@ functionalUtility({
3496
3584
  description: "will-change utility (static, arbitrary, custom property supported)",
3497
3585
  category: "interactivity"
3498
3586
  });
3587
+ staticUtility("scrollbar-auto", [["scrollbar-width", "auto"]], { category: "interactivity" });
3588
+ staticUtility("scrollbar-thin", [["scrollbar-width", "thin"]], { category: "interactivity" });
3589
+ staticUtility("scrollbar-none", [["scrollbar-width", "none"]], { category: "interactivity" });
3590
+ staticUtility("scrollbar-gutter-auto", [["scrollbar-gutter", "auto"]], { category: "interactivity" });
3591
+ staticUtility("scrollbar-gutter-stable", [["scrollbar-gutter", "stable"]], { category: "interactivity" });
3592
+ staticUtility("scrollbar-gutter-both", [["scrollbar-gutter", "stable both-edges"]], { category: "interactivity" });
3593
+ const SCROLLBAR_COLOR = "var(--baro-scrollbar-thumb) var(--baro-scrollbar-track)";
3594
+ const scrollbarProperties = () => atRoot([
3595
+ property("--baro-scrollbar-thumb", "#0000", "<color>"),
3596
+ property("--baro-scrollbar-track", "#0000", "<color>")
3597
+ ]);
3598
+ const stripColorHint = (v) => v.replace(/^color:/, "");
3599
+ for (const part of ["thumb", "track"]) {
3600
+ const key = `--baro-scrollbar-${part}`;
3601
+ const compose = (inner) => [scrollbarProperties(), ...inner, decl("scrollbar-color", SCROLLBAR_COLOR)];
3602
+ const withOpacity = (color, opacity) => opacity ? [decl(key, `color-mix(in oklab, ${color} ${opacity.replace(/^\[(.*)\]$/, "$1").replace(/%$/, "")}%, transparent)`)] : [decl(key, color)];
3603
+ functionalUtility({
3604
+ name: `scrollbar-${part}`,
3605
+ themeKeys: ["colors"],
3606
+ supportsOpacity: true,
3607
+ supportsArbitrary: true,
3608
+ supportsCustomProperty: true,
3609
+ handle: (value, _ctx, token, extra) => {
3610
+ if (extra?.realThemeValue) return compose(withOpacity(`var(--color-${extra.realThemeValue})`, extra.opacity));
3611
+ if (token.arbitrary) return compose(withOpacity(stripColorHint(value), extra?.opacity));
3612
+ if (value === "inherit" || value === "transparent") return compose([decl(key, value)]);
3613
+ if (value === "current") return compose(withOpacity("currentcolor", extra?.opacity));
3614
+ return null;
3615
+ },
3616
+ handleCustomProperty: (value, _ctx, _token, extra) => compose(withOpacity(`var(${stripColorHint(value)})`, extra?.opacity)),
3617
+ description: `scrollbar-color ${part} utility (theme, arbitrary, custom property, opacity)`,
3618
+ category: "interactivity"
3619
+ });
3620
+ }
3499
3621
  const defaultTiming = "var(--default-transition-timing-function)";
3500
3622
  const defaultDuration = "var(--default-transition-duration)";
3501
3623
  staticUtility("transition", [
@@ -3614,10 +3736,12 @@ staticUtility("animate-bounce", [["animation", "var(--animate-bounce)"]], { cate
3614
3736
  staticUtility("animate-none", [["animation", "none"]], { category: "transitions" });
3615
3737
  functionalUtility({
3616
3738
  name: "animate",
3617
- prop: "animation",
3739
+ // #274: theme.animations (and Tailwind's theme.animation) names, e.g. theme.extend.animation.wiggle.
3740
+ themeKeys: ["animations", "animation"],
3618
3741
  supportsArbitrary: true,
3619
3742
  supportsCustomProperty: true,
3620
- handle: (value, ctx, token) => {
3743
+ handle: (value, ctx, token, extra) => {
3744
+ if (extra?.realThemeValue) return [decl("animation", `var(--animate-${extra.realThemeValue})`)];
3621
3745
  if (token.customProperty) {
3622
3746
  return [decl("animation", `var(${value})`)];
3623
3747
  }
@@ -3631,53 +3755,99 @@ staticUtility("border-collapse", [["border-collapse", "collapse"]], { category:
3631
3755
  staticUtility("border-separate", [["border-collapse", "separate"]], { category: "table" });
3632
3756
  staticUtility("table-auto", [["table-layout", "auto"]], { category: "table" });
3633
3757
  staticUtility("table-fixed", [["table-layout", "fixed"]], { category: "table" });
3634
- functionalUtility({
3635
- name: "border-spacing-x",
3636
- prop: "border-spacing",
3637
- supportsArbitrary: true,
3638
- supportsCustomProperty: true,
3639
- handle: (value, _ctx, _token) => {
3640
- if (parseNumber(value)) {
3641
- return [decl("border-spacing", `calc(var(--spacing) * ${value}) var(--baro-border-spacing-y)`)];
3642
- }
3643
- return [decl("border-spacing", `${value} var(--baro-border-spacing-y)`)];
3644
- },
3645
- handleCustomProperty: (value) => [decl("border-spacing", `var(${value}) var(--baro-border-spacing-y)`)],
3646
- description: "border-spacing-x utility (static, number, arbitrary, custom property supported)",
3647
- category: "table"
3648
- });
3649
- functionalUtility({
3650
- name: "border-spacing-y",
3651
- prop: "border-spacing",
3652
- supportsArbitrary: true,
3653
- supportsCustomProperty: true,
3654
- handle: (value, _ctx, _token) => {
3655
- if (parseNumber(value)) {
3656
- return [decl("border-spacing", `var(--baro-border-spacing-x) calc(var(--spacing) * ${value})`)];
3657
- }
3658
- return [decl("border-spacing", `var(--baro-border-spacing-x) ${value}`)];
3659
- },
3660
- handleCustomProperty: (value) => [decl("border-spacing", `var(--baro-border-spacing-x) var(${value})`)],
3661
- description: "border-spacing-y utility (static, number, arbitrary, custom property supported)",
3662
- category: "table"
3663
- });
3664
- functionalUtility({
3665
- name: "border-spacing",
3666
- prop: "border-spacing",
3667
- supportsArbitrary: true,
3668
- supportsCustomProperty: true,
3669
- handle: (value, _ctx, _token) => {
3670
- if (parseNumber(value)) {
3671
- return [decl("border-spacing", `calc(var(--spacing) * ${value})`)];
3672
- }
3673
- return [decl("border-spacing", value)];
3674
- },
3675
- handleCustomProperty: (value) => [decl("border-spacing", `var(${value})`)],
3676
- description: "border-spacing utility (static, number, arbitrary, custom property supported)",
3677
- category: "table"
3758
+ const borderSpacingProperties = () => atRoot([
3759
+ property("--baro-border-spacing-x", "0", "<length>"),
3760
+ property("--baro-border-spacing-y", "0", "<length>")
3761
+ ]);
3762
+ const BORDER_SPACING = "var(--baro-border-spacing-x) var(--baro-border-spacing-y)";
3763
+ const borderSpacing = (axes, v) => [
3764
+ borderSpacingProperties(),
3765
+ ...axes.map((a) => decl(`--baro-border-spacing-${a}`, v)),
3766
+ decl("border-spacing", BORDER_SPACING)
3767
+ ];
3768
+ [
3769
+ ["border-spacing-x", ["x"]],
3770
+ ["border-spacing-y", ["y"]],
3771
+ ["border-spacing", ["x", "y"]]
3772
+ ].forEach(([name, axes]) => {
3773
+ staticUtility(`${name}-px`, [
3774
+ borderSpacingProperties,
3775
+ ...axes.map((a) => [`--baro-border-spacing-${a}`, "1px"]),
3776
+ ["border-spacing", BORDER_SPACING]
3777
+ ], { category: "table" });
3778
+ functionalUtility({
3779
+ name,
3780
+ prop: "border-spacing",
3781
+ supportsArbitrary: true,
3782
+ supportsCustomProperty: true,
3783
+ handle: (value) => borderSpacing(axes, parseNumber(value) ? `calc(var(--spacing) * ${value})` : value),
3784
+ handleCustomProperty: (value) => borderSpacing(axes, `var(${value})`),
3785
+ description: `${name} utility (number, px, arbitrary, custom property supported)`,
3786
+ category: "table"
3787
+ });
3678
3788
  });
3679
3789
  staticUtility("caption-top", [["caption-side", "top"]], { category: "table" });
3680
3790
  staticUtility("caption-bottom", [["caption-side", "bottom"]], { category: "table" });
3791
+ function parseAlpha(op) {
3792
+ if (!op) return null;
3793
+ if (/^\d+(\.\d+)?$/.test(op)) return { alpha: `${op}%`, isVar: false };
3794
+ const pct = /^\[(\d+(?:\.\d+)?)%\]$/.exec(op);
3795
+ if (pct) return { alpha: `${pct[1]}%`, isVar: false };
3796
+ const cp = /^\((--[\w-]+)\)$/.exec(op);
3797
+ if (cp) return { alpha: `var(${cp[1]})`, isVar: true };
3798
+ return null;
3799
+ }
3800
+ function splitTop(value, sep) {
3801
+ const out = [];
3802
+ let depth = 0;
3803
+ let cur = "";
3804
+ for (const ch of value) {
3805
+ if (ch === "(") depth++;
3806
+ else if (ch === ")") depth--;
3807
+ if (depth === 0 && (sep === " " ? /\s/.test(ch) : ch === sep)) {
3808
+ if (cur.trim()) out.push(cur.trim());
3809
+ cur = "";
3810
+ } else cur += ch;
3811
+ }
3812
+ if (cur.trim()) out.push(cur.trim());
3813
+ return out;
3814
+ }
3815
+ const LENGTH = /^-?(\d*\.)?\d+([a-z]+|%)?$/i;
3816
+ function shadowLayers(value, layer, alpha) {
3817
+ return splitTop(value, ",").map((l) => {
3818
+ const parts = splitTop(l, " ");
3819
+ const i = parts.findIndex((p) => p !== "inset" && !LENGTH.test(p));
3820
+ const c = i < 0 ? "currentcolor" : parts[i];
3821
+ parts[i < 0 ? parts.length : i] = `var(--baro-${layer}-color, ${alpha ? `oklab(from ${c} l a b / ${alpha})` : c})`;
3822
+ return parts.join(" ");
3823
+ });
3824
+ }
3825
+ function shadowValueDecls(layer, prop, value, opacity, render = (l) => l.join(", ")) {
3826
+ const a = parseAlpha(opacity);
3827
+ if (opacity && !a) return null;
3828
+ if (!a) return [decl(prop, render(shadowLayers(value, layer)))];
3829
+ const alphaDecl = decl(`--baro-${layer}-alpha`, a.alpha);
3830
+ if (!a.isVar) return [alphaDecl, decl(prop, render(shadowLayers(value, layer, a.alpha)))];
3831
+ return [
3832
+ alphaDecl,
3833
+ decl(prop, render(shadowLayers(value, layer))),
3834
+ atRule("supports", "(color: lab(from red l a b))", [decl(prop, render(shadowLayers(value, layer, a.alpha)))])
3835
+ ];
3836
+ }
3837
+ function shadowColorDecls(layer, color, opacity, ref = color) {
3838
+ const key = `--baro-${layer}-color`;
3839
+ if (color === "inherit") return [decl(key, "inherit")];
3840
+ const a = parseAlpha(opacity);
3841
+ if (opacity && !a) return null;
3842
+ const inner = a ? `color-mix(in oklab, ${ref} ${a.alpha}, transparent)` : ref;
3843
+ const fallback = a ? `color-mix(in srgb, ${color} ${a.alpha}, transparent)` : color;
3844
+ return [
3845
+ decl(key, fallback),
3846
+ atRule("supports", "(color: color-mix(in lab, red, red))", [
3847
+ decl(key, `color-mix(in oklab, ${inner} var(--baro-${layer}-alpha), transparent)`)
3848
+ ])
3849
+ ];
3850
+ }
3681
3851
  staticUtility("filter-none", [["filter", "none"]], { category: "effects" });
3682
3852
  functionalUtility({
3683
3853
  name: "filter",
@@ -3762,57 +3932,68 @@ functionalUtility({
3762
3932
  description: "contrast filter utility (static, number, arbitrary, custom property supported)",
3763
3933
  category: "effects"
3764
3934
  });
3765
- [
3766
- ["drop-shadow-xs", "xs", "0 1px 1px var(--baro-drop-shadow-color, #0000001a)"],
3767
- ["drop-shadow-sm", "sm", "0 1px 2px var(--baro-drop-shadow-color, #0000001a)"],
3768
- ["drop-shadow-md", "md", "0 3px 3px var(--baro-drop-shadow-color, #0000001a)"],
3769
- ["drop-shadow-lg", "lg", "0 4px 4px var(--baro-drop-shadow-color, #0000001a)"],
3770
- ["drop-shadow-xl", "xl", "0 9px 7px var(--baro-drop-shadow-color, #0000001a)"],
3771
- ["drop-shadow-2xl", "2xl", "0 25px 25px var(--baro-drop-shadow-color, #0000001a)"]
3772
- ].forEach(([name, size, sizeValue]) => {
3773
- staticUtility(name, [
3774
- decl("--baro-drop-shadow-size", `drop-shadow(${sizeValue})`),
3775
- decl("--baro-drop-shadow", `var(--drop-shadow-${size})`),
3776
- filters$1()
3777
- ]);
3778
- });
3779
- staticUtility("drop-shadow-none", [decl("--baro-drop-shadow", "drop-shadow(0 0 #0000)"), filters$1()]);
3780
- ["inherit", "current", "transparent"].forEach((name) => {
3781
- staticUtility(`drop-shadow-${name}`, [
3782
- decl("--baro-drop-shadow-color", name === "current" ? "currentColor" : name)
3783
- ]);
3784
- });
3785
- ["black", "white"].forEach((name) => {
3786
- staticUtility(`drop-shadow-${name}`, [
3787
- decl("--baro-drop-shadow-color", `var(--color-${name})`)
3788
- ]);
3935
+ const dropShadowProperties = () => atRoot([
3936
+ property("--baro-drop-shadow"),
3937
+ property("--baro-drop-shadow-color"),
3938
+ property("--baro-drop-shadow-alpha", "100%", "<percentage>"),
3939
+ property("--baro-drop-shadow-size")
3940
+ ]);
3941
+ const wrapDropShadow = (layers) => layers.map((l) => `drop-shadow(${l})`).join(" ");
3942
+ const DROP_SHADOW_DEFAULT = "0 1px 2px rgb(0 0 0 / 0.1), 0 1px 1px rgb(0 0 0 / 0.06)";
3943
+ const namedDropShadow = (ctx, name) => {
3944
+ const v = ctx.theme("dropShadow", name);
3945
+ return typeof v === "string" && /^[\w.-]+$/.test(name) ? v : null;
3946
+ };
3947
+ function dropShadowValue(value, opacity, named, keepNamed = false) {
3948
+ const decls = shadowValueDecls("drop-shadow", "--baro-drop-shadow-size", value, opacity, wrapDropShadow);
3949
+ if (!decls) return null;
3950
+ const composed = named !== void 0 && (!opacity || keepNamed) ? named : "var(--baro-drop-shadow-size)";
3951
+ return [dropShadowProperties(), ...decls, decl("--baro-drop-shadow", composed), filters$1()];
3952
+ }
3953
+ staticUtility("drop-shadow-none", [decl("--baro-drop-shadow", " "), filters$1()]);
3954
+ registerUtility({
3955
+ name: "drop-shadow",
3956
+ match: (className) => /^drop-shadow(\/.+)?$/.test(className),
3957
+ handler: (value, _ctx, token) => {
3958
+ const full = value ? `${token.prefix}-${value}` : token.prefix;
3959
+ const cut = full.indexOf("/");
3960
+ const opacity = cut < 0 ? void 0 : full.slice(cut + 1);
3961
+ const literal = "drop-shadow(0 1px 2px rgb(0 0 0 / 0.1)) drop-shadow( 0 1px 1px rgb(0 0 0 / 0.06))";
3962
+ return dropShadowValue(DROP_SHADOW_DEFAULT, opacity, literal, true) ?? [];
3963
+ },
3964
+ category: "effects"
3789
3965
  });
3966
+ const dropShadowColor = (color, opacity, ref) => {
3967
+ const decls = shadowColorDecls("drop-shadow", color, opacity, ref);
3968
+ return decls && [dropShadowProperties(), ...decls, decl("--baro-drop-shadow", "var(--baro-drop-shadow-size)")];
3969
+ };
3790
3970
  functionalUtility({
3791
3971
  name: "drop-shadow",
3792
3972
  themeKeys: ["colors"],
3793
3973
  supportsArbitrary: true,
3794
3974
  supportsCustomProperty: true,
3795
- handle: (value, _ctx, _token, extra) => {
3796
- if (extra?.realThemeValue) {
3797
- return [decl("--baro-drop-shadow-color", `var(--color-${extra.realThemeValue})`)];
3798
- }
3799
- if (parseColor(value)) {
3800
- return [decl("--baro-drop-shadow-color", value)];
3975
+ supportsOpacity: true,
3976
+ handleBareValue: ({ value, ctx }) => namedDropShadow(ctx, value) ? value : null,
3977
+ handle: (value, ctx, token, extra) => {
3978
+ const opacity = extra?.opacity;
3979
+ const keyword = token.arbitrary ? void 0 : { inherit: "inherit", current: "currentcolor", transparent: "transparent" }[extra?.realThemeValue ?? value];
3980
+ if (keyword) return dropShadowColor(keyword, opacity);
3981
+ if (extra?.realThemeValue) return dropShadowColor(value, opacity, `var(--color-${extra.realThemeValue})`);
3982
+ if (token.arbitrary) {
3983
+ if (parseColor(value)) return dropShadowColor(value, opacity);
3984
+ return dropShadowValue(value, opacity);
3801
3985
  }
3802
- return [
3803
- decl("--baro-drop-shadow-size", `drop-shadow(${value})`),
3804
- decl("--baro-drop-shadow", `var(--baro-drop-shadow-size)`)
3805
- ];
3986
+ const named = namedDropShadow(ctx, value);
3987
+ if (named) return dropShadowValue(named, opacity, `drop-shadow(var(--drop-shadow-${value}))`);
3988
+ return null;
3806
3989
  },
3807
3990
  handleCustomProperty: (value) => {
3808
- if (value.startsWith("color:")) {
3809
- return [
3810
- decl("--baro-drop-shadow-color", `var(${value.replace("color:", "")})`)
3811
- ];
3812
- }
3991
+ if (value.startsWith("color:")) return dropShadowColor(`var(${value.slice(6)})`, void 0) ?? [];
3813
3992
  return [
3993
+ dropShadowProperties(),
3814
3994
  decl("--baro-drop-shadow-size", `drop-shadow(var(${value}))`),
3815
- decl("--baro-drop-shadow", `var(--baro-drop-shadow-size)`)
3995
+ decl("--baro-drop-shadow", `var(--baro-drop-shadow-size)`),
3996
+ filters$1()
3816
3997
  ];
3817
3998
  },
3818
3999
  description: "drop-shadow filter utility (static, arbitrary, custom property supported)",
@@ -4182,166 +4363,119 @@ const ringShadowProperties = () => atRoot([
4182
4363
  property("--baro-ring-offset-width", "0px", "<length>"),
4183
4364
  property("--baro-ring-offset-color", "#fff")
4184
4365
  ]);
4185
- const shadowLayer = (value) => [
4186
- ringShadowProperties(),
4187
- decl("--baro-shadow", value),
4188
- decl("box-shadow", SHADOW_COMPOSITE)
4189
- ];
4190
- [
4191
- ["shadow-2xs", "var(--shadow-2xs)"],
4192
- ["shadow-xs", "var(--shadow-xs)"],
4193
- ["shadow-sm", "var(--shadow-sm)"],
4194
- ["shadow", "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)"],
4195
- ["shadow-md", "var(--shadow-md)"],
4196
- ["shadow-lg", "var(--shadow-lg)"],
4197
- ["shadow-xl", "var(--shadow-xl)"],
4198
- ["shadow-2xl", "var(--shadow-2xl)"],
4199
- ["shadow-none", "0 0 #0000"]
4200
- ].forEach(([name, value]) => {
4201
- staticUtility(name, [
4202
- ringShadowProperties,
4203
- ["--baro-shadow", value],
4204
- ["box-shadow", SHADOW_COMPOSITE]
4205
- ], { category: "effects" });
4206
- });
4207
- [
4208
- ["inset-shadow-2xs", "inset 0 1px var(--baro-inset-shadow-color, rgb(0 0 0 / 0.05))"],
4209
- ["inset-shadow-xs", "inset 0 1px 1px var(--baro-inset-shadow-color, rgb(0 0 0 / 0.05))"],
4210
- ["inset-shadow-sm", "inset 0 2px 4px var(--baro-inset-shadow-color, rgb(0 0 0 / 0.05))"],
4211
- ["inset-shadow-md", "inset 0 4px 6px -1px var(--baro-inset-shadow-color, rgb(0 0 0 / 0.05))"],
4212
- ["inset-shadow-lg", "inset 0 10px 15px -3px var(--baro-inset-shadow-color, rgb(0 0 0 / 0.05))"],
4213
- ["inset-shadow-xl", "inset 0 20px 25px -5px var(--baro-inset-shadow-color, rgb(0 0 0 / 0.05))"],
4214
- ["inset-shadow-2xl", "inset 0 25px 50px -12px var(--baro-inset-shadow-color, rgb(0 0 0 / 0.05))"],
4215
- ["inset-shadow-none", "0 0 #0000"]
4216
- ].forEach(([name, value]) => {
4217
- staticUtility(name, [
4218
- ringShadowProperties,
4219
- ["--baro-inset-shadow", value],
4220
- ["box-shadow", SHADOW_COMPOSITE]
4221
- ], { category: "effects" });
4222
- });
4223
- function createShadowThemeColor(key, main, opacity, realThemeValue) {
4224
- let fallbackColor = main;
4225
- const colorVar = `var(--color-${realThemeValue})`;
4226
- let colorValue = colorVar;
4227
- if (opacity) {
4228
- colorValue = `color-mix(in oklab, color-mix(in oklab, ${colorVar} ${opacity}%, transparent) var(--baro-shadow-alpha),transparent)`;
4229
- if (parseColor(main)) {
4230
- if (main.startsWith("#")) {
4231
- const opacityValue = Math.round(Number(opacity) / 100 * 255);
4232
- fallbackColor = `${main}${opacityValue.toString(16).padStart(2, "0")}`;
4233
- } else {
4234
- fallbackColor = `color-mix(in oklab, ${main} ${opacity}%, transparent)`;
4235
- }
4236
- }
4237
- }
4238
- return [
4239
- atRule("supports", "(color:color-mix(in lab, red, red))", [
4240
- decl(key, colorValue)
4241
- ]),
4242
- decl(key, fallbackColor)
4243
- ];
4366
+ const shadowColorProperties = (layer) => atRoot([
4367
+ property(`--baro-${layer}-color`),
4368
+ property(`--baro-${layer}-alpha`, "100%", "<percentage>")
4369
+ ]);
4370
+ const NAMED_SHADOWS = {
4371
+ "": "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)",
4372
+ "2xs": "0 1px rgb(0 0 0 / 0.05)",
4373
+ xs: "0 1px 2px 0 rgb(0 0 0 / 0.05)",
4374
+ sm: "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)",
4375
+ md: "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)",
4376
+ lg: "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)",
4377
+ xl: "0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)",
4378
+ "2xl": "0 25px 50px -12px rgb(0 0 0 / 0.25)",
4379
+ inner: "inset 0 2px 4px 0 rgb(0 0 0 / 0.05)"
4380
+ };
4381
+ const NAMED_INSET_SHADOWS = {
4382
+ "2xs": "inset 0 1px rgb(0 0 0 / 0.05)",
4383
+ xs: "inset 0 1px 1px rgb(0 0 0 / 0.05)",
4384
+ sm: "inset 0 2px 4px rgb(0 0 0 / 0.05)"
4385
+ };
4386
+ const INSET_EXTENSIONS = {
4387
+ md: "inset 0 4px 6px -1px rgb(0 0 0 / 0.05)",
4388
+ lg: "inset 0 10px 15px -3px rgb(0 0 0 / 0.05)",
4389
+ xl: "inset 0 20px 25px -5px rgb(0 0 0 / 0.05)",
4390
+ "2xl": "inset 0 25px 50px -12px rgb(0 0 0 / 0.05)"
4391
+ };
4392
+ const insetEach = (value) => value.split(/,(?![^(]*\))/).map((l) => `inset ${l.trim()}`).join(", ");
4393
+ const own = (table, key) => Object.prototype.hasOwnProperty.call(table, key);
4394
+ function boxShadowLayer(layer, value, opacity) {
4395
+ const decls = shadowValueDecls(layer, `--baro-${layer}`, value, opacity);
4396
+ if (!decls) return null;
4397
+ return [ringShadowProperties(), shadowColorProperties(layer), ...decls, decl("box-shadow", SHADOW_COMPOSITE)];
4398
+ }
4399
+ function namedBoxShadow(layer, name, opacity) {
4400
+ if (layer === "shadow") return own(NAMED_SHADOWS, name) ? boxShadowLayer(layer, NAMED_SHADOWS[name], opacity) : null;
4401
+ if (own(NAMED_INSET_SHADOWS, name)) return boxShadowLayer(layer, NAMED_INSET_SHADOWS[name], opacity);
4402
+ if (!opacity && own(INSET_EXTENSIONS, name)) return boxShadowLayer(layer, INSET_EXTENSIONS[name], void 0);
4403
+ return null;
4244
4404
  }
4245
- functionalUtility({
4405
+ staticUtility("shadow-none", [ringShadowProperties, ["--baro-shadow", "0 0 #0000"], ["box-shadow", SHADOW_COMPOSITE]], { category: "effects" });
4406
+ staticUtility("inset-shadow-none", [ringShadowProperties, ["--baro-inset-shadow", "inset 0 0 #0000"], ["box-shadow", SHADOW_COMPOSITE]], { category: "effects" });
4407
+ registerUtility({
4246
4408
  name: "shadow",
4247
- supportsArbitrary: true,
4248
- supportsCustomProperty: true,
4249
- supportsOpacity: true,
4250
- themeKeys: ["colors", "shadows"],
4251
- handle: (value, ctx, token, extra) => {
4252
- const main = value;
4253
- const opacity = extra?.opacity;
4254
- const realThemeValue = extra?.realThemeValue;
4255
- if (realThemeValue) {
4256
- return createShadowThemeColor(
4257
- "--baro-shadow-color",
4258
- main,
4259
- opacity,
4260
- realThemeValue
4261
- );
4262
- }
4263
- if (main.startsWith("color:")) {
4264
- const cp = main.replace("color:", "");
4265
- if (opacity) {
4266
- return [
4267
- decl(
4268
- "--baro-shadow-color",
4269
- `color-mix(in oklab, var(${cp}) ${opacity}%, transparent)`
4270
- )
4271
- ];
4272
- }
4273
- return [decl("--baro-shadow-color", `var(${cp})`)];
4274
- }
4275
- if (token.arbitrary) {
4276
- if (parseColor(main)) {
4277
- if (opacity) {
4278
- return [
4279
- decl(
4280
- "--baro-shadow-color",
4281
- `color-mix(in oklab, ${main} ${opacity}%, transparent)`
4282
- )
4283
- ];
4284
- }
4285
- return [decl("--baro-shadow-color", main)];
4286
- }
4287
- return shadowLayer(main);
4288
- }
4289
- if (main === "inherit" || main === "current" || main === "transparent") {
4290
- return [
4291
- decl("--baro-shadow-color", main === "current" ? "currentColor" : main)
4292
- ];
4293
- }
4294
- return null;
4409
+ match: (className) => /^shadow(\/.+)?$/.test(className),
4410
+ handler: (value, _ctx, token) => {
4411
+ const full = value ? `${token.prefix}-${value}` : token.prefix;
4412
+ const cut = full.indexOf("/");
4413
+ return namedBoxShadow("shadow", "", cut < 0 ? void 0 : full.slice(cut + 1)) ?? [];
4295
4414
  },
4296
- handleCustomProperty: (value) => shadowLayer(`var(${value})`)
4415
+ category: "effects"
4297
4416
  });
4417
+ const KEYWORD_COLORS = { inherit: "inherit", current: "currentcolor", transparent: "transparent" };
4418
+ function layerColor(layer, main, opacity, token, realThemeValue) {
4419
+ const keyword = token.arbitrary ? void 0 : KEYWORD_COLORS[realThemeValue ?? main];
4420
+ if (keyword) return shadowColorDecls(layer, keyword, opacity);
4421
+ if (realThemeValue) return shadowColorDecls(layer, main, opacity, `var(--color-${realThemeValue})`);
4422
+ if (main.startsWith("color:")) return shadowColorDecls(layer, `var(${main.slice(6)})`, opacity);
4423
+ if (token.arbitrary && parseColor(main)) return shadowColorDecls(layer, main, opacity);
4424
+ return void 0;
4425
+ }
4426
+ for (const layer of ["shadow", "inset-shadow"]) {
4427
+ functionalUtility({
4428
+ name: layer,
4429
+ supportsArbitrary: true,
4430
+ supportsCustomProperty: true,
4431
+ supportsOpacity: true,
4432
+ themeKeys: ["colors"],
4433
+ handleBareValue: ({ value, extra }) => namedBoxShadow(layer, value, extra?.opacity) ? value : null,
4434
+ handle: (value, _ctx, token, extra) => {
4435
+ const opacity = extra?.opacity;
4436
+ const named = !extra?.realThemeValue && !token.arbitrary ? namedBoxShadow(layer, value, opacity) : null;
4437
+ if (named) return named;
4438
+ const color = layerColor(layer, value, opacity, token, extra?.realThemeValue);
4439
+ if (color !== void 0) return color;
4440
+ if (token.arbitrary) return boxShadowLayer(layer, layer === "inset-shadow" ? insetEach(value) : value, opacity);
4441
+ return null;
4442
+ },
4443
+ handleCustomProperty: (value) => value.startsWith("color:") ? shadowColorDecls(layer, `var(${value.slice(6)})`, void 0) ?? [] : [ringShadowProperties(), decl(`--baro-${layer}`, layer === "inset-shadow" ? `inset var(${value})` : `var(${value})`), decl("box-shadow", SHADOW_COMPOSITE)]
4444
+ });
4445
+ }
4446
+ const textShadowProperties = () => atRoot([
4447
+ property("--baro-text-shadow-color"),
4448
+ property("--baro-text-shadow-alpha", "100%", "<percentage>")
4449
+ ]);
4450
+ const namedTextShadow = (ctx, name) => {
4451
+ const v = ctx.theme("textShadow", name);
4452
+ return typeof v === "string" && /^[\w.-]+$/.test(name) ? v : null;
4453
+ };
4454
+ const textShadowValue = (value, opacity) => {
4455
+ const decls = shadowValueDecls("text-shadow", "text-shadow", value, opacity);
4456
+ return decls ? [textShadowProperties(), ...decls] : null;
4457
+ };
4458
+ staticUtility("text-shadow-none", [textShadowProperties, ["text-shadow", "none"]], { category: "effects" });
4298
4459
  functionalUtility({
4299
- name: "inset-shadow",
4460
+ name: "text-shadow",
4300
4461
  supportsArbitrary: true,
4301
4462
  supportsCustomProperty: true,
4302
4463
  supportsOpacity: true,
4303
- themeKeys: ["colors", "shadows"],
4464
+ themeKeys: ["colors"],
4465
+ handleBareValue: ({ value, ctx }) => namedTextShadow(ctx, value) ? value : null,
4304
4466
  handle: (value, ctx, token, extra) => {
4305
- const main = value;
4306
4467
  const opacity = extra?.opacity;
4307
- const realThemeValue = extra?.realThemeValue;
4308
- if (realThemeValue) {
4309
- return createShadowThemeColor(
4310
- "--baro-inset-shadow-color",
4311
- main,
4312
- opacity,
4313
- realThemeValue
4314
- );
4315
- }
4316
- if (main.startsWith("color:")) {
4317
- const cp = main.replace("color:", "");
4318
- let colorValue = `var(${cp})`;
4319
- if (opacity) {
4320
- colorValue = `color-mix(in oklab, var(${cp}) ${opacity}%, transparent)`;
4321
- }
4322
- return [decl("--baro-inset-shadow-color", colorValue)];
4323
- }
4324
- if (token.arbitrary) {
4325
- if (parseColor(main)) {
4326
- let colorValue = main;
4327
- if (opacity) {
4328
- colorValue = `color-mix(in oklab, ${main} ${opacity}%, transparent)`;
4329
- }
4330
- return [decl("--baro-inset-shadow-color", colorValue)];
4331
- }
4332
- return [decl("box-shadow", `inset ${main}`)];
4333
- }
4334
- if (main === "inherit" || main === "current" || main === "transparent") {
4335
- return [
4336
- decl(
4337
- "--baro-inset-shadow-color",
4338
- main === "current" ? "currentColor" : main
4339
- )
4340
- ];
4468
+ if (!extra?.realThemeValue && !token.arbitrary) {
4469
+ const named = namedTextShadow(ctx, value);
4470
+ if (named) return textShadowValue(named, opacity);
4341
4471
  }
4472
+ const color = layerColor("text-shadow", value, opacity, token, extra?.realThemeValue);
4473
+ if (color !== void 0) return color && [textShadowProperties(), ...color];
4474
+ if (token.arbitrary) return textShadowValue(value, opacity);
4342
4475
  return null;
4343
4476
  },
4344
- handleCustomProperty: (value) => [decl("box-shadow", `var(${value})`)]
4477
+ handleCustomProperty: (value) => value.startsWith("color:") ? [textShadowProperties(), ...shadowColorDecls("text-shadow", `var(${value.slice(6)})`, void 0) ?? []] : [textShadowProperties(), decl("text-shadow", `var(${value})`)],
4478
+ category: "effects"
4345
4479
  });
4346
4480
  [
4347
4481
  ["ring", "1px"],
@@ -4884,12 +5018,15 @@ staticUtility("not-sr-only", [
4884
5018
  ], { category: "layout" });
4885
5019
  staticUtility("@container", [["container-type", "inline-size"]], { category: "layout" });
4886
5020
  staticUtility("@container-normal", [["container-type", "normal"]], { category: "layout" });
5021
+ staticUtility("@container-size", [["container-type", "size"]], { category: "layout" });
5022
+ const NAMED_CONTAINER = /^@container(-normal|-size)?\/([a-zA-Z0-9_-]+)$/;
5023
+ const CONTAINER_TYPE = { "": "inline-size", "-normal": "normal", "-size": "size" };
4887
5024
  registerUtility({
4888
5025
  name: "@container",
4889
- match: (className) => /^@container\/[a-zA-Z0-9_-]+$/.test(className),
5026
+ match: (className) => NAMED_CONTAINER.test(className),
4890
5027
  handler: (_value, _ctx, token) => {
4891
- const name = /^@container\/([a-zA-Z0-9_-]+)$/.exec(`${token.prefix}${token.value ? `-${token.value}` : ""}`)?.[1];
4892
- return name ? [decl("container-type", "inline-size"), decl("container-name", name)] : null;
5028
+ const m = NAMED_CONTAINER.exec(`${token.prefix}${token.value ? `-${token.value}` : ""}`);
5029
+ return m ? [decl("container-type", CONTAINER_TYPE[m[1] ?? ""]), decl("container-name", m[2])] : null;
4893
5030
  },
4894
5031
  category: "layout"
4895
5032
  });
@@ -4974,6 +5111,11 @@ staticUtility("sticky", [["position", "sticky"]], { category: "layout" });
4974
5111
  [
4975
5112
  ["inset-x", "inset-inline"],
4976
5113
  ["inset-y", "inset-block"],
5114
+ // Tailwind 4.3 logical sides; registered before `inset` so their handler runs first for `inset-s-*` etc.
5115
+ ["inset-s", "inset-inline-start"],
5116
+ ["inset-e", "inset-inline-end"],
5117
+ ["inset-bs", "inset-block-start"],
5118
+ ["inset-be", "inset-block-end"],
4977
5119
  ["inset", "inset"],
4978
5120
  ["start", "inset-inline-start"],
4979
5121
  ["end", "inset-inline-end"],
@@ -5069,6 +5211,15 @@ functionalUtility({
5069
5211
  description: "gap utility (number, arbitrary, custom property supported)",
5070
5212
  category: "layout"
5071
5213
  });
5214
+ functionalUtility({
5215
+ name: "zoom",
5216
+ prop: "zoom",
5217
+ supportsArbitrary: true,
5218
+ supportsCustomProperty: true,
5219
+ handleBareValue: ({ value }) => /^\d+$/.test(value) ? `${value}%` : null,
5220
+ description: "zoom utility (integer percent, arbitrary, custom property)",
5221
+ category: "layout"
5222
+ });
5072
5223
  staticUtility("basis-full", [["flex-basis", "100%"]], { category: "flex-grid" });
5073
5224
  staticUtility("basis-auto", [["flex-basis", "auto"]], { category: "flex-grid" });
5074
5225
  staticUtility("basis-3xs", [["flex-basis", "var(--container-3xs)"]], { category: "flex-grid" });
@@ -5343,6 +5494,8 @@ functionalUtility({
5343
5494
  // auto-cols-[minmax(0,2fr)]
5344
5495
  supportsCustomProperty: true,
5345
5496
  // auto-cols-(--my-auto-cols)
5497
+ handleBareValue: ({ value }) => parseNumber(value) ? `calc(var(--spacing) * ${value})` : null,
5498
+ // #310: auto-cols-4
5346
5499
  handle: (value) => {
5347
5500
  if (typeof value === "string") return [decl("grid-auto-columns", value)];
5348
5501
  return null;
@@ -5362,6 +5515,8 @@ functionalUtility({
5362
5515
  // auto-rows-[minmax(0,2fr)]
5363
5516
  supportsCustomProperty: true,
5364
5517
  // auto-rows-(--my-auto-rows)
5518
+ handleBareValue: ({ value }) => parseNumber(value) ? `calc(var(--spacing) * ${value})` : null,
5519
+ // #310: auto-rows-12
5365
5520
  handle: (value) => {
5366
5521
  if (typeof value === "string") return [decl("grid-auto-rows", value)];
5367
5522
  return null;
@@ -5564,6 +5719,8 @@ functionalUtility({
5564
5719
  ["py", "padding-block"],
5565
5720
  ["ps", "padding-inline-start"],
5566
5721
  ["pe", "padding-inline-end"],
5722
+ ["pbs", "padding-block-start"],
5723
+ ["pbe", "padding-block-end"],
5567
5724
  ["pt", "padding-top"],
5568
5725
  ["pr", "padding-right"],
5569
5726
  ["pb", "padding-bottom"],
@@ -5587,6 +5744,8 @@ functionalUtility({
5587
5744
  ["my", "margin-block"],
5588
5745
  ["ms", "margin-inline-start"],
5589
5746
  ["me", "margin-inline-end"],
5747
+ ["mbs", "margin-block-start"],
5748
+ ["mbe", "margin-block-end"],
5590
5749
  ["mt", "margin-top"],
5591
5750
  ["mr", "margin-right"],
5592
5751
  ["mb", "margin-bottom"],
@@ -5912,6 +6071,41 @@ functionalUtility({
5912
6071
  description: "max-width utility (spacing, fraction, arbitrary, custom property, static supported)",
5913
6072
  category: "sizing"
5914
6073
  });
6074
+ {
6075
+ const containers = ["3xs", "2xs", "xs", "sm", "md", "lg", "xl", "2xl", "3xl", "4xl", "5xl", "6xl", "7xl"].map(
6076
+ (k) => [k, `var(--container-${k})`]
6077
+ );
6078
+ const common = [["0", "0px"], ["px", "1px"], ["full", "100%"], ["min", "min-content"], ["max", "max-content"], ["fit", "fit-content"]];
6079
+ const inlineVp = [["screen", "100vw"], ["dvw", "100dvw"], ["lvw", "100lvw"], ["svw", "100svw"]];
6080
+ const blockVp = [["screen", "100vh"], ["dvh", "100dvh"], ["lvh", "100lvh"], ["svh", "100svh"], ["lh", "1lh"]];
6081
+ const families = [
6082
+ ["inline", "inline-size", [...common, ["auto", "auto"], ...inlineVp, ...containers]],
6083
+ ["min-inline", "min-inline-size", [...common, ["auto", "auto"], ...inlineVp, ...containers]],
6084
+ ["max-inline", "max-inline-size", [...common, ["none", "none"], ...inlineVp, ...containers]],
6085
+ ["block", "block-size", [...common, ["auto", "auto"], ...blockVp]],
6086
+ ["min-block", "min-block-size", [...common, ["auto", "auto"], ...blockVp]],
6087
+ ["max-block", "max-block-size", [...common, ["none", "none"], ...blockVp]]
6088
+ ];
6089
+ for (const [name, prop, statics] of families) {
6090
+ for (const [key, value] of statics) staticUtility(`${name}-${key}`, [[prop, value]], { category: "sizing" });
6091
+ functionalUtility({
6092
+ spacingKeys: true,
6093
+ name,
6094
+ prop,
6095
+ supportsArbitrary: true,
6096
+ supportsCustomProperty: true,
6097
+ supportsFraction: true,
6098
+ handleBareValue: ({ value, token }) => {
6099
+ if (token.negative) return null;
6100
+ if (parseNumber(value)) return `calc(var(--spacing) * ${value})`;
6101
+ if (parseFractionOrNumber(value)) return `calc(${value} * 100%)`;
6102
+ return null;
6103
+ },
6104
+ description: `${prop} utility (spacing, fraction, arbitrary, custom property, keywords)`,
6105
+ category: "sizing"
6106
+ });
6107
+ }
6108
+ }
5915
6109
  const leadingProperty = () => atRoot([property("--baro-leading")]);
5916
6110
  staticUtility("font-sans", [["font-family", "var(--font-sans)"]], { category: "typography" });
5917
6111
  staticUtility("font-serif", [["font-family", "var(--font-serif)"]], { category: "typography" });
@@ -5942,13 +6136,15 @@ functionalUtility({
5942
6136
  name: "font",
5943
6137
  supportsArbitrary: true,
5944
6138
  supportsCustomProperty: true,
5945
- handle: (value) => {
6139
+ handle: (value, _ctx, token) => {
6140
+ if (token.prefix !== "font") return null;
5946
6141
  if (parseNumber(value)) {
5947
6142
  return [decl("font-weight", value)];
5948
6143
  }
5949
6144
  return [decl("font-family", value)];
5950
6145
  },
5951
- handleCustomProperty: (value) => {
6146
+ handleCustomProperty: (value, _ctx, token) => {
6147
+ if (token.prefix !== "font") return null;
5952
6148
  if (value.startsWith("font-name:")) {
5953
6149
  return [decl("font-family", `var(${value.replace("font-name:", "")})`)];
5954
6150
  }
@@ -6247,6 +6443,42 @@ functionalUtility({
6247
6443
  description: "content utility (arbitrary, custom property supported)",
6248
6444
  category: "typography"
6249
6445
  });
6446
+ const placeholderColor = (value) => [rule("&::placeholder", [decl("color", value)])];
6447
+ staticUtility("placeholder-inherit", placeholderColor("inherit"), { category: "typography" });
6448
+ staticUtility("placeholder-current", placeholderColor("currentcolor"), { category: "typography" });
6449
+ staticUtility("placeholder-transparent", placeholderColor("transparent"), { category: "typography" });
6450
+ functionalUtility({
6451
+ name: "placeholder",
6452
+ themeKeys: ["colors"],
6453
+ supportsArbitrary: true,
6454
+ supportsCustomProperty: true,
6455
+ supportsOpacity: true,
6456
+ handle: (value, _ctx, _token, extra) => {
6457
+ if (extra?.realThemeValue) return [rule("&::placeholder", themeColorDecls("color", value, extra))];
6458
+ if (parseColor(value)) return placeholderColor(value);
6459
+ return null;
6460
+ },
6461
+ handleCustomProperty: (value) => placeholderColor(`var(${value})`),
6462
+ description: "placeholder color utility (theme, alpha, arbitrary, custom property)"
6463
+ });
6464
+ functionalUtility({
6465
+ name: "font-features",
6466
+ supportsArbitrary: true,
6467
+ supportsCustomProperty: true,
6468
+ handle: (value, _ctx, token) => token.arbitrary ? [decl("font-feature-settings", value)] : null,
6469
+ handleCustomProperty: (value) => [decl("font-feature-settings", `var(${value.replace(/^[a-z-]+:(?=--)/, "")})`)],
6470
+ description: "font-feature-settings utility (arbitrary, custom property)",
6471
+ category: "typography"
6472
+ });
6473
+ functionalUtility({
6474
+ name: "tab",
6475
+ prop: "tab-size",
6476
+ supportsArbitrary: true,
6477
+ supportsCustomProperty: true,
6478
+ handleBareValue: ({ value }) => /^\d+$/.test(value) ? value : null,
6479
+ description: "tab-size utility (integer, arbitrary, custom property)",
6480
+ category: "typography"
6481
+ });
6250
6482
  const gradientStopProperties = () => {
6251
6483
  return atRoot([
6252
6484
  property("--baro-gradient-position"),
@@ -6578,6 +6810,11 @@ const withBorderStyle = (props, width) => [
6578
6810
  [
6579
6811
  ["border-x", ["border-left-width", "border-right-width"]],
6580
6812
  ["border-y", ["border-top-width", "border-bottom-width"]],
6813
+ ["border-bs", ["border-block-start-width"]],
6814
+ ["border-be", ["border-block-end-width"]],
6815
+ ["border-s", ["border-inline-start-width"]],
6816
+ // #311 (Tailwind 4.3)
6817
+ ["border-e", ["border-inline-end-width"]],
6581
6818
  ["border-t", ["border-top-width"]],
6582
6819
  ["border-r", ["border-right-width"]],
6583
6820
  ["border-b", ["border-bottom-width"]],
@@ -6597,6 +6834,7 @@ const withBorderStyle = (props, width) => [
6597
6834
  functionalUtility({
6598
6835
  name,
6599
6836
  themeKeys: ["borderWidth", "colors"],
6837
+ supportsOpacity: true,
6600
6838
  supportsArbitrary: true,
6601
6839
  supportsCustomProperty: true,
6602
6840
  handleBareValue: ({ value }) => {
@@ -7577,9 +7815,10 @@ staticModifier("starting", ["&"], {
7577
7815
  wrap: () => [atRule("starting-style", "", [], "starting")],
7578
7816
  source: "starting"
7579
7817
  });
7580
- function createContainerParams(type, value, name) {
7818
+ function createContainerParams(type, value, name, negate = false) {
7581
7819
  const condition = type === "min" ? "width >=" : "width <";
7582
- return name ? `${name} (${condition} ${value})` : `(${condition} ${value})`;
7820
+ const query = `${negate ? "not " : ""}(${condition} ${value})`;
7821
+ return name ? `${name} ${query}` : query;
7583
7822
  }
7584
7823
  function createContainerRule(params, ast) {
7585
7824
  return {
@@ -7748,17 +7987,17 @@ functionalModifier(
7748
7987
  return result;
7749
7988
  }
7750
7989
  );
7751
- const SIZE_VARIANT = /^@(?:(min|max)-)?(\[[^\]]+\]|[a-zA-Z0-9.]+)(?:\/([a-zA-Z0-9_-]+))?$/;
7990
+ const SIZE_VARIANT = /^(not-)?@(?:(min|max)-)?(\[[^\]]+\]|[a-zA-Z0-9.]+)(?:\/([a-zA-Z0-9_-]+))?$/;
7752
7991
  functionalModifier(
7753
- (mod) => SIZE_VARIANT.test(mod) && !/^@container(?:\/|$)/.test(mod),
7992
+ (mod) => SIZE_VARIANT.test(mod) && !/^(?:not-)?@container(?:\/|$)/.test(mod),
7754
7993
  void 0,
7755
7994
  (mod, context) => {
7756
7995
  const m = SIZE_VARIANT.exec(mod.type);
7757
7996
  if (!m) return [];
7758
- const [, type, size, name] = m;
7997
+ const [, not, type, size, name] = m;
7759
7998
  const value = size.startsWith("[") ? size.slice(1, -1).replace(/_/g, " ") : context.theme("container." + size);
7760
7999
  if (!value) return [];
7761
- return [createContainerRule(createContainerParams(type === "max" ? "max" : "min", value, name), [])];
8000
+ return [createContainerRule(createContainerParams(type === "max" ? "max" : "min", value, name, !!not), [])];
7762
8001
  }
7763
8002
  );
7764
8003
  const startsAtRule = (bracket) => /^[\s_]*@/.test(bracket);
@@ -7898,7 +8137,7 @@ functionalModifier(
7898
8137
  }
7899
8138
  );
7900
8139
  functionalModifier(
7901
- (mod) => /^not-/.test(mod),
8140
+ (mod) => /^not-/.test(mod) && !mod.startsWith("not-@"),
7902
8141
  ({ selector, mod }) => {
7903
8142
  const m = /^not-(.+)$/.exec(mod.type);
7904
8143
  return {
@@ -7965,7 +8204,8 @@ functionalModifier(
7965
8204
  void 0
7966
8205
  );
7967
8206
  functionalModifier(
7968
- (mod) => mod.startsWith("not-"),
8207
+ (mod) => mod.startsWith("not-") && !mod.startsWith("not-@"),
8208
+ // not-@… is container negation (#311)
7969
8209
  ({ selector, mod }) => {
7970
8210
  const pseudo = mod.type.replace("not-", "");
7971
8211
  if (pseudo.startsWith("[")) {