sprintify-ui 0.6.33 → 0.6.35

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 (58) hide show
  1. package/dist/sprintify-ui.es.js +12984 -12888
  2. package/dist/style.css +1 -1
  3. package/dist/tailwindcss/button.js +3 -2
  4. package/dist/tailwindcss/theme.js +14 -7
  5. package/dist/types/src/components/BaseButtonGroup.vue.d.ts +9 -0
  6. package/dist/types/src/components/BaseDataIterator.vue.d.ts +3 -3
  7. package/dist/types/src/components/BaseDataIteratorSectionButton.vue.d.ts +2 -2
  8. package/dist/types/src/components/BaseDataIteratorSectionColumns.vue.d.ts +8 -8
  9. package/dist/types/src/components/BaseDataTable.vue.d.ts +3 -3
  10. package/dist/types/src/components/BaseDataTableRowAction.vue.d.ts +4 -3
  11. package/dist/types/src/components/BaseDatePicker.vue.d.ts +10 -0
  12. package/dist/types/src/components/BaseDateSelect.vue.d.ts +9 -0
  13. package/dist/types/src/components/BaseInput.vue.d.ts +18 -0
  14. package/dist/types/src/components/BasePassword.vue.d.ts +13 -0
  15. package/dist/types/src/components/BaseRichText.vue.d.ts +9 -0
  16. package/dist/types/src/components/BaseTable.vue.d.ts +3 -3
  17. package/dist/types/src/components/BaseTagAutocomplete.vue.d.ts +11 -2
  18. package/dist/types/src/components/BaseTextarea.vue.d.ts +18 -0
  19. package/dist/types/src/components/BaseTextareaAutoresize.vue.d.ts +12 -2
  20. package/dist/types/src/stories/PageInputSizes.vue.d.ts +2 -0
  21. package/dist/types/src/utils/slots.d.ts +1 -0
  22. package/package.json +1 -1
  23. package/src/assets/base-rich-text.css +148 -26
  24. package/src/components/BaseButton.vue +3 -2
  25. package/src/components/BaseButtonGroup.vue +37 -9
  26. package/src/components/BaseColor.vue +29 -31
  27. package/src/components/BaseDataIterator.stories.js +8 -1
  28. package/src/components/BaseDataIterator.vue +36 -76
  29. package/src/components/BaseDataIteratorSectionButton.vue +8 -19
  30. package/src/components/BaseDataTable.vue +25 -18
  31. package/src/components/BaseDataTableRowAction.vue +8 -7
  32. package/src/components/BaseDatePicker.stories.js +23 -0
  33. package/src/components/BaseDatePicker.vue +71 -11
  34. package/src/components/BaseDateSelect.stories.js +25 -1
  35. package/src/components/BaseDateSelect.vue +80 -101
  36. package/src/components/BaseDraggable.vue +5 -1
  37. package/src/components/BaseDropdownAutocomplete.stories.js +30 -15
  38. package/src/components/BaseHasMany.stories.js +22 -1
  39. package/src/components/BaseInput.stories.js +4 -4
  40. package/src/components/BaseInput.vue +61 -15
  41. package/src/components/BaseMediaPicturesItem.vue +2 -2
  42. package/src/components/BasePassword.stories.js +25 -0
  43. package/src/components/BasePassword.vue +35 -55
  44. package/src/components/BaseRichText.stories.js +6 -0
  45. package/src/components/BaseRichText.vue +12 -2
  46. package/src/components/BaseSelect.vue +5 -0
  47. package/src/components/BaseTable.vue +2 -1
  48. package/src/components/BaseTagAutocomplete.stories.js +1 -1
  49. package/src/components/BaseTagAutocomplete.vue +143 -88
  50. package/src/components/BaseTagAutocompleteFetch.stories.js +22 -1
  51. package/src/components/BaseTextarea.stories.js +25 -0
  52. package/src/components/BaseTextarea.vue +34 -3
  53. package/src/components/BaseTextareaAutoresize.stories.js +27 -2
  54. package/src/components/BaseTextareaAutoresize.vue +28 -9
  55. package/src/composables/inputSize.ts +5 -1
  56. package/src/stories/InputSizes.stories.js +22 -0
  57. package/src/stories/PageInputSizes.vue +205 -0
  58. package/src/utils/slots.ts +13 -0
