color-elements 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -11
- package/_build/copy-config.js +11 -1
- package/_build/copy-config.json +1 -1
- package/_build/eleventy.js +21 -0
- package/_build/filters-extra.js +3 -0
- package/_data/components.json +8 -0
- package/_includes/component.njk +61 -0
- package/_includes/partials/_nav-links.njk +12 -0
- package/_redirects +1 -1
- package/assets/js/index.js +8 -7
- package/eslint.config.js +316 -0
- package/index.js +6 -4
- package/logo.svg +22 -44
- package/package.json +11 -5
- package/src/channel-slider/README.md +123 -0
- package/src/channel-slider/channel-slider.css +19 -0
- package/src/channel-slider/channel-slider.js +252 -0
- package/{color-gamut → src/color-gamut}/README.md +1 -1
- package/{color-gamut → src/color-gamut}/color-gamut.js +1 -1
- package/src/color-inline/README.md +31 -0
- package/{color-swatch/color-swatch.js → src/color-inline/color-inline.js} +6 -6
- package/src/color-inline/style.css +14 -0
- package/src/color-picker/README.md +48 -0
- package/src/color-picker/color-picker.css +20 -0
- package/src/color-picker/color-picker.js +164 -0
- package/src/color-slider/README.md +193 -0
- package/src/color-slider/color-slider.css +164 -0
- package/src/color-slider/color-slider.js +278 -0
- package/src/color-swatch/README.md +100 -0
- package/src/color-swatch/color-swatch.css +95 -0
- package/{css-color/css-color.js → src/color-swatch/color-swatch.js} +30 -8
- package/src/common/color.js +12 -0
- package/src/common/dom.js +61 -0
- package/src/common/util.js +142 -0
- package/src/index.js.njk +7 -0
- package/src/src.json +3 -0
- package/_data/eleventyComputed.11tydata.js +0 -29
- package/color-slider/README.md +0 -84
- package/color-slider/color-slider.js +0 -79
- package/color-slider/style.css +0 -65
- package/color-swatch/index.njk +0 -40
- package/common/attributes.js +0 -68
- package/common/color.js +0 -10
- package/css-color/index.njk +0 -43
- package/css-color/style.css +0 -67
- /package/{color-gamut/style.css → src/color-gamut/color-gamut.css} +0 -0
- /package/{color-swatch/color-swatch.css → src/color-inline/color-inline.css} +0 -0
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
|
|
2
|
+
import Color from "../common/color.js";
|
|
3
|
+
import NudeElement from "../../node_modules/nude-element/src/Element.js";
|
|
4
|
+
import { getStep } from "../common/util.js";
|
|
5
|
+
|
|
6
|
+
let supports = {
|
|
7
|
+
inSpace: CSS?.supports("background", "linear-gradient(in oklab, red, tan)"),
|
|
8
|
+
fieldSizing: CSS?.supports("field-sizing", "content"),
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const Self = class ColorSlider extends NudeElement {
|
|
12
|
+
static postConstruct = [];
|
|
13
|
+
static tagName = "color-slider";
|
|
14
|
+
|
|
15
|
+
constructor () {
|
|
16
|
+
super();
|
|
17
|
+
this.attachShadow({mode: "open"});
|
|
18
|
+
|
|
19
|
+
let styleURL = new URL(`./${this.constructor.tagName}.css`, import.meta.url);
|
|
20
|
+
this.shadowRoot.innerHTML = `
|
|
21
|
+
<style>@import url("${ styleURL }")</style>
|
|
22
|
+
<input type="range" class="color-slider" part="slider" min="0" max="1" step="0.01" part="slider" />
|
|
23
|
+
<slot name="tooltip" class="slider-tooltip">
|
|
24
|
+
<input type="number" part="spinner" min="0" max="1" step="0.01" />
|
|
25
|
+
</slot>
|
|
26
|
+
<slot></slot>
|
|
27
|
+
`;
|
|
28
|
+
|
|
29
|
+
this._el = {
|
|
30
|
+
slider: this.shadowRoot.querySelector(".color-slider"),
|
|
31
|
+
spinner: this.shadowRoot.querySelector("input[type=number]"),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
connectedCallback() {
|
|
36
|
+
super.connectedCallback?.();
|
|
37
|
+
|
|
38
|
+
this._el.slider.addEventListener("input", this);
|
|
39
|
+
this._el.spinner.addEventListener("input", this);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
disconnectedCallback() {
|
|
43
|
+
this._el.slider.removeEventListener("input", this);
|
|
44
|
+
this._el.spinner.removeEventListener("input", this);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
handleEvent (event) {
|
|
48
|
+
if (event.type === "input") {
|
|
49
|
+
if (this.tooltip === "progress" && event.target === this._el.spinner) {
|
|
50
|
+
// Convert to value
|
|
51
|
+
let value = this._el.spinner.value;
|
|
52
|
+
this.value = this.valueAt(value / 100);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
this.value = event.target.value;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
this.dispatchEvent(new event.constructor(event.type, {...event}));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
propChangedCallback ({name, prop, detail: change}) {
|
|
63
|
+
if (["min", "max", "step", "value", "defaultValue"].includes(name)) {
|
|
64
|
+
prop.applyChange(this._el.slider, change);
|
|
65
|
+
|
|
66
|
+
let spinnerValue = this.tooltip === "progress" ? +(this.progress * 100).toPrecision(4) : this.value;
|
|
67
|
+
prop.applyChange(this._el.spinner, {...change, value: spinnerValue});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (name === "stops") {
|
|
71
|
+
// FIXME will fail if there are none values
|
|
72
|
+
let stops = this.stops;
|
|
73
|
+
let supported = stops.every(color => CSS.supports("color", color));
|
|
74
|
+
|
|
75
|
+
if (!supported) {
|
|
76
|
+
stops = this.tessellateStops({ steps: 3 });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
stops = stops.map(color => color.display()).join(", ");
|
|
80
|
+
|
|
81
|
+
this.style.setProperty("--slider-color-stops", stops);
|
|
82
|
+
}
|
|
83
|
+
else if (name === "space" && supports.inSpace) {
|
|
84
|
+
let space = this.space;
|
|
85
|
+
let spaceId = space.id;
|
|
86
|
+
let supported = CSS.supports("background", `linear-gradient(in ${ spaceId }, red, tan)`);
|
|
87
|
+
|
|
88
|
+
if (!supported) {
|
|
89
|
+
spaceId = this.space.isPolar ? "oklch" : "oklab";
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
this.style.setProperty("--color-space", spaceId);
|
|
93
|
+
}
|
|
94
|
+
else if (name === "color" || name === "defaultColor") {
|
|
95
|
+
let color = this.color;
|
|
96
|
+
|
|
97
|
+
if (color) {
|
|
98
|
+
let displayedColor = color.display();
|
|
99
|
+
this.style.setProperty("--color", displayedColor);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
else if (name === "value") {
|
|
103
|
+
this.style.setProperty("--progress", this.progress);
|
|
104
|
+
|
|
105
|
+
if (!supports.fieldSizing) {
|
|
106
|
+
let valueStr = this.value + "";
|
|
107
|
+
this._el.spinner.style.setProperty("--value-length", valueStr.length);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
tessellateStops (options = {}) {
|
|
113
|
+
let stops = this.stops;
|
|
114
|
+
let tessellated = [];
|
|
115
|
+
|
|
116
|
+
for (let i=1; i<stops.length; i++) {
|
|
117
|
+
let start = stops[i - 1];
|
|
118
|
+
let end = stops[i];
|
|
119
|
+
let steps = start.steps(end, { space: this.space, ...options });
|
|
120
|
+
tessellated.push(...steps);
|
|
121
|
+
|
|
122
|
+
if (i < stops.length - 1) {
|
|
123
|
+
tessellated.pop();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return tessellated;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
get progress () {
|
|
131
|
+
return this.progressAt(this.value);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
progressAt (value) {
|
|
135
|
+
return (value - this.min) / (this.max - this.min);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
valueAt (progress) {
|
|
139
|
+
return this.min + progress * (this.max - this.min);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
colorAt (value) {
|
|
143
|
+
let progress = this.progressAt(value);
|
|
144
|
+
return this.colorAtProgress(progress);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
colorAtProgress (progress) {
|
|
148
|
+
let bands = this.scales?.length;
|
|
149
|
+
|
|
150
|
+
if (bands <= 0) {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// FIXME the values outside of [0, 1] should be scaled
|
|
155
|
+
if (progress >= 1) {
|
|
156
|
+
return this.scales.at(-1)(progress);
|
|
157
|
+
}
|
|
158
|
+
else if (progress <= 0) {
|
|
159
|
+
return this.scales[0](progress);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
let band = 1 / bands;
|
|
163
|
+
let scaleIndex = Math.max(0, Math.min(Math.floor(progress / band), bands - 1));
|
|
164
|
+
let scale = this.scales[scaleIndex];
|
|
165
|
+
let color = scale((progress % band) * bands);
|
|
166
|
+
|
|
167
|
+
return color;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
static props = {
|
|
171
|
+
min: {
|
|
172
|
+
type: Number,
|
|
173
|
+
default: 0,
|
|
174
|
+
},
|
|
175
|
+
max: {
|
|
176
|
+
type: Number,
|
|
177
|
+
default: 1,
|
|
178
|
+
},
|
|
179
|
+
step: {
|
|
180
|
+
type: Number,
|
|
181
|
+
default () {
|
|
182
|
+
return getStep(this.max, this.min, { minSteps: 100 });
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
stops: {
|
|
186
|
+
type: Array,
|
|
187
|
+
typeOptions: {
|
|
188
|
+
itemType: Color,
|
|
189
|
+
},
|
|
190
|
+
default: el => []
|
|
191
|
+
},
|
|
192
|
+
defaultValue: {
|
|
193
|
+
type: Number,
|
|
194
|
+
default () {
|
|
195
|
+
return (this.min + this.max) / 2;
|
|
196
|
+
},
|
|
197
|
+
reflect: {
|
|
198
|
+
from: "value",
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
value: {
|
|
202
|
+
type: Number,
|
|
203
|
+
defaultProp: "defaultValue",
|
|
204
|
+
reflect: false,
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
space: {
|
|
208
|
+
default () {
|
|
209
|
+
return this.stops[0]?.space ?? "oklab";
|
|
210
|
+
},
|
|
211
|
+
parse (value) {
|
|
212
|
+
if (value instanceof Color.Space || value === null || value === undefined) {
|
|
213
|
+
return value;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
value += "";
|
|
217
|
+
|
|
218
|
+
return Color.Space.get(value);
|
|
219
|
+
},
|
|
220
|
+
stringify (value) {
|
|
221
|
+
return value?.id;
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
|
|
225
|
+
color: {
|
|
226
|
+
type: Color,
|
|
227
|
+
get () {
|
|
228
|
+
return this.colorAt(this.value);
|
|
229
|
+
},
|
|
230
|
+
dependencies: ["scales", "value"],
|
|
231
|
+
},
|
|
232
|
+
scales: {
|
|
233
|
+
get () {
|
|
234
|
+
let stops = this.stops;
|
|
235
|
+
let scales = [];
|
|
236
|
+
|
|
237
|
+
for (let i=1; i<stops.length; i++) {
|
|
238
|
+
let start = stops[i - 1];
|
|
239
|
+
let end = stops[i];
|
|
240
|
+
let range = start.range(end, { space: this.space, hue: "raw" });
|
|
241
|
+
scales.push(range);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return scales;
|
|
245
|
+
},
|
|
246
|
+
dependencies: ["stops", "space"],
|
|
247
|
+
},
|
|
248
|
+
|
|
249
|
+
tooltip: {
|
|
250
|
+
type: String,
|
|
251
|
+
},
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
static events = {
|
|
255
|
+
change: {
|
|
256
|
+
from () {
|
|
257
|
+
return this._el.slider;
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
valuechange: {
|
|
261
|
+
propchange: "value",
|
|
262
|
+
},
|
|
263
|
+
colorchange: {
|
|
264
|
+
propchange: "color",
|
|
265
|
+
},
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
static formAssociated = {
|
|
269
|
+
getSource: el => el._el.slider,
|
|
270
|
+
role: "slider",
|
|
271
|
+
valueProp: "value",
|
|
272
|
+
changeEvent: "valuechange",
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
customElements.define(Self.tagName, Self);
|
|
277
|
+
|
|
278
|
+
export default Self;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# `<color-swatch>`
|
|
2
|
+
|
|
3
|
+
## Examples
|
|
4
|
+
|
|
5
|
+
### Static
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<color-swatch>oklch(70% 0.25 138)</color-swatch>
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
<color-swatch size="large">oklch(70% 0.25 138)</color-swatch>
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Editable
|
|
16
|
+
|
|
17
|
+
```html
|
|
18
|
+
<color-swatch>
|
|
19
|
+
<input value="oklch(70% 0.25 138)" />
|
|
20
|
+
</color-swatch>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```html
|
|
24
|
+
<color-swatch size="large">
|
|
25
|
+
<input value="oklch(70% 0.25 138)" />
|
|
26
|
+
</color-swatch>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### With slot content
|
|
30
|
+
|
|
31
|
+
```html
|
|
32
|
+
<color-swatch>
|
|
33
|
+
<label slot="before" for=c1>Accent color:</label>
|
|
34
|
+
<input value="oklch(70% 0.25 138)" id=c1 />
|
|
35
|
+
</color-swatch>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```html
|
|
39
|
+
<color-swatch size="large">
|
|
40
|
+
<label slot="before" id=c2>Accent color:</label>
|
|
41
|
+
<input value="oklch(70% 0.25 138)" id=c2 />
|
|
42
|
+
<small slot="after">Tip: Pick a bright medium color.</small>
|
|
43
|
+
</color-swatch>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Adding text within the default swatch:
|
|
47
|
+
|
|
48
|
+
```html
|
|
49
|
+
<color-swatch size="large">
|
|
50
|
+
<div slot="swatch-content">Some text</div>
|
|
51
|
+
<input value="oklch(70% 0.25 138)" id=c1 />
|
|
52
|
+
</color-swatch>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Replacing the whole swatch with a custom element:
|
|
56
|
+
|
|
57
|
+
```html
|
|
58
|
+
<color-swatch size="large">
|
|
59
|
+
<div slot="swatch">Some text</div>
|
|
60
|
+
<input value="oklch(70% 0.25 138)" id=c1 />
|
|
61
|
+
</color-swatch>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Bound to CSS property
|
|
65
|
+
|
|
66
|
+
You can automatically bind the color swatch to a CSS property by setting the `property` attribute.
|
|
67
|
+
Then you don’t need to provide an initial value, it will be read from the CSS property.
|
|
68
|
+
|
|
69
|
+
```html
|
|
70
|
+
<color-swatch size="large" property="--color-red">
|
|
71
|
+
<input />
|
|
72
|
+
</color-swatch>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Events
|
|
76
|
+
|
|
77
|
+
```html
|
|
78
|
+
<color-swatch size="large" oncolorchange="this.nextElementSibling.textContent = this.color">
|
|
79
|
+
<input value="oklch(70% 0.25 138)" />
|
|
80
|
+
</color-swatch>
|
|
81
|
+
<color-inline></color-inline>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Update via JS
|
|
85
|
+
|
|
86
|
+
#### Static
|
|
87
|
+
|
|
88
|
+
```html
|
|
89
|
+
<color-swatch id="dynamic_static">oklch(70% 0.25 138)</color-swatch>
|
|
90
|
+
<button onclick='dynamic_static.color = "oklch(60% 0.15 0)"'>Change color</button>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Editable
|
|
94
|
+
|
|
95
|
+
```html
|
|
96
|
+
<color-swatch id="dynamic_editable">
|
|
97
|
+
<input value="oklch(70% 0.25 138)" />
|
|
98
|
+
</color-swatch>
|
|
99
|
+
<button onclick='dynamic_editable.color = "oklch(60% 0.15 0)"'>Change color</button>
|
|
100
|
+
```
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
:host {
|
|
2
|
+
--_transparency-cell-size: var(--transparency-cell-size, .5em);
|
|
3
|
+
--_transparency-background: var(--transparcency-background, transparent);
|
|
4
|
+
--_transparency-darkness: var(--transparency-darkness, 5%);
|
|
5
|
+
--_transparency: var(--transparcency,
|
|
6
|
+
repeating-conic-gradient(transparent 0 25%, rgb(0 0 0 / var(--_transparency-darkness)) 0 50%)
|
|
7
|
+
0 0 / calc(2 * var(--_transparency-cell-size)) calc(2 * var(--_transparency-cell-size))
|
|
8
|
+
content-box border-box var(--_transparency-background)
|
|
9
|
+
);
|
|
10
|
+
display: inline-flex;
|
|
11
|
+
gap: .3em;
|
|
12
|
+
width: min-content;
|
|
13
|
+
margin: .3em;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
:host([size="large"]) {
|
|
17
|
+
flex-flow: column;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
#gamut {
|
|
21
|
+
font-size: 80%;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
#wrapper {
|
|
25
|
+
display: flex;
|
|
26
|
+
flex-flow: inherit;
|
|
27
|
+
gap: inherit;
|
|
28
|
+
|
|
29
|
+
&.static {
|
|
30
|
+
gap: .4em;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
&:not(:host([size="large"]) *) {
|
|
34
|
+
align-items: baseline;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
[part="color-wrapper"] {
|
|
39
|
+
position: relative;
|
|
40
|
+
display: flex;
|
|
41
|
+
gap: .2em;
|
|
42
|
+
|
|
43
|
+
&:not(.static *) {
|
|
44
|
+
#gamut {
|
|
45
|
+
position: absolute;
|
|
46
|
+
inset: .3em;
|
|
47
|
+
inset-inline-start: auto;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
::slotted(input) {
|
|
52
|
+
padding-inline-end: 2em;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
slot:not([name]) {
|
|
57
|
+
white-space: nowrap;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
::slotted(input) {
|
|
61
|
+
font: inherit;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
slot[name=swatch]::slotted(*),
|
|
65
|
+
#swatch {
|
|
66
|
+
flex: 1;
|
|
67
|
+
display: flex;
|
|
68
|
+
flex-flow: column;
|
|
69
|
+
align-items: center;
|
|
70
|
+
justify-content: center;
|
|
71
|
+
padding: .5em;
|
|
72
|
+
display: flex;
|
|
73
|
+
flex-flow: column;
|
|
74
|
+
flex: 1;
|
|
75
|
+
background:
|
|
76
|
+
linear-gradient(var(--color) 0 100%),
|
|
77
|
+
var(--_transparency);
|
|
78
|
+
border-radius: .2rem;
|
|
79
|
+
|
|
80
|
+
&:is(:host([size="large"]) *) {
|
|
81
|
+
max-inline-size: 15em;
|
|
82
|
+
min-block-size: 6em;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
&:not(:host([size="large"]) *) {
|
|
86
|
+
display: flex;
|
|
87
|
+
min-inline-size: 2em;
|
|
88
|
+
font-size: 65%;
|
|
89
|
+
flex: 1;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
:host([swatch="none"]) #swatch {
|
|
94
|
+
display: none;
|
|
95
|
+
}
|
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
import Color from "../common/color.js";
|
|
2
|
+
import defineEvents from "../../node_modules/nude-element/src/events/defineEvents.js";
|
|
2
3
|
import "../color-gamut/color-gamut.js";
|
|
3
|
-
// const styles = await fetch("./style.css").then(r => r.text());
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
let importIncrementable;
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
const Self = class ColorSwatch extends HTMLElement {
|
|
8
|
+
static initQueue = [];
|
|
9
9
|
|
|
10
|
-
export default class CSSColor extends HTMLElement {
|
|
11
10
|
#dom = {};
|
|
12
11
|
|
|
13
12
|
constructor () {
|
|
14
13
|
super();
|
|
15
14
|
this.attachShadow({mode: "open"});
|
|
15
|
+
let styleURL = new URL("./color-swatch.css", import.meta.url);
|
|
16
16
|
this.shadowRoot.innerHTML = `
|
|
17
17
|
<style>@import url("${ styleURL }")</style>
|
|
18
18
|
<slot name="swatch">
|
|
19
|
-
<div id="swatch" part="swatch"
|
|
19
|
+
<div id="swatch" part="swatch">
|
|
20
|
+
<slot name="swatch-content"></slot>
|
|
21
|
+
</div>
|
|
20
22
|
</slot>
|
|
21
23
|
<div id="wrapper">
|
|
22
24
|
<slot name="before"></slot>
|
|
@@ -35,6 +37,8 @@ export default class CSSColor extends HTMLElement {
|
|
|
35
37
|
this.#initialize();
|
|
36
38
|
}
|
|
37
39
|
|
|
40
|
+
this.constructor.initQueue.forEach(init => init.call(this));
|
|
41
|
+
|
|
38
42
|
// This should eventually be a custom state
|
|
39
43
|
this.#dom.wrapper.classList.toggle("static", !this.#dom.input);
|
|
40
44
|
|
|
@@ -63,8 +67,14 @@ export default class CSSColor extends HTMLElement {
|
|
|
63
67
|
this.#dom.wrapper = this.shadowRoot.querySelector("#wrapper");
|
|
64
68
|
this.#dom.colorWrapper = this.shadowRoot.querySelector("[part=color-wrapper]");
|
|
65
69
|
this.#dom.input = this.querySelector("input");
|
|
70
|
+
this.#dom.slot = this.shadowRoot.querySelector("slot:not([name])");
|
|
71
|
+
|
|
72
|
+
this.#dom.slot.addEventListener("slotchange", evt => {
|
|
73
|
+
this.#render();
|
|
74
|
+
});
|
|
66
75
|
|
|
67
76
|
if (this.#dom.input) {
|
|
77
|
+
importIncrementable ??= import("https://incrementable.verou.me/incrementable.mjs").then(m => m.default);
|
|
68
78
|
this.#dom.input.addEventListener("input", evt => {
|
|
69
79
|
this.#render(evt);
|
|
70
80
|
});
|
|
@@ -228,7 +238,6 @@ export default class CSSColor extends HTMLElement {
|
|
|
228
238
|
else {
|
|
229
239
|
try {
|
|
230
240
|
colorString = this.#color.display({inGamut: false});
|
|
231
|
-
|
|
232
241
|
}
|
|
233
242
|
catch (e) {
|
|
234
243
|
colorString = this.value;
|
|
@@ -250,7 +259,20 @@ export default class CSSColor extends HTMLElement {
|
|
|
250
259
|
}
|
|
251
260
|
}
|
|
252
261
|
|
|
262
|
+
static events = {
|
|
263
|
+
colorchange: {
|
|
264
|
+
propchange: "color",
|
|
265
|
+
},
|
|
266
|
+
valuechange: {
|
|
267
|
+
propchange: "value",
|
|
268
|
+
},
|
|
269
|
+
};
|
|
270
|
+
|
|
253
271
|
static observedAttributes = ["for", "property"];
|
|
254
272
|
}
|
|
255
273
|
|
|
256
|
-
|
|
274
|
+
defineEvents(Self);
|
|
275
|
+
|
|
276
|
+
customElements.define("color-swatch", Self);
|
|
277
|
+
|
|
278
|
+
export default Self;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
let specifier;
|
|
2
|
+
|
|
3
|
+
try {
|
|
4
|
+
import.meta.resolve("colorjs.io");
|
|
5
|
+
specifier = "colorjs.io";
|
|
6
|
+
}
|
|
7
|
+
catch (e) {
|
|
8
|
+
// specifier = "../../node_modules/colorjs.io/dist/color.js";
|
|
9
|
+
specifier = "https://colorjs.io/dist/color.js";
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default await import(specifier).then(module => module.default);
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export function named (host, attributes = ["id", "part"]) {
|
|
2
|
+
let ret = {};
|
|
3
|
+
let selector = attributes.map(attr => `[${ attr }]`).join(", ");
|
|
4
|
+
|
|
5
|
+
for (let el of host.shadowRoot.querySelectorAll(selector)) {
|
|
6
|
+
// Get the value of the first attribute in attributes that has a value
|
|
7
|
+
let attribute = attributes.find(attr => el.hasAttribute(attr));
|
|
8
|
+
ret[el[attribute]] = el;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return ret;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function slots (host) {
|
|
15
|
+
let ret = {};
|
|
16
|
+
|
|
17
|
+
for (let slot of host.shadowRoot.querySelectorAll("slot")) {
|
|
18
|
+
ret[slot.name] = slot;
|
|
19
|
+
|
|
20
|
+
if (!slot.name || slot.dataset.default !== undefined) {
|
|
21
|
+
ret.default = slot;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return ret;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function toSlots ({
|
|
29
|
+
slots = this._slots,
|
|
30
|
+
slotElements = slots ? Object.values(slots) : Array.from(this.shadowRoot.querySelectorAll("slot")),
|
|
31
|
+
}) {
|
|
32
|
+
let children = this.childNodes;
|
|
33
|
+
let assignments = new WeakMap();
|
|
34
|
+
|
|
35
|
+
if (!slots && slotElements) {
|
|
36
|
+
slots = Object.fromEntries(slotElements.map(slot => [slot.name, slot]));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Assign to slots
|
|
40
|
+
for (let child of children) {
|
|
41
|
+
let assignedSlot;
|
|
42
|
+
|
|
43
|
+
if (child.slot) {
|
|
44
|
+
// Explicit slot
|
|
45
|
+
assignedSlot = slots[child.slot];
|
|
46
|
+
}
|
|
47
|
+
else if (child.matches) {
|
|
48
|
+
assignedSlot = slotElements.find(slot => child.matches(slot.dataset.assign));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
assignedSlot ??= slots.default;
|
|
52
|
+
let all = assignments.get(assignedSlot) ?? new Set();
|
|
53
|
+
all.add(child);
|
|
54
|
+
assignments.set(assignedSlot, all);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
for (let slot of slotElements) {
|
|
58
|
+
let all = assignments.get(slot) ?? new Set();
|
|
59
|
+
slot.assign(...all);
|
|
60
|
+
}
|
|
61
|
+
}
|