Procházet zdrojové kódy

Merge branch 'dev' of http://124.70.149.18:10880/lianghj/queenshow into dev-lhj

lianghongjie před 1 rokem
rodič
revize
29c8941df0

+ 5 - 1
src/modules/editor/components/CompUI/basicUI/Text/EditorCustom.ts

@@ -19,6 +19,7 @@ import { EditorConfig } from "@ckeditor/ckeditor5-core";
 export class HeadlessEditor extends DecoupledEditorBase {}
 interface HeadlessConfig extends EditorConfig {
   lineHeight: any;
+  letterSpacing: any;
 }
 HeadlessEditor.builtinPlugins = [
   Essentials,
@@ -59,7 +60,10 @@ HeadlessEditor.defaultConfig = {
     supportAllValues: true,
   },
   lineHeight: {
-    options: [1, 1.5, 2, 2.5, 3],
+    options: [0.5, 1, 1.5, 2, 2.5, 3],
+  },
+  letterSpacing: {
+    options: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
   },
   link: {},
 } as HeadlessConfig;

+ 49 - 132
src/modules/editor/components/CompUI/basicUI/Text/TextToolComp.tsx

@@ -1,19 +1,20 @@
 import {
+  IconStrikethrough,
+  IconTextBold,
   IconTextCenter,
+  IconTextItalic,
   IconTextJustify,
   IconTextLeft,
   IconTextLetterSpacing,
   IconTextLineHeight,
   IconTextRight,
   IconTextSize,
-  IconStrikethrough,
-  IconTextBold,
-  IconTextItalic,
   IconTextUnderline,
 } from "@/assets/icons";
 import { css } from "@linaria/core";
-import { Button, Input, InputNumber, Tooltip } from "ant-design-vue";
+import { Button, InputNumber, Tooltip } from "ant-design-vue";
 
+import { useEditor } from "@/modules/editor";
 import Select from "@queenjs-modules/queditor/components/FormUI/Items/Select";
 import "@simonwep/pickr/dist/themes/nano.min.css";
 import _ from "lodash";
@@ -24,10 +25,10 @@ import {
   onUnmounted,
   reactive,
   ref,
+  toRaw,
   watch,
 } from "vue";
 import { any, bool, func, number, object, string } from "vue-types";
