sprintify-ui 0.0.194 → 0.0.196
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.
- package/dist/sprintify-ui.es.js +6517 -6429
- package/dist/style.css +1 -1
- package/dist/types/src/components/BaseAddressForm.vue.d.ts +2 -2
- package/dist/types/src/components/BaseAutocomplete.vue.d.ts +5 -5
- package/dist/types/src/components/BaseAutocompleteDrawer.vue.d.ts +2 -2
- package/dist/types/src/components/BaseAutocompleteFetch.vue.d.ts +5 -5
- package/dist/types/src/components/BaseBelongsTo.vue.d.ts +3 -3
- package/dist/types/src/components/BaseButtonGroup.vue.d.ts +2 -2
- package/dist/types/src/components/BaseCharacterCounter.vue.d.ts +1 -1
- package/dist/types/src/components/BaseColor.vue.d.ts +2 -2
- package/dist/types/src/components/BaseDatePicker.vue.d.ts +1 -1
- package/dist/types/src/components/BaseDropdownAutocomplete.vue.d.ts +4 -4
- package/dist/types/src/components/BaseFieldI18n.vue.d.ts +2 -2
- package/dist/types/src/components/BaseFilePicker.vue.d.ts +1 -1
- package/dist/types/src/components/BaseFileUploader.vue.d.ts +2 -2
- package/dist/types/src/components/BaseForm.vue.d.ts +1 -1
- package/dist/types/src/components/BaseHasMany.vue.d.ts +2 -2
- package/dist/types/src/components/BaseInput.vue.d.ts +5 -5
- package/dist/types/src/components/BaseInputPercent.vue.d.ts +4 -4
- package/dist/types/src/components/BaseLoadingCover.vue.d.ts +2 -2
- package/dist/types/src/components/BaseMediaLibrary.vue.d.ts +4 -4
- package/dist/types/src/components/BaseModalCenter.vue.d.ts +1 -1
- package/dist/types/src/components/BaseModalSide.vue.d.ts +1 -1
- package/dist/types/src/components/BaseNavbarItemContent.vue.d.ts +1 -1
- package/dist/types/src/components/BaseNavbarSideItemContent.vue.d.ts +1 -1
- package/dist/types/src/components/BaseNumber.vue.d.ts +16 -7
- package/dist/types/src/components/BasePassword.vue.d.ts +2 -2
- package/dist/types/src/components/BaseRadioGroup.vue.d.ts +1 -1
- package/dist/types/src/components/BaseRichText.vue.d.ts +2 -2
- package/dist/types/src/components/BaseSelect.vue.d.ts +3 -3
- package/dist/types/src/components/BaseSwitch.vue.d.ts +1 -1
- package/dist/types/src/components/BaseTabItem.vue.d.ts +33 -30
- package/dist/types/src/components/BaseTabs.vue.d.ts +25 -1
- package/dist/types/src/components/BaseTagAutocomplete.vue.d.ts +4 -4
- package/dist/types/src/components/BaseTagAutocompleteFetch.vue.d.ts +2 -2
- package/dist/types/src/components/BaseTextarea.vue.d.ts +3 -3
- package/dist/types/src/components/BaseTextareaAutoresize.vue.d.ts +2 -2
- package/package.json +1 -1
- package/src/components/BaseForm.stories.js +48 -0
- package/src/components/BaseForm.vue +10 -5
- package/src/components/BaseNumber.stories.js +19 -3
- package/src/components/BaseNumber.vue +57 -4
- package/src/components/BaseTabItem.vue +53 -22
- package/src/components/BaseTabs.stories.js +33 -2
- package/src/components/BaseTabs.vue +74 -3
- package/src/composables/field.ts +11 -4
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
leave-from-class="transform scale-100 opacity-100"
|
|
9
9
|
leave-to-class="transform scale-90 opacity-0"
|
|
10
10
|
>
|
|
11
|
-
<div v-if="
|
|
11
|
+
<div v-if="showInvalidInput" class="absolute left-0 top-full z-[1]">
|
|
12
12
|
<div
|
|
13
13
|
class="mt-1 ml-1 rounded bg-red-500 px-2 py-1 text-xs font-medium text-white"
|
|
14
14
|
>
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
:max="max"
|
|
37
37
|
:class="[
|
|
38
38
|
['full', 'left'].includes(rounded) ? 'rounded-l' : '',
|
|
39
|
-
|
|
39
|
+
showInvalidInput ? 'focus:ring-red-400' : 'focus:ring-primary-500',
|
|
40
40
|
]"
|
|
41
41
|
class="w-full border-none focus:z-[1] focus:border-none focus:border-transparent focus:shadow-none focus:outline-none focus:ring-2 focus:ring-offset-1 disabled:cursor-not-allowed disabled:text-slate-300"
|
|
42
42
|
type="text"
|
|
@@ -73,8 +73,10 @@
|
|
|
73
73
|
import { useField } from '@/composables/field';
|
|
74
74
|
import { isNumber, round } from 'lodash';
|
|
75
75
|
import { PropType } from 'vue';
|
|
76
|
+
import { BaseIcon } from '.';
|
|
76
77
|
|
|
77
78
|
const AUTO_CORRECT_TIMEOUT = 2000;
|
|
79
|
+
const SHOW_INVALID_INPUT_TIMEOUT = 500;
|
|
78
80
|
|
|
79
81
|
const props = defineProps({
|
|
80
82
|
modelValue: {
|
|
@@ -124,17 +126,23 @@ const props = defineProps({
|
|
|
124
126
|
default: 'full',
|
|
125
127
|
type: String as PropType<'full' | 'left' | 'right' | 'none'>,
|
|
126
128
|
},
|
|
129
|
+
autoFix: {
|
|
130
|
+
default: false,
|
|
131
|
+
type: Boolean,
|
|
132
|
+
},
|
|
127
133
|
});
|
|
128
134
|
|
|
129
135
|
const emit = defineEmits(['update:modelValue', 'focus', 'blur', 'keydown']);
|
|
130
136
|
|
|
131
|
-
const { hasErrorInternal, emitUpdate } = useField({
|
|
137
|
+
const { hasErrorInternal, emitUpdate, enableForm, disableForm } = useField({
|
|
132
138
|
name: computed(() => props.name),
|
|
133
139
|
required: computed(() => props.required),
|
|
134
140
|
hasError: computed(() => props.hasError),
|
|
135
141
|
emit: emit,
|
|
136
142
|
});
|
|
137
143
|
|
|
144
|
+
const showInvalidInput = ref(false);
|
|
145
|
+
|
|
138
146
|
const stepNormalized = computed<number>(() => {
|
|
139
147
|
if (props.step === undefined) return 1;
|
|
140
148
|
if (props.step === 0) return 1;
|
|
@@ -170,9 +178,11 @@ function convertToNumber(
|
|
|
170
178
|
}
|
|
171
179
|
|
|
172
180
|
const valueInternal = ref<null | string | number>(null);
|
|
181
|
+
|
|
173
182
|
const realValueInternal = computed<number | null>(() => {
|
|
174
183
|
return convertToNumber(valueInternal.value);
|
|
175
184
|
});
|
|
185
|
+
|
|
176
186
|
const invalidInput = computed(() => {
|
|
177
187
|
if (realValueInternal.value == null && valueInternal.value == '') {
|
|
178
188
|
return false;
|
|
@@ -180,10 +190,12 @@ const invalidInput = computed(() => {
|
|
|
180
190
|
|
|
181
191
|
return realValueInternal.value != valueInternal.value;
|
|
182
192
|
});
|
|
193
|
+
|
|
183
194
|
const tooBig = computed(() => {
|
|
184
195
|
if (valueInternal.value === null) return false;
|
|
185
196
|
return hasMax.value && valueInternal.value > (props.max as number);
|
|
186
197
|
});
|
|
198
|
+
|
|
187
199
|
const tooSmall = computed(() => {
|
|
188
200
|
if (valueInternal.value === null) return false;
|
|
189
201
|
return hasMin.value && valueInternal.value < (props.min as number);
|
|
@@ -214,13 +226,37 @@ function onInput(event: any) {
|
|
|
214
226
|
|
|
215
227
|
emitUpdate(realValueInternal.value);
|
|
216
228
|
|
|
229
|
+
nextTick(() => {
|
|
230
|
+
showHideInvalidOnInput();
|
|
231
|
+
});
|
|
232
|
+
|
|
217
233
|
timeoutId = setTimeout(() => {
|
|
218
234
|
updateInternalValueToRealValue();
|
|
219
235
|
}, AUTO_CORRECT_TIMEOUT);
|
|
220
236
|
}
|
|
221
237
|
|
|
238
|
+
let showInvalidInputTimeoutId = undefined as undefined | number;
|
|
239
|
+
|
|
240
|
+
function showHideInvalidOnInput() {
|
|
241
|
+
clearTimeout(showInvalidInputTimeoutId);
|
|
242
|
+
|
|
243
|
+
if (!invalidInput.value) {
|
|
244
|
+
showInvalidInput.value = false;
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
showInvalidInputTimeoutId = setTimeout(() => {
|
|
249
|
+
showInvalidInput.value = true;
|
|
250
|
+
}, SHOW_INVALID_INPUT_TIMEOUT);
|
|
251
|
+
}
|
|
252
|
+
|
|
222
253
|
function onBlur(e: Event) {
|
|
223
254
|
emit('blur', e);
|
|
255
|
+
|
|
256
|
+
if (invalidInput.value) {
|
|
257
|
+
showInvalidInput.value = true;
|
|
258
|
+
}
|
|
259
|
+
|
|
224
260
|
updateInternalValueToRealValue();
|
|
225
261
|
}
|
|
226
262
|
|
|
@@ -244,6 +280,9 @@ const defaultValue = computed<number>(() => {
|
|
|
244
280
|
});
|
|
245
281
|
|
|
246
282
|
function updateInternalValueToRealValue() {
|
|
283
|
+
if (!props.autoFix) {
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
247
286
|
if (realValueInternal.value === null) {
|
|
248
287
|
valueInternal.value = '';
|
|
249
288
|
return;
|
|
@@ -287,7 +326,21 @@ function decrement() {
|
|
|
287
326
|
}
|
|
288
327
|
|
|
289
328
|
const borderColor = computed(() => {
|
|
290
|
-
if (hasErrorInternal.value) return 'border-red-500';
|
|
329
|
+
if (hasErrorInternal.value || invalidInput.value) return 'border-red-500';
|
|
291
330
|
return 'border-slate-300';
|
|
292
331
|
});
|
|
332
|
+
|
|
333
|
+
/** Disable form */
|
|
334
|
+
|
|
335
|
+
watch(
|
|
336
|
+
() => invalidInput.value,
|
|
337
|
+
() => {
|
|
338
|
+
if (invalidInput.value) {
|
|
339
|
+
disableForm();
|
|
340
|
+
} else {
|
|
341
|
+
enableForm();
|
|
342
|
+
}
|
|
343
|
+
},
|
|
344
|
+
{ immediate: true }
|
|
345
|
+
);
|
|
293
346
|
</script>
|
|
@@ -7,25 +7,26 @@
|
|
|
7
7
|
>
|
|
8
8
|
<a
|
|
9
9
|
:href="href"
|
|
10
|
-
class="group relative inline-block rounded-t-lg
|
|
10
|
+
class="group relative inline-block rounded-t-lg font-medium"
|
|
11
11
|
:class="[
|
|
12
|
-
(
|
|
13
|
-
? 'text-primary-600'
|
|
12
|
+
tabIsActive(isActive, isExactActive)
|
|
13
|
+
? 'active text-primary-600'
|
|
14
14
|
: 'text-slate-600 hover:text-slate-900',
|
|
15
15
|
disabled ? 'cursor-not-allowed opacity-60' : '',
|
|
16
|
+
sizeClass,
|
|
16
17
|
]"
|
|
17
|
-
@click="navigate"
|
|
18
|
+
@click.prevent="onClick(navigate)"
|
|
18
19
|
>
|
|
19
20
|
<div
|
|
20
21
|
class="absolute left-0 bottom-0 w-full"
|
|
21
22
|
:class="[
|
|
22
|
-
(
|
|
23
|
+
tabIsActive(isActive, isExactActive)
|
|
23
24
|
? 'h-[2px] bg-primary-600'
|
|
24
25
|
: 'group-hover:h-px group-hover:bg-slate-700',
|
|
25
26
|
]"
|
|
26
27
|
></div>
|
|
27
28
|
<div class="whitespace-nowrap">
|
|
28
|
-
<slot />
|
|
29
|
+
<slot :active="tabIsActive(isActive, isExactActive)" />
|
|
29
30
|
</div>
|
|
30
31
|
</a>
|
|
31
32
|
</router-link>
|
|
@@ -33,21 +34,51 @@
|
|
|
33
34
|
</template>
|
|
34
35
|
|
|
35
36
|
<script lang="ts" setup>
|
|
36
|
-
import {
|
|
37
|
-
import { RouteLocationRaw } from 'vue-router';
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
37
|
+
import { ComputedRef } from 'vue';
|
|
38
|
+
import { NavigationFailure, RouteLocationRaw } from 'vue-router';
|
|
39
|
+
|
|
40
|
+
const props = withDefaults(
|
|
41
|
+
defineProps<{
|
|
42
|
+
to: RouteLocationRaw;
|
|
43
|
+
disabled?: boolean;
|
|
44
|
+
activeStrategy?: 'default' | 'exact';
|
|
45
|
+
}>(),
|
|
46
|
+
{
|
|
47
|
+
disabled: false,
|
|
48
|
+
activeStrategy: 'default',
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const size = inject('tabs:size', ref('md')) as ComputedRef<
|
|
53
|
+
'xs' | 'sm' | 'md' | 'lg'
|
|
54
|
+
>;
|
|
55
|
+
|
|
56
|
+
function onClick(navigate: () => Promise<void | NavigationFailure>) {
|
|
57
|
+
if (props.disabled) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return navigate();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function tabIsActive(isActive: boolean, isExactActive: boolean) {
|
|
65
|
+
if (props.activeStrategy == 'default') {
|
|
66
|
+
return isActive;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return isExactActive;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const sizeClass = computed(() => {
|
|
73
|
+
switch (size.value) {
|
|
74
|
+
case 'xs':
|
|
75
|
+
return 'text-xs px-1.5 py-2';
|
|
76
|
+
case 'sm':
|
|
77
|
+
return 'text-sm px-1.5 py-2';
|
|
78
|
+
case 'md':
|
|
79
|
+
return 'text-base px-2 py-3';
|
|
80
|
+
case 'lg':
|
|
81
|
+
return 'text-lg px-3 py-4';
|
|
82
|
+
}
|
|
52
83
|
});
|
|
53
84
|
</script>
|
|
@@ -3,6 +3,7 @@ import BaseTabItem from './BaseTabItem.vue';
|
|
|
3
3
|
import BaseContainer from './BaseContainer.vue';
|
|
4
4
|
import BaseCard from './BaseCard.vue';
|
|
5
5
|
import BaseCardRow from './BaseCardRow.vue';
|
|
6
|
+
import BaseCounter from './BaseCounter.vue';
|
|
6
7
|
|
|
7
8
|
export default {
|
|
8
9
|
title: 'Layout/BaseTabs',
|
|
@@ -17,6 +18,7 @@ const Template = (args) => ({
|
|
|
17
18
|
BaseContainer,
|
|
18
19
|
BaseCard,
|
|
19
20
|
BaseCardRow,
|
|
21
|
+
BaseCounter,
|
|
20
22
|
},
|
|
21
23
|
setup() {
|
|
22
24
|
return { args };
|
|
@@ -25,8 +27,11 @@ const Template = (args) => ({
|
|
|
25
27
|
<div class="bg-slate-100 py-10">
|
|
26
28
|
<BaseContainer>
|
|
27
29
|
<BaseTabs v-bind="args">
|
|
28
|
-
<BaseTabItem to="/">
|
|
29
|
-
|
|
30
|
+
<BaseTabItem to="/" v-slot="{active}">
|
|
31
|
+
<div class="flex items-center">
|
|
32
|
+
<span class="mr-1">Home</span>
|
|
33
|
+
<BaseCounter :size="args.size" :color="active ? 'primary' : 'light'" :count="1"></BaseCounter>
|
|
34
|
+
</div>
|
|
30
35
|
</BaseTabItem>
|
|
31
36
|
<BaseTabItem to="/setup">
|
|
32
37
|
Setup
|
|
@@ -34,9 +39,15 @@ const Template = (args) => ({
|
|
|
34
39
|
<BaseTabItem to="/settings">
|
|
35
40
|
Settings
|
|
36
41
|
</BaseTabItem>
|
|
42
|
+
<BaseTabItem to="/articles">
|
|
43
|
+
Articles
|
|
44
|
+
</BaseTabItem>
|
|
37
45
|
<BaseTabItem to="/misc">
|
|
38
46
|
Miscellaneous
|
|
39
47
|
</BaseTabItem>
|
|
48
|
+
<BaseTabItem to="/users">
|
|
49
|
+
Users
|
|
50
|
+
</BaseTabItem>
|
|
40
51
|
</BaseTabs>
|
|
41
52
|
<div class="mt-10">
|
|
42
53
|
<BaseCard>
|
|
@@ -52,3 +63,23 @@ const Template = (args) => ({
|
|
|
52
63
|
|
|
53
64
|
export const Demo = Template.bind({});
|
|
54
65
|
Demo.args = {};
|
|
66
|
+
|
|
67
|
+
export const SizeXS = Template.bind({});
|
|
68
|
+
SizeXS.args = {
|
|
69
|
+
size: 'xs',
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const SizeSM = Template.bind({});
|
|
73
|
+
SizeSM.args = {
|
|
74
|
+
size: 'sm',
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export const SizeMD = Template.bind({});
|
|
78
|
+
SizeMD.args = {
|
|
79
|
+
size: 'md',
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export const SizeLG = Template.bind({});
|
|
83
|
+
SizeLG.args = {
|
|
84
|
+
size: 'lg',
|
|
85
|
+
};
|
|
@@ -2,14 +2,85 @@
|
|
|
2
2
|
<div class="relative">
|
|
3
3
|
<div class="absolute bottom-0 left-0 h-px w-full bg-slate-300" />
|
|
4
4
|
<div
|
|
5
|
-
|
|
5
|
+
ref="scrollable"
|
|
6
|
+
class="scrollable relative overflow-x-auto overflow-y-hidden"
|
|
6
7
|
data-scroll-lock-scrollable
|
|
7
8
|
>
|
|
8
|
-
<ul class="flex
|
|
9
|
+
<ul class="flex text-center" :class="[sizeClass]">
|
|
9
10
|
<slot />
|
|
10
11
|
</ul>
|
|
11
12
|
</div>
|
|
12
13
|
</div>
|
|
13
14
|
</template>
|
|
14
15
|
|
|
15
|
-
<script lang="ts" setup
|
|
16
|
+
<script lang="ts" setup>
|
|
17
|
+
const props = withDefaults(
|
|
18
|
+
defineProps<{
|
|
19
|
+
size?: 'xs' | 'sm' | 'md' | 'lg';
|
|
20
|
+
}>(),
|
|
21
|
+
{
|
|
22
|
+
size: 'md',
|
|
23
|
+
}
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
const route = useRoute();
|
|
27
|
+
const scrollable = ref<HTMLElement | null>(null);
|
|
28
|
+
|
|
29
|
+
watch(
|
|
30
|
+
() => route.fullPath,
|
|
31
|
+
() => {
|
|
32
|
+
nextTick(() => {
|
|
33
|
+
scrollToCenter();
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
provide(
|
|
39
|
+
'tabs:size',
|
|
40
|
+
computed(() => props.size)
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const sizeClass = computed(() => {
|
|
44
|
+
switch (props.size) {
|
|
45
|
+
case 'xs':
|
|
46
|
+
return 'space-x-1.5';
|
|
47
|
+
case 'sm':
|
|
48
|
+
return 'space-x-3';
|
|
49
|
+
case 'md':
|
|
50
|
+
return 'space-x-3';
|
|
51
|
+
case 'lg':
|
|
52
|
+
return 'space-x-6';
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
function scrollToCenter() {
|
|
57
|
+
if (!scrollable.value) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const activeTab = scrollable.value.querySelector(
|
|
62
|
+
'.active'
|
|
63
|
+
) as HTMLElement | null;
|
|
64
|
+
|
|
65
|
+
if (!activeTab) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const scrollableRect = scrollable.value.getBoundingClientRect();
|
|
70
|
+
const activeTabRect = activeTab.getBoundingClientRect();
|
|
71
|
+
|
|
72
|
+
const scrollLeft =
|
|
73
|
+
activeTab.offsetLeft - (scrollableRect.width - activeTabRect.width) / 2;
|
|
74
|
+
|
|
75
|
+
scrollable.value.scrollTo({
|
|
76
|
+
left: scrollLeft,
|
|
77
|
+
behavior: 'smooth',
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
</script>
|
|
81
|
+
|
|
82
|
+
<style scoped>
|
|
83
|
+
.scrollable::-webkit-scrollbar {
|
|
84
|
+
display: none;
|
|
85
|
+
}
|
|
86
|
+
</style>
|
package/src/composables/field.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { uniqueId } from 'lodash';
|
|
1
2
|
import { Ref } from 'vue';
|
|
2
3
|
|
|
3
4
|
interface Config {
|
|
@@ -10,6 +11,7 @@ interface Config {
|
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
export function useField(config: Config) {
|
|
14
|
+
const uuid = uniqueId();
|
|
13
15
|
const name = config.name;
|
|
14
16
|
const required = config.required;
|
|
15
17
|
const hasError = config.hasError;
|
|
@@ -60,11 +62,15 @@ export function useField(config: Config) {
|
|
|
60
62
|
|
|
61
63
|
const disableForm = inject('form:disable', () => {
|
|
62
64
|
return;
|
|
63
|
-
}) as () => void;
|
|
65
|
+
}) as (uuid: string) => void;
|
|
64
66
|
|
|
65
67
|
const enableForm = inject('form:enable', () => {
|
|
66
68
|
return;
|
|
67
|
-
}) as () => void;
|
|
69
|
+
}) as (uuid: string) => void;
|
|
70
|
+
|
|
71
|
+
onBeforeUnmount(() => {
|
|
72
|
+
enableForm(uuid);
|
|
73
|
+
});
|
|
68
74
|
|
|
69
75
|
const requiredInternal = computed((): boolean => {
|
|
70
76
|
if (required.value) {
|
|
@@ -98,13 +104,14 @@ export function useField(config: Config) {
|
|
|
98
104
|
emit('update:modelValue', value);
|
|
99
105
|
fieldOnUpdate();
|
|
100
106
|
}
|
|
107
|
+
|
|
101
108
|
return {
|
|
102
109
|
requiredInternal,
|
|
103
110
|
nameInternal,
|
|
104
111
|
hasErrorInternal,
|
|
105
112
|
errorMessageInternal,
|
|
106
113
|
emitUpdate,
|
|
107
|
-
enableForm,
|
|
108
|
-
disableForm,
|
|
114
|
+
enableForm: () => enableForm(uuid),
|
|
115
|
+
disableForm: () => disableForm(uuid),
|
|
109
116
|
};
|
|
110
117
|
}
|