UNPKG

ranui

Version:

A framework-agnostic Web Components UI library built on native custom elements, with TypeScript types, light/dark theming, SSR and PWA support.

240 lines (239 loc) 17.7 kB
import { B as x, F as d, T as b, _ as h, h as P, i as s } from "./factory-WDxu11V0.js"; import { t as m } from "./events-Cqz3ramM.js"; import "./builder-EH76YCFS.js"; import { a as k, i as y, l as p, n as w, o as S, t as A } from "./utils-U-9uH7EX.js"; import { a as $, n as _ } from "./ssr-BzykYefm.js"; import { i as C, n as D } from "./a11y-ZSlIUH9B.js"; import "./input-DEoPNM0j.js"; import "./select-E396XACJ.js"; import "./popover-Bw11RB79.js"; import { HEX_COLOR_REGEX as I, RGBA_REGEX as E, RGB_REGEX as R, hexToHsv as H, hsvToRgb as g, range as c, rgbToHex as f, rgbToHsv as v } from "ranuts/utils"; var V = ":host{box-sizing:border-box;min-width:var(--ran-colorpicker-min-width, var(--ran-size-7, 32px));height:var(--ran-colorpicker-height, var(--ran-size-7, 32px));border-radius:var(--ran-colorpicker-border-radius, var(--ran-radius-md, 8px));border:var(--ran-colorpicker-border, 1px solid var(--ran-color-border, #eaeaea));cursor:pointer;display:var(--ran-colorpicker-host-display, inline-flex);align-items:center;justify-content:center;transition:var(--ran-colorpicker-transition, none);background:var(--ran-colorpicker-background, var(--ran-color-bg-elevated, #ffffff));padding:var(--ran-colorpicker-padding, var(--ran-space-1, 4px))}:host(:hover){border-color:var(--ran-colorpicker-hover-border-color, var(--ran-color-border-hover, var(--ran-gray-500)))}.ran-colorpicker-block{position:relative;border-radius:var(--ran-colorpicker-block-border-radius, var(--ran-radius-sm, 4px));width:var(--ran-colorpicker-block-width, var(--ran-size-4, 24px));height:var(--ran-colorpicker-block-height, var(--ran-size-4, 24px));box-shadow:inset 0 0 0 1px var(--ran-gray-alpha-200, rgba(0, 0, 0, .09));background-image:conic-gradient(var(--ran-gray-alpha-100, rgba(0, 0, 0, .06)) 0 25%,transparent 0 50%,var(--ran-gray-alpha-100, rgba(0, 0, 0, .06)) 0 75%,transparent 0);background-size:50% 50%}.ran-colorpicker-block[disabled]{cursor:var(--ran-colorpicker-disabled-cursor, not-allowed);opacity:var(--ran-colorpicker-disabled-opacity, .5)}.ran-colorpicker-inner{width:100%;height:100%;border-radius:inherit}", F = ".ran-color-picker-inner{box-sizing:border-box}.ran-color-picker-inner-content{box-sizing:border-box;display:flex;flex-direction:column;gap:12px;width:224px;padding:12px;font-family:var(--ran-font-family, inherit)}.ran-color-picker-inner-content *,.ran-color-picker-inner-content *:before,.ran-color-picker-inner-content *:after{box-sizing:border-box}.ran-color-picker-palette{position:relative;width:100%;height:160px;border-radius:var(--ran-radius-sm, 6px);overflow:hidden;cursor:crosshair;box-shadow:inset 0 0 0 1px var(--ran-gray-alpha-200, rgba(0, 0, 0, .09));touch-action:none}.ran-color-picker-saturation{position:absolute;inset:0;border-radius:inherit;background-image:linear-gradient(to top,#000,#0000),linear-gradient(to right,#fff,#fff0)}.ran-color-picker-palette-dot{position:absolute;top:0;left:0;z-index:2;width:14px;height:14px;transform:translate(-50%,-50%);border-radius:50%;border:2px solid #fff;box-shadow:0 0 0 1px #0003,0 1px 3px #00000059;pointer-events:none}.ran-color-picker-controls{display:flex;align-items:center;gap:12px}.ran-color-picker-preview{position:relative;flex:none;width:28px;height:28px;border-radius:50%;overflow:hidden;box-shadow:inset 0 0 0 1px var(--ran-gray-alpha-200, rgba(0, 0, 0, .09));background-image:conic-gradient(var(--ran-gray-alpha-100, rgba(0, 0, 0, .06)) 0 25%,transparent 0 50%,var(--ran-gray-alpha-100, rgba(0, 0, 0, .06)) 0 75%,transparent 0);background-size:12px 12px}.ran-color-picker-preview-inner{position:absolute;inset:0;border-radius:inherit}.ran-color-picker-sliders{flex:1;min-width:0;display:flex;flex-direction:column;gap:12px}.ran-color-picker-slider{position:relative;height:10px;border-radius:999px;cursor:pointer;box-shadow:inset 0 0 0 1px var(--ran-gray-alpha-200, rgba(0, 0, 0, .09));touch-action:none}.ran-color-picker-slider-hue{background:linear-gradient(to right,red,#ff0,#0f0,#0ff,#00f,#f0f,red)}.ran-color-picker-slider-alpha{background-image:conic-gradient(var(--ran-gray-alpha-100, rgba(0, 0, 0, .06)) 0 25%,transparent 0 50%,var(--ran-gray-alpha-100, rgba(0, 0, 0, .06)) 0 75%,transparent 0);background-size:8px 8px}.ran-color-picker-slider-alpha-track{position:absolute;inset:0;border-radius:inherit}.ran-color-picker-slider-thumb{position:absolute;top:50%;left:0;z-index:1;width:14px;height:14px;transform:translate(-50%,-50%);border-radius:50%;border:2px solid #fff;box-shadow:0 0 0 1px #0003,0 1px 3px #00000059;pointer-events:none}.ran-color-picker-input-container{display:flex;align-items:center;gap:8px}.ran-color-picker-format{flex:none;width:68px}.ran-color-picker-value{flex:1;min-width:0}", u = 360, T = class extends _ { colorpicker; colorpickerInner; context; _shadowDom; _events = new m(); _effectDisposers = []; popoverBlock; popoverContent; colorPickerInner; colorPickerPalette; colorPickerSaturation; colorPickerPaletteDot; colorPickerHueSlider; colorPickerHueThumb; colorPickerAlphaSlider; colorPickerAlphaTrack; colorPickerAlphaThumb; colorPickerPreviewInner; colorPickerValueInput; colorPickerFormatSelect; colorPickerPaletteSelect; _activeSlider = null; _format = "HEX"; _editingInput = !1; static get observedAttributes() { return [ "disabled", "value", "sheet" ]; } constructor() { super(), this._shadowDom = A(this, V); const e = b(), t = b(), r = b(), i = s().class("ran-colorpicker-inner").ref(r).part("swatch").build(), o = s().class("ran-colorpicker-block").ref(t).part("block").children(i).build(), a = h("r-content").ref(e).class("ran-content").build(), n = h("r-popover").class("ran-popover").attr("trigger", "click").cssVar("ran-popover-content-padding", "0").children(o, a).build(); this._shadowDom.appendChild(n), this.popoverBlock = n, this.popoverContent = k(e, "r content"), this.colorpicker = k(t, "block"), this.colorpickerInner = k(r, "inner"), this.colorpicker.setAttribute("role", "button"), this.colorpicker.setAttribute("tabindex", "0"), this.colorpicker.setAttribute("aria-haspopup", "dialog"), this.colorpicker.setAttribute("aria-label", "Choose color"), this.colorPickerPaletteSelect = !1, this.createContext(); } get value() { return this.context?.value.getter() || ""; } set value(e) { this.setAttribute("value", e); } get sheet() { return w(this, "sheet"); } set sheet(e) { y(this, "sheet", e); } get disabled() { return p(this); } set disabled(e) { e === !1 || e === void 0 || e === null ? this.removeAttribute("disabled") : this.setAttribute("disabled", ""); } handlerExternalCss = () => { S(this, this._shadowDom, "sheet", null, this.sheet); }; syncDisabledState = () => { const e = p(this); this.context?.disabled.setter(e), e ? (this.setAttribute("aria-disabled", "true"), this.colorpicker?.setAttribute("disabled", "")) : (this.removeAttribute("aria-disabled"), this.colorpicker?.removeAttribute("disabled")), this.colorpicker?.setAttribute("aria-disabled", e ? "true" : "false"), this.colorpicker?.setAttribute("tabindex", e ? "-1" : "0"); }; blockWhenDisabled = (e) => { p(this) && (e.stopImmediatePropagation(), e.preventDefault()); }; createContext = () => { const e = (t) => { const [r, i] = x(t); return { getter: r, setter: i }; }; this.context = { value: e(""), disabled: e(!1), hue: e(0), saturation: e(0), lightness: e(100), transparency: e(100) }; }; currentRgba = () => { const { hue: e, saturation: t, lightness: r, transparency: i } = this.context, [o, a, n] = g(e.getter(), t.getter(), r.getter()); return { r: o, g: a, b: n, a: i.getter() / 100 }; }; currentValue = () => { const { r: e, g: t, b: r, a: i } = this.currentRgba(); return i < 1 ? `rgba(${e}, ${t}, ${r}, ${Number(i.toFixed(2))})` : f(e, t, r); }; currentDisplay = () => { const { r: e, g: t, b: r, a: i } = this.currentRgba(); return this._format === "RGB" ? i < 1 ? `rgba(${e}, ${t}, ${r}, ${Number(i.toFixed(2))})` : `rgb(${e}, ${t}, ${r})` : f(e, t, r); }; paintSwatch = () => { const { r: e, g: t, b: r, a: i } = this.currentRgba(); this.colorpickerInner?.style.setProperty("background", `rgba(${e}, ${t}, ${r}, ${Number(i.toFixed(3))})`); }; updateColorValue = (e) => { if (e === this.context?.value.getter()) return; const t = e.replace(/\s+/g, ""), r = I.exec(e), i = E.exec(t), o = R.exec(t); if (r) { const [a, n, l] = H(r[0]); this.context.hue.setter(a), this.context.saturation.setter(n), this.context.lightness.setter(l), this.context.transparency.setter(100); } else if (i) { const [a, n, l] = v(Number(i[1]), Number(i[2]), Number(i[3])); this.context.hue.setter(a), this.context.saturation.setter(n), this.context.lightness.setter(l), this.context.transparency.setter(Number(i[4]) * 100); } else if (o) { const [a, n, l] = v(Number(o[1]), Number(o[2]), Number(o[3])); this.context.hue.setter(a), this.context.saturation.setter(n), this.context.lightness.setter(l), this.context.transparency.setter(100); } else return; this.setAttribute("value", e), this.context?.value.setter(e), this.paintSwatch(); }; emitChange = () => { const e = this.currentValue(), { r: t, g: r, b: i, a: o } = this.currentRgba(); this.context?.value.setter(e), this.setAttribute("value", e), this.dispatchEvent(new CustomEvent("change", { detail: { value: e, hex: f(t, r, i), rgb: `rgb(${t}, ${r}, ${i})`, rgba: `rgba(${t}, ${r}, ${i}, ${Number(o.toFixed(2))})`, alpha: Number(o.toFixed(2)) }, bubbles: !0, composed: !0 })); }; palettePointerDown = (e) => { e.preventDefault(), this.colorPickerPaletteSelect = !0, this.updatePaletteFromEvent(e); }; updatePaletteFromEvent = (e) => { if (!this.colorPickerPalette) return; const { left: t, top: r, width: i, height: o } = this.colorPickerPalette.getBoundingClientRect(); if (!i || !o) return; const a = c(e.clientX - t, 0, i), n = c(e.clientY - r, 0, o); this.context.saturation.setter(a / i * 100), this.context.lightness.setter((1 - n / o) * 100), this.emitChange(); }; sliderPointerDown = (e) => (t) => { t.preventDefault(), this._activeSlider = e, this.updateSliderFromEvent(e, t); }; updateSliderFromEvent = (e, t) => { const r = e === "hue" ? this.colorPickerHueSlider : this.colorPickerAlphaSlider; if (!r) return; const { left: i, width: o } = r.getBoundingClientRect(); if (!o) return; const a = c(t.clientX - i, 0, o) / o; e === "hue" ? this.context.hue.setter(a * u) : this.context.transparency.setter(a * 100), this.emitChange(); }; onPointerMove = (e) => { const t = e; this.colorPickerPaletteSelect ? this.updatePaletteFromEvent(t) : this._activeSlider && this.updateSliderFromEvent(this._activeSlider, t); }; initSliderA11y = (e, t, r) => { e.setAttribute("role", "slider"), e.setAttribute("tabindex", "0"), e.setAttribute("aria-label", t), e.setAttribute("aria-orientation", "horizontal"), e.setAttribute("aria-valuemin", "0"), e.setAttribute("aria-valuemax", String(r)); }; sliderKeydown = (e) => (t) => { const r = e === "hue" ? u : 100, i = e === "hue" ? this.context.hue : this.context.transparency, o = C(t, { current: i.getter(), min: 0, max: r, step: 1 }); o !== void 0 && (t.preventDefault(), i.setter(c(o, 0, r)), this.emitChange()); }; onPointerUp = () => { this.colorPickerPaletteSelect = !1, this._activeSlider = null; }; onSwatchKeydown = (e) => { p(this) || D(e) && (e.preventDefault(), this.colorpicker?.click()); }; onValueInput = (e) => { const t = e.target, r = e.detail?.value ?? t?.value; typeof r == "string" && (this._editingInput = !0, this.updateColorValue(r.trim()), this._editingInput = !1, this.emitChange()); }; onFormatChange = (e) => { const t = e.detail?.value; this._format = t === "RGB" ? "RGB" : "HEX", this.syncValueInput(); }; syncValueInput = () => { this._editingInput || !this.colorPickerValueInput || (this.colorPickerValueInput.value = this.currentDisplay()); }; setupEffects = () => { this._effectDisposers.push(d(() => { const [e, t, r] = g(this.context.hue.getter(), 100, 100); this.colorPickerSaturation?.style.setProperty("background-color", `rgb(${e}, ${t}, ${r})`); }), d(() => { const e = c(this.context.saturation.getter(), 0, 100), t = c(this.context.lightness.getter(), 0, 100); this.colorPickerPaletteDot?.style.setProperty("left", `${e}%`), this.colorPickerPaletteDot?.style.setProperty("top", `${100 - t}%`); }), d(() => { const e = this.context.hue.getter(), [t, r, i] = g(e, 100, 100); this.colorPickerHueThumb?.style.setProperty("left", `${e / u * 100}%`), this.colorPickerHueThumb?.style.setProperty("background", `rgb(${t}, ${r}, ${i})`), this.colorPickerHueSlider?.setAttribute("aria-valuenow", String(Math.round(e))); }), d(() => { const { r: e, g: t, b: r, a: i } = this.currentRgba(), o = `rgb(${e}, ${t}, ${r})`, a = `rgba(${e}, ${t}, ${r}, ${Number(i.toFixed(3))})`; this.colorPickerAlphaTrack?.style.setProperty("background", `linear-gradient(to right, rgba(${e}, ${t}, ${r}, 0), ${o})`), this.colorPickerAlphaThumb?.style.setProperty("left", `${i * 100}%`), this.colorPickerAlphaThumb?.style.setProperty("background", a), this.colorPickerPreviewInner?.style.setProperty("background", a), this.colorpickerInner?.style.setProperty("background", a), this.colorPickerAlphaSlider?.setAttribute("aria-valuenow", String(Math.round(i * 100))), this.colorPickerAlphaSlider?.setAttribute("aria-valuetext", `${Math.round(i * 100)}%`), this.syncValueInput(); })); }; disposeEffects = () => { for (const e of this._effectDisposers) e(); this._effectDisposers = []; }; openColorPicker = () => { if (p(this) || this.colorPickerInner) return; this.colorPickerSaturation = s().class("ran-color-picker-saturation").build(), this.colorPickerPaletteDot = s().class("ran-color-picker-palette-dot").build(), this.colorPickerPalette = s().class("ran-color-picker-palette").on("pointerdown", this.palettePointerDown).children(this.colorPickerSaturation, this.colorPickerPaletteDot).build(), this.colorPickerPreviewInner = s().class("ran-color-picker-preview-inner").build(); const e = s().class("ran-color-picker-preview").children(this.colorPickerPreviewInner).build(); this.colorPickerHueThumb = s().class("ran-color-picker-slider-thumb").build(), this.colorPickerHueSlider = s().class("ran-color-picker-slider ran-color-picker-slider-hue").on("pointerdown", this.sliderPointerDown("hue")).on("keydown", this.sliderKeydown("hue")).children(this.colorPickerHueThumb).build(), this.initSliderA11y(this.colorPickerHueSlider, "Hue", u), this.colorPickerAlphaTrack = s().class("ran-color-picker-slider-alpha-track").build(), this.colorPickerAlphaThumb = s().class("ran-color-picker-slider-thumb").build(), this.colorPickerAlphaSlider = s().class("ran-color-picker-slider ran-color-picker-slider-alpha").on("pointerdown", this.sliderPointerDown("alpha")).on("keydown", this.sliderKeydown("alpha")).children(this.colorPickerAlphaTrack, this.colorPickerAlphaThumb).build(), this.initSliderA11y(this.colorPickerAlphaSlider, "Alpha opacity", 100); const t = s().class("ran-color-picker-sliders").children(this.colorPickerHueSlider, this.colorPickerAlphaSlider).build(), r = s().class("ran-color-picker-controls").children(e, t).build(); this.colorPickerFormatSelect = h("r-select").class("ran-color-picker-format").attr("value", this._format).attr("defaultValue", this._format).attr("trigger", "click").children(...["HEX", "RGB"].map((a) => h("r-option").attr("value", a).text(a).build())).on("change", this.onFormatChange).build(), this.colorPickerValueInput = h("r-input").class("ran-color-picker-value").on("change", this.onValueInput).build(); const i = s().class("ran-color-picker-input-container").children(this.colorPickerFormatSelect, this.colorPickerValueInput).build(), o = s().class("ran-color-picker-inner-content").children(this.colorPickerPalette, r, i).build(); this.colorPickerInner = s().class("ran-color-picker-inner").children(P().text(F).build(), o).build(), this.popoverContent.appendChild(this.colorPickerInner), this.setupEffects(), this.syncValueInput(); }; connectedCallback() { this.handlerExternalCss(), this.setAttribute("class", "ran-colorpicker"), this._events.on(this, "click", this.blockWhenDisabled, { capture: !0 }), this._events.on(this, "keydown", this.blockWhenDisabled, { capture: !0 }), this._events.on(this.popoverBlock, "click", this.openColorPicker), this._events.on(this.colorpicker, "keydown", this.onSwatchKeydown), this._events.on(document, "pointermove", this.onPointerMove), this._events.on(document, "pointerup", this.onPointerUp), this._events.on(document, "pointercancel", this.onPointerUp), this.syncDisabledState(), this.value && this.updateColorValue(this.value), this.paintSwatch(), this.colorPickerInner && this._effectDisposers.length === 0 && this.setupEffects(); } disconnectedCallback() { this._events.abort(), this.disposeEffects(); } attributeChangedCallback(e, t, r) { t !== r && (e === "value" && this.updateColorValue(r), e === "disabled" && this.syncDisabledState(), e === "sheet" && this.handlerExternalCss()); } }; $("r-colorpicker", T); export { T as t };