-import { useEditor } from "@/modules/editor";
 interface ColumnItem {
   label?: string;
   component?: ((...args: any[]) => any) | Record<string, any>;
@@ -36,104 +37,7 @@ interface ColumnItem {
   itemProps?: { [name: string]: any };
   changeExtra?: (data: any) => any;
 }
-// export const TextColor = defineComponent({
-//   props: {
-//     value: string().def("#666666"),
-//   },
-//   emits: ["change"],
-//   setup(props, { emit }) {
-//     let picker: any = null;
 
-//     let emitFlagRef = ref(true);
-//     const color = HSLToHex(props.value);
-//     function HSLToHex(hslStr: string): string {
-//       const isHsl = hslStr.indexOf("hsl");
-//       if (isHsl == -1) {
-//         return hslStr;
-//       }
-//       const reg = /(?<=hsl\()(\W|\w)*(?=\))/g;
-//       let hsl: any = hslStr.match(reg);
-//       if (!hsl) {
-//         return hslStr;
-//       }
-//       hsl = hsl[0];
-//       hsl = hsl.split(",");
-//       const [h, s, l] = hsl;
-
-//       const hDecimal = parseInt(l) / 100;
-//       const a = (parseInt(s) * Math.min(hDecimal, 1 - hDecimal)) / 100;
-//       const f = (n: number) => {
-//         const k = (n + parseInt(h) / 30) % 12;
-//         const color = hDecimal - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
-
-//         return Math.round(255 * color)
-//           .toString(16)
-//           .padStart(2, "0");
-//       };
-//       return `#${f(0)}${f(8)}${f(4)}`;
-//     }
-
-//     function initPicker() {
-//       picker = Pickr.create({
-//         el: ".color_picker",
-//         theme: "nano",
-//         default: color,
-//         i18n: {
-//           "btn:save": "确定",
-//         },
-//         components: {
-//           preview: true,
-//           opacity: false,
-//           hue: true,
-//           interaction: {
-//             hex: false,
-//             hsla: false,
-//             rgba: false,
-//             input: true,
-//             save: true,
-//           },
-//         },
-//       });
-//       // picker.on("change", (color: any) => {
-//       //   const hexa = color.toHEXA().toString();
-//       //   console.log("setChange", hexa);
-//       // });
-//       picker.on("save", (color: any) => {
-//         picker.hide();
-//         const hexa = color.toHEXA().toString();
-//         emit("change", hexa);
-//       });
-//     }
-//     watch(
-//       () => props.value,
-//       () => {
-//         const color = HSLToHex(props.value);
-//         const res = picker.setColor(color);
-//         console.log("picker change", color, res);
-//       }
-//     );
-//     onMounted(() => {
-//       initPicker();
-//     });
-//     onUnmounted(() => {
-//       if (picker) {
-//         picker.destroyAndRemove();
-//         picker = null;
-//       }
-//     });
-
-//     return () => (
-//       <div
-//         class={ColorPicker}
-//         onClick={() => {
-//           picker?.show();
-//         }}
-//       >
-//         <div class={"color_picker"} id="color_picker"></div>
-//       </div>
-//     );
-//   },
-// });
 export const TextColor = defineComponent({
   props: {
     value: string().def("#666666"),
@@ -227,12 +131,14 @@ export const AlignComp = defineComponent({
 });
 export const LetterSpacingComp = defineComponent({
   props: {
-    value: string().def("0"),
+    value: any<string | number>().def(0),
   },
   emits: ["change"],
   setup(props, { emit }) {
     return () => {
-      const value = parseFloat(props.value) || 0;
+      const value =
+        typeof props.value === "string" ? parseInt(props.value) : props.value;
+
       return (
         <InputNumber
           prefix={<IconTextLetterSpacing class="text-22px mr-6px" />}
@@ -243,10 +149,10 @@ export const LetterSpacingComp = defineComponent({
           value={value}
           onChange={(value: any) => {
             if (!value) {
-              emit("change", "0em");
+              emit("change", "0px");
               return;
             }
-            emit("change", value / 100 + "em");
+            emit("change", value + "px");
           }}
         />
       );
@@ -256,11 +162,13 @@ export const LetterSpacingComp = defineComponent({
 
 export const LineHeightComp = defineComponent({
   props: {
-    value: number().def(1.5),
+    value: any<string | number>().def(1.5),
   },
   emits: ["change"],
   setup(props, { emit }) {
     return () => {
+      const value =
+        typeof props.value === "string" ? parseFloat(props.value) : props.value;
       return (
         <InputNumber
           prefix={<IconTextLineHeight class="text-22px mr-6px" />}
@@ -268,7 +176,7 @@ export const LineHeightComp = defineComponent({
           min={0.5}
           max={3}
           step={0.5}
-          value={props.value || 1.5}
+          value={value || 1.5}
           onChange={(value: any) => {
             if (!value) {
               emit("change", 1.5);
@@ -282,9 +190,6 @@ export const LineHeightComp = defineComponent({
   },
 });
 export const FontStyleWapper = defineComponent({
-  props: {
-    editor: any(),
-  },
   emits: ["change"],
   setup(props, { emit }) {
     const fontStyleColumns = [
@@ -322,11 +227,10 @@ export const FontStyleWapper = defineComponent({
               column={{
                 label: e.label,
                 dataIndex: e.dataIndex,
-                component: (props) => (
-                  <FontStyleComp icon={e.icon} {...props} />
-                ),
+                component: (props) => {
+                  return <FontStyleComp icon={e.icon} {...props} />;
+                },
               }}
-              editor={props.editor}
               onChange={changeVal}
             />
           );
@@ -342,17 +246,15 @@ export const FontStyleComp = defineComponent({
   },
   emits: ["change"],
   setup(props, { emit }) {
-    const triggerStyle = () => {
-      emit("change", !props.value);
-    };
     return () => {
-      console.log(props.value);
       return (
         <Button
           type="text"
           class={props.value ? currStyle : null}
           icon={props.icon}
-          onClick={triggerStyle}
+          onClick={() => {
+            emit("change", !props.value);
+          }}
         ></Button>
       );
     };
@@ -387,7 +289,7 @@ export const FontFamily = defineComponent({
 });
 export const FontSize = defineComponent({
   props: {
-    value: string().def("12px"),
+    value: any().def("12px"),
   },
   emits: ["change"],
   setup(props, { emit }) {
@@ -435,29 +337,41 @@ export const TextToolItem = defineComponent({
   props: {
     column: object<ColumnItem>(),
     index: number(),
-    editor: any(),
     onChange: func(),
   },
   setup(props) {
     const state = reactive({
       value: undefined,
     });
+
+    const { controls } = useEditor();
+    let editor: any = null;
+    watch(
+      () => controls.textEditorCtrl.state.currEditor,
+      () => {
+        editor = toRaw(controls.textEditorCtrl.state.currEditor);
+        initCommands();
+      }
+    );
     function handleValueChange() {
-      const { column, editor } = props;
-      const command = editor ? editor.commands.get(column?.dataIndex) : "";
+      const { column } = props;
+      if (!editor) {
+        return;
+      }
+      const command = editor.commands.get(column?.dataIndex);
       if (command) {
-        console.log("change==>", column?.dataIndex, state.value);
         state.value = command.value;
       }
     }
     const initCommands = () => {
-      const { column, editor } = props;
-      const { controls } = useEditor();
-      const command = editor ? editor.commands.get(column?.dataIndex) : "";
-      console.log(column?.dataIndex, controls.textEditor);
+      const { column } = props;
+      if (!editor) {
+        return;
+      }
+      const command = editor.commands.get(column?.dataIndex);
       if (command) {
+        console.log("init", column?.dataIndex, command.value);
         state.value = command.value;
-
         command.on("change:value", handleValueChange);
       }
     };
@@ -465,8 +379,11 @@ export const TextToolItem = defineComponent({
       initCommands();
     });
     onUnmounted(() => {
-      const { column, editor } = props;
-      const command = editor ? editor.commands.get(column?.dataIndex) : "";
+      const { column } = props;
+      if (!editor) {
+        return;
+      }
+      const command = editor.commands.get(column?.dataIndex);
       if (command) {
         command.off("change:value", handleValueChange);
       }

+ 30 - 41
src/modules/editor/components/CompUI/basicUI/Text/TextToolForm.tsx

@@ -2,9 +2,9 @@ import { useEditor } from "@/modules/editor";
 import { DesignComp } from "@/modules/editor/objects/DesignTemp/DesignComp";
 
 import { css } from "@linaria/core";
-import { defineComponent } from "vue";
+import { defineComponent, toRaw, watch } from "vue";
 import { any } from "vue-types";
-
+import { Divider } from "ant-design-vue";
 import {
   AlignComp,
   FontFamily,
@@ -22,33 +22,34 @@ export const TextToolForm = defineComponent({
   setup(props) {
     const { store, actions, controls } = useEditor();
 
-    const toolbarColumns = [
-      // {
-      //   label: "字体颜色",
-      //   dataIndex: "fontColor",
-      //   component: TextColor,
-      // },
-      // {
-      //   label: "链接",
-      //   dataIndex: "link",
-      //   component: (props: any) => (
-      //     <LinkButton icon={<LinkOutlined />} {...props} />
-      //   ),
-      //   changeExtra: (record: any) => {
-      //     record.value = record.value.value;
-      //     return record;
-      //   },
-      //   itemProps: {
-      //     class: "!mx-2px",
-      //   },
-      // },
-    ];
+    // const toolbarColumns = [
+    // {
+    //   label: "字体颜色",
+    //   dataIndex: "fontColor",
+    //   component: TextColor,
+    // },
+    // {
+    //   label: "链接",
+    //   dataIndex: "link",
+    //   component: (props: any) => (
+    //     <LinkButton icon={<LinkOutlined />} {...props} />
+    //   ),
+    //   changeExtra: (record: any) => {
+    //     record.value = record.value.value;
+    //     return record;
+    //   },
+    //   itemProps: {
+    //     class: "!mx-2px",
+    //   },
+    // },
+    // ];
 
     const changeVal = (e: { dataIndex: string; value: any }) => {
-      const editor = controls.textEditor;
+      let editor = controls.textEditorCtrl.state.currEditor;
       if (!editor) {
         return;
       }
+      editor = toRaw(editor);
       editor.execute(e.dataIndex, e.value);
       console.log("change", e);
       setTimeout(() => {
@@ -59,9 +60,9 @@ export const TextToolForm = defineComponent({
     };
     return () => {
       return (
-        <div id="text_toolbar">
+        <div id="text_toolform">
           <div>文本</div>
-          <div class={"my-18px"}>
+          <div class={"mt-18px"}>
             <div class={formRowItem}>
               <TextToolItem
                 column={{
@@ -71,7 +72,6 @@ export const TextToolForm = defineComponent({
                     class: "w-190px",
                   },
                 }}
-                editor={controls.textEditor}
                 onChange={changeVal}
               />
               <TextToolItem
@@ -83,7 +83,6 @@ export const TextToolForm = defineComponent({
                     class: "!w-full",
                   },
                 }}
-                editor={controls.textEditor}
                 onChange={changeVal}
               />
             </div>
@@ -97,7 +96,6 @@ export const TextToolForm = defineComponent({
                     class: "!w-full",
                   },
                 }}
-                editor={controls.textEditor}
                 onChange={changeVal}
               />
               <TextToolItem
@@ -109,34 +107,25 @@ export const TextToolForm = defineComponent({
                     class: "!w-full",
                   },
                 }}
-                editor={controls.textEditor}
                 onChange={changeVal}
               />
             </div>
             <div class={formRowItem}>
-              <FontStyleWapper
-                editor={controls.textEditor}
-                onChange={changeVal}
-              />
+              <FontStyleWapper onChange={changeVal} />
               <TextToolItem
                 column={{
                   label: "",
                   dataIndex: "alignment",
                   component: AlignComp,
                 }}
-                editor={controls.textEditor}
                 onChange={changeVal}
               />
             </div>
           </div>
-
-          {/* <TextToolUI
-            editor={controls.textEditor}
-            columns={toolbarColumns}
-            onChange={changeVal}
-          /> */}
+          <Divider class={"!my-18px"} />
           <div>填充</div>
           <div>描边</div>
+          <Divider class={"!my-18px"} />
         </div>
       );
     };

+ 0 - 164
src/modules/editor/components/CompUI/basicUI/Text/TextToolUI.tsx

@@ -1,164 +0,0 @@
-import { css } from "@linaria/core";
-import { Tooltip } from "ant-design-vue";
-import { defineComponent, reactive, onMounted, onUnmounted } from "vue";
-import { any, array, func, number, object } from "vue-types";
-
-export interface ColumnItem {
-  label?: string;
-  component?: ((...args: any[]) => any) | Record<string, any>;
-  dataIndex?: string;
-  props?: { [name: string]: any };
-  itemProps?: { [name: string]: any };
-  changeExtra?: (data: any) => any;
-}
-
-export default defineComponent({
-  props: {
-    columns: array<ColumnItem>().isRequired,
-    editor: any(),
-    data: any(),
-    onChange: func(),
-  },
-  setup(props) {
-    return () => <FormUI {...props} />;
-  },
-});
-
-const FormUI = (props: {
-  columns: ColumnItem[];
-  editor: any;
-  onChange?: (...arg: any) => void;
-}) => {
-  const { columns, ...restProps } = props;
-  return (
-    <>
-      {columns?.map((column: ColumnItem, index: number) => {
-        if (!column.dataIndex) {
-          return renderUI({ props: restProps, column, index });
-        }
-        return <RenderFormItem column={column} index={index} {...restProps} />;
-      })}
-    </>
-  );
-};
-
-const renderUI = ({ props, column, index }: any) => {
-  const component = column.component;
-  if (component instanceof Function) {
-    const params: any = {
-      ...props,
-      column,
-      key: index,
-      children: FormUI({ ...props, columns: column.children }),
-    };
-    return component(params);
-  } else {
-    return (
-      <component {...props} column={column} key={index}>
-        <FormUI {...props} columns={column.children} />
-      </component>
-    );
-  }
-};
-
-export const RenderFormItem = defineComponent({
-  props: {
-    column: object<ColumnItem>(),
-    index: number(),
-    editor: any(),
-    onChange: func(),
-    onChangeEnd: func(),
-  },
-  setup(props) {
-    const state = reactive({
-      value: undefined,
-    });
-    function handleValueChange() {
-      const { column, editor } = props;
-      const command = editor ? editor.commands.get(column?.dataIndex) : "";
-      if (command) {
-        console.log("change==>", column?.dataIndex, state.value);
-        state.value = command.value;
-      }
-    }
-    const initCommands = () => {
-      const { column, editor } = props;
-      const command = editor ? editor.commands.get(column?.dataIndex) : "";
-      if (command) {
-        state.value = command.value;
-
-        command.on("change:value", handleValueChange);
-      }
-    };
-    onMounted(() => {
-      initCommands();
-    });
-    onUnmounted(() => {
-      const { column, editor } = props;
-      const command = editor ? editor.commands.get(column?.dataIndex) : "";
-      if (command) {
-        command.off("change:value", handleValueChange);
-      }
-    });
-
-    const changeVal = (value: any, ...args: any[]) => {
-      const { column } = props;
-      let params = {
-        dataIndex: column?.dataIndex,
-        value: { value },
-        ...args,
-      };
-      if (column?.changeExtra) params = column.changeExtra?.(params);
-      props.onChange?.(params);
-      return params;
-    };
-
-    const changeValEnd = (value: any, ...args: any[]) => {
-      const params = changeVal(value, ...args);
-      props.onChangeEnd?.(params);
-    };
-
-    const component = props.column?.component || number;
-    return () => {
-      const { column, index } = props;
-      return (
-        <div
-          key={index}
-          class={formItemStyles}
-          {...column?.itemProps}
-          onClick={(e) => e.stopPropagation()}
-        >
-          {column?.label ? (
-            <Tooltip title={column.label} placement="top">
-              <component
-                value={state.value}
-                {...column.props}
-                onChange={changeVal}
-                onChangeEnd={changeValEnd}
-              />
-            </Tooltip>
-          ) : (
-            <component
-              value={state.value}
-              {...column?.props}
-              onChange={changeVal}
-              onChangeEnd={changeValEnd}
-            />
-          )}
-        </div>
-      );
-    };
-  },
-});
-
-const formItemStyles = css`
-  height: 100%;
-  margin: 0 6px;
-  &.disabled {
-    cursor: not-allowed;
-  }
-`;
-
-export function useFormColumns(columns: ColumnItem[]) {
-  return columns;
-}

+ 4 - 9
src/modules/editor/components/CompUI/basicUI/Text/ckeditor-letter-spacing/LetterSpacingCommand.ts

@@ -14,10 +14,10 @@ export default class LetterSpacingCommand extends Command {
     this.value =
       this.isEnabled && firstBlock?.hasAttribute(Letter_Spacing)
         ? firstBlock.getAttribute(Letter_Spacing)
-        : "1";
+        : "0";
   }
 
-  execute(options: any) {
+  execute(options = {} as any) {
     const editor = this.editor;
     const model = editor.model;
     const doc = model.document;
@@ -34,13 +34,8 @@ export default class LetterSpacingCommand extends Command {
       const currentLetterSpacing = blocks[0].getAttribute(Letter_Spacing);
 
       const removeLetterSpacing =
-        currentLetterSpacing === value || typeof value === "undefined";
-
-      console.log(
-        value,
-        currentLetterSpacing === value,
-        typeof value === "undefined"
-      );
+        /* isDefault( value ) ||  */ currentLetterSpacing === value ||
+        typeof value === "undefined";
 
       if (removeLetterSpacing) {
         removeLetterSpacingFromSelection(blocks, writer);

+ 14 - 11
src/modules/editor/components/CompUI/basicUI/Text/ckeditor-letter-spacing/LetterSpacingEditing.ts

@@ -1,11 +1,15 @@
 import Plugin from "@ckeditor/ckeditor5-core/src/plugin";
-// import { isSupported, buildDefinition } from "./utils";
+import { isSupported, buildDefinition } from "./utils";
 import LetterSpacingCommand from "./LetterSpacingCommand";
 import HeadlessEditor from "../EditorCustom";
 
 export default class LetterSpacingEditing extends Plugin {
   constructor(editor: HeadlessEditor) {
     super(editor);
+
+    editor.config.define("letterSpacing", {
+      options: [0, 1, 2, 3, 4],
+    });
   }
 
   /**
@@ -14,22 +18,21 @@ export default class LetterSpacingEditing extends Plugin {
   init() {
     const editor = this.editor;
     const schema = editor.model.schema;
-
-    // const enabledOptions = editor.config
-    //   .get("lineHeight.options")
-    //   .map((option:any) => String(option))
-    //   .filter(isSupported); // filter
+    const config: any = editor.config?.get("letterSpacing.options");
+    const enabledOptions: any =
+      config &&
+      config?.map((option: any) => String(option)).filter(isSupported); // filter
 
     schema.extend("$block", { allowAttributes: "letterSpacing" });
     editor.model.schema.setAttributeProperties("letterSpacing", {
       isFormatting: true,
     });
 
-    // const definition = buildDefinition(
-    //   enabledOptions /* .filter( option => !isDefault( option ) ) */
-    // );
-
-    // editor.conversion.attributeToAttribute(definition);
+    const definition = buildDefinition(
+      enabledOptions /* .filter( option => !isDefault( option ) ) */
+    );
+    console.log(definition);
+    editor.conversion.attributeToAttribute(definition);
 
     editor.commands.add("letterSpacing", new LetterSpacingCommand(editor));
   }

+ 112 - 0
src/modules/editor/components/CompUI/basicUI/Text/ckeditor-letter-spacing/LetterSpacingUI.ts

@@ -0,0 +1,112 @@
+// import Plugin from "@ckeditor/ckeditor5-core/src/plugin";
+// import Model from "@ckeditor/ckeditor5-ui/src/model";
+// import Collection from "@ckeditor/ckeditor5-utils/src/collection";
+
+// import {
+//   createDropdown,
+//   addListToDropdown,
+// } from "@ckeditor/ckeditor5-ui/src/dropdown/utils";
+
+// import { isSupported, normalizeOptions, optionsKey } from "./utils";
+
+// export default class LetterSpacingUI extends Plugin {
+//   init() {
+//     const editor = this.editor;
+//     const t = editor.t;
+
+//     const options = this._getLocalizedOptions();
+
+//     const command = editor.commands.get("lineHeight");
+
+//     // Register UI component.
+//     editor.ui.componentFactory.add("lineHeight", (locale) => {
+//       const dropdownView = createDropdown(locale);
+//       addListToDropdown(dropdownView, _prepareListOptions(options, command));
+
+//       // Create dropdown model.
+//       dropdownView.buttonView.set({
+//         // label: 'Zeilenhöhe',
+//         label: t("Line Height"),
+//         icon:
+//           editor.config.get("lineHeight.icon") ||
+//           '<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"  width="24" height="24" viewBox="0 0 24 24"><path fill="#000000" d="M10,13H22V11H10M10,19H22V17H10M10,7H22V5H10M6,7H8.5L5,3.5L1.5,7H4V17H1.5L5,20.5L8.5,17H6V7Z" /></svg>',
+//         tooltip: true,
+//       });
+
+//       dropdownView.extendTemplate({
+//         attributes: {
+//           class: ["p0thi-ckeditor5-lineHeight-dropdown"],
+//         },
+//       });
+
+//       dropdownView.bind("isEnabled").to(command);
+
+//       // Execute command when an item from the dropdown is selected.
+//       this.listenTo(dropdownView, "execute", (evt) => {
+//         editor.execute(evt.source.commandName, {
+//           value: evt.source.commandParam,
+//         });
+//         editor.editing.view.focus();
+//       });
+
+//       return dropdownView;
+//     });
+//   }
+
+//   _getLocalizedOptions() {
+//     const editor = this.editor;
+//     const t = editor.t;
+
+//     const localizedTitles = {
+//       // Default: 'Standard'
+//       Default: t("Default"),
+//     };
+
+//     const options = normalizeOptions(
+//       editor.config
+//         .get("lineHeight.options")
+//         .filter((option) => isSupported(option))
+//     );
+
+//     return options.map((option: any) => {
+//       const title = localizedTitles[option.title];
+
+//       if (title && title != option.title) {
+//         // Clone the option to avoid altering the original `namedPresets` from `./utils.js`.
+//         option = Object.assign({}, option, { title });
+//       }
+
+//       return option;
+//     });
+//   }
+// }
+
+// function _prepareListOptions(options: optionsKey, command: any) {
+//   const itemDefinitions = new Collection();
+
+//   for (const option of options) {
+//     const def = {
+//       type: "button",
+//       model: new Model({
+//         commandName: "lineHeight",
+//         commandParam: option.model,
+//         label: option.title,
+//         class: "p0thi-ckeditor5-lineHeight-dropdown",
+//         withText: true,
+//       }),
+//     };
+
+//     if (option.view && option.view.classes) {
+//       def.model.set("class", `${def.model.class} ${option.view.classes}`);
+//     }
+
+//     def.model.bind("isOn").to(command, "value", (value) => {
+//       const newValue = value ? parseFloat(value) : value;
+//       return newValue === option.model;
+//     });
+
+//     itemDefinitions.add(def);
+//   }
+
+//   return itemDefinitions;
+// }

+ 66 - 0
src/modules/editor/components/CompUI/basicUI/Text/ckeditor-letter-spacing/utils.ts

@@ -0,0 +1,66 @@
+export function isSupported(option: any) {
+  // return supportedOptions.includes( option );
+  return /^\d(.\d+)?$/gm.test(String(option));
+}
+export type optionsKey = Record<string, any>;
+export function buildDefinition(options: any) {
+  const definition = {
+    model: {
+      key: "letterSpacing",
+      values: options.slice(),
+    },
+    view: {} as optionsKey,
+  };
+
+  for (const option of options) {
+    definition.view[option] = {
+      key: "style",
+      value: {
+        "letter-spacing": option,
+      },
+    };
+  }
+
+  return definition;
+}
+export function normalizeOptions(configuredOptions: any) {
+  return configuredOptions
+    .map(optionDefinition)
+    .filter((option: any) => !!option);
+}
+function optionDefinition(option: any) {
+  if (typeof option === "object") {
+    return option;
+  }
+
+  if (option === "default") {
+    return {
+      model: undefined,
+      title: "Default",
+    };
+  }
+
+  const sizePreset = parseFloat(option);
+
+  if (isNaN(sizePreset)) {
+    return;
+  }
+
+  return generatePixelPreset(sizePreset);
+}
+
+function generatePixelPreset(size: any) {
+  const sizeName = String(size);
+
+  return {
+    title: sizeName,
+    model: size,
+    view: {
+      name: "span",
+      styles: {
+        "letter-spacing": sizeName,
+      },
+      priority: 5,
+    },
+  };
+}

+ 3 - 2
src/modules/editor/components/CompUI/basicUI/Text/component2.tsx

@@ -116,7 +116,7 @@ const EditorComp = defineComponent({
       let curr: any = dom;
       do {
         if (
-          curr.id == "toptoolbar" ||
+          curr.id == "text_toolform" ||
           curr.classList.contains("pcr-app") ||
           curr.classList.contains("editor_toolbar_drop") ||
           curr.classList.contains("ant-select-dropdown")
@@ -173,6 +173,7 @@ const EditorComp = defineComponent({
 
       editorRefVal.model.document.on("change:data", () => {
         const value = editorRefVal?.getData();
+
         if (comp.value !== value) {
           actions.updateCompData(comp, "value", value);
           nextTick(() => {
@@ -198,7 +199,7 @@ const EditorComp = defineComponent({
           });
         }
       });
-      controls.textEditor = editorRefVal;
+      controls.textEditorCtrl.setCurrEditor(editorRefVal);
     };
 
     onMounted(() => {

+ 4 - 0
src/modules/editor/components/CompUI/basicUI/View.tsx

@@ -52,6 +52,10 @@ export const View = defineComponent({
         });
       }
 
+      if (comp.anim && comp.anim.transition) {
+          style.transition = "all 1s ease-out";
+      }
+
       return (
         <div
           ref={compRef}

+ 1 - 1
src/modules/editor/components/CompUI/defines/createAttrsForm.tsx

@@ -236,7 +236,7 @@ export function createAttrsForm(valueColumns: ColumnItem[], columnsUI?: any) {
                 <Divider></Divider>
               </>
             ) : null}
-            {columnsUI && <columnsUI component={component}/>}
+            {columnsUI && <columnsUI component={component} />}
             <div>布局</div>
             <FormUI
               data={component}

+ 66 - 0
src/modules/editor/controllers/AnimCtrl/index.ts

@@ -0,0 +1,66 @@
+import { Effect, ModuleControl } from "queenjs";
+import { EditorModule } from "../../module";
+import { DesignComp } from "../../objects/DesignTemp/DesignComp";
+import { Matrix } from "../SelectCtrl/matrix";
+
+
+export class AnimCtrl extends ModuleControl<EditorModule> {
+
+  initEvent() {
+     Effect.value(()=>this.store.shortPage).item((v)=>v.offset, (shortState)=>{
+        console.log("xx")
+
+        let next = shortState.index;
+        if (shortState.offset < 0 ) {
+            next = shortState.index + 1;
+        }
+        if (shortState.offset > 0 ) {
+            next = shortState.index - 1;
+        }
+        this.initAnim();
+        this.startAnim(next);
+
+     }).run();
+  }
+
+  startAnim(index:number) {
+    const childrens = this.helper.findCardAllChildren(index);
+
+    console.log("start anim=>", index, childrens.length);
+
+    childrens.forEach((c)=>{
+        const comp = this.helper.findComp(c) as DesignComp;
+        if (!comp.anim) return;
+        comp.anim.transition = false;
+        comp.layout.transformMatrix = comp.anim.startMatrix;
+        comp.layout.opacity = 0;
+
+        setTimeout(() => {
+            if (comp.anim) {
+                comp.anim.transition = true;
+                comp.layout.transformMatrix = comp.anim.endMatrix;
+                comp.layout.opacity = 1;
+            }
+        }, 100);
+    })
+  }
+  inited = false;
+  initAnim() {
+    if (this.inited) return;
+    this.inited = true;
+
+    let n = this.store.streamCardIds.length;
+    for( let i=0; i<n; i++) {
+        const childrens = this.helper.findCardAllChildren(i);
+        childrens.forEach((c)=>{
+            const comp = this.helper.findComp(c) as DesignComp;
+            const end = comp.layout.transformMatrix || "matrix(1,0,0,1,0,0)";
+            const m = Matrix.createFromMatrixStr(end);
+            m.ty = m.ty - comp.getH();
+            m.tx = m.tx - comp.getW();
+
+            comp.anim = {transition:false, startMatrix: m.getMatrixStr(), endMatrix: end}
+        })
+    }
+  }
+}

+ 15 - 0
src/modules/editor/controllers/TextEditorCtrl/index.ts

@@ -0,0 +1,15 @@
+import { ModuleControl } from "queenjs";
+import { reactive } from "vue";
+import { EditorModule } from "../../module";
+
+export class TextEditorCtrl extends ModuleControl<EditorModule> {
+  state = reactive({
+    currEditor: null as any,
+  });
+  constructor(moduel: EditorModule) {
+    super(moduel);
+  }
+  setCurrEditor(editor: any) {
+    this.state.currEditor = editor;
+  }
+}

+ 5 - 0
src/modules/editor/module/helpers/index.ts

@@ -71,6 +71,11 @@ export const helpers = EditorModule.helper({
     return this.store.designData.compMap["root"];
   },
 
+  findCardAllChildren(index:number) {
+    const cardId = this.store.streamCardIds[index];
+    return this.store.designData.compMap[cardId].children.default || [] as string[];
+  },
+
   getCompCard(compId: string) {
     const paths: DesignComp[] = this.helper.getCompTrees(compId);
     return paths[1];

+ 5 - 1
src/modules/editor/module/index.ts

@@ -22,6 +22,8 @@ import { manualActions } from "./actions/editWithManualHistory";
 import { wxController } from "@/controllers/wxController";
 import { ImageCropperCtrl } from "../controllers/CropperCtrl";
 import { MediaCtrl } from "../controllers/MediaCtrl/indext";
+import { AnimCtrl } from "../controllers/AnimCtrl";
+import { TextEditorCtrl } from "../controllers/TextEditorCtrl";
 
 export class EditorModule extends ModuleRoot {
   config = this.setConfig({
@@ -62,12 +64,14 @@ export class EditorModule extends ModuleRoot {
     selectCtrl: new SelectCtrl(this),
     cropCtrl: new ImageCropperCtrl(this),
     mediaCtrl: new MediaCtrl(this),
-    textEditor: null as any,
+    textEditorCtrl: new TextEditorCtrl(this),
+    animCtrl: new AnimCtrl(this)
   };
   compObjsMap = new Map<string, CompObject>();
 
   onReady() {
     this.actions.init();
+    this.controls.animCtrl.initEvent();
   }
 
   jumpIndexHtml(route = "#/") {

+ 2 - 0
src/modules/editor/objects/DesignTemp/DesignComp.ts

@@ -14,6 +14,8 @@ export class DesignComp {
   layout: Layout = { size: [200, 200] };
   background: Background = {};
   children: Record<string, any> & { default?: string[] } = {};
+  anim?:{startMatrix: string, endMatrix:string, transition: boolean}
+
   constructor(data?: Partial<DesignComp>) {
     if (!data) return;
     if (data instanceof DesignComp) return data;