sard-uniapp 1.4.0 → 1.5.0-rc

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/changelog.md +13 -0
  2. package/components/card/card.d.ts +2 -2
  3. package/components/card/common.d.ts +3 -3
  4. package/components/config/index.d.ts +20 -0
  5. package/components/config/index.js +10 -0
  6. package/components/dropdown-item/dropdown-item.vue +4 -4
  7. package/components/fab/common.d.ts +34 -0
  8. package/components/fab/common.js +5 -0
  9. package/components/fab/fab.d.ts +41 -0
  10. package/components/fab/fab.vue +159 -0
  11. package/components/fab/index.d.ts +1 -0
  12. package/components/fab/index.js +1 -0
  13. package/components/fab/index.scss +95 -0
  14. package/components/fab/variables.scss +22 -0
  15. package/components/floating-bubble/common.d.ts +28 -0
  16. package/components/floating-bubble/common.js +2 -0
  17. package/components/floating-bubble/floating-bubble.d.ts +49 -0
  18. package/components/floating-bubble/floating-bubble.vue +216 -0
  19. package/components/floating-bubble/index.d.ts +1 -0
  20. package/components/floating-bubble/index.js +1 -0
  21. package/components/floating-bubble/index.scss +33 -0
  22. package/components/floating-bubble/variables.scss +10 -0
  23. package/components/form-item/form-item.vue +4 -4
  24. package/components/navbar-item/navbar-item.d.ts +2 -2
  25. package/components/popup/index.scss +1 -1
  26. package/components/search/common.d.ts +3 -0
  27. package/components/search/search.d.ts +6 -0
  28. package/components/search/search.vue +14 -2
  29. package/components/tag/tag.d.ts +4 -4
  30. package/components/tag/tag.vue +3 -1
  31. package/global.d.ts +90 -173
  32. package/index.d.ts +4 -2
  33. package/index.js +4 -2
  34. package/index.scss +8 -6
  35. package/package.json +1 -1
  36. package/utils/dom.d.ts +9 -5
  37. package/utils/dom.js +7 -4
