frame(): concentric radiusThe first plugin, written only on scope() above. A frame passes its inner radius down the tree; a nested frame's radius is the parent's inner radius less its own margin, so a rounded field in a rounded card stays concentric with no wiring, however many plain wrappers sit between them.
import * as import csscss from "cssints" with { type: "cssints" };
import { const frame: () => Chain<"frame", {
readonly radius: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly padding: {
readonly args: "<length [0,∞]>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
readonly border: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly margin: {
readonly args: "<length>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
}, Own<{
readonly core: {
readonly css: string;
readonly atProperty: string;
readonly requires: ["css.at-rules.property", "css.types.max"];
};
readonly fallback: {
...;
};
readonly noBox: {
...;
};
readonly frame: {
...;
};
}>>
frame } from "cssints/frame" with { type: "cssints" };
const const radius: Token<"length", true, string>radius = import csscss.const token: {
readonly number: TokenFn<"number">;
readonly length: TokenFn<"length">;
readonly color: TokenFn<"color">;
readonly percentage: TokenFn<"percentage">;
readonly integer: TokenFn<"integer">;
readonly angle: TokenFn<"angle">;
readonly time: TokenFn<"time">;
readonly resolution: TokenFn<"resolution">;
readonly url: TokenFn<"url">;
readonly image: TokenFn<"image">;
readonly shadow: TokenFn<"shadow">;
readonly lengthPercentage: TokenFn<"lengthPercentage">;
readonly customIdent: TokenFn<...>;
readonly transformList: TokenFn<...>;
readonly easingFunction: TokenFn<...>;
} & {
...;
}
`token.<type>(initial, name?)`: a Typed OM value of the type, `var(--name)`. With a name it can be set.token.length: <"12px", "radius-lg">(initial: "12px", name?: "radius-lg" | undefined) => Token<"length", true, string>length("12px", "radius-lg");
// radius 24px, padding 16px, border 1px: the field inside gets 24 - 16 - 1 = 7px
export const const card: css.Stylecard = import csscss.const cn: (...styles: css.Style[]) => css.Stylecn(function frame(): Chain<"frame", {
readonly radius: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly padding: {
readonly args: "<length [0,∞]>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
readonly border: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly margin: {
readonly args: "<length>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
}, Own<{
readonly core: {
readonly css: string;
readonly atProperty: string;
readonly requires: ["css.at-rules.property", "css.types.max"];
};
readonly fallback: {
...;
};
readonly noBox: {
...;
};
readonly frame: {
...;
};
}>>
frame().radius: <readonly ["1.5rem"]>(parts_0: "1.5rem") => Chain<"frame", Omit<{
readonly radius: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly padding: {
readonly args: "<length [0,∞]>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
readonly border: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly margin: {
readonly args: "<length>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
}, "radius">, Own<{
readonly core: {
readonly css: string;
readonly atProperty: string;
readonly requires: [...];
};
readonly fallback: {
...;
};
readonly noBox: {
...;
};
readonly frame: {
...;
};
}>>
radius("1.5rem").padding: <readonly [4]>(parts_0: 4) => Chain<"frame", Omit<Omit<{
readonly radius: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly padding: {
readonly args: "<length [0,∞]>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
readonly border: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly margin: {
readonly args: "<length>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
}, "radius">, "padding">, Own<{
readonly core: {
readonly css: string;
readonly atProperty: string;
readonly requires: [...];
};
readonly fallback: {
...;
};
readonly noBox: {
...;
};
readonly frame: {
...;
};
}>>
padding(4).border: <readonly ["1px"]>(parts_0: "1px") => Chain<"frame", Omit<Omit<Omit<{
readonly radius: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly padding: {
readonly args: "<length [0,∞]>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
readonly border: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly margin: {
readonly args: "<length>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
}, "radius">, "padding">, "border">, Own<...>>
border("1px"), import csscss.const bg: <readonly ["white"]>(parts_0: "white") => css.Style`<color>`. Chrome 1, Edge 12, Firefox 1, Safari 1, iOS 1, Android 18. [MDN](https://developer.mozilla.org/docs/Web/CSS/background-color)bg("white"), import csscss.const borderColor: <readonly ["#9ca3af"]>(parts_0: "#9ca3af") => css.Style`<color>{1,4}`. Chrome 1, Edge 12, Firefox 1, Safari 1, iOS 1, Android 18. [MDN](https://developer.mozilla.org/docs/Web/CSS/border-color)borderColor("#9ca3af"));
export const const field: css.Stylefield = import csscss.const cn: (...styles: css.Style[]) => css.Stylecn(function frame(): Chain<"frame", {
readonly radius: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly padding: {
readonly args: "<length [0,∞]>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
readonly border: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly margin: {
readonly args: "<length>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
}, Own<{
readonly core: {
readonly css: string;
readonly atProperty: string;
readonly requires: ["css.at-rules.property", "css.types.max"];
};
readonly fallback: {
...;
};
readonly noBox: {
...;
};
readonly frame: {
...;
};
}>>
frame().padding: <readonly [2]>(parts_0: 2) => Chain<"frame", Omit<{
readonly radius: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly padding: {
readonly args: "<length [0,∞]>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
readonly border: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly margin: {
readonly args: "<length>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
}, "padding">, Own<{
readonly core: {
readonly css: string;
readonly atProperty: string;
readonly requires: [...];
};
readonly fallback: {
...;
};
readonly noBox: {
...;
};
readonly frame: {
...;
};
}>>
padding(2).border: <readonly ["1px"]>(parts_0: "1px") => Chain<"frame", Omit<Omit<{
readonly radius: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly padding: {
readonly args: "<length [0,∞]>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
readonly border: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly margin: {
readonly args: "<length>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
}, "padding">, "border">, Own<{
readonly core: {
readonly css: string;
readonly atProperty: string;
readonly requires: [...];
};
readonly fallback: {
...;
};
readonly noBox: {
...;
};
readonly frame: {
...;
};
}>>
border("1px"), import csscss.const borderColor: <readonly ["#9ca3af"]>(parts_0: "#9ca3af") => css.Style`<color>{1,4}`. Chrome 1, Edge 12, Firefox 1, Safari 1, iOS 1, Android 18. [MDN](https://developer.mozilla.org/docs/Web/CSS/border-color)borderColor("#9ca3af"));
// a token is a length; a condition just sets the custom property, and the whole subtree follows
export const const panel: css.Stylepanel = import csscss.const cn: (...styles: css.Style[]) => css.Stylecn(function frame(): Chain<"frame", {
readonly radius: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly padding: {
readonly args: "<length [0,∞]>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
readonly border: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly margin: {
readonly args: "<length>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
}, Own<{
readonly core: {
readonly css: string;
readonly atProperty: string;
readonly requires: ["css.at-rules.property", "css.types.max"];
};
readonly fallback: {
...;
};
readonly noBox: {
...;
};
readonly frame: {
...;
};
}>>
frame().radius: <readonly [Token<"length", true, string>]>(parts_0: Token<"length", true, string>) => Chain<"frame", Omit<{
readonly radius: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly padding: {
readonly args: "<length [0,∞]>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
readonly border: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly margin: {
readonly args: "<length>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
}, "radius">, Own<...>>
radius(const radius: Token<"length", true, string>radius).padding: <readonly [2]>(parts_0: 2) => Chain<"frame", Omit<Omit<{
readonly radius: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly padding: {
readonly args: "<length [0,∞]>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
readonly border: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly margin: {
readonly args: "<length>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
}, "radius">, "padding">, Own<{
readonly core: {
readonly css: string;
readonly atProperty: string;
readonly requires: [...];
};
readonly fallback: {
...;
};
readonly noBox: {
...;
};
readonly frame: {
...;
};
}>>
padding(2), import csscss.const media: Condition
<"(width >= 40rem)">(query: "(width >= 40rem)") => css.QueryWrap (+2 overloads)
media("(width >= 40rem)")(function frame(): Chain<"frame", {
readonly radius: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly padding: {
readonly args: "<length [0,∞]>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
readonly border: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly margin: {
readonly args: "<length>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
}, Own<{
readonly core: {
readonly css: string;
readonly atProperty: string;
readonly requires: ["css.at-rules.property", "css.types.max"];
};
readonly fallback: {
...;
};
readonly noBox: {
...;
};
readonly frame: {
...;
};
}>>
frame().padding: <readonly [6]>(parts_0: 6) => Chain<"frame", Omit<{
readonly radius: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly padding: {
readonly args: "<length [0,∞]>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
readonly border: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly margin: {
readonly args: "<length>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
}, "padding">, Own<{
readonly core: {
readonly css: string;
readonly atProperty: string;
readonly requires: [...];
};
readonly fallback: {
...;
};
readonly noBox: {
...;
};
readonly frame: {
...;
};
}>>
padding(6)));
export const const noNumber: Chain<"frame", Omit<{
readonly radius: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly padding: {
readonly args: "<length [0,∞]>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
readonly border: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly margin: {
readonly args: "<length>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
}, "radius">, Own<{
readonly core: {
readonly css: string;
readonly atProperty: string;
readonly requires: ["css.at-rules.property", "css.types.max"];
};
readonly fallback: {
...;
};
readonly noBox: {
...;
};
readonly frame: {
...;
};
}>>
noNumber = function frame(): Chain<"frame", {
readonly radius: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly padding: {
readonly args: "<length [0,∞]>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
readonly border: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly margin: {
readonly args: "<length>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
}, Own<{
readonly core: {
readonly css: string;
readonly atProperty: string;
readonly requires: ["css.at-rules.property", "css.types.max"];
};
readonly fallback: {
...;
};
readonly noBox: {
...;
};
readonly frame: {
...;
};
}>>
frame().radius: <readonly [4]>(parts_0: "frame.radius: unexpected \"4\" in \"4\", grammar <length [0,∞]>") => Chain<"frame", Omit<{
readonly radius: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly padding: {
readonly args: "<length [0,∞]>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
readonly border: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly margin: {
readonly args: "<length>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
}, "radius">, Own<...>>
radius(4); // error: a bare number is a spacing step in padding and margin onlyexport const const noPercent: Chain<"frame", Omit<{
readonly radius: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly padding: {
readonly args: "<length [0,∞]>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
readonly border: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly margin: {
readonly args: "<length>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
}, "padding">, Own<{
readonly core: {
readonly css: string;
readonly atProperty: string;
readonly requires: ["css.at-rules.property", "css.types.max"];
};
readonly fallback: {
...;
};
readonly noBox: {
...;
};
readonly frame: {
...;
};
}>>
noPercent = function frame(): Chain<"frame", {
readonly radius: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly padding: {
readonly args: "<length [0,∞]>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
readonly border: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly margin: {
readonly args: "<length>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
}, Own<{
readonly core: {
readonly css: string;
readonly atProperty: string;
readonly requires: ["css.at-rules.property", "css.types.max"];
};
readonly fallback: {
...;
};
readonly noBox: {
...;
};
readonly frame: {
...;
};
}>>
frame().padding: <readonly ["5%"]>(parts_0: "frame.padding: unexpected \"5%\" in \"5%\", grammar <length [0,∞]>") => Chain<"frame", Omit<{
readonly radius: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly padding: {
readonly args: "<length [0,∞]>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
readonly border: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly margin: {
readonly args: "<length>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
}, "padding">, Own<...>>
padding("5%"); // error: a length, not a percentageexport const const once: anyonce = function frame(): Chain<"frame", {
readonly radius: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly padding: {
readonly args: "<length [0,∞]>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
readonly border: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly margin: {
readonly args: "<length>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
}, Own<{
readonly core: {
readonly css: string;
readonly atProperty: string;
readonly requires: ["css.at-rules.property", "css.types.max"];
};
readonly fallback: {
...;
};
readonly noBox: {
...;
};
readonly frame: {
...;
};
}>>
frame().radius: <readonly ["1px"]>(parts_0: "1px") => Chain<"frame", Omit<{
readonly radius: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly padding: {
readonly args: "<length [0,∞]>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
readonly border: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly margin: {
readonly args: "<length>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
}, "radius">, Own<{
readonly core: {
readonly css: string;
readonly atProperty: string;
readonly requires: [...];
};
readonly fallback: {
...;
};
readonly noBox: {
...;
};
readonly frame: {
...;
};
}>>
radius("1px").radius("2px"); // error: a method is used onceexport const const own: anyown = function frame(): Chain<"frame", {
readonly radius: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly padding: {
readonly args: "<length [0,∞]>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
readonly border: {
readonly args: "<length [0,∞]>";
readonly emit: (v: string) => [string, string][];
};
readonly margin: {
readonly args: "<length>";
readonly spacing: true;
readonly emit: (v: string) => [string, string][];
};
}, Own<{
readonly core: {
readonly css: string;
readonly atProperty: string;
readonly requires: ["css.at-rules.property", "css.types.max"];
};
readonly fallback: {
...;
};
readonly noBox: {
...;
};
readonly frame: {
...;
};
}>>
frame().color("red"); // error: a frame chains its own methods onlyradius(<length>), padding(<length> | step), border(<length>) (a width; the style is solid), margin(<length> | step). radius is the radius of the outermost frame; inside a frame it is ignored (the radius is computed). A lone number in padding and margin is a step of the spacing scale (0.25rem). Tokens go anywhere a length does.cn() that holds frame() and a property it sets: padding*, margin*, border-radius and its corners, border, border-width, border-style and the border sides (cssints: frame: frame() sets padding, margin, border-radius and the border: use its methods (this style also sets padding)). Border colours (borderColor, borderTopColor) are plain styles and do not conflict. Conflicts across cx() are not seen, as for any plugin._frame-core and one class per method (._x{--frame-p:0.5rem}, in _.a, or _.b inside a condition). The kernel frame.core (about 1.2 kB minified with its registrations and fallback, once, in _.k) is two @container style(--frame-c: ...) rules that alternate two names, because a property cannot read itself; the @property rules of its custom properties (--frame-*) are at the top of the sheet. The names are the scope's own (--_x in the source is --frame-x, & is _frame-core), which is why they are longer than the --fr-* and _f of the helpers it was first written on. The inputs are registered lengths, so em, calc() and tokens reach the child as exact lengths (an em padding is the parent's em, not the child's). The 24-line kernel for px and rem only was not chosen: @property is the floor of the runtime anyway, and the registered one costs about 0.2 kB more.@container style() on custom properties (Chrome 111, Safari 18, Firefox 151) and @property (Chrome 85, Safari 16.4, Firefox 128). For a target that has @property and lacks style queries the build ships the fallback instead: polyfills: ["css.at-rules.container.style_queries_for_custom_properties"] and cssints/parent-vars (about 1 kB gzip, shared with other plugins), which copies each frame's inner radius to its frame children, and the fallback CSS. The script probes the browser and stays off where style queries work. Below @property (Firefox 127, Safari 16.3) the kernel is a build warning and nothing is shipped: a frame keeps no concentric radius there.transition of your own on a frame replaces the sentinel that lets :hover, media and container conditions reach the script (the script still follows class and style changes); shadow roots are not crossed; a first paint before the script runs shows declared radii.