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.
Files changed (89) hide show
  1. package/dist/sprintify-ui.es.js +6033 -5518
  2. package/dist/types/src/components/BaseAutocomplete.vue.d.ts +32 -12
  3. package/dist/types/src/components/BaseAutocompleteFetch.vue.d.ts +28 -28
  4. package/dist/types/src/components/BaseBelongsTo.vue.d.ts +35 -35
  5. package/dist/types/src/components/BaseButtonGroup.vue.d.ts +46 -8
  6. package/dist/types/src/components/BaseDatePicker.vue.d.ts +18 -9
  7. package/dist/types/src/components/BaseDateSelect.vue.d.ts +14 -5
  8. package/dist/types/src/components/BaseField.vue.d.ts +151 -0
  9. package/dist/types/src/components/BaseFieldI18n.vue.d.ts +93 -0
  10. package/dist/types/src/components/BaseForm.vue.d.ts +267 -0
  11. package/dist/types/src/components/BaseFormField.d.ts +81 -0
  12. package/dist/types/src/components/BaseHasMany.vue.d.ts +31 -31
  13. package/dist/types/src/components/BaseInput.vue.d.ts +1 -1
  14. package/dist/types/src/components/BaseInputError.vue.d.ts +48 -0
  15. package/dist/types/src/components/BaseInputPercent.vue.d.ts +1 -1
  16. package/dist/types/src/components/BaseLocaleForm.vue.d.ts +420 -0
  17. package/dist/types/src/components/BaseMediaLibrary.vue.d.ts +46 -24
  18. package/dist/types/src/components/BaseNumberForm.vue.d.ts +382 -0
  19. package/dist/types/src/components/BasePassword.vue.d.ts +10 -14
  20. package/dist/types/src/components/BasePasswordForm.vue.d.ts +365 -0
  21. package/dist/types/src/components/BaseRadioGroup.vue.d.ts +23 -4
  22. package/dist/types/src/components/BaseSelect.vue.d.ts +20 -1
  23. package/dist/types/src/components/BaseSwitch.vue.d.ts +155 -23
  24. package/dist/types/src/components/BaseTagAutocomplete.vue.d.ts +31 -12
  25. package/dist/types/src/components/BaseTagAutocompleteFetch.vue.d.ts +20 -20
  26. package/dist/types/src/components/BaseTextarea.vue.d.ts +9 -0
  27. package/dist/types/src/components/BaseTextareaAutoresize.vue.d.ts +18 -0
  28. package/dist/types/src/components/BaseTextareaForm.vue.d.ts +394 -0
  29. package/dist/types/src/components/index.d.ts +4 -1
  30. package/dist/types/src/composables/field.d.ts +17 -0
  31. package/dist/types/src/index.d.ts +3 -0
  32. package/dist/types/src/types/index.d.ts +11 -0
  33. package/package.json +4 -1
  34. package/src/components/BaseAutocomplete.stories.js +56 -51
  35. package/src/components/BaseAutocomplete.vue +25 -8
  36. package/src/components/BaseAutocompleteFetch.stories.js +67 -65
  37. package/src/components/BaseAutocompleteFetch.vue +9 -29
  38. package/src/components/BaseBelongsTo.stories.js +72 -82
  39. package/src/components/BaseBelongsTo.vue +10 -11
  40. package/src/components/BaseButtonGroup.stories.js +11 -10
  41. package/src/components/BaseButtonGroup.vue +22 -9
  42. package/src/components/BaseCharacterCounter.stories.js +1 -1
  43. package/src/components/BaseDatePicker.stories.js +13 -9
  44. package/src/components/BaseDatePicker.vue +25 -8
  45. package/src/components/BaseDateSelect.stories.js +15 -9
  46. package/src/components/BaseDateSelect.vue +20 -8
  47. package/src/components/BaseField.vue +109 -0
  48. package/src/components/BaseFieldI18n.stories.js +38 -0
  49. package/src/components/BaseFieldI18n.vue +162 -0
  50. package/src/components/BaseFileUploader.stories.js +3 -3
  51. package/src/components/BaseFileUploader.vue +3 -3
  52. package/src/components/BaseForm.vue +298 -0
  53. package/src/components/BaseFormField.ts +117 -0
  54. package/src/components/BaseHasMany.stories.js +25 -10
  55. package/src/components/BaseHasMany.vue +9 -9
  56. package/src/components/BaseInput.stories.js +27 -14
  57. package/src/components/BaseInput.vue +17 -8
  58. package/src/components/BaseInputError.vue +7 -0
  59. package/src/components/BaseInputPercent.stories.js +10 -3
  60. package/src/components/BaseInputPercent.vue +2 -1
  61. package/src/components/BaseLocaleForm.vue +142 -0
  62. package/src/components/BaseMediaLibrary.stories.js +7 -6
  63. package/src/components/BaseMediaLibrary.vue +32 -31
  64. package/src/components/BaseMenu.vue +1 -1
  65. package/src/components/BaseNumberForm.vue +67 -0
  66. package/src/components/BasePassword.stories.js +9 -4
  67. package/src/components/BasePassword.vue +49 -44
  68. package/src/components/BasePasswordForm.vue +59 -0
  69. package/src/components/BaseRadioGroup.stories.js +9 -8
  70. package/src/components/BaseRadioGroup.vue +17 -3
  71. package/src/components/BaseSelect.stories.js +15 -2
  72. package/src/components/BaseSelect.vue +26 -10
  73. package/src/components/BaseSwitch.stories.js +7 -0
  74. package/src/components/BaseSwitch.vue +134 -124
  75. package/src/components/BaseTagAutocomplete.stories.js +21 -14
  76. package/src/components/BaseTagAutocomplete.vue +25 -14
  77. package/src/components/BaseTagAutocompleteFetch.stories.js +37 -21
  78. package/src/components/BaseTagAutocompleteFetch.vue +5 -5
  79. package/src/components/BaseTextarea.stories.js +11 -3
  80. package/src/components/BaseTextarea.vue +20 -6
  81. package/src/components/BaseTextareaAutoresize.stories.js +11 -2
  82. package/src/components/BaseTextareaAutoresize.vue +28 -4
  83. package/src/components/BaseTextareaForm.vue +101 -0
  84. package/src/components/BaseTimeline.vue +1 -1
  85. package/src/components/BaseTimelineItem.vue +4 -4
  86. package/src/components/index.ts +6 -0
  87. package/src/composables/field.ts +100 -0
  88. package/src/index.ts +11 -1
  89. package/src/types/index.ts +12 -0
