Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export class UmbPropertyEditorUIColorPickerElement
@property({ type: Object })
public override set value(value: UmbSwatchDetails | undefined) {
super.value = value ? this.#ensureHashPrefix(value) : undefined;
this.#syncLabelFromSwatches();
}
public override get value(): UmbSwatchDetails | undefined {
return super.value;
Expand Down Expand Up @@ -49,6 +50,19 @@ export class UmbPropertyEditorUIColorPickerElement

const swatches = config?.getValueByAlias<Array<UmbSwatchDetails>>('items') ?? [];
this._swatches = swatches.map((swatch) => this.#ensureHashPrefix(swatch));
this.#syncLabelFromSwatches();
}

#syncLabelFromSwatches() {
if (!this.value || this._swatches.length === 0) return;
// Compare case-insensitively to match legacy/inconsistently-cased stored values (e.g. "#FF0000" vs "#ff0000").
const targetValue = this.value.value.toLowerCase();
const match = this._swatches.find((swatch) => swatch.value.toLowerCase() === targetValue);
if (match && match.label !== this.value.label) {
super.value = match;
// Dispatch outside of user interaction so the refreshed label is persisted on the next save.
this.dispatchEvent(new UmbChangeEvent());
}
Comment thread
AndyButland marked this conversation as resolved.
}
Comment thread
AndyButland marked this conversation as resolved.

#ensureHashPrefix(swatch: UmbSwatchDetails): UmbSwatchDetails {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { UmbPropertyEditorUIColorPickerElement } from './property-editor-ui-color-picker.element.js';
import { expect, fixture, html } from '@open-wc/testing';
import { type UmbTestRunnerWindow, defaultA11yConfig } from '@umbraco-cms/internal/test-utils';
import { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';

describe('UmbPropertyEditorUIColorPickerElement', () => {
let element: UmbPropertyEditorUIColorPickerElement;
Expand All @@ -13,6 +15,65 @@
expect(element).to.be.instanceOf(UmbPropertyEditorUIColorPickerElement);
});

describe('label sync', () => {
const swatches = [
{ value: '#28802a', label: 'Green' },
{ value: '#ff0000', label: 'Red' },
];

const configWith = (items: Array<{ value: string; label: string }>) =>
new UmbPropertyEditorConfigCollection([{ alias: 'items', value: items }]);

it('updates value.label and emits a single change event when config label differs from stored label', async () => {
let changeCount = 0;
element.addEventListener(UmbChangeEvent.TYPE, () => changeCount++);

element.config = configWith(swatches);
element.value = { value: '#28802a', label: 'Forest' };
await element.updateComplete;

expect(element.value?.label).to.equal('Green');
expect(element.value?.value).to.equal('#28802a');
expect(changeCount).to.equal(1);
});

Check warning on line 38 in src/Umbraco.Web.UI.Client/src/packages/property-editors/color-picker/property-editor-ui-color-picker.test.ts

View check run for this annotation

CodeScene Delta Analysis / CodeScene Code Health Review (main)

❌ New issue: Code Duplication

The module contains 4 functions with similar structure: 'does not emit a change event when labels already match','does not emit a change event when no swatch matches the stored value','refreshes a stale label even when the stored hex casing differs from the swatch','updates value.label and emits a single change event when config label differs from stored label'. Avoid duplicated, aka copy-pasted, code inside the module. More duplication lowers the code health.

it('refreshes a stale label even when the stored hex casing differs from the swatch', async () => {
let changeCount = 0;
element.addEventListener(UmbChangeEvent.TYPE, () => changeCount++);

element.config = configWith(swatches);
element.value = { value: '#28802A', label: 'Forest' };
await element.updateComplete;

expect(element.value?.label).to.equal('Green');
expect(changeCount).to.equal(1);
});

it('does not emit a change event when labels already match', async () => {
let changeCount = 0;
element.addEventListener(UmbChangeEvent.TYPE, () => changeCount++);

element.config = configWith(swatches);
element.value = { value: '#28802a', label: 'Green' };
await element.updateComplete;

expect(element.value?.label).to.equal('Green');
expect(changeCount).to.equal(0);
});

it('does not emit a change event when no swatch matches the stored value', async () => {
let changeCount = 0;
element.addEventListener(UmbChangeEvent.TYPE, () => changeCount++);

element.config = configWith(swatches);
element.value = { value: '#000000', label: 'Black' };
await element.updateComplete;

expect(element.value?.label).to.equal('Black');
expect(changeCount).to.equal(0);
});
});

if ((window as UmbTestRunnerWindow).__UMBRACO_TEST_RUN_A11Y_TEST) {
it('passes the a11y audit', async () => {
await expect(element).shadowDom.to.be.accessible(defaultA11yConfig);
Expand Down
Loading