Skip to content

Commit 5dc367b

Browse files
committed
Add advanced color slider story
1 parent d82b5e0 commit 5dc367b

File tree

2 files changed

+150
-5
lines changed

2 files changed

+150
-5
lines changed

packages/uui-color-slider/lib/uui-color-slider.element.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { LabelMixin } from '@umbraco-ui/uui-base/lib/mixins';
1414

1515
export type UUIColorSliderOrientation = 'horizontal' | 'vertical';
1616
//TODO implement saturation and lightness types for color slider
17-
export type UUIColorSliderType = 'hue' | 'opacity';
17+
export type UUIColorSliderType = 'hue' | 'opacity' | 'saturation' | 'lightness';
1818

1919
/**
2020
* @element uui-color-slider
@@ -107,12 +107,16 @@ export class UUIColorSliderElement extends LabelMixin('label', LitElement) {
107107
willUpdate(changedProperties: Map<string, any>) {
108108
if (changedProperties.has('type')) {
109109
if (this.type === 'hue') {
110-
this.max = 360;
111-
this.precision = 1;
110+
this.max = this.max ?? 360;
111+
} else if (this.type === 'saturation') {
112+
this.max = this.max ?? 100;
113+
} else if (this.type === 'lightness') {
114+
this.max = this.max ?? 100;
112115
} else if (this.type === 'opacity') {
113-
this.max = 100;
114-
this.precision = 1;
116+
this.max = this.max ?? 100;
115117
}
118+
119+
this.precision = this.precision ?? 1;
116120
}
117121
}
118122

packages/uui-color-slider/lib/uui-color-slider.story.ts

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
import '.';
22
import readme from '../README.md?raw';
33
import { html } from 'lit';
4+
import { ifDefined } from 'lit/directives/if-defined.js';
5+
import { styleMap } from 'lit/directives/style-map.js';
46
import type { Meta, StoryObj } from '@storybook/web-components';
7+
import { useState } from '@storybook/preview-api';
58
import { spread } from '../../../storyhelpers';
9+
import { repeat } from 'lit/directives/repeat.js';
10+
11+
import { HslaColor } from 'colord';
12+
13+
import type { UUIColorSliderElement } from '@umbraco-ui/uui-color-slider/lib';
614

715
const meta: Meta = {
816
id: 'uui-color-slider',
@@ -53,3 +61,136 @@ export const Vertical: Story = {
5361
vertical: true,
5462
},
5563
};
64+
65+
export const Advanced: Story = {
66+
render: () => {
67+
const sliders = [
68+
{ label: 'H', type: 'hue', color: '#0075ff', value: 0, min: 0, max: 360 },
69+
{
70+
label: 'S',
71+
type: 'saturation',
72+
color: '#0075ff',
73+
value: 100,
74+
min: 0,
75+
max: 100,
76+
},
77+
{
78+
label: 'L',
79+
type: 'lightness',
80+
color: '#0075ff',
81+
value: 50,
82+
min: 0,
83+
max: 100,
84+
},
85+
{ label: 'A', type: 'opacity', value: 1, min: 0, max: 1, precision: 2 },
86+
];
87+
88+
const [value, setValue] = useState({ h: 0, s: 100, l: 50, a: 1 });
89+
90+
function handleSliderChange(e: Event, slider: any) {
91+
e.stopPropagation();
92+
93+
const element = e.target as UUIColorSliderElement;
94+
95+
console.log('Slider changed', element.value);
96+
97+
if (isNaN(element.value)) return;
98+
99+
const newColor: HslaColor = {
100+
h: value.h,
101+
s: value.s,
102+
l: value.l,
103+
a: value.a,
104+
};
105+
106+
if (slider.type === 'hue') {
107+
newColor.h = element.value;
108+
} else if (slider.type === 'saturation') {
109+
newColor.s = element.value;
110+
} else if (slider.type === 'lightness') {
111+
newColor.l = element.value;
112+
} else if (slider.type === 'opacity') {
113+
newColor.a = element.value;
114+
}
115+
116+
slider.value = element.value;
117+
118+
setValue({ h: newColor.h, s: newColor.s, l: newColor.l, a: newColor.a });
119+
}
120+
121+
function handleInputChange(e: Event, slider: any) {
122+
e.stopPropagation();
123+
124+
const input = e.target as HTMLInputElement;
125+
const newValue = parseFloat(input.value);
126+
if (isNaN(newValue)) return;
127+
128+
const newColor: HslaColor = {
129+
h: value.h,
130+
s: value.s,
131+
l: value.l,
132+
a: value.a,
133+
};
134+
135+
if (slider.type === 'hue') {
136+
newColor.h = newValue;
137+
} else if (slider.type === 'saturation') {
138+
newColor.s = newValue;
139+
} else if (slider.type === 'lightness') {
140+
newColor.l = newValue;
141+
} else if (slider.type === 'opacity') {
142+
newColor.a = newValue;
143+
}
144+
145+
slider.value = newValue;
146+
147+
setValue({ h: newColor.h, s: newColor.s, l: newColor.l, a: newColor.a });
148+
}
149+
150+
return html` ${value.h}
151+
<div style="display: flex; gap: 20px;">
152+
<div style="display: flex; flex-direction: column; gap: 10px;">
153+
${repeat(sliders, (slider: any) => {
154+
return html`<div style="display: flex; gap: 10px 20px;">
155+
<label>${slider.label}</label>
156+
<uui-color-slider
157+
.type=${slider.type}
158+
.value=${slider.value}
159+
.min=${slider.min}
160+
.max=${slider.max}
161+
?precision=${ifDefined(slider.precision)}
162+
@change=${(e: Event) => handleSliderChange(e, slider)}
163+
style=${styleMap({
164+
'--uui-slider-background-image':
165+
slider.type === 'saturation'
166+
? `linear-gradient(to right, hsl(${value.h}, 0%, ${value.l}%), hsl(${value.h}, 100%, ${value.l}%))`
167+
: slider.type === 'lightness'
168+
? `linear-gradient(to right, hsl(${value.h}, ${value.s}%, 0%), hsl(${value.h}, ${value.s}%, ${slider.value}%))`
169+
: undefined,
170+
width: '400px',
171+
})}>
172+
</uui-color-slider>
173+
<uui-input
174+
type="number"
175+
.min=${slider.min}
176+
.max=${slider.max}
177+
.step=${slider.precision > 1 ? slider.max / 10 : 1}
178+
.value=${slider.value}
179+
@change=${(e: Event) => handleInputChange(e, slider)}
180+
style="width: 60px;">
181+
</uui-input>
182+
</div>`;
183+
})}
184+
</div>
185+
<div
186+
style="width: 100px; height: 100px;
187+
border: 1px solid var(--uui-color-border-standalone);
188+
background-image: linear-gradient(45deg, var(--uui-palette-grey) 25%, transparent 25%), linear-gradient(45deg, transparent 75%, var(--uui-palette-grey) 75%), linear-gradient(45deg, transparent 75%, var(--uui-palette-grey) 75%), linear-gradient(45deg, var(--uui-palette-grey) 25%, transparent 25%);
189+
background-size: 10px 10px;
190+
background-position: 0 0, 0 0, -5px -5px, 5px 5px;">
191+
<div
192+
style="width: 100%; height: 100%; background-color: hsla(${value.h}, ${value.s}%, ${value.l}%, ${value.a});"></div>
193+
</div>
194+
</div>`;
195+
},
196+
};

0 commit comments

Comments
 (0)