Skip to content

uui-swatch: ability to overwrite displayed color with a css custom prop #649

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
{
"cSpell.words": ["combobox", "cssprop", "noopener", "noreferrer", "Umbraco"],
"cSpell.words": [
"combobox",
"cssprop",
"deselectable",
"noopener",
"noreferrer",
"Umbraco"
],
"npm.enableRunFromFolder": true
}
113 changes: 38 additions & 75 deletions packages/uui-color-swatch/lib/uui-color-swatch.element.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,54 @@
import { Colord } from 'colord';
import { defineElement } from '@umbraco-ui/uui-base/lib/registration';
import { property } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { css, html, LitElement, nothing } from 'lit';
import { iconCheck } from '@umbraco-ui/uui-icon-registry-essential/lib/svgs';

import { styleMap } from 'lit/directives/style-map.js';

import {
ActiveMixin,
LabelMixin,
SelectableMixin,
} from '@umbraco-ui/uui-base/lib/mixins';

/**
* Color swatch, can have label and be selectable. Depends on colord library and exposes it's utility functions under color property.
* Color swatch, can have label and be selectable.
*
* @element uui-color-swatch
* @cssprop --uui-swatch-size - The size of the swatch.
* @cssprop --uui-swatch-border-width - The width of the border.
* @cssprop --uui-swatch-color - The width of the border.
* @slot label - Default slot for the label.
*/
@defineElement('uui-color-swatch')
export class UUIColorSwatchElement extends LabelMixin(
'label',
SelectableMixin(ActiveMixin(LitElement))
) {
private _value: string | undefined = '';

/**
* Value of the swatch. Should be a valid hex, hexa, rgb, rgba, hsl or hsla string. Should fulfill this [css spec](https://www.w3.org/TR/css-color-4/#color-type). If not provided element will look at its text content.
*
* @attr
* Value of the swatch. This will become the color value if color is left undefined, see the property `color` for more details.
*/
@property()
get value(): string {
return this._value ? this._value : this.textContent?.trim() || '';
return this._value ?? '';
}

set value(newValue: string) {
const oldValue = this._value;
this._value = newValue;
this.requestUpdate('value', oldValue);
}
private _value?: string;

/**
* Color of the swatch. Should be a valid hex, hexa, rgb, rgba, hsl or hsla string. Should fulfill this [css spec](https://www.w3.org/TR/css-color-4/#color-type). If not provided element will look at its text content.
*/
@property()
get color(): string | undefined {
return this._color;
}
set color(newValue: string) {
const oldValue = this._color;
this._color = newValue;
this.requestUpdate('color', oldValue);
}
private _color?: string;

/**
* Determines if the options is disabled. If true the option can't be selected
Expand All @@ -58,62 +64,24 @@ export class UUIColorSwatchElement extends LabelMixin(
* @attr
* @memberof UUIColorSwatchElement
*/
@property({ type: Boolean, attribute: 'show-label' })
@property({ type: Boolean, attribute: 'show-label', reflect: true })
showLabel = false;
/**
* Colord object instance based on the value provided to the element. If the value is not a valid color, it falls back to black (like Amy Winehouse). For more information about Colord, see [Colord](https://omgovich.github.io/colord/)
*
* @memberof UUIColorSwatchElement
*/
get color(): Colord | null {
return this._color;
}

set color(_) {
// do nothing, this is just to prevent the color from being set from outside
return;
}
private _color: Colord | null = null;

/**
* Returns true if the color brightness is >= 0.5
*
* @readonly
* @memberof UUIColorSwatchElement
*/
get isLight() {
return this.color?.isLight() ?? false;
}

constructor() {
super();
this.addEventListener('click', this._setAriaAttributes);
}

private _initializeColor() {
this._color = new Colord(this.value ?? '');
if (!this._color.isValid()) {
this.disabled = true;
console.error(
`Invalid color provided to uui-color-swatch: ${this.value}`
);
}
}

private _setAriaAttributes() {
if (this.selectable)
this.setAttribute('aria-checked', this.selected.toString());
}

firstUpdated() {
this._initializeColor();
this._setAriaAttributes();
}

willUpdate(changedProperties: Map<string, any>) {
if (changedProperties.has('value')) {
this._initializeColor();
}
if (changedProperties.has('disabled')) {
if (this.selectable) {
this.selectable = !this.disabled;
Expand All @@ -135,17 +103,16 @@ export class UUIColorSwatchElement extends LabelMixin(
aria-label=${this.label}
aria-disabled="${this.disabled}"
title="${this.label}">
<div
class=${classMap({
'color-swatch': true,
'color-swatch--transparent-bg': true,
'color-swatch--light': this.isLight,
'color-swatch--big': this.showLabel,
})}>
<div class="color-swatch color-swatch--transparent-bg">
<div
class="color-swatch__color"
style=${styleMap({ backgroundColor: this.value })}></div>
<div class="color-swatch__check">${iconCheck}</div>
style="background-color: var(--uui-swatch-color, ${this.color ??
this.value})"></div>
<div
class="color-swatch__check"
style="fill: var(--uui-swatch-color, ${this.color ?? this.value})">
${iconCheck}
</div>
</div>
${this._renderWithLabel()}
</button>
Expand Down Expand Up @@ -222,7 +189,7 @@ export class UUIColorSwatchElement extends LabelMixin(
width: calc(100% + calc(var(--uui-swatch-border-width, 1px) * 2));
height: calc(100% + calc(var(--uui-swatch-border-width, 1px) * 2));
box-sizing: border-box;
border: var(--uui-swatch-border-width, 1px) solid
border: var(--uui-swatch-border-width, 2px) solid
var(--uui-color-selected);
border-radius: calc(
var(--uui-border-radius) + var(--uui-swatch-border-width, 1px)
Expand Down Expand Up @@ -250,7 +217,13 @@ export class UUIColorSwatchElement extends LabelMixin(
justify-content: center;
align-items: center;
}
.color-swatch--transparent-bg {

:host([show-label]) .color-swatch {
width: 120px;
height: 50px;
}

.color-swatch.color-swatch--transparent-bg {
background-image: linear-gradient(
45deg,
var(--uui-palette-grey) 25%,
Expand All @@ -270,7 +243,7 @@ export class UUIColorSwatchElement extends LabelMixin(
box-sizing: border-box;
}

.color-swatch--big .color-swatch__color {
:host([show-label]) .color-swatch__color {
border-radius: 3px 3px 0 0;
}

Expand All @@ -280,16 +253,11 @@ export class UUIColorSwatchElement extends LabelMixin(
width: calc(var(--uui-swatch-size, 25px) / 2);
height: calc(var(--uui-swatch-size, 25px) / 2);
line-height: 0;
transition: fill 120ms, opacity 120ms;
fill: #fff;
filter: invert(1) grayscale(1) contrast(9);
pointer-events: none;
opacity: 0;
}

.color-swatch--light .color-swatch__check {
fill: #000;
}

:host([selected]) .color-swatch__check {
opacity: 1;
}
Expand All @@ -299,11 +267,6 @@ export class UUIColorSwatchElement extends LabelMixin(
font-size: var(--uui-size-4);
}

.color-swatch--big {
width: 120px;
height: 50px;
}

.color-swatch__label {
max-width: 120px;
box-sizing: border-box;
Expand Down
19 changes: 16 additions & 3 deletions packages/uui-color-swatch/lib/uui-color-swatch.story.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ const meta: Meta<UUIColorSwatchElement> = {
},
argTypes: {
value: { control: 'color' },
color: { control: false },
isLight: { control: false },
color: { control: 'color' },
},
parameters: {
readme: {
Expand Down Expand Up @@ -94,9 +93,23 @@ export const WithLabel: Story = {
},
};

export const DifferentColorThanValue: Story = {
args: {
value: 'color1',
color: 'green',
},
parameters: {
docs: {
source: {
code: `<uui-color-swatch value="color1" color="green"></uui-color-slider>`,
},
},
},
};

export const Transparent: Story = {
args: {
value: 'rgba(53, 68, 177, 0.5)',
color: 'rgba(53, 68, 177, 0.5)',
},
parameters: {
docs: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export class UUIColorSwatchesElement extends LabelMixin('label', LitElement) {
swatch.setAttribute('selectable', 'selectable');
}

if (this.value !== '' && swatch.color?.isEqual(this.value)) {
if (this.value !== '' && swatch.value === this.value) {
swatch.selected = true;
swatch.setAttribute('aria-checked', 'true');
this._selectedElement = swatch;
Expand Down
4 changes: 2 additions & 2 deletions packages/uui-color-swatches/lib/uui-color-swatches.story.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ const Template: Story = {

return html`<uui-color-swatch
label="${label}"
.showLabel=${args.showLabel}>
${value}
.showLabel=${args.showLabel}
.value=${value}>
</uui-color-swatch>`;
})}
</uui-color-swatches>
Expand Down