sprintify-ui 0.0.41 → 0.0.42
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 +6033 -5518
- package/dist/types/src/components/BaseAutocomplete.vue.d.ts +32 -12
- package/dist/types/src/components/BaseAutocompleteFetch.vue.d.ts +28 -28
- package/dist/types/src/components/BaseBelongsTo.vue.d.ts +35 -35
- package/dist/types/src/components/BaseButtonGroup.vue.d.ts +46 -8
- package/dist/types/src/components/BaseDatePicker.vue.d.ts +18 -9
- package/dist/types/src/components/BaseDateSelect.vue.d.ts +14 -5
- package/dist/types/src/components/BaseField.vue.d.ts +151 -0
- package/dist/types/src/components/BaseFieldI18n.vue.d.ts +93 -0
- package/dist/types/src/components/BaseForm.vue.d.ts +267 -0
- package/dist/types/src/components/BaseFormField.d.ts +81 -0
- package/dist/types/src/components/BaseHasMany.vue.d.ts +31 -31
- package/dist/types/src/components/BaseInput.vue.d.ts +1 -1
- package/dist/types/src/components/BaseInputError.vue.d.ts +48 -0
- package/dist/types/src/components/BaseInputPercent.vue.d.ts +1 -1
- package/dist/types/src/components/BaseLocaleForm.vue.d.ts +420 -0
- package/dist/types/src/components/BaseMediaLibrary.vue.d.ts +46 -24
- package/dist/types/src/components/BaseNumberForm.vue.d.ts +382 -0
- package/dist/types/src/components/BasePassword.vue.d.ts +10 -14
- package/dist/types/src/components/BasePasswordForm.vue.d.ts +365 -0
- package/dist/types/src/components/BaseRadioGroup.vue.d.ts +23 -4
- package/dist/types/src/components/BaseSelect.vue.d.ts +20 -1
- package/dist/types/src/components/BaseSwitch.vue.d.ts +155 -23
- package/dist/types/src/components/BaseTagAutocomplete.vue.d.ts +31 -12
- package/dist/types/src/components/BaseTagAutocompleteFetch.vue.d.ts +20 -20
- package/dist/types/src/components/BaseTextarea.vue.d.ts +9 -0
- package/dist/types/src/components/BaseTextareaAutoresize.vue.d.ts +18 -0
- package/dist/types/src/components/BaseTextareaForm.vue.d.ts +394 -0
- package/dist/types/src/components/index.d.ts +4 -1
- package/dist/types/src/composables/field.d.ts +17 -0
- package/dist/types/src/index.d.ts +3 -0
- package/dist/types/src/types/index.d.ts +11 -0
- package/package.json +4 -1
- package/src/components/BaseAutocomplete.stories.js +56 -51
- package/src/components/BaseAutocomplete.vue +25 -8
- package/src/components/BaseAutocompleteFetch.stories.js +67 -65
- package/src/components/BaseAutocompleteFetch.vue +9 -29
- package/src/components/BaseBelongsTo.stories.js +72 -82
- package/src/components/BaseBelongsTo.vue +10 -11
- package/src/components/BaseButtonGroup.stories.js +11 -10
- package/src/components/BaseButtonGroup.vue +22 -9
- package/src/components/BaseCharacterCounter.stories.js +1 -1
- package/src/components/BaseDatePicker.stories.js +13 -9
- package/src/components/BaseDatePicker.vue +25 -8
- package/src/components/BaseDateSelect.stories.js +15 -9
- package/src/components/BaseDateSelect.vue +20 -8
- package/src/components/BaseField.vue +109 -0
- package/src/components/BaseFieldI18n.stories.js +38 -0
- package/src/components/BaseFieldI18n.vue +162 -0
- package/src/components/BaseFileUploader.stories.js +3 -3
- package/src/components/BaseFileUploader.vue +3 -3
- package/src/components/BaseForm.vue +298 -0
- package/src/components/BaseFormField.ts +117 -0
- package/src/components/BaseHasMany.stories.js +25 -10
- package/src/components/BaseHasMany.vue +9 -9
- package/src/components/BaseInput.stories.js +27 -14
- package/src/components/BaseInput.vue +17 -8
- package/src/components/BaseInputError.vue +7 -0
- package/src/components/BaseInputPercent.stories.js +10 -3
- package/src/components/BaseInputPercent.vue +2 -1
- package/src/components/BaseLocaleForm.vue +142 -0
- package/src/components/BaseMediaLibrary.stories.js +7 -6
- package/src/components/BaseMediaLibrary.vue +32 -31
- package/src/components/BaseMenu.vue +1 -1
- package/src/components/BaseNumberForm.vue +67 -0
- package/src/components/BasePassword.stories.js +9 -4
- package/src/components/BasePassword.vue +49 -44
- package/src/components/BasePasswordForm.vue +59 -0
- package/src/components/BaseRadioGroup.stories.js +9 -8
- package/src/components/BaseRadioGroup.vue +17 -3
- package/src/components/BaseSelect.stories.js +15 -2
- package/src/components/BaseSelect.vue +26 -10
- package/src/components/BaseSwitch.stories.js +7 -0
- package/src/components/BaseSwitch.vue +134 -124
- package/src/components/BaseTagAutocomplete.stories.js +21 -14
- package/src/components/BaseTagAutocomplete.vue +25 -14
- package/src/components/BaseTagAutocompleteFetch.stories.js +37 -21
- package/src/components/BaseTagAutocompleteFetch.vue +5 -5
- package/src/components/BaseTextarea.stories.js +11 -3
- package/src/components/BaseTextarea.vue +20 -6
- package/src/components/BaseTextareaAutoresize.stories.js +11 -2
- package/src/components/BaseTextareaAutoresize.vue +28 -4
- package/src/components/BaseTextareaForm.vue +101 -0
- package/src/components/BaseTimeline.vue +1 -1
- package/src/components/BaseTimelineItem.vue +4 -4
- package/src/components/index.ts +6 -0
- package/src/composables/field.ts +100 -0
- package/src/index.ts +11 -1
- package/src/types/index.ts +12 -0
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
ref="inputElement"
|
|
7
7
|
:value="keywords"
|
|
8
8
|
type="text"
|
|
9
|
-
:class="inputClass + ' pl-9'"
|
|
10
9
|
:placeholder="
|
|
11
10
|
placeholder ? placeholder : $t('sui.autocomplete_placeholder')
|
|
12
11
|
"
|
|
13
|
-
class="rounded disabled:cursor-not-allowed disabled:text-slate-300"
|
|
12
|
+
class="w-full rounded pl-9 disabled:cursor-not-allowed disabled:text-slate-300"
|
|
13
|
+
:class="[hasErrorInternal ? 'border-red-600' : 'border-slate-300']"
|
|
14
14
|
autocomplete="off"
|
|
15
15
|
:disabled="disabled"
|
|
16
16
|
@focus="onTextFocus"
|
|
@@ -95,7 +95,11 @@
|
|
|
95
95
|
|
|
96
96
|
<div ref="footer">
|
|
97
97
|
<div v-if="$slots.footer" class="bg-white">
|
|
98
|
-
<slot
|
|
98
|
+
<slot
|
|
99
|
+
:options="filteredNormalizedOptions"
|
|
100
|
+
:keywords="keywords"
|
|
101
|
+
name="footer"
|
|
102
|
+
/>
|
|
99
103
|
</div>
|
|
100
104
|
</div>
|
|
101
105
|
|
|
@@ -125,8 +129,10 @@ import { get } from 'lodash';
|
|
|
125
129
|
import { PropType, Ref, ComputedRef } from 'vue';
|
|
126
130
|
import { NormalizedOption, Option } from '@/types';
|
|
127
131
|
import { useInfiniteScroll, useMutationObserver } from '@vueuse/core';
|
|
128
|
-
import BaseSkeleton from '
|
|
132
|
+
import BaseSkeleton from '@/components/BaseSkeleton.vue';
|
|
129
133
|
import { useHasOptions } from '@/composables/hasOptions';
|
|
134
|
+
import { useField } from '@/composables/field';
|
|
135
|
+
import { BaseIcon } from './index';
|
|
130
136
|
|
|
131
137
|
const props = defineProps({
|
|
132
138
|
modelValue: {
|
|
@@ -145,8 +151,8 @@ const props = defineProps({
|
|
|
145
151
|
required: true,
|
|
146
152
|
type: String,
|
|
147
153
|
},
|
|
148
|
-
|
|
149
|
-
default:
|
|
154
|
+
name: {
|
|
155
|
+
default: undefined,
|
|
150
156
|
type: String,
|
|
151
157
|
},
|
|
152
158
|
placeholder: {
|
|
@@ -169,6 +175,10 @@ const props = defineProps({
|
|
|
169
175
|
default: undefined,
|
|
170
176
|
type: Function as PropType<(option: NormalizedOption) => boolean>,
|
|
171
177
|
},
|
|
178
|
+
hasError: {
|
|
179
|
+
default: false,
|
|
180
|
+
type: Boolean,
|
|
181
|
+
},
|
|
172
182
|
});
|
|
173
183
|
|
|
174
184
|
const emit = defineEmits([
|
|
@@ -179,6 +189,13 @@ const emit = defineEmits([
|
|
|
179
189
|
'clear',
|
|
180
190
|
]);
|
|
181
191
|
|
|
192
|
+
const { hasErrorInternal, emitUpdate } = useField({
|
|
193
|
+
name: computed(() => props.name),
|
|
194
|
+
required: computed(() => props.required),
|
|
195
|
+
hasError: computed(() => props.hasError),
|
|
196
|
+
emit: emit,
|
|
197
|
+
});
|
|
198
|
+
|
|
182
199
|
const timerId = ref(0);
|
|
183
200
|
const keywords = ref('');
|
|
184
201
|
const showDropdown = ref(false);
|
|
@@ -358,7 +375,7 @@ const update = (normalizedSelection: Option | null | undefined) => {
|
|
|
358
375
|
if (normalizedSelection) {
|
|
359
376
|
setKeywordsWithoutEvent(normalizedSelection.label);
|
|
360
377
|
}
|
|
361
|
-
|
|
378
|
+
emitUpdate(selection);
|
|
362
379
|
};
|
|
363
380
|
|
|
364
381
|
const setKeywordsWithoutEvent = (input: string) => {
|
|
@@ -387,6 +404,6 @@ useMutationObserver(
|
|
|
387
404
|
() => {
|
|
388
405
|
preventUnfocusOnFooter();
|
|
389
406
|
},
|
|
390
|
-
{ attributes: false, childList: true }
|
|
407
|
+
{ attributes: false, childList: true, subtree: true }
|
|
391
408
|
);
|
|
392
409
|
</script>
|
|
@@ -1,43 +1,39 @@
|
|
|
1
1
|
import BaseAutocompleteFetch from './BaseAutocompleteFetch.vue';
|
|
2
|
+
import ShowValue from '@/../.storybook/components/ShowValue.vue';
|
|
3
|
+
import { options } from '@/../.storybook/utils';
|
|
4
|
+
import { createFieldStory } from '../../.storybook/utils';
|
|
2
5
|
|
|
3
6
|
export default {
|
|
4
7
|
title: 'Form/BaseAutocompleteFetch',
|
|
5
8
|
component: BaseAutocompleteFetch,
|
|
6
|
-
argTypes: {},
|
|
7
9
|
args: {
|
|
8
10
|
url: 'https://effettandem.com/api/content/articles',
|
|
9
11
|
labelKey: 'title',
|
|
10
12
|
valueKey: 'id',
|
|
11
|
-
disabled: false,
|
|
12
13
|
},
|
|
13
14
|
decorators: [() => ({ template: '<div class="mb-36"><story/></div>' })],
|
|
14
15
|
};
|
|
15
16
|
|
|
16
|
-
const Template = (args) => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
></BaseAutocompleteFetch>
|
|
28
|
-
<p class="mt-5 text-sm">Value: <span class="bg-slate-200 font-mono px-1 py-px rounded">{{ value ?? 'NULL' }}</span></p>
|
|
29
|
-
`,
|
|
30
|
-
};
|
|
31
|
-
};
|
|
17
|
+
const Template = (args) => ({
|
|
18
|
+
components: { BaseAutocompleteFetch, ShowValue },
|
|
19
|
+
setup() {
|
|
20
|
+
const value = ref(null);
|
|
21
|
+
return { args, value };
|
|
22
|
+
},
|
|
23
|
+
template: `
|
|
24
|
+
<BaseAutocompleteFetch v-model="value" v-bind="args"></BaseAutocompleteFetch>
|
|
25
|
+
<ShowValue :value="value" />
|
|
26
|
+
`,
|
|
27
|
+
});
|
|
32
28
|
|
|
33
29
|
export const Demo = Template.bind({});
|
|
34
30
|
Demo.args = {};
|
|
35
31
|
|
|
36
32
|
export const Disabled = Template.bind({});
|
|
37
33
|
Disabled.args = {
|
|
38
|
-
modelValue: { label: 'Dark Maul', value: '1' },
|
|
39
34
|
labelKey: 'label',
|
|
40
35
|
valueKey: 'value',
|
|
36
|
+
modelValue: options[0],
|
|
41
37
|
disabled: true,
|
|
42
38
|
};
|
|
43
39
|
|
|
@@ -49,28 +45,26 @@ export const SlotOption = (args) => {
|
|
|
49
45
|
return { args, value };
|
|
50
46
|
},
|
|
51
47
|
template: `
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
</
|
|
70
|
-
</
|
|
71
|
-
|
|
72
|
-
</div>
|
|
73
|
-
`,
|
|
48
|
+
<BaseAutocompleteFetch
|
|
49
|
+
v-model="value"
|
|
50
|
+
v-bind="args"
|
|
51
|
+
>
|
|
52
|
+
<template #option="{ option, active, selected }">
|
|
53
|
+
<div
|
|
54
|
+
class="rounded px-2 py-1"
|
|
55
|
+
:class="{
|
|
56
|
+
'hover:bg-slate-100': !active && !selected,
|
|
57
|
+
'bg-slate-200 hover:bg-slate-300': active && !selected,
|
|
58
|
+
'bg-blue-500 text-white hover:bg-blue-600': !active && selected,
|
|
59
|
+
'bg-blue-600 text-white hover:bg-blue-700': active && selected,
|
|
60
|
+
}"
|
|
61
|
+
>
|
|
62
|
+
<p class="text-sm font-medium">{{ option.title }}</p>
|
|
63
|
+
<p class="opacity-60 text-xs">{{ option.owner?.name }}</p>
|
|
64
|
+
</div>
|
|
65
|
+
</template>
|
|
66
|
+
</BaseAutocompleteFetch>
|
|
67
|
+
`,
|
|
74
68
|
};
|
|
75
69
|
};
|
|
76
70
|
|
|
@@ -80,22 +74,24 @@ export const SlotFooter = (args) => {
|
|
|
80
74
|
setup() {
|
|
81
75
|
const value = ref(null);
|
|
82
76
|
function onClick() {
|
|
83
|
-
|
|
77
|
+
setTimeout(() => {
|
|
78
|
+
alert(1);
|
|
79
|
+
}, 150);
|
|
84
80
|
}
|
|
85
81
|
return { args, value, onClick };
|
|
86
82
|
},
|
|
87
83
|
template: `
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
84
|
+
<BaseAutocompleteFetch
|
|
85
|
+
v-model="value"
|
|
86
|
+
v-bind="args"
|
|
87
|
+
>
|
|
88
|
+
<template #footer>
|
|
89
|
+
<div class="text-center p-2 border-t">
|
|
90
|
+
<button @click=onClick class="btn btn-sm w-full btn-slate-200-outline">This is the footer 💯</button>
|
|
91
|
+
</div>
|
|
92
|
+
</template>
|
|
93
|
+
</BaseAutocompleteFetch>
|
|
94
|
+
`,
|
|
99
95
|
};
|
|
100
96
|
};
|
|
101
97
|
|
|
@@ -107,17 +103,23 @@ export const SlotEmpty = (args) => {
|
|
|
107
103
|
return { args, value };
|
|
108
104
|
},
|
|
109
105
|
template: `
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
106
|
+
<BaseAutocompleteFetch
|
|
107
|
+
v-model="value"
|
|
108
|
+
v-bind="args"
|
|
109
|
+
>
|
|
110
|
+
<template #empty="props">
|
|
111
|
+
<div>
|
|
112
|
+
<div v-if="props.firstSearch" class="text-center py-10 p-6">🤓🤓🤓</div>
|
|
113
|
+
<div v-else class="text-center p-6">Start your search... 🔎</div>
|
|
114
|
+
</div>
|
|
115
|
+
</template>
|
|
116
|
+
</BaseAutocompleteFetch>
|
|
117
|
+
`,
|
|
122
118
|
};
|
|
123
119
|
};
|
|
120
|
+
|
|
121
|
+
export const Field = createFieldStory({
|
|
122
|
+
component: BaseAutocompleteFetch,
|
|
123
|
+
componentName: 'BaseAutocompleteFetch',
|
|
124
|
+
label: 'Article',
|
|
125
|
+
});
|
|
@@ -4,11 +4,12 @@
|
|
|
4
4
|
:loading="showLoading && page == 1"
|
|
5
5
|
:model-value="modelValue"
|
|
6
6
|
:disabled="disabled"
|
|
7
|
+
:name="name"
|
|
7
8
|
:placeholder="placeholder"
|
|
8
9
|
:options="options"
|
|
9
10
|
:value-key="valueKey"
|
|
10
11
|
:label-key="labelKey"
|
|
11
|
-
:
|
|
12
|
+
:has-error="hasError"
|
|
12
13
|
:filter="() => true"
|
|
13
14
|
@clear="onClear"
|
|
14
15
|
@focus="onFocus"
|
|
@@ -21,27 +22,7 @@
|
|
|
21
22
|
</template>
|
|
22
23
|
|
|
23
24
|
<template #footer="footerProps">
|
|
24
|
-
<slot name="footer" v-bind="footerProps" :keywords="keywords"
|
|
25
|
-
<div
|
|
26
|
-
v-if="createNewUrl"
|
|
27
|
-
class="p-2"
|
|
28
|
-
:class="{
|
|
29
|
-
'border-t border-slate-300': footerProps.options.length > 0,
|
|
30
|
-
}"
|
|
31
|
-
>
|
|
32
|
-
<router-link
|
|
33
|
-
:to="createNewUrl"
|
|
34
|
-
target="_blank"
|
|
35
|
-
class="btn btn-slate-200-outline flex items-center justify-center"
|
|
36
|
-
>
|
|
37
|
-
<BaseIcon
|
|
38
|
-
icon="heroicons-solid:plus"
|
|
39
|
-
class="mr-1.5 block h-5 w-5"
|
|
40
|
-
/>
|
|
41
|
-
<span>{{ $t('sui.create_new') }}</span>
|
|
42
|
-
</router-link>
|
|
43
|
-
</div>
|
|
44
|
-
</slot>
|
|
25
|
+
<slot name="footer" v-bind="footerProps" :keywords="keywords" />
|
|
45
26
|
</template>
|
|
46
27
|
|
|
47
28
|
<template #empty="emptyProps">
|
|
@@ -58,11 +39,10 @@
|
|
|
58
39
|
</template>
|
|
59
40
|
|
|
60
41
|
<script lang="ts" setup>
|
|
61
|
-
import { config } from '
|
|
42
|
+
import { config } from '@/index';
|
|
62
43
|
import { debounce } from 'lodash';
|
|
63
44
|
import { PropType, Ref } from 'vue';
|
|
64
45
|
import { Option } from '@/types';
|
|
65
|
-
import { RouteLocationRaw } from 'vue-router';
|
|
66
46
|
import BaseAutocomplete from './BaseAutocomplete.vue';
|
|
67
47
|
|
|
68
48
|
const props = defineProps({
|
|
@@ -82,7 +62,7 @@ const props = defineProps({
|
|
|
82
62
|
required: true,
|
|
83
63
|
type: String,
|
|
84
64
|
},
|
|
85
|
-
|
|
65
|
+
name: {
|
|
86
66
|
default: undefined,
|
|
87
67
|
type: String,
|
|
88
68
|
},
|
|
@@ -98,14 +78,14 @@ const props = defineProps({
|
|
|
98
78
|
default: false,
|
|
99
79
|
type: Boolean,
|
|
100
80
|
},
|
|
101
|
-
createNewUrl: {
|
|
102
|
-
default: '',
|
|
103
|
-
type: [String, Object] as PropType<RouteLocationRaw>,
|
|
104
|
-
},
|
|
105
81
|
queryKey: {
|
|
106
82
|
default: 'search',
|
|
107
83
|
type: String,
|
|
108
84
|
},
|
|
85
|
+
hasError: {
|
|
86
|
+
default: false,
|
|
87
|
+
type: Boolean,
|
|
88
|
+
},
|
|
109
89
|
});
|
|
110
90
|
|
|
111
91
|
const emit = defineEmits([
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import BaseBelongsTo from './BaseBelongsTo.vue';
|
|
2
|
+
import ShowValue from '@/../.storybook/components/ShowValue.vue';
|
|
3
|
+
import { options } from '@/../.storybook/utils';
|
|
4
|
+
import { createFieldStory } from '../../.storybook/utils';
|
|
2
5
|
|
|
3
6
|
export default {
|
|
4
7
|
title: 'Form/BaseBelongsTo',
|
|
5
8
|
component: BaseBelongsTo,
|
|
6
|
-
argTypes: {},
|
|
7
9
|
args: {
|
|
8
10
|
url: 'https://effettandem.com/api/content/articles',
|
|
9
11
|
field: 'title',
|
|
@@ -11,45 +13,27 @@ export default {
|
|
|
11
13
|
decorators: [() => ({ template: '<div class="mb-36"><story/></div>' })],
|
|
12
14
|
};
|
|
13
15
|
|
|
14
|
-
const Template = (args) => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
></BaseBelongsTo>
|
|
26
|
-
<p class="mt-5 text-sm">Value: <span class="bg-slate-200 font-mono px-1 py-px rounded">{{ value ?? 'NULL' }}</span></p>
|
|
27
|
-
`,
|
|
28
|
-
};
|
|
29
|
-
};
|
|
16
|
+
const Template = (args) => ({
|
|
17
|
+
components: { BaseBelongsTo, ShowValue },
|
|
18
|
+
setup() {
|
|
19
|
+
const value = ref(null);
|
|
20
|
+
return { args, value };
|
|
21
|
+
},
|
|
22
|
+
template: `
|
|
23
|
+
<BaseBelongsTo v-model="value" v-bind="args"></BaseBelongsTo>
|
|
24
|
+
<ShowValue :value="value" />
|
|
25
|
+
`,
|
|
26
|
+
});
|
|
30
27
|
|
|
31
28
|
export const Demo = Template.bind({});
|
|
32
29
|
Demo.args = {};
|
|
33
30
|
|
|
34
|
-
export const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
return {
|
|
41
|
-
components: { BaseBelongsTo },
|
|
42
|
-
setup() {
|
|
43
|
-
const value = ref(null);
|
|
44
|
-
return { args, value };
|
|
45
|
-
},
|
|
46
|
-
template: `<BaseBelongsTo
|
|
47
|
-
v-bind="args"
|
|
48
|
-
v-model="value"
|
|
49
|
-
:current-model="{title: 'Dark Vader', id: 1}"
|
|
50
|
-
:disabled="true"
|
|
51
|
-
></BaseBelongsTo>`,
|
|
52
|
-
};
|
|
31
|
+
export const Disabled = Template.bind({});
|
|
32
|
+
Disabled.args = {
|
|
33
|
+
currentModel: options[0],
|
|
34
|
+
primaryKey: 'value',
|
|
35
|
+
field: 'label',
|
|
36
|
+
disabled: true,
|
|
53
37
|
};
|
|
54
38
|
|
|
55
39
|
export const SlotOption = (args) => {
|
|
@@ -60,28 +44,26 @@ export const SlotOption = (args) => {
|
|
|
60
44
|
return { args, value };
|
|
61
45
|
},
|
|
62
46
|
template: `
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
</
|
|
81
|
-
</
|
|
82
|
-
|
|
83
|
-
</div>
|
|
84
|
-
`,
|
|
47
|
+
<BaseBelongsTo
|
|
48
|
+
v-model="value"
|
|
49
|
+
v-bind="args"
|
|
50
|
+
>
|
|
51
|
+
<template #option="{ option, active, selected }">
|
|
52
|
+
<div
|
|
53
|
+
class="rounded px-2 py-1"
|
|
54
|
+
:class="{
|
|
55
|
+
'hover:bg-slate-100': !active && !selected,
|
|
56
|
+
'bg-slate-200 hover:bg-slate-300': active && !selected,
|
|
57
|
+
'bg-blue-500 text-white hover:bg-blue-600': !active && selected,
|
|
58
|
+
'bg-blue-600 text-white hover:bg-blue-700': active && selected,
|
|
59
|
+
}"
|
|
60
|
+
>
|
|
61
|
+
<p class="text-sm font-medium">{{ option.title }}</p>
|
|
62
|
+
<p class="opacity-60 text-xs">{{ option.owner?.name }}</p>
|
|
63
|
+
</div>
|
|
64
|
+
</template>
|
|
65
|
+
</BaseBelongsTo>
|
|
66
|
+
`,
|
|
85
67
|
};
|
|
86
68
|
};
|
|
87
69
|
|
|
@@ -91,22 +73,24 @@ export const SlotFooter = (args) => {
|
|
|
91
73
|
setup() {
|
|
92
74
|
const value = ref(null);
|
|
93
75
|
function onClick() {
|
|
94
|
-
|
|
76
|
+
setTimeout(() => {
|
|
77
|
+
alert(1);
|
|
78
|
+
}, 150);
|
|
95
79
|
}
|
|
96
80
|
return { args, value, onClick };
|
|
97
81
|
},
|
|
98
82
|
template: `
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
83
|
+
<BaseBelongsTo
|
|
84
|
+
v-model="value"
|
|
85
|
+
v-bind="args"
|
|
86
|
+
>
|
|
87
|
+
<template #footer>
|
|
88
|
+
<div class="text-center p-2 border-t">
|
|
89
|
+
<button @click=onClick class="btn btn-sm w-full btn-slate-200-outline">This is the footer 💯</button>
|
|
90
|
+
</div>
|
|
91
|
+
</template>
|
|
92
|
+
</BaseBelongsTo>
|
|
93
|
+
`,
|
|
110
94
|
};
|
|
111
95
|
};
|
|
112
96
|
|
|
@@ -118,17 +102,23 @@ export const SlotEmpty = (args) => {
|
|
|
118
102
|
return { args, value };
|
|
119
103
|
},
|
|
120
104
|
template: `
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
105
|
+
<BaseBelongsTo
|
|
106
|
+
v-model="value"
|
|
107
|
+
v-bind="args"
|
|
108
|
+
>
|
|
109
|
+
<template #empty="props">
|
|
110
|
+
<div>
|
|
111
|
+
<div v-if="props.firstSearch" class="text-center py-10 p-6">🤓🤓🤓</div>
|
|
112
|
+
<div v-else class="text-center p-6">Start your search... 🔎</div>
|
|
113
|
+
</div>
|
|
114
|
+
</template>
|
|
115
|
+
</BaseBelongsTo>
|
|
116
|
+
`,
|
|
133
117
|
};
|
|
134
118
|
};
|
|
119
|
+
|
|
120
|
+
export const Field = createFieldStory({
|
|
121
|
+
component: BaseBelongsTo,
|
|
122
|
+
componentName: 'BaseBelongsTo',
|
|
123
|
+
label: 'Article',
|
|
124
|
+
});
|
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
:model-value="model"
|
|
4
4
|
:url="url"
|
|
5
5
|
:disabled="disabled"
|
|
6
|
+
:name="name"
|
|
6
7
|
:placeholder="placeholder"
|
|
7
8
|
:required="required"
|
|
8
|
-
:value-key="
|
|
9
|
+
:value-key="primaryKey"
|
|
9
10
|
:label-key="field"
|
|
10
|
-
:
|
|
11
|
-
:input-class="inputClass"
|
|
11
|
+
:has-error="hasError"
|
|
12
12
|
@update:model-value="onUpdate"
|
|
13
13
|
>
|
|
14
14
|
<template #option="optionProps">
|
|
@@ -25,7 +25,6 @@
|
|
|
25
25
|
|
|
26
26
|
<script lang="ts" setup>
|
|
27
27
|
import { PropType } from 'vue';
|
|
28
|
-
import { RouteLocationRaw } from 'vue-router';
|
|
29
28
|
import { AxiosResponse } from 'axios';
|
|
30
29
|
import { config } from '@/index';
|
|
31
30
|
import BaseAutocompleteFetch from './BaseAutocompleteFetch.vue';
|
|
@@ -46,7 +45,7 @@ const props = defineProps({
|
|
|
46
45
|
default: undefined,
|
|
47
46
|
type: Function as PropType<((id: string | number) => string) | undefined>,
|
|
48
47
|
},
|
|
49
|
-
|
|
48
|
+
primaryKey: {
|
|
50
49
|
default: 'id',
|
|
51
50
|
type: String,
|
|
52
51
|
},
|
|
@@ -62,11 +61,11 @@ const props = defineProps({
|
|
|
62
61
|
default: false,
|
|
63
62
|
type: Boolean,
|
|
64
63
|
},
|
|
65
|
-
|
|
64
|
+
name: {
|
|
66
65
|
default: undefined,
|
|
67
66
|
type: String,
|
|
68
67
|
},
|
|
69
|
-
|
|
68
|
+
placeholder: {
|
|
70
69
|
default: undefined,
|
|
71
70
|
type: String,
|
|
72
71
|
},
|
|
@@ -74,9 +73,9 @@ const props = defineProps({
|
|
|
74
73
|
default: null,
|
|
75
74
|
type: [Object, null] as PropType<Option | null>,
|
|
76
75
|
},
|
|
77
|
-
|
|
78
|
-
default:
|
|
79
|
-
type:
|
|
76
|
+
hasError: {
|
|
77
|
+
default: false,
|
|
78
|
+
type: Boolean,
|
|
80
79
|
},
|
|
81
80
|
});
|
|
82
81
|
|
|
@@ -126,7 +125,7 @@ function onUpdate(newModel: Option | null) {
|
|
|
126
125
|
emit('update:modelValue', null);
|
|
127
126
|
} else {
|
|
128
127
|
model.value = newModel;
|
|
129
|
-
emit('update:modelValue', newModel[props.
|
|
128
|
+
emit('update:modelValue', newModel[props.primaryKey]);
|
|
130
129
|
}
|
|
131
130
|
}
|
|
132
131
|
</script>
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { createFieldStory, options } from '../../.storybook/utils';
|
|
1
2
|
import BaseButtonGroup from './BaseButtonGroup.vue';
|
|
3
|
+
import ShowValue from '../../.storybook/components/ShowValue.vue';
|
|
2
4
|
|
|
3
5
|
export default {
|
|
4
6
|
title: 'Form/BaseButtonGroup',
|
|
@@ -7,27 +9,20 @@ export default {
|
|
|
7
9
|
args: {
|
|
8
10
|
labelKey: 'label',
|
|
9
11
|
valueKey: 'value',
|
|
10
|
-
options:
|
|
11
|
-
{ label: 'Dark Vader', value: 'dark_vader' },
|
|
12
|
-
{ label: 'Darth Maul', value: 'darth_maul' },
|
|
13
|
-
{ label: 'Dark Sidious', value: 'dark_sidious' },
|
|
14
|
-
{ label: 'Obi Wan Kenobi', value: 'obiwan' },
|
|
15
|
-
{ label: 'Anakin Skywalker', value: 'anakin' },
|
|
16
|
-
{ label: 'Mace Windu', value: 'windu' },
|
|
17
|
-
],
|
|
12
|
+
options: options,
|
|
18
13
|
},
|
|
19
14
|
decorators: [() => ({ template: '<div class="mb-36"><story/></div>' })],
|
|
20
15
|
};
|
|
21
16
|
|
|
22
17
|
const Template = (args) => ({
|
|
23
|
-
components: { BaseButtonGroup },
|
|
18
|
+
components: { BaseButtonGroup, ShowValue },
|
|
24
19
|
setup() {
|
|
25
20
|
const value = ref(null);
|
|
26
21
|
return { args, value };
|
|
27
22
|
},
|
|
28
23
|
template: `
|
|
29
24
|
<BaseButtonGroup v-model="value" v-bind="args"></BaseButtonGroup>
|
|
30
|
-
<
|
|
25
|
+
<ShowValue :value="value"></ShowValue>
|
|
31
26
|
`,
|
|
32
27
|
});
|
|
33
28
|
|
|
@@ -82,3 +77,9 @@ export const SlotOption = (args) => ({
|
|
|
82
77
|
</BaseButtonGroup>
|
|
83
78
|
`,
|
|
84
79
|
});
|
|
80
|
+
|
|
81
|
+
export const Field = createFieldStory({
|
|
82
|
+
component: BaseButtonGroup,
|
|
83
|
+
componentName: 'BaseButtonGroup',
|
|
84
|
+
label: 'Choose your Jedi ou Sith',
|
|
85
|
+
});
|