From 9b25ed0d7004249bbb5a8b10670658ba0ae8cd82 Mon Sep 17 00:00:00 2001 From: Brandy Smith <6577830+brandyscarney@users.noreply.github.com> Date: Wed, 26 Mar 2025 10:00:14 -0400 Subject: [PATCH 01/25] feat(css): add support for the subtle color map --- core/src/themes/functions.color.scss | 172 +++++++++++--- .../src/themes/ionic/ionic.theme.default.scss | 209 +++++++++++++----- core/src/themes/ionic/test/colors/index.html | 10 +- .../themes/native/native.theme.default.scss | 109 ++++++--- 4 files changed, 371 insertions(+), 129 deletions(-) diff --git a/core/src/themes/functions.color.scss b/core/src/themes/functions.color.scss index 702bdf0bcf4..62d1148b02e 100644 --- a/core/src/themes/functions.color.scss +++ b/core/src/themes/functions.color.scss @@ -1,3 +1,5 @@ +@use "sass:map"; + // Set the theme colors map to be used by the color functions // -------------------------------------------------------------------------------------------- @mixin set-theme-colors($colorsMap) { @@ -10,11 +12,13 @@ // current-color(base) => var(--ion-color-base) // current-color(contrast, 0.1) => rgba(var(--ion-color-contrast-rgb), 0.1) // -------------------------------------------------------------------------------------------- -@function current-color($variation, $alpha: null) { +@function current-color($variation, $alpha: null, $subtle: false) { + $variable: if($subtle, "--ion-color-subtle-#{$variation}", "--ion-color-#{$variation}"); + @if $alpha == null { - @return var(--ion-color-#{$variation}); + @return var(#{$variable}); } @else { - @return rgba(var(--ion-color-#{$variation}-rgb), #{$alpha}); + @return rgba(var(#{$variable}-rgb), #{$alpha}); } } @@ -25,17 +29,25 @@ // ion-color(secondary, contrast) => var(--ion-color-secondary-contrast) // ion-color(primary, base, 0.5) => rgba(var(--ion-color-primary-rgb, 56, 128, 255), 0.5) // -------------------------------------------------------------------------------------------- -@function ion-color($name, $variation, $alpha: null, $rgb: null) { +@function ion-color($name, $variation, $alpha: null, $rgb: null, $subtle: false) { @if not($theme-colors) { @error 'No theme colors set. Please make sure to call set-theme-colors($colorsMap) before using ion-color()'; } - $values: map-get($theme-colors, $name); - $value: map-get($values, $variation); - $variable: --ion-color-#{$name}-#{$variation}; + $values: map.get($theme-colors, $name); + $values: map.get($values, if($subtle, subtle, bold)); + + $value: map.get($values, $variation); + + // If the color requested is subtle we return `--ion-color-primary-subtle-contrast` + // Otherwise we return `--ion-color-primary-contrast` + $variable: if($subtle, "--ion-color-#{$name}-subtle-#{$variation}", "--ion-color-#{$name}-#{$variation}"); + // If the variation being used is base, we do not include the variant so + // If the color requested is subtle we return `--ion-color-primary-subtle` + // Otherwise we return `--ion-color-primary` @if ($variation == base) { - $variable: --ion-color-#{$name}; + $variable: if($subtle, "--ion-color-#{$name}-subtle", "--ion-color-#{$name}"); } @if ($alpha) { @@ -79,43 +91,139 @@ @return #{red($color)}, #{green($color)}, #{blue($color)}; } -// Generates the color classes and variables -// based on the colors map +// Generates color variants for the specified color based on the +// colors map for whichever hue is passed (bold, subtle). // -------------------------------------------------------------------------------------------- -@mixin generate-color($color-name) { +// Example usage (bold): +// .ion-color-primary { +// @include generate-color-variants("primary"); +// } +// +// Example output (bold): +// .ion-color-primary { +// --ion-color-base: var(--ion-color-primary-base, #105cef) !important; +// --ion-color-base-rgb: var(--ion-color-primary-base-rgb, 16, 92, 239) !important; +// --ion-color-contrast: var(--ion-color-primary-contrast, #fff) !important; +// --ion-color-contrast-rgb: var(--ion-color-primary-contrast-rgb, 255, 255, 255) !important; +// --ion-color-shade: var(--ion-color-primary-shade, #0f54da) !important; +// --ion-color-tint: var(--ion-color-primary-tint, #94a5f4) !important; +// } +// -------------------------------------------------------------------------------------------- +// Example usage (subtle): +// .ion-color-primary { +// @include generate-color-variants("primary", "subtle") +// } +// +// Example output (subtle): +// .ion-color-primary { +// --ion-color-subtle-base: var(--ion-color-primary-subtle-base, #f2f4fd) !important; +// --ion-color-subtle-base-rgb: var(--ion-color-primary-subtle-base-rgb, 242, 244, 253) !important; +// --ion-color-subtle-contrast: var(--ion-color-primary-subtle-contrast, #105cef) !important; +// --ion-color-subtle-contrast-rgb: var(--ion-color-primary-subtle-contrast-rgb, 16, 92, 239) !important; +// --ion-color-subtle-shade: var(--ion-color-primary-subtle-shade, #d0d7fa) !important; +// --ion-color-subtle-tint: var(--ion-color-primary-subtle-tint, #e9ecfc) !important; +// } +// -------------------------------------------------------------------------------------------- +@mixin generate-color-variants($color-name, $hue: "bold") { @if not($theme-colors) { @error 'No theme colors set. Please make sure to call set-theme-colors($colorsMap) before using ion-color()'; } - $value: map-get($theme-colors, $color-name); - - $base: map-get($value, base); - $contrast: map-get($value, contrast); - $shade: map-get($value, shade); - $tint: map-get($value, tint); + // Grab the different hue color maps for the + // specified color and then grab the map of color variants + $hue-colors: map.get($theme-colors, $color-name); + $color-variants: map.get($hue-colors, $hue); + + // Determine prefix based on hue value + $prefix: if($hue == "subtle", "-subtle", ""); + + // TODO this @if can be removed if we add subtle colors for ios and md + // Only proceed if the color variants exist + @if $color-variants { + // Grab the individual color variants + $base: map.get($color-variants, base); + $base-rgb: map.get($color-variants, base-rgb); + $contrast: map.get($color-variants, contrast); + $contrast-rgb: map.get($color-variants, contrast-rgb); + $shade: map.get($color-variants, shade); + $tint: map.get($color-variants, tint); + + // Generate CSS variables dynamically + --ion-color#{$prefix}-base: var(--ion-color-#{$color-name}#{$prefix}, #{$base}) !important; + --ion-color#{$prefix}-base-rgb: var(--ion-color-#{$color-name}#{$prefix}-rgb, #{$base-rgb}) !important; + --ion-color#{$prefix}-contrast: var(--ion-color-#{$color-name}#{$prefix}-contrast, #{$contrast}) !important; + --ion-color#{$prefix}-contrast-rgb: var( + --ion-color-#{$color-name}#{$prefix}-contrast-rgb, + #{$contrast-rgb} + ) !important; + --ion-color#{$prefix}-shade: var(--ion-color-#{$color-name}#{$prefix}-shade, #{$shade}) !important; + --ion-color#{$prefix}-tint: var(--ion-color-#{$color-name}#{$prefix}-tint, #{$tint}) !important; + } +} - --ion-color-base: var(--ion-color-#{$color-name}, #{$base}) !important; - --ion-color-base-rgb: var(--ion-color-#{$color-name}-rgb, #{color-to-rgb-list($base)}) !important; - --ion-color-contrast: var(--ion-color-#{$color-name}-contrast, #{$contrast}) !important; - --ion-color-contrast-rgb: var(--ion-color-#{$color-name}-contrast-rgb, #{color-to-rgb-list($contrast)}) !important; - --ion-color-shade: var(--ion-color-#{$color-name}-shade, #{$shade}) !important; - --ion-color-tint: var(--ion-color-#{$color-name}-tint, #{$tint}) !important; +// Generates both bold and subtle color variables +// for the specified color in the colors map. +// -------------------------------------------------------------------------------------------- +@mixin generate-color($color-name) { + @include generate-color-variants($color-name); + @include generate-color-variants($color-name, "subtle"); } -// Generates the CSS variables for each color -// based on the colors map +// Generates color variables for all colors in the colors map for both hues (bold, subtle). +// -------------------------------------------------------------------------------------------- +// Example usage: +// :root { +// generate-color-variables() +// } +// +// Example output: +// :root { +// --ion-color-primary: #105cef; +// --ion-color-primary-rgb: 16, 92, 239; +// --ion-color-primary-contrast: #ffffff; +// --ion-color-primary-contrast-rgb: 255, 255, 255; +// --ion-color-primary-shade: #0f54da; +// --ion-color-primary-tint: #94a5f4; +// --ion-color-primary-subtle: #f2f4fd; +// --ion-color-primary-subtle-rgb: 242, 244, 253; +// --ion-color-primary-subtle-contrast: #105cef; +// --ion-color-primary-subtle-contrast-rgb: 16, 92, 239; +// --ion-color-primary-subtle-shade: #d0d7fa; +// --ion-color-primary-subtle-tint: #e9ecfc; +// ... +// --ion-color-dark: #292929; +// --ion-color-dark-rgb: 41, 41, 41; +// --ion-color-dark-contrast: #ffffff; +// --ion-color-dark-contrast-rgb: 255, 255, 255; +// --ion-color-dark-shade: #242424; +// --ion-color-dark-tint: #4e4e4e; +// --ion-color-dark-subtle: #f5f5f5; +// --ion-color-dark-subtle-rgb: 245, 245, 245; +// --ion-color-dark-subtle-contrast: #292929; +// --ion-color-dark-subtle-contrast-rgb: 41, 41, 41; +// --ion-color-dark-subtle-shade: #e0e0e0; +// --ion-color-dark-subtle-tint: #efefef; +// } // -------------------------------------------------------------------------------------------- @mixin generate-color-variables() { @if not($theme-colors) { - @error 'No theme colors set. Please make sure to call set-theme-colors($colorsMap) before using ion-color()'; + @error 'No theme colors set. Please make sure to call set-theme-colors($colorsMap) before using ion-color().'; } @each $color-name, $value in $theme-colors { - --ion-color-#{$color-name}: #{map-get($value, base)}; - --ion-color-#{$color-name}-rgb: #{color-to-rgb-list(map-get($value, base))}; - --ion-color-#{$color-name}-contrast: #{map-get($value, contrast)}; - --ion-color-#{$color-name}-contrast-rgb: #{color-to-rgb-list(map-get($value, contrast))}; - --ion-color-#{$color-name}-shade: #{map-get($value, shade)}; - --ion-color-#{$color-name}-tint: #{map-get($value, tint)}; + @each $hue in (bold, subtle) { + $colors: map.get($value, $hue); + + @if $colors != null { + $prefix: if($hue == subtle, "-subtle", ""); + + --ion-color-#{$color-name}#{$prefix}: #{map.get($colors, base)}; + --ion-color-#{$color-name}#{$prefix}-rgb: #{map.get($colors, base-rgb)}; + --ion-color-#{$color-name}#{$prefix}-contrast: #{map.get($colors, contrast)}; + --ion-color-#{$color-name}#{$prefix}-contrast-rgb: #{map.get($colors, contrast-rgb)}; + --ion-color-#{$color-name}#{$prefix}-shade: #{map.get($colors, shade)}; + --ion-color-#{$color-name}#{$prefix}-tint: #{map.get($colors, tint)}; + } + } } } diff --git a/core/src/themes/ionic/ionic.theme.default.scss b/core/src/themes/ionic/ionic.theme.default.scss index cd702ae9842..2d77e7a25da 100644 --- a/core/src/themes/ionic/ionic.theme.default.scss +++ b/core/src/themes/ionic/ionic.theme.default.scss @@ -10,84 +10,181 @@ // Default Ionic Colors // ------------------------------------------------------------------------------------------- // Color map should provide -// - base: main color to be used. +// - bold: a map of the bold color variations +// - subtle: a map of the subtle color variations +// +// Each hue color map should provide +// - base: Color that will be primarily used +// - base-rgb: The base color in rgb format // - contrast: Color that will provide readable text against the base color -// - shade: 12% darker version of the base color (mix with black) -// - tint: 10% lighter version of the base color (mix with white) +// - contrast-rgb: The contrast color in rgb format +// - shade: Darker version of the base color +// - tint: Lighter version of the base color // TODO(ROU-10778, ROU-10875): Sync the color names to the design system of // ios and md. This will allow us to have a single color map. -$primary: #105cef; -$secondary: initial; -$tertiary: initial; -$success: #1fbd3b; -$warning: #e18300; -$danger: #bf2222; -$light: #f2f4fd; -$medium: initial; -$neutral: #626262; -$dark: initial; - $ionic-colors: ( primary: ( - base: $primary, - contrast: #fff, - shade: color.get-color-shade($primary), - tint: color.get-color-tint($primary), + bold: ( + base: globals.$ion-semantics-primary-base, + base-rgb: globals.$ion-semantics-primary-base-rgb, + contrast: globals.$ion-primitives-base-white, + contrast-rgb: globals.$ion-primitives-base-white-rgb, + shade: globals.$ion-semantics-primary-800, + tint: globals.$ion-semantics-primary-500, + ), + subtle: ( + base: globals.$ion-semantics-primary-100, + base-rgb: globals.$ion-semantics-primary-100-rgb, + contrast: globals.$ion-semantics-primary-base, + contrast-rgb: globals.$ion-semantics-primary-base-rgb, + shade: globals.$ion-semantics-primary-300, + tint: globals.$ion-semantics-primary-200, + ), ), secondary: ( - base: $secondary, - contrast: $secondary, - shade: color.get-color-shade($secondary), - tint: color.get-color-tint($secondary), + bold: ( + base: globals.$ion-semantics-info-base, + base-rgb: globals.$ion-semantics-info-base-rgb, + contrast: globals.$ion-primitives-base-white, + contrast-rgb: globals.$ion-primitives-base-white-rgb, + shade: globals.$ion-semantics-info-800, + tint: globals.$ion-semantics-info-500, + ), + subtle: ( + base: globals.$ion-semantics-info-100, + base-rgb: globals.$ion-semantics-info-100-rgb, + contrast: globals.$ion-semantics-info-base, + contrast-rgb: globals.$ion-semantics-info-base-rgb, + shade: globals.$ion-semantics-info-300, + tint: globals.$ion-semantics-info-200, + ), ), tertiary: ( - base: $tertiary, - contrast: $tertiary, - shade: color.get-color-shade($tertiary), - tint: color.get-color-tint($tertiary), + bold: ( + base: globals.$ion-primitives-violet-700, + base-rgb: globals.$ion-primitives-violet-700-rgb, + contrast: globals.$ion-primitives-base-white, + contrast-rgb: globals.$ion-primitives-base-white-rgb, + shade: globals.$ion-primitives-violet-800, + tint: globals.$ion-primitives-violet-500, + ), + subtle: ( + base: globals.$ion-primitives-violet-100, + base-rgb: globals.$ion-primitives-violet-100-rgb, + contrast: globals.$ion-primitives-violet-700, + contrast-rgb: globals.$ion-primitives-violet-700-rgb, + shade: globals.$ion-primitives-violet-300, + tint: globals.$ion-primitives-violet-200, + ), ), success: ( - base: $success, - contrast: #000, - shade: color.get-color-shade($success), - tint: color.get-color-tint($success), + bold: ( + base: globals.$ion-semantics-success-base, + base-rgb: globals.$ion-semantics-success-base-rgb, + contrast: globals.$ion-primitives-base-white, + contrast-rgb: globals.$ion-primitives-base-white-rgb, + shade: globals.$ion-semantics-success-800, + tint: globals.$ion-semantics-success-500, + ), + subtle: ( + base: globals.$ion-semantics-success-100, + base-rgb: globals.$ion-semantics-success-100-rgb, + contrast: globals.$ion-semantics-success-base, + contrast-rgb: globals.$ion-semantics-success-base-rgb, + shade: globals.$ion-semantics-success-300, + tint: globals.$ion-semantics-success-200, + ), ), warning: ( - base: $warning, - contrast: #000, - shade: color.get-color-shade($warning), - tint: color.get-color-tint($warning), + bold: ( + base: globals.$ion-semantics-warning-base, + base-rgb: globals.$ion-semantics-warning-base-rgb, + contrast: globals.$ion-primitives-base-white, + contrast-rgb: globals.$ion-primitives-base-white-rgb, + shade: globals.$ion-semantics-warning-800, + tint: globals.$ion-semantics-warning-500, + ), + subtle: ( + base: globals.$ion-semantics-warning-100, + base-rgb: globals.$ion-semantics-warning-100-rgb, + contrast: globals.$ion-semantics-warning-base, + contrast-rgb: globals.$ion-semantics-warning-base-rgb, + shade: globals.$ion-semantics-warning-300, + tint: globals.$ion-semantics-warning-200, + ), ), danger: ( - base: $danger, - contrast: #fff, - shade: color.get-color-shade($danger), - tint: color.get-color-tint($danger), + bold: ( + base: globals.$ion-semantics-danger-base, + base-rgb: globals.$ion-semantics-danger-base-rgb, + contrast: globals.$ion-primitives-base-white, + contrast-rgb: globals.$ion-primitives-base-white-rgb, + shade: globals.$ion-semantics-danger-800, + tint: globals.$ion-semantics-danger-500, + ), + subtle: ( + base: globals.$ion-semantics-danger-100, + base-rgb: globals.$ion-semantics-danger-100-rgb, + contrast: globals.$ion-semantics-danger-base, + contrast-rgb: globals.$ion-semantics-danger-base-rgb, + shade: globals.$ion-semantics-danger-300, + tint: globals.$ion-semantics-danger-200, + ), ), light: ( - base: $light, - contrast: #000, - shade: color.get-color-shade($light), - tint: color.get-color-tint($light), + bold: ( + base: globals.$ion-primitives-neutral-200, + base-rgb: globals.$ion-primitives-neutral-200-rgb, + contrast: globals.$ion-primitives-base-black, + contrast-rgb: globals.$ion-primitives-base-black-rgb, + shade: globals.$ion-primitives-neutral-300, + tint: globals.$ion-primitives-neutral-100, + ), + subtle: ( + base: globals.$ion-primitives-neutral-100, + base-rgb: globals.$ion-primitives-neutral-100-rgb, + contrast: globals.$ion-primitives-neutral-700, + contrast-rgb: globals.$ion-primitives-neutral-700-rgb, + shade: globals.$ion-primitives-neutral-300, + tint: globals.$ion-primitives-neutral-200, + ), ), medium: ( - base: $medium, - contrast: $medium, - shade: color.get-color-shade($medium), - tint: color.get-color-tint($medium), - ), - neutral: ( - base: $neutral, - contrast: #fff, - shade: color.get-color-shade($neutral), - tint: color.get-color-tint($neutral), + bold: ( + base: globals.$ion-primitives-neutral-700, + base-rgb: globals.$ion-primitives-neutral-700-rgb, + contrast: globals.$ion-primitives-base-white, + contrast-rgb: globals.$ion-primitives-base-white-rgb, + shade: globals.$ion-primitives-neutral-800, + tint: globals.$ion-primitives-neutral-500, + ), + subtle: ( + base: globals.$ion-primitives-neutral-100, + base-rgb: globals.$ion-primitives-neutral-100-rgb, + contrast: globals.$ion-primitives-neutral-700, + contrast-rgb: globals.$ion-primitives-neutral-700-rgb, + shade: globals.$ion-primitives-neutral-300, + tint: globals.$ion-primitives-neutral-200, + ), ), dark: ( - base: $dark, - contrast: $dark, - shade: color.get-color-shade($dark), - tint: color.get-color-tint($dark), + bold: ( + base: globals.$ion-primitives-neutral-1100, + base-rgb: globals.$ion-primitives-neutral-1100-rgb, + contrast: globals.$ion-primitives-base-white, + contrast-rgb: globals.$ion-primitives-base-white-rgb, + shade: globals.$ion-primitives-neutral-1200, + tint: globals.$ion-primitives-neutral-900, + ), + subtle: ( + base: globals.$ion-primitives-neutral-100, + base-rgb: globals.$ion-primitives-neutral-100-rgb, + contrast: globals.$ion-primitives-neutral-1100, + contrast-rgb: globals.$ion-primitives-neutral-1100-rgb, + shade: globals.$ion-primitives-neutral-300, + tint: globals.$ion-primitives-neutral-200, + ), ), ); diff --git a/core/src/themes/ionic/test/colors/index.html b/core/src/themes/ionic/test/colors/index.html index 5f990e1fe12..759bfee4ac4 100644 --- a/core/src/themes/ionic/test/colors/index.html +++ b/core/src/themes/ionic/test/colors/index.html @@ -7,11 +7,11 @@ name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" /> - - - - - + + + + +