Skip to content
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

feat(color-picker): add support for alpha channel (deprecates hideChannels, hideHex, hideSaved) #2841

Merged
merged 95 commits into from
May 3, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
bf8a6d8
feat(color): enable alpha support
jcfranco Jul 30, 2020
b8ba4d2
merge master
jcfranco Aug 27, 2021
4a1f4f0
merge master
jcfranco Apr 8, 2022
b03d0c5
drop unnecessary helpers since latest color module has hexa support
jcfranco Apr 8, 2022
b2bf7b0
rename alphaSupport to alphaEnabled
jcfranco Apr 8, 2022
cb86b2c
deprecate hide props in favor of disabled
jcfranco Apr 9, 2022
30e05a9
process opacity changes on input
jcfranco Apr 9, 2022
c1b6ad5
convert valid shorthand hex to hexa
jcfranco Apr 9, 2022
cff25ac
add swatch e2e tests
jcfranco Apr 9, 2022
e74ae35
add hex input e2e tests
jcfranco Apr 9, 2022
eb43ebb
fix swatch tests
jcfranco Apr 9, 2022
f5c1a82
fix hex input tests
jcfranco Apr 9, 2022
08b641b
add spec test
jcfranco Apr 11, 2022
d99e58b
stabilize existingc color-picker tests
jcfranco Apr 11, 2022
8dc580f
wip – need to lint and fix remaining tests
jcfranco Apr 12, 2022
44eaaa8
merge master
jcfranco Nov 11, 2022
f27e4a3
sync master
benelan Nov 22, 2022
41b0225
Merge branch 'master' into jcfranco/749-add-support-for-alpha
benelan Nov 22, 2022
de37287
Merge branch 'master' into jcfranco/749-add-support-for-alpha
benelan Nov 29, 2022
33cee90
Merge branch 'master' into jcfranco/749-add-support-for-alpha
benelan Dec 9, 2022
f75c4d0
Merge branch 'master' into jcfranco/749-add-support-for-alpha
alisonailea Dec 15, 2022
50103dd
test(color-picker): alpha support (#6265)
alisonailea Mar 16, 2023
8e30ab8
Revert "test(color-picker): alpha support (#6265)"
jcfranco Apr 24, 2023
4c49050
update swatch to latest design
jcfranco Nov 20, 2022
c256057
update hex input to latest design
jcfranco Nov 20, 2022
e1761f4
merge master
jcfranco Apr 24, 2023
728a484
fine-tune swatch redesign
jcfranco Apr 24, 2023
2b011f1
implement slider section redesign
jcfranco Apr 25, 2023
5f95d98
use opacity vs alpha
jcfranco Apr 26, 2023
6b57370
update hex-input to show 6-chars and wire up opacity
jcfranco Apr 26, 2023
dcbb3b0
pass messages into hex input
jcfranco Apr 26, 2023
4e29c7e
tidy up
jcfranco Apr 26, 2023
575d167
add placeholder no-color swatch
jcfranco Apr 26, 2023
a049548
tweak preview + slider spacing
jcfranco Apr 26, 2023
da339e6
tidy up
jcfranco Apr 26, 2023
71056ea
merge master
jcfranco Apr 26, 2023
69d2672
update lock file
jcfranco Apr 26, 2023
c55bb98
improve hex-input opacity input sizing
jcfranco Apr 26, 2023
ac199db
apply correct scale to tabs
jcfranco Apr 26, 2023
e9dc34f
allow pasting #-leading hex codes per spec
jcfranco Apr 26, 2023
00e8e4a
improve hex-input layout
jcfranco Apr 26, 2023
18543ab
make slider trackes more round
jcfranco Apr 26, 2023
4562f04
display alpha channel under color mode section
jcfranco Apr 27, 2023
92ba2ee
improve channel layout
jcfranco Apr 27, 2023
4b5fa4d
tidy up
jcfranco Apr 27, 2023
f1fc63a
fix hex-input value clearing
jcfranco Apr 27, 2023
7924d98
preserve alpha when nudging hex
jcfranco Apr 27, 2023
a6f763d
merge master
jcfranco Apr 27, 2023
0e80960
tidy up
jcfranco Apr 27, 2023
e355cd4
tidy up
jcfranco Apr 27, 2023
2cca8ec
tidy up
jcfranco Apr 27, 2023
7b4c809
improve spacing
jcfranco Apr 28, 2023
bc69834
tidy up
jcfranco Apr 28, 2023
c95a03a
restore active swatch display
jcfranco Apr 28, 2023
88190c7
tidy up
jcfranco Apr 28, 2023
330104b
fix restoring previous color when invalid
jcfranco Apr 28, 2023
2fc6909
tidy up
jcfranco Apr 28, 2023
4c5137b
fix hex-input value nudging
jcfranco Apr 28, 2023
fa7c5c5
fix hue/opacity scope positioning
jcfranco Apr 28, 2023
55df747
tidy up
jcfranco Apr 28, 2023
5ed7105
tidy up
jcfranco Apr 28, 2023
a42c76f
tidy up
jcfranco Apr 28, 2023
e338ebd
drop unused CSS
jcfranco Apr 28, 2023
69d44fc
tidy up
jcfranco Apr 28, 2023
2404483
tidy up
jcfranco Apr 28, 2023
6a2483c
tidy up
jcfranco Apr 28, 2023
a06c05c
tidy up
jcfranco Apr 28, 2023
e6c9e8d
tidy up
jcfranco Apr 28, 2023
d54a8e1
update tests
jcfranco Apr 28, 2023
2f57b2c
fix doc
jcfranco Apr 28, 2023
1bd5350
tidy up
jcfranco Apr 28, 2023
f598e4c
stabilize swatch tests
jcfranco Apr 28, 2023
d92237f
merge master
jcfranco Apr 29, 2023
14acb59
rename opacityEnabled to alphaChannel
jcfranco Apr 29, 2023
1467a4c
Merge branch 'master' into jcfranco/749-add-support-for-alpha
jcfranco Apr 30, 2023
ed40353
stabilize hex-input tests
jcfranco Apr 30, 2023
6f85311
fix no-color swatch
jcfranco May 1, 2023
9b3ac1e
fix hue/opacity slider rendering
jcfranco May 1, 2023
4791924
fix hue slider thumb not restoring previous color on arrow up/down
jcfranco May 1, 2023
da12c0d
ensure interaction state is set before updating internals
jcfranco May 1, 2023
5764e15
tidy up
jcfranco May 1, 2023
b91654d
stabilize color-picker tests
jcfranco May 1, 2023
efc6bbd
merge master
jcfranco May 1, 2023
dd9d827
restore alpha tests
jcfranco May 1, 2023
712a06b
fix swatch spacing
jcfranco May 2, 2023
8f41dd1
drop active swatch styling
jcfranco May 2, 2023
bb1457a
fix alpha channel alignment
jcfranco May 2, 2023
5c63a5d
merge master
jcfranco May 2, 2023
95e1497
drop bottom padding on saved section
jcfranco May 2, 2023
ba19468
fix swatch outline
jcfranco May 2, 2023
5de5ace
fix input sandwich borders in RTL
jcfranco May 2, 2023
d69306f
tweak saved swatch spacing for scale=s
jcfranco May 2, 2023
579341a
skip input sandwich workaround for small scale
jcfranco May 2, 2023
1750177
fix input sandwich border for scale=s
jcfranco May 3, 2023
4547099
Merge branch 'master' into jcfranco/749-add-support-for-alpha
jcfranco May 3, 2023
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 @@ -12,10 +12,13 @@ import {
Watch
} from "@stencil/core";
import {
createColor,
hexChar,
hexify,
hexToRGB,
isLonghandHex,
isValidHex,
normalizeAlpha,
normalizeHex,
rgbToHex
} from "../calcite-color-picker/utils";
Expand All @@ -27,7 +30,7 @@ import { focusElement, getElementDir } from "../../utils/dom";
import { TEXT } from "../calcite-color-picker/resources";
import { getKey } from "../../utils/key";

const DEFAULT_COLOR = Color();
const DEFAULT_COLOR = createColor();

@Component({
tag: "calcite-color-picker-hex-input",
Expand All @@ -50,13 +53,13 @@ export class CalciteColorPickerHexInput {
//--------------------------------------------------------------------------

connectedCallback(): void {
const { allowEmpty, value } = this;
const { allowEmpty, alphaSupport, value } = this;

if (value) {
const normalized = normalizeHex(value);

if (isValidHex(normalized)) {
this.internalColor = Color(normalized);
if (isValidHex(normalized, alphaSupport)) {
this.internalColor = createColor(normalized);
this.value = normalized;
}

Expand All @@ -75,6 +78,11 @@ export class CalciteColorPickerHexInput {
//
//--------------------------------------------------------------------------

/**
* When true, the input will process and display hex characters for the alpha channel.
*/
@Prop() alphaSupport = false;

/**
* When false, empty color (null) will be allowed as a value. Otherwise, a color value is always enforced by the component.
*
Expand Down Expand Up @@ -102,17 +110,21 @@ export class CalciteColorPickerHexInput {
/**
* The hex value.
*/
@Prop({ mutable: true, reflect: true }) value: string = normalizeHex(DEFAULT_COLOR.hex());
@Prop({ mutable: true, reflect: true }) value: string = normalizeHex(
hexify(DEFAULT_COLOR, this.alphaSupport)
);

@Watch("value")
handleValueChange(value: string, oldValue: string): void {
if (value) {
const normalized = normalizeHex(value);
const { alphaSupport } = this;

if (isValidHex(normalized)) {
if (isValidHex(normalized, alphaSupport)) {
const { internalColor } = this;
const changed = !internalColor || normalized !== normalizeHex(internalColor.hex());
this.internalColor = Color(normalized);
const changed =
!internalColor || normalized !== normalizeHex(hexify(internalColor, alphaSupport));
this.internalColor = createColor(normalized);
this.previousNonNullValue = normalized;
this.value = normalized;

Expand Down Expand Up @@ -148,27 +160,34 @@ export class CalciteColorPickerHexInput {
const node = event.currentTarget as HTMLCalciteInputElement;
const inputValue = node.value;
const hex = `#${inputValue}`;
const willClearValue = this.allowEmpty && !inputValue;
const { allowEmpty, alphaSupport, internalColor } = this;
const willClearValue = allowEmpty && !inputValue;

if (willClearValue || (isValidHex(hex) && isLonghandHex(hex))) {
if (willClearValue || (isValidHex(hex, alphaSupport) && isLonghandHex(hex))) {
return;
}

// manipulating DOM directly since rerender doesn't update input value
node.value =
this.allowEmpty && !this.internalColor
allowEmpty && !internalColor
? ""
: this.formatForInternalInput(rgbToHex(this.internalColor.object() as any as RGB));
: this.formatForInternalInput(
rgbToHex(
alphaSupport
? normalizeAlpha(internalColor.object())
: (internalColor.object() as any as RGB)
)
);
};

private onInputChange = (event: Event): void => {
private onCalciteInputChange = (event: CustomEvent): void => {
const node = event.currentTarget as HTMLCalciteInputElement;
const inputValue = node.value;
let value: this["value"];

if (inputValue) {
const hex = inputValue;
const color = hexToRGB(`#${hex}`);
const color = hexToRGB(`#${hex}`, this.alphaSupport);

if (!color) {
return;
Expand All @@ -187,7 +206,7 @@ export class CalciteColorPickerHexInput {
@Listen("keydown", { capture: true })
protected onInputKeyDown(event: KeyboardEvent): void {
const { altKey, ctrlKey, metaKey, shiftKey } = event;
const { el, inputNode, internalColor, value } = this;
const { alphaSupport, el, inputNode, internalColor, value } = this;
const key = getKey(event.key);
const isNudgeKey = key === "ArrowDown" || key === "ArrowUp";

Expand All @@ -201,14 +220,16 @@ export class CalciteColorPickerHexInput {
const direction = key === "ArrowUp" ? 1 : -1;
const bump = shiftKey ? 10 : 1;

this.value = normalizeHex(this.nudgeRGBChannels(internalColor, bump * direction).hex());
this.value = normalizeHex(
hexify(this.nudgeRGBChannels(internalColor, bump * direction), alphaSupport)
);

event.preventDefault();
return;
}

const withModifiers = altKey || ctrlKey || metaKey;
const exceededHexLength = inputNode.value.length >= 6;
const exceededHexLength = inputNode.value.length >= (alphaSupport ? 8 : 6);
const focusedElement = el.shadowRoot.activeElement as HTMLInputElement;
const hasTextSelection =
// can't use window.getSelection() because of FF bug: https://bugzilla.mozilla.org/show_bug.cgi?id=85686
Expand Down Expand Up @@ -258,7 +279,7 @@ export class CalciteColorPickerHexInput {
dir={elementDir}
label={intlHex}
onCalciteInputBlur={this.onCalciteInputBlur}
onChange={this.onInputChange}
onChange={this.onCalciteInputChange}
prefixText="#"
ref={this.storeInputRef}
scale={this.scale}
Expand Down Expand Up @@ -303,6 +324,15 @@ export class CalciteColorPickerHexInput {
}

private nudgeRGBChannels(color: Color, amount: number): Color {
return Color.rgb(color.array().map((channel) => channel + amount));
const channels = color.array().map((channel) => channel + amount);

return Color.rgb(
this.alphaSupport
? [
...channels,
color.alpha() // only RGB channels are nudged
]
: channels
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,7 @@ $size-l: 28px;
inset-0
absolute;
}

.checker {
fill: #cacaca;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import Color from "color";
import { COLORS, CSS } from "./resources";
import { Scale } from "../interfaces";
import { getThemeName } from "../../utils/dom";
import { createColor, hexify } from "../calcite-color-picker/utils";

const CHECKER_SQUARE_SIZE_IN_PX = 4;
const CHECKER_SIZE_IN_PX = CHECKER_SQUARE_SIZE_IN_PX * 2;

@Component({
tag: "calcite-color-picker-swatch",
Expand Down Expand Up @@ -34,7 +38,7 @@ export class CalciteColorPickerSwatch {

@Watch("color")
handleColorChange(color: string): void {
this.internalColor = Color(color);
this.internalColor = createColor(color);
}

/**
Expand Down Expand Up @@ -69,17 +73,45 @@ export class CalciteColorPickerSwatch {
render(): VNode {
const { active, el, internalColor } = this;
const borderRadius = active ? "100%" : "0";
const hex = internalColor.hex();
const alpha = internalColor.alpha();
const hex = hexify(internalColor, alpha < 1);
const theme = getThemeName(el);
const borderColor = theme === "light" ? COLORS.borderLight : COLORS.borderDark;

return (
<svg class={CSS.swatch} xmlns="http://www.w3.org/2000/svg">
<title>{hex}</title>
<defs>
<pattern
height={CHECKER_SIZE_IN_PX}
id="checker"
patternUnits="userSpaceOnUse"
width={CHECKER_SIZE_IN_PX}
x="0"
y="0"
>
<rect
class={CSS.checker}
height={CHECKER_SQUARE_SIZE_IN_PX}
width={CHECKER_SQUARE_SIZE_IN_PX}
x="0"
y="0"
/>
<rect
class={CSS.checker}
height={CHECKER_SQUARE_SIZE_IN_PX}
width={CHECKER_SQUARE_SIZE_IN_PX}
x={CHECKER_SQUARE_SIZE_IN_PX}
y={CHECKER_SQUARE_SIZE_IN_PX}
/>
</pattern>
</defs>
<rect fill="url(#checker)" height="100%" rx={borderRadius} width="100%" />
<rect
fill={hex}
height="100%"
id="swatch"
opacity={alpha}
rx={borderRadius}
stroke={borderColor}
// stroke-width and clip-path are needed to hide overflowing portion of stroke
Expand Down
3 changes: 2 additions & 1 deletion src/components/calcite-color-picker-swatch/resources.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export const CSS = {
swatch: "swatch",
noColorIcon: "no-color-icon"
noColorIcon: "no-color-icon",
checker: "checker"
};

export const COLORS = {
Expand Down
30 changes: 27 additions & 3 deletions src/components/calcite-color-picker/calcite-color-picker.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ describe("calcite-color-picker", () => {
propertyName: "allowEmpty",
defaultValue: false
},
{
propertyName: "alphaSupport",
defaultValue: false
},
{
propertyName: "appearance",
defaultValue: "default"
Expand Down Expand Up @@ -248,11 +252,17 @@ describe("calcite-color-picker", () => {

const supportedFormatToSampleValue = {
hex: "#ffffff",
hexa: "#ffffffff",
"rgb-css": "rgb(255, 255, 255)",
"rgba-css": "rgba(255, 255, 255, 1)",
"hsl-css": "hsl(0, 0%, 100%)",
"hsla-css": "hsla(0, 0%, 100%, 1)",
rgb: { r: 255, g: 255, b: 255 },
rgba: { r: 255, g: 255, b: 255, a: 1 },
hsl: { h: 0, s: 0, l: 100 },
hsv: { h: 0, s: 0, v: 100 }
hsla: { h: 0, s: 0, l: 100, a: 1 },
hsv: { h: 0, s: 0, v: 100 },
hsva: { h: 0, s: 0, v: 100, a: 1 }
};

const clearAndEnterHexOrChannelValue = async (
Expand Down Expand Up @@ -366,8 +376,11 @@ describe("calcite-color-picker", () => {

const supportedStringFormats = [
supportedFormatToSampleValue.hex,
supportedFormatToSampleValue.hexa,
supportedFormatToSampleValue["rgb-css"],
supportedFormatToSampleValue["hsl-css"]
supportedFormatToSampleValue["rgba-css"],
supportedFormatToSampleValue["hsl-css"],
supportedFormatToSampleValue["hsla-css"]
];

for (const value of supportedStringFormats) {
Expand All @@ -379,8 +392,11 @@ describe("calcite-color-picker", () => {

const supportedObjectFormats = [
supportedFormatToSampleValue.rgb,
supportedFormatToSampleValue.rgba,
supportedFormatToSampleValue.hsl,
supportedFormatToSampleValue.hsv
supportedFormatToSampleValue.hsla,
supportedFormatToSampleValue.hsv,
supportedFormatToSampleValue.hsva
];

for (const value of supportedObjectFormats) {
Expand Down Expand Up @@ -577,6 +593,7 @@ describe("calcite-color-picker", () => {
});

it("normalizes shorthand CSS hex", async () => {
// TODO: needs alpha test
jcfranco marked this conversation as resolved.
Show resolved Hide resolved
const page = await newE2EPage({
html: "<calcite-color-picker></calcite-color-picker>"
});
Expand Down Expand Up @@ -638,6 +655,8 @@ describe("calcite-color-picker", () => {
let page: E2EPage;
let picker: E2EElement;

// TODO: needs alpha

beforeEach(async () => {
page = await newE2EPage({
html: "<calcite-color-picker></calcite-color-picker>"
Expand Down Expand Up @@ -767,6 +786,7 @@ describe("calcite-color-picker", () => {
});

describe("color gets propagated to support inputs", () => {
// TODO: needs alpha
describe("valid color", () => {
it("color gets propagated to hex, RGB & HSV inputs", async () => {
const page = await newE2EPage({
Expand Down Expand Up @@ -902,6 +922,7 @@ describe("calcite-color-picker", () => {
});

describe("clearing color via supporting inputs", () => {
// TODO: add alpha
it("clears color via hex input", async () => {
const page = await newE2EPage({
html: "<calcite-color-picker allow-empty value='#c0ff33'></calcite-color-picker>"
Expand Down Expand Up @@ -961,6 +982,7 @@ describe("calcite-color-picker", () => {
});

it("restores previous color value when a nudge key is pressed", async () => {
// TODO: add alpha
const consistentRgbHsvChannelValue = "0";
const initialValue = "#".padEnd(7, consistentRgbHsvChannelValue);

Expand Down Expand Up @@ -1035,6 +1057,7 @@ describe("calcite-color-picker", () => {
});

describe("color storage", () => {
// TODO: add alpha
const storageId = "test-storage-id";
const color1 = "#ff00ff";
const color2 = "#beefee";
Expand Down Expand Up @@ -1157,6 +1180,7 @@ describe("calcite-color-picker", () => {
});

it("allows hiding sections", async () => {
// TODO: add alpha hidden w/ channels
const page = await newE2EPage({
html: `<calcite-color-picker></calcite-color-picker>`
});
Expand Down
Loading