color-elements 0.0.3 → 0.0.4

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.
@@ -15,5 +15,6 @@
15
15
  <li><a href="https://github.com/color-js/elements/issues/new{{ ('?title=[' + name + '] ') if name }}">New</a></li>
16
16
  </ul>
17
17
  </div>
18
+ <a href="https://opencollective.com/color">♡&nbsp;Sponsor</a>
18
19
 
19
20
 
package/_redirects CHANGED
@@ -1,5 +1,5 @@
1
1
  # Specific versions
2
- node_modules/nude-element/* https://cdn.jsdelivr.net/npm/nude-element@0.0.12/:splat 200
2
+ node_modules/nude-element/* https://cdn.jsdelivr.net/npm/nude-element@0.0.14/:splat 200
3
3
 
4
4
  # Catch all NPM fallback
5
5
  node_modules/:modulename/* https://cdn.jsdelivr.net/npm/:modulename@latest/:splat 200
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "color-elements",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "A set of web components for working with color. A Color.js project.",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -14,6 +14,7 @@
14
14
  "release": "release-it",
15
15
  "test": "echo \"Error: no test specified\" && exit 1",
16
16
  "build:html": "npx @11ty/eleventy --config=_build/eleventy.js",
17
+ "serve": "npx @11ty/eleventy --config=_build/eleventy.js --serve",
17
18
  "watch:html": "npx @11ty/eleventy --config=_build/eleventy.js --serve"
18
19
  },
19
20
  "repository": {
@@ -26,23 +27,27 @@
26
27
  "web components"
27
28
  ],
28
29
  "author": "Lea Verou",
30
+ "funding": {
31
+ "type": "opencollective",
32
+ "url": "https://opencollective.com/color"
33
+ },
29
34
  "license": "MIT",
30
35
  "bugs": {
31
36
  "url": "https://github.com/color-js/elements/issues"
32
37
  },
33
38
  "homepage": "https://github.com/color-js/elements#readme",
34
39
  "dependencies": {
40
+ "@11ty/eleventy": "^3.1.2",
35
41
  "colorjs.io": "^0.5.0",
36
42
  "nude-element": "latest"
37
43
  },
38
44
  "devDependencies": {
39
- "@11ty/eleventy": "^3.0.0-alpha.6",
40
45
  "@stylistic/eslint-plugin": "latest",
41
46
  "eslint": "latest",
42
47
  "globals": "latest",
43
- "markdown-it-attrs": "^4.1.6",
44
48
  "markdown-it-anchor": "^8",
49
+ "markdown-it-attrs": "^4.1.6",
45
50
  "npm-run-all": "^4.1.5",
46
51
  "release-it": "^17.2.0"
47
52
  }
48
- }
53
+ }
@@ -5,7 +5,7 @@ import * as dom from "../common/dom.js";
5
5
  const Self = class ChannelPicker extends ColorElement {
6
6
  static tagName = "channel-picker";
7
7
  static url = import.meta.url;
8
- static shadowStyle = true;
8
+ static styles = "./channel-picker.css";
9
9
  static shadowTemplate = `
10
10
  <space-picker part="color-space" exportparts="base: color-space-base" id="space_picker"></space-picker>
11
11
  <select id="picker" part="color-channel-base"></select>`;
@@ -6,7 +6,7 @@ import { getStep } from "../common/util.js";
6
6
  const Self = class ChannelSlider extends ColorElement {
7
7
  static tagName = "channel-slider";
8
8
  static url = import.meta.url;
9
- static shadowStyle = true;
9
+ static styles = "./channel-slider.css";
10
10
  static shadowTemplate = `
11
11
  <label class="color-slider-label" part="label">
12
12
  <slot>
@@ -22,14 +22,18 @@
22
22
  inherits: true;
23
23
  }
24
24
 
25
+ color-chart {
26
+ --_point-size: var(--point-size, .6em);
27
+ --_line-width: var(--line-width, .2em);
28
+ --color-swatch-width: var(--color-swatch-width, var(--_point-size));
29
+ --color-swatch-radius: var(--color-swatch-radius, 50%);
30
+ }
31
+
25
32
  color-chart > color-scale {
26
33
  --extent-x: calc(var(--max-x) - var(--min-x));
27
34
  --extent-y: calc(var(--max-y) - var(--min-y));
28
35
 
29
36
  &::part(color-swatch) {
30
- --_point-size: var(--point-size, .6em);
31
- --_line-width: var(--line-width, .2em);
32
-
33
37
  position: absolute;
34
38
  top: calc((1 - (var(--y) - var(--min-y)) / (var(--max-y) - var(--min-y))) * 100cqh);
35
39
  left: calc( (var(--x) - var(--min-x)) / (var(--max-x) - var(--min-x)) * 100%);
@@ -39,8 +43,8 @@ color-chart > color-scale {
39
43
  background: yellow;
40
44
  min-block-size: 0;
41
45
  translate: -50% -50%;
42
- transition: 300ms;
43
- transition-property: width;
46
+ transition: 300ms .01ms;
47
+ transition-property: width, opacity;
44
48
  }
45
49
 
46
50
  &::part(color-swatch):hover {
@@ -5,7 +5,8 @@ import ColorElement from "../common/color-element.js";
5
5
  const Self = class ColorChart extends ColorElement {
6
6
  static tagName = "color-chart";
7
7
  static url = import.meta.url;
8
- static shadowStyle = true;
8
+ static styles = "./color-chart.css";
9
+ static globalStyles = "./color-chart-global.css";
9
10
  static shadowTemplate = `
10
11
  <slot name="color-channel">
11
12
  <channel-picker id="channel_picker" part="color-channel"></channel-picker>
@@ -24,7 +25,6 @@ const Self = class ColorChart extends ColorElement {
24
25
  <div class="ticks" part="x ticks"></div>
25
26
  </div>`;
26
27
  static dependencies = new Set(["color-scale"]);
27
- static globalStyle = new URL("color-chart-global.css", import.meta.url);
28
28
 
29
29
  constructor () {
30
30
  super();
@@ -426,9 +426,7 @@ function normalizeAngles (angles) {
426
426
  if (Math.abs(delta) > 180) {
427
427
  let equivalent = [h + 360, h - 360];
428
428
  // Offset hue to minimize difference in the direction that brings it closer to the average
429
- let delta = h - averageHue;
430
-
431
- if (Math.abs(equivalent[0] - prevHue) <= Math.abs(equivalent[1] - prevHue)) {
429
+ if (Math.abs(equivalent[0] - averageHue) <= Math.abs(equivalent[1] - averageHue)) {
432
430
  angles[i] = equivalent[0];
433
431
  }
434
432
  else {
@@ -3,7 +3,7 @@ import ColorElement from "../common/color-element.js";
3
3
  const Self = class ColorInline extends ColorElement {
4
4
  static tagName = "color-inline";
5
5
  static url = import.meta.url;
6
- static shadowStyle = true;
6
+ static styles = "./color-inline.css";
7
7
  static shadowTemplate = `
8
8
  <div part="swatch-wrapper">
9
9
  <div id="swatch" part="swatch"></div>
@@ -8,7 +8,7 @@ const Self = class ColorPicker extends ColorElement {
8
8
  static tagName = "color-picker";
9
9
  static url = import.meta.url;
10
10
  static dependencies = new Set(["channel-slider"]);
11
- static shadowStyle = true;
11
+ static styles = "./color-picker.css";
12
12
  static shadowTemplate = `
13
13
  <slot name="color-space">
14
14
  <space-picker id="space_picker" part="color-space" exportparts="base: color-space-base"></space-picker>
@@ -1,28 +1,23 @@
1
1
  :host {
2
+ display: grid;
2
3
  gap: .3em;
4
+ grid-auto-flow: row;
5
+ grid-template-rows: auto auto;
6
+ grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
3
7
  }
4
8
 
5
9
  #swatches {
6
- display: flex;
7
- gap: inherit;
10
+ display: contents;
8
11
  }
9
12
 
10
13
  color-swatch {
11
14
  margin: 0;
12
- flex: 1;
13
15
  }
14
16
 
15
17
  @supports (grid-template-columns: subgrid) {
16
18
  /* Avoid uneven swatch heights */
