@opentiny/vue-renderless
Version:
An enterprise-class UI component library, support both Vue.js 2 and Vue.js 3, as well as PC and mobile.
366 lines (365 loc) • 9.29 kB
JavaScript
import "../../chunk-G2ADBYYC.js";
const INT_HEX_MAP = {
10: "A",
11: "B",
12: "C",
13: "D",
14: "E",
15: "F"
};
const HEX_INT_MAP = {
A: 10,
B: 11,
C: 12,
D: 13,
E: 14,
F: 15
};
const parseHex = function(hex) {
if (hex.length === 2) {
return (HEX_INT_MAP[hex[0].toUpperCase()] || +hex[0]) * 16 + (HEX_INT_MAP[hex[1].toUpperCase()] || +hex[1]);
}
return HEX_INT_MAP[hex[1].toUpperCase()] || +hex[1];
};
const hsv2hsl = ({ hue, sat, val }) => {
const hue_ = (2 - sat) * val;
return [hue, sat * val / (hue_ < 1 ? hue_ : 2 - hue_) || 0, hue_ / 2];
};
const isString = (val) => typeof val === "string";
const isOnePointZero = (n) => {
return isString(n) && n.includes(".") && Number.parseFloat(n) === 1;
};
const isPercentage = (n) => {
return isString(n) && n.includes("%");
};
const normalized = (value, max) => {
if (isOnePointZero(value))
value = "100%";
const processPercent = isPercentage(value);
value = Math.min(max, Math.max(0, Number.parseFloat(`${value}`)));
if (processPercent) {
value = Number.parseInt(`${value * max}`, 10) / 100;
}
if (Math.abs(value - max) < 1e-6) {
return 1;
}
return value % max / Number.parseFloat(max);
};
const hexOne = (value) => {
value = Math.min(Math.round(value), 255);
const high = Math.floor(value / 16);
const low = value % 16;
return `${INT_HEX_MAP[high] || high}${INT_HEX_MAP[low] || low}`;
};
const toHex = ({ r, g, b }) => {
if (Number.isNaN(+r) || Number.isNaN(+g) || Number.isNaN(+b))
return "";
return `#${hexOne(r)}${hexOne(g)}${hexOne(b)}`;
};
const hsl2hsv = ({ hue, sat, light }) => {
sat = sat / 100;
light = light / 100;
let smin = sat;
const lmin = Math.max(light, 0.01);
light *= 2;
sat *= light <= 1 ? light : 2 - light;
smin *= lmin <= 1 ? lmin : 2 - lmin;
const v = (light + sat) / 2;
const sv = light === 0 ? 2 * smin / (lmin + smin) : 2 * sat / (light + sat);
return {
h: hue,
s: sv * 100,
v: v * 100
};
};
const rgb2hsv = ({ r, g, b }) => {
r = normalized(r, 255);
g = normalized(g, 255);
b = normalized(b, 255);
const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
let h;
const v = max;
const d = max - min;
const s = max === 0 ? 0 : d / max;
if (max === min) {
h = 0;
} else {
switch (max) {
case r: {
h = (g - b) / d + (g < b ? 6 : 0);
break;
}
case g: {
h = (b - r) / d + 2;
break;
}
case b: {
h = (r - g) / d + 4;
break;
}
}
h /= 6;
}
return { h: h * 360, s: s * 100, v: v * 100 };
};
const hsv2rgb = ({ h, s, v }) => {
h = normalized(h, 360) * 6;
s = normalized(s, 100);
v = normalized(v, 100);
const i = Math.floor(h);
const f = h - i;
const p = v * (1 - s);
const q = v * (1 - f * s);
const t = v * (1 - (1 - f) * s);
const mod = i % 6;
const r = [v, q, p, p, t, v][mod];
const g = [t, v, v, q, p, p][mod];
const b = [p, p, t, v, v, q][mod];
return {
r: Math.round(r * 255),
g: Math.round(g * 255),
b: Math.round(b * 255)
};
};
class Color {
constructor(opts) {
this._hue = 0;
this._sat = 100;
this._value = 100;
this._alpha = 100;
this.enableAlpha = false;
this.format = "hex";
this.value = "";
for (const opt in opts) {
if (opt in opts) {
this[opt] = opts[opt];
}
}
if (opts.value) {
this.fromString(opts.value);
} else {
this.onChange();
}
}
get(prop) {
if (prop === "alpha") {
return Math.floor(this._alpha);
}
return this[`_${prop}`];
}
set(props, value) {
if (arguments.length === 1 && typeof props === "object") {
for (const p in props) {
if (Object.hasOwn(props, p)) {
this.set(p, props[p]);
}
}
return;
}
this[`_${props}`] = value;
this.onChange();
}
compare(color) {
return Math.abs(color._hue - this._hue) < 2 && Math.abs(color._sat - this._sat) < 1 && Math.abs(color._value - this._value) < 1 && Math.abs(color._alpha - this._alpha) < 1;
}
isHSL(value) {
return value.includes("hsl");
}
isHsv(value) {
return value.includes("hsv");
}
isRgb(value) {
return value.includes("rgb");
}
isHex(value) {
return value.includes("#");
}
splitPart(value, regExp) {
return value.replace(regExp, "").split(/\s|,/g).filter((v) => v).map((val, idx) => {
return idx > 2 ? Number.parseFloat(val) : Number.parseInt(val, 10);
});
}
onHsv(value) {
const parts = this.splitPart(value, /hsva|hsv|\(|\)/gm);
if (parts.length === 4) {
this._alpha = Number.parseFloat(String(parts[3])) * 100;
} else {
this._alpha = 100;
}
if (parts.length >= 3) {
this.fromHSV({
h: parts[0],
s: parts[1],
v: parts[2]
});
}
}
onRgb(value) {
const rgbRegExp = /rgba|rgb|\(|\)/gm;
const parts = this.splitPart(value, rgbRegExp);
if (parts.length === 4) {
this._alpha = Number.parseFloat(String(parts[3])) * 100;
} else {
this._alpha = 100;
}
if (parts.length >= 3) {
const { h, s, v } = rgb2hsv({ r: parts[0], g: parts[1], b: parts[2] });
this.fromHSV({ h, s, v });
}
}
onHex(value) {
const hex = value.replace("#", "").trim();
const isValidHex = (hex2) => /^[0-9a-fA-F]{3}$|^[0-9a-fA-F]{6}$|^[0-9a-fA-F]{8}$/.test(hex2);
if (!isValidHex(hex)) {
return;
}
let [r, g, b] = [0, 0, 0];
if (hex.length === 3) {
r = parseHex(hex[0] + hex[0]);
g = parseHex(hex[1] + hex[1]);
b = parseHex(hex[2] + hex[2]);
} else if (hex.length === 6 || hex.length === 8) {
r = parseHex(hex.slice(0, 2));
g = parseHex(hex.slice(2, 4));
b = parseHex(hex.slice(4, 6));
}
if (hex.length === 8) {
this._alpha = parseHex(hex.slice(6)) / 255 * 100;
} else if (hex.length === 3 || hex.length === 6) {
this._alpha = 100;
}
const { h, s, v } = rgb2hsv({ r, g, b });
this.fromHSV({ h, s, v });
}
onHsl(value) {
const parts = value.replace(/hsla|hsl\(|\)gm/, "").split(/\s|,/g).filter((val) => val).map((val, idx) => {
return idx > 2 ? Number.parseFloat(val) : Number.parseInt(val, 10);
});
if (parts.length === 4) {
this._alpha = Number.parseFloat(String(parts[3])) * 100;
} else {
this._alpha = 100;
}
if (parent.length >= 3) {
const { h, s, v } = hsl2hsv({
hue: parts[0],
sat: parts[1],
light: parts[2]
});
this.fromHSV({ h, s, v });
}
}
/**
* @effect 会修改 this._hue, this._sat, this._value
*/
fromHSV({ h, s, v }) {
this._hue = Math.max(0, Math.min(360, h));
this._sat = Math.max(0, Math.min(100, s));
this._value = Math.max(0, Math.min(100, v));
this.onChange();
}
fromString(value) {
if (!value) {
this._hue = 0;
this._sat = 0;
this._value = 0;
this.onChange();
return;
}
if (this.isHSL(value)) {
this.onHsl(value);
}
if (this.isHsv(value)) {
this.onHsv(value);
}
if (this.isRgb(value)) {
this.onRgb(value);
}
if (this.isHex(value)) {
this.onHex(value);
}
}
toRgb() {
return hsv2rgb({
h: this._hue,
s: this._sat,
v: this._value
});
}
onChange() {
const { _hue, _sat, _value, _alpha, format, enableAlpha } = this;
if (!enableAlpha) {
switch (format) {
case "hsl": {
let [_, sat, light] = hsv2hsl({
hue: _hue,
sat: _sat / 100,
val: _value / 100
});
sat = Math.round(sat * 100);
light = Math.round(light * 100);
this.value = `hsl(${_hue}, ${sat}%, ${light}%)`;
break;
}
case "hsv": {
this.value = `hsv(${_hue}, ${Math.round(_sat)}%, ${Math.round(_value)}%)`;
break;
}
case "rgb": {
const { r, g, b } = hsv2rgb({ h: _hue, s: _sat, v: _value });
this.value = `rgb(${r},${g},${b})`;
break;
}
default: {
this.value = toHex(
hsv2rgb({
h: _hue,
s: _sat,
v: _value
})
);
}
}
return;
}
switch (format) {
case "hsl": {
let [_, sat, light] = hsv2hsl({
hue: _hue,
sat: _sat / 100,
val: _value / 100
});
sat = Math.round(sat * 100);
light = Math.round(light * 100);
this.value = `hsla(${_hue}, ${sat}%, ${light}%, ${this.get("alpha") / 100})`;
break;
}
case "hsv": {
this.value = `hsva(${_hue}, ${Math.round(_sat)}%, ${Math.round(_value)}%, ${this.get("alpha") / 100})`;
break;
}
case "hex": {
this.value = `${toHex(
hsv2rgb({
h: _hue,
s: _sat,
v: _value
})
)}${hexOne(_alpha * 255 / 100)}`;
break;
}
default: {
const { r, g, b } = hsv2rgb({
h: _hue,
s: _sat,
v: _value
});
this.value = `rgba(${r}, ${g}, ${b}, ${this.get("alpha") / 100})`;
}
}
}
}
export {
Color
};