sprintify-ui 0.6.32 → 0.6.34

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 (93) hide show
  1. package/dist/sprintify-ui.es.js +13449 -13183
  2. package/dist/style.css +1 -1
  3. package/dist/tailwindcss/button.js +261 -0
  4. package/dist/tailwindcss/index.js +16 -301
  5. package/dist/tailwindcss/input.js +24 -0
  6. package/dist/tailwindcss/overlay.js +13 -0
  7. package/dist/tailwindcss/theme.js +46 -0
  8. package/dist/types/src/components/BaseActionItemButton.vue.d.ts +2 -2
  9. package/dist/types/src/components/BaseAddressForm.vue.d.ts +10 -0
  10. package/dist/types/src/components/BaseAutocomplete.vue.d.ts +10 -10
  11. package/dist/types/src/components/BaseAutocompleteDrawer.vue.d.ts +3 -3
  12. package/dist/types/src/components/BaseAutocompleteFetch.vue.d.ts +6 -6
  13. package/dist/types/src/components/BaseAvatarGroup.vue.d.ts +1 -1
  14. package/dist/types/src/components/BaseBelongsTo.vue.d.ts +6 -6
  15. package/dist/types/src/components/BaseBelongsToFetch.vue.d.ts +6 -6
  16. package/dist/types/src/components/BaseButton.vue.d.ts +12 -12
  17. package/dist/types/src/components/BaseButtonGroup.vue.d.ts +24 -24
  18. package/dist/types/src/components/BaseCalendar.vue.d.ts +1 -1
  19. package/dist/types/src/components/BaseColor.vue.d.ts +19 -0
  20. package/dist/types/src/components/BaseDataIterator.vue.d.ts +1 -1
  21. package/dist/types/src/components/BaseDataIteratorSectionColumns.vue.d.ts +4 -4
  22. package/dist/types/src/components/BaseDataTable.vue.d.ts +1 -1
  23. package/dist/types/src/components/BaseDropdownAutocomplete.vue.d.ts +1 -1
  24. package/dist/types/src/components/BaseField.vue.d.ts +13 -3
  25. package/dist/types/src/components/BaseInput.vue.d.ts +53 -4
  26. package/dist/types/src/components/BaseInputError.vue.d.ts +14 -1
  27. package/dist/types/src/components/BaseInputLabel.vue.d.ts +15 -5
  28. package/dist/types/src/components/BaseLayoutSidebarConfigurable.vue.d.ts +1 -1
  29. package/dist/types/src/components/BaseLayoutStackedConfigurable.vue.d.ts +1 -1
  30. package/dist/types/src/components/BaseLoadingCover.vue.d.ts +1 -1
  31. package/dist/types/src/components/BaseMediaGallery.vue.d.ts +1 -1
  32. package/dist/types/src/components/BaseMediaListItem.vue.d.ts +1 -1
  33. package/dist/types/src/components/BaseMediaPictures.vue.d.ts +1 -1
  34. package/dist/types/src/components/BaseMediaPicturesItem.vue.d.ts +1 -1
  35. package/dist/types/src/components/BaseMenu.vue.d.ts +1 -1
  36. package/dist/types/src/components/BaseMenuItem.vue.d.ts +1 -1
  37. package/dist/types/src/components/BaseNavbar.vue.d.ts +1 -1
  38. package/dist/types/src/components/BaseNavbarItemContent.vue.d.ts +1 -1
  39. package/dist/types/src/components/BaseNavbarSideItemContent.vue.d.ts +1 -1
  40. package/dist/types/src/components/BasePassword.vue.d.ts +13 -0
  41. package/dist/types/src/components/BaseSelect.vue.d.ts +27 -0
  42. package/dist/types/src/components/BaseSideNavigation.vue.d.ts +3 -3
  43. package/dist/types/src/components/BaseSwitch.vue.d.ts +1 -1
  44. package/dist/types/src/components/BaseTable.vue.d.ts +1 -1
  45. package/dist/types/src/components/BaseTabs.vue.d.ts +3 -3
  46. package/dist/types/src/components/BaseTagAutocomplete.vue.d.ts +3 -3
  47. package/dist/types/src/components/BaseTextarea.vue.d.ts +18 -0
  48. package/dist/types/src/components/BaseTextareaAutoresize.vue.d.ts +9 -0
  49. package/dist/types/src/composables/field.d.ts +3 -0
  50. package/dist/types/src/composables/inputSize.d.ts +6 -0
  51. package/dist/types/src/utils/sizes.d.ts +19 -0
  52. package/package.json +1 -1
  53. package/src/assets/form.css +1 -1
  54. package/src/components/BaseAddressForm.stories.js +7 -2
  55. package/src/components/BaseAddressForm.vue +64 -37
  56. package/src/components/BaseAutocomplete.stories.js +1 -1
  57. package/src/components/BaseAutocomplete.vue +86 -96
  58. package/src/components/BaseAutocompleteDrawer.vue +3 -2
  59. package/src/components/BaseAutocompleteFetch.stories.js +1 -1
  60. package/src/components/BaseAutocompleteFetch.vue +3 -2
  61. package/src/components/BaseBelongsTo.stories.js +1 -1
  62. package/src/components/BaseBelongsTo.vue +3 -2
  63. package/src/components/BaseBelongsToFetch.vue +3 -2
  64. package/src/components/BaseButton.stories.js +21 -0
  65. package/src/components/BaseButton.vue +42 -6
  66. package/src/components/BaseButtonGroup.stories.js +31 -1
  67. package/src/components/BaseButtonGroup.vue +46 -33
  68. package/src/components/BaseColor.stories.js +22 -0
  69. package/src/components/BaseColor.vue +28 -25
  70. package/src/components/BaseDataTable.vue +5 -5
  71. package/src/components/BaseDataTableRowAction.vue +6 -6
  72. package/src/components/BaseDatePicker.vue +6 -3
  73. package/src/components/BaseDraggable.vue +5 -1
  74. package/src/components/BaseDropdown.stories.js +2 -3
  75. package/src/components/BaseDropdownAutocomplete.vue +2 -2
  76. package/src/components/BaseField.vue +19 -8
  77. package/src/components/BaseInput.stories.js +36 -2
  78. package/src/components/BaseInput.vue +199 -74
  79. package/src/components/BaseInputError.vue +32 -2
  80. package/src/components/BaseInputLabel.vue +36 -9
  81. package/src/components/BasePassword.stories.js +25 -0
  82. package/src/components/BasePassword.vue +35 -55
  83. package/src/components/BaseSelect.stories.js +34 -0
  84. package/src/components/BaseSelect.vue +57 -8
  85. package/src/components/BaseTagAutocomplete.vue +3 -2
  86. package/src/components/BaseTextarea.stories.js +25 -0
  87. package/src/components/BaseTextarea.vue +34 -3
  88. package/src/components/BaseTextareaAutoresize.stories.js +27 -2
  89. package/src/components/BaseTextareaAutoresize.vue +27 -8
  90. package/src/components/BaseTimelineItem.stories.js +1 -3
  91. package/src/composables/field.ts +20 -0
  92. package/src/composables/inputSize.ts +29 -0
  93. package/src/utils/sizes.ts +21 -0
