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