@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.
472 lines (471 loc) • 13.2 kB
JavaScript
import {
__spreadProps,
__spreadValues
} from "../chunk-G2ADBYYC.js";
import colors from "./utils/color-map";
import { Color } from "./utils/color";
import { createContext } from "./utils/context";
import { ColorPoint } from "./utils/color-points";
const panelRgb = (color, alpha) => {
const { r, g, b } = color.toRgb();
return alpha ? `rgba(${r},${g},${b},${color.get("alpha") / 100})` : `rgb(${r},${g},${b})`;
};
const updateModelValue = (value, emit) => {
emit("update:modelValue", value);
};
const triggerCancel = (value, emit) => {
emit("cancel");
};
const triggerColorUpdate = (value, emit) => {
emit("color-update", value);
};
const triggerConfirm = (value, emit) => {
emit("confirm", value);
};
const parseCustomRGBA = (str, type) => {
if (!str || typeof str !== "string") {
return [0, 0, 0, 0];
}
let content = "";
let match = null;
if (type === "hsl") {
match = str.match(/hsla?\(([^)]+)\)/);
} else if (type === "rgb") {
match = str.match(/rgba?\(([^)]+)\)/);
} else if (type === "hsv") {
match = str.match(/hsva?\(([^)]+)\)/);
}
if (!match || !match[1]) {
return [0, 0, 0, 0];
}
content = match[1];
const parts = content.split(",").map((item) => item.trim());
const result = parts.map((item, index) => {
if (index === 0 || index === parts.length - 1 && parts.length === 4) {
return parseFloat(item);
}
return item;
});
return result;
};
const isGrandient = (val) => {
if (typeof val !== "string") {
return false;
}
return val.trim().startsWith("linear-gradient");
};
const sideCornerDegreeMap = {
top: 0,
right: 90,
bottom: 180,
left: 270,
"top left": 315,
"left top": 315,
"top right": 45,
"right top": 45,
"bottom left": 225,
"left bottom": 225,
"bottom right": 135,
"right bottom": 135
};
const createColorPoints = (val, props, hooks, ext, bar) => {
if (!isGrandient(val)) {
return { colorPoints: [], angular: 180 };
}
const nodes = ext.parse(val);
let angular = 180;
const parseAngular = (node2) => {
if (node2.type === "angular") {
return Number.parseInt(node2.value);
}
return sideCornerDegreeMap[node2.value] || 180;
};
const parseBehavior = {
hex: (node2) => {
return new ColorPoint(new Color({ value: `#${node2.value}`, format: "hex", enableAlpha: props.alpha }), 0);
},
rgb: (node2) => {
if (props.alpha) {
return parseBehavior.rgba(__spreadProps(__spreadValues({}, node2), { type: "rgba" }));
}
return new ColorPoint(new Color({ enableAlpha: false, format: "rgb", value: `rgb(${node2.value.join(",")})` }), 0);
},
rgba: (node2) => {
const color = new Color({ enableAlpha: props.alpha, format: "rgba", value: `rgba(${node2.value.join(",")})` });
return new ColorPoint(color, 0);
},
hsl: (node2) => {
if (props.alpha) {
return parseBehavior.hsla(__spreadProps(__spreadValues({}, node2), { type: "hsla" }));
}
const color = new Color({ enableAlpha: false, format: "hsl", value: `hsl(${node2.value.join(" ")})` });
return new ColorPoint(color, 0);
},
hsla: (node2) => {
const color = new Color({ enableAlpha: props.alpha, format: "hsl", value: `hsl(${node2.value.join(" ")})` });
return new ColorPoint(color, 0);
},
literal: (node2) => {
let value = colors[node2.value] || "#00000000";
const color = new Color({ enableAlpha: true, format: "hex", value });
return new ColorPoint(color, 0);
},
"var": (node2) => {
hooks.warn("unsupported var ref.");
return parseBehavior.hex({ type: "hex", value: "#000", length: node2.length });
}
};
const unsupportedLengthUnit = ["em", "calc"];
const parseLength = (node2) => {
if (!node2 || !bar) {
return 0;
}
if (unsupportedLengthUnit.includes(node2.type)) {
hooks.warn(`unsupported unit ${node2.type}`);
return 0;
}
const barRect = bar.getBoundingClientRect();
const { width } = barRect;
const numberValue = Number.parseFloat(node2.value);
if (node2.type === "%") {
return Number.parseInt(`${numberValue / 100 * width}`);
}
if (node2.type === "px") {
return Number.parseInt(`${numberValue / width}`);
}
return 0;
};
const parseColotStop = (colorStop) => {
if (!(colorStop.type in parseBehavior)) {
hooks.warn(`unknown behavior ${colorStop}`);
throw new Error(`unknown behavior ${colorStop}`);
}
const colorPoint = parseBehavior[colorStop.type](colorStop);
const cursorLeft = parseLength(colorStop.length);
colorPoint.cursorLeft = cursorLeft;
return colorPoint;
};
const [node] = nodes;
if (node.type !== "linear-gradient") {
hooks.warn(`Only support linear-gradient yet.`);
return { colorPoints: [], angular: 180 };
}
if (!node) {
return { colorPoints: [], angular: 180 };
}
if (node.orientation) {
angular = parseAngular(node.orientation);
} else {
angular = 180;
}
const colorPoints = node.colorStops.map((colorStop) => parseColotStop(colorStop));
return { colorPoints, angular };
};
const initApi = (props, state, utils, hooks, ext) => {
const { emit, nextTick } = utils;
const setShowPicker = (value) => state.showPicker = value;
const resetColor = () => {
nextTick(() => {
if (props.modelValue) {
state.color.fromString(props.modelValue);
} else {
state.color.value = "";
nextTick(() => {
state.showPanel = false;
});
}
});
};
const submitValue = () => {
if (state.ctx.colorMode === "linear-gradient") {
updateModelValue(state.ctx.linearGardientValue, emit);
triggerConfirm(state.ctx.linearGardientValue, emit);
setShowPicker(false);
return;
}
const value = state.color.value;
updateModelValue(value, emit);
triggerConfirm(value, emit);
setShowPicker(false);
nextTick(() => {
var _a;
const newColor = new Color({
enableAlpha: props.alpha,
format: (_a = state.currentFormat) != null ? _a : "",
value: props.modelValue
});
if (!state.color.compare(newColor)) {
resetColor();
}
});
};
const onConfirm = () => {
submitValue();
if (!state.enableHistory) {
return;
}
let index = state.stack.indexOf(state.input);
if (index === -1) {
state.stack.push(state.input);
} else {
state.stack = [state.input, ...state.stack.filter((c, i) => i !== index)];
}
};
const onCancel = () => {
resetColor();
close();
emit("cancel");
};
const clear = () => {
updateModelValue(null, emit);
triggerCancel(null, emit);
resetColor();
};
const onClickOutside = () => {
if (!state.showPicker) {
return;
}
close();
resetColor();
emit("cancel");
};
const onHueReady = (update) => {
state.hue = { update };
};
const onSvReady = (update) => {
state.sv = { update };
};
const onAlphaReady = (update) => {
state.alpha = { update };
};
const open = () => {
setShowPicker(true);
};
const close = () => {
setShowPicker(false);
};
const onHistoryClick = (historyColor) => {
if (state.ctx.colorMode === "monochrome") {
state.ctx.activeColor.color.fromString(historyColor);
return;
}
const colorString = isGrandient(historyColor) ? historyColor : `linear-gradient(90deg, #fff 0%, ${historyColor} 100%)`;
const colorPoints = createColorPoints(colorString, props, hooks, ext, state.ctx.bar);
state.ctx.colorPoints = colorPoints.colorPoints;
const lastPoint = colorPoints.colorPoints.at(-1);
if (lastPoint) {
state.ctx.activeColor = lastPoint;
}
state.ctx.deg = colorPoints.angular;
};
const onPredefineColorClick = (predefineColor) => {
if (state.ctx.colorMode === "monochrome") {
state.color.fromString(predefineColor);
return;
}
const colorString = isGrandient(predefineColor) ? predefineColor : `linear-gradient(180deg, #fff 0%, ${predefineColor} 100%)`;
const colorPoints = createColorPoints(colorString, props, hooks, ext, state.ctx.bar);
state.ctx.colorPoints = colorPoints.colorPoints;
const lastPoint = colorPoints.colorPoints.at(-1);
if (lastPoint) {
state.ctx.activeColor = lastPoint;
}
state.ctx.deg = colorPoints.angular;
};
return {
open,
close,
resetColor,
onConfirm,
onCancel,
submitValue,
clear,
onHueReady,
onSvReady,
onAlphaReady,
onPredefineColorClick,
onHistoryClick,
onClickOutside
};
};
const initState = (props, hooks, utils, ext) => {
var _a, _b;
const { reactive, ref, computed } = hooks;
const stack = ref([...(_a = props.history) != null ? _a : []]);
const predefineStack = computed(() => props.predefine);
const hue = ref();
const sv = ref();
const alpha = ref();
const currentFormat = ref(props.format[0]);
const color = reactive(
new Color({
enableAlpha: props.alpha,
format: (_b = currentFormat.value) != null ? _b : "hex",
value: props.modelValue
})
);
const bar = ref(null);
const ctx = {
colorMode: computed(() => {
var _a2;
return (_a2 = props.colorMode) != null ? _a2 : "monochrome";
}),
activeColor: ref(new ColorPoint(color, 0)),
colorPoints: ref([new ColorPoint(color, 0)]),
linearGardientValue: ref(""),
bar,
deg: ref(180)
};
if (isGrandient(props.modelValue)) {
hooks.watchEffect(() => {
if (!bar.value) {
return;
}
const { colorPoints, angular } = createColorPoints(props.modelValue, props, hooks, ext, bar.value);
ctx.deg.value = angular;
ctx.colorPoints.value = colorPoints;
const lastPoint = colorPoints.at(-1);
if (lastPoint) {
ctx.activeColor.value = lastPoint;
}
});
}
createContext(ctx, hooks);
const input = ref("");
const hexInput1 = ref();
const hexInput2 = ref();
const hexInput4 = ref();
const hexInput5 = ref();
const hexInput6 = ref();
const hexInput7 = ref();
const showPicker = ref(props.visible);
const showPanel = ref(false);
const panelColor = computed(() => {
if (!props.modelValue && !showPanel.value) {
return "transparent";
}
return panelRgb(color, props.alpha);
});
const currentColor = computed(() => !props.modelValue && !showPicker.value ? "" : color.value);
const state = reactive({
color,
input,
hexInput1,
hexInput2,
hexInput4,
hexInput5,
hexInput6,
hexInput7,
showPicker,
showPanel,
panelColor,
currentColor,
hue,
sv,
alpha,
stack,
predefineStack,
enablePredefineColor: computed(() => props.enablePredefineColor),
enableHistory: computed(() => props.enableHistory),
currentFormat,
formats: props.format,
ctx,
isLinearGradient: computed(() => ctx.colorMode.value === "linear-gradient"),
linearGradient: computed(() => ctx.linearGardientValue.value)
});
return state;
};
const initWatch = (state, props, { nextTick, watch }, { emit }) => {
watch(
() => state.color,
() => {
emit("color-update", state.color);
}
);
watch(
() => props.visible,
() => {
state.showPicker = props.visible;
}
);
watch(
() => props.modelValue,
() => {
if (!props.modelValue) {
state.showPanel = false;
}
if (props.modelValue && props.modelValue !== state.color.value) {
state.color.fromString(props.modelValue);
}
}
);
watch(
() => [state.currentFormat, props.alpha],
() => {
state.color.enableAlpha = props.alpha;
state.color.format = state.currentFormat || state.color.format;
state.color.onChange();
updateModelValue(state.color.value, emit);
}
);
watch(
() => [state.currentColor, state.linearGradient],
() => {
if (state.isLinearGradient) {
state.input = state.linearGradient;
return;
} else {
state.input = state.currentColor;
const result = parseCustomRGBA(state.currentColor, state.currentFormat);
state.hexInput4 = Math.ceil(Number(result[0]));
state.hexInput5 = result[1];
state.hexInput6 = result[2];
state.hexInput7 = `${(Number(result[3]) || 1) * 100}%`;
}
triggerColorUpdate(state.input, emit);
},
{ flush: "sync" }
);
watch(state.color, () => {
if (!props.modelValue && !state.showPanel) {
state.showPanel = true;
}
});
watch(
() => state.showPicker,
() => {
nextTick(() => {
if (state.hue) {
state.hue.update();
}
if (state.sv) {
state.sv.update();
}
if (state.alpha) {
state.alpha.update();
}
});
}
);
watch(
() => props.history,
() => {
if (!state.enableHistory) {
return;
}
state.stack = props.history;
},
{ deep: true }
);
};
export {
initApi,
initState,
initWatch,
panelRgb,
parseCustomRGBA,
triggerCancel,
triggerColorUpdate,
triggerConfirm,
updateModelValue
};