@@ -1,27 +1,27 @@
1
1
  <template>
2
- <div
3
- class="inline-flex rounded border"
4
- :class="[borderColor]"
5
- >
6
- <div
7
- v-if="iconLeft"
8
- class="flex shrink-0 items-center justify-center rounded-l border-r px-3 transition-colors"
9
- :class="[borderColor, backgroundColor, textColor]"
10
- >
11
- <BaseIcon :icon="iconLeft" />
12
- </div>
13
- <div
14
- v-if="prefix"
15
- class="flex shrink-0 items-center justify-center border-r px-4 transition-colors"
16
- :class="[
17
- iconLeft ? '' : 'rounded-l',
18
- borderColor,
19
- backgroundColor,
20
- textColor,
21
- ]"
22
- >
23
- {{ prefix }}
2
+ <div :class="classes">
3
+ <div :class="decorationWrapClasses">
4
+ <component
5
+ :is="hasLeftListener ? 'button' : 'div'"
6
+ v-if="iconLeft"
7
+ :type="hasLeftListener ? 'button' : undefined"
8
+ :class="[decorationClasses, hasLeftListener ? 'hover:bg-slate-100' : '']"
9
+ @click="onIconLeftClickInternal"
10
+ >
11
+ <BaseIcon
12
+ :icon="iconLeft"
13
+ :class="iconClasses"
14
+ />
15
+ </component>
16
+ <div
17
+ v-if="prefix"
18
+ :class="decorationClasses"
19
+ @click="focusAction"
20
+ >
21
+ {{ prefix }}
22
+ </div>
24
23
  </div>
