Skip to content

Commit 0cee9f7

Browse files
authored
fix(ui5-color-picker): ensure RGB and HSL values are within limits (#11915)
Previously if an user was about to type a RGB or HSL value in the input fields, that were out of boundaries (from 0 to 255 for all RGB fields, 0 to 360 for Hue, 0 to 100(%) for Saturation and Light in HSL), the input fields became disabled, which led to bad UX. With this change we now 'normalise' the values that are out of the bounds (mentioned above) to the closest one. For RGB: values above 255 –> e.g 275 are normalised to 255; values below 0 –> e.g -20 are normalised to 0; For HSL: Hue: values above 360 –> e.g 375 are normalised to 360; values below 0 –> e.g -20 are normlised to 0; Saturation and Light: values above 100 –> e.g. 120 are normalised to 100; values below 0 –> e.g. -20 are normalised
1 parent c957009 commit 0cee9f7

File tree

3 files changed

+84
-12
lines changed

3 files changed

+84
-12
lines changed

packages/main/cypress/specs/ColorPicker.cy.tsx

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,43 @@ describe("Color Picker general interaction tests", () => {
221221
.should("have.value", "rgba(70, 64, 191, 0.5)");
222222
});
223223

224+
it("should normalize RGB values above 255 to 255", () => {
225+
cy.mount(<ColorPicker value="rgba(100, 100, 100, 1)"></ColorPicker>);
226+
227+
cy.get("[ui5-color-picker]")
228+
.as("colorPicker");
229+
230+
// Test red input normalization
231+
cy.get<ColorPicker>("@colorPicker")
232+
.ui5ColorPickerUpdateInput("#red", "300");
233+
234+
cy.get<ColorPicker>("@colorPicker")
235+
.ui5ColorPickerValidateInput("#red", "255");
236+
237+
cy.get<ColorPicker>("@colorPicker")
238+
.should("have.value", "rgba(255, 100, 100, 1)");
239+
240+
// Test green input normalization
241+
cy.get<ColorPicker>("@colorPicker")
242+
.ui5ColorPickerUpdateInput("#green", "400");
243+
244+
cy.get<ColorPicker>("@colorPicker")
245+
.ui5ColorPickerValidateInput("#green", "255");
246+
247+
cy.get<ColorPicker>("@colorPicker")
248+
.should("have.value", "rgba(255, 255, 100, 1)");
249+
250+
// Test blue input normalization
251+
cy.get<ColorPicker>("@colorPicker")
252+
.ui5ColorPickerUpdateInput("#blue", "500");
253+
254+
cy.get<ColorPicker>("@colorPicker")
255+
.ui5ColorPickerValidateInput("#blue", "255");
256+
257+
cy.get<ColorPicker>("@colorPicker")
258+
.should("have.value", "rgba(255, 255, 255, 1)");
259+
});
260+
224261
it("should update Saturation & Light inputs when selecting color from main color grid", () => {
225262
cy.mount(<ColorPicker value="rgba(136, 64, 101, 1)"></ColorPicker>);
226263

packages/main/src/ColorPicker.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,33 +358,41 @@ class ColorPicker extends UI5Element implements IFormInputElement {
358358
_handleColorInputChange(e: Event) {
359359
const target = e.target as Input;
360360
const targetValue = parseInt(target.value) || 0;
361+
let normalizedValue = targetValue;
361362

362363
switch (target.id) {
363364
case "red":
364365
this._colorValue.R = targetValue;
366+
normalizedValue = this._colorValue.R;
365367
break;
366368

367369
case "green":
368370
this._colorValue.G = targetValue;
371+
normalizedValue = this._colorValue.G;
369372
break;
370373

371374
case "blue":
372375
this._colorValue.B = targetValue;
376+
normalizedValue = this._colorValue.B;
373377
break;
374378

375379
case "hue":
376380
this._colorValue.H = targetValue;
381+
normalizedValue = this._colorValue.H;
377382
break;
378383

379384
case "saturation":
380385
this._colorValue.S = targetValue;
386+
normalizedValue = this._colorValue.S;
381387
break;
382388

383389
case "light":
384390
this._colorValue.L = targetValue;
391+
normalizedValue = this._colorValue.L;
385392
break;
386393
}
387394

395+
target.value = String(normalizedValue);
388396
const color = this._colorValue.toRGBString();
389397
this._setValue(color);
390398
this._updateColorGrid();

packages/main/src/colorpicker-utils/ColorValue.ts

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -94,33 +94,39 @@ class ColorValue {
9494
}
9595

9696
set H(value: number) {
97-
this.validateHValue(value);
98-
this._updateHSL({ h: value, s: this.S, l: this.L });
97+
const normalizedValue = this.normalizeHValue(value);
98+
this._valid = true;
99+
this._updateHSL({ h: normalizedValue, s: this.S, l: this.L });
99100
}
100101

101102
set S(value: number) {
102-
this.validateSLValue(value);
103-
this._updateHSL({ h: this.H, s: value, l: this.L });
103+
const normalizedValue = this.normalizeSLValue(value);
104+
this._valid = true;
105+
this._updateHSL({ h: this.H, s: normalizedValue, l: this.L });
104106
}
105107

106108
set L(value: number) {
107-
this.validateSLValue(value);
108-
this._updateHSL({ h: this.H, s: this.S, l: value });
109+
const normalizedValue = this.normalizeSLValue(value);
110+
this._valid = true;
111+
this._updateHSL({ h: this.H, s: this.S, l: normalizedValue });
109112
}
110113

111114
set R(value: number) {
112-
this.validateRGBValue(value);
113-
this._updateRGB({ r: value, g: this.G, b: this.B });
115+
const normalizedValue = this.normalizeRGBValue(value);
116+
this._valid = true;
117+
this._updateRGB({ r: normalizedValue, g: this.G, b: this.B });
114118
}
115119

116120
set G(value: number) {
117-
this.validateRGBValue(value);
118-
this._updateRGB(this.RGB = { r: this.R, g: value, b: this.B });
121+
const normalizedValue = this.normalizeRGBValue(value);
122+
this._valid = true;
123+
this._updateRGB({ r: this.R, g: normalizedValue, b: this.B });
119124
}
120125

121126
set B(value: number) {
122-
this.validateRGBValue(value);
123-
this._updateRGB({ r: this.R, g: this.G, b: value });
127+
const normalizedValue = this.normalizeRGBValue(value);
128+
this._valid = true;
129+
this._updateRGB({ r: this.R, g: this.G, b: normalizedValue });
124130
}
125131

126132
set Alpha(value: number) {
@@ -135,6 +141,13 @@ class ColorValue {
135141
this._valid = this._isValidRGBValue(value);
136142
}
137143

144+
normalizeRGBValue(value: number): number {
145+
if (this._isValidRGBValue(value)) {
146+
return value;
147+
}
148+
return value < 0 ? 0 : 255;
149+
}
150+
138151
validateRGBColor(color: ColorRGB) {
139152
this._valid = this._isValidRGBValue(color.r) && this._isValidRGBValue(color.g) && this._isValidRGBValue(color.b);
140153
}
@@ -147,10 +160,24 @@ class ColorValue {
147160
this._valid = this._isValidHValue(value);
148161
}
149162

163+
normalizeHValue(value: number): number {
164+
if (this._isValidHValue(value)) {
165+
return value;
166+
}
167+
return value < 0 ? 0 : 360;
168+
}
169+
150170
validateSLValue(value: number) {
151171
this._valid = this._isValidSLValue(value);
152172
}
153173

174+
normalizeSLValue(value: number): number {
175+
if (this._isValidSLValue(value)) {
176+
return value;
177+
}
178+
return value < 0 ? 0 : 100;
179+
}
180+
154181
validateHEX(value: string) {
155182
const hexRegex = new RegExp("^[<0-9 abcdef]+$");
156183
this._valid = value.length === 6 && hexRegex.test(value);

0 commit comments

Comments
 (0)