UNPKG

amis-theme-editor

Version:

amis主题编辑器

590 lines (580 loc) 20.6 kB
/** * amis-theme-editor v2.0.22-beta.2 * Copyright 2018-2023 @fex */ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var tslib = require('tslib'); var React = require('react'); var amisUi = require('amis-ui'); var amisCore = require('amis-core'); var lodash = require('lodash'); var amisThemeEditorHelper = require('amis-theme-editor-helper'); var BaseContent = require('./BaseContent.js'); require('../renderers/PaddingAndMargin.js'); require('../renderers/Border.js'); require('../renderers/Radius.js'); require('../renderers/ColorPicker.js'); require('../renderers/Size.js'); require('../renderers/Font.js'); require('../renderers/Shadow.js'); require('../renderers/ThemeWrapper.js'); var Color = require('../global/Color.js'); var Font = require('../global/Font.js'); var Border = require('../global/Border.js'); var Size = require('../global/Size.js'); var Shadow = require('../global/Shadow.js'); var index = require('../component/index.js'); require('../icons/index.js'); var tpl = require('../tpl.js'); var i18nRuntime = require('i18n-runtime'); var amis = require('amis'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var React__default = /*#__PURE__*/_interopDefaultLegacy(React); /** * 主题编辑器 */ var CSS_NAMESPACE = ['.ThemeEditor-body-content-item-content', '.Theme-ColorSelect', '.Theme-ColorPicker', '.themeEditor-DialogView', '.UserPicker-Body']; var navList = [{ label: '', children: [{ icon: 'global', label: i18nRuntime.i18n("b3652bdb239c558126e9981229c46adf"), key: 'global' }, { icon: 'component', label: i18nRuntime.i18n("16e90fff8cc77b24a91541b5d76b2c8b"), key: 'component', isSvg: true }, { icon: 'code', label: i18nRuntime.i18n("cf209d136a55c008586b4d75832a55e0"), key: 'custom' }] }]; var globalStyleTab = [{ label: '', children: [{ label: i18nRuntime.i18n("6b36c6f7ec834692ec6c8e3816349fdd"), key: 'color', component: Color["default"] }, { label: i18nRuntime.i18n("8456bc40d48da5af833f1c63385e9879"), key: 'font', component: Font["default"] }, { label: i18nRuntime.i18n("961534b4ea37e4e88aada736b299d063"), key: 'border', component: Border["default"] }, { label: i18nRuntime.i18n("c8339fd2a85af4ba66084d28df808de4"), key: 'space', component: Size["default"] }, { label: i18nRuntime.i18n("803205e38834280d9e6a75993ac00764"), key: 'shadow', component: Shadow["default"] }] }]; var componentStyleTab = index.getAllComponent(); var customStyleTab = [{ label: '', children: [] }]; var tabList = { global: globalStyleTab, component: componentStyleTab, custom: customStyleTab }; var themeConfig = { title: i18nRuntime.i18n("b9420c6f66a59ff2d7e324dc736dcd47"), path: 'config', activeId: null, body: tpl.getSchemaTpl('normal', [{ type: 'input-text', label: i18nRuntime.i18n("2cdc6176e4ee0e11c71235932d3619ce"), required: true, name: 'name' }, // { // type: 'input-text', // label: '标识', // disabled: true, // name: 'key' // }, // { // type: 'radios', // label: '启用状态', // name: 'status', // options: [ // { // label: '启用', // value: true // }, // { // label: '停用', // value: false // } // ] // }, { type: 'textarea', label: i18nRuntime.i18n("3bdd08adab6ea90b9164b20a0e4151ac"), name: 'description' }]) }; var ThemeEditor = function (props) { var _a = React__default["default"].useState(), themePanelConfig = _a[0], setThemePanelConfig = _a[1]; var _b = React__default["default"].useState(true), themePanelClose = _b[0], setThemePanelClose = _b[1]; var _c = React__default["default"].useState(true), themePanelInnerClose = _c[0], setThemePanelInnerClose = _c[1]; var value = props.value, name = props.name, versionData = props.versionData; var _d = React__default["default"].useState(value), data = _d[0], setData = _d[1]; var _e = React__default["default"].useState(lodash.cloneDeep(versionData)), source = _e[0], setSource = _e[1]; var _f = React__default["default"].useState(''), themeName = _f[0], setThemeName = _f[1]; var _g = React__default["default"].useState(), nav = _g[0], setNav = _g[1]; var _h = React__default["default"].useState(), tab = _h[0], setTab = _h[1]; var _j = React__default["default"].useState(), content = _j[0], setContent = _j[1]; var _k = React__default["default"].useState(''), activeToken = _k[0], setActiveEditColor = _k[1]; var _l = React__default["default"].useState(''), refreshToken = _l[0], setRefreshToken = _l[1]; var _m = React__default["default"].useState(null), filterComponent = _m[0], setFilterComponent = _m[1]; function handleReFreshToken(token) { setRefreshToken(token); setTimeout(function () { setRefreshToken(''); }); } // 修改正在编辑的颜色的token function handleSetActiveToken(token) { if (token === activeToken) { setActiveEditColor(''); } else { setActiveEditColor(token); } } function changeThemeData() { return tslib.__awaiter(this, void 0, void 0, function () { var themeData, parseThemeData; return tslib.__generator(this, function (_a) { themeData = value; setThemeName(name); setData(themeData); parseThemeData = new amisThemeEditorHelper.ParseThemeData(themeData, CSS_NAMESPACE); parseThemeData.generator(); amisThemeEditorHelper.insertStyle(parseThemeData.getStyle(), 'theme'); return [2 /*return*/]; }); }); } // 切换query默认Nav下Tab function toggleNavTab() { var query = amisCore.parseQuery(window.location); var _a = query.nav, nav = _a === void 0 ? 'global' : _a, _b = query.tab, tab = _b === void 0 ? 'color' : _b; var currentNav = tabList[nav] || []; var tabChildren = []; currentNav.forEach(function (item) { tabChildren = tslib.__spreadArray(tslib.__spreadArray([], tabChildren, true), item.children, true); }); tabChildren === null || tabChildren === void 0 ? void 0 : tabChildren.find(function (item) { if (item.key === tab) { setNav(nav); setTab(item.key); setContent(item.component); handleCloseRightPanel(); return true; } return false; }); } // 加参数到url上 function updateUrl(state) { var location = window.location; var query = amisCore.parseQuery(location); query = Object.assign({}, query, state); var url = "".concat(origin).concat(location.pathname, "?").concat(amisCore.qsstringify(query)); history.replaceState({}, document.title, url); } // 合并新增Tab function mergeNavConfig() { var _a; // 更新组件目录 tabList.component = index.getAllComponent(); var moreNavConfig = props.moreNavConfig; if (moreNavConfig) { var globalChildren = tabList.global[0].children; var componentChildren = tabList.component[0].children; var customChildren = tabList.custom[0].children; var children_1 = { globalStyleTab: globalChildren, componentStyleTab: componentChildren, customStyleTab: customChildren }; var _loop_1 = function (key) { var k = key; (_a = moreNavConfig[k]) === null || _a === void 0 ? void 0 : _a.forEach(function (item) { var isExist = children_1[k].find(function (ele) { return ele.key === item.key; }); !isExist && children_1[k].push(item); }); }; for (var key in moreNavConfig) { _loop_1(key); } } } React__default["default"].useEffect(function () { mergeNavConfig(); // 切换query默认Tab toggleNavTab(); }, []); React__default["default"].useEffect(function () { changeThemeData(); }, [value]); // 子组件改变触发 function onChange(data) { var value = lodash.cloneDeep(data); setData(value); props.onChange && props.onChange(value); var parseThemeData = new amisThemeEditorHelper.ParseThemeData(value, CSS_NAMESPACE); parseThemeData.generator(); amisThemeEditorHelper.insertStyle(parseThemeData.getStyle(), 'theme'); } // 右侧配置面板获取数据 function getFormData(value) { if (!value || !(themePanelConfig === null || themePanelConfig === void 0 ? void 0 : themePanelConfig.path)) { return {}; } var path = themePanelConfig.path.split('.'); // @ts-ignore var children = value[path[0]]; for (var i = 1; i < path.length; i++) { children = children[path[i]]; } return children; } // 过滤掉空数据 function filterNullData(data) { var res = {}; for (var key in data) { if (typeof data[key] === 'object' && data[key] !== null && !Array.isArray(data[key])) { res[key] = filterNullData(data[key]); } else if (data[key] !== null) { res[key] = data[key]; } } return res; } // 子组件修改右侧面板配置 function handleSetConfig(newPanelConfig) { var _a, _b; if (newPanelConfig.path !== (themePanelConfig === null || themePanelConfig === void 0 ? void 0 : themePanelConfig.path) || newPanelConfig.activeId !== (themePanelConfig === null || themePanelConfig === void 0 ? void 0 : themePanelConfig.activeId)) { setThemePanelInnerClose(true); setThemePanelConfig({ title: '', path: '', activeId: null, body: [] }); // 图标的配置窗口用的是动态插入,如果存在动态节点则隐藏动态节点 var panelTitleNode = document.getElementsByClassName('ThemeEditor-body-rightPanel-title'); var panelBodyNode = document.getElementsByClassName('ThemeEditor-body-rightPanel-body'); var titleChildNodes = (_a = panelTitleNode[0]) === null || _a === void 0 ? void 0 : _a.childNodes; var bodyChildNodes = (_b = panelBodyNode[0]) === null || _b === void 0 ? void 0 : _b.childNodes; if ((titleChildNodes === null || titleChildNodes === void 0 ? void 0 : titleChildNodes.length) && (bodyChildNodes === null || bodyChildNodes === void 0 ? void 0 : bodyChildNodes.length)) { [titleChildNodes, bodyChildNodes].forEach(function (item) { for (var i = 0; i < item.length; i++) { if (item[i].nodeName === 'DIV') { item[i].style.display = 'none'; } } }); } setTimeout(function () { setThemePanelConfig(newPanelConfig); setThemePanelInnerClose(false); setThemePanelClose(false); }, 230); } } //右侧面板 var RightPanelBody = function (themePanelConfig) { if (!themePanelConfig) { return null; } var formData = Object.assign(filterNullData(getFormData(lodash.cloneDeep(data))), amisThemeEditorHelper.getGlobalData(data)); return amisCore.render({ type: 'form', // debug: true, mode: 'horizontal', labelAlign: 'left', labelWidth: 65, wrapWithPanel: false, submitOnChange: true, body: themePanelConfig === null || themePanelConfig === void 0 ? void 0 : themePanelConfig.body }, { data: formData, onFinished: function (form) { var value = lodash.cloneDeep(data); var children = getFormData(value); for (var key in form) { if (['colorOptions', 'fontFamilyOptions', 'fontSizeOptions', 'lineHeightOptions', 'fontWeightOptions', 'borderRadiusOptions', 'borderWidthOptions', 'borderStyleOptions', 'sizesOptions', 'shadowOptions'].includes(key)) { continue; } if (form.hasOwnProperty(key)) { if (typeof form[key] === 'object') { if (Array.isArray(form[key]) || form[key].boxShadow) { // 数组需要直接赋值 TODO:代码优化 children[key] = lodash.cloneDeep(form[key]); } else { children[key] = lodash.defaultsDeep(lodash.cloneDeep(form[key]), children[key]); } } else { children[key] = form[key]; } } } setData(value); props.onChange && props.onChange(value); var parseThemeData = new amisThemeEditorHelper.ParseThemeData(value, CSS_NAMESPACE); parseThemeData.generator(); amisThemeEditorHelper.insertStyle(parseThemeData.getStyle(), 'theme'); } }); }; function handleExit() { props.onBack(); } // 关闭右侧面板,清空表单项 function handleCloseRightPanel() { setThemePanelClose(true); setTimeout(function () { setThemePanelConfig({ title: '', path: '', activeId: null, body: [] }); }, 500); } function handleSaveDraft() { return tslib.__awaiter(this, void 0, void 0, function () { return tslib.__generator(this, function (_a) { props.onSaveDraft(data); return [2 /*return*/]; }); }); } function handleSave() { return tslib.__awaiter(this, void 0, void 0, function () { var res; return tslib.__generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, props.onSave(data)]; case 1: res = _a.sent(); if (res) { setSource(lodash.cloneDeep(data)); } return [2 /*return*/]; } }); }); } function onComponentSearch(item) { var regular = item ? new RegExp(item, 'i') : null; if (regular) { var originComponent = lodash.cloneDeep(tabList.component); var filterComponent_1 = []; originComponent.forEach(function (item) { var filterchildren = []; item.children.forEach(function (child) { if (regular.test(child.key) || regular.test(child.label)) { filterchildren.push(child); } }); if (filterchildren.length) { item.children = filterchildren; filterComponent_1.push(item); } }); setFilterComponent(filterComponent_1); } else { setFilterComponent(null); } } var renderHeader = function () { var dataIsEqual = lodash.isEqual(source, data); return React__default["default"].createElement("div", { className: "Editor-header ThemeEditor-header" }, React__default["default"].createElement("div", { className: "Editor-title" }, React__default["default"].createElement("div", { className: "editor-back-icon", onClick: handleExit }, React__default["default"].createElement(amisUi.Icon, { icon: "down-arrow-bold", className: "left-arrow" })), React__default["default"].createElement("div", { className: "page-title-text" }, i18nRuntime.i18n("03b6472ec3f65ccbfb197aafa22bf437"), " ", themeName), React__default["default"].createElement("div", { onClick: function () { return handleSetConfig(themeConfig); }, className: amisCore.classnames(':ThemeEditor-header-setting', (themePanelConfig === null || themePanelConfig === void 0 ? void 0 : themePanelConfig.path) === 'config' && ':ThemeEditor-header-setting--active') }, React__default["default"].createElement("i", { className: "iconfont icon-setting" }))), React__default["default"].createElement("div", { className: "Editor-header-actions" }, props.actions, React__default["default"].createElement(amisUi.Button, { onClick: handleSaveDraft, className: "header-action-btn preview-btn margin-left-space", level: "primary" }, i18nRuntime.i18n("d8acae3bcfbc9ec9ade58c2dbacf65aa")), React__default["default"].createElement(amisUi.Button, { disabled: dataIsEqual, level: "primary", onClick: handleSave, className: amisCore.classnames('header-action-btn', dataIsEqual && 'disabled') }, i18nRuntime.i18n("be5fbbe34ce9979bfb6576d9eddc5612")))); }; var renderContent = function (component) { if (!component) { return null; } return BaseContent["default"](component(tslib.__assign(tslib.__assign({}, props), { data: data, setConfig: handleSetConfig, activeId: (themePanelConfig === null || themePanelConfig === void 0 ? void 0 : themePanelConfig.activeId) || (themePanelConfig === null || themePanelConfig === void 0 ? void 0 : themePanelConfig.path), onChange: onChange, activeToken: activeToken, handleSetActiveToken: handleSetActiveToken, handleCloseRightPanel: handleCloseRightPanel, refreshToken: refreshToken, handleReFreshToken: handleReFreshToken })), handleSetConfig); }; if (!data) { return null; } return React__default["default"].createElement(amisUi.Layout, { header: renderHeader(), headerClassName: ":Editor-page-header", bodyClassName: "Editor-page", mainClassName: "h-0", contentClassName: ":Editor-body", asideFixed: true, headerFixed: false }, React__default["default"].createElement("div", { style: { display: 'none' } }, JSON.stringify(data)), React__default["default"].createElement("div", { className: "ThemeEditor-body" }, React__default["default"].createElement("div", { className: "ThemeEditor-body-leftTab" }, React__default["default"].createElement(amisUi.AsideNav, { className: ":ThemeEditor-nav", navigations: navList, renderLink: function (item) { var link = item.link; return React__default["default"].createElement("div", { onClick: function () { setNav(link.key); setTab(tabList[link.key][0].children[0].key); setContent(tabList[link.key][0].children[0].component); updateUrl({ nav: link.key, tab: tabList[link.key][0].children[0].key }); handleCloseRightPanel(); setFilterComponent(null); }, className: "ThemeEditor-nav-item", "editor-tooltip": link.label }, React__default["default"].createElement(amis.Icon, { icon: link.icon, className: "ThemeEditor-nav-icon" })); }, isActive: function (item) { return item.key === nav; } }), React__default["default"].createElement("div", { className: "ThemeEditor-tab" }, nav === 'component' && React__default["default"].createElement("div", { className: "ThemeEditor-tab-search" }, React__default["default"].createElement(amisUi.SearchBox, { mini: false, clearable: true, placeholder: i18nRuntime.i18n("8d81823ea62fc676658ae560a27879a7"), onChange: function (item) { return onComponentSearch(item); }, onSearch: function (item) { return onComponentSearch(item); } })), React__default["default"].createElement(amisUi.AsideNav, { navigations: nav ? nav === 'component' && filterComponent ? filterComponent : tabList[nav] : [], renderLink: function (item) { var link = item.link; return React__default["default"].createElement("div", { onClick: function () { setTab(link.key); setContent(link.component); updateUrl({ tab: link.key }); handleCloseRightPanel(); }, className: "ThemeEditor-tab-item" }, link.label); }, isActive: function (item) { return item.key === tab; } }))), renderContent(content), React__default["default"].createElement("div", { className: amisCore.classnames(':ThemeEditor-body-rightPanel', themePanelClose && ':ThemeEditor-body-rightPanel--close') }, React__default["default"].createElement("div", { className: amisCore.classnames(':ThemeEditor-body-rightPanel-inner', themePanelInnerClose && ':ThemeEditor-body-rightPanelInner--close') }, React__default["default"].createElement("div", { className: "ThemeEditor-body-rightPanel-title" }, themePanelConfig === null || themePanelConfig === void 0 ? void 0 : themePanelConfig.title, React__default["default"].createElement(amisUi.Icon, { icon: "close", onClick: function () { return handleCloseRightPanel(); } })), React__default["default"].createElement("div", { className: "ThemeEditor-body-rightPanel-body" }, RightPanelBody(themePanelConfig)))))); }; exports["default"] = ThemeEditor; exports.themeConfig = themeConfig;