@@ -2,10 +2,17 @@ import BaseDateSelect from './BaseDateSelect.vue';
2
2
  import ShowValue from '@/../.storybook/components/ShowValue.vue';
3
3
  import { createFieldStory } from '../../.storybook/utils';
4
4
 
5
+ const sizes = ['xs', 'sm', 'md'];
6
+
5
7
  export default {
6
8
  title: 'Form/BaseDateSelect',
7
9
  component: BaseDateSelect,
8
- argTypes: {},
10
+ argTypes: {
11
+ size: {
12
+ control: { type: 'select' },
13
+ options: sizes,
14
+ }
15
+ },
9
16
  };
10
17
 
11
18
  const Template = (args) => ({
@@ -40,6 +47,23 @@ Disabled.args = {
40
47
  disabled: true,
41
48
  };
42
49
 
50
+ const TemplateSizes = (args) => ({
51
+ components: { BaseDateSelect },
52
+ setup() {
53
+ const value = ref(null);
54
+ const sizes = ['xs', 'sm', 'md'];
55
+ return { args, value, sizes };
56
+ },
57
+ template: `
58
+ <div v-for="size in sizes" :key="size" class="mb-4">
59
+ <p class="text-xs text-slate-600 leading-tight mb-1">{{ size }}</p>
60
+ <BaseDateSelect v-model="value" v-bind="args" :size="size" class="w-full"></BaseDateSelect>
61
+ </div>
62
+ `,
63
+ });
64
+
65
+ export const Sizes = TemplateSizes.bind({});
66
+
43
67
  export const Field = createFieldStory({
44
68
  component: BaseDateSelect,
45
69
  componentName: 'BaseDateSelect',
@@ -1,114 +1,82 @@
1
1
  <template>
2
2
  <div>
3
- <div class="-m-0.5 flex">
4
- <div class="w-auto p-0.5">
5
- <select
6
- v-model="date.year"
7
- :disabled="disabled"
8
- :required="required"
9
- data-cy="year"
10
- class="w-full rounded"
11
- :class="[
12
- {
13
- 'cursor-not-allowed bg-slate-100 text-slate-500': disabled,
14
- },
15
- [hasErrorInternal ? 'border-red-500' : 'border-slate-300'],
16
- ]"
17
- :placeholder="t('sui.year')"
18
- @change="update()"
3
+ <div
4
+ class="flex"
5
+ :class="[
6
+ sizeInternal === 'xs' ? 'gap-0.5' : '',
7
+ sizeInternal === 'sm' ? 'gap-0.5' : '',
8
+ sizeInternal === 'md' ? 'gap-1' : '',
9
+ ]"
10
+ >
11
+ <BaseSelect
12
+ v-model="date.year"
13
+ :disabled="disabled"
14
+ :required="requiredInternal"
15
+ data-cy="year"
16
+ :has-error="hasErrorInternal"
17
+ :placeholder="t('sui.year')"
18
+ :size="sizeInternal"
19
+ @update:model-value="update()"
20
+ >
21
+ <option
22
+ v-for="year in years"
23
+ :key="year"
24
+ :value="year"
19
25
  >
20
- <option
21
- disabled
22
- selected
23
- hidden
24
- :value="null"
25
- >
26
- {{ t('sui.year') }}
27
- </option>
28
- <option
29
- v-for="year in years"
30
- :key="year"
31
- :value="year"
32
- >
33
- {{ year }}
34
- </option>
35
- </select>
36
- </div>
37
-
38
- <div class="w-auto p-0.5">
39
- <select
40
- v-model="date.month"
41
- :disabled="disabled"
42
- :required="required"
43
- data-cy="month"
44
- class="w-full rounded capitalize"
45
- :class="[
46
- {
47
- 'cursor-not-allowed bg-slate-100 text-slate-500': disabled,
48
- },
49
- [hasErrorInternal ? 'border-red-500' : 'border-slate-300'],
50
- ]"
51
- :placeholder="t('sui.month')"
52
- @change="update()"
26
+ {{ year }}
27
+ </option>
28
+ </BaseSelect>
29
+
30
+ <BaseSelect
31
+ v-model="date.month"
32
+ :disabled="disabled"
33
+ :required="requiredInternal"
34
+ data-cy="month"
35
+ class="capitalize"
36
+ :has-error="hasErrorInternal"
37
+ :placeholder="t('sui.month')"
38
+ :size="sizeInternal"
39
+ @update:model-value="update()"
40
+ >
41
+ <option
42
+ v-for="(month, i) in months"
43
+ :key="month"
44
+ :value="i + 1"
53
45
  >
54
- <option
55
- disabled
56
- selected
57
- hidden
58
- :value="null"
59
- >
60
- {{ t('sui.month') }}
61
- </option>
62
- <option
63
- v-for="(month, i) in months"
64
- :key="month"
65
- :value="i + 1"
66
- >
67
- {{ month }}
68
- </option>
69
- </select>
70
- </div>
71
-
72
- <div class="w-auto p-0.5">
73
- <select
74
- v-model="date.day"
75
- :disabled="dayDisabled"
76
- :required="required"
77
- data-cy="day"
78
- class="w-full rounded capitalize"
79
- :class="[
80
- {
81
- 'cursor-not-allowed bg-slate-100 text-slate-500': dayDisabled,
82
- },
83
- [hasErrorInternal ? 'border-red-500' : 'border-slate-300'],
84
- ]"
85
- :placeholder="t('sui.day')"
86
- @change="update()"
46
+ {{ month }}
47
+ </option>
48
+ </BaseSelect>
49
+
50
+ <BaseSelect
51
+ v-model="date.day"
52
+ :disabled="dayDisabled"
53
+ :required="requiredInternal"
54
+ data-cy="day"
55
+ :has-error="hasErrorInternal"
56
+ :placeholder="t('sui.day')"
57
+ :size="sizeInternal"
58
+ @update:model-value="update()"
59
+ >
60
+ <option
61
+ v-for="day in days"
62
+ :key="day"
63
+ :value="day"
87
64
  >
