UNPKG

color-elements

Version:

A set of web components for working with color. A Color.js project.

170 lines (140 loc) 3.79 kB
import ColorElement from "../common/color-element.js"; import "../color-swatch/color-swatch.js"; const Self = class ColorScale extends ColorElement { static tagName = "color-scale"; static url = import.meta.url; static dependencies = new Set(["color-swatch"]); static styles = import("./color-scale.css", { with: { type: "css" } }).catch( () => new URL("./color-scale.css", import.meta.url), ); static shadowTemplate = ` <div id=swatches></div> <slot></slot>`; constructor () { super(); this._el = { slot: this.shadowRoot.querySelector("slot"), swatches: this.shadowRoot.getElementById("swatches"), }; } connectedCallback () { super.connectedCallback?.(); this._el.swatches.addEventListener("colorchange", this, { capture: true }); } disconnectedCallback () { this.#swatches = []; this._el.swatches.removeEventListener("colorchange", this, { capture: true }); } handleEvent (event) { this.dispatchEvent(new event.constructor(event.type, { ...event })); } propChangedCallback ({ name, prop, detail: change }) { if (name === "computedColors") { // Re-render swatches this.render(); } } #swatches = []; render () { let colors = this.computedColors; if (!colors) { return; } let colorCount = colors.length; let i = 0; let newSwatches = []; for (let { name, color } of colors) { let swatch = (this.#swatches[i] = this._el.swatches.children[i]); if (!swatch) { this.#swatches[i] = swatch = document.createElement("color-swatch"); swatch.setAttribute("size", "large"); swatch.setAttribute("part", "color-swatch"); swatch.setAttribute("exportparts", "swatch, info, gamut, label: swatch-label"); newSwatches.push(swatch); } swatch.color = color; swatch.label = name; if (this.info) { swatch.info = this.info; } i++; } if (newSwatches.length > 0) { this._el.swatches.append(...newSwatches); } else if (colorCount < this._el.swatches.children.length) { // Remove but keep them around in this.#swatches [...this._el.swatches.children].slice(colorCount).forEach(child => child.remove()); } } static props = { colors: { type: { is: Object, // Support overriding the Color object get values () { return ColorScale.Color; }, defaultKey: (v, i) => v, }, }, space: { default: "oklch", parse (value) { let ColorSpace = ColorScale.Color.Space; if (value instanceof ColorSpace || value === null || value === undefined) { return value; } value += ""; return ColorSpace.get(value); }, stringify (value) { return value?.id; }, }, steps: { type: Number, default: 0, }, computedColors: { get () { if (!this.colors) { return null; } let colors = Object.entries(this.colors).map(([name, color]) => ({ name, color })); if (this.steps > 0) { // Insert intermediate steps let tessellated = []; for (let i = 1; i < colors.length; i++) { let start = colors[i - 1]; let end = colors[i]; let steps = ColorScale.Color.steps(start.color, end.color, { space: this.space, steps: this.steps + 2, }); steps.shift(); steps.pop(); steps = steps.map(color => ({ name: color + "", color })); tessellated.push(start, ...steps); if (i === colors.length - 1) { // Only add the last color at the end // In all other iterations, it’s the same as the start of the next pair tessellated.push(end); } } colors = tessellated; } return colors; }, additionalDependencies: ["info"], }, info: {}, }; static events = { colorschange: { propchange: "computedColors", }, }; }; Self.define(); export default Self;