24
+
25
25
  <input
26
26
  v-if="maskOptions"
27
27
  ref="input"
@@ -30,12 +30,10 @@
30
30
  :value="modelValue"
31
31
  :type="type"
32
32
  :autocomplete="autocomplete ? 'on' : 'off'"
33
- :class="{
34
- 'rounded-l': emptyLeft,
35
- 'rounded-r': emptyRight,
36
- 'w-full border-none bg-white outline-none focus:z-[1] focus:ring-2 focus:ring-primary-600 focus:ring-offset-1 disabled:cursor-not-allowed disabled:text-slate-300': true,
37
- }"
38
- @input="update"
33
+ :class="baseClasses"
34
+ @input="onInput"
35
+ @click="onClick"
36
+ @keydown="onKeydown"
39
37
  >
40
38
  <input
41
39
  v-else
@@ -44,31 +42,31 @@
44
42
  :value="modelValue"
45
43
  :type="type"
46
44
  :autocomplete="autocomplete ? 'on' : 'off'"
47
- :class="{
48
- 'rounded-l': emptyLeft,
49
- 'rounded-r': emptyRight,
50
- 'w-full border-none bg-white outline-none focus:z-[1] focus:ring-2 focus:ring-primary-600 focus:ring-offset-1 disabled:cursor-not-allowed disabled:text-slate-300': true,
51
- }"
52
- @input="update"
53
- >
54
- <div
55
- v-if="suffix"
56
- class="flex shrink-0 items-center justify-center border-l px-4 transition-colors"
57
- :class="[
58
- iconRight ? '' : 'rounded-r',
59
- borderColor,
60
- backgroundColor,
61
- textColor,
62
- ]"
63
- >
64
- {{ suffix }}
65
- </div>
66
- <div
67
- v-if="iconRight"
68
- class="flex shrink-0 items-center justify-center rounded-r border-l px-3 transition-colors"
69
- :class="[borderColor, backgroundColor, textColor]"
45
+ :class="baseClasses"
46
+ @input="onInput"
47
+ @click="onClick"
48
+ @keydown="onKeydown"
70
49
  >
71
- <BaseIcon :icon="iconRight" />
50
+ <div :class="decorationWrapClasses">
51
+ <div
52
+ v-if="suffix"
53
+ :class="decorationClasses"
54
+ @click="focusAction"
55
+ >
56
+ {{ suffix }}
57
+ </div>
58
+ <component
59
+ :is="hasRightListener ? 'button' : 'div'"
60
+ v-if="iconRight"
61
+ :type="hasRightListener ? 'button' : undefined"
62
+ :class="[decorationClasses, hasRightListener ? 'hover:bg-slate-100' : '']"
63
+ @click="onIconRightClickInternal"
64
+ >
65
+ <BaseIcon
66
+ :icon="iconRight"
67
+ :class="iconClasses"
68
+ />
69
+ </component>
72
70
  </div>