88
- <option
89
- disabled
90
- selected
91
- hidden
92
- :value="null"
93
- >
94
- {{ t('sui.day') }}
95
- </option>
96
- <option
97
- v-for="day in days"
98
- :key="day"
99
- :value="day"
100
- >
101
- {{ day }}
102
- </option>
103
- </select>
104
- </div>
65
+ {{ day }}
66
+ </option>
67
+ </BaseSelect>
105
68
  </div>
106
69
 
107
70
  <button
108
71
  v-if="clearable"
109
72
  type="button"
110
73
  :disabled="disabled"
111
- class="mt-1 appearance-none border-transparent bg-transparent text-sm text-slate-700 underline outline-none disabled:cursor-not-allowed disabled:opacity-50"
74
+ class="mt-1 appearance-none border-transparent bg-transparent text-slate-700 underline outline-none disabled:cursor-not-allowed disabled:opacity-50"
75
+ :class="[
76
+ sizeInternal === 'xs' ? 'text-xs' : '',
77
+ sizeInternal === 'sm' ? 'text-xs' : '',
78
+ sizeInternal === 'md' ? 'text-sm' : '',
79
+ ]"
112
80
  @click="clear()"
113
81
  >
114
82
  <span>{{ t('sui.clear') }}</span>
@@ -123,6 +91,8 @@ import { DateTime, Info } from 'luxon';
123
91
  import { useField } from '@/composables/field';
