form-driver 0.3.13 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +3 -3
  2. package/dist/m3.css +57 -0
  3. package/dist/m3.js +1 -1
  4. package/es/m3.css +57 -0
  5. package/es/m3.js +2190 -1386
  6. package/lib/m3.css +57 -0
  7. package/lib/m3.js +2188 -1382
  8. package/package.json +13 -9
  9. package/src/framework/Init.tsx +152 -150
  10. package/src/framework/M3.tsx +83 -59
  11. package/src/framework/MUtil.tsx +275 -140
  12. package/src/framework/MViewer.tsx +198 -106
  13. package/src/framework/Schema.ts +100 -87
  14. package/src/types/MSetType.ts +128 -71
  15. package/src/ui/editor/basic/ACheckBox.tsx +98 -50
  16. package/src/ui/editor/complex/ACheckDrag.tsx +356 -0
  17. package/src/ui/editor/complex/AForm.tsx +3 -1
  18. package/src/ui/editor/complex/JsonEditor.tsx +32 -21
  19. package/src/ui/widget/DIYCheckbox.less +36 -0
  20. package/src/ui/widget/DIYCheckbox.tsx +154 -0
  21. package/src/ui/widget/SortDrag.less +32 -0
  22. package/src/ui/widget/SortDrag.tsx +145 -0
  23. package/types/framework/Assembly.d.ts +2 -2
  24. package/types/framework/M3.d.ts +2 -2
  25. package/types/framework/MUtil.d.ts +5 -5
  26. package/types/framework/MViewer.d.ts +1 -1
  27. package/types/framework/Schema.d.ts +13 -11
  28. package/types/framework/Validator.d.ts +1 -1
  29. package/types/types/MDecorationType.d.ts +3 -3
  30. package/types/types/MSetType.d.ts +1 -1
  31. package/types/ui/editor/basic/ACheckBox.d.ts +2 -2
  32. package/types/ui/editor/basic/ARangePicker.d.ts +6 -2
  33. package/types/ui/editor/complex/ACheckDrag.d.ts +28 -0
  34. package/types/ui/editor/complex/JsonEditor.d.ts +1 -1
  35. package/types/ui/widget/DIYCheckbox.d.ts +19 -0
  36. package/types/ui/widget/SegmentEditSwitch.d.ts +1 -1
  37. package/types/ui/widget/SortDrag.d.ts +14 -0
