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