@gnist/themes
Advanced tools
+22
-11
@@ -1,15 +0,19 @@ | ||
| import { globalStyle, style } from "@vanilla-extract/css"; | ||
| import { globalStyle } from "@vanilla-extract/css"; | ||
| import { createSprinkles, defineProperties } from "@vanilla-extract/sprinkles"; | ||
| import { typography } from "./layers.css.js"; | ||
| import { gnist, gnistStyle } from "./layers.css.js"; | ||
| import { tokens } from "./tokens.css.js"; | ||
| export const textContainer = style({}); | ||
| export const textContainer = gnistStyle({}); | ||
| globalStyle(`${textContainer} p, ${textContainer} ul, ${textContainer} ol`, { | ||
| marginTop: tokens.type.small.body.paragraphSpacing, | ||
| "@media": { | ||
| "screen and (min-width: 768px)": { | ||
| marginTop: tokens.type.medium.body.paragraphSpacing, | ||
| "@layer": { | ||
| [gnist]: { | ||
| marginTop: tokens.type.small.body.paragraphSpacing, | ||
| "@media": { | ||
| "screen and (min-width: 768px)": { | ||
| marginTop: tokens.type.medium.body.paragraphSpacing, | ||
| }, | ||
| "screen and (min-width: 1024px)": { | ||
| marginTop: tokens.type.large.body.paragraphSpacing, | ||
| }, | ||
| }, | ||
| }, | ||
| "screen and (min-width: 1024px)": { | ||
| marginTop: tokens.type.large.body.paragraphSpacing, | ||
| }, | ||
| }, | ||
@@ -19,2 +23,3 @@ }); | ||
| const responsiveProperties = defineProperties({ | ||
| "@layer": gnist, | ||
| conditions: { | ||
@@ -62,2 +67,3 @@ mobile: {}, | ||
| const colorProperties = defineProperties({ | ||
| "@layer": gnist, | ||
| properties: { | ||
@@ -72,2 +78,3 @@ backgroundColor: color, | ||
| const radiusProperties = defineProperties({ | ||
| "@layer": gnist, | ||
| properties: { | ||
@@ -90,2 +97,3 @@ borderTopLeftRadius: radius, | ||
| const strokeProperties = defineProperties({ | ||
| "@layer": gnist, | ||
| properties: { | ||
@@ -108,2 +116,3 @@ borderTopWidth: stroke, | ||
| const elevationProperties = defineProperties({ | ||
| "@layer": gnist, | ||
| properties: { | ||
@@ -115,2 +124,3 @@ boxShadow: elevation, | ||
| const sizeProperties = defineProperties({ | ||
| "@layer": gnist, | ||
| properties: { | ||
@@ -139,3 +149,3 @@ width: size, | ||
| const responsiveTypeProperties = defineProperties({ | ||
| "@layer": typography, | ||
| "@layer": gnist, | ||
| conditions: { | ||
@@ -152,2 +162,3 @@ mobile: {}, | ||
| const positionProperties = defineProperties({ | ||
| "@layer": gnist, | ||
| properties: { | ||
@@ -154,0 +165,0 @@ position: ["static", "relative", "absolute", "fixed", "sticky"], |
+58
-0
@@ -0,2 +1,60 @@ | ||
| import { ComplexStyleRule } from "@vanilla-extract/css"; | ||
| import { RecipeVariants, RuntimeFn } from "@vanilla-extract/recipes"; | ||
| /** @deprecated No longer used internally. Will be removed in next major version. */ | ||
| export declare const typography: string; | ||
| /** @deprecated No longer used internally. Will be removed in next major version. */ | ||
| export declare const framework: string; | ||
| export declare const gnist = "gnist"; | ||
| /** | ||
| * A custom style() function that wraps all styles in @layer gnist { }. | ||
| * Has the same API as vanilla-extract's style() function. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * import { gnistStyle } from "@gnist/themes/layers.css.js"; | ||
| * | ||
| * const myClass = gnistStyle({ | ||
| * color: "red", | ||
| * padding: "10px", | ||
| * }); | ||
| * ``` | ||
| */ | ||
| export declare function gnistStyle(rule: ComplexStyleRule, debugId?: string): string; | ||
| type RecipeStyleRule = ComplexStyleRule | string; | ||
| type VariantDefinitions = Record<string, RecipeStyleRule>; | ||
| type BooleanMap<T> = T extends "true" | "false" ? boolean : T; | ||
| type VariantGroups = Record<string, VariantDefinitions>; | ||
| type VariantSelection<Variants extends VariantGroups> = { | ||
| [VariantGroup in keyof Variants]?: BooleanMap<keyof Variants[VariantGroup]> | undefined; | ||
| }; | ||
| interface CompoundVariant<Variants extends VariantGroups> { | ||
| variants: VariantSelection<Variants>; | ||
| style: RecipeStyleRule; | ||
| } | ||
| type PatternOptions<Variants extends VariantGroups> = { | ||
| base?: RecipeStyleRule; | ||
| variants?: Variants; | ||
| defaultVariants?: VariantSelection<Variants>; | ||
| compoundVariants?: Array<CompoundVariant<Variants>>; | ||
| }; | ||
| /** | ||
| * A custom recipe() function that wraps all styles in @layer gnist { }. | ||
| * Has the same API as @vanilla-extract/recipes' recipe() function. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * import { gnistRecipe } from "@gnist/themes/layers.css.js"; | ||
| * | ||
| * const myRecipe = gnistRecipe({ | ||
| * base: { padding: "10px" }, | ||
| * variants: { | ||
| * color: { | ||
| * primary: { backgroundColor: "blue" }, | ||
| * secondary: { backgroundColor: "gray" }, | ||
| * }, | ||
| * }, | ||
| * }); | ||
| * ``` | ||
| */ | ||
| export declare function gnistRecipe<Variants extends VariantGroups>(options: PatternOptions<Variants>, debugId?: string): RuntimeFn<Variants>; | ||
| export type { RecipeVariants }; |
+128
-1
@@ -1,3 +0,130 @@ | ||
| import { layer } from "@vanilla-extract/css"; | ||
| import { layer, style, } from "@vanilla-extract/css"; | ||
| import { recipe } from "@vanilla-extract/recipes"; | ||
| /** @deprecated No longer used internally. Will be removed in next major version. */ | ||
| export const typography = layer("typography"); | ||
| /** @deprecated No longer used internally. Will be removed in next major version. */ | ||
| export const framework = layer("framework"); | ||
| export const gnist = "gnist"; | ||
| /** | ||
| * Wraps a StyleRule object with the gnist layer. | ||
| * Preserves any existing @layer rules by merging them. | ||
| */ | ||
| function wrapInGnistLayer(rule) { | ||
| if (rule["@layer"]) { | ||
| // If there's already a @layer, we need to merge | ||
| const existingLayer = rule["@layer"]; | ||
| return { | ||
| ...rule, | ||
| "@layer": { | ||
| [gnist]: existingLayer, | ||
| }, | ||
| }; | ||
| } | ||
| return { | ||
| "@layer": { | ||
| [gnist]: rule, | ||
| }, | ||
| }; | ||
| } | ||
| /** | ||
| * Processes a ComplexStyleRule, wrapping StyleRule objects with the gnist layer. | ||
| * Handles strings (class names), arrays, and StyleRule objects. | ||
| */ | ||
| function processComplexStyleRule(rule) { | ||
| if (typeof rule === "string") { | ||
| // Class name string - pass through unchanged | ||
| return rule; | ||
| } | ||
| if (Array.isArray(rule)) { | ||
| // Recursively process array items | ||
| return rule.map((item) => item ? processComplexStyleRule(item) : item); | ||
| } | ||
| // It's a StyleRule object - wrap it | ||
| return wrapInGnistLayer(rule); | ||
| } | ||
| /** | ||
| * A custom style() function that wraps all styles in @layer gnist { }. | ||
| * Has the same API as vanilla-extract's style() function. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * import { gnistStyle } from "@gnist/themes/layers.css.js"; | ||
| * | ||
| * const myClass = gnistStyle({ | ||
| * color: "red", | ||
| * padding: "10px", | ||
| * }); | ||
| * ``` | ||
| */ | ||
| export function gnistStyle(rule, debugId) { | ||
| const processedRule = processComplexStyleRule(rule); | ||
| return style(processedRule, debugId); | ||
| } | ||
| /** | ||
| * Processes a RecipeStyleRule, wrapping StyleRule objects with the gnist layer. | ||
| * Strings (class names) pass through unchanged. | ||
| */ | ||
| function processRecipeStyleRule(rule) { | ||
| if (typeof rule === "string") { | ||
| // Class name string - pass through unchanged | ||
| return rule; | ||
| } | ||
| return processComplexStyleRule(rule); | ||
| } | ||
| /** | ||
| * Processes recipe variants, wrapping each variant's styles with the gnist layer. | ||
| */ | ||
| function processRecipeVariants(variants) { | ||
| const processed = {}; | ||
| for (const [variantName, variantValues] of Object.entries(variants)) { | ||
| processed[variantName] = {}; | ||
| for (const [valueName, styles] of Object.entries(variantValues)) { | ||
| processed[variantName][valueName] = processRecipeStyleRule(styles); | ||
| } | ||
| } | ||
| return processed; | ||
| } | ||
| /** | ||
| * Processes compound variants, wrapping each compound variant's style with the gnist layer. | ||
| */ | ||
| function processCompoundVariants(compoundVariants) { | ||
| return compoundVariants.map((cv) => ({ | ||
| ...cv, | ||
| style: processRecipeStyleRule(cv.style), | ||
| })); | ||
| } | ||
| /** | ||
| * A custom recipe() function that wraps all styles in @layer gnist { }. | ||
| * Has the same API as @vanilla-extract/recipes' recipe() function. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * import { gnistRecipe } from "@gnist/themes/layers.css.js"; | ||
| * | ||
| * const myRecipe = gnistRecipe({ | ||
| * base: { padding: "10px" }, | ||
| * variants: { | ||
| * color: { | ||
| * primary: { backgroundColor: "blue" }, | ||
| * secondary: { backgroundColor: "gray" }, | ||
| * }, | ||
| * }, | ||
| * }); | ||
| * ``` | ||
| */ | ||
| export function gnistRecipe(options, debugId) { | ||
| const processedOptions = {}; | ||
| if (options.base !== undefined) { | ||
| processedOptions.base = processRecipeStyleRule(options.base); | ||
| } | ||
| if (options.variants) { | ||
| processedOptions.variants = processRecipeVariants(options.variants); | ||
| } | ||
| if (options.defaultVariants) { | ||
| processedOptions.defaultVariants = options.defaultVariants; | ||
| } | ||
| if (options.compoundVariants) { | ||
| processedOptions.compoundVariants = processCompoundVariants(options.compoundVariants); | ||
| } | ||
| return recipe(processedOptions, debugId); | ||
| } |
@@ -1,3 +0,4 @@ | ||
| import { globalStyle, style } from "@vanilla-extract/css"; | ||
| import { globalStyle } from "@vanilla-extract/css"; | ||
| import { atoms } from "./atoms.css.js"; | ||
| import { gnist, gnistStyle } from "./layers.css.js"; | ||
| import { tokens } from "./tokens.css.js"; | ||
@@ -28,3 +29,3 @@ /** | ||
| })); | ||
| export const globalTextStyles = style([ | ||
| export const globalTextStyles = gnistStyle([ | ||
| atoms({ backgroundColor: "background", color: "on-background" }), | ||
@@ -34,4 +35,8 @@ responsiveTypography.body, | ||
| globalStyle("p, ul, ol", { | ||
| margin: 0, | ||
| fontFamily: tokens.typeface.brand, | ||
| "@layer": { | ||
| [gnist]: { | ||
| margin: 0, | ||
| fontFamily: tokens.typeface.brand, | ||
| }, | ||
| }, | ||
| }); |
+6
-2
| { | ||
| "name": "@gnist/themes", | ||
| "version": "3.29.0", | ||
| "version": "3.30.0-alpha.2", | ||
| "license": "UNLICENSED", | ||
@@ -8,2 +8,6 @@ "description": "", | ||
| "exports": { | ||
| "./layers.css.js": { | ||
| "import": "./dist/layers.css.js", | ||
| "types": "./dist/layers.css.d.ts" | ||
| }, | ||
| "./atoms.css.js": { | ||
@@ -67,3 +71,3 @@ "import": "./dist/atoms.css.js", | ||
| }, | ||
| "gitHead": "1b5b7189ae8c3576e8fec2c28f1d418667a544d4" | ||
| "gitHead": "a7a72c810de3a341dee37cad940f4a6e7bfb66be" | ||
| } |
+63
-9
@@ -7,2 +7,55 @@ # Themes for @gnist/design-system | ||
| ## CSS Layers | ||
| All styles produced by this library are wrapped in `@layer gnist { }`. This means consumers can override any design system style without specificity issues — unlayered styles always take precedence over layered styles. | ||
| To ensure correct layer ordering, add a `@layer` declaration at the top of your main CSS file (e.g. `globals.css`): | ||
| ```css | ||
| @layer base, gnist; | ||
| ``` | ||
| This guarantees that `gnist` styles take precedence over `base` styles. Any global or reset CSS you write should be wrapped in `@layer base { }` so it doesn't unintentionally override design system styles: | ||
| ```css | ||
| @layer base { | ||
| *, | ||
| *::before, | ||
| *::after { | ||
| box-sizing: border-box; | ||
| margin: 0; | ||
| } | ||
| } | ||
| ``` | ||
| Styles written outside any `@layer` will still take the highest precedence, allowing you to override design system styles when needed. | ||
| ## Development | ||
| When writing styles within the design system or gnist-app, use `gnistStyle` and `gnistRecipe` instead of vanilla-extract's `style` and `recipe`: | ||
| ```ts | ||
| import { gnistStyle, gnistRecipe } from "@gnist/themes/layers.css.js"; | ||
| const myClass = gnistStyle({ color: "red" }); | ||
| const myRecipe = gnistRecipe({ | ||
| base: { padding: "10px" }, | ||
| variants: { | ||
| size: { | ||
| small: { fontSize: "12px" }, | ||
| large: { fontSize: "18px" }, | ||
| }, | ||
| }, | ||
| }); | ||
| ``` | ||
| A lint rule enforces this — importing `style` from `@vanilla-extract/css` or `recipe` from `@vanilla-extract/recipes` will produce an error. | ||
| Note that `globalStyle` and `styleVariants` are not wrapped automatically and must be manually placed inside `@layer` when needed. | ||
| See DEVELOPMENT.md for more details. | ||
| ## Overview | ||
@@ -96,7 +149,7 @@ | ||
| ```ts | ||
| import { style } from "@vanilla-extract/css"; | ||
| import { gnistStyle } from "@gnist/themes/layers.css.js"; | ||
| import { tokens } from "@gnist/themes/tokens.css.js"; | ||
| import { boxColors } from "@gnist/themes/colors.css.js"; | ||
| const box = style([ | ||
| const box = gnistStyle([ | ||
| boxColors["primary-container"], | ||
@@ -121,7 +174,7 @@ { borderWidth: tokens.stroke.medium }, | ||
| ```tsx | ||
| import { style } from "@vanilla-extract/css"; | ||
| import { gnistStyle } from "@gnist/themes/layers.css.js"; | ||
| import { atoms } from "@gnist/themes/atoms.css.js"; | ||
| import { responsiveTypography } from "@gnist/themes/typography.css.js" | ||
| const someStyle = style([ | ||
| const someStyle = gnistStyle([ | ||
| atoms({ display: "flex", padding: "xs" }), | ||
@@ -145,7 +198,7 @@ responsiveTypography.lead, | ||
| ```ts | ||
| import { recipe } from "@vanilla-extract/recipes"; | ||
| import { gnistRecipe } from "@gnist/themes/layers.css.js"; | ||
| import { atoms } from "@gnist/themes/atoms.css.js"; | ||
| import { densityTypography } from "@gnist/themes/typography.css.js"; | ||
| const action = recipe({ | ||
| const action = gnistRecipe({ | ||
| base: atoms({ display: "block" }), | ||
@@ -155,3 +208,3 @@ ...densityTypography.action, | ||
| const className = recipe({ density: "default" }); | ||
| const className = action({ density: "default" }); | ||
| ``` | ||
@@ -162,7 +215,7 @@ | ||
| ```ts | ||
| import { recipe } from "@vanilla-extract/recipes"; | ||
| import { gnistRecipe } from "@gnist/themes/layers.css.js"; | ||
| import { atoms } from "@gnist/themes/atoms.css.js"; | ||
| import { densityTypography } from "@gnist/themes/typography.css.js"; | ||
| const box = recipe({ | ||
| const box = gnistRecipe({ | ||
| base: [atoms({ display: "block" })], | ||
@@ -360,1 +413,2 @@ variants: { | ||
| **Note:** These tokens stay in sync with the vanilla-extract themes automatically when design tokens are updated from Figma. | ||
Sorry, the diff of this file is not supported yet
Explicitly Unlicensed Item
LicenseSomething was found which is explicitly marked as unlicensed.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
Explicitly Unlicensed Item
LicenseSomething was found which is explicitly marked as unlicensed.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
768975
1.12%22014
0.92%407
14.97%2
100%3
50%