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.

315 lines (314 loc) 19.2 kB
import { a as v, c as h, g as l, n as x, o as m, r as P, t as y } from "./utils-D1iZnChu.js"; import { t as w } from "./events-C59wGdni.js"; import { N as S, O as p, _ as u, h as A, i as n } from "./factory-ZNhcQ4tf.js"; import { a as $, n as _ } from "./ssr-DSGwPtEd.js"; import "./input-ZY2Wumze.js"; import "./select-DRKYa3W2.js"; import "./popover-BZKSLe3D.js"; var D = (e) => { const { r: t, g: i, b: r } = I(e); return f(t, i, r); }, I = (e) => (e[0] === "#" && (e = e.substr(1)), e.length === 3 ? { r: parseInt(e[0] + e[0], 16), g: parseInt(e[1] + e[1], 16), b: parseInt(e[2] + e[2], 16) } : { r: parseInt(e.substr(0, 2), 16), g: parseInt(e.substr(2, 2), 16), b: parseInt(e.substr(4, 2), 16) }), f = (e, t, i) => { let r; const o = Math.max(e, t, i), a = o - Math.min(e, t, i); a === 0 ? r = 0 : e === o ? r = (t - i) / a % 6 : t === o ? r = (i - e) / a + 2 : r = (e - t) / a + 4, r = Math.round(r * 60), r < 0 && (r += 360); const s = Math.round((o === 0 ? 0 : a / o) * 100), c = Math.round(o / 255 * 100); return { h: r, s, v: c }; }, b = (e, t, i) => { t = t / 100, i = i / 100; let r = []; const o = i * t, a = e / 60, s = o * (1 - Math.abs(a % 2 - 1)), c = i - o; return a >= 0 && a < 1 ? r = [ o, s, 0 ] : a >= 1 && a < 2 ? r = [ s, o, 0 ] : a >= 2 && a < 3 ? r = [ 0, o, s ] : e >= 3 && a < 4 ? r = [ 0, s, o ] : e >= 4 && a < 5 ? r = [ s, 0, o ] : e >= 5 && a <= 6 ? r = [ o, 0, s ] : r = [ 0, 0, 0 ], { r: Math.round(255 * (r[0] + c)), g: Math.round(255 * (r[1] + c)), b: Math.round(255 * (r[2] + c)) }; }, k = (e) => { const t = e.toString(16); return t.length === 1 ? "0" + t : t; }, g = (e, t, i) => "#" + [ k(e), k(t), k(i) ].join(""), C = /^#([\da-f]{6}|[\da-f]{3})$/i, E = /^rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)$/, R = /^rgba\((\d{1,3}),(\d{1,3}),(\d{1,3}),(\d{1,3}(\.\d+)?)\)$/, V = ".remove-wap-active-focus{outline:0;-webkit-tap-highlight-color:transparent}.remove-wap-active-focus:active,.remove-wap-active-focus:focus{outline:0;-webkit-tap-highlight-color:transparent}.ran-colorpicker{box-sizing:border-box;min-width:32px;height: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: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:3px}.ran-colorpicker:hover{border-color:var(--ran-colorpicker-border-hover, 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:24px;height: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-inner{width:100%;height:100%;border-radius:inherit}.ran-colorpicker-block[disabled]{cursor:var(--ran-colorpicker-disabled-cursor, not-allowed);opacity:var(--ran-colorpicker-disabled-opacity, .5)}", H = ".remove-wap-active-focus{outline:0;-webkit-tap-highlight-color:transparent}.remove-wap-active-focus:active,.remove-wap-active-focus:focus{outline:0;-webkit-tap-highlight-color:transparent}.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}", d = 360, F = class extends _ { colorpicker; colorpickerInner; context; _shadowDom; _events = new w(); _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 = x(this, V); const e = y(this._shadowDom, "r-popover", () => { const t = n().class("ran-colorpicker-inner").part("swatch").build(), i = n().class("ran-colorpicker-block").part("block").children(t).build(), r = u("r-content").class("ran-content").build(); return u("r-popover").class("ran-popover").attr("trigger", "click").children(i, r).build(); }); this.popoverBlock = e, this.popoverContent = e.querySelector("r-content"), this.colorpicker = e.querySelector(".ran-colorpicker-block"), this.colorpickerInner = e.querySelector(".ran-colorpicker-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 P(this, "sheet"); } set sheet(e) { v(this, "sheet", e); } get disabled() { return h(this); } set disabled(e) { e === !1 || e === void 0 || e === null ? this.removeAttribute("disabled") : this.setAttribute("disabled", ""); } handlerExternalCss = () => { m(this, this._shadowDom, "sheet", null, this.sheet); }; syncDisabledState = () => { const e = h(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) => { h(this) && (e.stopImmediatePropagation(), e.preventDefault()); }; createContext = () => { const e = (t) => { const [i, r] = S(t); return { getter: i, setter: r }; }; 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: i, transparency: r } = this.context, { r: o, g: a, b: s } = b(e.getter(), t.getter(), i.getter()); return { r: o, g: a, b: s, a: r.getter() / 100 }; }; currentValue = () => { const { r: e, g: t, b: i, a: r } = this.currentRgba(); return r < 1 ? `rgba(${e}, ${t}, ${i}, ${Number(r.toFixed(2))})` : g(e, t, i); }; currentDisplay = () => { const { r: e, g: t, b: i, a: r } = this.currentRgba(); return this._format === "RGB" ? r < 1 ? `rgba(${e}, ${t}, ${i}, ${Number(r.toFixed(2))})` : `rgb(${e}, ${t}, ${i})` : g(e, t, i); }; updateColorValue = (e) => { if (e === this.context?.value.getter()) return; const t = e.replace(/\s+/g, ""), i = C.exec(e), r = R.exec(t), o = E.exec(t); if (i) { const { h: a, s, v: c } = D(i[0]); this.context.hue.setter(a), this.context.saturation.setter(s), this.context.lightness.setter(c), this.context.transparency.setter(100); } else if (r) { const { h: a, s, v: c } = f(Number(r[1]), Number(r[2]), Number(r[3])); this.context.hue.setter(a), this.context.saturation.setter(s), this.context.lightness.setter(c), this.context.transparency.setter(Number(r[4]) * 100); } else if (o) { const { h: a, s, v: c } = f(Number(o[1]), Number(o[2]), Number(o[3])); this.context.hue.setter(a), this.context.saturation.setter(s), this.context.lightness.setter(c), this.context.transparency.setter(100); } else return; this.setAttribute("value", e), this.context?.value.setter(e); }; emitChange = () => { const e = this.currentValue(), { r: t, g: i, b: r, a: o } = this.currentRgba(); this.context?.value.setter(e), this.setAttribute("value", e), this.dispatchEvent(new CustomEvent("change", { detail: { value: e, hex: g(t, i, r), rgb: `rgb(${t}, ${i}, ${r})`, rgba: `rgba(${t}, ${i}, ${r}, ${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: i, width: r, height: o } = this.colorPickerPalette.getBoundingClientRect(); if (!r || !o) return; const a = l(e.clientX - t, 0, r), s = l(e.clientY - i, 0, o); this.context.saturation.setter(a / r * 100), this.context.lightness.setter((1 - s / o) * 100), this.emitChange(); }; sliderPointerDown = (e) => (t) => { t.preventDefault(), this._activeSlider = e, this.updateSliderFromEvent(e, t); }; updateSliderFromEvent = (e, t) => { const i = e === "hue" ? this.colorPickerHueSlider : this.colorPickerAlphaSlider; if (!i) return; const { left: r, width: o } = i.getBoundingClientRect(); if (!o) return; const a = l(t.clientX - r, 0, o) / o; e === "hue" ? this.context.hue.setter(a * d) : 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, i) => { 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(i)); }; sliderKeydown = (e) => (t) => { const i = e === "hue" ? d : 100, r = e === "hue" ? this.context.hue : this.context.transparency, o = t.shiftKey ? 10 : 1, a = r.getter(); let s = a; switch (t.key) { case "ArrowRight": case "ArrowUp": s = a + o; break; case "ArrowLeft": case "ArrowDown": s = a - o; break; case "Home": s = 0; break; case "End": s = i; break; default: return; } t.preventDefault(), r.setter(l(s, 0, i)), this.emitChange(); }; onPointerUp = () => { this.colorPickerPaletteSelect = !1, this._activeSlider = null; }; onSwatchKeydown = (e) => { h(this) || (e.key === "Enter" || e.key === " " || e.key === "Spacebar") && (e.preventDefault(), this.colorpicker?.click()); }; onValueInput = (e) => { const t = e.target, i = e.detail?.value ?? t?.value; typeof i == "string" && (this._editingInput = !0, this.updateColorValue(i.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(p(() => { const { r: e, g: t, b: i } = b(this.context.hue.getter(), 100, 100); this.colorPickerSaturation?.style.setProperty("background-color", `rgb(${e}, ${t}, ${i})`); }), p(() => { const e = l(this.context.saturation.getter(), 0, 100), t = l(this.context.lightness.getter(), 0, 100); this.colorPickerPaletteDot?.style.setProperty("left", `${e}%`), this.colorPickerPaletteDot?.style.setProperty("top", `${100 - t}%`); }), p(() => { const e = this.context.hue.getter(), { r: t, g: i, b: r } = b(e, 100, 100); this.colorPickerHueThumb?.style.setProperty("left", `${e / d * 100}%`), this.colorPickerHueThumb?.style.setProperty("background", `rgb(${t}, ${i}, ${r})`), this.colorPickerHueSlider?.setAttribute("aria-valuenow", String(Math.round(e))); }), p(() => { const { r: e, g: t, b: i, a: r } = this.currentRgba(), o = `rgb(${e}, ${t}, ${i})`, a = `rgba(${e}, ${t}, ${i}, ${Number(r.toFixed(3))})`; this.colorPickerAlphaTrack?.style.setProperty("background", `linear-gradient(to right, rgba(${e}, ${t}, ${i}, 0), ${o})`), this.colorPickerAlphaThumb?.style.setProperty("left", `${r * 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(r * 100))), this.colorPickerAlphaSlider?.setAttribute("aria-valuetext", `${Math.round(r * 100)}%`), this.syncValueInput(); })); }; disposeEffects = () => { for (const e of this._effectDisposers) e(); this._effectDisposers = []; }; openColorPicker = () => { if (h(this) || this.colorPickerInner) return; this.colorPickerSaturation = n().class("ran-color-picker-saturation").build(), this.colorPickerPaletteDot = n().class("ran-color-picker-palette-dot").build(), this.colorPickerPalette = n().class("ran-color-picker-palette").on("mousedown", this.palettePointerDown).children(this.colorPickerSaturation, this.colorPickerPaletteDot).build(), this.colorPickerPreviewInner = n().class("ran-color-picker-preview-inner").build(); const e = n().class("ran-color-picker-preview").children(this.colorPickerPreviewInner).build(); this.colorPickerHueThumb = n().class("ran-color-picker-slider-thumb").build(), this.colorPickerHueSlider = n().class("ran-color-picker-slider ran-color-picker-slider-hue").on("mousedown", this.sliderPointerDown("hue")).on("keydown", this.sliderKeydown("hue")).children(this.colorPickerHueThumb).build(), this.initSliderA11y(this.colorPickerHueSlider, "Hue", d), this.colorPickerAlphaTrack = n().class("ran-color-picker-slider-alpha-track").build(), this.colorPickerAlphaThumb = n().class("ran-color-picker-slider-thumb").build(), this.colorPickerAlphaSlider = n().class("ran-color-picker-slider ran-color-picker-slider-alpha").on("mousedown", this.sliderPointerDown("alpha")).on("keydown", this.sliderKeydown("alpha")).children(this.colorPickerAlphaTrack, this.colorPickerAlphaThumb).build(), this.initSliderA11y(this.colorPickerAlphaSlider, "Alpha opacity", 100); const t = n().class("ran-color-picker-sliders").children(this.colorPickerHueSlider, this.colorPickerAlphaSlider).build(), i = n().class("ran-color-picker-controls").children(e, t).build(); this.colorPickerFormatSelect = u("r-select").class("ran-color-picker-format").attr("value", this._format).attr("defaultValue", this._format).attr("trigger", "click").children(...["HEX", "RGB"].map((a) => u("r-option").attr("value", a).text(a).build())).on("change", this.onFormatChange).build(), this.colorPickerValueInput = u("r-input").class("ran-color-picker-value").on("change", this.onValueInput).build(); const r = n().class("ran-color-picker-input-container").children(this.colorPickerFormatSelect, this.colorPickerValueInput).build(), o = n().class("ran-color-picker-inner-content").children(this.colorPickerPalette, i, r).build(); this.colorPickerInner = n().class("ran-color-picker-inner").children(A().text(H).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, "mousemove", this.onPointerMove), this._events.on(document, "mouseup", this.onPointerUp), this.syncDisabledState(), this.value && this.updateColorValue(this.value), this.colorPickerInner && this._effectDisposers.length === 0 && this.setupEffects(); } disconnectedCallback() { this._events.abort(), this.disposeEffects(); } attributeChangedCallback(e, t, i) { t !== i && (e === "value" && this.updateColorValue(i), e === "disabled" && this.syncDisabledState(), e === "sheet" && this.handlerExternalCss()); } }; $("r-colorpicker", F); export { F as t };