@@ -0,0 +1,298 @@
1
+ <template>
2
+ <form ref="form" class="relative" @submit.prevent="submit()">
3
+ <slot
4
+ :errors="errors"
5
+ :loading="loading"
6
+ :disabled="disabled"
7
+ :submit="submit"
8
+ />
9
+
10
+ <transition
11
+ enter-active-class="transition duration-100 ease-out"
12
+ enter-from-class="opacity-0"
13
+ enter-to-class="opacity-100"
14
+ leave-active-class="transition duration-200 ease-in"
15
+ leave-from-class="opacity-100"
16
+ leave-to-class="opacity-0"
17
+ >
18
+ <slot v-if="loading" name="loading">
19
+ <div
20
+ class="absolute inset-0 flex h-full w-full items-center justify-center"
21
+ >
22
+ <div
23
+ class="absolute inset-0 h-full w-full opacity-80"
24
+ :class="loadingMaskClass"
25
+ />
26
+ <svg
27
+ class="relative h-6 w-6 animate-spin text-blue-600"
28
+ viewBox="0 0 24 24"
29
+ >
30
+ <path
31
+ fill="currentColor"
32
+ d="M12,4V2A10,10 0 0,0 2,12H4A8,8 0 0,1 12,4Z"
33
+ />
34
+ </svg>
35
+ </div>
36
+ </slot>
37
+ </transition>
38
+ </form>
39
+ </template>
40
+
41
+ <script lang="ts" setup>
42
+ import { PropType, Ref } from 'vue';
43
+ import { serialize } from 'object-to-formdata';
44
+ import { Method, DataFormat } from '@/types';
45
+ import { AxiosError, AxiosInstance, AxiosResponse } from 'axios';
46
+ import { config, useNotificationsStore } from '@/index';
47
+ import { isArray } from 'lodash';
48
+
49
+ const notifications = useNotificationsStore();
50
+
51
+ type NextFunction = () => void;
52
+
53
+ const props = defineProps({
54
+ url: {
55
+ required: true,
56
+ type: String,
57
+ },
58
+ method: {
59
+ required: true,
60
+ type: String as PropType<Method>,
61
+ validator: (value: string) => {
62
+ return Object.values(Method).includes(value as Method);
63
+ },
64
+ },
65
+ data: {
66
+ required: true,
67
+ type: Object as PropType<Record<string, any>>,
68
+ },
69
+ axiosInstance: {
70
+ default: null,
71
+ type: Object as PropType<AxiosInstance | null>,
72
+ },
73
+ format: {
74
+ type: String as PropType<DataFormat>,
75
+ default: DataFormat.json,
76
+ validator: (value: string) => {
77
+ return Object.values(DataFormat).includes(value as DataFormat);
78
+ },
79
+ },
80
+ beforeSubmit: {
81
+ default: (next: NextFunction) => {
82
+ next();
83
+ },
84
+ type: Function as PropType<(next: NextFunction) => void>,
85
+ },
86
+ successHandler: {
87
+ default: undefined,
88
+ type: Function as PropType<(response: any) => void>,
89
+ },
90
+ errorHandler: {
91
+ default: (error: AxiosError) => {
92
+ error;
93
+ },
94
+ type: Function as PropType<(error: AxiosError) => void>,
95
+ },
96
+ loadingMaskClass: {
97
+ default: 'bg-white',
98
+ type: String,
99
+ },
100
+ });
101
+
102
+ const i18n = useI18n();
103
+ const emit = defineEmits(['error', 'success']);
104
+
105
+ const form = ref(null) as Ref<null | HTMLFormElement>;
106
+ const loading = ref(false);
107
+ const disabled = ref(false);
108
+ const errors = ref({}) as Ref<Record<string, string[]>>;
109
+
110
+ const httpClient = computed((): AxiosInstance => {
111
+ if (props.axiosInstance) {
112
+ return props.axiosInstance;
113
+ }
114
+
115
+ return config.http;
116
+ });
117
+
118
+ const htmlFormElement = computed((): HTMLFormElement | null => {
119
+ return form.value;
120
+ });
121
+
122
+ const hasErrors = computed((): boolean => {
123
+ return Object.keys(errors.value).length > 0;
124
+ });
125
+
126
+ const elementWithError = computed((): HTMLElement | null => {
127
+ if (!hasErrors.value) {
128
+ return null;
129
+ }
130
+
131
+ const keys = Object.keys(errors.value);
132
+
133
+ for (let i = 0; i < keys.length; i++) {
134
+ const name = keys[i];
135
+ const element = findElementByName(name);
136
+ if (element) {
137
+ return element;
138
+ }
139
+ }
140
+
141
+ return null;
142
+ });
143
+
144
+ function findElementByName(name: string): HTMLElement | null {
145
+ let el = htmlFormElement.value?.querySelector(`[name='${name}']`) as
146
+ | HTMLElement
147
+ | undefined;
148
+ if (el) {
149
+ return el;
150
+ }
151
+
152
+ el = htmlFormElement.value?.querySelector(`[data-name='${name}']`) as
153
+ | HTMLElement
154
+ | undefined;
155
+
156
+ if (el) {
157
+ return el;
158
+ }
159
+
160
+ return null;
161
+ }
162
+
163
+ function submit() {
164
+ props.beforeSubmit(query);
165
+ }
166
+
167
+ function query() {
168
+ if (loading.value) {
169
+ return;
170
+ }
171
+
172
+ loading.value = true;
173
+
174
+ let method = props.method as Method;
175
+ let data = props.data;
176
+ let headers = { 'Content-Type': 'application/json' };
177
+
178
+ if (props.format == 'formData') {
179
+ method = Method.post;
180
+
181
+ data = serialize(props.data, {
182
+ nullsAsUndefineds: false,
183
+ booleansAsIntegers: true,
184
+ allowEmptyArrays: true,
185
+ });
186
+
187
+ if (props.method !== Method.post) {
188
+ data.append('_method', props.method);
189
+ }
190
+
191
+ headers = {
192
+ 'Content-Type': 'multipart/form-data',
193
+ };
194
+ }
195
+
196
+ httpClient.value[method](props.url, data, { headers: headers })
197
+ .then((response) => {
198
+ loading.value = false;
199
+
200
+ errors.value = {};
201
+
202
+ successHandler(response);
203
+
204
+ emit('success', response);
205
+ })
206
+ .catch((error: AxiosError<AxiosResponse<any>>) => {
207
+ console.error(error);
208
+
209
+ loading.value = false;
210
+
211
+ if (error.response && error.response.status == 422) {
212
+ loadErrors(error);
213
+ }
214
+
215
+ props.errorHandler(error);
216
+
217
+ emit('error', error);
218
+ });
219
+ }
220
+
221
+ function successHandler(response: AxiosResponse<any, any>) {
222
+ if (props.successHandler) {
223
+ props.successHandler(response);
224
+ } else {
225
+ const message = response.data.message ?? ('' as string);
226
+
227
+ if (!message) {
228
+ return;
229
+ }
230
+
231
+ notifications.push({
232
+ color: 'success',
233
+ title: i18n.t('sui.success'),
234
+ text: message,
235
+ });
236
+ }
237
+ }
238
+
239
+ function loadErrors(error: AxiosError): void {
240
+ errors.value = error?.response?.data.errors ?? {};
241
+
242
+ if (elementWithError.value) {
243
+ elementWithError.value.scrollIntoView({
244
+ behavior: 'smooth',
245
+ block: 'center',
246
+ });
247
+ }
248
+ }
249
+
250
+ function getErrorMessageByName(name: string): string | null {
251
+ if (!errors.value[name]) {
252
+ return null;
253
+ }
254
+
255
+ if (!isArray(errors.value[name])) {
256
+ return null;
257
+ }
258
+
259
+ if (errors.value[name].length == 0) {
260
+ return null;
261
+ }
262
+
263
+ return errors.value[name][0];
264
+ }
265
+
266
+ function clearErrors(name = null): void {
267
+ if (name == null) {
268
+ errors.value = {};
269
+ } else {
270
+ delete errors.value[name];
271
+ }
272
+ }
273
+
274
+ function disabledForm() {
275
+ disabled.value = true;
276
+ }
277
+
278
+ function enableForm() {
279
+ disabled.value = false;
280
+ }
281
+
282
+ provide('form:errors', readonly(errors));
283
+ provide('form:getErrorMessageByName', getErrorMessageByName);
284
+ provide('form:clearErrors', clearErrors);
285
+
286
+ provide('form:disabled', readonly(disabled));
287
+ provide('form:enable', enableForm);
288
+ provide('form:disable', disabledForm);
289
+
290
+ defineExpose({
291
+ submit,
292
+ errors,
293
+ hasErrors,
294
+ clearErrors,
295
+ disabled,
296
+ loading,
297
+ });
298
+ </script>
@@ -0,0 +1,117 @@
1
+ import { defineComponent } from 'vue';
2
+ import BaseForm from './BaseForm.vue';
3
+
4
+ export default defineComponent({
5
+ props: {
6
+ name: {
7
+ required: true,
8
+ type: String,
9
+ },
10
+ placeholder: {
11
+ default: '',
12
+ type: String,
13
+ },
14
+ label: {
15
+ default: '',
16
+ type: String,
17
+ },
18
+ disabled: {
19
+ type: Boolean,
20
+ default: false,
21
+ },
22
+ required: {
23
+ default: false,
24
+ type: Boolean,
25
+ },
26
+ autofocus: {
27
+ default: false,
28
+ type: Boolean,
29
+ },
30
+ preventSubmit: {
31
+ default: false,
32
+ type: Boolean,
33
+ },
34
+ },
35
+ emits: ['update:modelValue'],
36
+ computed: {
37
+ form(): typeof BaseForm | null {
38
+ let parent = this.$parent;
39
+ for (let i = 0; i < 20; i++) {
40
+ if (parent == null) {
41
+ throw new Error(
42
+ 'A BaseForm field component must be in a BaseForm component'
43
+ );
44
+ }
45
+ if (parent.$options.__name == 'BaseForm') {
46
+ return parent as unknown as typeof BaseForm;
47
+ }
48
+ parent = parent.$parent;
49
+ }
50
+ return null;
51
+ },
52
+ errors() {
53
+ if (!this.form) {
54
+ return {};
55
+ }
56
+
57
+ return this.form.errors;
58
+ },
59
+ labelValue(): string {
60
+ if (this.label != '' && this.label != null && this.label != undefined) {
61
+ return this.label;
62
+ }
63
+
64
+ if (this.label === '') {
65
+ return '';
66
+ }
67
+
68
+ if (this.$te(this.name)) {
69
+ return this.$t(this.name);
70
+ }
71
+
72
+ return this.name;
73
+ },
74
+ },
75
+ methods: {
76
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
77
+ inputListener(payload: any) {
78
+ this.clearErrors();
79
+ this.$emit('update:modelValue', payload);
80
+ },
81
+ errorMessage(name: string | null = null) {
82
+ if (name == null) {
83
+ name = this.name;
84
+ }
85
+ if (this.hasError(name)) {
86
+ return this.errors[name][0];
87
+ }
88
+ return null;
89
+ },
90
+ hasError(name: string | null = null) {
91
+ if (name == null) {
92
+ name = this.name;
93
+ }
94
+ return (
95
+ Object.keys(this.errors).length > 0 &&
96
+ Object.prototype.hasOwnProperty.call(this.errors, name) &&
97
+ this.errors[name].length > 0
98
+ );
99
+ },
100
+ clearErrors(name: string | null = null) {
101
+ if (name == null) {
102
+ name = this.name;
103
+ }
104
+ this.form?.clearErrors(name);
105
+ },
106
+ disableForm() {
107
+ if (this.form) {
108
+ this.form.disabled = true;
109
+ }
110
+ },
111
+ enableForm() {
112
+ if (this.form) {
113
+ this.form.disabled = false;
114
+ }
115
+ },
116
+ },
117
+ });
@@ -1,4 +1,7 @@
1
1
  import BaseHasMany from './BaseHasMany.vue';
