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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Setting `min` or `max` with a value before the first render no longer throws a `TypeError`.
- #### Color picker
- The HSL saturation no longer becomes infinite for a very small saturation at full value.
- The initial `value` is now in the notation of `format` when the `value` attribute comes before the `format` attribute. Before, `value` and the form data stayed in hex until the color changed.
- #### Virtual scroll
- `layoutComplete` now resolves after the rendered items are measured. Before, it could resolve first, so `scrollToIndex` stopped its correction early, and an item with a size other than the estimate landed up to tens of pixels from the requested edge.
- A list larger than the maximum scroll size of the browser now shows its last items at the end of the scroll range, and `scrollToIndex` puts the item at the requested edge. The items also move evenly during a scroll. Before, the last items could not be reached, the item landed tens of pixels off, and the items jumped by some pixels each time the rendered window changed.
Expand Down
50 changes: 50 additions & 0 deletions src/components/color-picker/color-picker.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1313,6 +1313,56 @@ describe('Color picker', () => {
});
});

describe('Initial format', () => {
const rgb = 'rgb(186 218 85)';

it('serializes a value attribute that comes before the format attribute', async () => {
picker = await fixture<IgcColorPickerComponent>(
html`<igc-color-picker value="#bada55" format="rgb"></igc-color-picker>`
);

expect(picker.value).to.equal(rgb);
});

it('serializes a value attribute that comes after the format attribute', async () => {
picker = await fixture<IgcColorPickerComponent>(
html`<igc-color-picker format="rgb" value="#bada55"></igc-color-picker>`
);

expect(picker.value).to.equal(rgb);
});

describe('with a default value set before the format', () => {
const spec = createFormAssociatedTestBed<IgcColorPickerComponent>(html`
<igc-color-picker
name="color-picker"
.defaultValue=${'#bada55'}
format=${'rgb'}
></igc-color-picker>
`);

beforeEach(async () => {
await spec.setup(IgcColorPickerComponent.tagName);
});

it('stays pristine', () => {
spec.assertIsPristine();
expect(spec.element.value).to.equal(rgb);
});

it('submits the value in the format', () => {
spec.assertSubmitHasValue(rgb);
});

it('restores the value in the format on form reset', () => {
spec.setProperties({ value: '#ff0000' });

spec.reset();
expect(spec.element.value).to.equal(rgb);
});
});
});

describe('Validation', () => {
const spec = createFormAssociatedTestBed<IgcColorPickerComponent>(html`
<igc-color-picker name="color-picker"></igc-color-picker>
Expand Down
20 changes: 18 additions & 2 deletions src/components/color-picker/color-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,8 +347,8 @@ export default class IgcColorPickerComponent extends FormAssociatedRequiredMixin
this._rootClickController.update();
}

if (this.hasUpdated && props.has('format')) {
this._formValue.setValueAndFormState(this._color.asString(this.format));
if (props.has('format')) {
this._serializeInFormat();
}

this._applyColorProperties();
Expand Down Expand Up @@ -682,6 +682,22 @@ export default class IgcColorPickerComponent extends FormAssociatedRequiredMixin
this.requestUpdate();
}

/**
* Renders the current color in the active format.
*
* The `value` attribute can come before `format`, so the first update also
* runs this. The color does not change, so the pristine state stays.
*/
private _serializeInFormat(): void {
const value = this._color.asString(this.format);

if (value !== this.value) {
const pristine = this._pristine;
this._formValue.setValueAndFormState(value);
this._pristine = pristine;
}
}

private _syncCanvasPosition(): void {
if (!this._canvasRef.value || !this.open) return;

Expand Down
7 changes: 5 additions & 2 deletions src/components/color-picker/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
| 2 | 2026-09-24 | Describe the naming order and the host ARIA naming |
| 3 | 2026-09-24 | Keep `aria-expanded` off the input mode text input |
| 4 | 2026-09-28 | Add the property-based color suite |
| 5 | 2026-09-30 | Serialize the initial value in the declared format |

## Overview

Expand Down Expand Up @@ -185,7 +186,9 @@ and HSV representations plus an alpha channel. An empty, whitespace-only or inva
rather than a stale color; while empty, the anchor renders a checkered background and the serialized value is `''`.

The active `format` determines how the color is re-serialized into the observable `value`. Changing `format`
re-serializes the existing color without altering it, so no `igcInput` or `igcChange` is emitted.
re-serializes the existing color without altering it, so no `igcInput` or `igcChange` is emitted. The initial value
is serialized in the declared `format` whatever the attribute order, and the re-serialization keeps the pristine
state of the control.

#### The picker surface

Expand Down Expand Up @@ -403,7 +406,7 @@ The component suite reuses `createFormAssociatedTestBed`, `runValidationContaine
11. Open and close - the pointer, keyboard and outside-click paths.
12. Input mode - the anchor input, its label and its prefix.
13. Rendering of the picker surface rows.
14. Form association, the touched state, `defaultValue`, and validation.
14. Form association, the touched state, `defaultValue`, the initial format, and validation.
15. Validation message slots, generated by `runValidationContainerTests`.
16. External label association and ARIA projection, generated by `runExternalLabelAssociationTests` and
`runAriaProjectionTests`.
Expand Down
Loading