@tmagic/form 1.0.0 → 1.0.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.
@@ -12,6 +12,7 @@ declare const Tab: DefineComponent<{
12
12
  default: () => {};
13
13
  };
14
14
  prop: StringConstructor;
15
+ name: StringConstructor;
15
16
  size: StringConstructor;
16
17
  }, {
17
18
  mForm: FormState | undefined;
@@ -36,6 +37,7 @@ declare const Tab: DefineComponent<{
36
37
  default: () => {};
37
38
  };
38
39
  prop: StringConstructor;
40
+ name: StringConstructor;
39
41
  size: StringConstructor;
40
42
  }>>, {
41
43
  config: TabConfig;
@@ -0,0 +1,13 @@
1
+ import type { DefineComponent, ComponentOptionsMixin, VNodeProps, AllowedComponentProps, ComponentCustomProps, ExtractPropTypes } from 'vue';
2
+ declare const _sfc_main: DefineComponent<{
3
+ options: {
4
+ type: ArrayConstructor;
5
+ required: true;
6
+ };
7
+ }, {}, unknown, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, Record<string, any>, string, VNodeProps & AllowedComponentProps & ComponentCustomProps, Readonly<ExtractPropTypes<{
8
+ options: {
9
+ type: ArrayConstructor;
10
+ required: true;
11
+ };
12
+ }>>, {}>;
13
+ export default _sfc_main;
@@ -0,0 +1,21 @@
1
+ import type { DefineComponent, ComponentOptionsMixin, VNodeProps, AllowedComponentProps, ComponentCustomProps, ExtractPropTypes } from 'vue';
2
+ declare const _sfc_main: DefineComponent<{
3
+ options: {
4
+ type: ArrayConstructor;
5
+ required: true;
6
+ };
7
+ valueKey: {
8
+ type: StringConstructor;
9
+ required: false;
10
+ };
11
+ }, {}, unknown, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, Record<string, any>, string, VNodeProps & AllowedComponentProps & ComponentCustomProps, Readonly<ExtractPropTypes<{
12
+ options: {
13
+ type: ArrayConstructor;
14
+ required: true;
15
+ };
16
+ valueKey: {
17
+ type: StringConstructor;
18
+ required: false;
19
+ };
20
+ }>>, {}>;
21
+ export default _sfc_main;
@@ -31,6 +31,6 @@ export { default as MSelect } from './fields/Select.vue';
31
31
  export { default as MCascader } from './fields/Cascader.vue';
32
32
  export { default as MDynamicField } from './fields/DynamicField.vue';
33
33
  declare const _default: {
34
- install: (app: App, opt: any) => void;
34
+ install: (app: App<any>, opt: any) => void;
35
35
  };
36
36
  export default _default;
@@ -137,7 +137,14 @@ export interface SelectGroupOption {
137
137
  label: string;
138
138
  /** 是否禁用该选项组 */
139
139
  disabled: boolean;
140
- options: SelectOption[];
140
+ options: {
141
+ /** 选项的标签 */
142
+ label: string | SelectOptionTextFunction;
143
+ /** 选项的值 */
144
+ value: any | SelectOptionValueFunction;
145
+ /** 是否禁用该选项 */
146
+ disabled?: boolean;
147
+ }[];
141
148
  }
142
149
  declare type SelectOptionFunction = (mForm: FormState | undefined, data: {
143
150
  model: any;
@@ -404,6 +411,7 @@ export interface TabPaneConfig {
404
411
  lazy?: boolean;
405
412
  labelWidth?: string;
406
413
  items: FormConfig;
414
+ onTabClick?: (mForm: FormState | undefined, tab: any, data: any) => void;
407
415
  [key: string]: any;
408
416
  }
409
417
  export interface TabConfig extends FormItem, ContainerCommonConfig {
@@ -416,6 +424,7 @@ export interface TabConfig extends FormItem, ContainerCommonConfig {
416
424
  onChange?: (mForm: FormState | undefined, data: any) => void;
417
425
  onTabAdd?: (mForm: FormState | undefined, data: any) => void;
418
426
  onTabRemove?: (mForm: FormState | undefined, tabName: string, data: any) => void;
427
+ onTabClick?: (mForm: FormState | undefined, tab: any, data: any) => void;
419
428
  activeChange?: (mForm: FormState | undefined, tabName: string, data: any) => void;
420
429
  }
421
430
  /**
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.0.0",
2
+ "version": "1.0.3",
3
3
  "name": "@tmagic/form",
4
4
  "sideEffects": [
5
5
  "dist/*",
@@ -22,7 +22,7 @@
22
22
  },
23
23
  "license": "Apache-2.0",
24
24
  "scripts": {
25
- "build": "vite build"
25
+ "build": "vue-tsc --noEmit && vite build"
26
26
  },
27
27
  "engines": {
28
28
  "node": ">=14"
@@ -33,15 +33,15 @@
33
33
  },
34
34
  "dependencies": {
35
35
  "@element-plus/icons": "0.0.11",
36
- "@tmagic/utils": "1.0.0",
37
- "element-plus": "^2.2.0",
36
+ "@tmagic/utils": "1.0.3",
37
+ "element-plus": "^2.2.6",
38
38
  "lodash-es": "^4.17.21",
39
39
  "moment": "^2.29.2",
40
40
  "sortablejs": "^1.14.0",
41
41
  "vue": "^3.2.0"
42
42
  },
43
43
  "peerDependencies": {
44
- "element-plus": "^2.2.0",
44
+ "element-plus": "^2.2.6",
45
45
  "vue": "^3.2.0"
46
46
  },
47
47
  "devDependencies": {
@@ -49,14 +49,13 @@
49
49
  "@types/lodash-es": "^4.17.4",
50
50
  "@types/node": "^15.12.4",
51
51
  "@types/sortablejs": "^1.10.7",
52
- "@vitejs/plugin-vue": "^1.2.3",
53
- "@vitejs/plugin-vue-jsx": "^1.1.6",
52
+ "@vitejs/plugin-vue": "^2.3.3",
54
53
  "@vue/compiler-sfc": "^3.2.0",
55
54
  "@vue/test-utils": "^2.0.0",
56
55
  "sass": "^1.35.1",
57
56
  "typescript": "^4.3.4",
58
- "vite": "^2.3.7",
57
+ "vite": "^2.9.13",
59
58
  "vite-plugin-dts": "^0.9.6",
60
- "vue-tsc": "^0.0.24"
59
+ "vue-tsc": "^0.38.2"
61
60
  }
62
61
  }
@@ -4,25 +4,15 @@
4
4
  class="m-fieldset"
5
5
  :style="show ? 'padding: 15px 15px 0 5px;' : 'border: 0'"
6
6
  >
7
- <el-checkbox
8
- v-if="!show && name"
9
- v-model="model[name].value"
10
- :prop="`${prop}${prop ? '.' : ''}${config.name}.value`"
11
- :true-label="1"
12
- :false-label="0"
13
- @change="change"
14
- ><span v-html="config.legend"></span><span v-if="config.extra" v-html="config.extra" class="m-form-tip"></span
15
- ></el-checkbox>
16
- <legend v-else-if="config.checkbox && name">
7
+ <component v-if="name && config.checkbox" :is="!show ? 'div' : 'legend'">
17
8
  <el-checkbox
18
9
  v-model="model[name].value"
19
10
  :prop="`${prop}${prop ? '.' : ''}${config.name}.value`"
20
11
  :true-label="1"
21
12
  :false-label="0"
22
- @change="change"
23
13
  ><span v-html="config.legend"></span><span v-if="config.extra" v-html="config.extra" class="m-form-tip"></span
24
14
  ></el-checkbox>
25
- </legend>
15
+ </component>
26
16
  <legend v-else>
27
17
  <span v-html="config.legend"></span>
28
18
  <span v-if="config.extra" v-html="config.extra" class="m-form-tip"></span>
@@ -62,77 +52,59 @@
62
52
  </fieldset>
63
53
  </template>
64
54
 
65
- <script lang="ts">
66
- import { computed, defineComponent, inject, PropType } from 'vue';
55
+ <script lang="ts" setup>
56
+ import { computed, inject, watch } from 'vue';
67
57
 
68
58
  import { FieldsetConfig, FormState } from '../schema';
69
59
 
70
- export default defineComponent({
71
- name: 'm-form-fieldset',
72
-
73
- props: {
74
- labelWidth: String,
75
-
76
- model: {
77
- type: Object,
78
- default: () => ({}),
79
- },
80
-
81
- config: {
82
- type: Object as PropType<FieldsetConfig>,
83
- default: () => ({}),
84
- },
85
-
86
- rules: {
87
- type: Object,
88
- default: () => ({}),
89
- },
90
-
91
- prop: {
92
- type: String,
93
- default: () => '',
94
- },
95
-
96
- size: String,
60
+ const props = withDefaults(
61
+ defineProps<{
62
+ labelWidth?: string;
63
+ prop: string;
64
+ size?: string;
65
+ model: Record<string, any>;
66
+ config: FieldsetConfig;
67
+ rules?: any;
68
+ }>(),
69
+ {
70
+ rules: {},
71
+ prop: '',
97
72
  },
73
+ );
98
74
 
99
- emits: ['change'],
75
+ const emit = defineEmits(['change']);
100
76
 
101
- setup(props, { emit }) {
102
- const mForm = inject<FormState | undefined>('mForm');
77
+ const mForm = inject<FormState | undefined>('mForm');
103
78
 
104
- const name = computed(() => props.config.name || '');
79
+ const name = computed(() => props.config.name || '');
105
80
 
106
- const show = computed(() => {
107
- if (props.config.expand && name.value) {
108
- return props.model[name.value]?.value;
109
- }
110
- return true;
111
- });
81
+ const show = computed(() => {
82
+ if (props.config.expand && name.value) {
83
+ return props.model[name.value]?.value;
84
+ }
85
+ return true;
86
+ });
112
87
 
113
- const lWidth = computed(() => {
114
- if (props.config.items) {
115
- return props.config.labelWidth || props.labelWidth;
116
- }
117
- return props.config.labelWidth || props.labelWidth || (props.config.text ? null : '0');
118
- });
88
+ const lWidth = computed(() => {
89
+ if (props.config.items) {
90
+ return props.config.labelWidth || props.labelWidth;
91
+ }
92
+ return props.config.labelWidth || props.labelWidth || (props.config.text ? null : '0');
93
+ });
119
94
 
120
- const change = () => {
121
- emit('change', props.model);
122
- };
95
+ const change = () => {
96
+ emit('change', props.model);
97
+ };
123
98
 
124
- const key = (item: any, index: number) => item[mForm?.keyProp || '__key'] ?? index;
99
+ const key = (item: any, index: number) => item[mForm?.keyProp || '__key'] ?? index;
125
100
 
126
- return {
127
- show,
128
- name,
129
- mForm,
130
- lWidth,
131
- key,
132
- change,
133
- };
134
- },
135
- });
101
+ if (props.config.checkbox && name.value) {
102
+ watch(
103
+ () => props.model[name.value]?.value,
104
+ () => {
105
+ console.log(props.model);
106
+ emit('change', props.model);
107
+ },
108
+ );
109
+ }
136
110
  </script>
137
-
138
- <style lang="scss"></style>
@@ -80,6 +80,8 @@ export default defineComponent({
80
80
  return props.config.addable(mForm, {
81
81
  model: props.model[props.name],
82
82
  formValue: mForm?.values,
83
+ prop: props.prop,
84
+ config: props.config,
83
85
  });
84
86
  }
85
87
 
@@ -101,6 +103,8 @@ export default defineComponent({
101
103
  initValues = await props.config.defaultAdd(mForm, {
102
104
  model: props.model[props.name],
103
105
  formValue: mForm?.values,
106
+ prop: props.prop,
107
+ config: props.config,
104
108
  });
105
109
  } else if (props.config.defaultAdd) {
106
110
  initValues = props.config.defaultAdd;
@@ -154,7 +154,7 @@
154
154
  /* eslint-disable no-param-reassign */
155
155
  import { computed, defineComponent, inject, onMounted, PropType, ref, toRefs } from 'vue';
156
156
  import { ArrowDown, ArrowUp, Delete, FullScreen, Grid } from '@element-plus/icons';
157
- import { ElMessage, ElTable, ElUpload } from 'element-plus';
157
+ import { ElMessage, ElTable, UploadFile } from 'element-plus';
158
158
  import { cloneDeep } from 'lodash-es';
159
159
  import Sortable, { SortableEvent } from 'sortablejs';
160
160
 
@@ -163,23 +163,6 @@ import { asyncLoadJs, sleep } from '@tmagic/utils';
163
163
  import { ColumnConfig, FormState, SortProp, TableConfig } from '../schema';
164
164
  import { display, initValue } from '../utils/form';
165
165
 
166
- export type UploadStatus = 'ready' | 'uploading' | 'success' | 'fail';
167
-
168
- export interface ElFile extends File {
169
- uid: number;
170
- }
171
-
172
- export type UploadFile = {
173
- name: string;
174
- percentage?: number;
175
- status: UploadStatus;
176
- size: number;
177
- response?: unknown;
178
- uid: number;
179
- url?: string;
180
- raw: ElFile;
181
- };
182
-
183
166
  let loadedAMapJS = false; // 是否加载完js
184
167
  let firstLoadingAMapJS = true; // 否是第一次请求
185
168
 
@@ -241,7 +224,7 @@ export default defineComponent({
241
224
  const mForm = inject<FormState | undefined>('mForm');
242
225
 
243
226
  const elTable = ref<InstanceType<typeof ElTable>>();
244
- const excelBtn = ref<InstanceType<typeof ElUpload>>();
227
+ const excelBtn = ref<any>();
245
228
  const mTable = ref<HTMLDivElement>();
246
229
 
247
230
  const pagesize = ref(10);
@@ -21,7 +21,15 @@
21
21
  v-for="item in tabItems(tab)"
22
22
  :key="item[mForm?.keyProp || '__key']"
23
23
  :config="item"
24
- :model="config.dynamic ? model[config.name || ''][tabIndex] : tab.name ? model[tab.name] : model"
24
+ :model="
25
+ config.dynamic
26
+ ? (name ? model[name] : model)[tabIndex]
27
+ : tab.name
28
+ ? (name ? model[name] : model)[tab.name]
29
+ : name
30
+ ? model[name]
31
+ : model
32
+ "
25
33
  :prop="config.dynamic ? `${prop}${prop ? '.' : ''}${String(tabIndex)}` : prop"
26
34
  :size="size"
27
35
  :label-width="tab.labelWidth || labelWidth"
@@ -34,7 +42,6 @@
34
42
  </template>
35
43
 
36
44
  <script lang="ts">
37
- /* eslint-disable vue/no-mutating-props */
38
45
  import { computed, defineComponent, inject, PropType, ref, watchEffect } from 'vue';
39
46
  import { cloneDeep } from 'lodash-es';
40
47
 
@@ -87,6 +94,8 @@ const Tab = defineComponent({
87
94
 
88
95
  prop: String,
89
96
 
97
+ name: String,
98
+
90
99
  size: String,
91
100
  },
92
101
 
@@ -79,8 +79,9 @@ export default defineComponent({
79
79
  if (typeof body === 'function' && props.model && mForm) {
80
80
  body = body(mForm, {
81
81
  model: props.model,
82
- formValue: null,
82
+ formValue: mForm.values,
83
83
  formValues: mForm.values,
84
+ config: props.config,
84
85
  });
85
86
  }
86
87
  postOptions.data = body;
@@ -8,7 +8,7 @@
8
8
  :disabled="disabled"
9
9
  :format="config.format || 'YYYY-MM-DD HH:mm:ss'"
10
10
  :value-format="config.valueFormat || 'YYYY-MM-DD HH:mm:ss'"
11
- :default-time="config.defaultTime || [new Date(2000, 1, 1, 23, 59, 59)]"
11
+ :default-time="config.defaultTime"
12
12
  @change="changeHandler"
13
13
  ></el-date-picker>
14
14
  </template>
@@ -8,7 +8,7 @@
8
8
  :size="size"
9
9
  :unlink-panels="true"
10
10
  :disabled="disabled"
11
- :default-time="config.defaultTime || [new Date(2000, 1, 1, 23, 59, 59)]"
11
+ :default-time="config.defaultTime"
12
12
  @change="changeHandler"
13
13
  ></el-date-picker>
14
14
  </template>
@@ -19,33 +19,14 @@
19
19
  @change="changeHandler"
20
20
  @visible-change="visibleHandler"
21
21
  >
22
- <template v-if="config.group">
23
- <el-option-group v-for="(group, index) in options" :key="index" :label="group.label" :disabled="group.disabled">
24
- <el-option
25
- v-for="(item, index) in group.options"
26
- :key="index"
27
- :label="item.label"
28
- :value="item.value"
29
- :disabled="item.disabled"
30
- >
31
- </el-option>
32
- </el-option-group>
33
- </template>
34
- <template v-else>
35
- <el-option
36
- v-for="option in options"
37
- :label="option.text"
38
- :value="option.value"
39
- :key="config.valueKey ? option.value[config.valueKey] : option.value"
40
- :disabled="option.disabled"
41
- ></el-option>
42
- </template>
22
+ <template v-if="config.group"><select-option-groups :options="groupOptions"></select-option-groups></template>
23
+ <template v-else><select-options :options="options"></select-options></template>
43
24
  <div v-loading="true" v-if="moreLoadingVisible"></div>
44
25
  </el-select>
45
26
  </template>
46
27
 
47
28
  <script lang="ts">
48
- import { defineComponent, inject, onBeforeMount, onMounted, PropType, ref, watch } from 'vue';
29
+ import { defineComponent, inject, onBeforeMount, onMounted, PropType, Ref, ref, watch } from 'vue';
49
30
  import { ElSelect } from 'element-plus';
50
31
 
51
32
  import { FormState, SelectConfig, SelectGroupOption, SelectOption } from '../schema';
@@ -53,9 +34,14 @@ import { getConfig } from '../utils/config';
53
34
  import fieldProps from '../utils/fieldProps';
54
35
  import { useAddField } from '../utils/useAddField';
55
36
 
37
+ import SelectOptionGroups from './SelectOptionGroups.vue';
38
+ import SelectOptions from './SelectOptions.vue';
39
+
56
40
  export default defineComponent({
57
41
  name: 'm-fields-select',
58
42
 
43
+ components: { SelectOptions, SelectOptionGroups },
44
+
59
45
  props: {
60
46
  ...fieldProps,
61
47
  config: {
@@ -344,7 +330,8 @@ export default defineComponent({
344
330
  select,
345
331
  loading,
346
332
  remote,
347
- options,
333
+ options: options as Ref<SelectOption[]>,
334
+ groupOptions: options as Ref<SelectGroupOption[]>,
348
335
  moreLoadingVisible,
349
336
  popperClass: mForm?.popperClass,
350
337
 
@@ -0,0 +1,20 @@
1
+ <template>
2
+ <el-option-group v-for="(group, index) in options" :key="index" :label="group.label" :disabled="group.disabled">
3
+ <el-option
4
+ v-for="(item, index) in group.options"
5
+ :key="index"
6
+ :label="item.label"
7
+ :value="item.value"
8
+ :disabled="item.disabled"
9
+ >
10
+ </el-option>
11
+ </el-option-group>
12
+ </template>
13
+
14
+ <script lang="ts" setup>
15
+ import { SelectGroupOption } from '../schema';
16
+
17
+ defineProps<{
18
+ options: SelectGroupOption[];
19
+ }>();
20
+ </script>
@@ -0,0 +1,18 @@
1
+ <template>
2
+ <el-option
3
+ v-for="option in options"
4
+ :label="option.text"
5
+ :value="option.value"
6
+ :key="valueKey ? option.value[valueKey] : option.value"
7
+ :disabled="option.disabled"
8
+ ></el-option>
9
+ </template>
10
+
11
+ <script lang="ts" setup>
12
+ import { SelectOption } from '../schema';
13
+
14
+ defineProps<{
15
+ options: SelectOption[];
16
+ valueKey?: string;
17
+ }>();
18
+ </script>
package/src/index.ts CHANGED
@@ -95,7 +95,7 @@ const install = (app: App, opt: any) => {
95
95
  app.component(Form.name, Form);
96
96
  app.component(FormDialog.name, FormDialog);
97
97
  app.component(Container.name, Container);
98
- app.component(Fieldset.name, Fieldset);
98
+ app.component('m-form-fieldset', Fieldset);
99
99
  app.component(GroupList.name, GroupList);
100
100
  app.component(Panel.name, Panel);
101
101
  app.component(Row.name, Row);
package/src/schema.ts CHANGED
@@ -184,7 +184,14 @@ export interface SelectGroupOption {
184
184
  label: string;
185
185
  /** 是否禁用该选项组 */
186
186
  disabled: boolean;
187
- options: SelectOption[];
187
+ options: {
188
+ /** 选项的标签 */
189
+ label: string | SelectOptionTextFunction;
190
+ /** 选项的值 */
191
+ value: any | SelectOptionValueFunction;
192
+ /** 是否禁用该选项 */
193
+ disabled?: boolean;
194
+ }[];
188
195
  }
189
196
 
190
197
  type SelectOptionFunction = (
@@ -508,6 +515,7 @@ export interface TabPaneConfig {
508
515
  lazy?: boolean;
509
516
  labelWidth?: string;
510
517
  items: FormConfig;
518
+ onTabClick?: (mForm: FormState | undefined, tab: any, data: any) => void;
511
519
  [key: string]: any;
512
520
  }
513
521
  export interface TabConfig extends FormItem, ContainerCommonConfig {
@@ -520,6 +528,7 @@ export interface TabConfig extends FormItem, ContainerCommonConfig {
520
528
  onChange?: (mForm: FormState | undefined, data: any) => void;
521
529
  onTabAdd?: (mForm: FormState | undefined, data: any) => void;
522
530
  onTabRemove?: (mForm: FormState | undefined, tabName: string, data: any) => void;
531
+ onTabClick?: (mForm: FormState | undefined, tab: any, data: any) => void;
523
532
  activeChange?: (mForm: FormState | undefined, tabName: string, data: any) => void;
524
533
  }
525
534
 
@@ -5,6 +5,10 @@ fieldset.m-fieldset {
5
5
  margin-bottom: 10px;
6
6
  min-inline-size: auto;
7
7
 
8
+ .el-checkbox {
9
+ height: 22px;
10
+ }
11
+
8
12
  legend {
9
13
  font-size: 14px;
10
14
  position: absolute;
package/src/utils/form.ts CHANGED
@@ -53,16 +53,7 @@ const asyncLoadConfig = (value: FormValue, initValue: FormValue, { asyncLoad, na
53
53
 
54
54
  const isMultipleValue = (type?: string | TypeFunction) =>
55
55
  typeof type === 'string' &&
56
- [
57
- 'checkbox-group',
58
- 'checkboxGroup',
59
- 'table',
60
- 'cascader',
61
- 'group-list',
62
- 'groupList',
63
- 'dynamic-tab',
64
- 'dynamicTab',
65
- ].includes(type);
56
+ ['checkbox-group', 'checkboxGroup', 'table', 'cascader', 'group-list', 'groupList'].includes(type);
66
57
 
67
58
  const initItemsValue = (
68
59
  mForm: FormState | undefined,
@@ -71,7 +62,7 @@ const initItemsValue = (
71
62
  { items, name, extensible }: any,
72
63
  ) => {
73
64
  if (Array.isArray(initValue[name])) {
74
- value[name] = initValue[name].map((v: any) => init(mForm, items, v));
65
+ value[name] = initValue[name].map((v: any, index: number) => init(mForm, items, v, value[name]?.[index]));
75
66
  } else {
76
67
  value[name] = init(mForm, items, initValue[name], value[name]);
77
68
  if (extensible) {
@@ -83,7 +74,7 @@ const initItemsValue = (
83
74
  const setValue = (mForm: FormState | undefined, value: FormValue, initValue: FormValue, item: any) => {
84
75
  const { items, name, type, checkbox } = item;
85
76
  // 值是数组, 有可能也有items配置,所以不能放到getDefaultValue里赋值
86
- if (isMultipleValue(type)) {
77
+ if (isMultipleValue(type) || (type === 'tab' && item.dynamic)) {
87
78
  value[name] = initValue[name] || [];
88
79
  }
89
80
 
@@ -232,7 +223,7 @@ export const getRules = function (mForm: FormState | undefined, rules: Rule[] |
232
223
  fnc(
233
224
  {
234
225
  rule,
235
- value,
226
+ value: props.config.names ? props.model : value,
236
227
  callback,
237
228
  source,
238
229
  options,