17
- #swatches {
18
- display: grid;
19
- grid-auto-flow: row;
20
- grid-template-rows: auto auto;
21
- grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
22
- }
23
-
24
19
  color-swatch {
25
- width: 100%;
20
+ max-width: 100%;
26
21
  grid-row: 1 / span 2;
27
22
  display: grid;
28
23
  grid-template-rows: subgrid;
@@ -37,4 +32,4 @@ color-swatch {
37
32
  grid-row: 1;
38
33
  }
39
34
  }
40
- }
35
+ }
@@ -5,7 +5,7 @@ const Self = class ColorScale extends ColorElement {
5
5
  static tagName = "color-scale";
6
6
  static url = import.meta.url;
7
7
  static dependencies = new Set(["color-swatch"]);
8
- static shadowStyle = true;
8
+ static styles = "./color-scale.css";
9
9
  static shadowTemplate = `
10
10
  <div id=swatches></div>
11
11
  <slot></slot>`;
@@ -60,7 +60,7 @@ const Self = class ColorScale extends ColorElement {
60
60
  this.#swatches[i] = swatch = document.createElement("color-swatch");
61
61
  swatch.setAttribute("size", "large");
62
62
  swatch.setAttribute("part", "color-swatch");
63
- swatch.setAttribute("exportparts", "swatch, info, gamut");
63
+ swatch.setAttribute("exportparts", "swatch, info, gamut, label: swatch-label");
64
64
  newSwatches.push(swatch);
65
65
  }
66
66
 
@@ -9,7 +9,7 @@ let supports = {
9
9
  const Self = class ColorSlider extends ColorElement {
10
10
  static tagName = "color-slider";
11
11
  static url = import.meta.url;
12
- static shadowStyle = true;
12
+ static styles = "./color-slider.css";
13
13
  static shadowTemplate = `
14
14
  <input type="range" class="color-slider" part="slider" min="0" max="1" step="0.01" />
15
15
  <slot name="tooltip" class="slider-tooltip">
@@ -11,9 +11,9 @@
11
11
  position: relative;
12
12
  display: inline-flex;
13
13
  gap: .3em;
14
- width: fit-content;
14
+ width: var(--color-swatch-width, fit-content);
15
15
  margin: .3em;
16
- border-radius: .2rem;
16
+ border-radius: var(--color-swatch-radius, .2rem);
17
17
  }
18
18
 
19
19
  :host([size="large"]) {
@@ -96,9 +96,12 @@ slot {
96
96
  flex-flow: inherit;
97
97
  gap: inherit;
98
98
 
99
+ /* Prevent flex items from overflowing */
100
+ min-inline-size: 0;
101
+
99
102
  &.static {
100
103
  &:is(:host([size="large"]) *) {
101
- background: white;
104
+ background: canvas;
102
105
  }
103
106
  }
104
107
 
@@ -176,6 +179,12 @@ slot {
176
179
  gap: .2em;
177
180
  }
178
181
 
182
+ [part="label"] {
183
+ overflow: hidden;
184
+ white-space: nowrap;
185
+ text-overflow: ellipsis;
186
+ }
187
+
179
188
  slot:not([name]) {
180
189
  &::slotted(input) {
181
190
  display: flex;
@@ -7,7 +7,7 @@ const Self = class ColorSwatch extends ColorElement {
7
7
  static tagName = "color-swatch";
8
8
  static url = import.meta.url;
9
9
  static dependencies = new Set(["gamut-badge"]);
10
- static shadowStyle = true;
10
+ static styles = "./color-swatch.css";
11
11
  static shadowTemplate = `
12
12
  <slot name="swatch">
13
13
  <div id="swatch" part="swatch">
@@ -111,9 +111,11 @@ const Self = class ColorSwatch extends ColorElement {
111
111
  if (name === "label") {
112
112
  if (this.label.length && this.label !== this.swatchTextContent) {
113
113
  this._el.label.textContent = this.label;
114
+ this._el.label.title = this.label;
114
115
  }
115
116
  else {
116
117
  this._el.label.textContent = "";
118
+ this._el.label.title = "";
117
119
  }
118
120
  }
119
121
 
@@ -1,22 +1,91 @@
1
1
  import NudeElement from "../../node_modules/nude-element/src/Element.js";
2
- import { getType, wait } from "./util.js";
2
+ import { getType, defer, wait, dynamicAll, noOpTemplateTag as css } from "./util.js";
3
+
4
+ const baseGlobalStyles = css`
5
+ @keyframes fade-in {
6
+ from { opacity: 0; }
7
+ }
8
+
9
+ :state(color-element) {
10
+ &:state(loading) {
11
+ content-visibility: hidden;
12
+ opacity: 0;
13
+
14
+ &, * {
15
+ transition-property: opacity !important;
16
+ }
17
+ }
18
+
19
+ &:not(:state(loading)) {
20
+ xanimation: fade-in 300ms both;
21
+ }
22
+ }
23
+ `;
24
+
3
25
 
4
26
  const Self = class ColorElement extends NudeElement {
27
+ static url = import.meta.url;
5
28
  // TODO make lazy
6
29
  static Color;
7
30
  static all = {};
8
31
  static dependencies = new Set();
9
32
 
33
+ static globalStyles = [{css: baseGlobalStyles}];
34
+
10
35
  constructor () {
11
36
  super();
12
37
 
13
- if (this.constructor.shadowTemplate !== undefined) {
38
+ let Self = this.constructor;
39
+
40
+ if (Self.shadowTemplate !== undefined) {
14
41
  this.attachShadow({mode: "open"});
15
- this.shadowRoot.innerHTML = this.constructor.shadowTemplate;
42
+ this.shadowRoot.innerHTML = Self.shadowTemplate;
43
+ }
44
+
45
+ this._internals ??= this.attachInternals?.();
46
+ if (this._internals.states) {
47
+ this._internals.states.add("color-element");
48
+
49
+ this._internals.states.add("loading");
50
+ Self.whenReady.then(() => {
51
+ this._internals.states.delete("loading");
52
+ });
16
53
  }
17
54
  }
18
55
 
56
+ static init () {
57
+ let wasInitialized = super.init();
58
+
59
+ if (!wasInitialized) {
60
+ return wasInitialized;
61
+ }
62
+
63
+ if (this.fetchedStyles) {
64
+ this.ready.push(...this.fetchedStyles);
65
+ }
66
+
67
+ if (this.fetchedGlobalStyles) {
68
+ this.ready.push(...this.fetchedGlobalStyles );
69
+ }
70
+
71
+
72
+ this.ready[0].resolve();
73
+
74
+ return wasInitialized;
75
+ }
76
+
77
+ static ready = [defer()];
78
+ static whenReady = dynamicAll(this.ready);
79
+
19
80
  static async define () {
81
+ // Overwrite static properties, otherwise they will be shared across subclasses
82
+ this.ready = [defer()];
83
+ this.whenReady = dynamicAll(this.ready);
84
+
85
+ if (!Object.hasOwn(this, "dependencies")) {
86
+ this.dependencies = new Set();
87
+ }
88
+
20
89
  Self.all[this.tagName] = this;
21
90
  let colorTags = Object.keys(Self.all);
22
91
 
@@ -27,31 +96,16 @@ const Self = class ColorElement extends NudeElement {
27
96
  this.dependencies ??= new Set();
28
97
  this.dependencies.add(tag);
29
98
  });
30
-
31
- if (this.shadowStyle) {
32
- let url = this.shadowStyle;
33
- url = url === true ? `./${this.tagName}.css` : url;
34
- url = new URL(url, this.url);
35
- this.shadowTemplate = `<style>@import url("${ url }")</style>` + "\n" + this.shadowTemplate;
36
- }
37
- }
38
-
39
- // Hide elements before they are defined
40
- let style = document.getElementById("color-element-styles")
41
- ?? Object.assign(document.createElement("style"), {id: "color-element-styles"});
42
- style.textContent = `:is(${ colorTags.join(", ") }):not(:defined) {display: none}`;
43
- if (!style.parentNode) {
44
- document.head.append(style);
45
99
  }
46
100
 
47
101
  if (this.dependencies.size > 0) {
48
- await Promise.all([...this.dependencies].map(tag => customElements.whenDefined(tag)));
49
- }
50
- else {
51
- // Give other code a chance to overwrite Self.Color
52
- await wait();
102
+ let whenDefined = [...this.dependencies].map(tag => customElements.whenDefined(tag).then(Class => Class.whenReady));
103
+ this.ready.push(...whenDefined);
53
104
  }
54
105
 
106
+ // Give other code a chance to overwrite Self.Color
107
+ await wait();
108
+
55
109
  if (!Self.Color) {
56
110
  let specifier;
57
111
 
@@ -6,6 +6,61 @@ export async function wait (ms) {
6
6
  return new Promise(resolve => setTimeout(resolve, ms));
7
7
  }
8
8
 
9
+ export function defer (executor) {
10
+ let res, rej;
11
+
12
+ let promise = new Promise((resolve, reject) => {
13
+ res = resolve;
14
+ rej = reject;
15
+
16
+ executor?.(res, rej);
17
+ });
18
+
19
+ promise.resolve = res;
20
+ promise.reject = rej;
21
+
22
+ return promise;
23
+ }
24
+
25
+ /**
26
+ * Wait for all promises to resolve. Supports dynamically adding promises to the list after the initial call.
27
+ * @param {Promise[] | Set<Promise>} promises
28
+ * @returns {Promise}
29
+ */
30
+ export async function dynamicAll (promises) {
31
+ let all = new Set([...promises]);
32
+ let unresolved = new Set();
33
+
34
+ for (let promise of promises) {
35
+ if (promise?.then) {
36
+ unresolved.add(promise);
37
+ promise.then(() => {
38
+ // Remove the promise from the list
39
+ unresolved.delete(promise);
40
+ });
41
+ }
42
+ }
43
+
44
+ return Promise.all(unresolved).then(resolved => {
45
+ // Check if the array has new items
46
+ for (let promise of promises) {
47
+ if (!all.has(promise)) {
48
+ all.add(promise);
49
+
50
+ if (promise?.then) {
51
+ unresolved.add(promise);
52
+ }
53
+ }
54
+ }
55
+
56
+ if (unresolved.size > 0) {
57
+ return dynamicAll(unresolved).then(r => [...resolved, ...r]);
58
+ }
59
+
60
+ return resolved;
61
+ });
62
+ }
63
+
9
64
  /**
10
65
  * Compute the ideal step for a range, to be used as a default in spinners and sliders
11
66
  * @param {number} min
@@ -53,3 +108,13 @@ export function getType (value) {
53
108
 
54
109
  return Object.prototype.toString.call(value).slice(8, -1);
55
110
  }
111
+
112
+ /**
113
+ * Template tag that does nothing. Useful for importing under different names (e.g. `css`) for syntax highlighting.
114
+ * @param {string[]} strings
115
+ * @param {...any} values
116
+ * @returns {string}
117
+ */
118
+ export function noOpTemplateTag (strings, ...values) {
119
+ return strings.reduce((acc, string, i) => acc + string + (values[i] ?? ""), "");
120
+ }
@@ -3,7 +3,7 @@ import ColorElement from "../common/color-element.js";
3
3
  const Self = class GamutBadge extends ColorElement {
4
4
  static tagName = "gamut-badge";
5
5
  static url = import.meta.url;
6
- static shadowStyle = true;
6
+ static styles = "./gamut-badge.css";
7
7
  static shadowTemplate = `
8
8
  <slot>
9
9
  <span id="label" part="label"></span>
@@ -3,7 +3,7 @@ import ColorElement from "../common/color-element.js";
3
3
  const Self = class SpacePicker extends ColorElement {
4
4
  static tagName = "space-picker";
5
5
  static url = import.meta.url;
6
- static shadowStyle = true;
6
+ static styles = "./space-picker.css";
7
7
  static shadowTemplate = `<select id="picker" part="base"></select>`;
8
8
 
9
9
  constructor () {
package/debug.html DELETED
@@ -1,447 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
-
4
- <head>
5
- <meta charset="UTF-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <!-- <link rel="stylesheet" href="./src/color-chart/color-chart-global.css"> -->
8
- <title>Document</title>
9
- <style>
10
- :root {
11
- --test: red;
12
- }
13
-
14
- html,
15
- body {
16
- margin: 0;
17
- min-height: 100vh;
18
- }
19
- </style>
20
- </head>
21
-
22
- <!-- <body style="display: grid; place-items: center; align-content: center; margin: 2rem"> -->
23
-
24
- <body style="display: grid; align-items: center; align-content: center; margin: 2rem">
25
-
26
- <html-demo>
27
- <channel-slider space="lch" color="lch(91% 14 50)" channel="c"></channel-slider>
28
- </html-demo>
29
-
30
- <!-- <html-demo>
31
- <label for="el">Element:</label>
32
- <color-chart y="oklch.l" id="el">
33
- <color-scale
34
- colors="#e3f2fd, #bbdefb, #90caf9, #64b5f6, #42a5f5, #2196f3, #1e88e5, #1976d2, #1565c0, #0d47a1"></color-scale>
35
- </color-chart>
36
-
37
- <style>
38
- #el:focus {
39
- outline: 2px solid salmon;
40
- outline-offset: 2px;
41
- }
42
- </style>
43
- </html-demo> -->
44
- <!-- <html-demo>
45
- <space-picker id="picker" spaces="oklch, p3, srgb" value="oklch"></space-picker>
46
-
47
- <script>
48
- picker.labelFor = space => space.id;
49
- </script>
50
- </html-demo> -->
51
- <!-- <html-demo>
52
- <channel-slider space="jzazbz" color="oklch(50% 50% 180)"></channel-slider>
53
- </html-demo> -->
54
- <!-- <html-demo>
55
- <color-slider space="jzazbz" color="oklch(50% 50% 180)"></color-slider>
56
- </html-demo> -->
57
- <!-- <html-demo>
58
- <color-swatch>
59
- oklch(65% 0.15 210)
60
- </color-swatch>
61
- </html-demo>
62
- <html-demo>
63
- <color-swatch label="My color">
64
- oklch(65% 0.15 210)
65
- </color-swatch>
66
- </html-demo>
67
- <html-demo>
68
- <color-swatch value="oklch(65% 0.15 210)"></color-swatch>
69
- </html-demo>
70
- <html-demo>
71
- <color-swatch value="oklch(65% 0.15 210)">Color Label</color-swatch>
72
- </html-demo> -->
73
- <!-- <html-demo>
74
- <color-picker space="oklch" color="oklch(60% 30% 180)"></color-picker>
75
- </html-demo> -->
76
- <!-- <html-demo>
77
- <color-picker></color-picker>
78
- </html-demo> -->
79
- <!-- <html-demo>
80
- <color-scale editable space="oklch" colors="Gray 50: #f9fafb,
81
- Gray 100: #f3f4f6,
82
- Gray 400: #9ca3af,
83
- Gray 500: #6b7280,
84
- Gray 850: #1a202c"></color-scale>
85
-
86
- <style>
87
- color-scale::part(delete-button) {
88
- border: none;
89
- border-radius: .2em;
90
- }
91
- </style>
92
- </html-demo> -->
93
- <!-- <html-demo>
94
- <color-scale editable="editable" space="oklch"
95
- colors="Peach: #F6D6D6, Yellow: #F6F7C4, Mint: #A1EEBD, Blue: #7BD3EA"></color-scale>
96
- </html-demo> -->
97
- <!-- <html-demo>
98
- <color-scale editable="color" colors="#e3fafc, #0b7285" steps="4" space="oklch"></color-scale>
99
- </html-demo>
100
- <html-demo>
101
- <label>
102
- <input type="checkbox" onchange="this.parentElement.nextElementSibling.editable = this.checked" />Editable
103
- </label>
104
- <color-scale space="oklch" colors="Peach: #F6D6D6, Yellow: #F6F7C4, Mint: #A1EEBD, Blue: #7BD3EA"></color-scale>
105
- </html-demo> -->
106
- <!-- <html-demo>
107
- <label>
108
- <input type="checkbox" onchange="this.parentElement.nextElementSibling.editable = this.checked" />Editable
109
- </label>
110
- <color-scale space="oklch" colors="
111
- Gray 50: #f9fafb,
112
- Gray 100: #f3f4f6,
113
- Gray 400: #9ca3af,
114
- Gray 500: #6b7280,
115
- Gray 850: #1a202c
116
- "></color-scale>
117
- </html-demo> -->
118
- <!-- <color-chart y="oklch.c" info="L: oklch.l, C: oklch.c, H: oklch.h">
119
- <color-scale class="js"
120
- colors="10: oklch(22.74% 0.05346 127.56), 20: oklch(31.363% 0.07637 127.56), 30: oklch(38.586% 0.09929 127.56), 40: oklch(45.71% 0.1222 127.56), 50: oklch(55.583% 0.14511 127.56), 60: oklch(65.706% 0.16802 127.56), 70: oklch(74.234% 0.14016 127.56), 80: oklch(82.712% 0.09698 127.56), 90: oklch(91.289% 0.04521 127.56), 95: oklch(95.028% 0.0168 127.56), 05: oklch(17.028% 0.04201 127.56)"
121
- info="L: oklch.l, C: oklch.c, H: oklch.h" style="--color-count: 11;"></color-scale>
122
- <color-scale class="wa"
123
- colors="10 (WA) / 10: oklch(22.96% 0.05732 124.46), 20 (WA) / 20: oklch(31.023% 0.07932 126.35), 30 (WA) / 30: oklch(38.591% 0.0999 127.27), 40 (WA) / 40: oklch(45.187% 0.11752 127.61), 50 (WA) / 50: oklch(54.919% 0.144 128.2), 60 (WA) / 60: oklch(65.706% 0.16802 127.56), 70 (WA) / 70: oklch(74.318% 0.14579 124.41), 80 (WA) / 80: oklch(82.976% 0.10008 122.07), 90 (WA) / 90: oklch(91.96% 0.04779 121.53), 95 (WA) / 95: oklch(95.877% 0.02304 120.19), 05 (WA) / 05: oklch(17.406% 0.04251 122.61)"
124
- info="L: oklch.l, C: oklch.c, H: oklch.h" style="--color-count: 11;"></color-scale>
125
- </color-chart> -->
126
- <!-- <color-chart y="oklch.l">
127
- <color-scale colors="#e3f2fd, #bbdefb, #90caf9, #64b5f6, #42a5f5, #2196f3, #1e88e5, #1976d2, #1565c0, #0d47a1"
128
- info="L: oklch.l, C: oklch.c, H: oklch.h"></color-scale>
129
- </color-chart> -->
130
- <!-- <color-chart y="lab.b" info="oklch.l, oklch.c, oklch.h">
131
- <color-scale
132
- colors="10: #fff0f7, 20: #ffd6e8, 30: #ffafd2, 40: #ff7eb6, 50: #ee5396, 60: #d02670, 70: #9f1853, 80: #740937, 90: #510224, 100: #2a0a18"></color-scale>
133
- </color-chart> -->
134
- <!-- <color-chart y="oklch.h" info="L: oklch.l, C: oklch.c, H: oklch.h">
135
- <color-scale
136
- colors="0: #e7f5ff, 1: #d0ebff, 2: #a5d8ff, 3: #74c0fc, 4: #4dabf7, 5: #339af0, 6: #228be6, 7: #1c7ed6, 8: #1971c2, 9: #1864ab, 10: #145591, 11: #114678, 12: #0d375e"></color-scale><color-scale
137
- colors="0: #ebfbee, 1: #d3f9d8, 2: #b2f2bb, 3: #8ce99a, 4: #69db7c, 5: #51cf66, 6: #40c057, 7: #37b24d, 8: #2f9e44, 9: #2b8a3e, 10: #237032, 11: #1b5727, 12: #133d1b"></color-scale>
138
- </color-chart> -->
139
- <!--<color-chart y="oklch.c" ymin="0.1" ymax="0.2" info="oklch.c">
140
- <color-scale
141
- colors="Red 50: #fef2f2, Red 100: #fee2e2, Red 200: #fecaca, Red 300: #fca5a5, Red 400: #f87171, Red 500: #ef4444, Red 600: #dc2626, Red 700: #b91c1c, Red 800: #991b1b, Red 900: #7f1d1d, Red 950: #450a0a"></color-scale>
142
- <color-scale
143
- colors="Orange 50: #fff7ed, Orange 100: #ffedd5, Orange 200: #fed7aa, Orange 300: #fdba74, Orange 400: #fb923c, Orange 500: #f97316, Orange 600: #ea580c, Orange 700: #c2410c, Orange 800: #9a3412, Orange 900: #7c2d12, Orange 950: #431407"></color-scale>
144
- <color-scale
145
- colors="Yellow 50: #fefce8, Yellow 100: #fef9c3, Yellow 200: #fef08a, Yellow 300: #fde047, Yellow 400: #facc15, Yellow 500: #eab308, Yellow 600: #ca8a04, Yellow 700: #a16207, Yellow 800: #854d0e, Yellow 900: #713f12, Yellow 950: #422006"></color-scale>
146
- </color-chart>-->
147
-
148
- <!--<color-chart y="oklch.h" info="L: oklch.l, C: oklch.c, H: oklch.h">
149
- <color-scale class="js" colors="10: oklch(24.407% 0.05594 29.731), 20: oklch(33.308% 0.07991 31.508), 30: oklch(40.809% 0.10388 33.285), 40: oklch(48.21% 0.12785 35.062), 50: oklch(58.362% 0.15183 36.839), 60: oklch(68.763% 0.1758 38.616), 70: oklch(76.854% 0.14664 39.468), 80: oklch(84.895% 0.10147 40.321), 90: oklch(93.036% 0.04731 41.174), 95: oklch(96.556% 0.01758 42.027), 05: oklch(18.556% 0.04395 29.731)"></color-scale>
150
- <color-scale class="wa" colors="10 (WA) / 10: oklch(24.025% 0.06086 31.256), 20 (WA) / 20: oklch(32.951% 0.09091 32.447), 30 (WA) / 30: oklch(40.519% 0.11729 32.521), 40 (WA) / 40: oklch(48.059% 0.14232 32.918), 50 (WA) / 50: oklch(58.004% 0.15904 35.567), 60 (WA) / 60: oklch(68.763% 0.1758 38.616), 70 (WA) / 70: oklch(76.593% 0.14912 46.395), 80 (WA) / 80: oklch(84.512% 0.09722 53.3), 90 (WA) / 90: oklch(92.492% 0.0445 54.008), 95 (WA) / 95: oklch(96.208% 0.02193 54.343), 05 (WA) / 05: oklch(18.569% 0.04081 32.111)"></color-scale>
151
- </color-chart>-->
152
-
153
- <!-- <html-demo>
154
- <space-picker></space-picker>
155
- </html-demo>
156
-
157
- <html-demo>
158
- <space-picker value="oklab"></space-picker>
159
- </html-demo>
160
-
161
- <html-demo>
162
- <space-picker spaces="oklch, p3, srgb"></space-picker>
163
- </html-demo>
164
-
165
- <html-demo>
166
- <space-picker spaces="foo"></space-picker>
167
- </html-demo>
168
-
169
- <html-demo>
170
- <space-picker spaces="oklch, p3, srgb" value="p3"></space-picker>
171
- </html-demo>
172
-
173
- <html-demo>
174
- <space-picker spaces="bar, oklch, p3, srgb, foo" value="baz"></space-picker>
175
- </html-demo>
176
-
177
- <html-demo>
178
- <space-picker onspacechange="this.nextElementSibling.textContent = this.value"></space-picker>
179
- <output></output>
180
- </html-demo>
181
-
182
- <html-demo>
183
- <space-picker id="space_picker" spaces="oklch, p3, srgb" value="p3"></space-picker>
184
-
185
- <script type="module">
186
- space_picker.groupBy = (space) => {
187
- let isPolar = space.coords.h?.type === "angle";
188
- return isPolar ? "Polar" : "Rectangular";
189
- };
190
- </script>
191
- </html-demo> -->
192
-
193
- <!-- <color-scale
194
- colors="10: oklch(22.74% 0.05346 127.56), 20: oklch(31.363% 0.07637 127.56), 30: oklch(38.586% 0.09929 127.56), 40: oklch(45.71% 0.1222 127.56), 50: oklch(55.583% 0.14511 127.56), 60: oklch(65.706% 0.16802 127.56), 70: oklch(74.234% 0.14016 127.56), 80: oklch(82.712% 0.09698 127.56), 90: oklch(91.289% 0.04521 127.56), 95: oklch(95.028% 0.0168 127.56), 05: oklch(17.028% 0.04201 127.56)"></color-scale> -->
195
-
196
- <!-- <color-chart y="oklch.c" info="L: oklch.l, C: oklch.c, H: oklch.h">
197
- <color-scale
198
- colors="opencolor 0 / 0: #f4fce3, opencolor 1 / 11.11111111111111: #e9fac8, opencolor 2 / 22.22222222222222: #d8f5a2, opencolor 3 / 33.33333333333333: #c0eb75, opencolor 4 / 44.44444444444444: #a9e34b, opencolor 5 / 55.55555555555556: #94d82d, opencolor 6 / 66.66666666666666: #82c91e, opencolor 7 / 77.77777777777777: #74b816, opencolor 8 / 88.88888888888889: #66a80f, opencolor 9 / 100: #5c940d">
199
- </color-scale>
200
- </color-chart> -->
201
- <!-- <label>
202
- Space:
203
- <select onchange="this.parentNode.nextElementSibling.nextElementSibling.space = this.value">
204
- <option value="cam16-jmh">CAM16-JMh</option>
205
- <option value="hct">HCT</option>
206
- <option value="hpluv">HPLuv</option>
207
- <option value="hsl">HSL</option>
208
- <option value="hsluv">HSLuv</option>
209
- <option value="hsv">HSV</option>
210
- <option value="hwb">HWB</option>
211
- <option value="lch">LCH</option>
212
- <option value="lchuv">LChuv</option>
213
- <option value="oklch" selected>Oklch</option>
214
- <option value="oklrch">Oklrch</option>
215
- <option value="okhsl">Okhsl</option>
216
- <option value="okhsv">Okhsv</option>
217
- </select>
218
- </label>
219
- <label>Coord:
220
- <select onchange="this.parentNode.nextElementSibling.y = this.value">
221
- <option selected>oklch.l</option>
222
- <option>oklch.c</option>
223
- <option>oklch.h</option>
224
- </select>
225
- </label>
226
- <color-chart y="oklch.l" info="L: oklch.l, C: oklch.c, H: oklch.h">
227
- <color-scale
228
- colors="Red 50: #fef2f2, Red 100: #fee2e2, Red 200: #fecaca, Red 300: #fca5a5, Red 400: #f87171, Red 500: #ef4444, Red 600: #dc2626, Red 700: #b91c1c, Red 800: #991b1b, Red 900: #7f1d1d, 950: #450a0a"
229
- info="oklch.l"></color-scale>
230
- <color-scale
231
- colors="Orange 50: #fff7ed, Orange 100: #ffedd5, Orange 200: #fed7aa, Orange 300: #fdba74, Orange 400: #fb923c, Orange 500: #f97316, Orange 600: #ea580c, Orange 700: #c2410c, Orange 800: #9a3412, Orange 900: #7c2d12, Orange 950: #431407"></color-scale>
232
- <color-scale
233
- colors="Yellow 50: #fefce8, Yellow 100: #fef9c3, Yellow 200: #fef08a, Yellow 300: #fde047, Yellow 400: #facc15, Yellow 500: #eab308, Yellow 600: #ca8a04, Yellow 700: #a16207, Yellow 800: #854d0e, Yellow 900: #713f12, Yellow 950: #422006"></color-scale>
234
- </color-chart> -->
235
- <!-- <color-swatch id="dynamic_static">oklch(70% 0.25 138)</color-swatch>
236
- <button onclick='dynamic_static.color = "oklch(60% 0.15 0)"'>Change color</button> -->
237
- <!-- <color-picker id="dynamic_static" space="oklch"></color-picker>
238
- <button onclick='dynamic_static.color = "gold"'>Change color</button> -->
239
-
240
- <!--<html-demo>
241
- <color-swatch info="deltaE2000, WCAG21 contrast" vs="gold" size="large">
242
- oklch(65% 0.15 210)
243
- </color-swatch>
244
- </html-demo>-->
245
- <!-- <color-swatch info="L: oklch.l, C: oklch.c, H: oklch.h" vs="gold" size="large">
246
- oklch(65% 0.15 210)
247
- </color-swatch> -->
248
- <!-- <html-demo>
249
- <color-swatch info="L: oklch.l, C: oklch.c, H: oklch.h" vs="gold" size="large">
250
- oklch(65% 0.15 210)
251
- </color-swatch>
252
- </html-demo>
253
-
254
- <html-demo>
255
- <color-swatch info="L: oklch.l, C: oklch.c, H: oklch.h, deltaE.2000, contrast.Weber" vs="gold" size="large">
256
- oklch(65% 0.15 210)
257
- </color-swatch>
258
- </html-demo>
259
-
260
- <html-demo>
261
- <color-swatch info="L: oklch.l, C: oklch.c, H: oklch.h, deltaE.2000, foo" vs="blue">
262
- oklch(65% 0.15 210)
263
- </color-swatch>
264
- </html-demo> -->
265
- <!-- <color-swatch info="L: oklch.l, C: oklch.c, H: oklch.h" vs="oklch(65% 0.15 210)" size="large">
266
- oklch(65% 0.15 210)
267
- </color-swatch> -->
268
- <!-- <color-swatch data="L: oklch.l, C: oklch.c, H: oklch.h, ΔE: 2000" vs="oklch(55% 0.1 210)" size="large">
269
- oklch(55% 0.15 230)
270
- </color-swatch>
271
- <color-swatch data="L: oklch.l, C: oklch.c, H: oklch.h" vs="blue">oklch(65% 0.15 210)</color-swatch> -->
272
- <!-- <color-swatch coords="L: l, C: c, H: h">oklch(80% 50% 70)</color-swatch> -->
273
- <!-- <color-swatch size="large">green</color-swatch> -->
274
- <!-- <div id="future_swatch_container"></div>
275
- <script>
276
- let swatch = document.createElement("color-swatch");
277
- swatch.color = "oklch(65% 0.15 210)";
278
- swatch.setAttribute("size", "large");
279
- swatch.textContent = "Turquoise";
280
- swatch.coords = "L: oklch.l, C: oklch.c, H: oklch.h";
281
- future_swatch_container.append(swatch);
282
- </script> -->
283
-
284
- <!-- <color-scale colors="#e3fafc, #0b7285" steps="4" space="oklch" info="L: oklch.l, C: oklch.c" deltas></color-scale> -->
285
- <!-- <color-scale space="oklch" info="L: oklch.l, C: oklch.c, H: oklch.h"
286
- colors="#e3fafc, #c5f6fa, #99e9f2, #66d9e8, #3bc9db"></color-scale> -->
287
- <!-- <color-scale colors="rgb(255 0 0), rgb(0 0 255)" steps="4" space="oklch"></color-scale> -->
288
-
289
- <!-- <color-scale
290
- colors="50: #ecfeff, 100: #cffafe, 200: #a5f3fc, 300: #67e8f9, 400: #22d3ee, 500: #06b6d4, 600: #0891b2, 700: #0e7490, 800: #155e75, 900: #164e63, 950: #083344"
291
- info="L: lch.l, C: lch.c, H: lch.h"></color-scale>
292
- <color-scale
293
- colors="50: #fef2f2, 100: #fee2e2, 200: #fecaca, 300: #fca5a5, 400: #f87171, 500: #ef4444, 600: #dc2626, 700: #b91c1c, 800: #991b1b, 900: #7f1d1d, 950: #450a0a"
294
- info="L: lch.l, C: lch.c, H: lch.h"></color-scale>
295
- <color-scale
296
- colors="50: #fff7ed, 100: #ffedd5, 200: #fed7aa, 300: #fdba74, 400: #fb923c, 500: #f97316, 600: #ea580c, 700: #c2410c, 800: #9a3412, 900: #7c2d12, 950: #431407"
297
- info="L: lch.l, C: lch.c, H: lch.h"></color-scale>
298
- <color-scale
299
- colors="50: #fefce8, 100: #fef9c3, 200: #fef08a, 300: #fde047, 400: #facc15, 500: #eab308, 600: #ca8a04, 700: #a16207, 800: #854d0e, 900: #713f12, 950: #422006"
300
- info="L: lch.l, C: lch.c, H: lch.h"></color-scale> -->
301
- <!-- <color-scale space="oklch" colors="
302
- #f8f9fa,
303
- #f1f3f5,
304
- #e9ecef
305
- " info="L: oklch.l, C: oklch.c, H: oklch.h, deltaE2000" vs="previous"></color-scale>
306
-
307
-
308
- <color-scale space="oklch" colors="
309
- #f8f9fa,
310
- #f1f3f5,
311
- #e9ecef
312
- " info="L: oklch.l, C: oklch.c, H: oklch.h, deltaE2000" vs="next"></color-scale>
313
-
314
- <color-scale space="oklch" colors="
315
- #f8f9fa,
316
- #f1f3f5,
317
- #e9ecef
318
- " info="L: oklch.l, C: oklch.c, H: oklch.h, deltaE2000" vs="#f8f9fa"></color-scale> -->
319
-
320
- <!-- <color-scale space="oklch" colors="
321
- #f8f9fa,
322
- #f1f3f5,
323
- #e9ecef,
324
- #dee2e6,
325
- #ced4da,
326
- #adb5bd,
327
- #868e96,
328
- #495057,
329
- #343a40,
330
- #212529
331
- " info="L: oklch.l, C: oklch.c, H: oklch.h, deltaE2000" vs></color-scale> -->
332
-
333
- <!-- <color-inline value="oklch(80% 50% 70)"></color-inline> -->
334
- <!-- <button onclick="this.nextElementSibling.value = Math.random()">Random color</button>
335
- <color-slider space="oklch" stops="gold, darkcyan, indigo"
336
- oncolorchange="this.nextElementSibling.textContent = this.color"></color-slider> -->
337
- <!-- <button onclick="this.nextElementSibling.textContent = 'gold'">Random color</button>
338
- <color-swatch>red</color-swatch> -->
339
-
340
- <!-- <color-swatch size="large" oncolorchange="this.nextElementSibling.textContent = this.color">
341
- <input value="oklch(90% .8 250)" />
342
- </color-swatch>
343
- <output></output> -->
344
-
345
- <!--<color-chart y="oklch.c" info="L: oklch.l, C: oklch.c, H: oklch.h">
346
- <color-scale class="js"></color-scale>
347
- <color-scale class="wa"></color-scale>
348
- </color-chart>
349
- <color-picker space="oklch" id="color_picker"></color-picker>
350
-
351
- <script type="module">
352
- // import Color from "https://colorjs.io/dist/color.js";
353
- for (let colorScale of document.querySelectorAll("color-chart color-scale.js")) {
354
- colorScale.colors = "10: oklch(23.363% 0.01102 274.75), 20: oklch(32.076% 0.01602 274.75), 30: oklch(39.389% 0.02119 274.75), 40: oklch(46.601% 0.02665 274.75), 50: oklch(56.564% 0.03294 274.75), 60: oklch(66.951% 0.02512 274.75), 70: oklch(75.289% 0.01834 274.75), 80: oklch(83.576% 0.0119 274.75), 90: oklch(91.963% 0.00568 274.75), 95: oklch(95.607% 0.00264 274.75), 05: oklch(17.607% 0.00857 274.75)";
355
- }
356
- // let color = new Color("oklch(56.564% 0.03294 274.75)");
357
- let color = "oklch(56.564% 0.03294 274.75)";
358
- color_picker.color = color;
359
- </script>-->
360
-
361
- <!-- <html-demo>
362
- <color-picker id="custom-space-select" space="oklch" color="oklch(60% 30% 180)">
363
- <select slot="space-picker" size="3" class="horizontal" onchange="this.parentElement.space = this.value">
364
- <option value="oklch" selected>OKLCh</option>
365
- <option value="hwb">HWB</option>
366
- <option value="hpluv">HPLuv</option>
367
- </select>
368
- </color-picker>
369
-
370
- <style>
371
- select.horizontal {
372
- writing-mode: tb;
373
- field-sizing: content;
374
-
375
- option {
376
- writing-mode: horizontal-tb;
377
- padding: .5em;
378
- }
379
- }
380
- </style>
381
- </html-demo> -->
382
-
383
- <!--<html-demo>
384
- <space-picker onspacechange="console.log(this.selectedSpace)"></space-picker>
385
- </html-demo>-->
386
-
387
- <!-- <html-demo>
388
- <channel-picker></channel-picker>
389
- </html-demo>
390
-
391
- <html-demo>
392
- <channel-picker value="foo.bar"></channel-picker>
393
- </html-demo>
394
-
395
- <html-demo>
396
- <channel-picker value="oklch.bar"></channel-picker>
397
- </html-demo>
398
-
399
- <html-demo>
400
- <channel-picker value="foo"></channel-picker>
401
- </html-demo> -->
402
-
403
- <!-- <html-demo>
404
- <channel-picker value="p3.b"></channel-picker>
405
- </html-demo>
406
-
407
- <html-demo>
408
- <channel-picker id="picker" value="hsl.h"></channel-picker>
409
-
410
- <style>
411
- #picker::part(space_picker) {
412
- display: none;
413
- }
414
- </style>
415
- </html-demo> -->
416
-
417
- <!-- <html-demo>
418
- <label>Coord:
419
- <channel-picker onvaluechange="this.parentNode.nextElementSibling.y = this.value"></channel-picker>
420
- </label>
421
- <color-chart>
422
- <color-scale colors="Red 50: #fef2f2, Red 100: #fee2e2, Red 200: #fecaca, Red 300: #fca5a5, Red 400: #f87171, Red 500: #ef4444, Red 600: #dc2626, Red 700: #b91c1c, Red 800: #991b1b, Red 900: #7f1d1d, Red 950: #450a0a"></color-scale>
423
- <color-scale colors="Orange 50: #fff7ed, Orange 100: #ffedd5, Orange 200: #fed7aa, Orange 300: #fdba74, Orange 400: #fb923c, Orange 500: #f97316, Orange 600: #ea580c, Orange 700: #c2410c, Orange 800: #9a3412, Orange 900: #7c2d12, Orange 950: #431407"></color-scale>
424
- <color-scale colors="Yellow 50: #fefce8, Yellow 100: #fef9c3, Yellow 200: #fef08a, Yellow 300: #fde047, Yellow 400: #facc15, Yellow 500: #eab308, Yellow 600: #ca8a04, Yellow 700: #a16207, Yellow 800: #854d0e, Yellow 900: #713f12, Yellow 950: #422006"></color-scale>
425
- </color-chart>
426
- </html-demo> -->
427
-
428
- <!--<html-demo>
429
- <channel-picker spaces="p3, oklch, hsl"></channel-picker>
430
- </html-demo>-->
431
-
432
-
433
- <script src="./index.js" type="module"></script>
434
- <script src="./src/color-picker/color-picker.js" type="module"></script>
435
- <!-- <script src="./src/color-slider/color-slider.js" type="module"></script> -->
436
- <script src="./src/color-swatch/color-swatch.js" type="module"></script>
437
- <script src="./src/color-scale/color-scale.js" type="module"></script>
438
- <script src="./src/color-chart/color-chart.js" type="module"></script>
439
- <script src="./src/space-picker/space-picker.js" type="module"></script>
440
- <script src="./src/channel-picker/channel-picker.js" type="module"></script>
441
- <!-- <script src="./src/gamut-badge/gamut-badge.js" type="module"></script>-->
442
- <!-- <script src="./src/color-inline/color-inline.js" type="module"></script> -->
443
- <script src="https://nudeui.com/elements/html-demo/html-demo.js" type="module"></script>
444
-
445
- </body>
446
-
447
- </html>