sprintify-ui 0.0.195 → 0.0.197

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 (56) hide show
  1. package/dist/sprintify-ui.es.js +7969 -7889
  2. package/dist/types/src/components/BaseAddressForm.vue.d.ts +2 -2
  3. package/dist/types/src/components/BaseAutocomplete.vue.d.ts +5 -5
  4. package/dist/types/src/components/BaseAutocompleteDrawer.vue.d.ts +2 -2
  5. package/dist/types/src/components/BaseAutocompleteFetch.vue.d.ts +5 -5
  6. package/dist/types/src/components/BaseBelongsTo.vue.d.ts +3 -3
  7. package/dist/types/src/components/BaseButtonGroup.vue.d.ts +2 -2
  8. package/dist/types/src/components/BaseCharacterCounter.vue.d.ts +1 -1
  9. package/dist/types/src/components/BaseColor.vue.d.ts +2 -2
  10. package/dist/types/src/components/BaseCounter.vue.d.ts +6 -6
  11. package/dist/types/src/components/BaseDatePicker.vue.d.ts +1 -1
  12. package/dist/types/src/components/BaseDropdownAutocomplete.vue.d.ts +4 -4
  13. package/dist/types/src/components/BaseFieldI18n.vue.d.ts +2 -2
  14. package/dist/types/src/components/BaseFilePicker.vue.d.ts +1 -1
  15. package/dist/types/src/components/BaseFileUploader.vue.d.ts +2 -2
  16. package/dist/types/src/components/BaseForm.vue.d.ts +1 -1
  17. package/dist/types/src/components/BaseHasMany.vue.d.ts +2 -2
  18. package/dist/types/src/components/BaseInput.vue.d.ts +5 -5
  19. package/dist/types/src/components/BaseInputPercent.vue.d.ts +4 -4
  20. package/dist/types/src/components/BaseLayoutNotificationDropdown.vue.d.ts +9 -0
  21. package/dist/types/src/components/BaseLayoutSidebar.vue.d.ts +10 -0
  22. package/dist/types/src/components/BaseLayoutSidebarConfigurable.vue.d.ts +9 -0
  23. package/dist/types/src/components/BaseLoadingCover.vue.d.ts +2 -2
  24. package/dist/types/src/components/BaseMediaLibrary.vue.d.ts +4 -4
  25. package/dist/types/src/components/BaseModalCenter.vue.d.ts +1 -1
  26. package/dist/types/src/components/BaseModalSide.vue.d.ts +1 -1
  27. package/dist/types/src/components/BaseNavbarItemContent.vue.d.ts +11 -1
  28. package/dist/types/src/components/BaseNavbarSideItem.vue.d.ts +9 -0
  29. package/dist/types/src/components/BaseNavbarSideItemContent.vue.d.ts +11 -1
  30. package/dist/types/src/components/BaseNumber.vue.d.ts +16 -7
  31. package/dist/types/src/components/BasePassword.vue.d.ts +2 -2
  32. package/dist/types/src/components/BaseRadioGroup.vue.d.ts +1 -1
  33. package/dist/types/src/components/BaseRichText.vue.d.ts +2 -2
  34. package/dist/types/src/components/BaseSelect.vue.d.ts +3 -3
  35. package/dist/types/src/components/BaseSwitch.vue.d.ts +1 -1
  36. package/dist/types/src/components/BaseTagAutocomplete.vue.d.ts +4 -4
  37. package/dist/types/src/components/BaseTagAutocompleteFetch.vue.d.ts +2 -2
  38. package/dist/types/src/components/BaseTextarea.vue.d.ts +3 -3
  39. package/dist/types/src/components/BaseTextareaAutoresize.vue.d.ts +2 -2
  40. package/package.json +1 -1
  41. package/src/components/BaseAvatar.vue +1 -1
  42. package/src/components/BaseCounter.stories.js +15 -0
  43. package/src/components/BaseCounter.vue +16 -8
  44. package/src/components/BaseForm.stories.js +48 -0
  45. package/src/components/BaseForm.vue +10 -5
  46. package/src/components/BaseLayoutNotificationDropdown.vue +39 -8
  47. package/src/components/BaseLayoutSidebar.vue +19 -3
  48. package/src/components/BaseLayoutSidebarConfigurable.stories.js +34 -16
  49. package/src/components/BaseLayoutSidebarConfigurable.vue +48 -11
  50. package/src/components/BaseMenuItem.vue +4 -9
  51. package/src/components/BaseNavbarItemContent.vue +13 -7
  52. package/src/components/BaseNavbarSideItem.vue +28 -8
  53. package/src/components/BaseNavbarSideItemContent.vue +40 -13
  54. package/src/components/BaseNumber.stories.js +19 -3
  55. package/src/components/BaseNumber.vue +57 -4
  56. package/src/composables/field.ts +11 -4
