@tmagic/form 1.2.0-beta.2 → 1.2.0-beta.3

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 (66) hide show
  1. package/dist/tmagic-form.mjs +2081 -2500
  2. package/dist/tmagic-form.mjs.map +1 -1
  3. package/dist/tmagic-form.umd.js +2104 -2524
  4. package/dist/tmagic-form.umd.js.map +1 -1
  5. package/package.json +3 -4
  6. package/src/Form.vue +116 -159
  7. package/src/FormDialog.vue +104 -126
  8. package/src/containers/Col.vue +22 -38
  9. package/src/containers/Container.vue +135 -171
  10. package/src/containers/Fieldset.vue +11 -7
  11. package/src/containers/GroupList.vue +80 -112
  12. package/src/containers/GroupListItem.vue +87 -124
  13. package/src/containers/Panel.vue +26 -49
  14. package/src/containers/Row.vue +18 -40
  15. package/src/containers/Step.vue +36 -48
  16. package/src/containers/Table.vue +437 -478
  17. package/src/containers/Tabs.vue +89 -118
  18. package/src/fields/Cascader.vue +88 -136
  19. package/src/fields/Checkbox.vue +46 -50
  20. package/src/fields/CheckboxGroup.vue +39 -35
  21. package/src/fields/ColorPicker.vue +4 -2
  22. package/src/fields/Date.vue +20 -26
  23. package/src/fields/DateTime.vue +31 -39
  24. package/src/fields/Daterange.vue +3 -2
  25. package/src/fields/DynamicField.vue +63 -77
  26. package/src/fields/Link.vue +65 -86
  27. package/src/fields/Number.vue +32 -34
  28. package/src/fields/RadioGroup.vue +23 -23
  29. package/src/fields/Select.vue +294 -310
  30. package/src/fields/SelectOptionGroups.vue +10 -5
  31. package/src/fields/SelectOptions.vue +4 -2
  32. package/src/fields/Switch.vue +46 -49
  33. package/src/fields/Text.vue +99 -107
  34. package/src/fields/Textarea.vue +32 -44
  35. package/src/fields/Time.vue +19 -30
  36. package/src/index.ts +22 -23
  37. package/src/schema.ts +45 -12
  38. package/types/Form.vue.d.ts +213 -111
  39. package/types/FormDialog.vue.d.ts +812 -155
  40. package/types/containers/Col.vue.d.ts +94 -40
  41. package/types/containers/Container.vue.d.ts +124 -65
  42. package/types/containers/GroupList.vue.d.ts +88 -53
  43. package/types/containers/GroupListItem.vue.d.ts +99 -67
  44. package/types/containers/Panel.vue.d.ts +92 -39
  45. package/types/containers/Row.vue.d.ts +94 -39
  46. package/types/containers/Step.vue.d.ts +104 -42
  47. package/types/containers/Table.vue.d.ts +157 -130
  48. package/types/containers/Tabs.vue.d.ts +95 -50
  49. package/types/fields/Cascader.vue.d.ts +97 -71
  50. package/types/fields/Checkbox.vue.d.ts +97 -56
  51. package/types/fields/CheckboxGroup.vue.d.ts +97 -53
  52. package/types/fields/Date.vue.d.ts +97 -54
  53. package/types/fields/DateTime.vue.d.ts +97 -54
  54. package/types/fields/DynamicField.vue.d.ts +97 -64
  55. package/types/fields/Link.vue.d.ts +62 -657
  56. package/types/fields/Number.vue.d.ts +101 -56
  57. package/types/fields/RadioGroup.vue.d.ts +98 -52
  58. package/types/fields/Select.vue.d.ts +99 -65
  59. package/types/fields/Switch.vue.d.ts +97 -56
  60. package/types/fields/Text.vue.d.ts +100 -57
  61. package/types/fields/Textarea.vue.d.ts +102 -60
  62. package/types/fields/Time.vue.d.ts +97 -55
  63. package/types/index.d.ts +0 -1
  64. package/types/schema.d.ts +37 -9
  65. package/src/utils/fieldProps.ts +0 -39
  66. package/types/utils/fieldProps.d.ts +0 -21
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.2.0-beta.2",
2
+ "version": "1.2.0-beta.3",
3
3
  "name": "@tmagic/form",
