diff web/light9-color-picker.ts @ 2376:4556eebe5d73

topdir reorgs; let pdm have its src/ dir; separate vite area from light9/
author drewp@bigasterisk.com
date Sun, 12 May 2024 19:02:10 -0700
parents light9/web/light9-color-picker.ts@18d6bdd422f2
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/light9-color-picker.ts	Sun May 12 19:02:10 2024 -0700
@@ -0,0 +1,106 @@
+import debug from "debug";
+import { css, html, LitElement, PropertyValueMap } from "lit";
+import { customElement, property, queryAsync, state } from "lit/decorators.js";
+import color from "onecolor";
+import { ClientCoord, pickerFloat } from "./floating_color_picker";
+export { Slider } from "@material/mwc-slider";
+
+const log = debug("control.color");
+type int8 = number;
+
+@customElement("light9-color-picker")
+export class Light9ColorPicker extends LitElement {
+  static styles = [
+    css`
+      :host {
+        position: relative;
+        display: flex;
+        align-items: center;
+        flex-wrap: wrap;
+        user-select: none;
+      }
+
+      #swatch {
+        display: inline-block;
+        width: 50px;
+        height: 30px;
+        margin-right: 3px;
+        border: 1px solid #333;
+      }
+
+      mwc-slider {
+        width: 160px;
+      }
+
+      #vee {
+        display: flex;
+        align-items: center;
+      }
+    `,
+  ];
+  render() {
+    return html`
+      <div id="swatch" style="background-color: ${this.color}; border-color: ${this.hueSatColor}" @mousedown=${this.startFloatingPick}></div>
+      <span id="vee"> V: <mwc-slider id="value" .value=${this.value} step="1" min="0" max="255" @input=${this.onVSliderChange}></mwc-slider> </span>
+    `;
+  }
+
+  // Selected color. Read/write. Equal to value*hueSatColor. Never null.
+  @property() color: string = "#000";
+
+  @state() hueSatColor: string = "#fff"; // always full value
+  @state() value: int8 = 0;
+
+  @queryAsync("#swatch") swatchEl!: Promise<HTMLElement>;
+
+  connectedCallback(): void {
+    super.connectedCallback();
+    pickerFloat.pageInit();
+  }
+  update(changedProperties: PropertyValueMap<this>) {
+    super.update(changedProperties);
+    if (changedProperties.has("color")) {
+      this.setColor(this.color);
+    }
+    if (changedProperties.has("value") || changedProperties.has("hueSatColor")) {
+      this.updateColorFromHSV();
+
+      this.dispatchEvent(new CustomEvent("input", { detail: { value: this.color } }));
+
+      this.swatchEl.then((sw) => {
+        sw.style.borderColor = this.hueSatColor;
+      });
+    }
+  }
+
+  private updateColorFromHSV() {
+    this.color = color(this.hueSatColor)
+      .value(this.value / 255)
+      .hex();
+  }
+
+  private onVSliderChange(ev: CustomEvent) {
+    this.value = ev.detail.value;
+  }
+
+  // for outside users of the component
+  setColor(col: string) {
+    if (col === null) throw new Error("col===null");
+    if (typeof col !== "string") throw new Error("typeof col=" + typeof col);
+    this.value = color(col).value() * 255;
+
+    // don't update this if only the value changed, or we desaturate
+    this.hueSatColor = color(col).value(1).hex();
+  }
+
+  private startFloatingPick(ev: MouseEvent) {
+    if (this.value < (20 as int8)) {
+      log("boost");
+      this.value = 255 as int8;
+      this.updateColorFromHSV();
+    }
+    pickerFloat.startPick(new ClientCoord(ev.clientX, ev.clientY), this.color, (hsc: string) => {
+      this.hueSatColor = hsc;
+    });
+  }
+}