UNPKG

eapp-amis-theme-editor

Version:

amis主题编辑器

721 lines (717 loc) 24.2 kB
/** * 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 };