4
4
  "sideEffects": [
5
5
  "dist/*",
@@ -35,14 +35,13 @@
35
35
  },
36
36
  "dependencies": {
37
37
  "@element-plus/icons-vue": "^2.0.9",
38
- "@tmagic/utils": "1.2.0-beta.2",
39
- "element-plus": "^2.2.17",
38
+ "@tmagic/design": "1.2.0-beta.3",
39
+ "@tmagic/utils": "1.2.0-beta.3",
40
40
  "lodash-es": "^4.17.21",
41
41
  "sortablejs": "^1.14.0",
42
42
  "vue": "^3.2.37"
43
43
  },
44
44
  "peerDependencies": {
45
- "element-plus": "^2.2.17",
46
45
  "vue": "^3.2.37"
47
46
  },
48
47
  "devDependencies": {
package/src/Form.vue CHANGED
@@ -1,7 +1,7 @@
1
1
  <template>
2
- <el-form
2
+ <TMagicForm
3
3
  class="m-form"
4
- ref="elForm"
4
+ ref="tMagicForm"
5
5
  :model="values"
6
6
  :label-width="labelWidth"
7
7
  :disabled="disabled"
@@ -10,7 +10,7 @@
10
10
  :label-position="labelPosition"
11
11
  >
12
12
  <template v-if="initialized && Array.isArray(config)">
13
- <m-form-container
13
+ <Container
14
14
  v-for="(item, index) in config"
15
15
  :key="item[keyProp] ?? index"
16
16
  :config="item"
@@ -19,175 +19,132 @@
19
19
  :step-active="stepActive"
20
20
  :size="size"
21
21
  @change="changeHandler"
22
- ></m-form-container>
22
+ ></Container>
23
23
  </template>
24
- </el-form>
24
+ </TMagicForm>
25
25
  </template>
26
26
 
27
- <script lang="ts">
28
- import { defineComponent, PropType, provide, reactive, ref, toRaw, watch } from 'vue';
29
- import { cloneDeep, isEqual } from 'lodash-es';
27
+ <script setup lang="ts">
28
+ import { provide, reactive, ref, toRaw, watch } from 'vue';
29
+ import cloneDeep from 'lodash-es/cloneDeep';
30
+ import isEqual from 'lodash-es/isEqual';
30
31
 
32
+ import { TMagicForm } from '@tmagic/design';
33
+
34
+ import Container from './containers/Container.vue';
31
35
  import { getConfig } from './utils/config';
32
36
  import { initValue } from './utils/form';
33
- import { FormConfig, FormState, FormValue } from './schema';
34
-
35
- interface ValidateError {
36
- message: string;
37
- field: string;
38
- }
39
-
40
- export default defineComponent({
41
- name: 'm-form',
42
-
43
- props: {
44
- // 表单初始化值
45
- initValues: {
46
- type: Object,
47
- required: true,
48
- default: () => ({}),
49
- },
50
-
51
- parentValues: {
52
- type: Object,
53
- default: () => ({}),
54
- },
55
-
56
- // 表单配置
57
- config: {
58
- type: Array as PropType<FormConfig>,
59
- required: true,
60
- default: () => [],
61
- },
62
-
63
- labelWidth: {
64
- type: String,
65
- default: () => '200px',
66
- },
67
-
68
- disabled: {
69
- type: Boolean,
70
- default: () => false,
71
- },
72
-
73
- height: {
74
- type: String,
75
- default: () => 'auto',
76
- },
77
-
78
- stepActive: {
79
- type: [String, Number],
80
- default: () => 1,
81
- },
82
-
83
- size: {
84
- type: String as PropType<'small' | 'default' | 'large'>,
85
- },
86
-
87
- inline: {
88
- type: Boolean,
89
- default: false,
90
- },
91
-
92
- labelPosition: {
93
- type: String,
94
- default: 'right',
95
- },
96
-
97
- keyProp: {
98
- type: String,
99
- default: '__key',
100
- },
101
-
102
- popperClass: {
103
- type: String,
104
- },
37
+ import type { FormConfig, FormState, FormValue, ValidateError } from './schema';
38
+
39
+ const props = withDefaults(
40
+ defineProps<{
41
+ config: FormConfig;
42
+ initValues: Object;
43
+ parentValues?: Object;
44
+ labelWidth?: string;
45
+ disabled?: boolean;
46
+ height?: string;
47
+ stepActive?: string | number;
48
+ size?: 'small' | 'default' | 'large';
49
+ inline?: boolean;
50
+ labelPosition?: string;
51
+ keyProp?: string;
52
+ popperClass?: string;
53
+ }>(),
54
+ {
55
+ config: () => [],
56
+ initValues: () => ({}),
57
+ parentValues: () => ({}),
58
+ labelWidth: '200px',
59
+ disabled: false,
60
+ height: 'auto',
61
+ stepActive: 1,
62
+ inline: false,
63
+ labelPosition: 'right',
64
+ keyProp: '__key',
105
65
  },
66
+ );
67
+
68
+ const emit = defineEmits(['change', 'field-input', 'field-change']);
69
+
70
+ const tMagicForm = ref<InstanceType<typeof TMagicForm>>();
71
+ const initialized = ref(false);
72
+ const values = ref<FormValue>({});
73
+ const fields = new Map<string, any>();
74
+
75
+ const requestFuc = getConfig('request') as Function;
76
+
77
+ const formState: FormState = reactive<FormState>({
78
+ keyProp: props.keyProp,
79
+ popperClass: props.popperClass,
80
+ config: props.config,
81
+ initValues: props.initValues,
82
+ parentValues: props.parentValues,
83
+ values,
84
+ $emit: emit as (event: string, ...args: any[]) => void,
85
+ fields,
86
+ setField: (prop: string, field: any) => fields.set(prop, field),
87
+ getField: (prop: string) => fields.get(prop),
88
+ deleteField: (prop: string) => fields.delete(prop),
89
+ post: (options: any) => {
90
+ if (requestFuc) {
91
+ return requestFuc({
92
+ ...options,
93
+ method: 'POST',
94
+ });
95
+ }
96
+ },
97
+ });
106
98
 
107
- emits: ['change', 'field-input', 'field-change'],
108
-
109
- setup(props, { emit }) {
110
- // InstanceType<typeof ElForm>,构建types的时候会出错
111
- const elForm = ref<any>();
112
- const initialized = ref(false);
113
- const values = ref<FormValue>({});
114
- const fields = new Map<string, any>();
99
+ provide('mForm', formState);
115
100
 
116
- const requestFuc = getConfig('request') as Function;
101
+ watch(
102
+ [() => props.config, () => props.initValues],
103
+ ([config], [preConfig]) => {
104
+ if (!isEqual(toRaw(config), toRaw(preConfig))) {
105
+ initialized.value = false;
106
+ }
117
107
 
118
- const formState: FormState = reactive<FormState>({
119
- keyProp: props.keyProp,
120
- popperClass: props.popperClass,
121
- config: props.config,
108
+ initValue(formState, {
122
109
  initValues: props.initValues,
123
- parentValues: props.parentValues,
124
- values,
125
- $emit: emit as (event: string, ...args: any[]) => void,
126
- fields,
127
- setField: (prop: string, field: any) => fields.set(prop, field),
128
- getField: (prop: string) => fields.get(prop),
129
- deleteField: (prop: string) => fields.delete(prop),
130
- post: (options: any) => {
131
- if (requestFuc) {
132
- return requestFuc({
133
- ...options,
134
- method: 'POST',
135
- });
136
- }
137
- },
110
+ config: props.config,
111
+ }).then((value) => {
112
+ values.value = value;
113
+ initialized.value = true;
138
114
  });
139
-
140
- provide('mForm', formState);
141
-
142
- watch(
143
- [() => props.config, () => props.initValues],
144
- ([config], [preConfig]) => {
145
- if (!isEqual(toRaw(config), toRaw(preConfig))) {
146
- initialized.value = false;
147
- }
148
-
149
- initValue(formState, {
150
- initValues: props.initValues,
151
- config: props.config,
152
- }).then((value) => {
153
- values.value = value;
154
- initialized.value = true;
115
+ },
116
+ { immediate: true },
117
+ );
118
+
119
+ const changeHandler = () => {
120
+ emit('change', values.value);
121
+ };
122
+
123
+ defineExpose({
124
+ values,
125
+ formState,
126
+ initialized,
127
+
128
+ changeHandler,
129
+
130
+ resetForm: () => tMagicForm.value?.resetFields(),
131
+
132
+ submitForm: async (native?: boolean): Promise<any> => {
133
+ try {
134
+ await tMagicForm.value?.validate();
135
+ return native ? values.value : cloneDeep(toRaw(values.value));
136
+ } catch (invalidFields: any) {
137
+ const error: string[] = [];
138
+
139
+ Object.entries(invalidFields).forEach(([, ValidateError]) => {
140
+ (ValidateError as ValidateError[]).forEach(({ field, message }) => {
141
+ if (field && message) error.push(`${field} -> ${message}`);
142
+ if (field && !message) error.push(`${field} -> 出现错误`);
143
+ if (!field && message) error.push(`${message}`);
155
144
  });
156
- },
157
- { immediate: true },
158
- );
159
-
160
- return {
161
- initialized,
162
- values,
163
- elForm,
164
-
165
- formState,
166
-
167
- changeHandler: () => {
168
- emit('change', values.value);
169
- },
170
-
171
- resetForm: () => elForm.value?.resetFields(),
172
-
173
- submitForm: async (native?: boolean): Promise<any> => {
174
- try {
175
- await elForm.value?.validate();
176
- return native ? values.value : cloneDeep(toRaw(values.value));
177
- } catch (invalidFields: any) {
178
- const error: string[] = [];
179
-
180
- Object.entries(invalidFields).forEach(([, ValidateError]) => {
181
- (ValidateError as ValidateError[]).forEach(({ field, message }) => {
182
- if (field && message) error.push(`${field} -> ${message}`);
183
- if (field && !message) error.push(`${field} -> 出现错误`);
184
- if (!field && message) error.push(`${message}`);
185
- });
186
- });
187
- throw new Error(error.join('<br>'));
188
- }
189
- },
190
- };
145
+ });
146
+ throw new Error(error.join('<br>'));
147
+ }
191
148
  },
192
149
  });
193
150
  </script>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <el-dialog
2
+ <TMagicDialog
3
3
  v-model="dialogVisible"
4
4
  class="m-form-dialog"
5
5
  top="20px"
@@ -15,7 +15,7 @@
15
15
  class="m-dialog-body"
16
16
  :style="`max-height: ${bodyHeight}; overflow-y: auto; overflow-x: hidden;`"
17
17
  >
18
- <m-form
18
+ <Form
19
19
  v-model="stepActive"
20
20
  ref="form"
21
21
  :size="size"
@@ -24,150 +24,128 @@
24
24
  :parent-values="parentValues"
25
25
  :label-width="labelWidth"
26
26
  @change="changeHandler"
27
- ></m-form>
27
+ ></Form>
28
28
  <slot></slot>
29
29
  </div>
30
30
 
31
31
  <template #footer>
32
- <el-row class="dialog-footer">
33
- <el-col :span="12" style="text-align: left">
32
+ <TMagicRow class="dialog-footer">
33
+ <TMagicCol :span="12" style="text-align: left">
34
34
  <div style="min-height: 1px">
35
35
  <slot name="left"></slot>
36
36
  </div>
37
- </el-col>
38
- <el-col :span="12">
37
+ </TMagicCol>
38
+ <TMagicCol :span="12">
39
39
  <slot name="footer">
40
- <el-button @click="cancel" size="small">取 消</el-button>
41
- <el-button v-if="hasStep && stepActive > 1" type="info" size="small" @click="preStep">上一步</el-button>
42
- <el-button v-if="hasStep && stepCount > stepActive" type="info" size="small" @click="nextStep"
43
- >下一步</el-button
40
+ <TMagicButton @click="cancel" size="small">取 消</TMagicButton>
41
+ <TMagicButton v-if="hasStep && stepActive > 1" type="info" size="small" @click="preStep"
42
+ >上一步</TMagicButton
44
43
  >
45
- <el-button v-else type="primary" size="small" :loading="saveFetch" @click="save">{{
44
+ <TMagicButton v-if="hasStep && stepCount > stepActive" type="info" size="small" @click="nextStep"
45
+ >下一步</TMagicButton
46
+ >
47
+ <TMagicButton v-else type="primary" size="small" :loading="saveFetch" @click="save">{{
46
48
  confirmText
47
- }}</el-button>
49
+ }}</TMagicButton>
48
50
  </slot>
49
- </el-col>
50
- </el-row>
51
+ </TMagicCol>
52
+ </TMagicRow>
51
53
  </template>
52
- </el-dialog>
54
+ </TMagicDialog>
53
55
  </template>
54
56
 
55
- <script lang="ts">
56
- import { computed, defineComponent, PropType, ref } from 'vue';
57
+ <script setup lang="ts">
58
+ import { computed, ref } from 'vue';
59
+
60
+ import { TMagicButton, TMagicCol, TMagicDialog, TMagicRow } from '@tmagic/design';
57
61
 
58
62
  import Form from './Form.vue';
59
63
  import { FormConfig, StepConfig } from './schema';
60
64
 
61
- export default defineComponent({
62
- name: 'm-form-dialog',
63
-
64
- props: {
65
- values: {
66
- type: Object,
67
- default: () => ({}),
68
- },
69
-
70
- parentValues: {
71
- type: Object,
72
- },
73
-
74
- width: [Number, String],
75
-
76
- fullscreen: Boolean,
77
-
78
- title: String,
79
-
80
- config: {
81
- type: Array as PropType<FormConfig>,
82
- required: true,
83
- default: () => [],
84
- },
85
-
86
- labelWidth: [Number, String],
65
+ const props = withDefaults(
66
+ defineProps<{
67
+ config?: FormConfig;
68
+ values?: Object;
69
+ parentValues?: Object;
70
+ width?: string | number;
71
+ labelWidth?: string;
72
+ fullscreen?: boolean;
73
+ title?: string;
74
+ size?: 'small' | 'default' | 'large';
75
+ confirmText?: string;
76
+ }>(),
77
+ {
78
+ config: () => [],
79
+ values: () => ({}),
80
+ confirmText: '确定',
81
+ },
82
+ );
83
+
84
+ const emit = defineEmits(['close', 'submit', 'error', 'change']);
85
+
86
+ const form = ref<InstanceType<typeof Form>>();
87
+ const dialogVisible = ref(false);
88
+ const saveFetch = ref(false);
89
+ const stepActive = ref(1);
90
+ const bodyHeight = ref(`${document.body.clientHeight - 194}px`);
91
+
92
+ const stepCount = computed(() => {
93
+ const { length } = props.config;
94
+ for (let index = 0; index < length; index++) {
95
+ if (props.config[index].type === 'step') {
96
+ return (props.config[index] as StepConfig).items.length;
97
+ }
98
+ }
99
+ return 0;
100
+ });
87
101
 
88
- size: String as PropType<'small' | 'default' | 'large'>,
102
+ const hasStep = computed(() => {
103
+ const { length } = props.config;
104
+ for (let index = 0; index < length; index++) {
105
+ if (props.config[index].type === 'step') {
106
+ return true;
107
+ }
108
+ }
89
109
 
90
- confirmText: {
91
- type: String,
92
- default: '确定',
93
- },
94
- },
110
+ return false;
111
+ });
95
112
 
96
- emits: ['close', 'submit', 'error', 'change'],
97
-
98
- setup(props, { emit }) {
99
- const form = ref<InstanceType<typeof Form>>();
100
- const dialogVisible = ref(false);
101
- const saveFetch = ref(false);
102
- const stepActive = ref(1);
103
- const bodyHeight = ref(`${document.body.clientHeight - 194}px`);
104
-
105
- const stepCount = computed(() => {
106
- const { length } = props.config;
107
- for (let index = 0; index < length; index++) {
108
- if (props.config[index].type === 'step') {
109
- return (props.config[index] as StepConfig).items.length;
110
- }
111
- }
112
- return 0;
113
- });
114
-
115
- const hasStep = computed(() => {
116
- const { length } = props.config;
117
- for (let index = 0; index < length; index++) {
118
- if (props.config[index].type === 'step') {
119
- return true;
120
- }
121
- }
122
-
123
- return false;
124
- });
125
-
126
- const cancel = () => {
127
- dialogVisible.value = false;
128
- };
129
-
130
- const closeHandler = () => {
131
- stepActive.value = 1;
132
- emit('close');
133
- };
134
-
135
- const save = async () => {
136
- try {
137
- const values = await form.value?.submitForm();
138
- emit('submit', values);
139
- } catch (e) {
140
- emit('error', e);
141
- }
142
- };
143
-
144
- const preStep = () => {
145
- stepActive.value -= 1;
146
- };
147
-
148
- const nextStep = () => {
149
- stepActive.value += 1;
150
- };
151
-
152
- const changeHandler = (value: any) => {
153
- emit('change', value);
154
- };
155
-
156
- return {
157
- form,
158
- saveFetch,
159
- stepActive,
160
- dialogVisible,
161
- bodyHeight,
162
- stepCount,
163
- hasStep,
164
- cancel,
165
- closeHandler,
166
- save,
167
- preStep,
168
- nextStep,
169
- changeHandler,
170
- };
171
- },
113
+ const cancel = () => {
114
+ dialogVisible.value = false;
115
+ };
116
+
117
+ const closeHandler = () => {
118
+ stepActive.value = 1;
119
+ emit('close');
120
+ };
121
+
122
+ const save = async () => {
123
+ try {
124
+ const values = await form.value?.submitForm();
125
+ emit('submit', values);
126
+ } catch (e) {
127
+ emit('error', e);
128
+ }
129
+ };
130
+
131
+ const preStep = () => {
132
+ stepActive.value -= 1;
133
+ };
134
+
135
+ const nextStep = () => {
136
+ stepActive.value += 1;
137
+ };
138
+
139
+ const changeHandler = (value: any) => {
140
+ emit('change', value);
141
+ };
142
+
143
+ defineExpose({
144
+ form,
145
+ saveFetch,
146
+ dialogVisible,
147
+
148
+ cancel,
149
+ save,
172
150
  });
173
151
  </script>
@@ -1,6 +1,6 @@
1
1
  <template>
2
- <el-col v-show="display && config.type !== 'hidden'" :span="span">
3
- <m-form-container
2
+ <TMagicCol v-show="display && config.type !== 'hidden'" :span="span">
3
+ <Container
4
4
  :model="model"
5
5
  :config="config"
6
6
  :prop="prop"
@@ -8,49 +8,33 @@
8
8
  :expand-more="expandMore"
9
9
  :size="size"
10
10
  @change="changeHandler"
11
- ></m-form-container>
12
- </el-col>
11
+ ></Container>
12
+ </TMagicCol>
13
13
  </template>
14
14
 
15
- <script lang="ts">
16
- import { computed, defineComponent, inject, PropType } from 'vue';
15
+ <script setup lang="ts">
16
+ import { computed, inject } from 'vue';
17
+
18
+ import { TMagicCol } from '@tmagic/design';
17
19
 
18
20
  import { ChildConfig, FormState } from '../schema';
19
21
  import { display as displayFunction } from '../utils/form';
20
22
 
21
- export default defineComponent({
22
- props: {
23
- labelWidth: String,
24
- expandMore: Boolean,
25
- span: Number,
26
-
27
- model: {
28
- type: Object,
29
- default: () => ({}),
30
- },
31
-
32
- config: {
33
- type: Object as PropType<ChildConfig>,
34
- default: () => ({}),
35
- },
36
-
37
- prop: String,
38
-
39
- size: String,
40
- },
41
-
42
- emits: ['change'],
23
+ import Container from './Container.vue';
43
24
 
44
- setup(props, { emit }) {
45
- const mForm = inject<FormState | undefined>('mForm');
25
+ const props = defineProps<{
26
+ model: any;
27
+ config: ChildConfig;
28
+ labelWidth?: string;
29
+ expandMore?: boolean;
30
+ span?: number;
31
+ size?: string;
32
+ prop?: string;
33
+ }>();
46
34
 
47
- const changeHandler = () => emit('change', props.model);
35
+ const emit = defineEmits(['change']);
48
36
 
49
- return {
50
- mForm,
51
- display: computed(() => displayFunction(mForm, props.config.display, props)),
52
- changeHandler,
53
- };
54
- },
55
- });
37
+ const mForm = inject<FormState | undefined>('mForm');
38
+ const display = computed(() => displayFunction(mForm, props.config.display, props));
39
+ const changeHandler = () => emit('change', props.model);
56
40
  </script>