Skip to content

Commit 3cdf1bf

Browse files
committed
Fix input-color
Refs: #7164
1 parent 2e99c31 commit 3cdf1bf

File tree

7 files changed

+135
-194
lines changed

7 files changed

+135
-194
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,69 @@
1-
import { test } from '@stencil/playwright';
1+
import { type E2EPage, test } from '@stencil/playwright';
22
import { testInputCallbacksAndEvents, testInputValueReflection } from '../../e2e';
3-
3+
import type { FillAction } from '../../e2e/utils/FillAction';
4+
import type { Page } from '@playwright/test';
5+
import { expect } from '@playwright/test';
6+
import { KolEvent } from '../../utils/events';
47
const COMPONENT_NAME = 'kol-input-color';
58
const TEST_VALUE = '#cc006e';
6-
9+
const NEW_VALUE = '#00ccff';
10+
const fillAction: FillAction = async (page) => {
11+
const textInput = page.locator('input[type="text"]');
12+
await textInput.fill(TEST_VALUE);
13+
await textInput.dispatchEvent('input');
14+
};
15+
const selectTextInput = (page: Page & E2EPage) => page.locator('input[type="text"]');
16+
const selectColorInput = (page: Page & E2EPage) => page.locator('input[type="color"]');
717
test.describe(COMPONENT_NAME, () => {
8-
testInputValueReflection<HTMLKolInputColorElement>(COMPONENT_NAME, TEST_VALUE);
9-
testInputCallbacksAndEvents<HTMLKolInputColorElement>(COMPONENT_NAME, TEST_VALUE);
18+
testInputValueReflection<HTMLKolInputColorElement>(COMPONENT_NAME, TEST_VALUE, fillAction);
19+
testInputCallbacksAndEvents<HTMLKolInputColorElement>(COMPONENT_NAME, TEST_VALUE, fillAction, ['input'], undefined, selectTextInput);
20+
test('should sync value between color input and text input', async ({ page }) => {
21+
await page.setContent(`<${COMPONENT_NAME} _label="Color Picker"></${COMPONENT_NAME}>`);
22+
const colorInput = selectColorInput(page);
23+
const textInput = selectTextInput(page);
24+
await colorInput.fill(TEST_VALUE);
25+
await expect(textInput).toHaveValue(TEST_VALUE);
26+
await textInput.fill(NEW_VALUE);
27+
await expect(colorInput).toHaveValue(NEW_VALUE);
28+
});
29+
test.describe('Callbacks', () => {
30+
test(`should call onChange callback when internal input emits`, async ({ page }) => {
31+
await page.setContent(`<${COMPONENT_NAME} _label="Color Picker"></${COMPONENT_NAME}>`);
32+
const component = page.locator(COMPONENT_NAME);
33+
const textInput = selectTextInput(page);
34+
const callbackPromise = component.evaluate((element: HTMLKolInputColorElement) => {
35+
return new Promise<unknown>((resolve) => {
36+
element._on = {
37+
onChange: (_event: Event, value?: unknown) => {
38+
resolve(value);
39+
},
40+
};
41+
});
42+
});
43+
await page.waitForChanges();
44+
await fillAction(page);
45+
await page.waitForChanges();
46+
await textInput.dispatchEvent('change');
47+
await expect(callbackPromise).resolves.toBe(TEST_VALUE);
48+
});
49+
});
50+
test.describe('DOM events', () => {
51+
test(`should emit change when internal input emits`, async ({ page }) => {
52+
await page.setContent(`<${COMPONENT_NAME} _label="Color Picker"></${COMPONENT_NAME}>`);
53+
const component = page.locator(COMPONENT_NAME);
54+
const textInput = selectTextInput(page);
55+
const eventPromise = component.evaluate((element: HTMLKolInputColorElement, KolEvent) => {
56+
return new Promise<unknown>((resolve) => {
57+
element.addEventListener(KolEvent.change, (event: Event) => {
58+
resolve((event as CustomEvent).detail);
59+
});
60+
});
61+
}, KolEvent);
62+
await page.waitForChanges();
63+
await fillAction(page);
64+
await page.waitForChanges();
65+
await textInput.dispatchEvent('change');
66+
await expect(eventPromise).resolves.toBe(TEST_VALUE);
67+
});
68+
});
1069
});