73
71
  </div>
74
72
  </template>
@@ -79,12 +77,22 @@ import { PropType } from 'vue';
79
77
  import { Icon as BaseIcon } from '@iconify/vue';
80
78
  import { useField } from '@/composables/field';
81
79
  import { vMaska } from 'maska';
80
+ import { Size, sizes } from '@/utils/sizes';
81
+ import { twMerge } from 'tailwind-merge';
82
+
83
+ defineOptions({
84
+ inheritAttrs: false,
85
+ })
82
86
 
83
87
  const props = defineProps({
84
88
  modelValue: {
85
89
  default: '',
86
90
  type: [String, Number, null] as PropType<string | number | null>,
87
91
  },
92
+ class: {
93
+ default: '',
94
+ type: [String, Array] as PropType<string | string[]>,
95
+ },
88
96
  type: {
89
97
  type: String,
90
98
  default: 'text',
@@ -140,6 +148,10 @@ const props = defineProps({
140
148
  default: false,
141
149
  type: Boolean,
142
150
  },
151
+ size: {
152
+ default: undefined,
153
+ type: String as PropType<Size>,
154
+ },
143
155
  min: {
144
156
  default: undefined,
145
157
  type: [null, Number] as PropType<undefined | null | number>,
@@ -154,9 +166,38 @@ const props = defineProps({
154
166
  return null;
155
167
  },
156
168
  },
169
+ visibleFocus: {
170
+ default: true,
171
+ type: Boolean,
172
+ },
173
+ onIconLeftClick: {
174
+ default: undefined,
175
+ type: Function as PropType<() => void>,
176
+ },
177
+ onIconRightClick: {
178
+ default: undefined,
179
+ type: Function as PropType<() => void>,
180
+ },
157
181
  });
158
182
 
159
183
  const input = ref<HTMLInputElement | null>(null);
184
+ const focus = ref(false);
185
+
186
+ const hasLeftDecoration = computed(() => {
187
+ return props.iconLeft || props.prefix;
188
+ });
189
+
190
+ const hasRightDecoration = computed(() => {
191
+ return props.iconRight || props.suffix;
192
+ });
193
+
194
+ const hasLeftListener = computed(() => {
195
+ return props.onIconLeftClick !== undefined;
196
+ });
197
+
198
+ const hasRightListener = computed(() => {
199
+ return props.onIconRightClick !== undefined;
200
+ });
160
201
 
161
202
  const maskOptions = computed(() => {
162
203
  if (props.mask) {
@@ -167,14 +208,6 @@ const maskOptions = computed(() => {
167
208
  return undefined;
168
209
  });
169
210
 
170
- const emptyLeft = computed(() => {
171
- return !props.iconLeft && !props.prefix;
172
- });
173
-
174
- const emptyRight = computed(() => {
175
- return !props.iconRight && !props.suffix;
176
- });
177
-
178
211
  const bindings = computed<any>(() => {
179
212
  return {
180
213
  name: nameInternal.value,
@@ -184,7 +217,6 @@ const bindings = computed<any>(() => {
184
217
  disabled: props.disabled,
185
218
  placeholder: props.placeholder,
186
219
  required: requiredInternal.value,
187
-
188
220
  onKeydown(event: KeyboardEvent) {
189
221
  if (event.code == 'Enter' && props.preventSubmit) {
190
222
  event.preventDefault();
@@ -192,9 +224,11 @@ const bindings = computed<any>(() => {
192
224
  },
193
225
  onFocus: (e: Event) => {
194
226
  emit('focus', e);
227
+ focus.value = true;
195
228
  },
196
229
  onBlur: (e: Event) => {
197
230
  emit('blur', e);
231
+ focus.value = false;
198
232
  },
199
233
  };
200
234
  });
@@ -219,17 +253,18 @@ const maskInternal = computed(() => {
219
253
  return props.mask;
220
254
  });
221
255
 
222
- const emit = defineEmits(['update:modelValue', 'focus', 'blur']);
256
+ const emit = defineEmits(['update:modelValue', 'focus', 'blur', 'click', 'keydown']);
223
257
 
224
- const { nameInternal, requiredInternal, hasErrorInternal, emitUpdate } =
258
+ const { nameInternal, requiredInternal, hasErrorInternal, emitUpdate, sizeInternal } =
225
259
  useField({
226
260
  name: computed(() => props.name),
227
261
  required: computed(() => props.required),
228
262
  hasError: computed(() => props.hasError),
263
+ size: computed(() => props.size),
229
264
  emit: emit,
230
265
  });
231
266
 
232
- function update(event: any | null) {
267
+ function onInput(event: any | null) {
233
268
  if (event === null) {
234
269
  emitUpdate(null);
235
270
  }
@@ -237,28 +272,118 @@ function update(event: any | null) {
237
272
  return emitUpdate(get(event, 'target.value', ''));
238
273
  }
239
274
 
240
- const borderColor = computed(() => {
241
- return hasErrorInternal.value ? 'border-red-500' : 'border-slate-300';
275
+ function onClick(event: MouseEvent) {
276
+ emit('click', event);
277
+ }
278
+
279
+ function onKeydown(event: KeyboardEvent) {
280
+ emit('keydown', event);
281
+ }
282
+
283
+ const classes = computed(() => {
284
+ const base = `inline-flex bg-white input-rounded border transition-colors duration-200`;
285
+ const border = hasErrorInternal.value ? 'border-red-500' : 'border-slate-300';
286
+ const disabled = props.disabled ? 'cursor-not-allowed text-slate-300' : '';
287
+ const sizeConfig = sizes[sizeInternal.value];
288
+ let focusClass = '';
289
+ if (props.visibleFocus) {
290
+ if (hasErrorInternal.value) {
291
+ focusClass = 'focus-within:input-focus-error';
292
+ } else {
293
+ focusClass = 'focus-within:input-focus';
294
+ }
295
+ }
296
+
297
+ return twMerge([
298
+ base,
299
+ border,
300
+ disabled,
301
+ sizeConfig.height,
302
+ sizeConfig.fontSize,
303
+ focusClass,
304
+ props.class,
305
+ ]);
306
+ });
307
+
308
+ const baseClasses = computed(() => {
309
+ const base = `border-none outline-none bg-transparent grow min-w-0 focus:border-none focus:outline-none focus:ring-0`;
310
+ const sizeConfig = sizes[sizeInternal.value];
311
+ const disabled = props.disabled ? 'cursor-not-allowed text-slate-300' : '';
312
+
313
+ const paddingX = {
314
+ xs: [hasLeftDecoration.value ? 'pl-0.5' : 'pl-2', hasRightDecoration.value ? 'pr-0' : 'pr-2'],
315
+ sm: [hasLeftDecoration.value ? 'pl-0.5' : 'pl-2.5', hasRightDecoration.value ? 'pr-0' : 'pr-2.5'],
316
+ md: [hasLeftDecoration.value ? 'pl-1' : 'pl-3', hasRightDecoration.value ? 'pr-1' : 'pr-3'],
317
+ }[sizeInternal.value];
318
+
319
+ return [
320
+ base,
321
+ disabled,
322
+ paddingX,
323
+ sizeConfig.fontSize,
324
+ ];
242
325
  });
243
326
 
244
- const backgroundColor = computed(() => {
245
- return hasErrorInternal.value ? 'bg-red-100' : 'bg-slate-100';
327
+ const decorationWrapClasses = computed(() => {
328
+ const base = `flex justify-center empty:hidden`;
329
+ const spacing = {
330
+ xs: 'first:pl-0.5 last:pr-0.5 py-0.5',
331
+ sm: 'first:pl-1 last:pr-1 py-1',
332
+ md: 'first:pl-1 last:pr-1 py-1',
333
+ }[sizeInternal.value];
334
+
335
+ return [
336
+ base,
337
+ spacing,
338
+ ];
246
339
  });
247
340
 
248
- const textColor = computed(() => {
249
- return hasErrorInternal.value ? 'text-red-800' : 'text-slate-600';
341
+ const decorationClasses = computed(() => {
342
+ const base = `flex items-center justify-center rounded-md`;
343
+ const textColor = hasErrorInternal.value ? 'text-red-800' : 'text-slate-500';
344
+ const padding = {
345
+ xs: 'p-1',
346
+ sm: 'p-1.5',
347
+ md: 'p-2',
348
+ }[sizeInternal.value];
349
+
350
+ return `${base} ${textColor} ${padding}`;
351
+ });
352
+
353
+ const iconClasses = computed(() => {
354
+ const sizeConfig = sizes[sizeInternal.value];
355
+
356
+ return [
357
+ sizeConfig.iconSize,
358
+ ];
250
359
  });
251
360
 
252
- function focus() {
361
+ function focusAction() {
253
362
  input.value?.focus();
254
363
  }
255
364
 
256
- function blur() {
365
+ function blurAction() {
257
366
  input.value?.blur();
258
367
  }
259
368
 
369
+ function onIconLeftClickInternal() {
370
+ if (props.onIconLeftClick) {
371
+ props.onIconLeftClick();
372
+ } else {
373
+ focusAction();
374
+ }
375
+ }
376
+
377
+ function onIconRightClickInternal() {
378
+ if (props.onIconRightClick) {
379
+ props.onIconRightClick();
380
+ } else {
381
+ blurAction();
382
+ }
383
+ }
384
+
260
385
  defineExpose({
261
- focus,
262
- blur,
386
+ focus: focusAction,
387
+ blur: blurAction,
263
388
  });
264
389
  </script>
@@ -1,7 +1,37 @@
1
1
  <template>
2
- <p class="block text-sm font-medium leading-tight text-red-600">
2
+ <p :class="classes">
3
3
  <slot />
4
4
  </p>
5
5
  </template>
6
6
 
7
- <script lang="ts" setup></script>
7
+ <script lang="ts" setup>
8
+ import { useInputSize } from '@/composables/inputSize';
9
+ import { Size } from '@/utils/sizes';
10
+ import { PropType } from 'vue';
11
+
12
+
13
+ const props = defineProps({
14
+ size: {
15
+ default: undefined,
16
+ type: String as PropType<Size>,
17
+ },
18
+ });
19
+
20
+ const { size } = useInputSize(computed(() => props.size));
21
+
22
+ const classes = computed(() => {
23
+ const base = 'block font-medium leading-tight text-red-600';
24
+
25
+ const responsive = {
26
+ 'xs': 'text-xs mb-0.5',
27
+ 'sm': 'text-xs mb-1',
28
+ 'md': 'text-sm mb-1',
29
+ }[size.value];
30
+
31
+ return [
32
+ base,
33
+ responsive,
34
+ ]
35
+ });
36
+
37
+ </script>
@@ -2,25 +2,27 @@
2
2
  <label :class="classes">
3
3
  <div
4
4
  ref="labelRef"
5
- class="relative inline-flex"
5
+ class="relative inline-flex items-center flex-wrap"
6
6
  :class="[help ? 'cursor-help' : 'cursor-default']"
7
7
  >
8
8
  <div> {{ label }}</div>
9
9
 
10
+ <div
11
+ v-if="required"
12
+ class="ml-0.5 text-red-600"
13
+ > *</div>
14
+
10
15
  <BaseTooltip
11
16
  v-if="help"
12
17
  :text="help"
13
18
  >
14
19
  <BaseIcon
15
- class="block relative text-slate-900 -bottom-[3px] ml-1 mr-1 h-[13px] w-[13px]"
20
+ class="block relative text-slate-900 ml-1 mr-1 h-[13px] w-[13px]"
16
21
  icon="mdi:information-outline"
17
22
  />
18
23
  </BaseTooltip>
19
24
 
20
- <div
21
- v-if="required"
22
- class="ml-0.5 text-red-600"
23
- > *</div>
25
+
24
26
  </div>
25
27
  </label>
26
28
  </template>
@@ -29,8 +31,15 @@
29
31
  import { PropType } from 'vue';
30
32
  import { Icon as BaseIcon } from '@iconify/vue';
31
33
  import BaseTooltip from './BaseTooltip.vue';
34
+ import { Size } from '@/utils/sizes';
35
+ import { useInputSize } from '@/composables/inputSize';
36
+ import { ClassNameValue, twMerge } from 'tailwind-merge';
32
37
 
33
- defineProps({
38
+ defineOptions({
39
+ inheritAttrs: false,
40
+ });
41
+
42
+ const props = defineProps({
34
43
  required: {
35
44
  default: false,
36
45
  type: Boolean,
@@ -39,16 +48,34 @@ defineProps({
39
48
  required: true,
40
49
  type: String,
41
50
  },
42
- classes: {
51
+ class: {
43
52
  default: 'mb-1 block text-sm',
44
- type: String,
53
+ type: [String, Array] as PropType<ClassNameValue>,
45
54
  },
46
55
  help: {
47
56
  default: null,
48
57
  type: [String, null] as PropType<string | null>,
49
58
  },
59
+ size: {
60
+ default: undefined,
61
+ type: String as PropType<Size>,
62
+ },
50
63
  });
51
64
 
52
65
  const labelRef = ref();
53
66
 
67
+ const { size } = useInputSize(computed(() => props.size));
68
+
69
+ const classes = computed(() => {
70
+ const base = 'mb-1 block text-sm';
71
+
72
+ const responsive = {
73
+ 'xs': 'text-xs mb-[0.2rem]',
74
+ 'sm': 'text-sm mb-1',
75
+ 'md': 'text-sm mb-1',
76
+ }[size.value];
77
+
78
+ return twMerge(base, responsive, props.class);
79
+ });
80
+
54
81
  </script>
@@ -1,10 +1,18 @@
1
1
  import BasePassword from './BasePassword.vue';
2
2
  import { createFieldStory } from '@/../.storybook/utils';
3
3
 
4
+ const sizes = ['xs', 'sm', 'md'];
5
+
4
6
  export default {
5
7
  title: 'Form/BasePassword',
6
8
  component: BasePassword,
7
9
  args: {},
10
+ argTypes: {
11
+ size: {
12
+ control: { type: 'select' },
13
+ options: sizes,
14
+ },
15
+ },
8
16
  };
9
17
 
10
18
  const Template = (args) => ({
@@ -55,4 +63,21 @@ const FocusTemplate = (args) => ({
55
63
  `,
56
64
  });
57
65
 
66
+ const TemplateSizes = (args) => ({
67
+ components: { BasePassword },
68
+ setup() {
69
+ const value = ref(null);
70
+ const sizes = ['xs', 'sm', 'md'];
71
+ return { args, value, sizes };
72
+ },
73
+ template: `
74
+ <div v-for="size in sizes" :key="size" class="mb-4">
75
+ <p class="text-xs text-slate-600 leading-tight mb-1">{{ size }}</p>
76
+ <BasePassword v-model="value" v-bind="args" :size="size" class="w-full"></BasePassword>
77
+ </div>
78
+ `,
79
+ });
80
+
81
+ export const Sizes = TemplateSizes.bind({});
82
+
58
83
  export const Focus = FocusTemplate.bind({});
@@ -1,50 +1,25 @@
1
1
  <template>
2
- <div
3
- class="flex rounded border bg-white"
4
- :class="[
5
- disabled ? 'cursor-not-allowed text-slate-300' : '',
6
- hasErrorInternal ? 'border-red-500' : 'border-slate-300',
7
- ]"
8
- >
9
- <input
10
- ref="input"
11
- :value="modelValue"
12
- :type="showPassword ? 'text' : 'password'"
13
- :name="nameInternal"
14
- :disabled="disabled"
15
- :placeholder="placeholder"
16
- :required="requiredInternal"
17
- class="grow rounded-l rounded-r-none border-none focus:ring-2 focus:ring-primary-500 disabled:cursor-not-allowed"
18
- @input="onInput"
19
- >
20
- <div class="flex shrink-0 pl-3">
21
- <button
22
- tabindex="-1"
23
- type="button"
24
- class="pr-3 text-slate-500 disabled:cursor-not-allowed disabled:text-slate-300"
25
- :disabled="disabled"
26
- @click="showPassword = !showPassword"
27
- >
28
- <BaseIcon
29
- v-if="!showPassword"
30
- icon="heroicons:eye-slash-20-solid"
31
- class="h-5 w-5"
32
- />
33
- <BaseIcon
34
- v-else
35
- icon="heroicons:eye-20-solid"
36
- class="h-5 w-5"
37
- />
38
- </button>
39
- </div>
40
- </div>
2
+ <BaseInput
3
+ ref="input"
4
+ :model-value="modelValue"
5
+ :type="showPassword ? 'text' : 'password'"
6
+ :disabled="disabled"
7
+ :placeholder="placeholder"
8
+ :size="size"
9
+ :icon-right="showPassword ? 'heroicons:eye-20-solid' : 'heroicons:eye-slash-20-solid'"
10
+ @icon-right-click="onIconRightClick"
11
+ @update:model-value="onUpdateModelValue"
12
+ @focus="onFocus"
13
+ @blur="onBlur"
14
+ />
41
15
  </template>
42
16
 
43
17
  <script lang="ts" setup>
44
- import { trim } from 'lodash';
45
- import { Icon as BaseIcon } from '@iconify/vue';
46
18
  import { PropType } from 'vue';
47
- import { useField } from '@/composables/field';
19
+ import { Size } from '@/utils/sizes';
20
+ import BaseInput from './BaseInput.vue';
21
+
22
+ const emit = defineEmits(['update:modelValue', 'blur', 'focus']);
48
23
 
49
24
  const props = defineProps({
50
25
  modelValue: {
@@ -55,6 +30,10 @@ const props = defineProps({
55
30
  default: false,
56
31
  type: Boolean,
57
32
  },
33
+ size: {
34
+ default: undefined,
35
+ type: String as PropType<Size>,
36
+ },
58
37
  name: {
59
38
  default: undefined,
60
39
  type: String,
@@ -75,21 +54,10 @@ const props = defineProps({
75
54
 
76
55
  const input = ref<HTMLInputElement | null>(null);
77
56
 
78
- const emit = defineEmits(['update:modelValue']);
79
-
80
- const { nameInternal, requiredInternal, hasErrorInternal, emitUpdate } =
81
- useField({
82
- name: computed(() => props.name),
83
- required: computed(() => props.required),
84
- hasError: computed(() => props.hasError),
85
- emit: emit,
86
- });
87
-
88
57
  const showPassword = ref(false);
89
58
 
90
- function onInput(event: any) {
91
- const value = event.target.value + '';
92
- emitUpdate(trim(value));
59
+ function onIconRightClick() {
60
+ showPassword.value = !showPassword.value;
93
61
  }
94
62
 
95
63
  function focus() {
@@ -100,6 +68,18 @@ function blur() {
100
68
  input.value?.blur();
101
69
  }
102
70
 
71
+ function onUpdateModelValue(value: string) {
72
+ emit('update:modelValue', value);
73
+ }
74
+
75
+ function onBlur() {
76
+ emit('blur');
77
+ }
78
+
79
+ function onFocus() {
80
+ emit('focus');
81
+ }
82
+
103
83
  defineExpose({
104
84
  focus,
105
85
  blur,