124
92
  import { t } from '@/i18n';
125
93
  import { useI18nStore } from '@/stores/i18n';
94
+ import BaseSelect from './BaseSelect.vue';
95
+ import { Size } from '@/utils/sizes';
126
96
 
127
97
  const props = defineProps({
128
98
  modelValue: {
@@ -133,6 +103,10 @@ const props = defineProps({
133
103
  default: false,
134
104
  type: Boolean,
135
105
  },
106
+ size: {
107
+ default: undefined,
108
+ type: String as PropType<Size>,
109
+ },
136
110
  disabled: {
137
111
  default: false,
138
112
  type: Boolean,
@@ -161,15 +135,18 @@ const props = defineProps({
161
135
 
162
136
  const emit = defineEmits(['update:modelValue']);
163
137
 
164
- const { hasErrorInternal, emitUpdate } = useField({
138
+ const { hasErrorInternal, emitUpdate, requiredInternal, sizeInternal } = useField({
165
139
  name: computed(() => props.name),
166
140
  required: computed(() => props.required),
141
+ size: computed(() => props.size),
167
142
  hasError: computed(() => props.hasError),
168
143
  emit: emit,
169
144
  });
170
145
 
171
146
  const years = range(props.maxYear, props.minYear) as number[];
147
+
172
148
  const months = Info.months('short', { locale: useI18nStore().locale });
149
+
173
150
  const days = computed(() => {
174
151
  if (!date.value.year) {
175
152
  return [];
@@ -197,6 +174,8 @@ watch(
197
174
  date.value.year = datetime.year;
198
175
  date.value.month = datetime.month;
199
176
  date.value.day = datetime.day;
177
+ } else {
178
+ clear();
200
179
  }
201
180
  },
202
181
  { immediate: true }
@@ -2,7 +2,7 @@
2
2
  <div ref="elementsRef">
3
3
  <slot
4
4
  v-for="(element, index) in modelValue"
5
- :key="element[itemKey]"
5
+ :key="getKey(element, index)"
6
6
  name="item"
7
7
  :element="element"
8
8
  :index="index"
@@ -25,6 +25,10 @@ const emit = defineEmits(['update:modelValue']);
25
25
 
26
26
  const elementsRef = ref<HTMLElement | null>(null);
27
27
 
28
+ function getKey(element: any, index: number) {
29
+ return element[props.itemKey] ?? index;
30
+ }
31
+
28
32
  let sortable = null as Sortable | null;
29
33
 
30
34
  onMounted(() => {
@@ -19,6 +19,35 @@ export default {
19
19
  },
20
20
  };
21
21
 
22
+ const template = `<template #button="{ newValue }">
23
+ <div class="btn btn-sm">
24
+ <div v-if="newValue" class="flex items-center gap-2 text-sm">
25
+ <div class="h-2 w-2 bg-red-500 rounded-full"></div>
26
+ <span>
27
+ {{ newValue.label }}
28
+ </span>
29
+ </div>
30
+ <div v-else class="">
31
+ Select a character
32
+ </div>
33
+ </div>
34
+ </template>
35
+ <template #option="{ option }">
36
+ <div class="flex items-center gap-2 text-sm px-2">
37
+ <div
38
+ class="h-2 w-2 rounded-full"
39
+ :class="{
40
+ 'bg-red-500': option?.type === 'sith',
41
+ 'bg-green-500': option?.type === 'jedi',
42
+ 'bg-slate-300': option?.type === undefined,
43
+ }"
44
+ ></div>
45
+ <span>
46
+ {{ option.label }}
47
+ </span>
48
+ </div>
49
+ </template>`
50
+
22
51
  export const Autocomplete = (args) => ({
23
52
  components: { BaseDropdownAutocomplete, BaseBadge, ShowValue },
24
53
  setup() {
@@ -30,21 +59,7 @@ export const Autocomplete = (args) => ({
30
59
  v-bind="args"
31
60
  v-model="value"
32
61
  >
33
- <template #button="{ newValue }">
34
- <BaseBadge v-if="newValue">
35
- {{ newValue.label }}
36
- </BaseBadge>
37
- <div v-else>
38
- <BaseBadge contrast="low">
39
- Nothing
40
- </BaseBadge>
41
- </div>
42
- </template>
43
- <template #option="{ option }">
44
- <BaseBadge :contrast="option?.value ? 'high' : 'low'">
45
- {{ option.label }}
46
- </BaseBadge>
47
- </template>
62
+ ${template}
48
63
  </BaseDropdownAutocomplete>
49
64
  <ShowValue :value="value" />
50
65
  `,
@@ -4,10 +4,17 @@ import { createFieldStory, options } from '../../.storybook/utils';
4
4
  import BaseAppNotifications from './BaseAppNotifications.vue';
5
5
  import QueryString from 'qs';
6
6
 
7
+ const sizes = ['xs', 'sm', 'md'];
8
+
7
9
  export default {
8
10
  title: 'Form/BaseHasMany',
9
11
  component: BaseHasMany,
10
- argTypes: {},
12
+ argTypes: {
13
+ size: {
14
+ control: { type: 'select' },
15
+ options: sizes,
16
+ },
17
+ },
11
18
  args: {
12
19
  url: 'https://effettandem.com/api/content/articles',
13
20
  field: 'title',
@@ -72,6 +79,20 @@ ShowRouteUrl.args = {
72
79
  },
73
80
  };
74
81
 
82
+ export const Sizes = (args) => ({
83
+ components: { BaseHasMany },
84
+ setup() {
85
+ const value = ref([]);
86
+ return { args, sizes, value };
87
+ },
88
+ template: `
89
+ <div v-for="size in sizes" class="mb-1">
90
+ <p class="text-xs text-slate-600 leading-tight">{{ size }}</p>
91
+ <BaseHasMany v-model="value" v-bind="args" :size="size"></BaseHasMany>
92
+ </div>
93
+ `,
94
+ });
95
+
75
96
  export const SlotOption = (args) => {
76
97
  return {
77
98
  components: { BaseHasMany },
@@ -54,13 +54,13 @@ export const Demo = Template.bind({});
54
54
 
55
55
  export const IconLeft = Template.bind({});
56
56
  IconLeft.args = {
57
- iconLeft: 'heroicons:phone-20-solid',
57
+ iconLeft: 'heroicons:calendar',
58
58
  placeholder: 'Enter your phone',
59
59
  };
60
60
 
61
61
  export const IconRight = Template.bind({});
62
62
  IconRight.args = {
63
- iconRight: 'mdi:email-outline',
63
+ iconRight: 'mdi:email',
64
64
  placeholder: 'Enter your email',
65
65
  };
66
66
 
@@ -169,7 +169,7 @@ export const Field = createFieldStory({
169
169
  });
170
170
 
171
171
  const TemplateSizes = (args) => ({
172
- components: { BaseInput, ShowValue },
172
+ components: { BaseInput },
173
173
  setup() {
174
174
  const value = ref(null);
175
175
  const sizes = ['xs', 'sm', 'md'];
@@ -177,7 +177,7 @@ const TemplateSizes = (args) => ({
177
177
  },
178
178
  template: `
179
179
  <div v-for="size in sizes" :key="size" class="mb-4">
180
- <p class="text-xs text-slate-600 leading-tight mb-1">btn {{ size }}</p>
180
+ <p class="text-xs text-slate-600 leading-tight mb-1">{{ size }}</p>
181
181
  <BaseInput v-model="value" v-bind="args" :size="size" class="w-full"></BaseInput>
182
182
  </div>
183
183
  `,
@@ -1,18 +1,22 @@
1
1
  <template>
2
2
  <div :class="classes">
3
3
  <div :class="decorationWrapClasses">
4
- <div
4
+ <component
5
+ :is="hasLeftListener ? 'button' : 'div'"
5
6
  v-if="iconLeft"
6
- :class="decorationClasses"
7
+ :type="hasLeftListener ? 'button' : undefined"
8
+ :class="[decorationClasses, hasLeftListener ? 'hover:bg-slate-100' : '']"
9
+ @click="onIconLeftClickInternal"
7
10
  >
8
11
  <BaseIcon
9
12
  :icon="iconLeft"
10
13
  :class="iconClasses"
11
14
  />
12
- </div>
15
+ </component>
13
16
  <div
14
17
  v-if="prefix"
15
18
  :class="decorationClasses"
19
+ @click="focusAction"
16
20
  >
17
21
  {{ prefix }}
18
22
  </div>
@@ -47,18 +51,22 @@
47
51
  <div
48
52
  v-if="suffix"
49
53
  :class="decorationClasses"
54
+ @click="focusAction"
50
55
  >
51
56
  {{ suffix }}
52
57
  </div>
53
- <div
58
+ <component
59
+ :is="hasRightListener ? 'button' : 'div'"
54
60
  v-if="iconRight"
55
- :class="decorationClasses"
61
+ :type="hasRightListener ? 'button' : undefined"
62
+ :class="[decorationClasses, hasRightListener ? 'hover:bg-slate-100' : '']"
63
+ @click="onIconRightClickInternal"
56
64
  >
57
65
  <BaseIcon
58
66
  :icon="iconRight"
59
67
  :class="iconClasses"
60
68
  />
61
- </div>
69
+ </component>
62
70
  </div>
63
71
  </div>
64
72
  </template>
@@ -162,6 +170,14 @@ const props = defineProps({
162
170
  default: true,
163
171
  type: Boolean,
164
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
+ },
165
181
  });
166
182
 
167
183
  const input = ref<HTMLInputElement | null>(null);
@@ -175,6 +191,14 @@ const hasRightDecoration = computed(() => {
175
191
  return props.iconRight || props.suffix;
176
192
  });
177
193
 
194
+ const hasLeftListener = computed(() => {
195
+ return props.onIconLeftClick !== undefined;
196
+ });
197
+
198
+ const hasRightListener = computed(() => {
199
+ return props.onIconRightClick !== undefined;
200
+ });
201
+
178
202
  const maskOptions = computed(() => {
179
203
  if (props.mask) {
180
204
  return {
@@ -260,6 +284,7 @@ const classes = computed(() => {
260
284
  const base = `inline-flex bg-white input-rounded border transition-colors duration-200`;
261
285
  const border = hasErrorInternal.value ? 'border-red-500' : 'border-slate-300';
262
286
  const disabled = props.disabled ? 'cursor-not-allowed text-slate-300' : '';
287
+
263
288
  const sizeConfig = sizes[sizeInternal.value];
264
289
  let focusClass = '';
265
290
  if (props.visibleFocus) {
@@ -287,9 +312,9 @@ const baseClasses = computed(() => {
287
312
  const disabled = props.disabled ? 'cursor-not-allowed text-slate-300' : '';
288
313
 
289
314
  const paddingX = {
290
- xs: [hasLeftDecoration.value ? 'pl-1.5' : 'pl-2', hasRightDecoration.value ? 'pr-1.5' : 'pr-2'],
291
- sm: [hasLeftDecoration.value ? 'pl-2' : 'pl-2.5', hasRightDecoration.value ? 'pr-2' : 'pr-2.5'],
292
- md: [hasLeftDecoration.value ? 'pl-2.5' : 'pl-3', hasRightDecoration.value ? 'pr-2.5' : 'pr-3'],
315
+ xs: [hasLeftDecoration.value ? 'pl-0' : 'pl-2', hasRightDecoration.value ? 'pr-0' : 'pr-2'],
316
+ sm: [hasLeftDecoration.value ? 'pl-0' : 'pl-2.5', hasRightDecoration.value ? 'pr-0' : 'pr-2.5'],
317
+ md: [hasLeftDecoration.value ? 'pl-0' : 'pl-3', hasRightDecoration.value ? 'pr-1' : 'pr-3'],
293
318
  }[sizeInternal.value];
294
319
 
295
320
  return [
@@ -301,11 +326,11 @@ const baseClasses = computed(() => {
301
326
  });
302
327
 
303
328
  const decorationWrapClasses = computed(() => {
304
- const base = `flex items-center justify-center empty:hidden`;
329
+ const base = `flex justify-center empty:hidden`;
305
330
  const spacing = {
306
- xs: 'first:pl-2 last:pr-2 gap-1',
307
- sm: 'first:pl-2.5 last:pr-2.5 gap-2',
308
- md: 'first:pl-3 last:pr-3 gap-3',
331
+ xs: 'first:pl-0.5 last:pr-0.5 py-0.5',
332
+ sm: 'first:pl-1 last:pr-1 py-1',
333
+ md: 'first:pl-1 last:pr-1 py-1',
309
334
  }[sizeInternal.value];
310
335
 
311
336
  return [
@@ -315,10 +340,15 @@ const decorationWrapClasses = computed(() => {
315
340
  });
316
341
 
317
342
  const decorationClasses = computed(() => {
318
- const base = `flex items-center justify-center`;
343
+ const base = `flex items-center justify-center rounded-md`;
319
344
  const textColor = hasErrorInternal.value ? 'text-red-800' : 'text-slate-500';
345
+ const padding = {
346
+ xs: 'p-1',
347
+ sm: 'p-1.5',
348
+ md: 'p-2',
349
+ }[sizeInternal.value];
320
350
 
321
- return `${base} ${textColor}`;
351
+ return `${base} ${textColor} ${padding}`;
322
352
  });
323
353
 
324
354
  const iconClasses = computed(() => {
@@ -337,6 +367,22 @@ function blurAction() {
337
367
  input.value?.blur();
338
368
  }
339
369
 
370
+ function onIconLeftClickInternal() {
371
+ if (props.onIconLeftClick) {
372
+ props.onIconLeftClick();
373
+ } else {
374
+ focusAction();
375
+ }
376
+ }
377
+
378
+ function onIconRightClickInternal() {
379
+ if (props.onIconRightClick) {
380
+ props.onIconRightClick();
381
+ } else {
382
+ blurAction();
383
+ }
384
+ }
385
+
340
386
  defineExpose({
341
387
  focus: focusAction,
342
388
  blur: blurAction,
@@ -22,7 +22,7 @@
22
22
  v-if="url"
23
23
  :href="url"
24
24
  target="_blank"
25
- class="btn btn-white rounded-full p-1 shadow-sm ring-1 ring-black ring-opacity-10"
25
+ class="btn btn-white btn-sm rounded-full aspect-1 p-0 shadow-sm ring-1 ring-black ring-opacity-[0.15]"
26
26
  >
27
27
  <BaseIcon
28
28
  class="h-4 w-4"
@@ -33,7 +33,7 @@
33
33
  v-if="showRemove"
34
34
  type="button"
35
35
  :disabled="disabled"
36
- class="btn btn-white rounded-full p-1 shadow-sm ring-1 ring-black ring-opacity-10 disabled:bg-white disabled:opacity-70"
36
+ class="btn btn-white btn-sm rounded-full aspect-1 p-0 shadow-sm ring-1 ring-black ring-opacity-[0.15] disabled:bg-white disabled:opacity-70"
37
37
  @click="$emit('remove')"
38
38
  >
39
39
  <BaseIcon
@@ -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({});