sprintify-ui 0.5.11 → 0.6.0

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 (61) hide show
  1. package/dist/sprintify-ui.es.js +16157 -17178
  2. package/dist/style.css +1 -1
  3. package/dist/tailwindcss/index.js +1 -0
  4. package/dist/types/src/components/BaseAddressForm.vue.d.ts +0 -5
  5. package/dist/types/src/components/BaseAutocomplete.vue.d.ts +10 -1
  6. package/dist/types/src/components/BaseAutocompleteFetch.vue.d.ts +10 -1
  7. package/dist/types/src/components/BaseAvatar.vue.d.ts +18 -0
  8. package/dist/types/src/components/BaseBelongsTo.vue.d.ts +9 -0
  9. package/dist/types/src/components/BaseBelongsToFetch.vue.d.ts +9 -0
  10. package/dist/types/src/components/BaseCalendar.vue.d.ts +2 -2
  11. package/dist/types/src/components/BaseClipboard.vue.d.ts +0 -1
  12. package/dist/types/src/components/BaseDisplayRelativeTime.vue.d.ts +3 -4
  13. package/dist/types/src/components/BaseDropdown.vue.d.ts +12 -35
  14. package/dist/types/src/components/BaseDropdownAutocomplete.vue.d.ts +5 -15
  15. package/dist/types/src/components/BaseIconPicker.vue.d.ts +9 -9
  16. package/dist/types/src/components/BaseInput.vue.d.ts +2 -2
  17. package/dist/types/src/components/BaseInputLabel.vue.d.ts +0 -1
  18. package/dist/types/src/components/BaseInputPercent.vue.d.ts +2 -2
  19. package/dist/types/src/components/BaseLoadingCover.vue.d.ts +2 -2
  20. package/dist/types/src/components/BaseMediaLibrary.vue.d.ts +1 -1
  21. package/dist/types/src/components/BaseMenu.vue.d.ts +14 -5
  22. package/dist/types/src/components/BaseModalCenter.vue.d.ts +1 -1
  23. package/dist/types/src/components/BaseModalSide.vue.d.ts +1 -1
  24. package/dist/types/src/components/BaseRichText.vue.d.ts +1 -1
  25. package/dist/types/src/components/BaseSelect.vue.d.ts +1 -1
  26. package/dist/types/src/components/BaseTableColumn.vue.d.ts +2 -2
  27. package/dist/types/src/components/BaseTagAutocomplete.vue.d.ts +10 -1
  28. package/dist/types/src/components/BaseTagAutocompleteFetch.vue.d.ts +10 -1
  29. package/dist/types/src/components/BaseTextareaAutoresize.vue.d.ts +1 -1
  30. package/dist/types/src/components/BaseTooltip.vue.d.ts +19 -0
  31. package/dist/types/src/components/index.d.ts +1 -2
  32. package/dist/types/src/composables/tooltip.d.ts +7 -0
  33. package/package.json +2 -3
  34. package/src/assets/main.css +0 -1
  35. package/src/components/BaseAddressForm.vue +1 -2
  36. package/src/components/BaseAutocomplete.vue +27 -5
  37. package/src/components/BaseAutocompleteFetch.vue +5 -0
  38. package/src/components/BaseAvatar.vue +42 -2
  39. package/src/components/BaseAvatarGroup.stories.js +1 -1
  40. package/src/components/BaseAvatarGroup.vue +2 -2
  41. package/src/components/BaseBelongsTo.vue +5 -0
  42. package/src/components/BaseBelongsToFetch.vue +5 -0
  43. package/src/components/BaseClipboard.vue +56 -34
  44. package/src/components/BaseCounter.vue +1 -1
  45. package/src/components/BaseDataTable.vue +3 -1
  46. package/src/components/BaseDatePicker.vue +4 -4
  47. package/src/components/BaseDisplayRelativeTime.vue +15 -12
  48. package/src/components/BaseDropdown.stories.js +22 -65
  49. package/src/components/BaseDropdown.vue +37 -243
  50. package/src/components/BaseDropdownAutocomplete.vue +5 -30
  51. package/src/components/BaseHeader.vue +0 -1
  52. package/src/components/BaseInputLabel.vue +14 -11
  53. package/src/components/BaseLayoutNotificationDropdown.vue +1 -2
  54. package/src/components/BaseMenu.vue +121 -111
  55. package/src/components/BaseTagAutocomplete.vue +19 -2
  56. package/src/components/BaseTagAutocompleteFetch.vue +5 -0
  57. package/src/components/BaseTooltip.vue +40 -0
  58. package/src/components/index.ts +0 -2
  59. package/src/composables/tooltip.ts +43 -0
  60. package/dist/types/src/components/BaseClickOutside.vue.d.ts +0 -28
  61. package/src/components/BaseClickOutside.vue +0 -37