2
+ import ShowValue from '@/../.storybook/components/ShowValue.vue';
3
+ import { createFieldStory, options } from '../../.storybook/utils';
4
+ import BaseAppNotifications from './BaseAppNotifications.vue';
2
5
 
3
6
  export default {
4
7
  title: 'Form/BaseHasMany',
@@ -7,14 +10,14 @@ export default {
7
10
  args: {
8
11
  url: 'https://effettandem.com/api/content/articles',
9
12
  field: 'title',
10
- foreignKey: 'id',
13
+ primaryKey: 'id',
11
14
  },
12
15
  decorators: [() => ({ template: '<div class="mb-36"><story/></div>' })],
13
16
  };
14
17
 
15
18
  const Template = (args) => {
16
19
  return {
17
- components: { BaseHasMany },
20
+ components: { BaseHasMany, ShowValue, BaseAppNotifications },
18
21
  setup() {
19
22
  const value = ref([]);
20
23
  return { args, value };
@@ -24,7 +27,8 @@ const Template = (args) => {
24
27
  v-model="value"
25
28
  v-bind="args"
26
29
  ></BaseHasMany>
27
- <p class="mt-5 text-sm">Value: <span class="bg-slate-200 font-mono px-1 py-px rounded">{{ value ?? '[]' }}</span></p>
30
+ <ShowValue :value="value" />
31
+ <BaseAppNotifications />
28
32
  `,
29
33
  };
30
34
  };
@@ -37,13 +41,16 @@ export const Disabled = (args) => {
37
41
  components: { BaseHasMany },
38
42
  setup() {
39
43
  const value = ref([]);
40
- return { args, value };
44
+ const currentModel = options[0];
45
+ return { args, value, currentModel };
41
46
  },
42
47
  template: `<BaseHasMany
43
48
  v-bind="args"
44
49
  v-model="value"
45
- :current-models="[{title: 'Dark Vader', id: 1}]"
50
+ :current-models="[currentModel]"
46
51
  :disabled="true"
52
+ primaryKey="value"
53
+ field="label"
47
54
  ></BaseHasMany>`,
48
55
  };
49
56
  };
@@ -55,7 +62,7 @@ Maximum.args = {
55
62
 
56
63
  export const SlotOption = (args) => {
57
64
  return {
58
- components: { BaseHasMany },
65
+ components: {},
59
66
  setup() {
60
67
  const value = ref([]);
61
68
  return { args, value };
@@ -88,11 +95,13 @@ export const SlotOption = (args) => {
88
95
 
89
96
  export const SlotFooter = (args) => {
90
97
  return {
91
- components: { BaseHasMany },
98
+ components: {},
92
99
  setup() {
93
100
  const value = ref([]);
94
101
  function onClick() {
95
- alert(1);
102
+ setTimeout(() => {
103
+ alert(1);
104
+ }, 300);
96
105
  }
97
106
  return { args, value, onClick };
98
107
  },
@@ -103,7 +112,7 @@ export const SlotFooter = (args) => {
103
112
  >
104
113
  <template #footer>
105
114
  <div class="text-center p-2 border-t">
106
- <button @click=onClick class="btn btn-sm w-full btn-slate-200-outline">This is the footer 💯</button>
115
+ <button type="button" @click=onClick class="btn btn-sm w-full btn-slate-200-outline">This is the footer 💯</button>
107
116
  </div>
108
117
  </template>
109
118
  </BaseHasMany>
@@ -113,7 +122,7 @@ export const SlotFooter = (args) => {
113
122
 
114
123
  export const SlotEmpty = (args) => {
115
124
  return {
116
- components: { BaseHasMany },
125
+ components: {},
117
126
  setup() {
118
127
  const value = ref([]);
119
128
  return { args, value };
@@ -133,3 +142,9 @@ export const SlotEmpty = (args) => {
133
142
  `,
134
143
  };
135
144
  };
145
+
146
+ export const Field = createFieldStory({
147
+ component: BaseHasMany,
148
+ componentName: 'BaseHasMany',
149
+ label: 'Name',
150
+ });
@@ -5,9 +5,9 @@
5
5
  :disabled="disabled"
6
6
  :placeholder="placeholder"
7
7
  :required="required"
8
- :value-key="foreignKey"
8
+ :value-key="primaryKey"
9
9
  :label-key="field"
10
- :input-class="inputClass"
10
+ :has-error="hasError"
11
11
  :query-key="queryKey"
12
12
  :max="max"
13
13
  @update:model-value="onUpdate"
@@ -32,13 +32,13 @@ import BaseTagAutocompleteFetch from './BaseTagAutocompleteFetch.vue';
32
32
  const props = defineProps({
33
33
  modelValue: {
34
34
  required: true,
35
- type: Array as PropType<Option[]>,
35
+ type: [Array, null] as PropType<Option[] | null>,
36
36
  },
37
37
  url: {
38
38
  required: true,
39
39
  type: String,
40
40
  },
41
- foreignKey: {
41
+ primaryKey: {
42
42
  default: 'id',
43
43
  type: String,
44
44
  },
@@ -58,10 +58,6 @@ const props = defineProps({
58
58
  default: undefined,
59
59
  type: String,
60
60
  },
61
- inputClass: {
62
- default: undefined,
63
- type: String,
64
- },
65
61
  max: {
66
62
  default: undefined,
67
63
  type: Number,
@@ -76,6 +72,10 @@ const props = defineProps({
76
72
  },
77
73
  type: Array as PropType<Option[]>,
78
74
  },
75
+ hasError: {
76
+ default: false,
77
+ type: Boolean,
78
+ },
79
79
  });
80
80
 
81
81
  const emit = defineEmits(['update:modelValue']);
@@ -94,7 +94,7 @@ function onUpdate(newModels: Option[]) {
94
94
  models.value = newModels;
95
95
  emit(
96
96
  'update:modelValue',
97
- newModels.map((m) => m[props.foreignKey])
97
+ newModels.map((m) => m[props.primaryKey])
98
98
  );
99
99
  }
100
100
  </script>
@@ -1,34 +1,38 @@
1
1
  import BaseInput from './BaseInput.vue';
2
+ import ShowValue from '@/../.storybook/components/ShowValue.vue';
3
+ import { createFieldStory } from '@/../.storybook/utils';
2
4
 
3
5
  export default {
4
6
  title: 'Form/BaseInput',
5
7
  component: BaseInput,
8
+ decorators: [
9
+ (story) => ({
10
+ components: { story },
11
+ template: `
12
+ <form @submit.prevent="" class="border-none">
13
+ <story/>
14
+ </form>`,
15
+ }),
16
+ ],
6
17
  args: {
7
- required: true,
8
18
  type: 'text',
9
- name: 'name',
19
+ placeholder: 'Enter your name',
10
20
  },
11
21
  };
12
22
 
13
23
  const Template = (args) => ({
14
- components: {
15
- BaseInput,
16
- },
24
+ components: { BaseInput, ShowValue },
17
25
  setup() {
18
- const value = ref('');
26
+ const value = ref(null);
19
27
  return { args, value };
20
28
  },
21
29
  template: `
22
- <form @submit.prevent="" class="border-none">
23
- <BaseInput v-model="value" v-bind="args"></BaseInput>
24
- </form>
30
+ <BaseInput v-model="value" v-bind="args" class="w-full"></BaseInput>
31
+ <ShowValue :value="value" />
25
32
  `,
26
33
  });
27
34
 
28
35
  export const Demo = Template.bind({});
29
- Demo.args = {
30
- placeholder: 'Enter your name',
31
- };
32
36
 
33
37
  export const IconLeft = Template.bind({});
34
38
  IconLeft.args = {
@@ -74,7 +78,11 @@ export const Disabled = Template.bind({});
74
78
  Disabled.args = {
75
79
  modelValue: 'Disabled input!',
76
80
  disabled: true,
77
- placeholder: 'Enter your name',
81
+ };
82
+
83
+ export const Required = Template.bind({});
84
+ Required.args = {
85
+ required: true,
78
86
  };
79
87
 
80
88
  export const Error = Template.bind({});
@@ -82,5 +90,10 @@ Error.args = {
82
90
  hasError: true,
83
91
  prefix: 'Price',
84
92
  iconRight: 'heroicons:currency-dollar',
85
- placeholder: 'Enter your name',
86
93
  };
94
+
95
+ export const Field = createFieldStory({
96
+ component: BaseInput,
97
+ componentName: 'BaseInput',
98
+ label: 'Name',
99
+ });