sprintify-ui 0.0.93 → 0.0.95
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 +15422 -6148
- package/dist/style.css +1 -1
- package/dist/types/src/components/BaseActionItem.vue.d.ts +25 -102
- package/dist/types/src/components/BaseApp.vue.d.ts +8 -47
- package/dist/types/src/components/BaseAutocomplete.vue.d.ts +91 -327
- package/dist/types/src/components/BaseAutocompleteFetch.vue.d.ts +85 -290
- package/dist/types/src/components/BaseBadge.vue.d.ts +27 -110
- package/dist/types/src/components/BaseBelongsTo.vue.d.ts +89 -294
- package/dist/types/src/components/BaseButtonGroup.vue.d.ts +71 -254
- package/dist/types/src/components/BaseCard.vue.d.ts +15 -68
- package/dist/types/src/components/BaseClipboard.vue.d.ts +15 -68
- package/dist/types/src/components/BaseColor.vue.d.ts +63 -0
- package/dist/types/src/components/BaseDataIterator.vue.d.ts +82 -258
- package/dist/types/src/components/BaseDataTable.vue.d.ts +158 -509
- package/dist/types/src/components/BaseDescriptionList.vue.d.ts +8 -47
- package/dist/types/src/components/BaseDescriptionListItem.vue.d.ts +9 -48
- package/dist/types/src/components/BaseDialog.vue.d.ts +31 -131
- package/dist/types/src/components/BaseDropdown.vue.d.ts +30 -111
- package/dist/types/src/components/BaseField.vue.d.ts +31 -124
- package/dist/types/src/components/BaseFieldI18n.vue.d.ts +1 -1
- package/dist/types/src/components/BaseFileUploader.vue.d.ts +54 -192
- package/dist/types/src/components/BaseForm.vue.d.ts +62 -226
- package/dist/types/src/components/BaseHasMany.vue.d.ts +66 -219
- package/dist/types/src/components/BaseInput.vue.d.ts +10 -1
- package/dist/types/src/components/BaseInputError.vue.d.ts +8 -47
- package/dist/types/src/components/BaseInputPercent.vue.d.ts +1 -1
- package/dist/types/src/components/BaseLayoutSidebar.vue.d.ts +25 -98
- package/dist/types/src/components/BaseLayoutSidebarConfigurable.vue.d.ts +39 -155
- package/dist/types/src/components/BaseLayoutStacked.vue.d.ts +17 -70
- package/dist/types/src/components/BaseLayoutStackedConfigurable.vue.d.ts +39 -155
- package/dist/types/src/components/BaseLocaleForm.vue.d.ts +1 -1
- package/dist/types/src/components/BaseMediaLibrary.vue.d.ts +63 -234
- package/dist/types/src/components/BaseMenu.vue.d.ts +32 -105
- package/dist/types/src/components/BaseModalCenter.vue.d.ts +42 -132
- package/dist/types/src/components/BaseModalSide.vue.d.ts +29 -118
- package/dist/types/src/components/BaseNavbar.vue.d.ts +24 -87
- package/dist/types/src/components/BaseNavbarSideItem.vue.d.ts +3 -3
- package/dist/types/src/components/BaseRadioGroup.vue.d.ts +53 -194
- package/dist/types/src/components/BaseReadMore.vue.d.ts +15 -68
- package/dist/types/src/components/BaseRichText.vue.d.ts +92 -0
- package/dist/types/src/components/BaseSelect.vue.d.ts +35 -144
- package/dist/types/src/components/BaseSideNavigation.vue.d.ts +8 -47
- package/dist/types/src/components/BaseSideNavigationItem.vue.d.ts +23 -94
- package/dist/types/src/components/BaseSkeleton.vue.d.ts +19 -82
- package/dist/types/src/components/BaseSwitch.vue.d.ts +35 -144
- package/dist/types/src/components/BaseSystemAlert.vue.d.ts +27 -116
- package/dist/types/src/components/BaseTabItem.vue.d.ts +23 -94
- package/dist/types/src/components/BaseTable.vue.d.ts +101 -361
- package/dist/types/src/components/BaseTableColumn.vue.d.ts +1 -1
- package/dist/types/src/components/BaseTabs.vue.d.ts +8 -47
- package/dist/types/src/components/BaseTagAutocomplete.vue.d.ts +66 -236
- package/dist/types/src/components/BaseTagAutocompleteFetch.vue.d.ts +62 -212
- package/dist/types/src/components/index.d.ts +3 -1
- 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 +5 -1
- package/src/components/BaseAppDialogs.vue +1 -1
- package/src/components/BaseAutocomplete.vue +6 -25
- package/src/components/BaseButtonGroup.vue +2 -2
- package/src/components/BaseColor.stories.js +50 -0
- package/src/components/BaseColor.vue +91 -0
- package/src/components/BaseDropdown.stories.js +47 -9
- package/src/components/BaseDropdown.vue +27 -35
- package/src/components/BaseForm.vue +3 -3
- package/src/components/BaseInput.stories.js +52 -0
- package/src/components/BaseInput.vue +38 -1
- package/src/components/BaseLayoutSidebar.vue +4 -1
- package/src/components/BaseModalCenter.stories.js +5 -0
- package/src/components/BaseModalCenter.vue +14 -10
- package/src/components/BaseModalSide.vue +1 -4
- package/src/components/BaseRichText.stories.js +102 -0
- package/src/components/BaseRichText.vue +121 -0
- 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/components/BaseTextarea.vue +1 -1
- package/src/components/index.ts +4 -0
- package/src/composables/clickOutside.ts +57 -0
- package/src/composables/modal.ts +2 -6
- package/src/utils/scrollPreventer.ts +3 -13
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sprintify-ui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.95",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"build": "rimraf dist && vue-tsc && vite build",
|
|
6
6
|
"build-fast": "rimraf dist && vite build",
|
|
@@ -16,11 +16,13 @@
|
|
|
16
16
|
"@tailwindcss/forms": "^0.5.3",
|
|
17
17
|
"@tailwindcss/line-clamp": "^0.4.2",
|
|
18
18
|
"@tailwindcss/typography": "^0.5.8",
|
|
19
|
+
"@vueup/vue-quill": "^1.0.0",
|
|
19
20
|
"@vueuse/core": "^9.0.0",
|
|
20
21
|
"axios": "^0.26.1",
|
|
21
22
|
"humanize-duration": "^3.0.0",
|
|
22
23
|
"lodash": "^4.17.21",
|
|
23
24
|
"luxon": "^3.0.0",
|
|
25
|
+
"maska": "^2.1.1",
|
|
24
26
|
"microtip": "^0.2.2",
|
|
25
27
|
"object-to-formdata": "^4.4.2",
|
|
26
28
|
"pikaday": "^1.8.2",
|
|
@@ -58,6 +60,7 @@
|
|
|
58
60
|
"@typescript-eslint/parser": "^5.42.1",
|
|
59
61
|
"@vitejs/plugin-vue": "^3.2.0",
|
|
60
62
|
"@vue/eslint-config-typescript": "^11.0.2",
|
|
63
|
+
"@vueup/vue-quill": "^1.0.0",
|
|
61
64
|
"@vueuse/core": "^9.5.0",
|
|
62
65
|
"autoprefixer": "^10.4.13",
|
|
63
66
|
"axios": "^0.26.1",
|
|
@@ -71,6 +74,7 @@
|
|
|
71
74
|
"humanize-duration": "^3.27.3",
|
|
72
75
|
"lodash": "^4.17.21",
|
|
73
76
|
"luxon": "^3.1.0",
|
|
77
|
+
"maska": "^2.1.1",
|
|
74
78
|
"microtip": "^0.2.2",
|
|
75
79
|
"object-hash": "^3.0.0",
|
|
76
80
|
"object-to-formdata": "^4.4.2",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
]"
|
|
25
25
|
autocomplete="off"
|
|
26
26
|
:disabled="disabled"
|
|
27
|
+
@click="open"
|
|
27
28
|
@input="onTextInput"
|
|
28
29
|
@keydown="onTextKeydown"
|
|
29
30
|
/>
|
|
@@ -69,6 +70,7 @@
|
|
|
69
70
|
>
|
|
70
71
|
<div
|
|
71
72
|
ref="dropdown"
|
|
73
|
+
data-scroll-lock-scrollable
|
|
72
74
|
class="max-h-[214px] min-h-[75px] w-full overflow-y-auto"
|
|
73
75
|
>
|
|
74
76
|
<slot v-if="filteredNormalizedOptions.length == 0" name="empty">
|
|
@@ -159,6 +161,7 @@ import BaseSkeleton from '@/components/BaseSkeleton.vue';
|
|
|
159
161
|
import { useHasOptions } from '@/composables/hasOptions';
|
|
160
162
|
import { useField } from '@/composables/field';
|
|
161
163
|
import { BaseIcon } from './index';
|
|
164
|
+
import { useClickOutside } from '@/composables/clickOutside';
|
|
162
165
|
|
|
163
166
|
const props = defineProps({
|
|
164
167
|
modelValue: {
|
|
@@ -314,33 +317,11 @@ watch(
|
|
|
314
317
|
{ immediate: true }
|
|
315
318
|
);
|
|
316
319
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
onBeforeMount(() => {
|
|
322
|
-
window.removeEventListener('mousedown', onMouseDown);
|
|
323
|
-
});
|
|
324
|
-
|
|
325
|
-
function onMouseDown(event: MouseEvent) {
|
|
326
|
-
if (!autocomplete.value) {
|
|
327
|
-
return;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
// Get the element that was clicked
|
|
331
|
-
const clickedElement = event.target as HTMLElement | null;
|
|
332
|
-
|
|
333
|
-
if (!clickedElement) {
|
|
334
|
-
return;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
// `el` is the element you're detecting clicks outside of
|
|
338
|
-
if (autocomplete.value.contains(clickedElement)) {
|
|
339
|
-
open();
|
|
340
|
-
} else {
|
|
320
|
+
useClickOutside(autocomplete, (outside: boolean) => {
|
|
321
|
+
if (outside) {
|
|
341
322
|
close();
|
|
342
323
|
}
|
|
343
|
-
}
|
|
324
|
+
});
|
|
344
325
|
|
|
345
326
|
function open() {
|
|
346
327
|
clearInterval(timerId);
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
>
|
|
17
17
|
<slot
|
|
18
18
|
name="option"
|
|
19
|
-
:selected="isSelected(option)"
|
|
19
|
+
:selected="computed(() => isSelected(option))"
|
|
20
20
|
:option="option"
|
|
21
21
|
:disabled="disabled"
|
|
22
22
|
>
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
</template>
|
|
29
29
|
|
|
30
30
|
<script lang="ts" setup>
|
|
31
|
-
import { PropType } from 'vue';
|
|
31
|
+
import { PropType, computed } from 'vue';
|
|
32
32
|
import { NormalizedOption, Option } from '@/types';
|
|
33
33
|
import { cloneDeep, isArray } from 'lodash';
|
|
34
34
|
import { useHasOptions } from '@/composables/hasOptions';
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { createFieldStory, colors } from '../../.storybook/utils';
|
|
2
|
+
import BaseColor from './BaseColor.vue';
|
|
3
|
+
import ShowValue from '../../.storybook/components/ShowValue.vue';
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: 'Form/BaseColor',
|
|
7
|
+
component: BaseColor,
|
|
8
|
+
argTypes: {},
|
|
9
|
+
args: {
|
|
10
|
+
colors: colors,
|
|
11
|
+
},
|
|
12
|
+
decorators: [() => ({ template: '<div class="mb-36"><story/></div>' })],
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const Template = (args) => ({
|
|
16
|
+
components: { BaseColor, ShowValue },
|
|
17
|
+
setup() {
|
|
18
|
+
const value = ref(null);
|
|
19
|
+
return { args, value };
|
|
20
|
+
},
|
|
21
|
+
template: `
|
|
22
|
+
<BaseColor v-model="value" v-bind="args"></BaseColor>
|
|
23
|
+
<ShowValue :value="value"></ShowValue>
|
|
24
|
+
`,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
export const Single = Template.bind({});
|
|
28
|
+
Single.args = {};
|
|
29
|
+
|
|
30
|
+
export const SingleRequired = Template.bind({});
|
|
31
|
+
SingleRequired.args = {
|
|
32
|
+
required: true,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const Multiple = Template.bind({});
|
|
36
|
+
Multiple.args = {
|
|
37
|
+
multiple: true,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const Disabled = Template.bind({});
|
|
41
|
+
Disabled.args = {
|
|
42
|
+
disabled: true,
|
|
43
|
+
modelValue: { label: '#16a34a', value: '#16a34a' },
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const Field = createFieldStory({
|
|
47
|
+
component: BaseColor,
|
|
48
|
+
componentName: 'BaseColor',
|
|
49
|
+
label: 'Choose your favorite color',
|
|
50
|
+
});
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<BaseButtonGroup
|
|
4
|
+
:model-value="modelValue"
|
|
5
|
+
:disabled="disabled"
|
|
6
|
+
value-key="value"
|
|
7
|
+
label-key="label"
|
|
8
|
+
:required="required"
|
|
9
|
+
:options="colorOptions"
|
|
10
|
+
:multiple="multiple"
|
|
11
|
+
:button-type="buttonType"
|
|
12
|
+
:button-class="''"
|
|
13
|
+
:button-selected-class="''"
|
|
14
|
+
:button-unselected-class="''"
|
|
15
|
+
@update:model-value="$emit('update:modelValue', $event)"
|
|
16
|
+
>
|
|
17
|
+
<template #option="option">
|
|
18
|
+
<div
|
|
19
|
+
:style="{ background: option.option.value }"
|
|
20
|
+
class="p-3 border-none rounded-md"
|
|
21
|
+
:class="[
|
|
22
|
+
option.selected.value ? 'text-white' : 'text-transparent',
|
|
23
|
+
disabled ? ' cursor-not-allowed opacity-50' : '',
|
|
24
|
+
]"
|
|
25
|
+
>
|
|
26
|
+
<BaseIcon icon="heroicons-solid:check-circle" class="w-5 h-5" />
|
|
27
|
+
</div>
|
|
28
|
+
</template>
|
|
29
|
+
</BaseButtonGroup>
|
|
30
|
+
</div>
|
|
31
|
+
</template>
|
|
32
|
+
|
|
33
|
+
<script lang="ts" setup>
|
|
34
|
+
import { PropType } from 'vue';
|
|
35
|
+
import { Option } from '@/types';
|
|
36
|
+
import { BaseButtonGroup } from '.';
|
|
37
|
+
|
|
38
|
+
const props = defineProps({
|
|
39
|
+
modelValue: {
|
|
40
|
+
default: undefined,
|
|
41
|
+
type: [Object, Array, null, undefined] as PropType<
|
|
42
|
+
Option[] | Option | null | undefined
|
|
43
|
+
>,
|
|
44
|
+
},
|
|
45
|
+
required: {
|
|
46
|
+
default: false,
|
|
47
|
+
type: Boolean,
|
|
48
|
+
},
|
|
49
|
+
disabled: {
|
|
50
|
+
default: false,
|
|
51
|
+
type: Boolean,
|
|
52
|
+
},
|
|
53
|
+
buttonType: {
|
|
54
|
+
default: 'button',
|
|
55
|
+
type: String as PropType<'button' | 'submit'>,
|
|
56
|
+
},
|
|
57
|
+
colors: {
|
|
58
|
+
type: [Array] as PropType<string[]>,
|
|
59
|
+
default() {
|
|
60
|
+
return [
|
|
61
|
+
'#0f172a',
|
|
62
|
+
'#dc2626',
|
|
63
|
+
'#ea580c',
|
|
64
|
+
'#eab308',
|
|
65
|
+
'#16a34a',
|
|
66
|
+
'#0d9488',
|
|
67
|
+
'#0891b2',
|
|
68
|
+
'#2563eb',
|
|
69
|
+
'#4f46e5',
|
|
70
|
+
'#9333ea',
|
|
71
|
+
'#db2777',
|
|
72
|
+
];
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
multiple: {
|
|
76
|
+
default: false,
|
|
77
|
+
type: Boolean,
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
defineEmits(['update:modelValue']);
|
|
82
|
+
|
|
83
|
+
const colorOptions = computed(() => {
|
|
84
|
+
return props.colors.map((c) => {
|
|
85
|
+
return {
|
|
86
|
+
label: c,
|
|
87
|
+
value: c,
|
|
88
|
+
};
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
</script>
|
|
@@ -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;
|
|
@@ -17,14 +17,14 @@
|
|
|
17
17
|
>
|
|
18
18
|
<slot v-if="loading" name="loading">
|
|
19
19
|
<div
|
|
20
|
-
class="absolute inset-0 flex
|
|
20
|
+
class="absolute inset-0 flex items-center justify-center w-full h-full"
|
|
21
21
|
>
|
|
22
22
|
<div
|
|
23
|
-
class="absolute inset-0
|
|
23
|
+
class="absolute inset-0 w-full h-full opacity-80"
|
|
24
24
|
:class="loadingMaskClass"
|
|
25
25
|
/>
|
|
26
26
|
<svg
|
|
27
|
-
class="relative
|
|
27
|
+
class="relative w-6 h-6 text-blue-600 animate-spin"
|
|
28
28
|
viewBox="0 0 24 24"
|
|
29
29
|
>
|
|
30
30
|
<path
|
|
@@ -18,6 +18,20 @@ export default {
|
|
|
18
18
|
type: 'text',
|
|
19
19
|
placeholder: 'Enter your name',
|
|
20
20
|
},
|
|
21
|
+
argTypes: {
|
|
22
|
+
mask: {
|
|
23
|
+
control: { type: 'select' },
|
|
24
|
+
options: [
|
|
25
|
+
'phone',
|
|
26
|
+
'date',
|
|
27
|
+
'time',
|
|
28
|
+
'credit-card',
|
|
29
|
+
'zip-code-canada',
|
|
30
|
+
'dynamicMask',
|
|
31
|
+
'customMask',
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
},
|
|
21
35
|
};
|
|
22
36
|
|
|
23
37
|
const Template = (args) => ({
|
|
@@ -92,6 +106,44 @@ Error.args = {
|
|
|
92
106
|
iconRight: 'heroicons:currency-dollar',
|
|
93
107
|
};
|
|
94
108
|
|
|
109
|
+
export const PhoneMask = Template.bind({});
|
|
110
|
+
PhoneMask.args = {
|
|
111
|
+
mask: 'phone',
|
|
112
|
+
placeholder: '(250) 555-0199',
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
export const DateMask = Template.bind({});
|
|
116
|
+
DateMask.args = {
|
|
117
|
+
mask: 'date',
|
|
118
|
+
placeholder: 'yyyy-mm-dd',
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export const TimeMask = Template.bind({});
|
|
122
|
+
TimeMask.args = {
|
|
123
|
+
mask: 'time',
|
|
124
|
+
placeholder: 'hh:mm:ss',
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
export const CreditCard = Template.bind({});
|
|
128
|
+
CreditCard.args = {
|
|
129
|
+
mask: 'credit-card', //4555 5666 6666 6634
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
export const CanadianZipCodeMask = Template.bind({});
|
|
133
|
+
CanadianZipCodeMask.args = {
|
|
134
|
+
mask: 'zip-code-canada', // M5M 4M4
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
export const DynamicMask = Template.bind({});
|
|
138
|
+
DynamicMask.args = {
|
|
139
|
+
mask: ['###.###.###-##', '##.###.###/####-##'],
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
export const CustomMask = Template.bind({});
|
|
143
|
+
CustomMask.args = {
|
|
144
|
+
mask: (value) => (value.startsWith('1') ? '#-#' : '##-##'),
|
|
145
|
+
};
|
|
146
|
+
|
|
95
147
|
export const Field = createFieldStory({
|
|
96
148
|
component: BaseInput,
|
|
97
149
|
componentName: 'BaseInput',
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
</div>
|
|
22
22
|
<input
|
|
23
23
|
ref="input"
|
|
24
|
+
v-maska:[maskOptions]
|
|
24
25
|
:value="modelValue"
|
|
25
26
|
:type="type"
|
|
26
27
|
:name="nameInternal"
|
|
@@ -64,10 +65,11 @@
|
|
|
64
65
|
</template>
|
|
65
66
|
|
|
66
67
|
<script lang="ts" setup>
|
|
67
|
-
import { get,
|
|
68
|
+
import { get, isString } from 'lodash';
|
|
68
69
|
import { PropType } from 'vue';
|
|
69
70
|
import { BaseIcon } from '@/index';
|
|
70
71
|
import { useField } from '@/composables/field';
|
|
72
|
+
import { vMaska } from 'maska';
|
|
71
73
|
|
|
72
74
|
const props = defineProps({
|
|
73
75
|
modelValue: {
|
|
@@ -137,6 +139,41 @@ const props = defineProps({
|
|
|
137
139
|
default: undefined,
|
|
138
140
|
type: Number,
|
|
139
141
|
},
|
|
142
|
+
mask: {
|
|
143
|
+
type: [String, Array, Function],
|
|
144
|
+
default() {
|
|
145
|
+
return null;
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const maskOptions = computed(() => {
|
|
151
|
+
if (props.mask) {
|
|
152
|
+
return {
|
|
153
|
+
mask: maskInternal.value,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
return undefined;
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const maskInternal = computed(() => {
|
|
160
|
+
if (props.mask === 'phone') {
|
|
161
|
+
return '(###) ###-####';
|
|
162
|
+
}
|
|
163
|
+
if (props.mask === 'date') {
|
|
164
|
+
return '####-##-##';
|
|
165
|
+
}
|
|
166
|
+
if (props.mask === 'time') {
|
|
167
|
+
return '##:##:##';
|
|
168
|
+
}
|
|
169
|
+
if (props.mask === 'credit-card') {
|
|
170
|
+
return '#### #### #### ####';
|
|
171
|
+
}
|
|
172
|
+
if (props.mask === 'zip-code-canada') {
|
|
173
|
+
return '@#@ #@#';
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return props.mask;
|
|
140
177
|
});
|
|
141
178
|
|
|
142
179
|
const emit = defineEmits(['update:modelValue', 'focus', 'blur']);
|
|
@@ -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>
|
|
@@ -52,6 +52,11 @@ VerticalAlignTop.args = {
|
|
|
52
52
|
verticalAlign: 'top',
|
|
53
53
|
};
|
|
54
54
|
|
|
55
|
+
export const NoCloseButton = Template.bind({});
|
|
56
|
+
NoCloseButton.args = {
|
|
57
|
+
showCloseButton: false,
|
|
58
|
+
};
|
|
59
|
+
|
|
55
60
|
export const CustomBackdropClass = Template.bind({});
|
|
56
61
|
CustomBackdropClass.args = {
|
|
57
62
|
backdropClass: 'bg-red-500 bg-opacity-70',
|
|
@@ -7,16 +7,18 @@
|
|
|
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
|
-
class="flex min-h-full w-full items-end justify-center overflow-hidden
|
|
16
|
-
:class="
|
|
17
|
-
'
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
class="flex min-h-full w-full items-end justify-center overflow-hidden sm:px-6 sm:pb-6"
|
|
15
|
+
:class="[
|
|
16
|
+
showCloseButton ? 'pt-20' : 'pt-6',
|
|
17
|
+
{
|
|
18
|
+
'sm:items-center': verticalAlign == 'center',
|
|
19
|
+
'sm:items-start': verticalAlign == 'top',
|
|
20
|
+
},
|
|
21
|
+
]"
|
|
20
22
|
>
|
|
21
23
|
<div class="pt-safe grow">
|
|
22
24
|
<transition
|
|
@@ -64,6 +66,7 @@
|
|
|
64
66
|
</div>
|
|
65
67
|
|
|
66
68
|
<button
|
|
69
|
+
v-if="showCloseButton"
|
|
67
70
|
class="right fixed top-2 right-2 flex h-16 w-16 items-center justify-center rounded-full hover:bg-black hover:bg-opacity-20"
|
|
68
71
|
type="button"
|
|
69
72
|
@click="modal.close()"
|
|
@@ -100,15 +103,16 @@ const props = defineProps({
|
|
|
100
103
|
default: '512px',
|
|
101
104
|
type: String,
|
|
102
105
|
},
|
|
106
|
+
showCloseButton: {
|
|
107
|
+
default: true,
|
|
108
|
+
type: Boolean,
|
|
109
|
+
},
|
|
103
110
|
});
|
|
104
111
|
|
|
105
112
|
const emit = defineEmits(['update:modelValue']);
|
|
106
113
|
|
|
107
|
-
const allow = ref(null);
|
|
108
|
-
|
|
109
114
|
const modal = useModal(
|
|
110
115
|
computed(() => props.modelValue),
|
|
111
|
-
allow,
|
|
112
116
|
emit as any
|
|
113
117
|
);
|
|
114
118
|
</script>
|