@@ -1,280 +1,74 @@
1
1
  <template>
2
- <div>
3
- <button
4
- ref="button"
5
- type="button"
6
- @click="toggle()"
7
- >
8
- <slot name="button" />
9
- </button>
2
+ <Popover v-slot="{ open }">
3
+ <PopoverButton class="outline-none">
4
+ <div ref="buttonRef">
5
+ <slot name="button" />
6
+ </div>
7
+ </PopoverButton>
8
+
10
9
  <Teleport to="body">
11
10
  <div
12
- ref="dropdown"
13
- class="z-menu"
14
- :style="dropdownStyles"
11
+ ref="dropdownRef"
12
+ :style="floatingStyles"
13
+ class="fixed top-0 left-0 z-menu"
15
14
  >
16
15
  <Transition
17
- :enter-active-class="
18
- animated ? 'transition duration-200 ease-out' : ''
19
- "
16
+ :enter-active-class="animated ? 'transition duration-200 ease-out' : ''"
20
17
  enter-from-class="transform scale-95 opacity-0"
21
18
  enter-to-class="transform scale-100 opacity-100"
22
19
  :leave-active-class="animated ? 'transition duration-75 ease-in' : ''"
23
20
  leave-from-class="transform scale-100 opacity-100"
24
21
  leave-to-class="transform scale-95 opacity-0"
25
22
  >
26
- <template v-if="showDropdown || keepAlive">
27
- <div
28
- v-show="showDropdown"
29
- class="inline-block"
23
+ <div v-if="open || keepAlive">
24
+ <PopoverPanel
25
+ v-show="open"
26
+ v-slot="{ close }"
27
+ static
30
28
  >
31
29
  <slot
32
30
  name="dropdown"
33
- :show-dropdown="showDropdown"
34
31
  :close="close"
35
- :open="open"
36
- :toggle="toggle"
32
+ :opened="open"
37
33
  />
38
- </div>
39
- </template>
34
+ </PopoverPanel>
35
+ </div>
40
36
  </Transition>
41
37
  </div>
42
38
  </Teleport>
43
- </div>
39
+ </Popover>
44
40
  </template>
45
41
 
46
42
  <script lang="ts" setup>
