view web/light9-color-picker.ts @ 2405:69ca2b2fc133

overcomplicated attempt at persisting the pane layout in the rdf graph this was hard because we have to somehow wait for the graph to load before config'ing the panes
author drewp@bigasterisk.com
date Fri, 17 May 2024 16:58:26 -0700
parents 4556eebe5d73
children
line wrap: on
line source

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;
    });
  }
}