eapp-amis-theme-editor
Version:
amis主题编辑器
721 lines (717 loc) • 24.2 kB
JavaScript
/**
* amis-theme-editor v2.0.11-beta.2
* Copyright 2018-2023 @fex
*/
import { __extends, __assign, __decorate } from 'tslib';
import React__default, { useRef, useState, useEffect } from 'react';
import { FormItem, resolveVariableAndFilter, findTree } from 'amis-core';
import cx from 'classnames';
import { SketchPicker } from 'react-color';
import { TooltipWrapper, Icon, Overlay, PopOver, NumberInput } from 'amis-ui';
import { cloneDeep } from 'lodash';
import { i18n } from 'i18n-runtime';
import { getValueByPath } from '../util.js';
/**
* @file 颜色选择器
* @description 设置颜色
*/
function findColor(value, tree) {
var res = {
label: value,
value: value
};
if (typeof value === 'string' && (value === null || value === void 0 ? void 0 : value.indexOf('var')) === 0) {
var r = findTree(tree, function (item) {
return item.value === value;
});
if (r) {
res = {
label: "".concat(r.label, "-").concat(r.realValue),
value: r.realValue
};
} else if (!value.includes('--colors-')) {
res = {
label: i18n("a4f758412c3797290c957544c56db443"),
value: value
};
}
}
if (value === 'transparent') {
res = {
label: i18n("1110ba0bda5a251c55247f122e923848"),
value: 'transparent'
};
}
if (value === 'custom') {
res = {
label: i18n("d8a4e8cdc29e9aa576e669ed165892c9"),
value: 'transparent'
};
}
if (value === 'inherit') {
res = {
label: i18n("a4f758412c3797290c957544c56db443"),
value: value
};
}
return res;
}
function ThemeColorList(props) {
var _a;
var themeList = props.themeList,
onChange = props.onChange,
value = props.value,
data = props.data,
itemName = props.itemName,
state = props.state;
var defaultVar = state && state !== 'default' ? 'inherit' : "var(".concat((_a = data === null || data === void 0 ? void 0 : data.default) === null || _a === void 0 ? void 0 : _a.token).concat(itemName, ")");
function setColor(value) {
onChange(value);
}
return React__default.createElement("div", {
className: "ThemeColorList"
}, React__default.createElement("div", {
className: "ThemeColorList-content ThemeColorList-content--top"
}, React__default.createElement("div", {
className: "ThemeColorList-content-title"
}, "\u901A\u7528"), React__default.createElement("div", {
className: "ThemeColorList-content-labels"
}, React__default.createElement(TooltipWrapper, {
trigger: "hover",
placement: "top",
tooltip: {
children: function () {
return React__default.createElement("div", null, "\u900F\u660E-transparent");
}
}
}, React__default.createElement("div", {
className: cx('ThemeColorList-content-label', value === 'transparent' && 'ThemeColorList-content-label--active'),
onClick: function () {
return setColor('transparent');
}
}, React__default.createElement("div", {
className: cx('ThemeColorList-content-label-inner', 'ThemeColor--transparent'),
"color-tooltip": ""
}))), (data === null || data === void 0 ? void 0 : data.state) && data.state !== 'default' || state && state !== 'default' ? React__default.createElement(TooltipWrapper, {
trigger: "hover",
placement: "top",
tooltip: {
children: function () {
return React__default.createElement("div", null, "\u7EE7\u627F\u5E38\u89C4");
}
}
}, React__default.createElement("div", {
className: cx('ThemeColorList-content-label', value === defaultVar && 'ThemeColorList-content-label--active'),
onClick: function () {
return setColor(defaultVar);
}
}, React__default.createElement("div", {
className: cx('ThemeColorList-content-label-inner', 'ThemeColor--transparent')
}, React__default.createElement("div", {
className: "ThemeColorList-content-label-inner",
style: {
background: defaultVar
}
})))) : null)), themeList === null || themeList === void 0 ? void 0 : themeList.map(function (item, i) {
var _a;
return React__default.createElement("div", {
key: i
}, React__default.createElement("div", {
className: "ThemeColorList-title"
}, i18n(item.label)), (_a = item.children) === null || _a === void 0 ? void 0 : _a.map(function (colors, i) {
var _a;
return React__default.createElement("div", {
className: "ThemeColorList-content",
key: i
}, React__default.createElement("div", {
className: "ThemeColorList-content-title"
}, i18n(colors.label)), React__default.createElement("div", {
className: "ThemeColorList-content-labels"
}, (_a = colors.children) === null || _a === void 0 ? void 0 : _a.map(function (color, i) {
return React__default.createElement(TooltipWrapper, {
key: i,
trigger: "hover",
placement: "top",
tooltip: {
children: function () {
return React__default.createElement("div", null, "".concat(i18n(color.label), "-").concat(color.realValue));
}
}
}, React__default.createElement("div", {
className: cx('ThemeColorList-content-label', value === color.value && 'ThemeColorList-content-label--active'),
onClick: function () {
return setColor(color.value);
}
}, React__default.createElement("div", {
className: cx('ThemeColorList-content-label-inner', color.realValue === '#ffffff' && 'ThemeColorList-content-label--border'),
style: {
background: color.value
}
})));
})));
}));
}));
}
function CustomColor(props) {
var value = props.value,
onChange = props.onChange,
themeList = props.themeList;
if ((value === null || value === void 0 ? void 0 : value.indexOf('var')) === 0) {
var res = findColor(value, themeList).value;
value = res;
}
return React__default.createElement("div", {
className: "Theme-CustomColor"
}, React__default.createElement(SketchPicker, {
width: "216px",
color: value,
onChangeComplete: function (value) {
if (value.rgb.a === 1) {
onChange(value.hex);
} else {
var rag = value.rgb;
onChange("rgba(".concat(rag.r, ", ").concat(rag.g, ", ").concat(rag.b, ", ").concat(rag.a, ")"));
}
}
}));
}
function GradientColor(props) {
var _a;
var slider = useRef(null);
var rangeRef = useRef(null);
var rangeRefPanel = useRef(null);
var value = props.value,
onChange = props.onChange,
themeList = props.themeList;
var _b = useState([]),
colors = _b[0],
setColors = _b[1];
var _c = useState(0),
index = _c[0],
setIndex = _c[1];
var _d = useState(0),
range = _d[0],
setRange = _d[1];
var _e = useState(false),
rangeShow = _e[0],
setRangeShow = _e[1];
var _f = useState(false),
move = _f[0],
setMove = _f[1];
var currentIndex = index;
// 格式化渐变
function formatGradient(value) {
var strs = /linear-gradient\((.*)\)/.exec(value);
var range = 0;
if (strs) {
strs = strs[1].split(',');
range = parseFloat(strs.shift());
}
var res = [];
var len = strs.length;
for (var i = 0; i < len; i++) {
var colorAndPosition = strs[i].split(' ');
var color = {
color: findColor(colorAndPosition[0], themeList).value,
position: (i + 1) / len * 100
};
if (colorAndPosition[1]) {
color.position = parseFloat(colorAndPosition[1]);
}
res.push(color);
}
return {
colors: res,
range: range
};
}
useEffect(function () {
if ((value === null || value === void 0 ? void 0 : value.indexOf('linear-gradient')) === 0) {
var _a = formatGradient(value),
colors_1 = _a.colors,
range_1 = _a.range;
setColors(colors_1);
setRange(range_1);
} else {
setColors([{
color: value || '#fff',
position: 0
}, {
color: value || '#fff',
position: 100
}]);
}
}, [value]);
function gradientChange(range, colors) {
onChange("linear-gradient(".concat(range, "deg,").concat(colors.map(function (item) {
return "".concat(item.color, " ").concat(item.position, "%");
}).join(','), ")"));
}
// 渐变角度改变
function rangeChange(value) {
setRange(value);
gradientChange(value, colors);
}
// 添加渐变点
function handleClickSlider(e) {
if (move) {
return;
}
var target = e.currentTarget.getBoundingClientRect();
var itemPosition = Math.round((e.clientX - target.x) / target.width * 100);
var tempColors = cloneDeep(colors);
var len = tempColors.length;
var index = 0;
if (tempColors[0].position > itemPosition) {
tempColors.unshift({
color: tempColors[0].color,
position: itemPosition
});
} else if (tempColors[len - 1].position < itemPosition) {
tempColors.push({
color: tempColors[len - 1].color,
position: itemPosition
});
index = len;
} else {
for (var i = 0; i < len; i++) {
if (tempColors[i].position < itemPosition && tempColors[i + 1].position > itemPosition) {
index = i + 1;
tempColors.splice(index, 0, {
color: tempColors[i].color,
position: itemPosition
});
break;
}
}
}
setColors(tempColors);
setIndex(index);
gradientChange(range, tempColors);
}
// 按住渐变点
function handleDownSliderItem(e, i) {
setIndex(i);
setMove(true);
currentIndex = i;
window.addEventListener('mousemove', handleMoveSliderItem);
window.addEventListener('mouseup', handleUpSliderItem);
}
// 移动渐变点
function handleMoveSliderItem(e) {
var target = slider.current.getBoundingClientRect();
var itemPosition = Math.round((e.x - target.x) / target.width * 100);
var tempColors = cloneDeep(colors);
// 渐变点个数大于2,当y轴移动大于30,删除渐变点
if (Math.abs(e.y - target.y) > 30 && tempColors.length > 2) {
tempColors.splice(currentIndex, 1);
setIndex(0);
setColors(tempColors);
gradientChange(range, tempColors);
}
// 限制不能超过最大、最小值
else if (itemPosition >= 0 && itemPosition <= 100) {
tempColors[currentIndex].position = itemPosition;
// 向前交换渐变点
if (tempColors[currentIndex - 1] && itemPosition < tempColors[currentIndex - 1].position) {
var temp = cloneDeep(tempColors[currentIndex - 1]);
tempColors[currentIndex - 1] = cloneDeep(tempColors[currentIndex]);
tempColors[currentIndex] = temp;
setIndex(currentIndex - 1);
}
// 向后交换渐变点
else if (tempColors[currentIndex + 1] && itemPosition > tempColors[currentIndex + 1].position) {
var temp = cloneDeep(tempColors[currentIndex + 1]);
tempColors[currentIndex + 1] = cloneDeep(tempColors[currentIndex]);
tempColors[currentIndex] = temp;
setIndex(currentIndex + 1);
}
setColors(tempColors);
gradientChange(range, tempColors);
}
}
// 放开渐变点
function handleUpSliderItem() {
window.removeEventListener('mousemove', handleMoveSliderItem);
window.removeEventListener('mouseup', handleUpSliderItem);
setTimeout(function () {
setMove(false);
}, 0);
}
// 通过角度计算位置
function computedRange(angle) {
if (angle === void 0) {
angle = 0;
}
var radian = Math.PI / 180 * angle;
var left = 21 + Math.sin(radian) * 25;
var top = 21 - Math.cos(radian) * 25;
return {
left: left,
top: top
};
}
// 按下渐变角度句柄
function handleDownRange() {
window.addEventListener('mousemove', handleMoveRange);
window.addEventListener('mouseup', handleUpRange);
}
// 移动渐变角度句柄
function handleMoveRange(e) {
var panel = rangeRefPanel.current.getBoundingClientRect();
var panelX = panel.x + 25;
var panelY = panel.y + 25;
var x = Math.abs(e.x - panelX);
var y = Math.abs(e.y - panelY);
var angle = Math.round(Math.atan(x / y) * 180 / Math.PI);
// 二象限
if (e.y > panelY && e.x > panelX) {
angle = 180 - angle;
}
// 三象限
if (e.x <= panelX && e.y > panelY) {
angle = 180 + angle;
}
// 四象限
if (e.x < panelX && e.y < panelY) {
angle = 360 - angle;
}
setRange(angle);
gradientChange(angle, colors);
}
// 抬起渐变角度句柄
function handleUpRange() {
window.removeEventListener('mousemove', handleMoveRange);
window.removeEventListener('mouseup', handleUpRange);
}
return React__default.createElement("div", {
className: "Theme-GradientColor"
}, React__default.createElement("div", {
className: "Theme-GradientColor-slider"
}, React__default.createElement("div", {
ref: slider,
className: "Theme-GradientColor-slider-inner",
style: {
backgroundImage: "linear-gradient(to right,".concat(colors.map(function (item) {
return "".concat(item.color, " ").concat(item.position, "%");
}).join(','), ")")
},
onClick: handleClickSlider
}, colors.map(function (item, i) {
return React__default.createElement("div", {
key: i,
className: cx('Theme-GradientColor-slider-inner-item', i === index && 'Theme-GradientColor-slider-inner-item--active'),
onMouseDown: function (e) {
handleDownSliderItem(e, i);
},
onClick: function (e) {
e.stopPropagation();
},
style: {
left: "calc(".concat(item.position, "% - 7px)"),
background: item.color
}
});
})), React__default.createElement("div", {
className: "Theme-GradientColor-range",
ref: rangeRef,
onClick: function (e) {
setRangeShow(true);
e.stopPropagation();
window.addEventListener('click', function () {
setRangeShow(false);
});
}
}, React__default.createElement(NumberInput, {
formatter: function (value) {
return value + '°';
},
max: 360,
min: 0,
value: range,
onChange: rangeChange
}), React__default.createElement(Overlay
// @ts-ignore
, {
// @ts-ignore
container: document.body,
// @ts-ignore
target: rangeRef.current,
show: rangeShow,
placement: "center-bottom-center-top",
rootClose: false,
offset: [0, 4]
}, React__default.createElement(PopOver, null, React__default.createElement("div", {
className: "Theme-GradientColor-range-panel"
}, React__default.createElement("div", {
className: "Theme-GradientColor-range-panel-title"
}, "\u6E10\u53D8\u89D2\u5EA6"), React__default.createElement("div", {
className: "Theme-GradientColor-range-panel-content",
ref: rangeRefPanel
}, React__default.createElement("div", {
className: "Theme-GradientColor-range-panel-content-handler",
onMouseDown: handleDownRange,
style: {
left: computedRange(range).left + 'px',
top: computedRange(range).top + 'px'
}
}))))))), React__default.createElement(SketchPicker, {
width: "216px",
color: (_a = colors[index]) === null || _a === void 0 ? void 0 : _a.color,
onChangeComplete: function (value) {
var color = value.hex;
if (value.rgb.a !== 1) {
var rag = value.rgb;
color = "rgba(".concat(rag.r, ", ").concat(rag.g, ", ").concat(rag.b, ", ").concat(rag.a, ")");
}
var colorsTemp = cloneDeep(colors);
colorsTemp[index].color = color;
setColors(colorsTemp);
gradientChange(range, colorsTemp);
}
}));
}
function ColorSelect(props) {
var show = props.show,
target = props.target,
themeList = props.themeList,
onChange = props.onChange,
close = props.close,
value = props.value,
needGradient = props.needGradient,
needTheme = props.needTheme,
needCustom = props.needCustom;
var _a = useState(0),
tab = _a[0],
setTab = _a[1];
var _b = useState(0),
subTab = _b[0],
setSubTab = _b[1];
var tabList = [{
name: 'color'
}, needGradient && {
name: 'gradient'
}
// needGradient && {
// name: 'img',
// icon: <ThemeIcon icon="color-picker-img" />,
// activeIcon: <ThemeIcon icon="color-picker-img-active" />
// }
].filter(function (n) {
return n;
});
var subTabList = [needTheme && themeList && themeList.length > 0 && {
name: i18n("a1c76c6e1bd796959e536718e04d10ca"),
parent: 0,
id: 0
}, needCustom && {
name: i18n("255f442c4a1b92624a6e96541202a0be"),
parent: 0,
id: 1
}].filter(function (n) {
return n;
});
function setSubTabCheck() {
if (needTheme && (value === null || value === void 0 ? void 0 : value.indexOf('var')) === 0 || value === 'transparent') {
setSubTab(0);
} else if (needCustom) {
setSubTab(1);
}
}
useEffect(function () {
if (needTheme && ((value === null || value === void 0 ? void 0 : value.indexOf('var')) === 0 || value === 'transparent')) {
setTab(0);
setSubTab(0);
} else if (needGradient && (value === null || value === void 0 ? void 0 : value.indexOf('linear-gradient')) === 0) {
setTab(1);
} else if (needCustom) {
setTab(0);
setSubTab(1);
}
}, [show]);
useEffect(function () {
if (needTheme) {
setSubTab(0);
} else if (needCustom) {
setSubTab(1);
}
}, [needCustom, needTheme]);
function renderSubTab() {
var list = subTabList.filter(function (item) {
return item.parent === tab;
});
if (list.length > 1) {
return React__default.createElement("div", {
className: "Theme-ColorSelect-tab-sub"
}, list.map(function (item) {
return React__default.createElement("div", {
key: item.id,
className: cx('Theme-ColorSelect-tab-sub-item', subTab === item.id && 'Theme-ColorSelect-tab-sub--active'),
onClick: function () {
return setSubTab(item.id);
}
}, item.name);
}));
} else {
return null;
}
}
return React__default.createElement(Overlay
// @ts-ignore
, {
// @ts-ignore
container: document.body,
target: target.current,
show: show,
// placement="right-bottom-right-top"
offset: [0, 4]
}, React__default.createElement(PopOver, {
overlay: true,
onHide: close
}, React__default.createElement("div", {
className: "Theme-ColorSelect"
}, tabList.length > 1 ? React__default.createElement("div", {
className: "Theme-ColorSelect-tab"
}, tabList.map(function (item, index) {
return React__default.createElement("div", {
key: index,
className: cx('Theme-ColorSelect-tab-' + item.name, tab === index && "Theme-ColorSelect-tab-".concat(item.name, "--active")),
onClick: function () {
setTab(index);
setSubTabCheck();
}
}, tab === index ? item.activeIcon : item.icon);
})) : null, renderSubTab(), React__default.createElement("div", {
className: "Theme-ColorSelect-content"
}, tab === 0 ? React__default.createElement("div", {
className: "Theme-ColorSelect-content-color"
}, subTab === 0 ? React__default.createElement(ThemeColorList, __assign({}, props, {
themeList: themeList,
onChange: function (value) {
onChange(value);
close(true);
},
value: value
})) : null, subTab === 1 ? React__default.createElement(CustomColor, {
onChange: onChange,
value: value,
themeList: themeList
}) : null) : null, tab === 1 ? React__default.createElement(GradientColor, {
value: value,
onChange: onChange,
themeList: themeList
}) : null))));
}
function ColorPicker(props) {
var value = props.value,
options = props.options,
data = props.data,
onChange = props.onChange,
labelMode = props.labelMode,
needGradient = props.needGradient,
needTheme = props.needTheme,
needCustom = props.needCustom,
placeholder = props.placeholder;
var themeList = options;
if (typeof options === 'string') {
themeList = resolveVariableAndFilter(options, data, '| raw');
}
var container = useRef(null);
var target = useRef(null);
var _a = useState(value || placeholder),
color = _a[0],
setColor = _a[1];
var _b = useState(false),
show = _b[0],
setShow = _b[1];
function colorSelectHandler() {
setShow(!show);
}
useEffect(function () {
setColor(value || placeholder);
}, [value]);
return React__default.createElement("div", {
className: "Theme-ColorPicker",
ref: container
}, React__default.createElement("div", {
className: cx('Theme-ColorPicker', labelMode === 'input' && 'Theme-ColorPicker--input'),
onClick: colorSelectHandler,
ref: target
}, React__default.createElement("div", {
className: "ThemeColor--transparent Theme-ColorPicker-label-out"
}, findColor(color, themeList).value ? React__default.createElement(TooltipWrapper, {
trigger: "hover",
placement: "left",
disabled: labelMode === 'input',
tooltip: {
children: function () {
return React__default.createElement("div", null, findColor(color, themeList).label);
}
}
}, React__default.createElement("div", {
className: cx('Theme-ColorPicker-label'),
style: {
background: findColor(color, themeList).value
}
})) : null), labelMode === 'input' ? React__default.createElement(React__default.Fragment, null, React__default.createElement("div", {
className: cx('Theme-ColorPicker-input')
}, React__default.createElement("div", null, findColor(color, themeList).label)), React__default.createElement("span", {
className: cx('Theme-ColorPicker-arrow', show && 'Theme-ColorPicker-arrow--active')
}, React__default.createElement(Icon, {
icon: "right-arrow-bold",
className: "icon"
}))) : null), React__default.createElement(ColorSelect, __assign({}, props, {
needGradient: needGradient,
needTheme: needTheme,
needCustom: needCustom,
value: value || placeholder || '',
show: show,
close: function () {
setShow(false);
},
container: container,
target: target,
themeList: themeList,
onChange: onChange
})));
}
function ColorPickerControl(props) {
var _a, _b, _c, _d;
var editorDefaultValue = getValueByPath(props.editorThemePath || '', props.data);
var value = props.value || editorDefaultValue;
return React__default.createElement(React__default.Fragment, null, React__default.createElement(ColorPicker, __assign({}, props, {
value: value,
options: props.options || props.data.colorOptions,
labelMode: (_a = props.labelMode) !== null && _a !== void 0 ? _a : 'default',
needGradient: (_b = props.needGradient) !== null && _b !== void 0 ? _b : false,
needTheme: (_c = props.needTheme) !== null && _c !== void 0 ? _c : true,
needCustom: (_d = props.needCustom) !== null && _d !== void 0 ? _d : false
})));
}
/** @class */(function (_super) {
__extends(ColorPickerRenderer, _super);
function ColorPickerRenderer() {
return _super !== null && _super.apply(this, arguments) || this;
}
Object.defineProperty(ColorPickerRenderer.prototype, "render", {
enumerable: false,
configurable: true,
writable: true,
value: function () {
var _a, _b, _c, _d;
return React__default.createElement(ColorPickerControl, __assign({}, this.props, {
labelMode: (_a = this.props.labelMode) !== null && _a !== void 0 ? _a : 'default',
needGradient: (_b = this.props.needGradient) !== null && _b !== void 0 ? _b : false,
needTheme: (_c = this.props.needTheme) !== null && _c !== void 0 ? _c : true,
needCustom: (_d = this.props.needCustom) !== null && _d !== void 0 ? _d : false
}));
}
});
ColorPickerRenderer = __decorate([FormItem({
type: 'amis-theme-color-picker',
strictMode: false,
renderLabel: true
})], ColorPickerRenderer);
return ColorPickerRenderer;
})(React__default.Component);
export { ColorPicker as default };