diff --git a/packages/amis-editor-core/package.json b/packages/amis-editor-core/package.json index ee7b6d8ab..f495b1efd 100644 --- a/packages/amis-editor-core/package.json +++ b/packages/amis-editor-core/package.json @@ -114,6 +114,7 @@ "amis-core": "*", "amis-formula": "*", "amis-ui": "*", + "amis-theme-editor-helper": "*", "i18n-runtime": "*", "react": ">=16.8.6", "react-dom": ">=16.8.6" diff --git a/packages/amis-editor-core/scss/editor.scss b/packages/amis-editor-core/scss/editor.scss index 000a366b4..8a6b312a6 100644 --- a/packages/amis-editor-core/scss/editor.scss +++ b/packages/amis-editor-core/scss/editor.scss @@ -48,7 +48,7 @@ @import './style-control/background'; @import './style-control/size'; @import './style-control/style-common'; -@import './style-control/theme_classname'; +@import './style-control/theme-css-code'; @keyframes growing { 0% { diff --git a/packages/amis-editor-core/scss/style-control/_theme-css-code.scss b/packages/amis-editor-core/scss/style-control/_theme-css-code.scss new file mode 100644 index 000000000..7f7b43a1c --- /dev/null +++ b/packages/amis-editor-core/scss/style-control/_theme-css-code.scss @@ -0,0 +1,85 @@ +.ThemeCssCode { + position: relative; + &-button { + width: 100%; + } + .is-group { + overflow: auto; + } +} +.icon-theme-css { + margin-right: 10px; +} +.ThemeCssCode-editor { + height: auto; + width: px2rem(460px); + padding: px2rem(16px); + position: relative; + &-title { + font-size: 14px; + margin-bottom: px2rem(16px); + } + &-close { + position: absolute; + top: px2rem(14px); + right: px2rem(16px); + button { + height: px2rem(16px); + padding: 0; + margin: 0; + } + } + &-content { + height: px2rem(500px); + width: 100%; + &-header { + display: flex; + margin-bottom: px2rem(10px); + border-bottom: 1px solid #e8e9eb; + + &-title { + margin-right: px2rem(30px); + cursor: pointer; + padding-bottom: px2rem(10px); + } + &-title--active { + color: #2468f2; + border-bottom: 2px solid #2468f2; + } + } + &-main { + overflow: auto; + height: px2rem(460px); + } + &-body--hidden { + display: none; + } + &-body { + margin-bottom: px2rem(10px); + &-title { + margin-bottom: px2rem(10px); + margin-left: px2rem(16px); + font-size: 12px; + } + &-editor { + height: 200px; + margin-bottom: px2rem(10px); + border-bottom: 1px solid #e8e9eb; + } + } + } +} +.editorPanel-inner { + .Theme-FontEditor { + .Theme-Wrapper-header-left { + font-weight: 400; + color: #5c5f66; + } + } + .Theme-ShadowEditor { + .Theme-Wrapper-header-left { + font-weight: 400; + color: #5c5f66; + } + } +} diff --git a/packages/amis-editor-core/scss/style-control/_theme_classname.scss b/packages/amis-editor-core/scss/style-control/_theme_classname.scss deleted file mode 100644 index e77ee9762..000000000 --- a/packages/amis-editor-core/scss/style-control/_theme_classname.scss +++ /dev/null @@ -1,48 +0,0 @@ -.ThemeClassName { - position: relative; - &-button { - position: absolute; - left: px2rem(-38px); - } - .is-group { - overflow: auto; - } -} -.ThemeClassName-editor { - height: auto; - width: px2rem(400px); - padding: px2rem(16px); - position: relative; - &-title { - font-size: 14px; - margin-bottom: px2rem(16px); - } - &-close { - position: absolute; - top: px2rem(14px); - right: px2rem(16px); - button { - height: px2rem(16px); - padding: 0; - margin: 0; - } - } - &-content { - height: px2rem(500px); - width: 100%; - } -} -.editorPanel-inner { - .Theme-FontEditor { - .Theme-Wrapper-header-left { - font-weight: 400; - color: #5c5f66; - } - } - .Theme-ShadowEditor { - .Theme-Wrapper-header-left { - font-weight: 400; - color: #5c5f66; - } - } -} diff --git a/packages/amis-editor-core/src/store/editor.ts b/packages/amis-editor-core/src/store/editor.ts index cee2316c9..d12fd1d80 100644 --- a/packages/amis-editor-core/src/store/editor.ts +++ b/packages/amis-editor-core/src/store/editor.ts @@ -18,6 +18,7 @@ import { needDefaultWidth, guid, addStyleClassName, + setThemeDefaultData, appTranslate } from '../../src/util'; import { @@ -528,7 +529,8 @@ export const MainStore = types getValueOf(id: string) { const schema = JSONGetById(self.schema, id); - const res = JSONPipeOut(schema, false); + const data = JSONPipeOut(schema, false); + const res = setThemeDefaultData(data); return res; }, @@ -546,7 +548,8 @@ export const MainStore = types key !== '$$commonSchema') || typeof props === 'function' || // pipeIn 和 pipeOut key.substring(0, 2) === '__' || - key === 'css' || + key === 'themeCss' || + key === 'editorPath' || key === 'editorState') // 样式不需要出现做json中, ); }, diff --git a/packages/amis-editor-core/src/util.ts b/packages/amis-editor-core/src/util.ts index 142e98d1c..9089c5d2d 100644 --- a/packages/amis-editor-core/src/util.ts +++ b/packages/amis-editor-core/src/util.ts @@ -9,6 +9,8 @@ import isPlainObject from 'lodash/isPlainObject'; import isNumber from 'lodash/isNumber'; import type {Schema} from 'amis'; import {SchemaObject} from 'amis/lib/Schema'; +import {assign, cloneDeep} from 'lodash'; +import {getGlobalData} from 'amis-theme-editor-helper'; const { guid, @@ -39,6 +41,8 @@ export { createObject }; +export let themeConfig: any = {}; + export function __uri(id: string) { return id; } @@ -198,15 +202,16 @@ export function JSONPipeOut( } /** - * 如果存在css属性,则给对应的className加上name + * 如果存在themeCss属性,则给对应的className加上name */ export function addStyleClassName(obj: Schema) { - const css = obj.css; - if (!obj.css) { + const themeCss = obj.themeCss || obj.css; + // page暂时不做处理 + if (!themeCss || obj.type === 'page') { return obj; } let toUpdate: any = {}; - Object.keys(css).forEach(key => { + Object.keys(themeCss).forEach(key => { if (key !== '$$id') { let classname = `${key}-${obj.id.replace('u:', '')}`; if (!obj[key]) { @@ -695,18 +700,23 @@ export function filterSchemaForEditor(schema: any): any { mapped[key] = filtered; // 组件切换状态修改classname - if (/[C|c]lassName/.test(key) && schema.editorState) { - mapped[key] = mapped[key] - ? mapped[key] + ' ' + schema.editorState - : schema.editorState; - modified = true; - } + // TODO:切换状态暂时先不改变组件的样式 + // if (/[C|c]lassName/.test(key) && schema.editorState) { + // mapped[key] = mapped[key] + // ? mapped[key] + ' ' + schema.editorState + // : schema.editorState; + // modified = true; + // } if (filtered !== value) { modified = true; } }); - return modified ? mapped : schema; + const finalSchema = modified ? mapped : schema; + if (finalSchema?.type) { + return setThemeDefaultData(finalSchema); + } + return finalSchema; } return schema; @@ -1083,3 +1093,15 @@ export function needFillPlaceholder(curProps: any) { } return needFillPlaceholder; } +// 设置主题数据 +export function setThemeConfig(config: any) { + themeConfig = config; +} + +// 将主题数据传入组件的schema +export function setThemeDefaultData(data: any) { + const schemaData = cloneDeep(data); + schemaData.themeConfig = themeConfig; + assign(schemaData, getGlobalData(themeConfig)); + return schemaData; +} diff --git a/packages/amis-editor/src/icons/index.tsx b/packages/amis-editor/src/icons/index.tsx index 8dbae9286..999e6aa13 100644 --- a/packages/amis-editor/src/icons/index.tsx +++ b/packages/amis-editor/src/icons/index.tsx @@ -175,6 +175,9 @@ import jFlexEnd from './display/jFlexEnd.svg'; import jSpaceBetween from './display/jSpaceBetween.svg'; import jSpaceAround from './display/jSpaceAround.svg'; +// 主题 +import themeCss from './theme/css.svg'; + // 功能类组件 icon x 11 registerIcon('audio-plugin', audio); registerIcon('custom-plugin', custom); @@ -336,4 +339,7 @@ registerIcon('jFlexEnd', jFlexEnd); registerIcon('jSpaceBetween', jSpaceBetween); registerIcon('jSpaceAround', jSpaceAround); +// 主题 +registerIcon('theme-css', themeCss); + export {Icon}; diff --git a/packages/amis-editor/src/icons/theme/css.svg b/packages/amis-editor/src/icons/theme/css.svg new file mode 100644 index 000000000..f4e98397e --- /dev/null +++ b/packages/amis-editor/src/icons/theme/css.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/amis-editor/src/index.tsx b/packages/amis-editor/src/index.tsx index 7614826cf..402436565 100644 --- a/packages/amis-editor/src/index.tsx +++ b/packages/amis-editor/src/index.tsx @@ -178,7 +178,7 @@ import './renderer/FeatureControl'; import './renderer/event-control/index'; import './renderer/TreeOptionControl'; import './renderer/TransferTableControl'; -import './renderer/style-control/ThemeClassName'; +import './renderer/style-control/ThemeCssCode'; import './renderer/ButtonGroupControl'; import './renderer/FlexSettingControl'; import 'amis-theme-editor/lib/renderers/Border'; diff --git a/packages/amis-editor/src/plugin/Button.tsx b/packages/amis-editor/src/plugin/Button.tsx index 4fa4b4a21..791b0778b 100644 --- a/packages/amis-editor/src/plugin/Button.tsx +++ b/packages/amis-editor/src/plugin/Button.tsx @@ -116,28 +116,35 @@ export class ButtonPlugin extends BasePlugin { return [ getSchemaTpl('theme:font', { label: '文字', - name: `css.className.font:${state}`, - visibleOn: visibleOn + name: `themeCss.className.font:${state}`, + visibleOn: visibleOn, + editorThemePath: [ + `button1.type.\${level}.${state}.body.font-color`, + `button1.size.\${size}.body.font` + ] }), getSchemaTpl('theme:colorPicker', { label: '背景', - name: `css.className.background:${state}`, + name: `themeCss.className.background:${state}`, labelMode: 'input', needGradient: true, - visibleOn: visibleOn + visibleOn: visibleOn, + editorThemePath: `button1.type.\${level}.${state}.body.bg-color` }), getSchemaTpl('theme:border', { - name: `css.className.border:${state}`, - visibleOn: visibleOn + name: `themeCss.className.border:${state}`, + visibleOn: visibleOn, + editorThemePath: `button1.type.\${level}.${state}.body.border` }), getSchemaTpl('theme:paddingAndMargin', { - name: `css.className.padding-and-margin:${state}`, - - visibleOn: visibleOn + name: `themeCss.className.padding-and-margin:${state}`, + visibleOn: visibleOn, + editorThemePath: `button1.size.\${size}.body.padding-and-margin` }), getSchemaTpl('theme:radius', { - name: `css.className.radius:${state}`, - visibleOn: visibleOn + name: `themeCss.className.radius:${state}`, + visibleOn: visibleOn, + editorThemePath: `button1.size.\${size}.body.border` }) ]; }; @@ -358,7 +365,14 @@ export class ButtonPlugin extends BasePlugin { ...buttonStateFunc("${editorState == 'active'}", 'active') ] }, - getSchemaTpl('theme:classNames', {isFormItem: false}) + getSchemaTpl('theme:cssCode', { + themeClass: [ + { + value: '', + state: ['default', 'hover', 'active'] + } + ] + }) ]) }, { diff --git a/packages/amis-editor/src/plugin/Container.tsx b/packages/amis-editor/src/plugin/Container.tsx index c74d63fb7..1ccdee05a 100644 --- a/packages/amis-editor/src/plugin/Container.tsx +++ b/packages/amis-editor/src/plugin/Container.tsx @@ -235,16 +235,7 @@ export class ContainerPlugin extends LayoutBasePlugin { title: '外观', className: 'p-none', body: getSchemaTpl('collapseGroup', [ - ...getSchemaTpl('style:common', ['layout']), - getSchemaTpl('style:classNames', { - isFormItem: false, - schema: [ - getSchemaTpl('className', { - name: 'bodyClassName', - label: '内容区' - }) - ] - }) + ...getSchemaTpl('theme:common', ['layout']) ]) } ]); diff --git a/packages/amis-editor/src/plugin/Form/InputNumber.tsx b/packages/amis-editor/src/plugin/Form/InputNumber.tsx index 011d69b86..3b4b7cd14 100644 --- a/packages/amis-editor/src/plugin/Form/InputNumber.tsx +++ b/packages/amis-editor/src/plugin/Form/InputNumber.tsx @@ -17,6 +17,7 @@ import { import {defaultValue, getSchemaTpl, tipedLabel} from 'amis-editor-core'; import {ValidatorTag} from '../../validator'; import {getEventControlConfig} from '../../renderer/event-control/helper'; +import {inputStateTpl} from '../../renderer/style-control/helper'; export class NumberControlPlugin extends BasePlugin { // 关联渲染器名字 @@ -272,7 +273,28 @@ export class NumberControlPlugin extends BasePlugin { } ] }), - getSchemaTpl('style:classNames') + getSchemaTpl('theme:form-label'), + getSchemaTpl('theme:form-description'), + { + title: '数字输入框样式', + body: [ + ...inputStateTpl( + 'themeCss.inputControlClassName', + 'inputNumber.base.base' + ) + ] + }, + getSchemaTpl('theme:cssCode', { + themeClass: [ + { + name: '数字输入框', + value: '', + className: 'inputControlClassName', + state: ['default', 'hover', 'active'] + } + ], + isFormItem: true + }) ], {...context?.schema, configTitle: 'style'} ) diff --git a/packages/amis-editor/src/plugin/Form/InputText.tsx b/packages/amis-editor/src/plugin/Form/InputText.tsx index f4e058ff5..f7edbb44d 100644 --- a/packages/amis-editor/src/plugin/Form/InputText.tsx +++ b/packages/amis-editor/src/plugin/Form/InputText.tsx @@ -9,6 +9,7 @@ import { import {defaultValue, getSchemaTpl, tipedLabel} from 'amis-editor-core'; import {ValidatorTag} from '../../validator'; import {getEventControlConfig} from '../../renderer/event-control/helper'; +import {inputStateTpl} from '../../renderer/style-control/helper'; const isText = 'data.type === "input-text"'; const isPassword = 'data.type === "input-password"'; @@ -154,36 +155,6 @@ export class TextControlPlugin extends BasePlugin { panelBodyCreator = (context: BaseEventContext) => { const renderer: any = context.info.renderer; - const inputStateFunc = (visibleOn: string, state: string) => { - return [ - getSchemaTpl('theme:font', { - label: '文字', - name: `css.inputControlClassName.font:${state}`, - visibleOn: visibleOn - }), - getSchemaTpl('theme:colorPicker', { - label: '背景', - name: `css.inputControlClassName.background:${state}`, - labelMode: 'input', - needGradient: true, - visibleOn: visibleOn - }), - getSchemaTpl('theme:border', { - name: `css.inputControlClassName.border:${state}`, - visibleOn: visibleOn - }), - getSchemaTpl('theme:paddingAndMargin', { - name: `css.inputControlClassName.padding-and-margin:${state}`, - - visibleOn: visibleOn - }), - getSchemaTpl('theme:radius', { - name: `css.inputControlClassName.radius:${state}`, - visibleOn: visibleOn - }) - ]; - }; - return getSchemaTpl('tabs', [ { title: '属性', @@ -389,32 +360,10 @@ export class TextControlPlugin extends BasePlugin { { title: '输入框样式', body: [ - { - type: 'select', - name: 'editorState', - label: '状态', - selectFirst: true, - options: [ - { - label: '常规', - value: 'default' - }, - { - label: '悬浮', - value: 'hover' - }, - { - label: '点击', - value: 'active' - } - ] - }, - ...inputStateFunc( - "${editorState == 'default' || !editorState}", - 'default' - ), - ...inputStateFunc("${editorState == 'hover'}", 'hover'), - ...inputStateFunc("${editorState == 'active'}", 'active') + ...inputStateTpl( + 'themeCss.inputControlClassName', + 'input.base.default' + ) ] }, { @@ -423,28 +372,28 @@ export class TextControlPlugin extends BasePlugin { body: [ getSchemaTpl('theme:font', { label: '文字', - name: 'css.addOnClassName.font' + name: 'themeCss.addOnClassName.font:default' }), getSchemaTpl('theme:paddingAndMargin', { - name: 'css.addOnClassName.padding-and-margin' + name: 'themeCss.addOnClassName.padding-and-margin:default' }) ] }, - getSchemaTpl('theme:classNames', { - schema: [ + getSchemaTpl('theme:cssCode', { + themeClass: [ { - type: 'theme-classname', - label: '输入框', - name: 'inputControlClassName' + name: '输入框', + value: '', + className: 'inputControlClassName', + state: ['default', 'hover', 'active'] }, { - type: 'theme-classname', - name: 'addOnClassName', - suffix: 'addOn', - label: 'AddOn', - visibleOn: 'this.addOn && this.addOn.type === "text"' + name: 'addOn', + value: 'addOn', + className: 'addOnClassName' } - ] + ], + isFormItem: true }) ], {...context?.schema, configTitle: 'style'} diff --git a/packages/amis-editor/src/plugin/IFrame.tsx b/packages/amis-editor/src/plugin/IFrame.tsx index bf1792596..2dce3552b 100644 --- a/packages/amis-editor/src/plugin/IFrame.tsx +++ b/packages/amis-editor/src/plugin/IFrame.tsx @@ -76,10 +76,7 @@ export class IFramePlugin extends BasePlugin { }) ] }, - getSchemaTpl('style:classNames', { - isFormItem: false - }), - ...getSchemaTpl('style:common', [], 'border') + ...getSchemaTpl('theme:common', ['layout']) ]) ] } diff --git a/packages/amis-editor/src/plugin/Layout/FlexPluginBase.tsx b/packages/amis-editor/src/plugin/Layout/FlexPluginBase.tsx index efc5373fe..cf5f5b5f8 100644 --- a/packages/amis-editor/src/plugin/Layout/FlexPluginBase.tsx +++ b/packages/amis-editor/src/plugin/Layout/FlexPluginBase.tsx @@ -210,13 +210,7 @@ export class FlexPluginBase extends LayoutBasePlugin { { title: '外观', className: 'p-none', - body: getSchemaTpl('collapseGroup', [ - ...getSchemaTpl('style:common', []), - { - title: 'CSS 类名', - body: [getSchemaTpl('className', {label: '外层CSS类名'})] - } - ]) + body: getSchemaTpl('collapseGroup', [...getSchemaTpl('theme:common')]) } ]) ]; diff --git a/packages/amis-editor/src/plugin/Page.tsx b/packages/amis-editor/src/plugin/Page.tsx index bd908ca5f..32730cbb7 100644 --- a/packages/amis-editor/src/plugin/Page.tsx +++ b/packages/amis-editor/src/plugin/Page.tsx @@ -275,30 +275,7 @@ export class PagePlugin extends BasePlugin { className: 'p-none', body: [ getSchemaTpl('collapseGroup', [ - ...getSchemaTpl('theme:common', ['layout']), - getSchemaTpl('style:classNames', { - isFormItem: false, - schema: [ - getSchemaTpl('className', { - name: 'headerClassName', - label: '顶部' - }), - getSchemaTpl('className', { - name: 'bodyClassName', - label: '内容区' - }), - - getSchemaTpl('className', { - name: 'asideClassName', - label: '边栏' - }), - - getSchemaTpl('className', { - name: 'toolbarClassName', - label: '工具栏' - }) - ] - }) + ...getSchemaTpl('theme:common', ['layout']) ]) ] }, diff --git a/packages/amis-editor/src/plugin/Steps.tsx b/packages/amis-editor/src/plugin/Steps.tsx index 61258eba8..a05533667 100644 --- a/packages/amis-editor/src/plugin/Steps.tsx +++ b/packages/amis-editor/src/plugin/Steps.tsx @@ -105,7 +105,29 @@ export class StepsPlugin extends BasePlugin { }, { title: '外观', - body: [getSchemaTpl('className')] + body: [ + { + name: 'mode', + type: 'select', + label: '模式', + value: 'horizontal', + options: [ + { + label: '水平', + value: 'horizontal' + }, + { + label: '竖直', + value: 'vertical' + }, + { + label: '简单', + value: 'simple' + } + ] + }, + getSchemaTpl('className') + ] }, { title: '显隐', diff --git a/packages/amis-editor/src/plugin/TableView.tsx b/packages/amis-editor/src/plugin/TableView.tsx index ede47b9e9..d8cd88581 100644 --- a/packages/amis-editor/src/plugin/TableView.tsx +++ b/packages/amis-editor/src/plugin/TableView.tsx @@ -245,13 +245,7 @@ export class TableViewPlugin extends BasePlugin { { title: '外观', className: 'p-none', - body: getSchemaTpl('collapseGroup', [ - ...getSchemaTpl('style:common'), - { - title: 'CSS 类名', - body: [getSchemaTpl('className')] - } - ]) + body: getSchemaTpl('collapseGroup', [...getSchemaTpl('theme:common')]) }, { title: '状态', @@ -446,7 +440,7 @@ export class TableViewPlugin extends BasePlugin { { title: '外观', className: 'p-none', - body: getSchemaTpl('collapseGroup', getSchemaTpl('style:common')) + body: getSchemaTpl('collapseGroup', getSchemaTpl('theme:common')) } ]) ]; @@ -476,7 +470,7 @@ export class TableViewPlugin extends BasePlugin { { title: '外观', className: 'p-none', - body: getSchemaTpl('collapseGroup', getSchemaTpl('style:common')) + body: getSchemaTpl('collapseGroup', getSchemaTpl('theme:common')) } ]) ]; diff --git a/packages/amis-editor/src/plugin/Tpl.tsx b/packages/amis-editor/src/plugin/Tpl.tsx index 0473dc7a7..d1a034751 100644 --- a/packages/amis-editor/src/plugin/Tpl.tsx +++ b/packages/amis-editor/src/plugin/Tpl.tsx @@ -219,10 +219,7 @@ export class TplPlugin extends BasePlugin { { title: '外观', body: getSchemaTpl('collapseGroup', [ - ...getSchemaTpl('style:common', ['layout']), - getSchemaTpl('style:classNames', { - isFormItem: false - }) + ...getSchemaTpl('theme:common', ['layout'], ['font']) ]) }, { diff --git a/packages/amis-editor/src/renderer/FormulaControl.tsx b/packages/amis-editor/src/renderer/FormulaControl.tsx index a1e50a413..4d99c4a67 100644 --- a/packages/amis-editor/src/renderer/FormulaControl.tsx +++ b/packages/amis-editor/src/renderer/FormulaControl.tsx @@ -409,7 +409,7 @@ export default class FormulaControl extends React.Component< 'kilobitSeparator', 'value', 'inputControlClassName', - 'css' + 'themeCss' ]; // 当前组件要剔除的字段 diff --git a/packages/amis-editor/src/renderer/style-control/ThemeClassName.tsx b/packages/amis-editor/src/renderer/style-control/ThemeClassName.tsx deleted file mode 100644 index 74c0eb9c4..000000000 --- a/packages/amis-editor/src/renderer/style-control/ThemeClassName.tsx +++ /dev/null @@ -1,237 +0,0 @@ -/** - * 类名输入框 + 自定义样式源码编辑器 - */ -import React, {useEffect, useRef, useState} from 'react'; -import {Button, Editor, Icon, Overlay, PopOver} from 'amis-ui'; -import {FormControlProps, FormItem, render} from 'amis-core'; -import {parse as cssParse} from 'amis-postcss'; -import {PlainObject} from './types'; -import {debounce} from 'lodash'; - -const valueMap: PlainObject = { - 'margin-top': 'marginTop', - 'margin-right': 'marginRight', - 'margin-bottom': 'marginBottom', - 'margin-left': 'marginLeft', - 'padding-top': 'paddingTop', - 'padding-right': 'paddingRight', - 'padding-bottom': 'paddingBottom', - 'padding-left': 'paddingLeft', - 'border-top-width': 'top-border-width', - 'border-right-width': 'right-border-width', - 'border-bottom-width': 'bottom-border-width', - 'border-left-width': 'left-border-width', - 'border-top-style': 'top-border-style', - 'border-right-style': 'right-border-style', - 'border-bottom-style': 'bottom-border-style', - 'border-left-style': 'left-border-style', - 'border-top-color': 'top-border-color', - 'border-right-color': 'right-border-color', - 'border-bottom-color': 'bottom-border-color', - 'border-left-color': 'left-border-color', - 'font-size': 'fontSize', - 'font-weight': 'fontWeight', - 'line-height': 'lineHeight' -}; - -const fontStyle = [ - 'color', - 'font-weight', - 'font-size', - 'font-style', - 'text-decoration', - 'text-align', - 'vertical-align', - 'font-family', - 'line-height' -]; - -function AmisStyleCodeEditor(props: FormControlProps) { - const {name, value: classname, suffix} = props; - const [value, setValue] = useState(''); - function getCssAndSetValue( - classname?: string, - name?: string, - suffix?: string - ) { - try { - const id = - classname?.replace(name + '-', '') + (suffix ? '-' + suffix : ''); - const dom = document.getElementById(id || '') || null; - const content = dom?.innerHTML || ''; - const ast = cssParse(content); - const nodes: any[] = []; - ast.nodes.forEach((node: any) => { - const selector = node.selector; - if (!selector.endsWith('.hover') && !selector.endsWith('.active')) { - nodes.push(node); - } - }); - ast.nodes = nodes; - - const css = nodes - .map(node => { - const style = node.nodes.map((n: any) => `${n.prop}: ${n.value};`); - return `${node.selector} {\n ${style.join('\n ')}\n}`; - }) - .join('\n\n'); - - setValue(css); - } catch (error) { - console.error(error); - } - } - - useEffect(() => { - getCssAndSetValue(classname, name, suffix); - }, []); - - function handleChange(value: string) { - setValue(value); - editorChange(value); - } - - const editorChange = debounce((value: string) => { - try { - const ast = cssParse(value); - const {data, onBulkChange, name} = props; - const sourceCss = data.css || {}; - const className: PlainObject = {}; - ast.nodes.forEach((node: any) => { - const nodes = node.nodes; - const selector = node.selector; - let state = 'default'; - if (!!~selector.indexOf(':hover:active')) { - state = 'active'; - } else if (!!~selector.indexOf(':hover')) { - state = 'hover'; - } - nodes.forEach((item: any) => { - const prop = item.prop; - const cssValue = item.value; - if (!!~prop.indexOf('radius')) { - const type = 'radius:' + state; - !className[type] && (className[type] = {}); - const radius = cssValue.split(' '); - - className[type]['top-left-border-radius'] = radius[0]; - className[type]['top-right-border-radius'] = radius[1]; - className[type]['bottom-right-border-radius'] = radius[2]; - className[type]['bottom-left-border-radius'] = radius[3]; - } else if (!!~prop.indexOf('border')) { - !className['border:' + state] && - (className['border:' + state] = {}); - className['border:' + state][valueMap[prop] || prop] = cssValue; - } else if (!!~prop.indexOf('padding') || !!~prop.indexOf('margin')) { - !className['padding-and-margin:' + state] && - (className['padding-and-margin:' + state] = {}); - className['padding-and-margin:' + state][valueMap[prop] || prop] = - cssValue; - } else if (fontStyle.includes(prop)) { - !className['font:' + state] && (className['font:' + state] = {}); - className['font:' + state][valueMap[prop] || prop] = cssValue; - } else { - className[(valueMap[prop] || prop) + ':' + state] = cssValue; - } - }); - }); - const newCss = { - ...sourceCss, - [name!]: className - }; - onBulkChange && - onBulkChange({ - css: newCss - }); - } catch (error) { - console.error(error); - } - }); - - return ( -
-
自定义样式源码
-
- -
- -
- -
-
- ); -} - -function ThemeClassName(props: FormControlProps) { - const ref = useRef(null); - const {value} = props; - const [showEditor, setShowEditor] = useState(false); - function handleShowEditor() { - setShowEditor(true); - } - return ( - <> -
- - {render({ - type: 'input-tag', - name: 'class', - placeholder: '请输入类名', - delimiter: ' ', - value: value, - onChange: (value: string) => { - props.onChange && props.onChange(value); - } - })} -
- - setShowEditor(false)}> - setShowEditor(false)} /> - - - - ); -} - -@FormItem({ - type: 'theme-classname', - strictMode: false -}) -export class BorderRenderer extends React.Component { - render() { - return ; - } -} diff --git a/packages/amis-editor/src/renderer/style-control/ThemeCssCode.tsx b/packages/amis-editor/src/renderer/style-control/ThemeCssCode.tsx new file mode 100644 index 000000000..119851e08 --- /dev/null +++ b/packages/amis-editor/src/renderer/style-control/ThemeCssCode.tsx @@ -0,0 +1,396 @@ +/** + * 类名输入框 + 自定义样式源码编辑器 + */ +import React, {useEffect, useRef, useState} from 'react'; +import {Button, Editor, Overlay, PopOver} from 'amis-ui'; +import {FormControlProps, FormItem, styleMap} from 'amis-core'; +import {parse as cssParse} from 'amis-postcss'; +import {PlainObject} from './types'; +import {debounce, isEmpty} from 'lodash'; +import {Icon} from '../../icons/index'; +import editorFactory from './themeLanguage'; +import cx from 'classnames'; + +const valueMap: PlainObject = {}; + +for (let key in styleMap) { + valueMap[styleMap[key]] = key; +} +const fontStyle = [ + 'color', + 'font-weight', + 'font-size', + 'font-style', + 'text-decoration', + 'text-align', + 'vertical-align', + 'font-family', + 'line-height' +]; + +interface CssNode { + value: string; + selector: string; +} + +interface CssNodeTab { + name: string; + children: CssNode[]; +} + +function AmisThemeCssCodeEditor(props: FormControlProps) { + const {themeClass, data} = props; + const id = data.id.replace('u:', ''); + const [cssNodes, setCssNodes] = useState([]); + const [tabId, setTabId] = useState(0); + function getCssAndSetValue(themeClass: any[]) { + try { + const newCssNodes: CssNodeTab[] = []; + themeClass?.forEach(n => { + const classId = n.value ? id + '-' + n.value : id; + const state = n.state || ['default']; + const className = n.className || 'className'; + const dom = document.getElementById(classId || '') || null; + const content = dom?.innerHTML || ''; + const ast = cssParse(content); + const nodes: any[] = []; + ast.nodes.forEach((node: any) => { + const selector = node.selector; + if (!selector.endsWith('.hover') && !selector.endsWith('.active')) { + nodes.push(node); + } + }); + + const css: {selector: string; value: string; state: string}[] = []; + state.forEach((s: string) => { + css.push({ + selector: `.${className}-${id}${s === 'default' ? '' : ':' + s}`, + state: s, + value: '' + }); + }); + nodes.forEach(node => { + const style = node.nodes.map((n: any) => `${n.prop}: ${n.value};`); + const item = css.find(c => { + if ( + c.selector === node.selector || + node.selector.endsWith(`:${c.state}`) + ) { + return c; + } + return false; + })!; + item.value = style.join('\n'); + }); + + newCssNodes.push({ + name: n.name || '自定义样式', + children: css + }); + }); + setCssNodes(newCssNodes); + } catch (error) { + console.error(error); + } + } + + useEffect(() => { + getCssAndSetValue(themeClass); + }, []); + + const editorChange = debounce((nodeTabs: CssNodeTab[]) => { + try { + const {data, onBulkChange} = props; + const sourceCss = data.themeCss || data.css || {}; + const newCss: any = {}; + nodeTabs.forEach(tab => { + tab.children.forEach(node => { + const nodes = cssParse(node.value) + .nodes.map(node => { + const {prop, value} = node; + return { + prop, + value + }; + }) + .filter(n => n.value); + const selector = node.selector; + const nameEtr = /\.(.*)\-/.exec(selector); + const cssCode: PlainObject = {}; + let name = nameEtr ? nameEtr[1] : ''; + let state = 'default'; + if (!!~selector.indexOf(':active')) { + state = 'active'; + } else if (!!~selector.indexOf(':hover')) { + state = 'hover'; + } + nodes.forEach(item => { + const prop = item.prop; + const cssValue = item.value; + if (!!~prop.indexOf('radius')) { + const type = 'radius:' + state; + !cssCode[type] && (cssCode[type] = {}); + const radius = cssValue.split(' '); + + cssCode[type]['top-left-border-radius'] = radius[0]; + cssCode[type]['top-right-border-radius'] = radius[1]; + cssCode[type]['bottom-right-border-radius'] = radius[2]; + cssCode[type]['bottom-left-border-radius'] = radius[3]; + } else if (!!~prop.indexOf('border')) { + !cssCode['border:' + state] && (cssCode['border:' + state] = {}); + cssCode['border:' + state][valueMap[prop] || prop] = cssValue; + } else if ( + !!~prop.indexOf('padding') || + !!~prop.indexOf('margin') + ) { + !cssCode['padding-and-margin:' + state] && + (cssCode['padding-and-margin:' + state] = {}); + cssCode['padding-and-margin:' + state][valueMap[prop] || prop] = + cssValue; + } else if (fontStyle.includes(prop)) { + !cssCode['font:' + state] && (cssCode['font:' + state] = {}); + cssCode['font:' + state][valueMap[prop] || prop] = cssValue; + } else { + cssCode[(valueMap[prop] || prop) + ':' + state] = cssValue; + } + }); + if (newCss[name]) { + newCss[name] = Object.assign(newCss[name], cssCode); + } else { + newCss[name] = cssCode; + } + }); + }); + onBulkChange && + onBulkChange({ + themeCss: { + ...sourceCss, + ...newCss + } + }); + } catch (error) { + console.error(error); + } + }); + + function handleChange(value: string, i: number, j: number) { + const newCssNodes = cssNodes; + newCssNodes[i].children[j].value = value; + setCssNodes(newCssNodes); // 好像不需要这个? + editorChange(newCssNodes); + } + function formateTitle(title: string) { + if (title.endsWith('hover')) { + return '悬浮态样式'; + } else if (title.endsWith('active')) { + return '点击态样式'; + } else if (title.endsWith('disabled')) { + return '禁用态样式'; + } + return '常规态样式'; + } + + return ( +
+
编辑样式源码
+
+ +
+
+
+ {cssNodes.map((node, index) => { + return ( +
setTabId(index)} + className={cx( + 'ThemeCssCode-editor-content-header-title', + index === tabId && + 'ThemeCssCode-editor-content-header-title--active' + )} + > + {node.name} +
+ ); + })} +
+
+ {cssNodes.map((node, i) => { + const children = node.children; + return ( +
+ {children.map((css, j) => { + return ( +
+ {children.length > 1 ? ( +
+ {formateTitle(css.selector)} +
+ ) : null} +
+ + handleChange(value, i, j) + }} + /> +
+
+ ); + })} +
+ ); + })} +
+
+
+ ); +} + +function AmisStyleCodeEditor(props: FormControlProps) { + const {data, onBulkChange} = props; + const {style} = data; + const [value, setValue] = useState(''); + + function getCssAndSetValue(data: any) { + if (isEmpty(data)) { + return ''; + } + let str = ''; + for (let key in data) { + if (key === 'radius') { + str += `border-radius: ${ + data.radius['top-left-border-radius'] + + ' ' + + data.radius['top-right-border-radius'] + + ' ' + + data.radius['bottom-right-border-radius'] + + ' ' + + data.radius['bottom-left-border-radius'] + };\n`; + } else { + str += `${styleMap[key] || key}: ${data[key]};\n`; + } + } + return str; + } + + useEffect(() => { + const res = getCssAndSetValue(style); + setValue(res); + }, []); + + const editorChange = debounce((value: string) => { + const newStyle: PlainObject = {}; + try { + const style = cssParse(value); + style.nodes.forEach(node => { + const {prop, value} = node; + if (value) { + if (prop === 'border-radius') { + const radius = value.split(' '); + newStyle['radius'] = { + 'top-left-border-radius': radius[0] || '', + 'top-right-border-radius': radius[1] || '', + 'bottom-right-border-radius': radius[2] || '', + 'bottom-left-border-radius': radius[3] || '' + }; + } else { + newStyle[valueMap[prop] || prop] = value; + } + } + }); + onBulkChange && + onBulkChange({ + style: newStyle + }); + } catch (error) { + console.error(error); + } + }); + + function handleChange(value: string) { + editorChange(value); + setValue(value); + } + return ( +
+
编辑样式源码
+
+ +
+
+ +
+
+ ); +} + +function ThemeCssCode(props: FormControlProps) { + const ref = useRef(null); + const [showEditor, setShowEditor] = useState(false); + function handleShowEditor() { + setShowEditor(true); + } + return ( + <> +
+ +
+ + setShowEditor(false)}> + {props.isLayout ? ( + setShowEditor(false)} + /> + ) : ( + setShowEditor(false)} + /> + )} + + + + ); +} + +@FormItem({ + type: 'theme-cssCode', + strictMode: false +}) +export class ThemeCssCodeRenderer extends React.Component { + render() { + return ; + } +} diff --git a/packages/amis-editor/src/renderer/style-control/helper.tsx b/packages/amis-editor/src/renderer/style-control/helper.tsx new file mode 100644 index 000000000..1b5711d7e --- /dev/null +++ b/packages/amis-editor/src/renderer/style-control/helper.tsx @@ -0,0 +1,85 @@ +import {getSchemaTpl} from 'amis-editor-core'; + +export const inputStateTpl = (className: string, path: string = '') => { + return [ + { + type: 'select', + name: 'editorState', + label: '状态', + selectFirst: true, + options: [ + { + label: '常规', + value: 'default' + }, + { + label: '悬浮', + value: 'hover' + }, + { + label: '点击', + value: 'active' + } + ] + }, + { + type: 'hidden', + name: 'editorPath', + value: path + }, + ...inputStateFunc( + "${editorState == 'default' || !editorState}", + 'default', + className, + path + ), + ...inputStateFunc("${editorState == 'hover'}", 'hover', className, path), + ...inputStateFunc("${editorState == 'active'}", 'active', className, path) + ]; +}; + +export const inputStateFunc = ( + visibleOn: string, + state: string, + className: string, + path: string, + options: any = [] +) => { + return [ + getSchemaTpl('theme:font', { + label: '文字', + name: `${className}.font:${state}`, + visibleOn: visibleOn, + editorThemePath: `${path}.${state}.body.font`, + state + }), + getSchemaTpl('theme:colorPicker', { + label: '背景', + name: `${className}.background:${state}`, + labelMode: 'input', + needGradient: true, + visibleOn: visibleOn, + editorThemePath: `${path}.${state}.body.bg-color`, + state + }), + getSchemaTpl('theme:border', { + name: `${className}.border:${state}`, + visibleOn: visibleOn, + editorThemePath: `${path}.${state}.body.border`, + state + }), + getSchemaTpl('theme:paddingAndMargin', { + name: `${className}.padding-and-margin:${state}`, + visibleOn: visibleOn, + editorThemePath: `${path}.${state}.body.padding-and-margin`, + state + }), + getSchemaTpl('theme:radius', { + name: `${className}.radius:${state}`, + visibleOn: visibleOn, + editorThemePath: `${path}.${state}.body.border`, + state + }), + ...options + ]; +}; diff --git a/packages/amis-editor/src/renderer/style-control/themeLanguage.ts b/packages/amis-editor/src/renderer/style-control/themeLanguage.ts new file mode 100644 index 000000000..1372c50ee --- /dev/null +++ b/packages/amis-editor/src/renderer/style-control/themeLanguage.ts @@ -0,0 +1,3150 @@ +import {PlainObject} from 'amis-core'; +import {isEmpty} from 'lodash'; + +const conf: any = { + ws: '[ \t\n\r\f]*', + identifier: + '-?-?([a-zA-Z]|(\\\\(([0-9a-fA-F]{1,6}\\s?)|[^[0-9a-fA-F])))([\\w\\-]|(\\\\(([0-9a-fA-F]{1,6}\\s?)|[^[0-9a-fA-F])))*', + + tokenizer: { + root: [{include: '@selector'}], + + selector: [{include: '@selectorbody'}], + + selectorbody: [ + [ + '[*_]?@identifier@ws:(?=(\\s|\\d|[^{;}]*[;}]))', + 'attribute.name', + '@rulevalue' + ] + ], + rulevalue: [ + {include: '@strings'}, + {include: '@term'}, + ['!important', 'keyword'], + [';', 'delimiter', '@pop'], + ['(?=})', {token: '', next: '@pop'}] + ], + term: [ + [ + '(url-prefix)(\\()', + [ + 'attribute.value', + {token: 'delimiter.parenthesis', next: '@urldeclaration'} + ] + ], + [ + '(url)(\\()', + [ + 'attribute.value', + {token: 'delimiter.parenthesis', next: '@urldeclaration'} + ] + ], + {include: '@numbers'}, + {include: '@name'}, + {include: '@strings'}, + ['([<>=\\+\\-\\*\\/\\^\\|\\~,])', 'delimiter'], + [',', 'delimiter'] + ], + + warndebug: [ + ['[@](warn|debug)', {token: 'keyword', next: '@declarationbody'}] + ], + + urldeclaration: [ + {include: '@strings'}, + ['[^)\r\n]+', 'string'], + ['\\)', {token: 'delimiter.parenthesis', next: '@pop'}] + ], + + parenthizedterm: [ + {include: '@term'}, + ['\\)', {token: 'delimiter.parenthesis', next: '@pop'}] + ], + + declarationbody: [ + {include: '@term'}, + [';', 'delimiter', '@pop'], + ['(?=})', {token: '', next: '@pop'}] // missing semicolon + ], + + name: [['@identifier', 'attribute.value']], + + numbers: [ + [ + '-?(\\d*\\.)?\\d+([eE][\\-+]?\\d+)?', + {token: 'attribute.value.number', next: '@units'} + ], + ['#[0-9a-fA-F_]+(?!\\w)', 'attribute.value.hex'] + ], + + units: [ + [ + '(em|ex|ch|rem|fr|vmin|vmax|vw|vh|vm|cm|mm|in|px|pt|pc|deg|grad|rad|turn|s|ms|Hz|kHz|%)?', + 'attribute.value.unit', + '@pop' + ] + ], + + strings: [ + ['~?"', {token: 'string', next: '@stringenddoublequote'}], + ["~?'", {token: 'string', next: '@stringendquote'}] + ], + + stringenddoublequote: [ + ['\\\\.', 'string'], + ['"', {token: 'string', next: '@pop'}], + [/[^\\"]+/, 'string'], + ['.', 'string'] + ], + + stringendquote: [ + ['\\\\.', 'string'], + ["'", {token: 'string', next: '@pop'}], + [/[^\\']+/, 'string'], + ['.', 'string'] + ] + } +}; + +const keywords: PlainObject = { + 'additive-symbols': {}, + 'align-content': { + values: [ + 'center', + 'flex-end', + 'flex-start', + 'space-around', + 'space-between', + 'stretch', + 'start', + 'end', + 'normal', + 'baseline', + 'first baseline', + 'last baseline', + 'space-around', + 'space-between', + 'space-evenly', + 'stretch', + 'safe', + 'unsafe' + ] + }, + 'align-items': { + values: [ + 'baseline', + 'center', + 'flex-end', + 'flex-start', + 'stretch', + 'normal', + 'start', + 'end', + 'self-start', + 'self-end', + 'first baseline', + 'last baseline', + 'stretch', + 'safe', + 'unsafe' + ] + }, + 'justify-items': { + values: [ + 'auto', + 'normal', + 'end', + 'start', + 'flex-end', + 'flex-start', + 'self-end', + 'self-start', + 'center', + 'left', + 'right', + 'baseline', + 'first baseline', + 'last baseline', + 'stretch', + 'safe', + 'unsafe', + 'legacy' + ] + }, + 'justify-self': { + values: [ + 'auto', + 'normal', + 'end', + 'start', + 'flex-end', + 'flex-start', + 'self-end', + 'self-start', + 'center', + 'left', + 'right', + 'baseline', + 'first baseline', + 'last baseline', + 'stretch', + 'save', + 'unsave' + ] + }, + 'align-self': { + values: [ + 'auto', + 'normal', + 'self-end', + 'self-start', + 'baseline', + 'center', + 'flex-end', + 'flex-start', + 'stretch', + 'baseline', + 'first baseline', + 'last baseline', + 'safe', + 'unsafe' + ] + }, + 'all': { + values: [] + }, + 'alt': { + values: [] + }, + 'animation': { + values: [ + 'alternate', + 'alternate-reverse', + 'backwards', + 'both', + 'forwards', + 'infinite', + 'none', + 'normal', + 'reverse' + ] + }, + 'animation-delay': {}, + 'animation-direction': { + values: ['alternate', 'alternate-reverse', 'normal', 'reverse'] + }, + 'animation-duration': {}, + 'animation-fill-mode': { + values: ['backwards', 'both', 'forwards', 'none'] + }, + 'animation-iteration-count': { + values: ['infinite'] + }, + 'animation-name': { + values: ['none'] + }, + 'animation-play-state': { + values: ['paused', 'running'] + }, + 'animation-timing-function': {}, + 'backface-visibility': { + values: ['hidden', 'visible'] + }, + 'background': { + values: ['fixed', 'local', 'none', 'scroll'] + }, + 'background-attachment': { + values: ['fixed', 'local', 'scroll'] + }, + 'background-blend-mode': { + values: [ + 'normal', + 'multiply', + 'screen', + 'overlay', + 'darken', + 'lighten', + 'color-dodge', + 'color-burn', + 'hard-light', + 'soft-light', + 'difference', + 'exclusion', + 'hue', + 'saturation', + 'color', + 'luminosity' + ] + }, + 'background-clip': {}, + 'background-color': {}, + 'background-image': { + values: ['none'] + }, + 'background-origin': {}, + 'background-position': {}, + 'background-position-x': { + values: ['center', 'left', 'right'] + }, + 'background-position-y': { + values: ['bottom', 'center', 'top'] + }, + 'background-repeat': { + values: [] + }, + 'background-size': { + values: ['auto', 'contain', 'cover'] + }, + 'behavior': {}, + 'block-size': { + values: ['auto'] + }, + 'border': {}, + 'border-block-end': {}, + 'border-block-start': {}, + 'border-block-end-color': {}, + 'border-block-start-color': {}, + 'border-block-end-style': {}, + 'border-block-start-style': {}, + 'border-block-end-width': {}, + 'border-block-start-width': {}, + 'border-bottom': {}, + 'border-bottom-color': {}, + 'border-bottom-left-radius': {}, + 'border-bottom-right-radius': {}, + 'border-bottom-style': {}, + 'border-bottom-width': {}, + 'border-collapse': { + values: ['collapse', 'separate'] + }, + 'border-color': { + values: [] + }, + 'border-image': { + values: [ + 'auto', + 'fill', + 'none', + 'repeat', + 'round', + 'space', + 'stretch', + 'url()' + ] + }, + 'border-image-outset': {}, + 'border-image-repeat': { + values: ['repeat', 'round', 'space', 'stretch'] + }, + 'border-image-slice': { + values: ['fill'] + }, + 'border-image-source': { + values: ['none'] + }, + 'border-image-width': { + values: ['auto'] + }, + 'border-inline-end': {}, + 'border-inline-start': {}, + 'border-inline-end-color': {}, + 'border-inline-start-color': {}, + 'border-inline-end-style': {}, + 'border-inline-start-style': {}, + 'border-inline-end-width': {}, + 'border-inline-start-width': {}, + 'border-left': {}, + 'border-left-color': {}, + 'border-left-style': {}, + 'border-left-width': {}, + 'border-radius': {}, + 'border-right': {}, + 'border-right-color': {}, + 'border-right-style': {}, + 'border-right-width': {}, + 'border-spacing': {}, + 'border-style': { + values: [] + }, + 'border-top': {}, + 'border-top-color': {}, + 'border-top-left-radius': {}, + 'border-top-right-radius': {}, + 'border-top-style': {}, + 'border-top-width': {}, + 'border-width': { + values: [] + }, + 'bottom': { + values: ['auto'] + }, + 'box-decoration-break': { + values: ['clone', 'slice'] + }, + 'box-shadow': { + values: ['inset', 'none'] + }, + 'box-sizing': { + values: ['border-box', 'content-box'] + }, + 'break-after': { + values: [ + 'always', + 'auto', + 'avoid', + 'avoid-column', + 'avoid-page', + 'column', + 'left', + 'page', + 'right' + ] + }, + 'break-before': { + values: [ + 'always', + 'auto', + 'avoid', + 'avoid-column', + 'avoid-page', + 'column', + 'left', + 'page', + 'right' + ] + }, + 'break-inside': { + values: ['auto', 'avoid', 'avoid-column', 'avoid-page'] + }, + 'caption-side': { + values: ['bottom', 'top'] + }, + 'caret-color': { + values: ['auto'] + }, + 'clear': { + values: ['both', 'left', 'none', 'right'] + }, + 'clip': { + values: ['auto', 'rect()'] + }, + 'clip-path': { + values: ['none', 'url()'] + }, + 'clip-rule': { + values: ['evenodd', 'nonzero'] + }, + 'color': {}, + 'color-interpolation-filters': { + values: ['auto', 'linearRGB', 'sRGB'] + }, + 'column-count': { + values: ['auto'] + }, + 'column-fill': { + values: ['auto', 'balance'] + }, + 'column-gap': { + values: ['normal'] + }, + 'column-rule': {}, + 'column-rule-color': {}, + 'column-rule-style': {}, + 'column-rule-width': {}, + 'columns': { + values: ['auto'] + }, + 'column-span': { + values: ['all', 'none'] + }, + 'column-width': { + values: ['auto'] + }, + 'contain': { + values: ['none', 'strict', 'content', 'size', 'layout', 'style', 'paint'] + }, + 'content': { + values: ['attr()', 'counter(name)', 'icon', 'none', 'normal', 'url()'] + }, + 'counter-increment': { + values: ['none'] + }, + 'counter-reset': { + values: ['none'] + }, + 'cursor': { + values: [ + 'alias', + 'all-scroll', + 'auto', + 'cell', + 'col-resize', + 'context-menu', + 'copy', + 'crosshair', + 'default', + 'e-resize', + 'ew-resize', + 'grab', + 'grabbing', + 'help', + 'move', + '-moz-grab', + '-moz-grabbing', + '-moz-zoom-in', + '-moz-zoom-out', + 'ne-resize', + 'nesw-resize', + 'no-drop', + 'none', + 'not-allowed', + 'n-resize', + 'ns-resize', + 'nw-resize', + 'nwse-resize', + 'pointer', + 'progress', + 'row-resize', + 'se-resize', + 's-resize', + 'sw-resize', + 'text', + 'vertical-text', + 'wait', + '-webkit-grab', + '-webkit-grabbing', + '-webkit-zoom-in', + '-webkit-zoom-out', + 'w-resize', + 'zoom-in', + 'zoom-out' + ] + }, + 'direction': { + values: ['ltr', 'rtl'] + }, + 'display': { + values: [ + 'block', + 'contents', + 'flex', + 'flexbox', + 'flow-root', + 'grid', + 'inline', + 'inline-block', + 'inline-flex', + 'inline-flexbox', + 'inline-table', + 'list-item', + '-moz-box', + '-moz-deck', + '-moz-grid', + '-moz-grid-group', + '-moz-grid-line', + '-moz-groupbox', + '-moz-inline-box', + '-moz-inline-grid', + '-moz-inline-stack', + '-moz-marker', + '-moz-popup', + '-moz-stack', + '-ms-flexbox', + '-ms-grid', + '-ms-inline-flexbox', + '-ms-inline-grid', + 'none', + 'ruby', + 'ruby-base', + 'ruby-base-container', + 'ruby-text', + 'ruby-text-container', + 'run-in', + 'table', + 'table-caption', + 'table-cell', + 'table-column', + 'table-column-group', + 'table-footer-group', + 'table-header-group', + 'table-row', + 'table-row-group', + '-webkit-box', + '-webkit-flex', + '-webkit-inline-box', + '-webkit-inline-flex' + ] + }, + 'empty-cells': { + values: ['hide', '-moz-show-background', 'show'] + }, + 'enable-background': { + values: ['accumulate', 'new'] + }, + 'fallback': {}, + 'fill': { + values: ['url()', 'none'] + }, + 'fill-opacity': {}, + 'fill-rule': { + values: ['evenodd', 'nonzero'] + }, + 'filter': { + values: [ + 'none', + 'blur()', + 'brightness()', + 'contrast()', + 'drop-shadow()', + 'grayscale()', + 'hue-rotate()', + 'invert()', + 'opacity()', + 'saturate()', + 'sepia()', + 'url()' + ] + }, + 'flex': { + values: ['auto', 'content', 'none'] + }, + 'flex-basis': { + values: ['auto', 'content'] + }, + 'flex-direction': { + values: ['column', 'column-reverse', 'row', 'row-reverse'] + }, + 'flex-flow': { + values: [ + 'column', + 'column-reverse', + 'nowrap', + 'row', + 'row-reverse', + 'wrap', + 'wrap-reverse' + ] + }, + 'flex-grow': {}, + 'flex-shrink': {}, + 'flex-wrap': { + values: ['nowrap', 'wrap', 'wrap-reverse'] + }, + 'float': { + values: ['inline-end', 'inline-start', 'left', 'none', 'right'] + }, + 'flood-color': {}, + 'flood-opacity': {}, + 'font': { + values: [ + '100', + '200', + '300', + '400', + '500', + '600', + '700', + '800', + '900', + 'bold', + 'bolder', + 'caption', + 'icon', + 'italic', + 'large', + 'larger', + 'lighter', + 'medium', + 'menu', + 'message-box', + 'normal', + 'oblique', + 'small', + 'small-caps', + 'small-caption', + 'smaller', + 'status-bar', + 'x-large', + 'x-small', + 'xx-large', + 'xx-small' + ] + }, + 'font-family': { + values: [ + "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif", + 'Arial, Helvetica, sans-serif', + "Cambria, Cochin, Georgia, Times, 'Times New Roman', serif", + "'Courier New', Courier, monospace", + 'cursive', + 'fantasy', + "'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif", + "Georgia, 'Times New Roman', Times, serif", + "'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif", + "Impact, Haettenschweiler, 'Arial Narrow Bold', sans-serif", + "'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif", + 'monospace', + 'sans-serif', + "'Segoe UI', Tahoma, Geneva, Verdana, sans-serif", + 'serif', + "'Times New Roman', Times, serif", + "'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif", + 'Verdana, Geneva, Tahoma, sans-serif' + ] + }, + 'font-feature-settings': { + values: [ + '"aalt"', + '"abvf"', + '"abvm"', + '"abvs"', + '"afrc"', + '"akhn"', + '"blwf"', + '"blwm"', + '"blws"', + '"calt"', + '"case"', + '"ccmp"', + '"cfar"', + '"cjct"', + '"clig"', + '"cpct"', + '"cpsp"', + '"cswh"', + '"curs"', + '"c2pc"', + '"c2sc"', + '"dist"', + '"dlig"', + '"dnom"', + '"dtls"', + '"expt"', + '"falt"', + '"fin2"', + '"fin3"', + '"fina"', + '"flac"', + '"frac"', + '"fwid"', + '"half"', + '"haln"', + '"halt"', + '"hist"', + '"hkna"', + '"hlig"', + '"hngl"', + '"hojo"', + '"hwid"', + '"init"', + '"isol"', + '"ital"', + '"jalt"', + '"jp78"', + '"jp83"', + '"jp90"', + '"jp04"', + '"kern"', + '"lfbd"', + '"liga"', + '"ljmo"', + '"lnum"', + '"locl"', + '"ltra"', + '"ltrm"', + '"mark"', + '"med2"', + '"medi"', + '"mgrk"', + '"mkmk"', + '"nalt"', + '"nlck"', + '"nukt"', + '"numr"', + '"onum"', + '"opbd"', + '"ordn"', + '"ornm"', + '"palt"', + '"pcap"', + '"pkna"', + '"pnum"', + '"pref"', + '"pres"', + '"pstf"', + '"psts"', + '"pwid"', + '"qwid"', + '"rand"', + '"rclt"', + '"rlig"', + '"rkrf"', + '"rphf"', + '"rtbd"', + '"rtla"', + '"rtlm"', + '"ruby"', + '"salt"', + '"sinf"', + '"size"', + '"smcp"', + '"smpl"', + '"ssty"', + '"stch"', + '"subs"', + '"sups"', + '"swsh"', + '"titl"', + '"tjmo"', + '"tnam"', + '"tnum"', + '"trad"', + '"twid"', + '"unic"', + '"valt"', + '"vatu"', + '"vert"', + '"vhal"', + '"vjmo"', + '"vkna"', + '"vkrn"', + '"vpal"', + '"vrt2"', + '"zero"', + 'normal', + 'off', + 'on' + ] + }, + 'font-kerning': { + values: ['auto', 'none', 'normal'] + }, + 'font-language-override': { + values: ['normal'] + }, + 'font-size': { + values: [ + 'large', + 'larger', + 'medium', + 'small', + 'smaller', + 'x-large', + 'x-small', + 'xx-large', + 'xx-small' + ] + }, + 'font-size-adjust': { + values: ['none'] + }, + 'font-stretch': { + values: [ + 'condensed', + 'expanded', + 'extra-condensed', + 'extra-expanded', + 'narrower', + 'normal', + 'semi-condensed', + 'semi-expanded', + 'ultra-condensed', + 'ultra-expanded', + 'wider' + ] + }, + 'font-style': { + values: ['italic', 'normal', 'oblique'] + }, + 'font-synthesis': { + values: ['none', 'style', 'weight'] + }, + 'font-variant': { + values: ['normal', 'small-caps'] + }, + 'font-variant-alternates': { + values: [ + 'annotation()', + 'character-variant()', + 'historical-forms', + 'normal', + 'ornaments()', + 'styleset()', + 'stylistic()', + 'swash()' + ] + }, + 'font-variant-caps': { + values: [ + 'all-petite-caps', + 'all-small-caps', + 'normal', + 'petite-caps', + 'small-caps', + 'titling-caps', + 'unicase' + ] + }, + 'font-variant-east-asian': { + values: [ + 'full-width', + 'jis04', + 'jis78', + 'jis83', + 'jis90', + 'normal', + 'proportional-width', + 'ruby', + 'simplified', + 'traditional' + ] + }, + 'font-variant-ligatures': { + values: [ + 'additional-ligatures', + 'common-ligatures', + 'contextual', + 'discretionary-ligatures', + 'historical-ligatures', + 'no-additional-ligatures', + 'no-common-ligatures', + 'no-contextual', + 'no-discretionary-ligatures', + 'no-historical-ligatures', + 'none', + 'normal' + ] + }, + 'font-variant-numeric': { + values: [ + 'diagonal-fractions', + 'lining-nums', + 'normal', + 'oldstyle-nums', + 'ordinal', + 'proportional-nums', + 'slashed-zero', + 'stacked-fractions', + 'tabular-nums' + ] + }, + 'font-variant-position': { + values: ['normal', 'sub', 'super'] + }, + 'font-weight': { + values: [ + '100', + '200', + '300', + '400', + '500', + '600', + '700', + '800', + '900', + 'bold', + 'bolder', + 'lighter', + 'normal' + ] + }, + 'glyph-orientation-horizontal': {}, + 'glyph-orientation-vertical': { + values: ['auto'] + }, + 'grid-area': { + values: ['auto', 'span'] + }, + 'grid': {}, + 'grid-auto-columns': { + values: ['min-content', 'max-content', 'auto', 'minmax()'] + }, + 'grid-auto-flow': { + values: ['row', 'column', 'dense'] + }, + 'grid-auto-rows': { + values: ['min-content', 'max-content', 'auto', 'minmax()'] + }, + 'grid-column': { + values: ['auto', 'span'] + }, + 'grid-column-end': { + values: ['auto', 'span'] + }, + 'grid-column-gap': {}, + 'grid-column-start': { + values: ['auto', 'span'] + }, + 'grid-gap': {}, + 'grid-row': { + values: ['auto', 'span'] + }, + 'grid-row-end': { + values: ['auto', 'span'] + }, + 'grid-row-gap': {}, + 'grid-row-start': { + values: ['auto', 'span'] + }, + 'grid-template': { + values: [ + 'none', + 'min-content', + 'max-content', + 'auto', + 'subgrid', + 'minmax()', + 'repeat()' + ] + }, + 'grid-template-areas': { + values: ['none'] + }, + 'grid-template-columns': { + values: [ + 'none', + 'min-content', + 'max-content', + 'auto', + 'subgrid', + 'minmax()', + 'repeat()' + ] + }, + 'grid-template-rows': { + values: [ + 'none', + 'min-content', + 'max-content', + 'auto', + 'subgrid', + 'minmax()', + 'repeat()' + ] + }, + 'height': { + values: ['auto', 'fit-content', 'max-content', 'min-content'] + }, + 'hyphens': { + values: ['auto', 'manual', 'none'] + }, + 'image-orientation': { + values: ['flip', 'from-image'] + }, + 'image-rendering': { + values: [ + 'auto', + 'crisp-edges', + '-moz-crisp-edges', + 'optimizeQuality', + 'optimizeSpeed', + 'pixelated' + ] + }, + 'ime-mode': { + values: ['active', 'auto', 'disabled', 'inactive', 'normal'] + }, + 'inline-size': { + values: ['auto'] + }, + 'isolation': { + values: ['auto', 'isolate'] + }, + 'justify-content': { + values: [ + 'center', + 'start', + 'end', + 'left', + 'right', + 'safe', + 'unsafe', + 'stretch', + 'space-evenly', + 'flex-end', + 'flex-start', + 'space-around', + 'space-between', + 'baseline', + 'first baseline', + 'last baseline' + ] + }, + 'kerning': { + values: ['auto'] + }, + 'left': { + values: ['auto'] + }, + 'letter-spacing': { + values: ['normal'] + }, + 'lighting-color': {}, + 'line-break': { + values: ['auto', 'loose', 'normal', 'strict', 'anywhere'] + }, + 'line-height': { + values: ['normal'] + }, + 'list-style': { + values: [ + 'armenian', + 'circle', + 'decimal', + 'decimal-leading-zero', + 'disc', + 'georgian', + 'inside', + 'lower-alpha', + 'lower-greek', + 'lower-latin', + 'lower-roman', + 'none', + 'outside', + 'square', + 'symbols()', + 'upper-alpha', + 'upper-latin', + 'upper-roman', + 'url()' + ] + }, + 'list-style-image': { + values: ['none'] + }, + 'list-style-position': { + values: ['inside', 'outside'] + }, + 'list-style-type': { + values: [ + 'armenian', + 'circle', + 'decimal', + 'decimal-leading-zero', + 'disc', + 'georgian', + 'lower-alpha', + 'lower-greek', + 'lower-latin', + 'lower-roman', + 'none', + 'square', + 'symbols()', + 'upper-alpha', + 'upper-latin', + 'upper-roman' + ] + }, + 'margin': { + values: ['auto'] + }, + 'margin-block-end': { + values: ['auto'] + }, + 'margin-block-start': { + values: ['auto'] + }, + 'margin-bottom': { + values: ['auto'] + }, + 'margin-inline-end': { + values: ['auto'] + }, + 'margin-inline-start': { + values: ['auto'] + }, + 'margin-left': { + values: ['auto'] + }, + 'margin-right': { + values: ['auto'] + }, + 'margin-top': { + values: ['auto'] + }, + 'marker': { + values: ['none', 'url()'] + }, + 'marker-end': { + values: ['none', 'url()'] + }, + 'marker-mid': { + values: ['none', 'url()'] + }, + 'marker-start': { + values: ['none', 'url()'] + }, + 'mask-image': { + values: ['none', 'url()'] + }, + 'mask-mode': { + values: ['alpha', 'auto', 'luminance'] + }, + 'mask-origin': {}, + 'mask-position': {}, + 'mask-repeat': {}, + 'mask-size': { + values: ['auto', 'contain', 'cover'] + }, + 'mask-type': { + values: ['alpha', 'luminance'] + }, + 'max-block-size': { + values: ['none'] + }, + 'max-height': { + values: ['none', 'fit-content', 'max-content', 'min-content'] + }, + 'max-inline-size': { + values: ['none'] + }, + 'max-width': { + values: ['none', 'fit-content', 'max-content', 'min-content'] + }, + 'min-block-size': {}, + 'min-height': { + values: ['auto', 'fit-content', 'max-content', 'min-content'] + }, + 'min-inline-size': {}, + 'min-width': { + values: ['auto', 'fit-content', 'max-content', 'min-content'] + }, + 'mix-blend-mode': { + values: [ + 'normal', + 'multiply', + 'screen', + 'overlay', + 'darken', + 'lighten', + 'color-dodge', + 'color-burn', + 'hard-light', + 'soft-light', + 'difference', + 'exclusion', + 'hue', + 'saturation', + 'color', + 'luminosity' + ] + }, + 'motion': { + values: ['none', 'path()', 'auto', 'reverse'] + }, + 'motion-offset': {}, + 'motion-path': { + values: ['none', 'path()'] + }, + 'motion-rotation': { + values: ['auto', 'reverse'] + }, + '-moz-animation': { + values: [ + 'alternate', + 'alternate-reverse', + 'backwards', + 'both', + 'forwards', + 'infinite', + 'none', + 'normal', + 'reverse' + ] + }, + '-moz-animation-delay': {}, + '-moz-animation-direction': { + values: ['alternate', 'alternate-reverse', 'normal', 'reverse'] + }, + '-moz-animation-duration': {}, + '-moz-animation-iteration-count': { + values: ['infinite'] + }, + '-moz-animation-name': { + values: ['none'] + }, + '-moz-animation-play-state': { + values: ['paused', 'running'] + }, + '-moz-animation-timing-function': {}, + '-moz-appearance': { + values: [ + 'button', + 'button-arrow-down', + 'button-arrow-next', + 'button-arrow-previous', + 'button-arrow-up', + 'button-bevel', + 'checkbox', + 'checkbox-container', + 'checkbox-label', + 'dialog', + 'groupbox', + 'listbox', + 'menuarrow', + 'menuimage', + 'menuitem', + 'menuitemtext', + 'menulist', + 'menulist-button', + 'menulist-text', + 'menulist-textfield', + 'menupopup', + 'menuradio', + 'menuseparator', + '-moz-mac-unified-toolbar', + '-moz-win-borderless-glass', + '-moz-win-browsertabbar-toolbox', + '-moz-win-communications-toolbox', + '-moz-win-glass', + '-moz-win-media-toolbox', + 'none', + 'progressbar', + 'progresschunk', + 'radio', + 'radio-container', + 'radio-label', + 'radiomenuitem', + 'resizer', + 'resizerpanel', + 'scrollbarbutton-down', + 'scrollbarbutton-left', + 'scrollbarbutton-right', + 'scrollbarbutton-up', + 'scrollbar-small', + 'scrollbartrack-horizontal', + 'scrollbartrack-vertical', + 'separator', + 'spinner', + 'spinner-downbutton', + 'spinner-textfield', + 'spinner-upbutton', + 'statusbar', + 'statusbarpanel', + 'tab', + 'tabpanels', + 'tab-scroll-arrow-back', + 'tab-scroll-arrow-forward', + 'textfield', + 'textfield-multiline', + 'toolbar', + 'toolbox', + 'tooltip', + 'treeheadercell', + 'treeheadersortarrow', + 'treeitem', + 'treetwistyopen', + 'treeview', + 'treewisty', + 'window' + ] + }, + '-moz-backface-visibility': { + values: ['hidden', 'visible'] + }, + '-moz-background-clip': { + values: ['padding'] + }, + '-moz-background-inline-policy': { + values: ['bounding-box', 'continuous', 'each-box'] + }, + '-moz-background-origin': {}, + '-moz-border-bottom-colors': {}, + '-moz-border-image': { + values: [ + 'auto', + 'fill', + 'none', + 'repeat', + 'round', + 'space', + 'stretch', + 'url()' + ] + }, + '-moz-border-left-colors': {}, + '-moz-border-right-colors': {}, + '-moz-border-top-colors': {}, + '-moz-box-align': { + values: ['baseline', 'center', 'end', 'start', 'stretch'] + }, + '-moz-box-direction': { + values: ['normal', 'reverse'] + }, + '-moz-box-flex': {}, + '-moz-box-flexgroup': {}, + '-moz-box-ordinal-group': {}, + '-moz-box-orient': { + values: ['block-axis', 'horizontal', 'inline-axis', 'vertical'] + }, + '-moz-box-pack': { + values: ['center', 'end', 'justify', 'start'] + }, + '-moz-box-sizing': { + values: ['border-box', 'content-box', 'padding-box'] + }, + '-moz-column-count': { + values: ['auto'] + }, + '-moz-column-gap': { + values: ['normal'] + }, + '-moz-column-rule': {}, + '-moz-column-rule-color': {}, + '-moz-column-rule-style': {}, + '-moz-column-rule-width': {}, + '-moz-columns': { + values: ['auto'] + }, + '-moz-column-width': { + values: ['auto'] + }, + '-moz-font-feature-settings': { + values: [ + '"c2cs"', + '"dlig"', + '"kern"', + '"liga"', + '"lnum"', + '"onum"', + '"smcp"', + '"swsh"', + '"tnum"', + 'normal', + 'off', + 'on' + ] + }, + '-moz-hyphens': { + values: ['auto', 'manual', 'none'] + }, + '-moz-perspective': { + values: ['none'] + }, + '-moz-perspective-origin': {}, + '-moz-text-align-last': { + values: ['auto', 'center', 'justify', 'left', 'right'] + }, + '-moz-text-decoration-color': {}, + '-moz-text-decoration-line': { + values: ['line-through', 'none', 'overline', 'underline'] + }, + '-moz-text-decoration-style': { + values: ['dashed', 'dotted', 'double', 'none', 'solid', 'wavy'] + }, + '-moz-text-size-adjust': { + values: ['auto', 'none'] + }, + '-moz-transform': { + values: [ + 'matrix()', + 'matrix3d()', + 'none', + 'perspective', + 'rotate()', + 'rotate3d()', + "rotateX('angle')", + "rotateY('angle')", + "rotateZ('angle')", + 'scale()', + 'scale3d()', + 'scaleX()', + 'scaleY()', + 'scaleZ()', + 'skew()', + 'skewX()', + 'skewY()', + 'translate()', + 'translate3d()', + 'translateX()', + 'translateY()', + 'translateZ()' + ] + }, + '-moz-transform-origin': {}, + '-moz-transition': { + values: ['all', 'none'] + }, + '-moz-transition-delay': {}, + '-moz-transition-duration': {}, + '-moz-transition-property': { + values: ['all', 'none'] + }, + '-moz-transition-timing-function': {}, + '-moz-user-focus': { + values: ['ignore', 'normal'] + }, + '-moz-user-select': { + values: [ + 'all', + 'element', + 'elements', + '-moz-all', + '-moz-none', + 'none', + 'text', + 'toggle' + ] + }, + '-ms-accelerator': { + values: ['false', 'true'] + }, + '-ms-behavior': {}, + '-ms-block-progression': { + values: ['bt', 'lr', 'rl', 'tb'] + }, + '-ms-content-zoom-chaining': { + values: ['chained', 'none'] + }, + '-ms-content-zooming': { + values: ['none', 'zoom'] + }, + '-ms-content-zoom-limit': {}, + '-ms-content-zoom-limit-max': {}, + '-ms-content-zoom-limit-min': {}, + '-ms-content-zoom-snap': { + values: [ + 'mandatory', + 'none', + 'proximity', + 'snapInterval(100%, 100%)', + 'snapList()' + ] + }, + '-ms-content-zoom-snap-points': { + values: ['snapInterval(100%, 100%)', 'snapList()'] + }, + '-ms-content-zoom-snap-type': { + values: ['mandatory', 'none', 'proximity'] + }, + '-ms-filter': {}, + '-ms-flex': { + values: ['auto', 'none'] + }, + '-ms-flex-align': { + values: ['baseline', 'center', 'end', 'start', 'stretch'] + }, + '-ms-flex-direction': { + values: ['column', 'column-reverse', 'row', 'row-reverse'] + }, + '-ms-flex-flow': { + values: [ + 'column', + 'column-reverse', + 'nowrap', + 'row', + 'wrap', + 'wrap-reverse' + ] + }, + '-ms-flex-item-align': { + values: ['auto', 'baseline', 'center', 'end', 'start', 'stretch'] + }, + '-ms-flex-line-pack': { + values: ['center', 'distribute', 'end', 'justify', 'start', 'stretch'] + }, + '-ms-flex-order': {}, + '-ms-flex-pack': { + values: ['center', 'distribute', 'end', 'justify', 'start'] + }, + '-ms-flex-wrap': { + values: ['nowrap', 'wrap', 'wrap-reverse'] + }, + '-ms-flow-from': { + values: ['none'] + }, + '-ms-flow-into': { + values: ['none'] + }, + '-ms-grid-column': { + values: ['auto', 'end', 'start'] + }, + '-ms-grid-column-align': { + values: ['center', 'end', 'start', 'stretch'] + }, + '-ms-grid-columns': {}, + '-ms-grid-column-span': {}, + '-ms-grid-layer': {}, + '-ms-grid-row': { + values: ['auto', 'end', 'start'] + }, + '-ms-grid-row-align': { + values: ['center', 'end', 'start', 'stretch'] + }, + '-ms-grid-rows': {}, + '-ms-grid-row-span': {}, + '-ms-high-contrast-adjust': { + values: ['auto', 'none'] + }, + '-ms-hyphenate-limit-chars': { + values: ['auto'] + }, + '-ms-hyphenate-limit-lines': { + values: ['no-limit'] + }, + '-ms-hyphenate-limit-zone': {}, + '-ms-hyphens': { + values: ['auto', 'manual', 'none'] + }, + '-ms-ime-mode': { + values: ['active', 'auto', 'disabled', 'inactive', 'normal'] + }, + '-ms-interpolation-mode': { + values: ['bicubic', 'nearest-neighbor'] + }, + '-ms-layout-grid': { + values: ['char', 'line', 'mode', 'type'] + }, + '-ms-layout-grid-char': { + values: ['auto', 'none'] + }, + '-ms-layout-grid-line': { + values: ['auto', 'none'] + }, + '-ms-layout-grid-mode': { + values: ['both', 'char', 'line', 'none'] + }, + '-ms-layout-grid-type': { + values: ['fixed', 'loose', 'strict'] + }, + '-ms-line-break': { + values: ['auto', 'keep-all', 'newspaper', 'normal', 'strict'] + }, + '-ms-overflow-style': { + values: ['auto', '-ms-autohiding-scrollbar', 'none', 'scrollbar'] + }, + '-ms-perspective': { + values: ['none'] + }, + '-ms-perspective-origin': {}, + '-ms-perspective-origin-x': {}, + '-ms-perspective-origin-y': {}, + '-ms-progress-appearance': { + values: ['bar', 'ring'] + }, + '-ms-scrollbar-3dlight-color': {}, + '-ms-scrollbar-arrow-color': {}, + '-ms-scrollbar-base-color': {}, + '-ms-scrollbar-darkshadow-color': {}, + '-ms-scrollbar-face-color': {}, + '-ms-scrollbar-highlight-color': {}, + '-ms-scrollbar-shadow-color': {}, + '-ms-scrollbar-track-color': {}, + '-ms-scroll-chaining': { + values: ['chained', 'none'] + }, + '-ms-scroll-limit': { + values: ['auto'] + }, + '-ms-scroll-limit-x-max': { + values: ['auto'] + }, + '-ms-scroll-limit-x-min': {}, + '-ms-scroll-limit-y-max': { + values: ['auto'] + }, + '-ms-scroll-limit-y-min': {}, + '-ms-scroll-rails': { + values: ['none', 'railed'] + }, + '-ms-scroll-snap-points-x': { + values: ['snapInterval(100%, 100%)', 'snapList()'] + }, + '-ms-scroll-snap-points-y': { + values: ['snapInterval(100%, 100%)', 'snapList()'] + }, + '-ms-scroll-snap-type': { + values: ['none', 'mandatory', 'proximity'] + }, + '-ms-scroll-snap-x': { + values: [ + 'mandatory', + 'none', + 'proximity', + 'snapInterval(100%, 100%)', + 'snapList()' + ] + }, + '-ms-scroll-snap-y': { + values: [ + 'mandatory', + 'none', + 'proximity', + 'snapInterval(100%, 100%)', + 'snapList()' + ] + }, + '-ms-scroll-translation': { + values: ['none', 'vertical-to-horizontal'] + }, + '-ms-text-align-last': { + values: ['auto', 'center', 'justify', 'left', 'right'] + }, + '-ms-text-autospace': { + values: [ + 'ideograph-alpha', + 'ideograph-numeric', + 'ideograph-parenthesis', + 'ideograph-space', + 'none', + 'punctuation' + ] + }, + '-ms-text-combine-horizontal': { + values: ['all', 'digits', 'none'] + }, + '-ms-text-justify': { + values: [ + 'auto', + 'distribute', + 'inter-cluster', + 'inter-ideograph', + 'inter-word', + 'kashida' + ] + }, + '-ms-text-kashida-space': {}, + '-ms-text-overflow': { + values: ['clip', 'ellipsis'] + }, + '-ms-text-size-adjust': { + values: ['auto', 'none'] + }, + '-ms-text-underline-position': { + values: ['alphabetic', 'auto', 'over', 'under'] + }, + '-ms-touch-action': { + values: [ + 'auto', + 'double-tap-zoom', + 'manipulation', + 'none', + 'pan-x', + 'pan-y', + 'pinch-zoom' + ] + }, + '-ms-touch-select': { + values: ['grippers', 'none'] + }, + '-ms-transform': { + values: [ + 'matrix()', + 'matrix3d()', + 'none', + 'rotate()', + 'rotate3d()', + "rotateX('angle')", + "rotateY('angle')", + "rotateZ('angle')", + 'scale()', + 'scale3d()', + 'scaleX()', + 'scaleY()', + 'scaleZ()', + 'skew()', + 'skewX()', + 'skewY()', + 'translate()', + 'translate3d()', + 'translateX()', + 'translateY()', + 'translateZ()' + ] + }, + '-ms-transform-origin': {}, + '-ms-transform-origin-x': {}, + '-ms-transform-origin-y': {}, + '-ms-transform-origin-z': {}, + '-ms-user-select': { + values: ['element', 'none', 'text'] + }, + '-ms-word-break': { + values: ['break-all', 'keep-all', 'normal'] + }, + '-ms-word-wrap': { + values: ['break-word', 'normal'] + }, + '-ms-wrap-flow': { + values: ['auto', 'both', 'clear', 'end', 'maximum', 'minimum', 'start'] + }, + '-ms-wrap-margin': {}, + '-ms-wrap-through': { + values: ['none', 'wrap'] + }, + '-ms-writing-mode': { + values: [ + 'bt-lr', + 'bt-rl', + 'lr-bt', + 'lr-tb', + 'rl-bt', + 'rl-tb', + 'tb-lr', + 'tb-rl' + ] + }, + '-ms-zoom': { + values: ['normal'] + }, + '-ms-zoom-animation': { + values: ['default', 'none'] + }, + 'nav-down': { + values: ['auto', 'current', 'root'] + }, + 'nav-index': { + values: ['auto'] + }, + 'nav-left': { + values: ['auto', 'current', 'root'] + }, + 'nav-right': { + values: ['auto', 'current', 'root'] + }, + 'nav-up': { + values: ['auto', 'current', 'root'] + }, + 'negative': {}, + '-o-animation': { + values: [ + 'alternate', + 'alternate-reverse', + 'backwards', + 'both', + 'forwards', + 'infinite', + 'none', + 'normal', + 'reverse' + ] + }, + '-o-animation-delay': {}, + '-o-animation-direction': { + values: ['alternate', 'alternate-reverse', 'normal', 'reverse'] + }, + '-o-animation-duration': {}, + '-o-animation-fill-mode': { + values: ['backwards', 'both', 'forwards', 'none'] + }, + '-o-animation-iteration-count': { + values: ['infinite'] + }, + '-o-animation-name': { + values: ['none'] + }, + '-o-animation-play-state': { + values: ['paused', 'running'] + }, + '-o-animation-timing-function': {}, + 'object-fit': { + values: ['contain', 'cover', 'fill', 'none', 'scale-down'] + }, + 'object-position': {}, + '-o-border-image': { + values: ['auto', 'fill', 'none', 'repeat', 'round', 'space', 'stretch'] + }, + '-o-object-fit': { + values: ['contain', 'cover', 'fill', 'none', 'scale-down'] + }, + '-o-object-position': {}, + 'opacity': {}, + 'order': {}, + 'orphans': {}, + '-o-table-baseline': {}, + '-o-tab-size': {}, + '-o-text-overflow': { + values: ['clip', 'ellipsis'] + }, + '-o-transform': { + values: [ + 'matrix()', + 'matrix3d()', + 'none', + 'rotate()', + 'rotate3d()', + "rotateX('angle')", + "rotateY('angle')", + "rotateZ('angle')", + 'scale()', + 'scale3d()', + 'scaleX()', + 'scaleY()', + 'scaleZ()', + 'skew()', + 'skewX()', + 'skewY()', + 'translate()', + 'translate3d()', + 'translateX()', + 'translateY()', + 'translateZ()' + ] + }, + '-o-transform-origin': {}, + '-o-transition': { + values: ['all', 'none'] + }, + '-o-transition-delay': {}, + '-o-transition-duration': {}, + '-o-transition-property': { + values: ['all', 'none'] + }, + '-o-transition-timing-function': {}, + 'offset-block-end': { + values: ['auto'] + }, + 'offset-block-start': { + values: ['auto'] + }, + 'offset-inline-end': { + values: ['auto'] + }, + 'offset-inline-start': { + values: ['auto'] + }, + 'outline': { + values: ['auto', 'invert'] + }, + 'outline-color': { + values: ['invert'] + }, + 'outline-offset': {}, + 'outline-style': { + values: ['auto'] + }, + 'outline-width': {}, + 'overflow': { + values: ['auto', 'hidden', '-moz-hidden-unscrollable', 'scroll', 'visible'] + }, + 'overflow-wrap': { + values: ['break-word', 'normal'] + }, + 'overflow-x': { + values: ['auto', 'hidden', 'scroll', 'visible'] + }, + 'overflow-y': { + values: ['auto', 'hidden', 'scroll', 'visible'] + }, + 'pad': {}, + 'padding': { + values: [] + }, + 'padding-bottom': {}, + 'padding-block-end': {}, + 'padding-block-start': {}, + 'padding-inline-end': {}, + 'padding-inline-start': {}, + 'padding-left': {}, + 'padding-right': {}, + 'padding-top': {}, + 'page-break-after': { + values: ['always', 'auto', 'avoid', 'left', 'right'] + }, + 'page-break-before': { + values: ['always', 'auto', 'avoid', 'left', 'right'] + }, + 'page-break-inside': { + values: ['auto', 'avoid'] + }, + 'paint-order': { + values: ['fill', 'markers', 'normal', 'stroke'] + }, + 'perspective': { + values: ['none'] + }, + 'perspective-origin': {}, + 'pointer-events': { + values: [ + 'all', + 'fill', + 'none', + 'painted', + 'stroke', + 'visible', + 'visibleFill', + 'visiblePainted', + 'visibleStroke' + ] + }, + 'position': { + values: [ + 'absolute', + 'fixed', + '-ms-page', + 'relative', + 'static', + 'sticky', + '-webkit-sticky' + ] + }, + 'prefix': {}, + 'quotes': { + values: ['none'] + }, + 'range': { + values: ['auto', 'infinite'] + }, + 'resize': { + values: ['both', 'horizontal', 'none', 'vertical'] + }, + 'right': { + values: ['auto'] + }, + 'ruby-align': { + values: [ + 'auto', + 'center', + 'distribute-letter', + 'distribute-space', + 'left', + 'line-edge', + 'right', + 'start', + 'space-between', + 'space-around' + ] + }, + 'ruby-overhang': { + values: ['auto', 'end', 'none', 'start'] + }, + 'ruby-position': { + values: ['after', 'before', 'inline', 'right'] + }, + 'ruby-span': { + values: ['attr(x)', 'none'] + }, + 'scrollbar-3dlight-color': {}, + 'scrollbar-arrow-color': {}, + 'scrollbar-base-color': {}, + 'scrollbar-darkshadow-color': {}, + 'scrollbar-face-color': {}, + 'scrollbar-highlight-color': {}, + 'scrollbar-shadow-color': {}, + 'scrollbar-track-color': {}, + 'scroll-behavior': { + values: ['auto', 'smooth'] + }, + 'scroll-snap-coordinate': { + values: ['none'] + }, + 'scroll-snap-destination': {}, + 'scroll-snap-points-x': { + values: ['none', 'repeat()'] + }, + 'scroll-snap-points-y': { + values: ['none', 'repeat()'] + }, + 'scroll-snap-type': { + values: ['none', 'mandatory', 'proximity'] + }, + 'shape-image-threshold': {}, + 'shape-margin': {}, + 'shape-outside': { + values: ['margin-box', 'none'] + }, + 'shape-rendering': { + values: ['auto', 'crispEdges', 'geometricPrecision', 'optimizeSpeed'] + }, + 'size': {}, + 'src': { + values: ['url()', 'format()', 'local()'] + }, + 'stop-color': {}, + 'stop-opacity': {}, + 'stroke': { + values: ['url()', 'none'] + }, + 'stroke-dasharray': { + values: ['none'] + }, + 'stroke-dashoffset': {}, + 'stroke-linecap': { + values: ['butt', 'round', 'square'] + }, + 'stroke-linejoin': { + values: ['bevel', 'miter', 'round'] + }, + 'stroke-miterlimit': {}, + 'stroke-opacity': {}, + 'stroke-width': {}, + 'suffix': {}, + 'system': { + values: [ + 'additive', + 'alphabetic', + 'cyclic', + 'extends', + 'fixed', + 'numeric', + 'symbolic' + ] + }, + 'symbols': {}, + 'table-layout': { + values: ['auto', 'fixed'] + }, + 'tab-size': {}, + 'text-align': { + values: ['center', 'end', 'justify', 'left', 'right', 'start'] + }, + 'text-align-last': { + values: ['auto', 'center', 'justify', 'left', 'right'] + }, + 'text-anchor': { + values: ['end', 'middle', 'start'] + }, + 'text-decoration': { + values: [ + 'dashed', + 'dotted', + 'double', + 'line-through', + 'none', + 'overline', + 'solid', + 'underline', + 'wavy' + ] + }, + 'text-decoration-color': {}, + 'text-decoration-line': { + values: ['line-through', 'none', 'overline', 'underline'] + }, + 'text-decoration-style': { + values: ['dashed', 'dotted', 'double', 'none', 'solid', 'wavy'] + }, + 'text-indent': { + values: [] + }, + 'text-justify': { + values: [ + 'auto', + 'distribute', + 'distribute-all-lines', + 'inter-cluster', + 'inter-ideograph', + 'inter-word', + 'kashida', + 'newspaper' + ] + }, + 'text-orientation': { + values: ['sideways', 'sideways-right', 'upright'] + }, + 'text-overflow': { + values: ['clip', 'ellipsis'] + }, + 'text-rendering': { + values: [ + 'auto', + 'geometricPrecision', + 'optimizeLegibility', + 'optimizeSpeed' + ] + }, + 'text-shadow': { + values: ['none'] + }, + 'text-transform': { + values: ['capitalize', 'lowercase', 'none', 'uppercase'] + }, + 'text-underline-position': { + values: ['above', 'auto', 'below'] + }, + 'top': { + values: ['auto'] + }, + 'touch-action': { + values: [ + 'auto', + 'cross-slide-x', + 'cross-slide-y', + 'double-tap-zoom', + 'manipulation', + 'none', + 'pan-x', + 'pan-y', + 'pinch-zoom' + ] + }, + 'transform': { + values: [ + 'matrix()', + 'matrix3d()', + 'none', + 'perspective()', + 'rotate()', + 'rotate3d()', + "rotateX('angle')", + "rotateY('angle')", + "rotateZ('angle')", + 'scale()', + 'scale3d()', + 'scaleX()', + 'scaleY()', + 'scaleZ()', + 'skew()', + 'skewX()', + 'skewY()', + 'translate()', + 'translate3d()', + 'translateX()', + 'translateY()', + 'translateZ()' + ] + }, + 'transform-origin': {}, + 'transform-style': { + values: ['flat', 'preserve-3d'] + }, + 'transition': { + values: ['all', 'none'] + }, + 'transition-delay': {}, + 'transition-duration': {}, + 'transition-property': { + values: ['all', 'none'] + }, + 'transition-timing-function': {}, + 'unicode-bidi': { + values: [ + 'bidi-override', + 'embed', + 'isolate', + 'isolate-override', + 'normal', + 'plaintext' + ] + }, + 'unicode-range': { + values: [ + 'U+26', + 'U+20-24F, U+2B0-2FF, U+370-4FF, U+1E00-1EFF, U+2000-20CF, U+2100-23FF, U+2500-26FF, U+E000-F8FF, U+FB00-FB4F', + 'U+20-17F, U+2B0-2FF, U+2000-206F, U+20A0-20CF, U+2100-21FF, U+2600-26FF', + 'U+20-2FF, U+370-4FF, U+1E00-20CF, U+2100-23FF, U+2500-26FF, U+FB00-FB4F, U+FFF0-FFFD', + 'U+20-4FF, U+530-58F, U+10D0-10FF, U+1E00-23FF, U+2440-245F, U+2500-26FF, U+FB00-FB4F, U+FE20-FE2F, U+FFF0-FFFD', + 'U+00-7F', + 'U+80-FF', + 'U+100-17F', + 'U+180-24F', + 'U+1E00-1EFF', + 'U+250-2AF', + 'U+370-3FF', + 'U+1F00-1FFF', + 'U+400-4FF', + 'U+500-52F', + 'U+00-52F, U+1E00-1FFF, U+2200-22FF', + 'U+530-58F', + 'U+590-5FF', + 'U+600-6FF', + 'U+750-77F', + 'U+8A0-8FF', + 'U+700-74F', + 'U+900-97F', + 'U+980-9FF', + 'U+A00-A7F', + 'U+A80-AFF', + 'U+B00-B7F', + 'U+B80-BFF', + 'U+C00-C7F', + 'U+C80-CFF', + 'U+D00-D7F', + 'U+D80-DFF', + 'U+118A0-118FF', + 'U+E00-E7F', + 'U+1A20-1AAF', + 'U+AA80-AADF', + 'U+E80-EFF', + 'U+F00-FFF', + 'U+1000-109F', + 'U+10A0-10FF', + 'U+1200-137F', + 'U+1380-139F', + 'U+2D80-2DDF', + 'U+AB00-AB2F', + 'U+1780-17FF', + 'U+1800-18AF', + 'U+1B80-1BBF', + 'U+1CC0-1CCF', + 'U+4E00-9FD5', + 'U+3400-4DB5', + 'U+2F00-2FDF', + 'U+2E80-2EFF', + 'U+1100-11FF', + 'U+AC00-D7AF', + 'U+3040-309F', + 'U+30A0-30FF', + 'U+A5, U+4E00-9FFF, U+30??, U+FF00-FF9F', + 'U+A4D0-A4FF', + 'U+A000-A48F', + 'U+A490-A4CF', + 'U+2000-206F', + 'U+3000-303F', + 'U+2070-209F', + 'U+20A0-20CF', + 'U+2100-214F', + 'U+2150-218F', + 'U+2190-21FF', + 'U+2200-22FF', + 'U+2300-23FF', + 'U+E000-F8FF', + 'U+FB00-FB4F', + 'U+FB50-FDFF', + 'U+1F600-1F64F', + 'U+2600-26FF', + 'U+1F300-1F5FF', + 'U+1F900-1F9FF', + 'U+1F680-1F6FF' + ] + }, + 'user-select': { + values: ['all', 'auto', 'contain', 'none', 'text'] + }, + 'vertical-align': { + values: [ + 'auto', + 'baseline', + 'bottom', + 'middle', + 'sub', + 'super', + 'text-bottom', + 'text-top', + 'top', + '-webkit-baseline-middle' + ] + }, + 'visibility': { + values: ['collapse', 'hidden', 'visible'] + }, + '-webkit-animation': { + values: [ + 'alternate', + 'alternate-reverse', + 'backwards', + 'both', + 'forwards', + 'infinite', + 'none', + 'normal', + 'reverse' + ] + }, + '-webkit-animation-delay': {}, + '-webkit-animation-direction': { + values: ['alternate', 'alternate-reverse', 'normal', 'reverse'] + }, + '-webkit-animation-duration': {}, + '-webkit-animation-fill-mode': { + values: ['backwards', 'both', 'forwards', 'none'] + }, + '-webkit-animation-iteration-count': { + values: ['infinite'] + }, + '-webkit-animation-name': { + values: ['none'] + }, + '-webkit-animation-play-state': { + values: ['paused', 'running'] + }, + '-webkit-animation-timing-function': {}, + '-webkit-appearance': { + values: [ + 'button', + 'button-bevel', + 'caps-lock-indicator', + 'caret', + 'checkbox', + 'default-button', + 'listbox', + 'listitem', + 'media-fullscreen-button', + 'media-mute-button', + 'media-play-button', + 'media-seek-back-button', + 'media-seek-forward-button', + 'media-slider', + 'media-sliderthumb', + 'menulist', + 'menulist-button', + 'menulist-text', + 'menulist-textfield', + 'none', + 'push-button', + 'radio', + 'scrollbarbutton-down', + 'scrollbarbutton-left', + 'scrollbarbutton-right', + 'scrollbarbutton-up', + 'scrollbargripper-horizontal', + 'scrollbargripper-vertical', + 'scrollbarthumb-horizontal', + 'scrollbarthumb-vertical', + 'scrollbartrack-horizontal', + 'scrollbartrack-vertical', + 'searchfield', + 'searchfield-cancel-button', + 'searchfield-decoration', + 'searchfield-results-button', + 'searchfield-results-decoration', + 'slider-horizontal', + 'sliderthumb-horizontal', + 'sliderthumb-vertical', + 'slider-vertical', + 'square-button', + 'textarea', + 'textfield' + ] + }, + '-webkit-backdrop-filter': { + values: [ + 'none', + 'blur()', + 'brightness()', + 'contrast()', + 'drop-shadow()', + 'grayscale()', + 'hue-rotate()', + 'invert()', + 'opacity()', + 'saturate()', + 'sepia()', + 'url()' + ] + }, + '-webkit-backface-visibility': { + values: ['hidden', 'visible'] + }, + '-webkit-background-clip': {}, + '-webkit-background-composite': { + values: ['border', 'padding'] + }, + '-webkit-background-origin': {}, + '-webkit-border-image': { + values: [ + 'auto', + 'fill', + 'none', + 'repeat', + 'round', + 'space', + 'stretch', + 'url()' + ] + }, + '-webkit-box-align': { + values: ['baseline', 'center', 'end', 'start', 'stretch'] + }, + '-webkit-box-direction': { + values: ['normal', 'reverse'] + }, + '-webkit-box-flex': {}, + '-webkit-box-flex-group': {}, + '-webkit-box-ordinal-group': {}, + '-webkit-box-orient': { + values: ['block-axis', 'horizontal', 'inline-axis', 'vertical'] + }, + '-webkit-box-pack': { + values: ['center', 'end', 'justify', 'start'] + }, + '-webkit-box-reflect': { + values: ['above', 'below', 'left', 'right'] + }, + '-webkit-box-sizing': { + values: ['border-box', 'content-box'] + }, + '-webkit-break-after': { + values: [ + 'always', + 'auto', + 'avoid', + 'avoid-column', + 'avoid-page', + 'avoid-region', + 'column', + 'left', + 'page', + 'region', + 'right' + ] + }, + '-webkit-break-before': { + values: [ + 'always', + 'auto', + 'avoid', + 'avoid-column', + 'avoid-page', + 'avoid-region', + 'column', + 'left', + 'page', + 'region', + 'right' + ] + }, + '-webkit-break-inside': { + values: ['auto', 'avoid', 'avoid-column', 'avoid-page', 'avoid-region'] + }, + '-webkit-column-break-after': { + values: [ + 'always', + 'auto', + 'avoid', + 'avoid-column', + 'avoid-page', + 'avoid-region', + 'column', + 'left', + 'page', + 'region', + 'right' + ] + }, + '-webkit-column-break-before': { + values: [ + 'always', + 'auto', + 'avoid', + 'avoid-column', + 'avoid-page', + 'avoid-region', + 'column', + 'left', + 'page', + 'region', + 'right' + ] + }, + '-webkit-column-break-inside': { + values: ['auto', 'avoid', 'avoid-column', 'avoid-page', 'avoid-region'] + }, + '-webkit-column-count': { + values: ['auto'] + }, + '-webkit-column-gap': { + values: ['normal'] + }, + '-webkit-column-rule': {}, + '-webkit-column-rule-color': {}, + '-webkit-column-rule-style': {}, + '-webkit-column-rule-width': {}, + '-webkit-columns': { + values: ['auto'] + }, + '-webkit-column-span': { + values: ['all', 'none'] + }, + '-webkit-column-width': { + values: ['auto'] + }, + '-webkit-filter': { + values: [ + 'none', + 'blur()', + 'brightness()', + 'contrast()', + 'drop-shadow()', + 'grayscale()', + 'hue-rotate()', + 'invert()', + 'opacity()', + 'saturate()', + 'sepia()', + 'url()' + ] + }, + '-webkit-flow-from': { + values: ['none'] + }, + '-webkit-flow-into': { + values: ['none'] + }, + '-webkit-font-feature-settings': { + values: [ + '"c2cs"', + '"dlig"', + '"kern"', + '"liga"', + '"lnum"', + '"onum"', + '"smcp"', + '"swsh"', + '"tnum"', + 'normal', + 'off', + 'on' + ] + }, + '-webkit-hyphens': { + values: ['auto', 'manual', 'none'] + }, + '-webkit-line-break': { + values: ['after-white-space', 'normal'] + }, + '-webkit-margin-bottom-collapse': { + values: ['collapse', 'discard', 'separate'] + }, + '-webkit-margin-collapse': { + values: ['collapse', 'discard', 'separate'] + }, + '-webkit-margin-start': { + values: ['auto'] + }, + '-webkit-margin-top-collapse': { + values: ['collapse', 'discard', 'separate'] + }, + '-webkit-mask-clip': {}, + '-webkit-mask-image': { + values: ['none', 'url()'] + }, + '-webkit-mask-origin': {}, + '-webkit-mask-repeat': {}, + '-webkit-mask-size': { + values: ['auto', 'contain', 'cover'] + }, + '-webkit-nbsp-mode': { + values: ['normal', 'space'] + }, + '-webkit-overflow-scrolling': { + values: ['auto', 'touch'] + }, + '-webkit-padding-start': {}, + '-webkit-perspective': { + values: ['none'] + }, + '-webkit-perspective-origin': {}, + '-webkit-region-fragment': { + values: ['auto', 'break'] + }, + '-webkit-tap-highlight-color': {}, + '-webkit-text-fill-color': {}, + '-webkit-text-size-adjust': { + values: ['auto', 'none'] + }, + '-webkit-text-stroke': {}, + '-webkit-text-stroke-color': {}, + '-webkit-text-stroke-width': {}, + '-webkit-touch-callout': { + values: ['none'] + }, + '-webkit-transform': { + values: [ + 'matrix()', + 'matrix3d()', + 'none', + 'perspective()', + 'rotate()', + 'rotate3d()', + "rotateX('angle')", + "rotateY('angle')", + "rotateZ('angle')", + 'scale()', + 'scale3d()', + 'scaleX()', + 'scaleY()', + 'scaleZ()', + 'skew()', + 'skewX()', + 'skewY()', + 'translate()', + 'translate3d()', + 'translateX()', + 'translateY()', + 'translateZ()' + ] + }, + '-webkit-transform-origin': {}, + '-webkit-transform-origin-x': {}, + '-webkit-transform-origin-y': {}, + '-webkit-transform-origin-z': {}, + '-webkit-transform-style': { + values: ['flat'] + }, + '-webkit-transition': { + values: ['all', 'none'] + }, + '-webkit-transition-delay': {}, + '-webkit-transition-duration': {}, + '-webkit-transition-property': { + values: ['all', 'none'] + }, + '-webkit-transition-timing-function': {}, + '-webkit-user-drag': { + values: ['auto', 'element', 'none'] + }, + '-webkit-user-modify': { + values: ['read-only', 'read-write', 'read-write-plaintext-only'] + }, + '-webkit-user-select': { + values: ['auto', 'none', 'text'] + }, + 'widows': {}, + 'width': { + values: ['auto', 'fit-content', 'max-content', 'min-content'] + }, + 'will-change': { + values: ['auto', 'contents', 'scroll-position'] + }, + 'word-break': { + values: ['break-all', 'keep-all', 'normal'] + }, + 'word-spacing': { + values: ['normal'] + }, + 'word-wrap': { + values: ['break-word', 'normal'] + }, + 'writing-mode': { + values: [ + 'horizontal-tb', + 'sideways-lr', + 'sideways-rl', + 'vertical-lr', + 'vertical-rl' + ] + }, + 'z-index': { + values: ['auto'] + }, + 'zoom': { + values: ['normal'] + }, + '-ms-ime-align': { + values: ['auto', 'after'] + }, + '-moz-binding': {}, + '-moz-context-properties': {}, + '-moz-float-edge': { + values: ['border-box', 'content-box', 'margin-box', 'padding-box'] + }, + '-moz-force-broken-image-icon': { + values: ['0', '1'] + }, + '-moz-image-region': {}, + '-moz-orient': { + values: ['inline', 'block', 'horizontal', 'vertical'] + }, + '-moz-outline-radius': {}, + '-moz-outline-radius-bottomleft': {}, + '-moz-outline-radius-bottomright': {}, + '-moz-outline-radius-topleft': {}, + '-moz-outline-radius-topright': {}, + '-moz-stack-sizing': { + values: ['ignore', 'stretch-to-fit'] + }, + '-moz-text-blink': { + values: ['none', 'blink'] + }, + '-moz-user-input': { + values: ['auto', 'none', 'enabled', 'disabled'] + }, + '-moz-user-modify': { + values: ['read-only', 'read-write', 'write-only'] + }, + '-moz-window-dragging': { + values: ['drag', 'no-drag'] + }, + '-moz-window-shadow': { + values: ['default', 'menu', 'tooltip', 'sheet', 'none'] + }, + '-webkit-border-before': {}, + '-webkit-border-before-color': {}, + '-webkit-border-before-style': {}, + '-webkit-border-before-width': {}, + '-webkit-line-clamp': {}, + '-webkit-mask': {}, + '-webkit-mask-attachment': {}, + '-webkit-mask-composite': {}, + '-webkit-mask-position': {}, + '-webkit-mask-position-x': {}, + '-webkit-mask-position-y': {}, + '-webkit-mask-repeat-x': { + values: ['repeat', 'no-repeat', 'space', 'round'] + }, + '-webkit-mask-repeat-y': { + values: ['repeat', 'no-repeat', 'space', 'round'] + }, + 'accent-color': {}, + 'align-tracks': {}, + 'animation-composition': {}, + 'animation-timeline': {}, + 'appearance': {}, + 'aspect-ratio': {}, + 'azimuth': {}, + 'backdrop-filter': {}, + 'border-block': {}, + 'border-block-color': {}, + 'border-block-style': {}, + 'border-block-width': {}, + 'border-end-end-radius': {}, + 'border-end-start-radius': {}, + 'border-inline': {}, + 'border-inline-color': {}, + 'border-inline-style': {}, + 'border-inline-width': {}, + 'border-start-end-radius': {}, + 'border-start-start-radius': {}, + 'box-align': { + values: ['start', 'center', 'end', 'baseline', 'stretch'] + }, + 'box-direction': { + values: ['normal', 'reverse', 'inherit'] + }, + 'box-flex': {}, + 'box-flex-group': {}, + 'box-lines': { + values: ['single', 'multiple'] + }, + 'box-ordinal-group': {}, + 'box-orient': { + values: ['horizontal', 'vertical', 'inline-axis', 'block-axis', 'inherit'] + }, + 'box-pack': { + values: ['start', 'center', 'end', 'justify'] + }, + 'caret': {}, + 'caret-shape': { + values: ['auto', 'bar', 'block', 'underscore'] + }, + 'print-color-adjust': { + values: ['economy', 'exact'] + }, + 'color-scheme': {}, + 'contain-intrinsic-size': {}, + 'contain-intrinsic-block-size': {}, + 'contain-intrinsic-height': {}, + 'contain-intrinsic-inline-size': {}, + 'contain-intrinsic-width': {}, + 'content-visibility': { + values: ['visible', 'auto', 'hidden'] + }, + 'counter-set': {}, + 'font-optical-sizing': { + values: ['auto', 'none'] + }, + 'font-variation-settings': {}, + 'font-smooth': {}, + 'forced-color-adjust': { + values: ['auto', 'none'] + }, + 'gap': {}, + 'hanging-punctuation': {}, + 'hyphenate-character': {}, + 'image-resolution': {}, + 'initial-letter': {}, + 'initial-letter-align': {}, + 'input-security': { + values: ['auto', 'none'] + }, + 'inset': {}, + 'inset-block': {}, + 'inset-block-end': {}, + 'inset-block-start': {}, + 'inset-inline': {}, + 'inset-inline-end': {}, + 'inset-inline-start': {}, + 'justify-tracks': {}, + 'line-clamp': {}, + 'line-height-step': {}, + 'margin-block': {}, + 'margin-inline': {}, + 'margin-trim': { + values: ['none', 'in-flow', 'all'] + }, + 'mask': {}, + 'mask-border': {}, + 'mask-border-mode': { + values: ['luminance', 'alpha'] + }, + 'mask-border-outset': {}, + 'mask-border-repeat': {}, + 'mask-border-slice': {}, + 'mask-border-source': {}, + 'mask-border-width': {}, + 'mask-clip': {}, + 'mask-composite': {}, + 'masonry-auto-flow': {}, + 'math-depth': {}, + 'math-shift': { + values: ['normal', 'compact'] + }, + 'math-style': { + values: ['normal', 'compact'] + }, + 'max-lines': {}, + 'offset': {}, + 'offset-anchor': {}, + 'offset-distance': {}, + 'offset-path': {}, + 'offset-position': {}, + 'offset-rotate': {}, + 'overflow-anchor': { + values: ['auto', 'none'] + }, + 'overflow-block': { + values: ['visible', 'hidden', 'clip', 'scroll', 'auto'] + }, + 'overflow-clip-box': { + values: ['padding-box', 'content-box'] + }, + 'overflow-clip-margin': {}, + 'overflow-inline': { + values: ['visible', 'hidden', 'clip', 'scroll', 'auto'] + }, + 'overscroll-behavior': {}, + 'overscroll-behavior-block': { + values: ['contain', 'none', 'auto'] + }, + 'overscroll-behavior-inline': { + values: ['contain', 'none', 'auto'] + }, + 'overscroll-behavior-x': { + values: ['contain', 'none', 'auto'] + }, + 'overscroll-behavior-y': { + values: ['contain', 'none', 'auto'] + }, + 'padding-block': {}, + 'padding-inline': {}, + 'place-content': {}, + 'place-items': {}, + 'place-self': {}, + 'rotate': {}, + 'row-gap': {}, + 'ruby-merge': { + values: ['separate', 'collapse', 'auto'] + }, + 'scale': {}, + 'scrollbar-color': {}, + 'scrollbar-gutter': {}, + 'scrollbar-width': { + values: ['auto', 'thin', 'none'] + }, + 'scroll-margin': {}, + 'scroll-margin-block': {}, + 'scroll-margin-block-start': {}, + 'scroll-margin-block-end': {}, + 'scroll-margin-bottom': {}, + 'scroll-margin-inline': {}, + 'scroll-margin-inline-start': {}, + 'scroll-margin-inline-end': {}, + 'scroll-margin-left': {}, + 'scroll-margin-right': {}, + 'scroll-margin-top': {}, + 'scroll-padding': {}, + 'scroll-padding-block': {}, + 'scroll-padding-block-start': {}, + 'scroll-padding-block-end': {}, + 'scroll-padding-bottom': {}, + 'scroll-padding-inline': {}, + 'scroll-padding-inline-start': {}, + 'scroll-padding-inline-end': {}, + 'scroll-padding-left': {}, + 'scroll-padding-right': {}, + 'scroll-padding-top': {}, + 'scroll-snap-align': {}, + 'scroll-snap-stop': { + values: ['normal', 'always'] + }, + 'scroll-snap-type-x': { + values: ['none', 'mandatory', 'proximity'] + }, + 'scroll-snap-type-y': { + values: ['none', 'mandatory', 'proximity'] + }, + 'scroll-timeline': {}, + 'scroll-timeline-axis': { + values: ['block', 'inline', 'vertical', 'horizontal'] + }, + 'scroll-timeline-name': {}, + 'text-combine-upright': {}, + 'text-decoration-skip': {}, + 'text-decoration-skip-ink': { + values: ['auto', 'all', 'none'] + }, + 'text-decoration-thickness': {}, + 'text-emphasis': {}, + 'text-emphasis-color': {}, + 'text-emphasis-position': {}, + 'text-emphasis-style': {}, + 'text-size-adjust': {}, + 'text-underline-offset': {}, + 'transform-box': { + values: ['content-box', 'border-box', 'fill-box', 'stroke-box', 'view-box'] + }, + 'translate': {}, + 'white-space': { + values: ['normal', 'pre', 'nowrap', 'pre-wrap', 'pre-line', 'break-spaces'] + }, + 'speak-as': {}, + 'ascent-override': {}, + 'descent-override': {}, + 'font-display': {}, + 'line-gap-override': {}, + 'size-adjust': {}, + 'bleed': {}, + 'marks': {}, + 'syntax': {}, + 'inherits': { + values: ['true', 'false'] + }, + 'initial-value': {}, + 'max-zoom': {}, + 'min-zoom': {}, + 'orientation': { + values: ['auto', 'portrait', 'landscape'] + }, + 'user-zoom': { + values: ['zoom', 'fixed'] + }, + 'viewport-fit': { + values: ['auto', 'contain', 'cover'] + } +}; + +function validate(editor: any, monaco: any) { + const model = editor.getModel(); + const markers = []; + const lineLen = model.getLineCount(); + for (let i = 1; i < lineLen + 1; i++) { + const range = { + startLineNumber: i, + startColumn: 1, + endLineNumber: i, + endColumn: model.getLineLength(i) + 1 + }; + const content: string = model.getValueInRange(range); + if (content !== '') { + // 检测是否有冒号 + if (!content.includes(':')) { + markers.push({ + message: '应为冒号', + severity: monaco.MarkerSeverity.Error, + startLineNumber: range.startLineNumber, + startColumn: range.endColumn, + endLineNumber: range.endLineNumber, + endColumn: range.endColumn + 1 + }); + } + // 检测是否有属性 + else if (/^(.*):\s?;?$/.test(content)) { + markers.push({ + message: '应为属性', + severity: monaco.MarkerSeverity.Error, + startLineNumber: range.startLineNumber, + startColumn: range.endColumn, + endLineNumber: range.endLineNumber, + endColumn: range.endColumn + 1 + }); + } + // 检测是否以分号结尾 + else if (!content.endsWith(';')) { + markers.push({ + message: '缺少分号', + severity: monaco.MarkerSeverity.Error, + startLineNumber: range.startLineNumber, + startColumn: range.endColumn, + endLineNumber: range.endLineNumber, + endColumn: range.endColumn + 1 + }); + } + } + } + monaco.editor.setModelMarkers(model, 'owner', markers); +} + +export default function editorFactory( + containerElement: HTMLElement, + monaco: any, + options: any +) { + if (!monaco.languages.getEncodedLanguageId('amisTheme')) { + // 注册语言 + monaco.languages.register({id: 'amisTheme'}); + // 设置高亮 + monaco.languages.setMonarchTokensProvider('amisTheme', conf); + // 设置提示 + monaco.languages.registerCompletionItemProvider('amisTheme', { + provideCompletionItems: (model: any, position: any) => { + const {lineNumber, column} = position; + // 获取输入前的字符 + const textBeforePointer = model.getValueInRange({ + startLineNumber: lineNumber, + startColumn: 0, + endLineNumber: lineNumber, + endColumn: column + }); + // 如果已经配置了key和value就不给建议了 + if (/(.*):(.*);/.test(textBeforePointer)) { + return {suggestions: []}; + } + const token = /(.*):/.exec(textBeforePointer) || []; + const valueTip = keywords[token[1]]; + let suggestions; + + // 判断是需要提示key还是value + if (!isEmpty(valueTip)) { + suggestions = [ + ...valueTip.values.map((k: string) => ({ + label: k, + kind: monaco.languages.CompletionItemKind.Enum, + insertText: k + ';' + })) + ]; + } else { + suggestions = [ + ...Object.keys(keywords).map(k => ({ + label: k, + kind: monaco.languages.CompletionItemKind.Keyword, + insertText: k + ': ' + })) + ]; + } + + return { + suggestions: suggestions + }; + }, + triggerCharacters: [' '] + }); + } + // const uri = monaco.Uri.parse(options.uri.replace(/:/g, '-')); + // let model: any = null; + // try { + // model = monaco.editor.createModel(options.value, 'amisTheme', uri); + // } catch (error) { + // model = monaco.editor.getModel(uri); + // } + + const editor = monaco.editor.create(containerElement, { + ...options, + 'language': 'amisTheme', + 'autoIndent': true, + 'formatOnType': true, + 'formatOnPaste': true, + 'selectOnLineNumbers': true, + 'scrollBeyondLastLine': false, + 'folding': true, + 'minimap': { + enabled: false + }, + 'scrollbar': { + alwaysConsumeMouseWheel: false + }, + 'bracketPairColorization.enabled': true, + 'automaticLayout': true, + 'lineNumbers': 'off', + 'glyphMargin': false, + 'wordWrap': 'on', + 'lineDecorationsWidth': 0, + 'lineNumbersMinChars': 0 + }); + editor.onDidChangeModelContent(() => { + validate(editor, monaco); + options.onChange && options.onChange(editor.getValue()); + }); + return editor; +} diff --git a/packages/amis-editor/src/tpl/style.tsx b/packages/amis-editor/src/tpl/style.tsx index 71977d866..d95e5c81d 100644 --- a/packages/amis-editor/src/tpl/style.tsx +++ b/packages/amis-editor/src/tpl/style.tsx @@ -427,39 +427,36 @@ export const styleTpl = { // css类名 setSchemaTpl( - 'theme:classNames', - (config: {schema: any; isFormItem: boolean; unsupportStatic?: boolean}) => { - const { - isFormItem = true, - unsupportStatic = false, - schema = [] - } = config || {}; + 'theme:cssCode', + ({ + themeClass = [], + isFormItem, + isLayout + }: { + themeClass?: any[]; + isFormItem?: boolean; + } = {}) => { + if (isFormItem) { + themeClass.push( + ...[ + { + name: 'description', + value: 'description', + className: 'descriptionClassName' + }, + {name: 'label', value: 'label', className: 'labelClassName'} + ] + ); + } return { - title: 'CSS 类名', - body: (isFormItem - ? [ - { - type: 'theme-classname', - label: 'Label', - suffix: 'label', - name: 'labelClassName' - }, - { - type: 'theme-classname', - label: '描述', - suffix: 'description', - name: 'descriptionClassName', - visibleOn: 'this.description' - } - ] - : [ - { - type: 'theme-classname', - label: '外层', - name: 'className' - } - ] - ).concat(schema) + title: '样式源码', + body: [ + { + type: 'theme-cssCode', + label: false, + themeClass + } + ] }; } ); @@ -471,10 +468,11 @@ setSchemaTpl('theme:form-label', () => { body: [ getSchemaTpl('theme:font', { label: '文字', - name: 'css.labelClassName.font' + name: 'themeCss.labelClassName.font:default', + editorThemePath: 'form.item.default.label.body.font' }), getSchemaTpl('theme:paddingAndMargin', { - name: 'css.labelClassName.padding-and-margin' + name: 'themeCss.labelClassName.padding-and-margin:default' }) ] }; @@ -488,10 +486,11 @@ setSchemaTpl('theme:form-description', () => { body: [ getSchemaTpl('theme:font', { label: '文字', - name: 'css.descriptionClassName.font' + name: 'themeCss.descriptionClassName.font:default', + editorThemePath: 'form.item.default.description.body.font' }), getSchemaTpl('theme:paddingAndMargin', { - name: 'css.descriptionClassName.padding-and-margin' + name: 'themeCss.descriptionClassName.padding-and-margin:default' }) ] }; @@ -503,7 +502,7 @@ setSchemaTpl('theme:font', (option: any = {}) => { mode: 'default', type: 'amis-theme-font-editor', label: '文字', - name: `css.className.font`, + name: `themeCss.className.font:default`, needColorCustom: true, ...option }; @@ -515,7 +514,7 @@ setSchemaTpl('theme:colorPicker', (option: any = {}) => { mode: 'default', type: 'amis-theme-color-picker', label: '颜色', - name: `css.className.color`, + name: `themeCss.className.color:default`, needCustom: true, ...option }; @@ -527,7 +526,7 @@ setSchemaTpl('theme:border', (option: any = {}) => { mode: 'default', type: 'amis-theme-border', label: '边框', - name: `css.className.border`, + name: `themeCss.className.border:default`, needColorCustom: true, ...option }; @@ -539,7 +538,7 @@ setSchemaTpl('theme:paddingAndMargin', (option: any = {}) => { mode: 'default', type: 'amis-theme-padding-and-margin', label: '边距', - name: `css.className.padding-and-margin`, + name: `themeCss.className.padding-and-margin:default`, ...option }; }); @@ -550,7 +549,7 @@ setSchemaTpl('theme:radius', (option: any = {}) => { mode: 'default', type: 'amis-theme-radius', label: '圆角', - name: `css.className.radius`, + name: `themeCss.className.radius:default`, ...option }; }); @@ -560,7 +559,7 @@ setSchemaTpl('theme:shadow', (option: any = {}) => { return { type: 'amis-theme-shadow-editor', label: false, - name: `css.className.boxShadow`, + name: `themeCss.className.boxShadow:default`, hasSenior: true, ...option }; @@ -568,15 +567,39 @@ setSchemaTpl('theme:shadow', (option: any = {}) => { setSchemaTpl( 'theme:common', - (exclude: string[] | string, include: string[] | string) => { + (exclude: string[] | string, include: string[]) => { // key统一转换成Kebab case,eg: boxShadow => bos-shadow exclude = ( exclude ? (Array.isArray(exclude) ? exclude : [exclude]) : [] ).map((key: string) => kebabCase(key)); - include = ( - include ? (Array.isArray(include) ? include : [include]) : [] - ).map((key: string) => kebabCase(key)); + const moreStyle = + include?.map(key => + getSchemaTpl(`theme:${key}`, { + name: 'style' + }) + ) || []; + const styles = moreStyle.concat([ + getSchemaTpl('theme:border', { + name: 'style' + }), + getSchemaTpl('theme:radius', { + name: 'style.radius' + }), + getSchemaTpl('theme:paddingAndMargin', { + name: 'style' + }), + getSchemaTpl('theme:colorPicker', { + name: 'style.background', + label: '背景', + needCustom: true, + needGradient: true, + labelMode: 'input' + }), + getSchemaTpl('theme:shadow', { + name: 'style.boxShadow' + }) + ]); return [ { header: '布局', @@ -590,52 +613,19 @@ setSchemaTpl( ].filter(comp => !~exclude.indexOf(comp.type.replace(/^style-/i, ''))) }, { - header: '样式', - key: 'style', + title: '自定义样式', + body: styles + }, + { + title: '样式源码', body: [ - getSchemaTpl('theme:border', { - name: 'style' - }), - getSchemaTpl('theme:radius', { - name: 'style.radius' - }), - getSchemaTpl('theme:paddingAndMargin', { - name: 'style' - }), - getSchemaTpl('theme:colorPicker', { - name: 'style.background', - label: '背景', - needCustom: true, - needGradient: true, - labelMode: 'input' - }), - getSchemaTpl('theme:shadow', { - name: 'style.boxShadow' - }) + { + type: 'theme-cssCode', + label: false, + isLayout: true + } ] - }, - { - header: '圆角', - key: 'radius', - body: [] - }, - { - header: '间距', - key: 'box-model', - body: [] - }, - { - header: '背景', - key: 'background', - body: [] - }, - { - header: '阴影', - key: 'box-shadow', - body: [] } - ].filter(item => - include.length ? ~include.indexOf(item.key) : !~exclude.indexOf(item.key) - ); + ].filter(item => !~exclude.indexOf(item.key || '')); } );