package/changelog.md CHANGED
@@ -1,3 +1,16 @@
1
+ # [1.5.0-rc](https://github.com/sutras/sard-uniapp/compare/v1.4.1...v1.5.0-rc) (2024-08-08)
2
+
3
+
4
+
5
+ ## [1.4.1](https://github.com/sutras/sard-uniapp/compare/v1.4.0...v1.4.1) (2024-08-02)
6
+
7
+
8
+ ### Features
9
+
10
+ * search组件新增clear, focus, blur事件 ([05dc641](https://github.com/sutras/sard-uniapp/commit/05dc641947e83a6d9e9c92b46cfc33135116eb22))
11
+
12
+
13
+
1
14
  # [1.4.0](https://github.com/sutras/sard-uniapp/compare/v1.3.0...v1.4.0) (2024-08-01)
2
15
 
3
16
 
@@ -1,8 +1,8 @@
1
1
  import { type CardProps, type CardSlots } from './common';
2
2
  declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__VLS_WithDefaults<__VLS_TypePropsToOption<CardProps>, {}>, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
3
- click: (...args: any[]) => void;
3
+ click: (event: any) => void;
4
4
  }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToOption<CardProps>, {}>>> & {
5
- onClick?: ((...args: any[]) => any) | undefined;
5
+ onClick?: ((event: any) => any) | undefined;
6
6
  }, {}, {}>, Readonly<CardSlots> & CardSlots>;
7
7
  export default _default;
8
8
  type __VLS_WithDefaults<P, D> = {
@@ -6,12 +6,12 @@ export interface CardProps {
6
6
  extra?: string;
7
7
  footer?: string;
8
8
  }
9
- export interface CardEmits {
10
- (e: 'click', event: any): void;
11
- }
12
9
  export interface CardSlots {
13
10
  default?(props: Record<string, never>): any;
14
11
  title?(props: Record<string, never>): any;
15
12
  extra?(props: Record<string, never>): any;
16
13
  footer?(props: Record<string, never>): any;
17
14
  }
15
+ export interface CardEmits {
16
+ (e: 'click', event: any): void;
17
+ }
@@ -80,6 +80,16 @@ export declare const defaultConfig: {
80
80
  empty: {
81
81
  icon: string;
82
82
  };
83
+ fab: {
84
+ overlayClosable: boolean;
85
+ hideName: boolean;
86
+ duration: number;
87
+ };
88
+ floatingBubble: {
89
+ axis: "y";
90
+ gapX: number;
91
+ gapY: number;
92
+ };
83
93
  form: {
84
94
  validateTrigger: "change";
85
95
  validateOnRuleChange: boolean;
@@ -428,6 +438,16 @@ export declare function useConfigContext(): DeepPartial<{
428
438
  empty: {
429
439
  icon: string;
430
440
  };
441
+ fab: {
442
+ overlayClosable: boolean;
443
+ hideName: boolean;
444
+ duration: number;
445
+ };
446
+ floatingBubble: {
447
+ axis: "y";
448
+ gapX: number;
449
+ gapY: number;
450
+ };
431
451
  form: {
432
452
  validateTrigger: "change";
433
453
  validateOnRuleChange: boolean;
@@ -81,6 +81,16 @@ export const defaultConfig = {
81
81
  empty: {
82
82
  icon: 'empty',
83
83
  },
84
+ fab: {
85
+ overlayClosable: false,
86
+ hideName: false,
87
+ duration: 150,
88
+ },
89
+ floatingBubble: {
90
+ axis: 'y',
91
+ gapX: 24,
92
+ gapY: 24,
93
+ },
84
94
  form: {
85
95
  validateTrigger: 'change',
86
96
  validateOnRuleChange: true,
@@ -92,7 +92,7 @@ import {
92
92
  createBem,
93
93
  uniqid,
94
94
  getBoundingClientRect,
95
- getViewportSize,
95
+ getWindowInfo,
96
96
  isNullish
97
97
  } from "../../utils";
98
98
  import SarPopup from "../popup/popup.vue";
@@ -167,7 +167,7 @@ export default _defineComponent({
167
167
  const popupInset = ref("");
168
168
  const awayInset = ref("");
169
169
  const setPosition = async () => {
170
- const viewportSize = await getViewportSize();
170
+ const windowInfo = await getWindowInfo();
171
171
  const itemRect = await getBoundingClientRect(`#${itemId}`, instance);
172
172
  const nextPopupInset = {
173
173
  left: 0,
@@ -185,10 +185,10 @@ export default _defineComponent({
185
185
  nextPopupInset.top = `calc(${itemRect.bottom}px + var(--window-top))`;
186
186
  nextPopupInset.bottom = 0;
187
187
  nextAwayInset.top = 0;
188
- nextAwayInset.bottom = `calc(${viewportSize.height - itemRect.bottom}px + var(--window-top))`;
188
+ nextAwayInset.bottom = `calc(${windowInfo.windowHeight - itemRect.bottom}px + var(--window-top))`;
189
189
  } else {
190
190
  nextPopupInset.top = 0;
191
- nextPopupInset.bottom = `${viewportSize.height - itemRect.top}px`;
191
+ nextPopupInset.bottom = `${windowInfo.windowHeight - itemRect.top}px`;
192
192
  nextAwayInset.top = `calc(${itemRect.bottom}px + var(--window-top))`;
193
193
  nextAwayInset.bottom = 0;
194
194
  }
@@ -0,0 +1,34 @@
1
+ import { type StyleValue } from 'vue';
2
+ export interface FabProps {
3
+ rootStyle?: StyleValue;
4
+ rootClass?: string;
5
+ top?: string;
6
+ right?: string;
7
+ bottom?: string;
8
+ left?: string;
9
+ color?: string;
10
+ background?: string;
11
+ icon?: string;
12
+ iconFamily?: string;
13
+ itemList?: FabItem[];
14
+ hideName?: boolean;
15
+ overlayClosable?: boolean;
16
+ duration?: number;
17
+ }
18
+ export declare const fabPropsDefaults: {
19
+ itemList: () => never[];
20
+ overlayClosable: boolean;
21
+ hideName: boolean;
22
+ duration: number;
23
+ };
24
+ export interface FabEmits {
25
+ (e: 'click', event: any): void;
26
+ (e: 'select', item: FabItem, index: number): void;
27
+ }
28
+ export interface FabItem {
29
+ name?: string;
30
+ color?: string;
31
+ background?: string;
32
+ icon?: string;
33
+ iconFamily?: string;
34
+ }
@@ -0,0 +1,5 @@
1
+ import { defaultConfig } from '../config';
2
+ export const fabPropsDefaults = {
3
+ ...defaultConfig.fab,
4
+ itemList: () => [],
5
+ };
@@ -0,0 +1,41 @@
1
+ import { type FabProps, FabItem } from './common';
2
+ declare const _default: import("vue").DefineComponent<__VLS_WithDefaults<__VLS_TypePropsToOption<FabProps>, {
3
+ itemList: () => never[];
4
+ overlayClosable: boolean;
5
+ hideName: boolean;
6
+ duration: number;
7
+ }>, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
8
+ click: (event: any) => void;
9
+ select: (item: FabItem, index: number) => void;
10
+ }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToOption<FabProps>, {
11
+ itemList: () => never[];
12
+ overlayClosable: boolean;
13
+ hideName: boolean;
14
+ duration: number;
15
+ }>>> & {
16
+ onClick?: ((event: any) => any) | undefined;
17
+ onSelect?: ((item: FabItem, index: number) => any) | undefined;
18
+ }, {
19
+ overlayClosable: boolean;
20
+ duration: number;
21
+ hideName: boolean;
22
+ itemList: FabItem[];
23
+ }, {}>;
24
+ export default _default;
25
+ type __VLS_WithDefaults<P, D> = {
26
+ [K in keyof Pick<P, keyof P>]: K extends keyof D ? __VLS_Prettify<P[K] & {
27
+ default: D[K];
28
+ }> : P[K];
29
+ };
30
+ type __VLS_Prettify<T> = {
31
+ [K in keyof T]: T[K];
32
+ } & {};
33
+ type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
34
+ type __VLS_TypePropsToOption<T> = {
35
+ [K in keyof T]-?: {} extends Pick<T, K> ? {
36
+ type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
37
+ } : {
38
+ type: import('vue').PropType<T[K]>;
39
+ required: true;
40
+ };
41
+ };
@@ -0,0 +1,159 @@
1
+ <template>
2
+ <sar-overlay
3
+ :visible="visible"
4
+ :z-index="zIndex"
5
+ background="var(--sar-fab-mask)"
6
+ @click="onOverlayClick"
7
+ />
8
+
9
+ <view :class="fabClass" :style="fabStyle">
10
+ <view
11
+ :class="contentClass"
12
+ :style="contentStyle"
13
+ @transitionend="onTransitionEnd"
14
+ >
15
+ <view
16
+ v-for="(item, index) in itemList"
17
+ :key="index"
18
+ :class="itemClass"
19
+ @click="onItemClick(item, index)"
20
+ >
21
+ <view v-if="!hideName" :class="bem.e('item-name')">
22
+ {{ item.name }}
23
+ </view>
24
+ <view
25
+ :class="bem.e('item-btn')"
26
+ :style="
27
+ stringifyStyle({ background: item.background, color: item.color })
28
+ "
29
+ >
30
+ <sar-icon :family="item.iconFamily" :name="item.icon" />
31
+ </view>
32
+ </view>
33
+ </view>
34
+ <view :class="itemEntryClass" @click="onItemEntryClick">
35
+ <view :class="bem.e('item-btn')" :style="itemEntryBtnStyle">
36
+ <sar-icon name="plus" />
37
+ </view>
38
+ </view>
39
+ </view>
40
+ </template>
41
+
42
+ <script>
43
+ import { mergeDefaults as _mergeDefaults, defineComponent as _defineComponent } from "vue";
44
+ import { computed, reactive, ref } from "vue";
45
+ import { classNames, stringifyStyle, createBem, isNullish } from "../../utils";
46
+ import {
47
+ fabPropsDefaults
48
+ } from "./common";
49
+ import { useTransition, useZIndex } from "../../use";
50
+ import SarIcon from "../icon/icon.vue";
51
+ import SarOverlay from "../overlay/overlay.vue";
52
+ export default _defineComponent({
53
+ ...{
54
+ options: {
55
+ virtualHost: true,
56
+ styleIsolation: "shared"
57
+ }
58
+ },
59
+ __name: "fab",
60
+ props: _mergeDefaults({
61
+ rootStyle: { type: [Boolean, null, String, Object, Array], required: false, skipCheck: true },
62
+ rootClass: { type: String, required: false },
63
+ top: { type: String, required: false },
64
+ right: { type: String, required: false },
65
+ bottom: { type: String, required: false },
66
+ left: { type: String, required: false },
67
+ color: { type: String, required: false },
68
+ background: { type: String, required: false },
69
+ icon: { type: String, required: false },
70
+ iconFamily: { type: String, required: false },
71
+ itemList: { type: Array, required: false },
72
+ hideName: { type: Boolean, required: false },
73
+ overlayClosable: { type: Boolean, required: false },
74
+ duration: { type: Number, required: false }
75
+ }, fabPropsDefaults),
76
+ emits: ["click", "select"],
77
+ setup(__props, { expose: __expose, emit: __emit }) {
78
+ __expose();
79
+ const props = __props;
80
+ const emit = __emit;
81
+ const bem = createBem("fab");
82
+ const visible = ref(false);
83
+ const [zIndex, increaseZIndex] = useZIndex();
84
+ const { realVisible, transitionClass, onTransitionEnd } = useTransition(
85
+ reactive({
86
+ visible,
87
+ duration: props.duration,
88
+ prefix: bem.m("zoom-")
89
+ })
90
+ );
91
+ const onItemEntryClick = (event) => {
92
+ if (props.itemList && props.itemList.length > 0) {
93
+ visible.value = !visible.value;
94
+ if (visible.value) {
95
+ increaseZIndex();
96
+ }
97
+ }
98
+ emit("click", event);
99
+ };
100
+ const onItemClick = (item, index) => {
101
+ visible.value = false;
102
+ emit("select", item, index);
103
+ };
104
+ const onOverlayClick = () => {
105
+ if (props.overlayClosable) {
106
+ visible.value = false;
107
+ }
108
+ };
109
+ const fabClass = computed(() => {
110
+ return classNames(
111
+ bem.b(),
112
+ bem.m(isNullish(props.top) ? "bottom" : "top"),
113
+ bem.m(isNullish(props.left) ? "right" : "left"),
114
+ bem.m("visible", visible.value),
115
+ props.rootClass
116
+ );
117
+ });
118
+ const fabStyle = computed(() => {
119
+ return stringifyStyle(props.rootStyle, {
120
+ zIndex: visible.value ? zIndex.value : null,
121
+ top: props.top,
122
+ left: props.left,
123
+ right: !isNullish(props.left) ? "auto" : props.right,
124
+ bottom: !isNullish(props.top) ? "auto" : props.bottom
125
+ });
126
+ });
127
+ const contentClass = computed(() => {
128
+ return classNames(bem.e("content"), transitionClass.value);
129
+ });
130
+ const contentStyle = computed(() => {
131
+ return stringifyStyle({
132
+ display: realVisible.value ? "flex" : "none",
133
+ transitionDuration: props.duration + "ms",
134
+ transformOrigin: `${isNullish(props.top) ? "bottom" : "top"} ${isNullish(props.left) ? "right" : "left"}`
135
+ });
136
+ });
137
+ const itemEntryClass = computed(() => {
138
+ return classNames(bem.e("item"), bem.em("item", "entry"));
139
+ });
140
+ const itemEntryBtnStyle = computed(() => {
141
+ return stringifyStyle({
142
+ color: props.color,
143
+ background: props.background
144
+ });
145
+ });
146
+ const itemClass = computed(() => {
147
+ return classNames(bem.e("item"));
148
+ });
149
+ const __returned__ = { props, emit, bem, visible, zIndex, increaseZIndex, realVisible, transitionClass, onTransitionEnd, onItemEntryClick, onItemClick, onOverlayClick, fabClass, fabStyle, contentClass, contentStyle, itemEntryClass, itemEntryBtnStyle, itemClass, get stringifyStyle() {
150
+ return stringifyStyle;
151
+ }, SarIcon, SarOverlay };
152
+ return __returned__;
153
+ }
154
+ });
155
+ </script>
156
+
157
+ <style lang="scss">
158
+ @import './index.scss';
159
+ </style>
@@ -0,0 +1 @@
1
+ export type { FabProps, FabEmits, FabItem } from './common';
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,95 @@
1
+ @use '../style/base' as *;
2
+
3
+ @include bem(fab) {
4
+ @include b() {
5
+ @include universal;
6
+ position: fixed;
7
+ right: var(--sar-fab-right);
8
+ bottom: var(--sar-fab-bottom);
9
+ z-index: var(--sar-fab-z-index);
10
+ gap: var(--sar-fab-item-gap);
11
+ }
12
+
13
+ @include e(content) {
14
+ @include universal;
15
+ gap: var(--sar-fab-item-gap);
16
+ }
17
+
18
+ @include m(zoom-enter-from, zoom-leave-to) {
19
+ opacity: 0;
20
+ transform: scale(0.4);
21
+ }
22
+
23
+ @include m(zoom-enter-to, zoom-leave-from) {
24
+ opacity: 1;
25
+ transform: scale(1);
26
+ }
27
+
28
+ @include m(zoom-enter-active, zoom-leave-active) {
29
+ transition: transform var(--sar-fab-duration) ease-out,
30
+ opacity var(--sar-fab-duration) ease-out;
31
+ }
32
+
33
+ @include e(item) {
34
+ @include universal;
35
+ flex-direction: row;
36
+ align-items: center;
37
+ gap: var(--sar-fab-item-name-gap);
38
+ cursor: pointer;
39
+
40
+ &:active {
41
+ opacity: var(--sar-fab-item-active-opacity);
42
+ }
43
+
44
+ @include m(entry) {
45
+ @include e(item-btn) {
46
+ transition: transform var(--sar-fab-duration);
47
+ }
48
+ }
49
+ }
50
+
51
+ @include e(item-name) {
52
+ @include universal;
53
+ font-size: var(--sar-fab-item-name-font-size);
54
+ color: var(--sar-fab-item-name-color);
55
+ }
56
+
57
+ @include e(item-btn) {
58
+ @include universal;
59
+ justify-content: center;
60
+ align-items: center;
61
+ width: var(--sar-fab-item-btn-size);
62
+ height: var(--sar-fab-item-btn-size);
63
+ border-radius: var(--sar-rounded-full);
64
+ font-size: var(--sar-fab-item-btn-font-size);
65
+ color: var(--sar-fab-item-btn-color);
66
+ background-color: var(--sar-fab-item-btn-bg);
67
+ box-shadow: var(--sar-fab-item-btn-shadow);
68
+ }
69
+
70
+ @include m(top) {
71
+ flex-direction: column-reverse;
72
+ }
73
+
74
+ @include m(left) {
75
+ align-items: flex-start;
76
+
77
+ @include e(item) {
78
+ flex-direction: row-reverse;
79
+ }
80
+ }
81
+
82
+ @include m(right) {
83
+ align-items: flex-end;
84
+ }
85
+
86
+ @include m(visible) {
87
+ @include e(item) {
88
+ @include m(entry) {
89
+ @include e(item-btn) {
90
+ transform: rotate(45deg);
91
+ }
92
+ }
93
+ }
94
+ }
95
+ }
@@ -0,0 +1,22 @@
1
+ // #variables
2
+ page {
3
+ --sar-fab-z-index: 1000;
4
+ --sar-fab-right: 48rpx;
5
+ --sar-fab-bottom: 96rpx;
6
+ --sar-fab-mask: var(--sar-mask-illegible);
7
+ --sar-fab-duration: var(--sar-duration-fast);
8
+
9
+ --sar-fab-item-gap: 32rpx;
10
+ --sar-fab-item-active-opacity: var(--sar-active-opacity);
11
+
12
+ --sar-fab-item-btn-size: 96rpx;
13
+ --sar-fab-item-btn-font-size: 48rpx;
14
+ --sar-fab-item-btn-color: var(--sar-white);
15
+ --sar-fab-item-btn-bg: var(--sar-primary);
16
+ --sar-fab-item-btn-shadow: var(--sar-shadow);
17
+
18
+ --sar-fab-item-name-gap: 16rpx;
19
+ --sar-fab-item-name-font-size: var(--sar-text-base);
20
+ --sar-fab-item-name-color: var(--sar-white);
21
+ }
22
+ // #endvariables
@@ -0,0 +1,28 @@
1
+ import { type StyleValue } from 'vue';
2
+ export interface FloatingBubbleProps {
3
+ rootStyle?: StyleValue;
4
+ rootClass?: string;
5
+ axis?: 'x' | 'y' | 'both' | 'none';
6
+ magnet?: 'x' | 'y';
7
+ gapX?: number;
8
+ gapY?: number;
9
+ offset?: {
10
+ x: number;
11
+ y: number;
12
+ };
13
+ }
14
+ export declare const floatingBubblePropsDefaults: {
15
+ axis: "y";
16
+ gapX: number;
17
+ gapY: number;
18
+ };
19
+ export interface FloatingBubbleSlots {
20
+ default?(props: Record<string, never>): any;
21
+ }
22
+ export interface FloatingBubbleEmits {
23
+ (e: 'click', event: any): void;
24
+ (e: 'update:offset', offset: {
25
+ x: number;
26
+ y: number;
27
+ }): void;
28
+ }
@@ -0,0 +1,2 @@
1
+ import { defaultConfig } from '../config';
2
+ export const floatingBubblePropsDefaults = defaultConfig.floatingBubble;
@@ -0,0 +1,49 @@
1
+ import { type FloatingBubbleProps, type FloatingBubbleSlots } from './common';
2
+ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__VLS_WithDefaults<__VLS_TypePropsToOption<FloatingBubbleProps>, {
3
+ axis: "y";
4
+ gapX: number;
5
+ gapY: number;
6
+ }>, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
7
+ click: (event: any) => void;
8
+ "update:offset": (offset: {
9
+ x: number;
10
+ y: number;
11
+ }) => void;
12
+ }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToOption<FloatingBubbleProps>, {
13
+ axis: "y";
14
+ gapX: number;
15
+ gapY: number;
16
+ }>>> & {
17
+ onClick?: ((event: any) => any) | undefined;
18
+ "onUpdate:offset"?: ((offset: {
19
+ x: number;
20
+ y: number;
21
+ }) => any) | undefined;
22
+ }, {
23
+ axis: "y" | "none" | "both" | "x";
24
+ gapX: number;
25
+ gapY: number;
26
+ }, {}>, Readonly<FloatingBubbleSlots> & FloatingBubbleSlots>;
27
+ export default _default;
28
+ type __VLS_WithDefaults<P, D> = {
29
+ [K in keyof Pick<P, keyof P>]: K extends keyof D ? __VLS_Prettify<P[K] & {
30
+ default: D[K];
31
+ }> : P[K];
32
+ };
33
+ type __VLS_Prettify<T> = {
34
+ [K in keyof T]: T[K];
35
+ } & {};
36
+ type __VLS_WithTemplateSlots<T, S> = T & {
37
+ new (): {
38
+ $slots: S;
39
+ };
40
+ };
41
+ type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
42
+ type __VLS_TypePropsToOption<T> = {
43
+ [K in keyof T]-?: {} extends Pick<T, K> ? {
44
+ type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
45
+ } : {
46
+ type: import('vue').PropType<T[K]>;
47
+ required: true;
48
+ };
49
+ };