packages/components/src/components/input-color/shadow.tsx

+34-6
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,19 @@ export class KolInputColor implements InputColorAPI, FocusableElement {
6161

6262
private readonly onColorInput = (event: InputEvent) => {
6363
const value = (event.target as HTMLInputElement).value;
64-
this._value = value;
64+
this.state._value = value;
65+
6566
if (this.refInputText) {
6667
this.refInputText.value = value;
6768
}
6869
this.controller.onFacade.onInput(event);
6970
};
71+
7072
private readonly onTextInput = (event: InputEvent) => {
71-
const value = (event.target as HTMLInputElement).value;
73+
let value = (event.target as HTMLInputElement).value;
74+
if (!value.startsWith('#')) {
75+
value = `#${value}`;
76+
}
7277
this._value = value;
7378
if (this.refInputColor) {
7479
this.refInputColor.value = value;
@@ -87,6 +92,10 @@ export class KolInputColor implements InputColorAPI, FocusableElement {
8792
this.refInputText?.focus();
8893
}
8994

95+
private get hasSuggestions(): boolean {
96+
return Array.isArray(this.state._suggestions) && this.state._suggestions.length > 0;
97+
}
98+
9099
private getFormFieldProps(): FormFieldStateWrapperProps {
91100
return {
92101
state: this.state,
@@ -99,27 +108,40 @@ export class KolInputColor implements InputColorAPI, FocusableElement {
99108

100109
private getInputColorProps(): InputStateWrapperProps {
101110
return {
111+
...this.getGenericInputProps(),
102112
ref: this.catchColorRef,
103113
type: 'color',
104114
name: this.state._name ? `${this.state._name}-color` : undefined,
115+
list: this.hasSuggestions ? `${this.state._id}-list` : undefined,
116+
id: undefined,
105117
'aria-hidden': 'true',
106-
state: this.state,
107-
...this.controller.onFacade,
118+
tabIndex: -1,
108119
onInput: this.onColorInput,
109120
};
110121
}
111122
private getInputTextProps(): InputStateWrapperProps {
112123
return {
124+
...this.getGenericInputProps(),
113125
ref: this.catchRef,
114126
type: 'text',
115127
name: this.state._name ? `${this.state._name}-text` : undefined,
116-
state: this.state,
117-
...this.controller.onFacade,
128+
list: this.hasSuggestions ? `${this.state._id}-list` : undefined,
118129
onInput: this.onTextInput,
130+
};
131+
}
132+
133+
private getGenericInputProps() {
134+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
135+
const { _suggestions, ...other } = this.state;
136+
137+
return {
138+
state: { ...other, _suggestions: [] },
139+
...this.controller.onFacade,
119140
onBlur: this.onBlur,
120141
onFocus: this.onFocus,
121142
};
122143
}
144+
123145
public render(): JSX.Element {
124146
return (
125147
<KolFormFieldStateWrapperFc {...this.getFormFieldProps()}>
@@ -344,6 +366,12 @@ export class KolInputColor implements InputColorAPI, FocusableElement {
344366
this.controller.validateValue(value);
345367
}
346368

369+
public componentDidLoad(): void {
370+
if (!this._value && this.refInputColor) {
371+
this._value = this.refInputColor.value;
372+
}
373+
}
374+
347375
public componentWillLoad(): void {
348376
this._touched = this._touched === true;
349377
this.controller.componentWillLoad();

packages/components/src/components/input-color/style.scss

+9-3
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,21 @@
1111
@include kol-input;
1212

1313
.kol-input-color {
14-
&__input--color {
15-
cursor: pointer;
14+
&__input {
15+
&--color {
16+
cursor: pointer;
17+
flex-grow: 1;
18+
}
19+
20+
&--text {
21+
width: rem(112);
22+
}
1623
}
1724

1825
&__inputs-wrapper {
1926
align-items: center;
2027
display: flex;
2128
flex-direction: row;
22-
flex-grow: 1;
2329
gap: rem(6) !important;
2430
}
2531
}

0 commit comments

Comments
 (0)