@@ -2,7 +2,7 @@
2
2
  <div :class="classes">
3
3
  <div class="group flex grow items-center">
4
4
  <BaseIcon v-if="icon" :icon="icon" :class="iconClasses" />
5
- {{ label }}
5
+ <span :class="[sizeClasses]">{{ label }}</span>
6
6
  </div>
7
7
  <div v-if="count" class="relative -top-px ml-[5px]">
8
8
  <BaseCounter :count="count" :max-digit="2" :color="'primary'" />
@@ -12,6 +12,7 @@
12
12
 
13
13
  <script lang="ts" setup>
14
14
  import { Icon as BaseIcon } from '@iconify/vue';
15
+ import { PropType } from 'vue';
15
16
  import BaseCounter from './BaseCounter.vue';
16
17
 
17
18
  const props = defineProps({
@@ -35,6 +36,10 @@ const props = defineProps({
35
36
  default: false,
36
37
  type: Boolean,
37
38
  },
39
+ size: {
40
+ default: 'md',
41
+ type: String as PropType<'sm' | 'md'>,
42
+ },
38
43
  });
39
44
 
40
45
  const classes = computed(() => {
@@ -42,12 +47,6 @@ const classes = computed(() => {
42
47
  'text-left border-b-2 px-2 flex items-center text-base font-medium w-full',
43
48
  ];
44
49
 
45
- if (props.dark) {
46
- classList.push('');
47
- } else {
48
- classList.push('');
49
- }
50
-
51
50
  if (props.active) {
52
51
  if (props.dark) {
53
52
  classList.push('border-white text-white');
@@ -77,4 +76,11 @@ const iconClasses = computed((): string[] => {
77
76
  }
78
77
  return classList;
79
78
  });
79
+
80
+ const sizeClasses = computed(() => {
81
+ if (props.size == 'sm') {
82
+ return 'text-sm';
83
+ }
84
+ return 'text-base';
85
+ });
80
86
  </script>
@@ -15,25 +15,21 @@
15
15
  :active="active"
16
16
  :count="item.count"
17
17
  :dark="dark"
18
+ :size="size"
18
19
  />
19
20
  </template>
20
21
  </BaseActionItem>
21
22
 
22
23
  <div
23
24
  v-if="showSubActions && item.actions && item.actions.length"
24
- class="ml-10 mt-1.5 mb-3"
25
+ class="mt-2 mb-3"
25
26
  >
26
- <div v-for="subItem in item.actions" :key="subItem.label" class="mb-1">
27
+ <div v-for="subItem in item.actions" :key="subItem.label">
27
28
  <BaseActionItem
28
29
  :to="subItem.to"
29
30
  :href="subItem.href"
30
31
  :action="subItem.action"
31
- :class="[
32
- 'flex w-full',
33
- dark
34
- ? 'text-slate-300 hover:text-white'
35
- : 'text-slate-900 hover:text-slate-600',
36
- ]"
32
+ :class="subItemClasses"
37
33
  >
38
34
  {{ subItem.label }}
39
35
  </BaseActionItem>
@@ -61,6 +57,10 @@ const props = defineProps({
61
57
  default: 'toggle',
62
58
  type: String as PropType<'toggle' | 'always'>,
63
59
  },
60
+ size: {
61
+ default: 'md',
62
+ type: String as PropType<'xs' | 'sm' | 'md'>,
63
+ },
64
64
  });
65
65
 
66
66
  const emit = defineEmits(['click']);
@@ -88,4 +88,24 @@ const showSubActions = computed((): boolean => {
88
88
  }
89
89
  return routeActive.value;
90
90
  });
91
+
92
+ const subItemClasses = computed((): string[] => {
93
+ const classList = ['flex w-full font-normal'];
94
+
95
+ if (props.dark) {
96
+ classList.push('text-slate-300 hover:text-white');
97
+ } else {
98
+ classList.push('text-slate-900 hover:text-slate-600');
99
+ }
100
+
101
+ if (props.size == 'xs') {
102
+ classList.push('pl-[33.5px] text-[13px] mb-1');
103
+ } else if (props.size == 'sm') {
104
+ classList.push('pl-[36px] text-sm mb-1.5');
105
+ } else {
106
+ classList.push('pl-[40px] text-base mb-1');
107
+ }
108
+
109
+ return classList;
110
+ });
91
111
  </script>
@@ -2,16 +2,22 @@
2
2
  <div :class="classes">
3
3
  <div class="group flex grow items-center">
4
4
  <BaseIcon v-if="icon" :icon="icon" :class="iconClasses" />
5
- {{ label }}
5
+ <span>{{ label }}</span>
6
6
  </div>
7
7
  <div v-if="count" class="relative -top-px ml-[5px]">
8
- <BaseCounter :count="count" :max-digit="2" :color="'primary'" />
8
+ <BaseCounter
9
+ :size="size"
10
+ :count="count"
11
+ :max-digit="2"
12
+ :color="'primary'"
13
+ />
9
14
  </div>
10
15
  </div>
11
16
  </template>
12
17
 
13
18
  <script lang="ts" setup>
14
19
  import { Icon as BaseIcon } from '@iconify/vue';
20
+ import { PropType } from 'vue';
15
21
  import BaseCounter from './BaseCounter.vue';
16
22
 
17
23
  const props = defineProps({
@@ -35,24 +41,20 @@ const props = defineProps({
35
41
  default: false,
36
42
  type: Boolean,
37
43
  },
44
+ size: {
45
+ default: 'md',
46
+ type: String as PropType<'xs' | 'sm' | 'md'>,
47
+ },
38
48
  });
39
49
 
40
50
  const classes = computed(() => {
41
- const classList = [
42
- 'text-left px-3 py-2 rounded-md flex text-base font-medium w-full',
43
- ];
44
-
45
- if (props.dark) {
46
- classList.push('');
47
- } else {
48
- classList.push('');
49
- }
51
+ const classList = ['text-left rounded-md flex w-full'];
50
52
 
51
53
  if (props.active) {
52
54
  if (props.dark) {
53
55
  classList.push('bg-slate-700 text-white');
54
56
  } else {
55
- classList.push('bg-slate-100 text-slate-900');
57
+ classList.push('bg-slate-100 text-primary-700');
56
58
  }
57
59
  } else {
58
60
  if (props.dark) {
@@ -62,16 +64,41 @@ const classes = computed(() => {
62
64
  }
63
65
  }
64
66
 
67
+ if (props.size == 'xs') {
68
+ classList.push('text-[13px] px-2.5 py-1 font-medium');
69
+ }
70
+
71
+ if (props.size == 'sm') {
72
+ classList.push('text-sm px-3 py-1.5 font-medium');
73
+ }
74
+
75
+ if (props.size == 'md') {
76
+ classList.push('text-base px-3 py-2 font-medium');
77
+ }
78
+
65
79
  return classList;
66
80
  });
67
81
 
68
82
  const iconClasses = computed((): string[] => {
69
- const classList = ['w-5 h-5 shrink-0 mr-2 leading-none inline-block'];
83
+ const classList = ['shrink-0 leading-none inline-block'];
70
84
  if (props.active) {
71
85
  classList.push('opacity-100');
72
86
  } else {
73
87
  classList.push('opacity-70 group-hover:opacity-100');
74
88
  }
89
+
90
+ if (props.size == 'xs') {
91
+ classList.push('w-3.5 h-3.5 mr-2');
92
+ }
93
+
94
+ if (props.size == 'sm') {
95
+ classList.push('w-4 h-4 mr-2');
96
+ }
97
+
98
+ if (props.size == 'md') {
99
+ classList.push('w-5 h-5 mr-2');
100
+ }
101
+
75
102
  return classList;
76
103
  });
77
104
  </script>
@@ -8,8 +8,6 @@ export default {
8
8
  args: {
9
9
  placeholder: 'Enter number',
10
10
  step: 0.1,
11
- min: 0,
12
- max: 100,
13
11
  },
14
12
  };
15
13
 
@@ -19,7 +17,7 @@ const Template = (args) => ({
19
17
  BaseNumber,
20
18
  },
21
19
  setup() {
22
- const value = ref(12.1212);
20
+ const value = ref(null);
23
21
  return { args, value };
24
22
  },
25
23
  template: `
@@ -33,6 +31,24 @@ const Template = (args) => ({
33
31
  export const Demo = Template.bind({});
34
32
  Demo.args = {};
35
33
 
34
+ export const Min = Template.bind({});
35
+ Min.args = {
36
+ min: 10000,
37
+ };
38
+
39
+ export const Max = Template.bind({});
40
+ Max.args = {
41
+ max: 10000,
42
+ };
43
+
44
+ export const AutoFix = Template.bind({});
45
+ AutoFix.args = {
46
+ autoFix: true,
47
+ min: 10,
48
+ max: 20,
49
+ step: 0.01,
50
+ };
51
+
36
52
  export const Disabled = Template.bind({});
37
53
  Disabled.args = {
38
54
  disabled: true,
@@ -8,7 +8,7 @@
8
8
  leave-from-class="transform scale-100 opacity-100"
9
9
  leave-to-class="transform scale-90 opacity-0"
10
10
  >
11
- <div v-if="invalidInput" class="absolute left-0 top-full">
11
+ <div v-if="showInvalidInput" class="absolute left-0 top-full z-[1]">
12
12
  <div
13
13
  class="mt-1 ml-1 rounded bg-red-500 px-2 py-1 text-xs font-medium text-white"
14
14
  >
@@ -36,7 +36,7 @@
36
36
  :max="max"
37
37
  :class="[
38
38
  ['full', 'left'].includes(rounded) ? 'rounded-l' : '',
39
- invalidInput ? 'focus:ring-red-400' : 'focus:ring-primary-500',
39
+ showInvalidInput ? 'focus:ring-red-400' : 'focus:ring-primary-500',
40
40
  ]"
41
41
  class="w-full border-none focus:z-[1] focus:border-none focus:border-transparent focus:shadow-none focus:outline-none focus:ring-2 focus:ring-offset-1 disabled:cursor-not-allowed disabled:text-slate-300"
42
42
  type="text"
@@ -73,8 +73,10 @@
73
73
  import { useField } from '@/composables/field';
74
74
  import { isNumber, round } from 'lodash';
75
75
  import { PropType } from 'vue';
76
+ import { BaseIcon } from '.';
76
77
 
77
78
  const AUTO_CORRECT_TIMEOUT = 2000;
79
+ const SHOW_INVALID_INPUT_TIMEOUT = 500;
78
80
 
79
81
  const props = defineProps({
80
82
  modelValue: {
@@ -124,17 +126,23 @@ const props = defineProps({
124
126
  default: 'full',
125
127
  type: String as PropType<'full' | 'left' | 'right' | 'none'>,
126
128
  },
129
+ autoFix: {
130
+ default: false,
131
+ type: Boolean,
132
+ },
127
133
  });
128
134
 
129
135
  const emit = defineEmits(['update:modelValue', 'focus', 'blur', 'keydown']);
130
136
 
131
- const { hasErrorInternal, emitUpdate } = useField({
137
+ const { hasErrorInternal, emitUpdate, enableForm, disableForm } = useField({
132
138
  name: computed(() => props.name),
133
139
  required: computed(() => props.required),
134
140
  hasError: computed(() => props.hasError),
135
141
  emit: emit,
136
142
  });
137
143
 
144
+ const showInvalidInput = ref(false);
145
+
138
146
  const stepNormalized = computed<number>(() => {
139
147
  if (props.step === undefined) return 1;
140
148
  if (props.step === 0) return 1;
@@ -170,9 +178,11 @@ function convertToNumber(
170
178
  }
171
179
 
172
180
  const valueInternal = ref<null | string | number>(null);
181
+
173
182
  const realValueInternal = computed<number | null>(() => {
174
183
  return convertToNumber(valueInternal.value);
175
184
  });
185
+
176
186
  const invalidInput = computed(() => {
177
187
  if (realValueInternal.value == null && valueInternal.value == '') {
178
188
  return false;
@@ -180,10 +190,12 @@ const invalidInput = computed(() => {
180
190
 
181
191
  return realValueInternal.value != valueInternal.value;
182
192
  });
193
+
183
194
  const tooBig = computed(() => {
184
195
  if (valueInternal.value === null) return false;
185
196
  return hasMax.value && valueInternal.value > (props.max as number);
186
197
  });
198
+
187
199
  const tooSmall = computed(() => {
188
200
  if (valueInternal.value === null) return false;
189
201
  return hasMin.value && valueInternal.value < (props.min as number);
@@ -214,13 +226,37 @@ function onInput(event: any) {
214
226
 
215
227
  emitUpdate(realValueInternal.value);
216
228
 
229
+ nextTick(() => {
230
+ showHideInvalidOnInput();
231
+ });
232
+
217
233
  timeoutId = setTimeout(() => {
218
234
  updateInternalValueToRealValue();
219
235
  }, AUTO_CORRECT_TIMEOUT);
220
236
  }
221
237
 
238
+ let showInvalidInputTimeoutId = undefined as undefined | number;
239
+
240
+ function showHideInvalidOnInput() {
241
+ clearTimeout(showInvalidInputTimeoutId);
242
+
243
+ if (!invalidInput.value) {
244
+ showInvalidInput.value = false;
245
+ return;
246
+ }
247
+
248
+ showInvalidInputTimeoutId = setTimeout(() => {
249
+ showInvalidInput.value = true;
250
+ }, SHOW_INVALID_INPUT_TIMEOUT);
251
+ }
252
+
222
253
  function onBlur(e: Event) {
223
254
  emit('blur', e);
255
+
256
+ if (invalidInput.value) {
257
+ showInvalidInput.value = true;
258
+ }
259
+
224
260
  updateInternalValueToRealValue();
225
261
  }
226
262
 
@@ -244,6 +280,9 @@ const defaultValue = computed<number>(() => {
244
280
  });
245
281
 
246
282
  function updateInternalValueToRealValue() {
283
+ if (!props.autoFix) {
284
+ return;
285
+ }
247
286
  if (realValueInternal.value === null) {
248
287
  valueInternal.value = '';
249
288
  return;
@@ -287,7 +326,21 @@ function decrement() {
287
326
  }
288
327
 
289
328
  const borderColor = computed(() => {
290
- if (hasErrorInternal.value) return 'border-red-500';
329
+ if (hasErrorInternal.value || invalidInput.value) return 'border-red-500';
291
330
  return 'border-slate-300';
292
331
  });
332
+
333
+ /** Disable form */
334
+
335
+ watch(
336
+ () => invalidInput.value,
337
+ () => {
338
+ if (invalidInput.value) {
339
+ disableForm();
340
+ } else {
341
+ enableForm();
342
+ }
343
+ },
344
+ { immediate: true }
345
+ );
293
346
  </script>
@@ -1,3 +1,4 @@
1
+ import { uniqueId } from 'lodash';
1
2
  import { Ref } from 'vue';
2
3
 
3
4
  interface Config {
@@ -10,6 +11,7 @@ interface Config {
10
11
  }
11
12
 
12
13
  export function useField(config: Config) {
14
+ const uuid = uniqueId();
13
15
  const name = config.name;
14
16
  const required = config.required;
15
17
  const hasError = config.hasError;
@@ -60,11 +62,15 @@ export function useField(config: Config) {
60
62
 
61
63
  const disableForm = inject('form:disable', () => {
62
64
  return;
63
- }) as () => void;
65
+ }) as (uuid: string) => void;
64
66
 
65
67
  const enableForm = inject('form:enable', () => {
66
68
  return;
67
- }) as () => void;
69
+ }) as (uuid: string) => void;
70
+
71
+ onBeforeUnmount(() => {
72
+ enableForm(uuid);
73
+ });
68
74
 
69
75
  const requiredInternal = computed((): boolean => {
70
76
  if (required.value) {
@@ -98,13 +104,14 @@ export function useField(config: Config) {
98
104
  emit('update:modelValue', value);
99
105
  fieldOnUpdate();
100
106
  }
107
+
101
108
  return {
102
109
  requiredInternal,
103
110
  nameInternal,
104
111
  hasErrorInternal,
105
112
  errorMessageInternal,
106
113
  emitUpdate,
107
- enableForm,
108
- disableForm,
114
+ enableForm: () => enableForm(uuid),
115
+ disableForm: () => disableForm(uuid),
109
116
  };
110
117
  }