@@ -0,0 +1,145 @@
1
+ import React, { memo, useRef, useEffect, useState, ReactNode } from "react";
2
+ import { draggable } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
3
+ import { dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
4
+ import { monitorForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
5
+ import { Button } from "antd";
6
+ import { HolderOutlined } from "@ant-design/icons";
7
+ import clsx from "clsx";
8
+
9
+ import "./SortDrag.less";
10
+
11
+ type SortDragProps = {
12
+ changeOriginDataSource: (value: any) => void;
13
+ sortList: Array<{
14
+ cpn: ReactNode;
15
+ id: string;
16
+ isChecked: boolean;
17
+ label: string;
18
+ checkedIndex: number;
19
+ }>;
20
+ };
21
+
22
+ const SortDrag: React.FC<SortDragProps> = memo((props) => {
23
+ const { sortList, changeOriginDataSource } = props;
24
+ const [items, setItems] = useState<SortDragProps["sortList"]>([]);
25
+
26
+ // 记录当前拖拽的 item id
27
+ const [draggingId, setDraggingId] = useState<string | null>(null);
28
+ // 记录当前 hover 的 Id
29
+ const [droppingId, setDroppingId] = useState<string | null>(null);
30
+ // refs 用于绑定每个 item 的 DOM
31
+ const itemRefs = useRef<Record<string, HTMLDivElement | null>>({});
32
+ // 修改:为每个 item 单独管理 dragHandle ref
33
+ const dragHandleRefs = useRef<Record<string, HTMLSpanElement | null>>({});
34
+
35
+ // 注册拖拽和 drop target
36
+ useEffect(() => {
37
+ // 清理函数集合
38
+ const cleanups: (() => void)[] = [];
39
+ items.forEach((item, idx) => {
40
+ const el = itemRefs.current[item.id];
41
+ if (!el) return;
42
+ // 注册为 draggable
43
+ cleanups.push(
44
+ draggable({
45
+ element: el,
46
+ dragHandle: dragHandleRefs.current[item.id],
47
+ canDrag: () => item.isChecked,
48
+ getInitialData: () => ({
49
+ id: item.id,
50
+ index: idx,
51
+ label: item.label,
52
+ }),
53
+ onDragStart: () => setDraggingId(item.id),
54
+ onDrop: () => setDraggingId(null),
55
+ })
56
+ );
57
+ // 注册为 drop target
58
+ cleanups.push(
59
+ dropTargetForElements({
60
+ element: el,
61
+ canDrop: () => item.isChecked,
62
+ onDragEnter: (args) => {
63
+ const fromIdx = items.findIndex(
64
+ (i) => i.id === args.source.data.id
65
+ );
66
+ if (fromIdx === idx) return;
67
+ console.log("当前hover元素", item.id);
68
+ console.log("当前拖拽元素", args);
69
+ setDroppingId(item.id);
70
+ },
71
+ onDragLeave: () => {
72
+ setDroppingId(null);
73
+ },
74
+ onDrop: ({ source }) => {
75
+ // console.log("当前拖拽元素", source);
76
+ if (!source) return;
77
+ const fromIdx = items.findIndex((i) => i.id === source.data.id);
78
+ const toIdx = idx;
79
+ if (fromIdx === -1 || fromIdx === toIdx) return;
80
+ const newItems = [...items];
81
+ const [moved] = newItems.splice(fromIdx, 1);
82
+ newItems.splice(toIdx, 0, moved);
83
+ console.log("排序之后的数据", newItems);
84
+ setItems(newItems);
85
+
86
+ changeOriginDataSource(newItems);
87
+ setDroppingId(null);
88
+ },
89
+ })
90
+ );
91
+ });
92
+ // 监听全局拖拽,拖拽结束时清理 draggingId
93
+ const monitorCleanup = monitorForElements({
94
+ onDrop: () => setDraggingId(null),
95
+ });
96
+ cleanups.push(monitorCleanup);
97
+ return () => {
98
+ cleanups.forEach((fn) => fn());
99
+ };
100
+ }, [items]);
101
+
102
+ useEffect(() => {
103
+ const checkedItems = sortList
104
+ .filter((item) => item.isChecked)
105
+ .sort((a, b) => a.checkedIndex - b.checkedIndex);
106
+ const unCheckedItems = sortList.filter((item) => !item.isChecked);
107
+ console.log("DRAG: 排序之后实际展示的数据", {
108
+ sortList,
109
+ checkedItems,
110
+ unCheckedItems,
111
+ });
112
+ setItems([...checkedItems, ...unCheckedItems]);
113
+ }, [sortList]);
114
+
115
+ return (
116
+ <div className="sortDrag">
117
+ {items.map((item, index) => {
118
+ const itemClass = clsx("dragItem", {
119
+ dragging: draggingId === item.id,
120
+ dropping: droppingId === item.id,
121
+ });
122
+
123
+ return (
124
+ <div
125
+ className={itemClass}
126
+ ref={(el) => (itemRefs.current[item.id] = el)}
127
+ key={item.id}
128
+ >
129
+ <div className="dragBody">{item.cpn}</div>
130
+ <div>
131
+ {item.isChecked ? (
132
+ <HolderOutlined
133
+ ref={(el) => (dragHandleRefs.current[item.id] = el)}
134
+ style={{ cursor: "grab", marginLeft: "8px" }}
135
+ />
136
+ ) : null}
137
+ </div>
138
+ </div>
139
+ );
140
+ })}
141
+ </div>
142
+ );
143
+ });
144
+
145
+ export default SortDrag;
@@ -1,8 +1,8 @@
1
1
  import { ClassType } from "react";
2
2
  import { MFieldSchemaAnonymity, MProp, MValidationFail } from './Schema';
3
3
  import { MType, PluginType } from "../types/MType";
4
- export declare type MORPH = "readable" | "editor";
5
- export declare type VIEWER = ClassType<MProp, any, any>;
4
+ export type MORPH = "readable" | "editor";
5
+ export type VIEWER = ClassType<MProp, any, any>;
6
6
  /** 统一的视觉样式 */
7
7
  export interface MTheme {
8
8
  /** 数据未知时展示 */
@@ -1,5 +1,5 @@
1
- import React from 'react';
2
- import { M3Prop } from './MViewer';
1
+ import React from "react";
2
+ import { M3Prop } from "./MViewer";
3
3
  declare const M3: (props: React.PropsWithChildren<M3Prop & {
4
4
  debug?: boolean;
5
5
  }>) => JSX.Element;
@@ -1,8 +1,8 @@
1
1
  /// <reference types="react" />
2
2
  import moment from "moment";
3
- import { M3UISpec, MEnumField, MFieldSchema, MFieldSchemaAnonymity, MValidationFail } from './Schema';
4
- import { JSONSchema6 } from 'json-schema';
5
- export declare type HideMap = {
3
+ import { M3UISpec, MEnumField, MFieldSchema, MFieldSchemaAnonymity, MValidationFail } from "./Schema";
4
+ import { JSONSchema6 } from "json-schema";
5
+ export type HideMap = {
6
6
  [fieldName: string]: boolean;
7
7
  };
8
8
  export declare let MUtil: {
@@ -79,7 +79,7 @@ export declare let MUtil: {
79
79
  * 计算 showIf 的值
80
80
  * @returns Boolean
81
81
  * @param database
82
- * @param objectFields
82
+ * @param objectFields
83
83
  */
84
84
  isShow: (database: any, objectFields: MFieldSchema[], showIfExpr: string) => any;
85
85
  scoreOf: (f: MFieldSchema, database: any) => number;
@@ -174,7 +174,7 @@ export declare let MUtil: {
174
174
  isEquals: (v1: any, v2: any, tolerate: boolean) => boolean;
175
175
  };
176
176
  /** 压缩数组,如果只有一个元素时,它是数据本身,多于一个元素时才是数组 */
177
- export declare type CompactArrayType<T> = T | T[];
177
+ export type CompactArrayType<T> = T | T[];
178
178
  export declare let CompactArray: {
179
179
  indexOf: <T>(ca?: CompactArrayType<T>, d?: T) => -1 | number;
180
180
  };
@@ -1,7 +1,7 @@
1
1
  import React from "react";
2
2
  import { AFTER_CHANGE_CALLBACK, CHANGE_SCHEMA_CALLBACK, MFieldSchema, M3UISpec } from "../framework/Schema";
3
3
  import "./MViewer.less";
4
- import { MORPH } from './Assembly';
4
+ import { MORPH } from "./Assembly";
5
5
  import { PersistantConf } from "./Persistant";
6
6
  export interface MViewerProp {
7
7
  schema: MFieldSchema;
@@ -1,6 +1,6 @@
1
1
  /// <reference types="react" />
2
- import { MORPH, VIEWER, Assembly } from './Assembly';
3
- export declare type ValueConst = string | boolean | number;
2
+ import { MORPH, VIEWER, Assembly } from "./Assembly";
3
+ export type ValueConst = string | boolean | number;
4
4
  export interface MEnumField {
5
5
  /** 选项文案 */
6
6
  label?: string;
@@ -12,24 +12,26 @@ export interface MEnumField {
12
12
  value: ValueConst;
13
13
  exclusive?: string;
14
14
  score?: number;
15
+ remark?: string;
15
16
  children?: MEnumField[];
16
17
  }
17
18
  /** 匿名的MFieldSchema,没有name字段 */
18
- export declare type MFieldSchemaAnonymity = Omit<MFieldSchema, "name">;
19
+ export type MFieldSchemaAnonymity = Omit<MFieldSchema, "name">;
19
20
  /** JS表达式 */
20
- export declare type JSEXPR = string;
21
+ export type JSEXPR = string;
21
22
  /** 如何适配屏幕 */
22
- export declare type SCREEN_ADAPTION =
23
+ export type SCREEN_ADAPTION =
23
24
  /** 强制使用适应大屏的控件 */
24
- "big" |
25
+ "big"
25
26
  /** 强制使用适应小屏的控件 */
26
- "phone";
27
+ | "phone";
27
28
  /** M3 单元的 schema */
28
29
  export interface MFieldSchema {
29
30
  type?: string;
30
31
  name: string;
31
32
  label?: string;
32
33
  labelTip?: string;
34
+ value?: number;
33
35
  /** 编辑器,editor:<viewer名字> 是 viewerFor: {morph:"editor", name:<viewer名字>} 的简写 */
34
36
  editor?: string | VIEWER;
35
37
  /** 查看器,readable:<viewer名字> 是 viewerFor: {morph:"readable", name:<viewer名字>} 的简写 */
@@ -138,7 +140,7 @@ export interface MFieldSchema {
138
140
  showTime?: boolean;
139
141
  };
140
142
  /** 数据格式 */
141
- dataFormat?: "x" | "YYYYMMDD" | /** 用于时间日期类型字段的数据格式,参考moment,例如x表示数据是时间戳,YYYYMMDD表示数据是形如19990130的字符串 */ string;
143
+ dataFormat?: "x" | "YYYYMMDD" /** 用于时间日期类型字段的数据格式,参考moment,例如x表示数据是时间戳,YYYYMMDD表示数据是形如19990130的字符串 */ | string;
142
144
  /**
143
145
  * 例如:
144
146
  * 4.5 与去年同期(2019 年 1 月初-6 月底)相比,您的收入
@@ -249,8 +251,8 @@ export interface MFieldSchema {
249
251
  * final=false表示回调是因为用户操作导致的,不处理的话也不会导致最终数据不一致,因为后续会有final=true的回调。
250
252
  * 对于暂存表单等比较重的操作,应该仅在final=true时触发,以减少调用次数
251
253
  */
252
- export declare type AFTER_CHANGE_CALLBACK = (path: string, v: any, final: boolean) => void;
253
- export declare type CHANGE_SCHEMA_CALLBACK = (v: any) => void;
254
+ export type AFTER_CHANGE_CALLBACK = (path: string, v: any, final: boolean) => void;
255
+ export type CHANGE_SCHEMA_CALLBACK = (v: any) => void;
254
256
  export interface MProp {
255
257
  /** database的数据描述 */
256
258
  schema: MFieldSchemaAnonymity;
@@ -315,4 +317,4 @@ export interface MValidationFail {
315
317
  * pass: 直接通过校验,不再经过下一个校验器了(例如 required=false时,数值是nil, 可以直接pass,否则之后的校验器都要处理nil)
316
318
  * undefined: 表示让下一个校验器再校验
317
319
  */
318
- export declare type MValidationResult = MValidationFail | "pass" | undefined;
320
+ export type MValidationResult = MValidationFail | "pass" | undefined;
@@ -1,6 +1,6 @@
1
1
  import { Assembly } from './Assembly';
2
2
  import { MFieldSchemaAnonymity, MValidationResult } from './Schema';
3
- export declare type VALIDATOR = (a: Assembly, schema: MFieldSchemaAnonymity, value: any, path: string) => MValidationResult;
3
+ export type VALIDATOR = (a: Assembly, schema: MFieldSchemaAnonymity, value: any, path: string) => MValidationResult;
4
4
  /**
5
5
  * 非空校验,数据不能是null/undefined/""/NaN/[]
6
6
  * 要在其他条件之前,以便required=false时短路掉nil的数据,否则后面的校验全都得处理nil
@@ -1,7 +1,7 @@
1
1
  /** HTML装饰物,并不修改数据 */
2
2
  export declare const MDecorationType: {
3
3
  validators: any[];
4
- createDefaultValue: (assembly: import("..").Assembly, s: Pick<import("..").MFieldSchema, "type" | "label" | "labelTip" | "editor" | "readable" | "option" | "enumFields" | "setFields" | "openOption" | "enumOpen" | "setOpen" | "defaultValue" | "props" | "stringLines" | "min" | "max" | "required" | "showIf" | "column" | "toReadable" | "tolerate" | "screenAdaption" | "postfix" | "popoverDesc" | "requiredMessage" | "placeholder" | "objectFields" | "objectLabelFields" | "stringAllowSpaceOnly" | "matrix" | "arrayMember" | "copyFields" | "autoValue" | "arrayAddLabel" | "experience" | "dateRange" | "dataFormat" | "intDiff" | "css" | "removeConfirm" | "mcs" | "uispec" | "hpOrg" | "ossFile" | "decoration" | "remote" | "a" | "style" | "layoutHint" | "options" | "bizData">) => any;
5
- standardValue: (assembly: import("..").Assembly, s: Pick<import("..").MFieldSchema, "type" | "label" | "labelTip" | "editor" | "readable" | "option" | "enumFields" | "setFields" | "openOption" | "enumOpen" | "setOpen" | "defaultValue" | "props" | "stringLines" | "min" | "max" | "required" | "showIf" | "column" | "toReadable" | "tolerate" | "screenAdaption" | "postfix" | "popoverDesc" | "requiredMessage" | "placeholder" | "objectFields" | "objectLabelFields" | "stringAllowSpaceOnly" | "matrix" | "arrayMember" | "copyFields" | "autoValue" | "arrayAddLabel" | "experience" | "dateRange" | "dataFormat" | "intDiff" | "css" | "removeConfirm" | "mcs" | "uispec" | "hpOrg" | "ossFile" | "decoration" | "remote" | "a" | "style" | "layoutHint" | "options" | "bizData">, v: any, strict: boolean) => any;
6
- toReadable: (assembly: import("..").Assembly, s: Pick<import("..").MFieldSchema, "type" | "label" | "labelTip" | "editor" | "readable" | "option" | "enumFields" | "setFields" | "openOption" | "enumOpen" | "setOpen" | "defaultValue" | "props" | "stringLines" | "min" | "max" | "required" | "showIf" | "column" | "toReadable" | "tolerate" | "screenAdaption" | "postfix" | "popoverDesc" | "requiredMessage" | "placeholder" | "objectFields" | "objectLabelFields" | "stringAllowSpaceOnly" | "matrix" | "arrayMember" | "copyFields" | "autoValue" | "arrayAddLabel" | "experience" | "dateRange" | "dataFormat" | "intDiff" | "css" | "removeConfirm" | "mcs" | "uispec" | "hpOrg" | "ossFile" | "decoration" | "remote" | "a" | "style" | "layoutHint" | "options" | "bizData">, vs: any) => string;
4
+ createDefaultValue: (assembly: import("..").Assembly, s: import("..").MFieldSchemaAnonymity) => any;
5
+ standardValue: (assembly: import("..").Assembly, s: import("..").MFieldSchemaAnonymity, v: any, strict: boolean) => any;
6
+ toReadable: (assembly: import("..").Assembly, s: import("..").MFieldSchemaAnonymity, vs: any) => string;
7
7
  };
@@ -1,7 +1,7 @@
1
1
  import { MFieldSchemaAnonymity } from "../framework/Schema";
2
2
  import { MType } from "./MType";
3
3
  export declare const MSetType: MType & {
4
- change: (isAdd: boolean, newValue: any, value: any[], s: MFieldSchemaAnonymity) => any[];
4
+ change: (isAdd: boolean, newValue: any, value: any[], s: MFieldSchemaAnonymity, isNeedSkipHandleOpenValue?: boolean) => any[];
5
5
  openValueIndex: (s: MFieldSchemaAnonymity, vs: any[]) => number;
6
6
  clearOpenValue: (s: MFieldSchemaAnonymity, vs: any[], keepOne: boolean) => any[];
7
7
  };
@@ -1,6 +1,6 @@
1
1
  /// <reference types="react" />
2
- import { BaseViewer } from '../../BaseViewer';
3
- import { MEnumField, MProp, ValueConst } from '../../../framework/Schema';
2
+ import { BaseViewer } from "../../BaseViewer";
3
+ import { MEnumField, MProp, ValueConst } from "../../../framework/Schema";
4
4
  /**
5
5
  * 多选
6
6
  * 示例:{label:"1.13 除爱人/对象之外,目前和您一起生活的家庭成员包括(多选):",name:"familyAccompany",type:"set", option: "父亲 母亲 孩子 爱人/对象的父亲 爱人/对象的母亲 兄弟姐妹"},
@@ -3,8 +3,12 @@ import moment from "moment";
3
3
  import { RangePickerProps } from "antd/lib/date-picker";
4
4
  import { Viewer, ViewerState } from '../../BaseViewer';
5
5
  import { MProp } from "../../../framework/Schema";
6
- export declare type ARangePickerData = [string | null | undefined, string | null | undefined, boolean | null | undefined];
7
- declare type AntData = [moment.Moment | null, moment.Moment | null];
6
+ export type ARangePickerData = [
7
+ string | null | undefined,
8
+ string | null | undefined,
9
+ boolean | null | undefined
10
+ ];
11
+ type AntData = [moment.Moment | null, moment.Moment | null];
8
12
  interface State extends ViewerState {
9
13
  mobileDlg: boolean;
10
14
  }
@@ -0,0 +1,28 @@
1
+ import React from "react";
2
+ import { Viewer } from "../../BaseViewer";
3
+ import { MEnumField, MProp, ValueConst } from "../../../framework/Schema";
4
+ import { ViewerState } from "../../BaseViewer";
5
+ interface ACheckDragState extends ViewerState {
6
+ data: any[];
7
+ }
8
+ /**
9
+ * 多选
10
+ * 示例:{label:"1.13 除爱人/对象之外,目前和您一起生活的家庭成员包括(多选):",name:"familyAccompany",type:"set", option: "父亲 母亲 孩子 爱人/对象的父亲 爱人/对象的母亲 兄弟姐妹"},
11
+ * 值:["孩子", "父亲"]
12
+ */
13
+ export declare class ACheckDrag extends Viewer<ACheckDragState> {
14
+ _enumFields: MEnumField[];
15
+ _enumValues: ValueConst[];
16
+ /** 这个是开放输入框的值 */
17
+ _inputBoxValue: ValueConst;
18
+ timer: any;
19
+ inputRef: React.RefObject<HTMLInputElement>;
20
+ checkFields: MEnumField[];
21
+ checkValues: ValueConst[];
22
+ dataRef: any;
23
+ constructor(p: MProp);
24
+ _createBr(): JSX.Element;
25
+ componentDidUpdate(prevProps: Readonly<MProp>, prevState: Readonly<ACheckDragState>, snapshot?: any): void;
26
+ element(ctx: any): JSX.Element;
27
+ }
28
+ export {};
@@ -1,5 +1,5 @@
1
1
  /// <reference types="react" />
2
- import { BaseViewer } from '../../BaseViewer';
2
+ import { BaseViewer } from "../../BaseViewer";
3
3
  /**
4
4
  * 用文本框编辑json object或者json array
5
5
  */
@@ -0,0 +1,19 @@
1
+ import React, { ReactNode } from "react";
2
+ import { CheckboxProps } from "antd";
3
+ import "./DIYCheckbox.less";
4
+ export interface DIYCheckboxProps extends Omit<CheckboxProps, "children"> {
5
+ /** 自定义选中时的图标 */
6
+ checkedIcon?: ReactNode;
7
+ /** 自定义未选中时的图标 */
8
+ uncheckedIcon?: ReactNode;
9
+ /** 自定义半选中时的图标 */
10
+ indeterminateIcon?: ReactNode;
11
+ /** 子元素内容 */
12
+ children?: ReactNode;
13
+ /** 图标大小 */
14
+ iconSize?: number;
15
+ /** 图标颜色 */
16
+ iconColor?: string;
17
+ }
18
+ declare const DIYCheckbox: React.FC<DIYCheckboxProps>;
19
+ export default DIYCheckbox;
@@ -1,5 +1,5 @@
1
1
  /// <reference types="react" />
2
- export declare type SegmentEditSwitchState =
2
+ export type SegmentEditSwitchState =
3
3
  /** 只有一个可以按的【编辑】按钮 */
4
4
  "readable" |
5
5
  /** 只有一个disable的编辑按钮 */
@@ -0,0 +1,14 @@
1
+ import React, { ReactNode } from "react";
2
+ import "./SortDrag.less";
3
+ type SortDragProps = {
4
+ changeOriginDataSource: (value: any) => void;
5
+ sortList: Array<{
6
+ cpn: ReactNode;
7
+ id: string;
8
+ isChecked: boolean;
9
+ label: string;
10
+ checkedIndex: number;
11
+ }>;
12
+ };
13
+ declare const SortDrag: React.FC<SortDragProps>;
14
+ export default SortDrag;