@skyservice-developers/vue-dev-kit 1.5.9 → 1.5.10
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/README.md +202 -217
- package/dist/vue2/style.css +1 -1
- package/dist/vue2/vue-dev-kit.cjs +1 -1
- package/dist/vue2/vue-dev-kit.js +256 -197
- package/dist/vue3/style.css +1 -1
- package/dist/vue3/vue-dev-kit.cjs +1 -1
- package/dist/vue3/vue-dev-kit.js +570 -509
- package/package.json +1 -1
- package/src/vue2/components/SkySelect.vue +81 -17
- package/src/vue3/components/SkySelect.vue +146 -38
package/package.json
CHANGED
|
@@ -26,24 +26,49 @@
|
|
|
26
26
|
</svg>
|
|
27
27
|
</button>
|
|
28
28
|
|
|
29
|
-
<
|
|
30
|
-
<
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
29
|
+
<template v-if="open">
|
|
30
|
+
<portal v-if="teleport" to="sky-select-portal">
|
|
31
|
+
<div
|
|
32
|
+
class="sky-select-dropdown sky-select-dropdown-teleported"
|
|
33
|
+
:style="dropdownStyle"
|
|
34
|
+
>
|
|
35
|
+
<div
|
|
36
|
+
v-for="(option, idx) in normalizedOptions"
|
|
37
|
+
:key="option.value"
|
|
38
|
+
class="sky-select-option"
|
|
39
|
+
:class="{
|
|
40
|
+
'sky-select-option-selected': option.value === value,
|
|
41
|
+
'sky-select-option-focused': idx === focusedIdx,
|
|
42
|
+
}"
|
|
43
|
+
@click="select(option)"
|
|
44
|
+
@mouseenter="focusedIdx = idx"
|
|
45
|
+
>
|
|
46
|
+
<span>{{ option.label }}</span>
|
|
47
|
+
<svg v-if="option.value === value" class="sky-select-check" viewBox="0 0 16 16" fill="none" aria-hidden="true">
|
|
48
|
+
<path d="M3 8l4 4 6-6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
49
|
+
</svg>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
</portal>
|
|
53
|
+
<div v-else class="sky-select-dropdown">
|
|
54
|
+
<div
|
|
55
|
+
v-for="(option, idx) in normalizedOptions"
|
|
56
|
+
:key="option.value"
|
|
57
|
+
class="sky-select-option"
|
|
58
|
+
:class="{
|
|
59
|
+
'sky-select-option-selected': option.value === value,
|
|
60
|
+
'sky-select-option-focused': idx === focusedIdx,
|
|
61
|
+
}"
|
|
62
|
+
@click="select(option)"
|
|
63
|
+
@mouseenter="focusedIdx = idx"
|
|
64
|
+
>
|
|
65
|
+
<span>{{ option.label }}</span>
|
|
66
|
+
<svg v-if="option.value === value" class="sky-select-check" viewBox="0 0 16 16" fill="none" aria-hidden="true">
|
|
67
|
+
<path d="M3 8l4 4 6-6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
68
|
+
</svg>
|
|
69
|
+
</div>
|
|
45
70
|
</div>
|
|
46
|
-
</
|
|
71
|
+
</template>
|
|
47
72
|
</div>
|
|
48
73
|
</template>
|
|
49
74
|
|
|
@@ -71,11 +96,16 @@ export default {
|
|
|
71
96
|
type: Boolean,
|
|
72
97
|
default: false,
|
|
73
98
|
},
|
|
99
|
+
teleport: {
|
|
100
|
+
type: Boolean,
|
|
101
|
+
default: false,
|
|
102
|
+
},
|
|
74
103
|
},
|
|
75
104
|
data() {
|
|
76
105
|
return {
|
|
77
106
|
open: false,
|
|
78
107
|
focusedIdx: -1,
|
|
108
|
+
dropdownStyle: {},
|
|
79
109
|
};
|
|
80
110
|
},
|
|
81
111
|
computed: {
|
|
@@ -89,6 +119,17 @@ export default {
|
|
|
89
119
|
},
|
|
90
120
|
},
|
|
91
121
|
methods: {
|
|
122
|
+
calcDropdownStyle() {
|
|
123
|
+
if (!this.teleport || !this.$refs.root) return;
|
|
124
|
+
const rect = this.$refs.root.getBoundingClientRect();
|
|
125
|
+
this.dropdownStyle = {
|
|
126
|
+
position: 'fixed',
|
|
127
|
+
top: `${rect.bottom + 4}px`,
|
|
128
|
+
left: `${rect.left}px`,
|
|
129
|
+
width: `${rect.width}px`,
|
|
130
|
+
zIndex: 'var(--sky-select-dropdown-z-index, 9999)',
|
|
131
|
+
};
|
|
132
|
+
},
|
|
92
133
|
toggle() {
|
|
93
134
|
if (this.disabled) return;
|
|
94
135
|
this.open ? this.close() : this.openDropdown();
|
|
@@ -96,11 +137,18 @@ export default {
|
|
|
96
137
|
openDropdown() {
|
|
97
138
|
this.open = true;
|
|
98
139
|
this.focusedIdx = this.normalizedOptions.findIndex((o) => o.value === this.value);
|
|
140
|
+
this.calcDropdownStyle();
|
|
99
141
|
this.$nextTick(() => document.addEventListener('mousedown', this.onOutsideClick));
|
|
142
|
+
if (this.teleport) {
|
|
143
|
+
window.addEventListener('scroll', this.onScrollOrResize, true);
|
|
144
|
+
window.addEventListener('resize', this.onScrollOrResize);
|
|
145
|
+
}
|
|
100
146
|
},
|
|
101
147
|
close() {
|
|
102
148
|
this.open = false;
|
|
103
149
|
document.removeEventListener('mousedown', this.onOutsideClick);
|
|
150
|
+
window.removeEventListener('scroll', this.onScrollOrResize, true);
|
|
151
|
+
window.removeEventListener('resize', this.onScrollOrResize);
|
|
104
152
|
},
|
|
105
153
|
select(option) {
|
|
106
154
|
this.$emit('input', option.value);
|
|
@@ -109,6 +157,9 @@ export default {
|
|
|
109
157
|
onOutsideClick(e) {
|
|
110
158
|
if (!this.$refs.root.contains(e.target)) this.close();
|
|
111
159
|
},
|
|
160
|
+
onScrollOrResize() {
|
|
161
|
+
this.calcDropdownStyle();
|
|
162
|
+
},
|
|
112
163
|
onKeydown(e) {
|
|
113
164
|
if (!this.open) {
|
|
114
165
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
@@ -133,6 +184,8 @@ export default {
|
|
|
133
184
|
},
|
|
134
185
|
beforeDestroy() {
|
|
135
186
|
document.removeEventListener('mousedown', this.onOutsideClick);
|
|
187
|
+
window.removeEventListener('scroll', this.onScrollOrResize, true);
|
|
188
|
+
window.removeEventListener('resize', this.onScrollOrResize);
|
|
136
189
|
},
|
|
137
190
|
};
|
|
138
191
|
</script>
|
|
@@ -233,6 +286,17 @@ export default {
|
|
|
233
286
|
padding: 4px;
|
|
234
287
|
}
|
|
235
288
|
|
|
289
|
+
.sky-select-dropdown-teleported {
|
|
290
|
+
position: fixed;
|
|
291
|
+
background: var(--sky-select-dropdown-bg, #fff);
|
|
292
|
+
border: var(--sky-select-dropdown-border, 1px solid #d1d5db);
|
|
293
|
+
border-radius: var(--sky-select-dropdown-radius, 6px);
|
|
294
|
+
box-shadow: var(--sky-select-dropdown-shadow, 0 4px 12px rgba(0, 0, 0, 0.1));
|
|
295
|
+
max-height: var(--sky-select-dropdown-max-height, 220px);
|
|
296
|
+
overflow-y: auto;
|
|
297
|
+
padding: 4px;
|
|
298
|
+
}
|
|
299
|
+
|
|
236
300
|
/* Option */
|
|
237
301
|
.sky-select-option {
|
|
238
302
|
display: flex;
|
|
@@ -21,34 +21,94 @@
|
|
|
21
21
|
>
|
|
22
22
|
{{ selectedOption ? selectedOption.label : placeholder }}
|
|
23
23
|
</span>
|
|
24
|
-
<svg
|
|
25
|
-
|
|
24
|
+
<svg
|
|
25
|
+
class="sky-select-chevron"
|
|
26
|
+
viewBox="0 0 16 16"
|
|
27
|
+
fill="none"
|
|
28
|
+
aria-hidden="true"
|
|
29
|
+
>
|
|
30
|
+
<path
|
|
31
|
+
d="M4 6l4 4 4-4"
|
|
32
|
+
stroke="currentColor"
|
|
33
|
+
stroke-width="1.5"
|
|
34
|
+
stroke-linecap="round"
|
|
35
|
+
stroke-linejoin="round"
|
|
36
|
+
/>
|
|
26
37
|
</svg>
|
|
27
38
|
</button>
|
|
28
39
|
|
|
29
|
-
<
|
|
30
|
-
<
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
<template v-if="open">
|
|
41
|
+
<Teleport v-if="teleport" to="body">
|
|
42
|
+
<div
|
|
43
|
+
class="sky-select-dropdown sky-select-dropdown-teleported"
|
|
44
|
+
:style="dropdownStyle"
|
|
45
|
+
>
|
|
46
|
+
<div
|
|
47
|
+
v-for="(option, idx) in normalizedOptions"
|
|
48
|
+
:key="option.value"
|
|
49
|
+
class="sky-select-option"
|
|
50
|
+
:class="{
|
|
51
|
+
'sky-select-option-selected': option.value === modelValue,
|
|
52
|
+
'sky-select-option-focused': idx === focusedIdx,
|
|
53
|
+
}"
|
|
54
|
+
@click="select(option)"
|
|
55
|
+
@mouseenter="focusedIdx = idx"
|
|
56
|
+
>
|
|
57
|
+
<span>{{ option.label }}</span>
|
|
58
|
+
<svg
|
|
59
|
+
v-if="option.value === modelValue"
|
|
60
|
+
class="sky-select-check"
|
|
61
|
+
viewBox="0 0 16 16"
|
|
62
|
+
fill="none"
|
|
63
|
+
aria-hidden="true"
|
|
64
|
+
>
|
|
65
|
+
<path
|
|
66
|
+
d="M3 8l4 4 6-6"
|
|
67
|
+
stroke="currentColor"
|
|
68
|
+
stroke-width="1.5"
|
|
69
|
+
stroke-linecap="round"
|
|
70
|
+
stroke-linejoin="round"
|
|
71
|
+
/>
|
|
72
|
+
</svg>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
</Teleport>
|
|
76
|
+
<div v-else class="sky-select-dropdown">
|
|
77
|
+
<div
|
|
78
|
+
v-for="(option, idx) in normalizedOptions"
|
|
79
|
+
:key="option.value"
|
|
80
|
+
class="sky-select-option"
|
|
81
|
+
:class="{
|
|
82
|
+
'sky-select-option-selected': option.value === modelValue,
|
|
83
|
+
'sky-select-option-focused': idx === focusedIdx,
|
|
84
|
+
}"
|
|
85
|
+
@click="select(option)"
|
|
86
|
+
@mouseenter="focusedIdx = idx"
|
|
87
|
+
>
|
|
88
|
+
<span>{{ option.label }}</span>
|
|
89
|
+
<svg
|
|
90
|
+
v-if="option.value === modelValue"
|
|
91
|
+
class="sky-select-check"
|
|
92
|
+
viewBox="0 0 16 16"
|
|
93
|
+
fill="none"
|
|
94
|
+
aria-hidden="true"
|
|
95
|
+
>
|
|
96
|
+
<path
|
|
97
|
+
d="M3 8l4 4 6-6"
|
|
98
|
+
stroke="currentColor"
|
|
99
|
+
stroke-width="1.5"
|
|
100
|
+
stroke-linecap="round"
|
|
101
|
+
stroke-linejoin="round"
|
|
102
|
+
/>
|
|
103
|
+
</svg>
|
|
104
|
+
</div>
|
|
45
105
|
</div>
|
|
46
|
-
</
|
|
106
|
+
</template>
|
|
47
107
|
</div>
|
|
48
108
|
</template>
|
|
49
109
|
|
|
50
110
|
<script setup>
|
|
51
|
-
import { ref, computed, onBeforeUnmount } from
|
|
111
|
+
import { ref, computed, onBeforeUnmount } from "vue";
|
|
52
112
|
|
|
53
113
|
const props = defineProps({
|
|
54
114
|
modelValue: {
|
|
@@ -60,7 +120,7 @@ const props = defineProps({
|
|
|
60
120
|
},
|
|
61
121
|
placeholder: {
|
|
62
122
|
type: String,
|
|
63
|
-
default:
|
|
123
|
+
default: "",
|
|
64
124
|
},
|
|
65
125
|
disabled: {
|
|
66
126
|
type: Boolean,
|
|
@@ -70,24 +130,42 @@ const props = defineProps({
|
|
|
70
130
|
type: Boolean,
|
|
71
131
|
default: false,
|
|
72
132
|
},
|
|
133
|
+
teleport: {
|
|
134
|
+
type: Boolean,
|
|
135
|
+
default: false,
|
|
136
|
+
},
|
|
73
137
|
});
|
|
74
138
|
|
|
75
|
-
const emit = defineEmits([
|
|
139
|
+
const emit = defineEmits(["update:modelValue"]);
|
|
76
140
|
|
|
77
141
|
const root = ref(null);
|
|
78
142
|
const open = ref(false);
|
|
79
143
|
const focusedIdx = ref(-1);
|
|
144
|
+
const dropdownStyle = ref({});
|
|
80
145
|
|
|
81
146
|
const normalizedOptions = computed(() =>
|
|
82
147
|
props.options.map((opt) =>
|
|
83
|
-
typeof opt ===
|
|
84
|
-
)
|
|
148
|
+
typeof opt === "string" ? { label: opt, value: opt } : opt,
|
|
149
|
+
),
|
|
85
150
|
);
|
|
86
151
|
|
|
87
|
-
const selectedOption = computed(
|
|
88
|
-
|
|
152
|
+
const selectedOption = computed(
|
|
153
|
+
() =>
|
|
154
|
+
normalizedOptions.value.find((o) => o.value === props.modelValue) ?? null,
|
|
89
155
|
);
|
|
90
156
|
|
|
157
|
+
function calcDropdownStyle() {
|
|
158
|
+
if (!props.teleport || !root.value) return;
|
|
159
|
+
const rect = root.value.getBoundingClientRect();
|
|
160
|
+
dropdownStyle.value = {
|
|
161
|
+
position: "fixed",
|
|
162
|
+
top: `${rect.bottom + 4}px`,
|
|
163
|
+
left: `${rect.left}px`,
|
|
164
|
+
width: `${rect.width}px`,
|
|
165
|
+
zIndex: "var(--sky-select-dropdown-z-index, 9999)",
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
91
169
|
function toggle() {
|
|
92
170
|
if (props.disabled) return;
|
|
93
171
|
open.value ? close() : openDropdown();
|
|
@@ -95,17 +173,26 @@ function toggle() {
|
|
|
95
173
|
|
|
96
174
|
function openDropdown() {
|
|
97
175
|
open.value = true;
|
|
98
|
-
focusedIdx.value = normalizedOptions.value.findIndex(
|
|
99
|
-
|
|
176
|
+
focusedIdx.value = normalizedOptions.value.findIndex(
|
|
177
|
+
(o) => o.value === props.modelValue,
|
|
178
|
+
);
|
|
179
|
+
calcDropdownStyle();
|
|
180
|
+
document.addEventListener("mousedown", onOutsideClick);
|
|
181
|
+
if (props.teleport) {
|
|
182
|
+
window.addEventListener("scroll", onScrollOrResize, true);
|
|
183
|
+
window.addEventListener("resize", onScrollOrResize);
|
|
184
|
+
}
|
|
100
185
|
}
|
|
101
186
|
|
|
102
187
|
function close() {
|
|
103
188
|
open.value = false;
|
|
104
|
-
document.removeEventListener(
|
|
189
|
+
document.removeEventListener("mousedown", onOutsideClick);
|
|
190
|
+
window.removeEventListener("scroll", onScrollOrResize, true);
|
|
191
|
+
window.removeEventListener("resize", onScrollOrResize);
|
|
105
192
|
}
|
|
106
193
|
|
|
107
194
|
function select(option) {
|
|
108
|
-
emit(
|
|
195
|
+
emit("update:modelValue", option.value);
|
|
109
196
|
close();
|
|
110
197
|
}
|
|
111
198
|
|
|
@@ -113,30 +200,40 @@ function onOutsideClick(e) {
|
|
|
113
200
|
if (!root.value?.contains(e.target)) close();
|
|
114
201
|
}
|
|
115
202
|
|
|
203
|
+
function onScrollOrResize() {
|
|
204
|
+
calcDropdownStyle();
|
|
205
|
+
}
|
|
206
|
+
|
|
116
207
|
function onKeydown(e) {
|
|
117
208
|
if (!open.value) {
|
|
118
|
-
if (e.key ===
|
|
209
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
119
210
|
e.preventDefault();
|
|
120
211
|
openDropdown();
|
|
121
212
|
}
|
|
122
213
|
return;
|
|
123
214
|
}
|
|
124
|
-
if (e.key ===
|
|
215
|
+
if (e.key === "Escape") {
|
|
125
216
|
close();
|
|
126
|
-
} else if (e.key ===
|
|
217
|
+
} else if (e.key === "ArrowDown") {
|
|
127
218
|
e.preventDefault();
|
|
128
|
-
focusedIdx.value = Math.min(
|
|
129
|
-
|
|
219
|
+
focusedIdx.value = Math.min(
|
|
220
|
+
focusedIdx.value + 1,
|
|
221
|
+
normalizedOptions.value.length - 1,
|
|
222
|
+
);
|
|
223
|
+
} else if (e.key === "ArrowUp") {
|
|
130
224
|
e.preventDefault();
|
|
131
225
|
focusedIdx.value = Math.max(focusedIdx.value - 1, 0);
|
|
132
|
-
} else if (e.key ===
|
|
226
|
+
} else if (e.key === "Enter") {
|
|
133
227
|
e.preventDefault();
|
|
134
|
-
if (focusedIdx.value >= 0)
|
|
228
|
+
if (focusedIdx.value >= 0)
|
|
229
|
+
select(normalizedOptions.value[focusedIdx.value]);
|
|
135
230
|
}
|
|
136
231
|
}
|
|
137
232
|
|
|
138
233
|
onBeforeUnmount(() => {
|
|
139
|
-
document.removeEventListener(
|
|
234
|
+
document.removeEventListener("mousedown", onOutsideClick);
|
|
235
|
+
window.removeEventListener("scroll", onScrollOrResize, true);
|
|
236
|
+
window.removeEventListener("resize", onScrollOrResize);
|
|
140
237
|
});
|
|
141
238
|
</script>
|
|
142
239
|
|
|
@@ -236,6 +333,17 @@ onBeforeUnmount(() => {
|
|
|
236
333
|
padding: 4px;
|
|
237
334
|
}
|
|
238
335
|
|
|
336
|
+
.sky-select-dropdown-teleported {
|
|
337
|
+
position: fixed;
|
|
338
|
+
background: var(--sky-select-dropdown-bg, #fff);
|
|
339
|
+
border: var(--sky-select-dropdown-border, 1px solid #d1d5db);
|
|
340
|
+
border-radius: var(--sky-select-dropdown-radius, 6px);
|
|
341
|
+
box-shadow: var(--sky-select-dropdown-shadow, 0 4px 12px rgba(0, 0, 0, 0.1));
|
|
342
|
+
max-height: var(--sky-select-dropdown-max-height, 220px);
|
|
343
|
+
overflow-y: auto;
|
|
344
|
+
padding: 4px;
|
|
345
|
+
}
|
|
346
|
+
|
|
239
347
|
/* Option */
|
|
240
348
|
.sky-select-option {
|
|
241
349
|
display: flex;
|