47
- import { useClickOutside } from '@/composables/clickOutside';
48
- import { MaybeElement, MaybeRef, useResizeObserver } from '@vueuse/core';
49
- import { throttle } from 'lodash';
50
- import { PropType, StyleValue } from 'vue';
51
- import { disableScroll, enableScroll } from '../utils';
43
+ import { autoUpdate, offset, flip, shift, useFloating, Placement } from '@floating-ui/vue';
44
+ import { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue';
45
+ import { unrefElement } from '@vueuse/core';
46
+ import { PropType } from 'vue';
47
+
48
+ const buttonRef = ref<InstanceType<typeof PopoverButton> | null>(null);
49
+ const dropdownRef = ref<HTMLElement | null>(null);
52
50
 
53
- const button = ref<HTMLElement | null>(null);
54
- const dropdown = ref<HTMLElement | null>(null);
51
+ const buttonRefEl = computed(() => unrefElement(buttonRef));
55
52
 
56
- const showDropdown = ref(false);
57
53
  const props = defineProps({
58
- placement: {
59
- type: String as PropType<
60
- 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end'
61
- >,
62
- default() {
63
- return 'bottom-start';
64
- },
65
- },
66
- padding: {
67
- default: 8,
68
- type: Number,
69
- },
70
54
  animated: {
71
- default: false,
55
+ default: true,
72
56
  type: Boolean,
73
57
  },
74
58
  keepAlive: {
75
- default: true,
59
+ default: false,
76
60
  type: Boolean,
77
61
  },
78
- });
79
-
80
- const emit = defineEmits(['close', 'open']);
81
-
82
- const buttonX = ref(0);
83
- const buttonY = ref(0);
84
- const buttonWidth = ref(0);
85
- const buttonHeight = ref(0);
86
-
87
- const dropdownX = ref(0);
88
- const dropdownY = ref(0);
89
- const dropdownWidth = ref(0);
90
- const dropdownHeight = ref(0);
91
-
92
- function setBoundingBoxes() {
93
- if (button.value) {
94
- const { y, x, height, width } = button.value.getBoundingClientRect();
95
- buttonX.value = x;
96
- buttonY.value = y;
97
- buttonWidth.value = width;
98
- buttonHeight.value = height;
99
- }
100
-
101
- if (dropdown.value) {
102
- const { y, x, height, width } = dropdown.value.getBoundingClientRect();
103
- dropdownX.value = x;
104
- dropdownY.value = y;
105
- dropdownWidth.value = width;
106
- dropdownHeight.value = height;
107
- }
108
- }
109
-
110
- function toggle() {
111
- if (showDropdown.value) {
112
- close();
113
- } else {
114
- open();
115
- }
116
- }
117
-
118
- function open() {
119
- activate();
120
- showDropdown.value = true;
121
- nextTick(() => {
122
- setBoundingBoxes();
123
- disableScroll();
124
- emit('open');
125
- });
126
- }
127
-
128
- function close() {
129
- deactivate();
130
- showDropdown.value = false;
131
- enableScroll();
132
- emit('close');
133
- }
134
-
135
- function onKeydown(event: KeyboardEvent) {
136
- if (event.code == 'Escape') {
137
- if (showDropdown.value) {
138
- close();
139
- }
140
- }
141
- }
142
-
143
- const setBoundingBoxesDebounced = throttle(() => {
144
- setBoundingBoxes();
145
- }, 10);
146
-
147
- let buttonResizeObserver = null as any;
148
- let dropdownResizeObserver = null as any;
149
-
150
- function activate() {
151
- buttonResizeObserver = useResizeObserver(button, setBoundingBoxesDebounced);
152
- dropdownResizeObserver = useResizeObserver(
153
- dropdown,
154
- setBoundingBoxesDebounced
155
- );
156
- window.addEventListener('keydown', onKeydown);
157
- window.addEventListener('resize', setBoundingBoxesDebounced);
158
- window.addEventListener('scroll', setBoundingBoxesDebounced, true);
159
- }
160
-
161
- function deactivate() {
162
- buttonResizeObserver?.stop();
163
- dropdownResizeObserver?.stop();
164
- window.removeEventListener('resize', setBoundingBoxesDebounced);
165
- window.removeEventListener('scroll', setBoundingBoxesDebounced, true);
166
- window.removeEventListener('keydown', onKeydown);
167
- }
168
-
169
- useClickOutside(
170
- dropdown,
171
- () => {
172
- if (showDropdown.value) {
173
- close();
174
- }
175
- },
176
- { includes: () => [button] }
177
- );
178
-
179
- const placementInternal = computed(() => {
180
- // vertical
181
- const spaceTop = buttonY.value - props.padding;
182
- const spaceBottom =
183
- window.innerHeight - buttonY.value - buttonHeight.value - props.padding;
184
-
185
- const tooTallForTop = spaceTop < dropdownHeight.value;
186
- const tooTallForBottom = spaceBottom < dropdownHeight.value;
187
-
188
- let verticalPreference = props.placement.split('-')[0];
189
-
190
- if (tooTallForTop && !tooTallForBottom) {
191
- verticalPreference = 'bottom';
192
- } else if (!tooTallForTop && tooTallForBottom) {
193
- verticalPreference = 'top';
194
- } else if (tooTallForTop && tooTallForBottom) {
195
- if (spaceTop > spaceBottom) {
196
- verticalPreference = 'top';
197
- } else {
198
- verticalPreference = 'bottom';
199
- }
200
- }
201
-
202
- // horizontal
203
- const spaceStart = buttonX.value + buttonWidth.value;
204
- const spaceEnd = window.innerWidth - buttonX.value;
205
-
206
- const tooLargeForStart = spaceStart < dropdownWidth.value;
207
- const tooLargeForEnd = spaceEnd < dropdownWidth.value;
208
-
209
- let horizontalPreference = props.placement.split('-')[1];
210
-
211
- if (tooLargeForStart && !tooLargeForEnd) {
212
- horizontalPreference = 'start';
213
- } else if (!tooLargeForStart && tooLargeForEnd) {
214
- horizontalPreference = 'end';
215
- } else if (tooLargeForStart && tooLargeForEnd) {
216
- if (spaceStart > spaceEnd) {
217
- horizontalPreference = 'end';
218
- } else {
219
- horizontalPreference = 'start';
220
- }
221
- }
222
-
223
- return `${verticalPreference}-${horizontalPreference}`;
224
- });
225
-
226
- const dropdownStyles = computed((): StyleValue => {
227
- let top = buttonY.value;
228
-
229
- if (
230
- placementInternal.value == 'bottom-start' ||
231
- placementInternal.value == 'bottom-end'
232
- ) {
233
- top += buttonHeight.value;
234
- top += props.padding;
235
- }
236
-
237
- if (
238
- placementInternal.value == 'top-start' ||
239
- placementInternal.value == 'top-end'
240
- ) {
241
- top -= dropdownHeight.value;
242
- top -= props.padding;
243
- }
244
-
245
- const styles = {
246
- position: 'fixed',
247
- top: `${top}px`,
248
- } as any;
249
-
250
- if (
251
- placementInternal.value == 'bottom-end' ||
252
- placementInternal.value == 'top-end'
253
- ) {
254
- styles.left = `${
255
- buttonX.value + buttonWidth.value - dropdownWidth.value
256
- }px`;
257
- } else {
258
- styles.left = `${buttonX.value}px`;
62
+ placement: {
63
+ default: 'bottom-end',
64
+ type: String as PropType<Placement>,
259
65
  }
260
-
261
- return styles as StyleValue;
262
66
  });
263
67
 
264
- const addClickOutsideInclude = inject('clickOutside:addInclude', () => {
265
- return;
266
- }) as (include: MaybeRef<MaybeElement> | string) => void;
267
-
268
- addClickOutsideInclude(dropdown);
269
-
270
- onBeforeUnmount(() => {
271
- close();
272
- deactivate();
68
+ const { floatingStyles } = useFloating(buttonRefEl, dropdownRef, {
69
+ placement: props.placement,
70
+ middleware: [offset(6), flip(), shift()],
71
+ whileElementsMounted: autoUpdate,
273
72
  });
274
73
 
275
- defineExpose({
276
- open,
277
- close,
278
- toggle,
279
- });
280
74
  </script>
@@ -3,9 +3,6 @@
3
3
  :animated="true"
4
4
  :keep-alive="false"
5
5
  :placement="placement"
6
- :padding="padding"
7
- @open="onOpen"
8
- @close="onClose"
9
6
  >
10
7
  <template #button="buttonProps">
11
8
  <slot
@@ -16,7 +13,7 @@
16
13
  </template>
17
14
  <template #dropdown="{ close }">
18
15
  <div
19
- class="inline-block w-[320px] overflow-hidden rounded-md border border-slate-300 bg-white px-1 pt-1 shadow-lg"
16
+ class="inline-block w-[320px] overflow-hidden rounded-md ring-1 ring-black ring-opacity-10 bg-white px-2 pt-2 shadow-lg"
20
17
  >
21
18
  <component
22
19
  :is="componentName"
@@ -29,6 +26,7 @@
29
26
  :inline="true"
30
27
  :required="required"
31
28
  :select="select"
29
+ :focus-on-mount="true"
32
30
  dropdown-show="always"
33
31
  @update:model-value="onUpdate($event, close)"
34
32
  >
@@ -69,6 +67,7 @@ import BaseAutocomplete from './BaseAutocomplete.vue';
69
67
  import BaseAutocompleteFetch from './BaseAutocompleteFetch.vue';
70
68
  import BaseTagAutocomplete from './BaseTagAutocomplete.vue';
71
69
  import BaseTagAutocompleteFetch from './BaseTagAutocompleteFetch.vue';
70
+ import { Placement } from '@floating-ui/vue';
72
71
 
73
72
  const props = defineProps({
74
73
  modelValue: {
@@ -110,14 +109,8 @@ const props = defineProps({
110
109
  type: String,
111
110
  },
112
111
  placement: {
113
- type: String as PropType<
114
- 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end'
115
- >,
116
- default: undefined,
117
- },
118
- padding: {
112
+ type: String as PropType<Placement>,
119
113
  default: undefined,
120
- type: Number,
121
114
  },
122
115
  select: {
123
116
  default: undefined,
@@ -125,7 +118,7 @@ const props = defineProps({
125
118
  },
126
119
  });
127
120
 
128
- const emit = defineEmits(['update:model-value', 'close']);
121
+ const emit = defineEmits(['update:model-value']);
129
122
 
130
123
  const componentName = computed<any>(() => {
131
124
  if (props.multiple) {
@@ -180,24 +173,6 @@ watch(
180
173
  { immediate: true, deep: true }
181
174
  );
182
175
 
183
- function onOpen() {
184
- nextTick(() => {
185
- setTimeout(() => {
186
- autocomplete.value?.open();
187
- }, 1);
188
- });
189
- }
190
-
191
- function onClose() {
192
- nextTick(() => {
193
- setTimeout(() => {
194
- autocomplete.value?.setKeywords('');
195
- }, 1);
196
- });
197
-
198
- emit('close');
199
- }
200
-
201
176
  function onUpdate(
202
177
  value: Option | Option[] | null | undefined,
203
178
  close: () => void
@@ -78,7 +78,6 @@
78
78
  v-if="secondaryActions.length"
79
79
  :items="secondaryActions"
80
80
  size="sm"
81
- :position="compactLayout ? 'bottom-right' : 'bottom-left'"
82
81
  >
83
82
  <template #button="{ open }">
84
83
  <div
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <label :class="classes">
3
3
  <div
4
- :ref="help ? 'info' : ''"
4
+ ref="labelRef"
5
5
  class="relative inline-flex"
6
6
  :class="[help ? 'cursor-help' : 'cursor-default']"
7
7
  >
@@ -18,16 +18,25 @@
18
18
  class="ml-0.5 text-red-600"
19
19
  > *</div>
20
20
  </div>
21
+
22
+ <BaseTooltip
23
+ v-if="help"
24
+ :target="labelRef"
25
+ >
26
+ <div class="text-xs">
27
+ {{ help }}
28
+ </div>
29
+ </BaseTooltip>
30
+
21
31
  </label>
22
32
  </template>
23
33
 
24
34
  <script lang="ts" setup>
25
35
  import { PropType } from 'vue';
26
36
  import { Icon as BaseIcon } from '@iconify/vue';
27
- import { useTippy } from 'vue-tippy'
28
- import 'tippy.js/dist/tippy.css'
37
+ import BaseTooltip from './BaseTooltip.vue';
29
38
 
30
- const props = defineProps({
39
+ defineProps({
31
40
  required: {
32
41
  default: false,
33
42
  type: Boolean,
@@ -46,12 +55,6 @@ const props = defineProps({
46
55
  },
47
56
  });
48
57
 
49
- const info = ref();
50
- const content = computed(() => { return props.help })
51
-
52
- useTippy(info, {
53
- content: content,
54
- placement: 'auto',
55
- })
58
+ const labelRef = ref();
56
59
 
57
60
  </script>
@@ -1,8 +1,7 @@
1
1
  <template>
2
2
  <BaseMenu
3
3
  class="inline-block"
4
- :position="mobile ? 'custom' : 'bottom-left'"
5
- :tw-menu="['sm:w-[320px] w-[280px]', mobile ? 'right-4' : '']"
4
+ :width="mobile ? 230 : 320"
6
5
  >
7
6
  <template #button="{ open }">
8
7
  <div