| @use "sass:map"; |
| @use "config" as *; |
| |
| @function theme-color-values($key) { |
| $result: (); |
| |
| @each $color-name, $color-map in $theme-colors { |
| @if map.has-key($color-map, $key) { |
| $result: map.merge($result, ($color-name: map.get($color-map, $key))); |
| } |
| } |
| |
| @return $result; |
| } |
| |
| // Themes map sub-keys |
| // |
| // Return var() references to root tokens instead of raw values. |
| // Ex: theme-color-refs("bg") => (primary: var(--primary-bg), accent: var(--accent-bg), ...) |
| @function theme-color-refs($key) { |
| $result: (); |
| |
| @each $color-name, $color-map in $theme-colors { |
| @if map.has-key($color-map, $key) { |
| $result: map.merge($result, ($color-name: var(--#{$color-name}-#{$key}))); |
| } |
| } |
| |
| @return $result; |
| } |
| |
| // Theme token to root tokens |
| // |
| // Returns the global :root token reference for a given a given token map, prefix, and key. |
| // Ex: theme-token-refs($theme-bgs, "bg") => (body: var(--bg-body), 1: var(--bg-1), ...) |
| // Skips `inherit` since it's a CSS-wide keyword that can't be stored in a custom property. |
| @function theme-token-refs($map, $prefix) { |
| $result: (); |
| |
| @each $key, $value in $map { |
| @if $value != inherit { |
| $result: map.merge($result, ($key: var(--#{$prefix}-#{$key}))); |
| } |
| } |
| |
| @return $result; |
| } |
| |
| // Generate opacity values using color-mix() |
| // $fallback lets the referenced $color-var fall back to another color (e.g. currentcolor) |
| // when it hasn't been set by a companion color utility. |
| @function theme-opacity-values($color-var, $fallback: null, $opacities: $util-opacity) { |
| $result: (); |
| // stylelint-disable-next-line scss/at-function-named-arguments, @stylistic/function-whitespace-after |
| $color: if(sass($fallback): var($color-var, $fallback); else: var($color-var)); |
| |
| @each $key, $value in $opacities { |
| @if $key == 100 { |
| // For 100%, use direct variable reference (more efficient) |
| $result: map.merge($result, ($key: $color)); |
| } @else { |
| // For other values, use color-mix() |
| $percentage: $key * 1%; |
| $result: map.merge($result, ($key: color-mix(in oklch, $color $percentage, transparent))); |
| } |
| } |
| |
| @return $result; |
| } |
| |
| // Set each --theme-* token to `initial` so descendants drop inherited theme colors. |
| // Use `initial`, not `unset`. `unset` inherits from the parent again. |
| // scss-docs-start generate-theme-reset |
| @mixin generate-theme-reset() { |
| .theme-reset { |
| $keys: (); |
| |
| @each $color-map in map.values($theme-colors) { |
| @each $key in map.keys($color-map) { |
| $keys: map.merge($keys, ($key: true)); |
| } |
| } |
| |
| @each $key in map.keys($keys) { |
| --theme-#{$key}: initial; |
| } |
| } |
| } |
| // scss-docs-end generate-theme-reset |
| |
| // Generate theme classes dynamically based on the keys in each theme color map |
| @mixin generate-theme-classes() { |
| @each $color-name, $color-map in $theme-colors { |
| .theme-#{$color-name} { |
| @each $key, $value in $color-map { |
| --theme-#{$key}: var(--#{$color-name}-#{$key}); |
| } |
| } |
| } |
| |
| @include generate-theme-reset(); |
| } |
| |
| // Theme maps use the `defaults()` pattern so `@use ... with (...)` merges custom |
| // values on top of the built-ins instead of replacing the whole map. Set a key |
| // to `null` to remove it. See scss/_config.scss for `defaults()`. |
| |
| // scss-docs-start theme-colors |
| $theme-colors: () !default; |
| // stylelint-disable-next-line scss/dollar-variable-default |
| $theme-colors: defaults( |
| ( |
| "primary": ( |
| "base": var(--blue-500), |
| "fg": light-dark(var(--blue-600), var(--blue-400)), |
| "fg-emphasis": light-dark(var(--blue-800), var(--blue-200)), |
| "bg": var(--blue-500), |
| "bg-subtle": light-dark(var(--blue-100), var(--blue-900)), |
| "bg-muted": light-dark(var(--blue-200), var(--blue-800)), |
| "border": light-dark(var(--blue-300), var(--blue-600)), |
| "focus-ring": light-dark(color-mix(in oklch, var(--blue-500) 50%, var(--bg-body)), color-mix(in oklch, var(--blue-500) 75%, var(--bg-body))), |
| "contrast": var(--white) |
| ), |
| "accent": ( |
| "base": var(--indigo-500), |
| "fg": light-dark(var(--indigo-600), color-mix(in oklch, var(--indigo-400), var(--indigo-300))), |
| "fg-emphasis": light-dark(var(--indigo-800), var(--indigo-300)), |
| "bg": var(--indigo-500), |
| "bg-subtle": light-dark(var(--indigo-100), var(--indigo-900)), |
| "bg-muted": light-dark(var(--indigo-200), var(--indigo-800)), |
| "border": light-dark(var(--indigo-300), var(--indigo-600)), |
| "focus-ring": light-dark(color-mix(in oklch, var(--indigo-500) 50%, var(--bg-body)), color-mix(in oklch, var(--indigo-500) 75%, var(--bg-body))), |
| "contrast": var(--white) |
| ), |
| "success": ( |
| "base": var(--green-500), |
| "fg": light-dark(var(--green-600), var(--green-400)), |
| "fg-emphasis": light-dark(var(--green-800), var(--green-300)), |
| "bg": var(--green-500), |
| "bg-subtle": light-dark(var(--green-100), var(--green-900)), |
| "bg-muted": light-dark(var(--green-200), var(--green-800)), |
| "border": light-dark(var(--green-300), var(--green-600)), |
| "focus-ring": light-dark(color-mix(in oklch, var(--green-500) 50%, var(--bg-body)), color-mix(in oklch, var(--green-500) 75%, var(--bg-body))), |
| "contrast": var(--white) |
| ), |
| "danger": ( |
| "base": var(--red-500), |
| "fg": light-dark(var(--red-600), var(--red-400)), |
| "fg-emphasis": light-dark(var(--red-800), var(--red-300)), |
| "bg": var(--red-500), |
| "bg-subtle": light-dark(var(--red-100), var(--red-900)), |
| "bg-muted": light-dark(var(--red-200), var(--red-800)), |
| "border": light-dark(var(--red-300), var(--red-600)), |
| "focus-ring": light-dark(color-mix(in oklch, var(--red-500) 50%, var(--bg-body)), color-mix(in oklch, var(--red-500) 75%, var(--bg-body))), |
| "contrast": var(--white) |
| ), |
| "warning": ( |
| "base": var(--yellow-500), |
| "fg": light-dark(var(--yellow-700), var(--yellow-400)), |
| "fg-emphasis": light-dark(var(--yellow-800), var(--yellow-300)), |
| "bg": var(--yellow-500), |
| "bg-subtle": light-dark(var(--yellow-100), var(--yellow-900)), |
| "bg-muted": light-dark(var(--yellow-200), var(--yellow-800)), |
| "border": light-dark(var(--yellow-300), var(--yellow-600)), |
| "focus-ring": light-dark(color-mix(in oklch, var(--yellow-500) 50%, var(--bg-body)), color-mix(in oklch, var(--yellow-400) 85%, var(--bg-body))), |
| "contrast": var(--gray-900) |
| ), |
| "info": ( |
| "base": var(--cyan-500), |
| "fg": light-dark(var(--cyan-600), var(--cyan-400)), |
| "fg-emphasis": light-dark(var(--cyan-800), var(--cyan-300)), |
| "bg": var(--cyan-500), |
| "bg-subtle": light-dark(var(--cyan-100), var(--cyan-900)), |
| "bg-muted": light-dark(var(--cyan-200), var(--cyan-800)), |
| "border": light-dark(var(--cyan-300), var(--cyan-600)), |
| "focus-ring": light-dark(color-mix(in oklch, var(--cyan-500) 50%, var(--bg-body)), color-mix(in oklch, var(--cyan-500) 75%, var(--bg-body))), |
| "contrast": var(--gray-900) |
| ), |
| "inverse": ( |
| "base": var(--gray-900), |
| "fg": light-dark(var(--gray-900), var(--gray-200)), |
| "fg-emphasis": light-dark(var(--gray-975), var(--white)), |
| "bg": light-dark(var(--gray-900), var(--gray-025)), |
| "bg-subtle": light-dark(var(--gray-100), var(--gray-900)), |
| "bg-muted": light-dark(var(--gray-200), var(--gray-300)), |
| "border": light-dark(var(--gray-400), var(--gray-100)), |
| "focus-ring": color-mix(in oklch, light-dark(var(--gray-900), var(--gray-100)) 50%, var(--bg-body)), |
| "contrast": light-dark(var(--white), var(--gray-900)) |
| ), |
| "secondary": ( |
| "base": var(--gray-200), |
| "fg": light-dark(var(--gray-600), var(--gray-400)), |
| "fg-emphasis": light-dark(var(--gray-800), var(--gray-200)), |
| "bg": light-dark(var(--gray-100), var(--gray-600)), |
| "bg-subtle": light-dark(var(--gray-050), var(--gray-800)), |
| "bg-muted": light-dark(var(--gray-100), var(--gray-700)), |
| "border": light-dark(var(--gray-300), var(--gray-600)), |
| "focus-ring": color-mix(in oklch, light-dark(var(--gray-500), var(--gray-300)) 50%, var(--bg-body)), |
| "contrast": light-dark(var(--gray-900), var(--white)) |
| ) |
| ), |
| $theme-colors |
| ); |
| // scss-docs-end theme-colors |
| |
| $theme-bgs: () !default; |
| // stylelint-disable-next-line scss/dollar-variable-default |
| $theme-bgs: defaults( |
| ( |
| "body": light-dark(var(--white), var(--gray-975)), |
| "1": light-dark(var(--gray-025), var(--gray-950)), |
| "2": light-dark(var(--gray-050), var(--gray-900)), |
| "3": light-dark(var(--gray-100), var(--gray-800)), |
| "4": light-dark(var(--gray-200), var(--gray-700)), |
| "fg": var(--fg-body), |
| "white": var(--white), |
| "black": var(--black), |
| "transparent": transparent, |
| "inherit": inherit, |
| ), |
| $theme-bgs |
| ); |
| |
| $theme-fgs: () !default; |
| // stylelint-disable-next-line scss/dollar-variable-default |
| $theme-fgs: defaults( |
| ( |
| "body": light-dark(var(--gray-900), var(--gray-050)), |
| "1": light-dark(var(--gray-800), var(--gray-200)), |
| "2": light-dark(var(--gray-700), var(--gray-300)), |
| "3": light-dark(var(--gray-600), var(--gray-500)), |
| "4": light-dark(var(--gray-500), var(--gray-600)), |
| "bg": var(--bg-body), |
| "white": var(--white), |
| "black": var(--black), |
| "inherit": inherit, |
| ), |
| $theme-fgs |
| ); |
| |
| $theme-borders: () !default; |
| // stylelint-disable-next-line scss/dollar-variable-default |
| $theme-borders: defaults( |
| ( |
| "bg": var(--bg-body), |
| "body": light-dark(var(--gray-300), var(--gray-800)), |
| "muted": light-dark(var(--gray-200), var(--gray-800)), |
| "subtle": light-dark(color-mix(in oklch, var(--gray-100), var(--gray-200)), color-mix(in oklch, var(--gray-800), var(--gray-900))), |
| "emphasized": light-dark(var(--gray-400), var(--gray-600)), |
| "white": var(--white), |
| "black": var(--black), |
| ), |
| $theme-borders |
| ); |
| |
| $util-opacity: () !default; |
| // stylelint-disable-next-line scss/dollar-variable-default |
| $util-opacity: defaults( |
| ( |
| 10: .1, |
| 20: .2, |
| 30: .3, |
| 40: .4, |
| 50: .5, |
| 60: .6, |
| 70: .7, |
| 80: .8, |
| 90: .9, |
| 100: 1 |
| ), |
| $util-opacity |
| ); |