@tak-ps/vue-tabler 4.29.3 → 5.1.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.
- package/CHANGELOG.md +15 -0
- package/components/Slidedown.vue +26 -1
- package/lib.ts +0 -1
- package/package.json +1 -1
- package/components/List.vue +0 -148
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,21 @@
|
|
|
10
10
|
|
|
11
11
|
## Version History
|
|
12
12
|
|
|
13
|
+
### Pending
|
|
14
|
+
|
|
15
|
+
### v5.1.0
|
|
16
|
+
|
|
17
|
+
- :bug: TablerSlidedown: `clickAnywhereExpand` no longer collapses an expanded slidedown - collapse is explicit via the arrow control (or opt-in via `clickAnywhereCollapse`)
|
|
18
|
+
|
|
19
|
+
### v5.0.1
|
|
20
|
+
|
|
21
|
+
- :bug: TablerSlidedown: reset wrapper scroll on expand so content focused while collapsed (ie autofocused inputs) cannot leave the top of the expanded content cut off
|
|
22
|
+
- :bug: TablerSlidedown: release the measured max-height once the expand transition completes so content that grows after expansion (async lists etc.) is not clipped
|
|
23
|
+
|
|
24
|
+
### v5.0.0
|
|
25
|
+
|
|
26
|
+
- :rocket: Remove `TablerList` as it used an outdated `window.std` requirement for fetching data
|
|
27
|
+
|
|
13
28
|
### v4.29.3
|
|
14
29
|
|
|
15
30
|
- :bug: Fix incorrect border when using pre or post icons in TablerInput
|
package/components/Slidedown.vue
CHANGED
|
@@ -74,8 +74,33 @@ function toggle() {
|
|
|
74
74
|
|
|
75
75
|
if (el) {
|
|
76
76
|
if (isExpanded.value) {
|
|
77
|
+
// The wrapper is overflow: hidden but can still be scrolled
|
|
78
|
+
// programmatically (ie by a browser focus() scrolling an input in
|
|
79
|
+
// the collapsed content into view) which would leave the top of
|
|
80
|
+
// the expanded content cut off
|
|
81
|
+
el.scrollTop = 0;
|
|
82
|
+
|
|
77
83
|
el.style.maxHeight = el.scrollHeight + 'px';
|
|
84
|
+
|
|
85
|
+
const release = (event: TransitionEvent) => {
|
|
86
|
+
if (event.target !== el) return;
|
|
87
|
+
el.removeEventListener('transitionend', release);
|
|
88
|
+
|
|
89
|
+
if (isExpanded.value) {
|
|
90
|
+
// Release the measured height so content that grows after
|
|
91
|
+
// expansion (async lists etc.) is not clipped
|
|
92
|
+
el.style.maxHeight = 'none';
|
|
93
|
+
el.scrollTop = 0;
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
el.addEventListener('transitionend', release);
|
|
78
98
|
} else {
|
|
99
|
+
// Re-fix the current height so the collapse can animate from it
|
|
100
|
+
// even if the max-height was released after expansion
|
|
101
|
+
el.style.maxHeight = el.scrollHeight + 'px';
|
|
102
|
+
void el.offsetHeight;
|
|
103
|
+
|
|
79
104
|
el.style.maxHeight = ''; // Reset to CSS default (0)
|
|
80
105
|
}
|
|
81
106
|
}
|
|
@@ -87,7 +112,7 @@ function handleClick(event: MouseEvent) {
|
|
|
87
112
|
if (el && el === event.target) return;
|
|
88
113
|
if (el && el.contains(event.target as Node)) return;
|
|
89
114
|
|
|
90
|
-
if (props.clickAnywhereExpand) {
|
|
115
|
+
if (props.clickAnywhereExpand && !isExpanded.value) {
|
|
91
116
|
toggle();
|
|
92
117
|
} else if (props.clickAnywhereCollapse && isExpanded.value) {
|
|
93
118
|
toggle();
|
package/lib.ts
CHANGED
|
@@ -20,7 +20,6 @@ export { default as TablerSlidedown } from './components/Slidedown.vue'
|
|
|
20
20
|
export { default as TablerPager } from './components/Pager.vue'
|
|
21
21
|
export { default as TablerNone } from './components/None.vue'
|
|
22
22
|
export { default as TablerError } from './components/Err.vue'
|
|
23
|
-
export { default as TablerList } from './components/List.vue'
|
|
24
23
|
export { default as TablerHelp } from './components/Help.vue'
|
|
25
24
|
export { default as TablerModal } from './components/Modal.vue'
|
|
26
25
|
export { default as TablerProgress } from './components/Progress.vue'
|
package/package.json
CHANGED
package/components/List.vue
DELETED
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class='dropdown'>
|
|
3
|
-
<label
|
|
4
|
-
v-if='label'
|
|
5
|
-
class='form-label'
|
|
6
|
-
:class='{
|
|
7
|
-
"required": required
|
|
8
|
-
}'
|
|
9
|
-
v-text='label'
|
|
10
|
-
/>
|
|
11
|
-
<div
|
|
12
|
-
id='list-menu-button'
|
|
13
|
-
ref='button'
|
|
14
|
-
type='button'
|
|
15
|
-
data-bs-toggle='dropdown'
|
|
16
|
-
aria-expanded='false'
|
|
17
|
-
class='border rounded'
|
|
18
|
-
style='height: 36px;'
|
|
19
|
-
>
|
|
20
|
-
<div class='d-flex mx-2'>
|
|
21
|
-
<span
|
|
22
|
-
v-if='ele && namekey'
|
|
23
|
-
style='padding-top: 6px;'
|
|
24
|
-
v-text='ele[namekey]'
|
|
25
|
-
/>
|
|
26
|
-
<span
|
|
27
|
-
v-else
|
|
28
|
-
style='padding-top: 6px;'
|
|
29
|
-
>Select <span v-text='label' /></span>
|
|
30
|
-
|
|
31
|
-
<div class='ms-auto'>
|
|
32
|
-
<IconSettings
|
|
33
|
-
:size='32'
|
|
34
|
-
stroke='1'
|
|
35
|
-
style='margin-top: 4px;'
|
|
36
|
-
/>
|
|
37
|
-
</div>
|
|
38
|
-
</div>
|
|
39
|
-
</div>
|
|
40
|
-
<ul
|
|
41
|
-
class='dropdown-menu'
|
|
42
|
-
aria-labelledby='list-menu-button'
|
|
43
|
-
:style='{
|
|
44
|
-
"width": `${buttonHeight}px`
|
|
45
|
-
}'
|
|
46
|
-
>
|
|
47
|
-
<div class='m-1'>
|
|
48
|
-
<TablerInput
|
|
49
|
-
v-model='filter'
|
|
50
|
-
:disabled='disabled'
|
|
51
|
-
placeholder='Name'
|
|
52
|
-
/>
|
|
53
|
-
<div
|
|
54
|
-
v-for='ele in (listkey ? list[listkey] : [])'
|
|
55
|
-
:key='ele.id'
|
|
56
|
-
@click='select(ele)'
|
|
57
|
-
>
|
|
58
|
-
<div
|
|
59
|
-
v-if='namekey'
|
|
60
|
-
class='d-flex align-items-center my-1 cursor-pointer'
|
|
61
|
-
v-text='ele[namekey]'
|
|
62
|
-
/>
|
|
63
|
-
</div>
|
|
64
|
-
</div>
|
|
65
|
-
</ul>
|
|
66
|
-
</div>
|
|
67
|
-
</template>
|
|
68
|
-
|
|
69
|
-
<script setup lang="ts">
|
|
70
|
-
import { ref, computed, watch, onMounted } from 'vue'
|
|
71
|
-
import TablerInput from './input/Input.vue';
|
|
72
|
-
import {
|
|
73
|
-
IconSettings
|
|
74
|
-
} from '@tabler/icons-vue';
|
|
75
|
-
|
|
76
|
-
export interface ListProps {
|
|
77
|
-
url?: string;
|
|
78
|
-
listkey?: string;
|
|
79
|
-
namekey?: string;
|
|
80
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
81
|
-
initial?: Record<string, any>;
|
|
82
|
-
label?: string;
|
|
83
|
-
required?: boolean;
|
|
84
|
-
disabled?: boolean;
|
|
85
|
-
limit?: number;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const props = withDefaults(defineProps<ListProps>(), {
|
|
89
|
-
label: '',
|
|
90
|
-
required: false,
|
|
91
|
-
disabled: false,
|
|
92
|
-
limit: 10
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
const emit = defineEmits<{
|
|
96
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
97
|
-
(e: 'selected', ele: any): void
|
|
98
|
-
}>()
|
|
99
|
-
|
|
100
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
101
|
-
const ele = ref<any>(null)
|
|
102
|
-
const isMounted = ref(false)
|
|
103
|
-
const filter = ref('')
|
|
104
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
105
|
-
const list = ref<any>({})
|
|
106
|
-
const button = ref<HTMLElement | null>(null)
|
|
107
|
-
|
|
108
|
-
const buttonHeight = computed(() => {
|
|
109
|
-
if(!isMounted.value) return 100;
|
|
110
|
-
const buttonDOM = button.value
|
|
111
|
-
return buttonDOM ? buttonDOM.offsetWidth : 100;
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
115
|
-
const select = (selectedEle: any) => {
|
|
116
|
-
ele.value = selectedEle;
|
|
117
|
-
if (props.namekey) {
|
|
118
|
-
filter.value = selectedEle[props.namekey];
|
|
119
|
-
}
|
|
120
|
-
emit("selected", selectedEle)
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const fetchList = async () => {
|
|
124
|
-
if (!props.url) return;
|
|
125
|
-
// @ts-expect-error: Global window function
|
|
126
|
-
const url = window.stdurl(props.url);
|
|
127
|
-
url.searchParams.append('filter', filter.value);
|
|
128
|
-
url.searchParams.append('limit', String(props.limit));
|
|
129
|
-
// @ts-expect-error: Global window function
|
|
130
|
-
list.value = await window.std(url);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// Watchers
|
|
134
|
-
watch(ele, () => {
|
|
135
|
-
filter.value = '';
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
watch(filter, async () => {
|
|
139
|
-
await fetchList();
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
// Mounted lifecycle
|
|
143
|
-
onMounted(async () => {
|
|
144
|
-
if (props.initial && props.namekey && props.initial[props.namekey]) ele.value = props.initial;
|
|
145
|
-
await fetchList();
|
|
146
|
-
isMounted.value = true;
|
|
147
|
-
})
|
|
148
|
-
</script>
|