From 70f70628252740a7afa0674163c4bf5c4d2ae70e Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Sun, 19 Oct 2025 13:47:56 +0200 Subject: [PATCH 1/8] Add brand color and used on Umbraco backoffice --- .../lib/uui-color-swatches.story.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/uui-color-swatches/lib/uui-color-swatches.story.ts b/packages/uui-color-swatches/lib/uui-color-swatches.story.ts index f83451968..a95247645 100644 --- a/packages/uui-color-swatches/lib/uui-color-swatches.story.ts +++ b/packages/uui-color-swatches/lib/uui-color-swatches.story.ts @@ -6,9 +6,15 @@ import { spread } from '../../../storyhelpers'; import { repeat } from 'lit/directives/repeat.js'; const swatches = [ - { label: 'Blood Orange', value: '#d0021b' }, - { label: 'Avocado', value: '#417505' }, - { label: 'Tufts Blue', value: '#4a90e2' }, + { label: 'Black', value: '#060606' }, + { label: 'Sunglow', value: '#fad634' }, + { label: 'Spanish Pink', value: '#f5c1bc' }, + { label: 'Violet Blue', value: '#3544b1' }, + { label: 'Malibu', value: '#3879ff' }, + { label: 'Maroon Flush', value: '#d42054' }, + { label: 'Jungle Green', value: '#2bc37c' }, + { label: 'Chamoisee', value: '#9d8057' }, + { label: 'Dusty Grey', value: '#9b9b9b' }, ]; const gradients = [ From d898eba90d43c82fe79f22b7b631d4774fee65bc Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Sun, 19 Oct 2025 13:56:51 +0200 Subject: [PATCH 2/8] Check contrast color for hex colors --- .../lib/uui-color-swatch.element.ts | 54 +++++++++++++++++-- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/packages/uui-color-swatch/lib/uui-color-swatch.element.ts b/packages/uui-color-swatch/lib/uui-color-swatch.element.ts index f14668652..b76c2e59c 100644 --- a/packages/uui-color-swatch/lib/uui-color-swatch.element.ts +++ b/packages/uui-color-swatch/lib/uui-color-swatch.element.ts @@ -1,7 +1,8 @@ import { defineElement } from '@umbraco-ui/uui-base/lib/registration'; -import { property } from 'lit/decorators.js'; +import { property, state } from 'lit/decorators.js'; import { css, html, LitElement, nothing } from 'lit'; import { ref } from 'lit/directives/ref.js'; +import { ifDefined } from 'lit/directives/if-defined.js'; import { iconCheck } from '@umbraco-ui/uui-icon-registry-essential/lib/svgs'; import { ActiveMixin, @@ -23,6 +24,9 @@ export class UUIColorSwatchElement extends LabelMixin( 'label', SelectableMixin(ActiveMixin(LitElement)), ) { + @state() + private _contrast: 'dark' | 'light' | undefined = undefined; + /** * Value of the swatch. This will become the color value if color is left undefined, see the property `color` for more details. */ @@ -90,6 +94,11 @@ export class UUIColorSwatchElement extends LabelMixin( firstUpdated() { this._setAriaAttributes(); + + const color = this.color ?? this.value; + if (color.startsWith('#')) { + this._contrast = this.#contrast(color) === 'light' ? 'light' : 'dark'; + } } willUpdate(changedProperties: Map) { @@ -118,6 +127,27 @@ export class UUIColorSwatchElement extends LabelMixin( this.selectableTarget = button || this; } + #contrast(hex: string): string { + const rgb = this.#hexToRgb(hex); + const o = Math.round((rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000); + + return o <= 180 ? 'dark' : 'light'; + } + + #hexToRgb(hex: string): number[] { + hex = hex.startsWith('#') ? hex.slice(1) : hex; + if (hex.length === 3) { + hex = Array.from(hex).reduce((str, x) => str + x + x, ''); // 123 -> 112233 + } + + const bigint = parseInt(hex, 16); + const r = (bigint >> 16) & 255; + const g = (bigint >> 8) & 255; + const b = bigint & 255; + + return [r, g, b]; + } + render() { return html`