sprintify-ui 0.0.94 → 0.0.96
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.
- package/dist/sprintify-ui.es.js +4547 -4521
- package/dist/style.css +1 -1
- package/dist/types/src/components/BaseAutocomplete.vue.d.ts +2 -2
- package/dist/types/src/components/BaseColor.vue.d.ts +0 -16
- package/dist/types/src/components/BaseDatePicker.vue.d.ts +9 -0
- package/dist/types/src/components/BaseDropdown.vue.d.ts +3 -2
- package/dist/types/src/components/BaseFieldI18n.vue.d.ts +1 -1
- package/dist/types/src/components/BaseInput.vue.d.ts +1 -1
- package/dist/types/src/components/BaseInputPercent.vue.d.ts +1 -1
- package/dist/types/src/components/BaseLocaleForm.vue.d.ts +1 -1
- package/dist/types/src/components/BaseNavbarSideItem.vue.d.ts +3 -3
- package/dist/types/src/composables/clickOutside.d.ts +8 -0
- package/dist/types/src/composables/modal.d.ts +1 -1
- package/dist/types/src/utils/scrollPreventer.d.ts +1 -2
- package/package.json +1 -1
- package/src/components/BaseAppDialogs.vue +1 -1
- package/src/components/BaseAutocomplete.vue +6 -25
- package/src/components/BaseColor.stories.js +0 -2
- package/src/components/BaseColor.vue +3 -10
- package/src/components/BaseDatePicker.stories.js +5 -0
- package/src/components/BaseDatePicker.vue +8 -3
- package/src/components/BaseDropdown.stories.js +47 -9
- package/src/components/BaseDropdown.vue +27 -35
- package/src/components/BaseLayoutSidebar.vue +4 -1
- package/src/components/BaseModalCenter.vue +1 -5
- package/src/components/BaseModalSide.vue +1 -4
- package/src/components/BaseSideNavigation.vue +4 -1
- package/src/components/BaseTable.vue +1 -0
- package/src/components/BaseTabs.vue +4 -1
- package/src/components/BaseTagAutocomplete.vue +1 -0
- package/src/composables/clickOutside.ts +57 -0
- package/src/composables/modal.ts +2 -6
- package/src/utils/scrollPreventer.ts +3 -13
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import BaseBadge from './BaseBadge.vue';
|
|
2
2
|
import BaseAutocomplete from './BaseAutocomplete.vue';
|
|
3
|
+
import BaseModalCenter from './BaseModalCenter.vue';
|
|
3
4
|
import BaseDropdown from './BaseDropdown.vue';
|
|
4
5
|
import { options } from '../../.storybook/utils';
|
|
5
6
|
|
|
7
|
+
const items = [];
|
|
8
|
+
|
|
9
|
+
for (let i = 0; i < 100; i++) {
|
|
10
|
+
items.push({
|
|
11
|
+
label: `Item ${i + 1}`,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
|
|
6
15
|
export default {
|
|
7
16
|
title: 'Components/BaseDropdown',
|
|
8
17
|
component: BaseDropdown,
|
|
@@ -23,7 +32,7 @@ export default {
|
|
|
23
32
|
const Template = (args) => ({
|
|
24
33
|
components: { BaseDropdown },
|
|
25
34
|
setup() {
|
|
26
|
-
return { args };
|
|
35
|
+
return { args, items };
|
|
27
36
|
},
|
|
28
37
|
template: `
|
|
29
38
|
<div style="height: 1000px; margin-top: 300px;">
|
|
@@ -33,10 +42,11 @@ const Template = (args) => ({
|
|
|
33
42
|
<div class="btn btn-primary">Click me</div>
|
|
34
43
|
</template>
|
|
35
44
|
<template #dropdown>
|
|
36
|
-
<div
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
45
|
+
<div
|
|
46
|
+
class="bg-white shadow py-1 px-1 rounded"
|
|
47
|
+
style="max-height: 200px; overflow: auto;"
|
|
48
|
+
data-scroll-lock-scrollable>
|
|
49
|
+
<button type="button" v-for="item in items" :key="item.label" class="block text-sm px-4 py-1.5">{{ item.label }}</button>
|
|
40
50
|
</div>
|
|
41
51
|
</template>
|
|
42
52
|
</BaseDropdown>
|
|
@@ -67,11 +77,11 @@ export const WithAutocomplete = (args) => ({
|
|
|
67
77
|
}
|
|
68
78
|
|
|
69
79
|
function onClose() {
|
|
70
|
-
|
|
71
|
-
|
|
80
|
+
setTimeout(() => {
|
|
81
|
+
if (autocomplete.value) {
|
|
72
82
|
autocomplete.value.setKeywords('');
|
|
73
|
-
}
|
|
74
|
-
}
|
|
83
|
+
}
|
|
84
|
+
}, 10);
|
|
75
85
|
}
|
|
76
86
|
|
|
77
87
|
function onUpdate(v, close) {
|
|
@@ -113,3 +123,31 @@ WithAutocomplete.args = {
|
|
|
113
123
|
placement: 'bottom-start',
|
|
114
124
|
padding: 3,
|
|
115
125
|
};
|
|
126
|
+
|
|
127
|
+
export const ModalWithScroll = (args) => ({
|
|
128
|
+
components: { BaseDropdown, BaseModalCenter },
|
|
129
|
+
setup() {
|
|
130
|
+
return { args, items };
|
|
131
|
+
},
|
|
132
|
+
template: `
|
|
133
|
+
<BaseModalCenter :model-value="true">
|
|
134
|
+
<div class="p-10 bg-white">
|
|
135
|
+
<BaseDropdown v-bind="args">
|
|
136
|
+
<template #button>
|
|
137
|
+
<div class="btn btn-primary">Click me</div>
|
|
138
|
+
</template>
|
|
139
|
+
<template #dropdown>
|
|
140
|
+
<div
|
|
141
|
+
class="bg-white shadow py-1 px-1 rounded"
|
|
142
|
+
style="max-height: 200px; overflow: auto;"
|
|
143
|
+
data-scroll-lock-scrollable>
|
|
144
|
+
<button type="button" v-for="item in items" :key="item.label" class="block text-sm px-4 py-1.5">{{ item.label }}</button>
|
|
145
|
+
</div>
|
|
146
|
+
</template>
|
|
147
|
+
</BaseDropdown>
|
|
148
|
+
|
|
149
|
+
<div style="height: 3000px;"></div>
|
|
150
|
+
</div>
|
|
151
|
+
</BaseModalCenter>
|
|
152
|
+
`,
|
|
153
|
+
});
|
|
@@ -15,9 +15,10 @@
|
|
|
15
15
|
leave-from-class="transform scale-100 opacity-100"
|
|
16
16
|
leave-to-class="transform scale-90 opacity-0"
|
|
17
17
|
>
|
|
18
|
-
<div v-show="showDropdown" class="inline-block"
|
|
18
|
+
<div v-show="showDropdown" class="inline-block">
|
|
19
19
|
<slot
|
|
20
20
|
name="dropdown"
|
|
21
|
+
:show-dropdown="showDropdown"
|
|
21
22
|
:close="close"
|
|
22
23
|
:open="open"
|
|
23
24
|
:toggle="toggle"
|
|
@@ -30,6 +31,8 @@
|
|
|
30
31
|
</template>
|
|
31
32
|
|
|
32
33
|
<script lang="ts" setup>
|
|
34
|
+
import { useClickOutside } from '@/composables/clickOutside';
|
|
35
|
+
import { throttle } from 'lodash';
|
|
33
36
|
import { PropType, StyleValue } from 'vue';
|
|
34
37
|
import { disableScroll, enableScroll } from '../utils';
|
|
35
38
|
|
|
@@ -96,7 +99,7 @@ function open() {
|
|
|
96
99
|
showDropdown.value = true;
|
|
97
100
|
nextTick(() => {
|
|
98
101
|
setBoundingBoxes();
|
|
99
|
-
disableScroll(
|
|
102
|
+
disableScroll();
|
|
100
103
|
emit('open');
|
|
101
104
|
});
|
|
102
105
|
}
|
|
@@ -108,16 +111,6 @@ function close() {
|
|
|
108
111
|
emit('close');
|
|
109
112
|
}
|
|
110
113
|
|
|
111
|
-
function activate() {
|
|
112
|
-
window.addEventListener('keydown', onKeydown);
|
|
113
|
-
window.addEventListener('mousedown', onMouseDown);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function deactivate() {
|
|
117
|
-
window.removeEventListener('keydown', onKeydown);
|
|
118
|
-
window.removeEventListener('mousedown', onMouseDown);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
114
|
function onKeydown(event: KeyboardEvent) {
|
|
122
115
|
if (event.code == 'Escape') {
|
|
123
116
|
if (showDropdown.value) {
|
|
@@ -126,33 +119,32 @@ function onKeydown(event: KeyboardEvent) {
|
|
|
126
119
|
}
|
|
127
120
|
}
|
|
128
121
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
// Get the element that was clicked
|
|
134
|
-
const clickedElement = event.target as HTMLElement | null;
|
|
135
|
-
|
|
136
|
-
if (!clickedElement) {
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
122
|
+
const setBoundingBoxesDebounced = throttle(() => {
|
|
123
|
+
setBoundingBoxes();
|
|
124
|
+
}, 10);
|
|
139
125
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
126
|
+
function activate() {
|
|
127
|
+
window.addEventListener('keydown', onKeydown);
|
|
128
|
+
window.addEventListener('resize', setBoundingBoxesDebounced);
|
|
129
|
+
window.addEventListener('scroll', setBoundingBoxesDebounced, true);
|
|
130
|
+
}
|
|
147
131
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
close();
|
|
153
|
-
}
|
|
132
|
+
function deactivate() {
|
|
133
|
+
window.removeEventListener('resize', setBoundingBoxesDebounced);
|
|
134
|
+
window.removeEventListener('scroll', setBoundingBoxesDebounced, true);
|
|
135
|
+
window.removeEventListener('keydown', onKeydown);
|
|
154
136
|
}
|
|
155
137
|
|
|
138
|
+
useClickOutside(
|
|
139
|
+
dropdown,
|
|
140
|
+
(outside: boolean) => {
|
|
141
|
+
if (outside && showDropdown.value) {
|
|
142
|
+
close();
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
{ includes: [button] }
|
|
146
|
+
);
|
|
147
|
+
|
|
156
148
|
const placementInternal = computed(() => {
|
|
157
149
|
const tooTallForTop =
|
|
158
150
|
buttonY.value - dropdownHeight.value - props.padding < 0;
|
|
@@ -59,7 +59,10 @@
|
|
|
59
59
|
<div class="flex flex-shrink-0 items-center px-4">
|
|
60
60
|
<img class="block h-8 w-auto" :src="logoUrl" :alt="appName" />
|
|
61
61
|
</div>
|
|
62
|
-
<div
|
|
62
|
+
<div
|
|
63
|
+
data-scroll-lock-scrollable
|
|
64
|
+
class="mt-5 h-0 flex-1 overflow-y-auto"
|
|
65
|
+
>
|
|
63
66
|
<nav>
|
|
64
67
|
<slot name="menu" />
|
|
65
68
|
</nav>
|
|
@@ -7,9 +7,8 @@
|
|
|
7
7
|
>
|
|
8
8
|
<div v-show="modelValue">
|
|
9
9
|
<div
|
|
10
|
-
|
|
10
|
+
data-scroll-lock-scrollable
|
|
11
11
|
class="fixed inset-0 z-modal w-full overflow-y-auto overflow-x-hidden"
|
|
12
|
-
scroll-lock-target
|
|
13
12
|
>
|
|
14
13
|
<div
|
|
15
14
|
class="flex min-h-full w-full items-end justify-center overflow-hidden sm:px-6 sm:pb-6"
|
|
@@ -112,11 +111,8 @@ const props = defineProps({
|
|
|
112
111
|
|
|
113
112
|
const emit = defineEmits(['update:modelValue']);
|
|
114
113
|
|
|
115
|
-
const allow = ref(null);
|
|
116
|
-
|
|
117
114
|
const modal = useModal(
|
|
118
115
|
computed(() => props.modelValue),
|
|
119
|
-
allow,
|
|
120
116
|
emit as any
|
|
121
117
|
);
|
|
122
118
|
</script>
|
|
@@ -7,9 +7,8 @@
|
|
|
7
7
|
>
|
|
8
8
|
<div v-show="modelValue">
|
|
9
9
|
<div
|
|
10
|
-
|
|
10
|
+
data-scroll-lock-scrollable
|
|
11
11
|
class="fixed inset-0 z-modal w-full overflow-y-auto overflow-x-hidden"
|
|
12
|
-
scroll-lock-target
|
|
13
12
|
>
|
|
14
13
|
<div class="flex min-h-full w-full pt-20 sm:pt-0">
|
|
15
14
|
<div class="min-h-full grow">
|
|
@@ -97,10 +96,8 @@ const props = defineProps({
|
|
|
97
96
|
|
|
98
97
|
const emit = defineEmits(['update:modelValue']);
|
|
99
98
|
|
|
100
|
-
const allow = ref(null);
|
|
101
99
|
const modal = useModal(
|
|
102
100
|
computed(() => props.modelValue),
|
|
103
|
-
allow,
|
|
104
101
|
emit
|
|
105
102
|
);
|
|
106
103
|
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<nav aria-label="Sidebar" class="relative">
|
|
3
3
|
<div class="absolute bottom-0 left-0 h-full w-px bg-slate-300" />
|
|
4
|
-
<div
|
|
4
|
+
<div
|
|
5
|
+
class="relative overflow-x-auto overflow-y-hidden"
|
|
6
|
+
data-scroll-lock-scrollable
|
|
7
|
+
>
|
|
5
8
|
<div class="space-y-2">
|
|
6
9
|
<slot />
|
|
7
10
|
</div>
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="relative">
|
|
3
3
|
<div class="absolute bottom-0 left-0 h-px w-full bg-slate-300" />
|
|
4
|
-
<div
|
|
4
|
+
<div
|
|
5
|
+
class="relative overflow-x-auto overflow-y-hidden"
|
|
6
|
+
data-scroll-lock-scrollable
|
|
7
|
+
>
|
|
5
8
|
<ul class="flex space-x-4 text-center">
|
|
6
9
|
<slot />
|
|
7
10
|
</ul>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { MaybeElementRef, unrefElement, tryOnScopeDispose } from '@vueuse/core';
|
|
2
|
+
|
|
3
|
+
interface UseClickOutsideOptions {
|
|
4
|
+
includes?: MaybeElementRef[];
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function useClickOutside(
|
|
8
|
+
element: MaybeElementRef,
|
|
9
|
+
callback: (outside: boolean) => void,
|
|
10
|
+
options: UseClickOutsideOptions = {}
|
|
11
|
+
) {
|
|
12
|
+
function cleanup() {
|
|
13
|
+
window.removeEventListener('mousedown', onClick);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const stopWatch = watch(
|
|
17
|
+
() => unrefElement(element),
|
|
18
|
+
(el) => {
|
|
19
|
+
if (el) {
|
|
20
|
+
cleanup();
|
|
21
|
+
window.addEventListener('mousedown', onClick);
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
{ immediate: true }
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
function onClick(e: Event) {
|
|
28
|
+
const el = unrefElement(element);
|
|
29
|
+
|
|
30
|
+
const includeEls = options.includes?.map(unrefElement) ?? [];
|
|
31
|
+
|
|
32
|
+
if (!el) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const contains = el.contains(e.target as HTMLElement);
|
|
37
|
+
|
|
38
|
+
const includeContainsEl = includeEls.some((exceptionEl) =>
|
|
39
|
+
exceptionEl?.contains(e.target as HTMLElement)
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const outside = !contains && !includeContainsEl;
|
|
43
|
+
|
|
44
|
+
callback(outside);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const stop = () => {
|
|
48
|
+
cleanup();
|
|
49
|
+
stopWatch();
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
tryOnScopeDispose(stop);
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
stop,
|
|
56
|
+
};
|
|
57
|
+
}
|
package/src/composables/modal.ts
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import { disableScroll, enableScroll } from '../utils';
|
|
2
2
|
import { Ref } from 'vue';
|
|
3
3
|
|
|
4
|
-
export function useModal(
|
|
5
|
-
modelValue: Ref<boolean>,
|
|
6
|
-
scrollable: Ref<HTMLElement | null>,
|
|
7
|
-
emit: any
|
|
8
|
-
) {
|
|
4
|
+
export function useModal(modelValue: Ref<boolean>, emit: any) {
|
|
9
5
|
const mounted = ref(false);
|
|
10
6
|
|
|
11
7
|
watch(
|
|
@@ -38,7 +34,7 @@ export function useModal(
|
|
|
38
34
|
}
|
|
39
35
|
|
|
40
36
|
function activate() {
|
|
41
|
-
disableScroll(
|
|
37
|
+
disableScroll();
|
|
42
38
|
window.addEventListener('keydown', onKeydown);
|
|
43
39
|
}
|
|
44
40
|
|
|
@@ -1,20 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
disablePageScroll,
|
|
3
|
-
clearQueueScrollLocks,
|
|
4
|
-
enablePageScroll,
|
|
5
|
-
ScrollableTarget,
|
|
6
|
-
} from 'scroll-lock';
|
|
1
|
+
import { disablePageScroll, enablePageScroll } from 'scroll-lock';
|
|
7
2
|
|
|
8
|
-
function disableScroll(
|
|
9
|
-
|
|
10
|
-
allow = document.querySelectorAll('[scroll-lock-target]');
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
disablePageScroll(allow);
|
|
3
|
+
function disableScroll() {
|
|
4
|
+
disablePageScroll();
|
|
14
5
|
}
|
|
15
6
|
|
|
16
7
|
function enableScroll() {
|
|
17
|
-
clearQueueScrollLocks();
|
|
18
8
|
enablePageScroll();
|
|
19
9
|
}
|
|
20
10
|
|