@mptw/skylens-ui 1.2.21 → 1.3.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.
|
@@ -172,24 +172,22 @@ export default defineComponent({
|
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
function onInputCompositionEnd(e: CompositionEvent) {
|
|
175
|
-
|
|
176
|
-
if (target) {
|
|
177
|
-
if (Number.isInteger(lazy.value) || lazy.value) {
|
|
178
|
-
debounceUpdateModelValue(target.value);
|
|
179
|
-
}
|
|
175
|
+
isComposing.value = false;
|
|
180
176
|
|
|
181
|
-
|
|
182
|
-
}
|
|
177
|
+
updateModelValue(e);
|
|
183
178
|
}
|
|
184
179
|
|
|
185
180
|
function onInputedModelValue(e: Event) {
|
|
186
181
|
const inputEvent = e as InputEvent;
|
|
187
|
-
if (isComposing.value
|
|
188
|
-
isComposing.value = false;
|
|
182
|
+
if (isComposing.value || inputEvent.isComposing) {
|
|
189
183
|
return;
|
|
190
184
|
}
|
|
191
185
|
|
|
192
|
-
|
|
186
|
+
updateModelValue(e);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function updateModelValue(e: Event) {
|
|
190
|
+
const target = e.target as HTMLInputElement;
|
|
193
191
|
|
|
194
192
|
if (target) {
|
|
195
193
|
if (Number.isInteger(lazy.value) || lazy.value) {
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
<template lang="pug">
|
|
2
|
+
.two-layer-single-select(:class="[sizeClass]" ref="selectEl")
|
|
3
|
+
a(
|
|
4
|
+
href="javascript:;"
|
|
5
|
+
:class="{ selected: !!modelValue }"
|
|
6
|
+
@click="onClickedToggle"
|
|
7
|
+
ref="toggleEl"
|
|
8
|
+
data-cy="project-button-toggle"
|
|
9
|
+
).toggle-button
|
|
10
|
+
span.button-title {{ placeholder }}
|
|
11
|
+
SLIcon(icon="caret-down")
|
|
12
|
+
SLTwoLayerSelect(
|
|
13
|
+
:search-placeholder='searchPlaceholder',
|
|
14
|
+
:first-layer-title='firstOptionTitle',
|
|
15
|
+
:second-layer-title='secondOptionTitle',
|
|
16
|
+
:model-value='modelValue',
|
|
17
|
+
:selected-first-layer-key='selectedFirstOption',
|
|
18
|
+
:query='queryProxy',
|
|
19
|
+
:first-layers='firstOptions',
|
|
20
|
+
:second-layers='secondOptions',
|
|
21
|
+
ref='popupComp',
|
|
22
|
+
@update:model-value="onInputedSecondOption",
|
|
23
|
+
@search="onSearch"
|
|
24
|
+
@select-first-layer="onClickedFirstOption"
|
|
25
|
+
)
|
|
26
|
+
</template>
|
|
27
|
+
|
|
28
|
+
<script lang="ts">
|
|
29
|
+
import type { PropType } from "vue";
|
|
30
|
+
import { fromEvent } from "rxjs";
|
|
31
|
+
import { createPopper } from "@popperjs/core";
|
|
32
|
+
import type { Placement } from "@popperjs/core";
|
|
33
|
+
import { SLTwoLayerSelect } from '#components';
|
|
34
|
+
|
|
35
|
+
type SLTwoLayerSelectType = InstanceType<typeof SLTwoLayerSelect>;
|
|
36
|
+
|
|
37
|
+
export default defineComponent({
|
|
38
|
+
name: "SLTwoLayerSingleSelect",
|
|
39
|
+
components: {},
|
|
40
|
+
props: {
|
|
41
|
+
size: {
|
|
42
|
+
type: String,
|
|
43
|
+
default: "",
|
|
44
|
+
validator: (val: string) => ["sm", ""].includes(val),
|
|
45
|
+
},
|
|
46
|
+
placeholder: {
|
|
47
|
+
type: String,
|
|
48
|
+
default: "",
|
|
49
|
+
},
|
|
50
|
+
searchPlaceholder: {
|
|
51
|
+
type: String,
|
|
52
|
+
default: "",
|
|
53
|
+
},
|
|
54
|
+
placement: {
|
|
55
|
+
type: String as PropType<Placement>,
|
|
56
|
+
default: "bottom-start",
|
|
57
|
+
},
|
|
58
|
+
firstOptionTitle: {
|
|
59
|
+
type: String,
|
|
60
|
+
default: "",
|
|
61
|
+
},
|
|
62
|
+
secondOptionTitle: {
|
|
63
|
+
type: String,
|
|
64
|
+
default: "",
|
|
65
|
+
},
|
|
66
|
+
modelValue: {
|
|
67
|
+
type: Object as PropType<{
|
|
68
|
+
firstLayer: string;
|
|
69
|
+
secondLayer: string;
|
|
70
|
+
} | null>,
|
|
71
|
+
default: () => [],
|
|
72
|
+
},
|
|
73
|
+
options: {
|
|
74
|
+
type: Array as PropType<
|
|
75
|
+
{
|
|
76
|
+
key: string;
|
|
77
|
+
name: string;
|
|
78
|
+
subOptions: { key: string; name: string }[];
|
|
79
|
+
}[]
|
|
80
|
+
>,
|
|
81
|
+
default: () => [],
|
|
82
|
+
},
|
|
83
|
+
query: {
|
|
84
|
+
type: String,
|
|
85
|
+
default: '',
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
emits: ["update:modelValue", "update:selecting", 'update:query'],
|
|
89
|
+
setup(props, { emit }) {
|
|
90
|
+
const { size, options, placement, query } = toRefs(props);
|
|
91
|
+
|
|
92
|
+
const selectEl = shallowRef<HTMLElement | null>(null);
|
|
93
|
+
const toggleEl = shallowRef<HTMLElement | null>(null);
|
|
94
|
+
const popupComp = shallowRef<SLTwoLayerSelectType | null>(null);
|
|
95
|
+
const selfQuery = ref(query.value);
|
|
96
|
+
const selectedFirstOption = ref<string | null>(null);
|
|
97
|
+
const isSelecting = ref(false);
|
|
98
|
+
|
|
99
|
+
let popperInstance: any = null;
|
|
100
|
+
let clickSubscriber: any = null;
|
|
101
|
+
|
|
102
|
+
const queryProxy = computed({
|
|
103
|
+
get() { return selfQuery.value },
|
|
104
|
+
set(newValue: string) {
|
|
105
|
+
emit('update:query', newValue);
|
|
106
|
+
selfQuery.value = newValue;
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
const sizeClass = computed(() => {
|
|
110
|
+
if (!size.value) return "";
|
|
111
|
+
return `two-layer-multi-select-${size.value}`;
|
|
112
|
+
});
|
|
113
|
+
const filteredOptions = computed(() => {
|
|
114
|
+
if (!queryProxy.value) {
|
|
115
|
+
return options.value;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const regexp = new RegExp(`[.]*${queryProxy.value}[.]*`, "ig");
|
|
119
|
+
return options.value
|
|
120
|
+
.map((option) => {
|
|
121
|
+
if (regexp.test(option.name)) {
|
|
122
|
+
return option;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
...option,
|
|
127
|
+
subOptions: option.subOptions.filter((o) => regexp.test(o.name)),
|
|
128
|
+
};
|
|
129
|
+
})
|
|
130
|
+
.filter((option) => option.subOptions.length > 0);
|
|
131
|
+
});
|
|
132
|
+
const firstOptions = computed(() => {
|
|
133
|
+
return filteredOptions.value
|
|
134
|
+
});
|
|
135
|
+
const secondOptions = computed(() => {
|
|
136
|
+
const found = filteredOptions.value.find(
|
|
137
|
+
(option) =>
|
|
138
|
+
selectedFirstOption.value && option.key === selectedFirstOption.value
|
|
139
|
+
);
|
|
140
|
+
return found?.subOptions || [];
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
function onClickedFirstOption(key: string) {
|
|
144
|
+
selectedFirstOption.value = key;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function onInputedFirstOption(key: string) {
|
|
148
|
+
selectedFirstOption.value = key;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function onInputedSecondOption(newValue: {
|
|
152
|
+
firstLayer: string;
|
|
153
|
+
secondLayer: string;
|
|
154
|
+
} | null) {
|
|
155
|
+
emit("update:modelValue", newValue);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function onClearQuery() {
|
|
159
|
+
queryProxy.value = "";
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function subscribeClick() {
|
|
163
|
+
clickSubscriber = fromEvent(window, "click").subscribe((e) => {
|
|
164
|
+
const { target } = e;
|
|
165
|
+
if (selectEl.value && !selectEl.value.contains(target as HTMLElement)) {
|
|
166
|
+
hide();
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function unsubscribeClick() {
|
|
172
|
+
if (clickSubscriber) {
|
|
173
|
+
clickSubscriber.unsubscribe();
|
|
174
|
+
}
|
|
175
|
+
clickSubscriber = null;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function show() {
|
|
179
|
+
if (!popupComp.value?.$el) return;
|
|
180
|
+
|
|
181
|
+
isSelecting.value = true;
|
|
182
|
+
|
|
183
|
+
const body = document.querySelector("body");
|
|
184
|
+
if (body) {
|
|
185
|
+
body.classList.add("popup");
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (popupComp.value?.$el) {
|
|
189
|
+
popupComp.value.$el.setAttribute("data-show", "");
|
|
190
|
+
}
|
|
191
|
+
subscribeClick();
|
|
192
|
+
popperInstance.setOptions({
|
|
193
|
+
modifiers: [
|
|
194
|
+
{
|
|
195
|
+
name: "offset",
|
|
196
|
+
options: {
|
|
197
|
+
offset: [0, 8],
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
{ name: "eventListeners", enabled: true },
|
|
201
|
+
],
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function hide() {
|
|
206
|
+
const body = document.querySelector("body");
|
|
207
|
+
if (body) {
|
|
208
|
+
body.classList.remove("popup");
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (!popupComp.value?.$el || popupComp.value?.$el.getAttribute("data-show") === null)
|
|
212
|
+
return;
|
|
213
|
+
|
|
214
|
+
isSelecting.value = false;
|
|
215
|
+
|
|
216
|
+
unsubscribeClick();
|
|
217
|
+
|
|
218
|
+
if (popupComp.value?.$el) {
|
|
219
|
+
popupComp.value?.$el.removeAttribute("data-show");
|
|
220
|
+
}
|
|
221
|
+
popperInstance.setOptions({
|
|
222
|
+
modifiers: [{ name: "eventListeners", enabled: false }],
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
queryProxy.value = "";
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function onClickedToggle() {
|
|
229
|
+
if (!popupComp.value?.$el || popupComp.value?.$el.getAttribute("data-show") !== null) {
|
|
230
|
+
hide();
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
show();
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function onSearch(search: string) {
|
|
238
|
+
console.log("search", search === '');
|
|
239
|
+
queryProxy.value = search;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
watch(isSelecting, () => {
|
|
243
|
+
emit("update:selecting", isSelecting.value);
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
onMounted(() => {
|
|
247
|
+
if (!popupComp.value?.$el) return;
|
|
248
|
+
|
|
249
|
+
if (selectEl.value && popupComp.value?.$el) {
|
|
250
|
+
popperInstance = createPopper(selectEl.value, popupComp.value?.$el, {
|
|
251
|
+
placement: placement.value as Placement,
|
|
252
|
+
modifiers: [{ name: "eventListeners", enabled: false }],
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
onBeforeUnmount(() => {
|
|
257
|
+
const body = document.querySelector("body");
|
|
258
|
+
if (body) {
|
|
259
|
+
body.classList.remove("popup");
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (popperInstance) {
|
|
263
|
+
popperInstance.destroy();
|
|
264
|
+
}
|
|
265
|
+
popperInstance = null;
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
return {
|
|
269
|
+
selectEl,
|
|
270
|
+
toggleEl,
|
|
271
|
+
popupComp,
|
|
272
|
+
queryProxy,
|
|
273
|
+
sizeClass,
|
|
274
|
+
selectedFirstOption,
|
|
275
|
+
firstOptions,
|
|
276
|
+
secondOptions,
|
|
277
|
+
onClickedFirstOption,
|
|
278
|
+
onInputedFirstOption,
|
|
279
|
+
onInputedSecondOption,
|
|
280
|
+
onClearQuery,
|
|
281
|
+
onClickedToggle,
|
|
282
|
+
onSearch,
|
|
283
|
+
};
|
|
284
|
+
},
|
|
285
|
+
});
|
|
286
|
+
</script>
|
|
287
|
+
|
|
288
|
+
<style lang="stylus">
|
|
289
|
+
.two-layer-single-select
|
|
290
|
+
@apply relative w-full
|
|
291
|
+
|
|
292
|
+
&.two-layer-single-select-sm
|
|
293
|
+
.toggle-button
|
|
294
|
+
@apply text-sm
|
|
295
|
+
|
|
296
|
+
.toggle-button
|
|
297
|
+
@apply relative flex items-center w-full s('p-1.75') s('space-x-1.75') border border-primary-light rounded text-base text-gray-4
|
|
298
|
+
|
|
299
|
+
&.selected
|
|
300
|
+
@apply text-gray-2
|
|
301
|
+
|
|
302
|
+
.button-title
|
|
303
|
+
@apply flex-grow
|
|
304
|
+
|
|
305
|
+
.icon
|
|
306
|
+
@apply flex-grow-0 flex-shrink-0 inline-flex text-xs text-gray-2 leading-none
|
|
307
|
+
|
|
308
|
+
.tw-layer-select
|
|
309
|
+
@apply z-10 invisible pointer-events-none
|
|
310
|
+
|
|
311
|
+
&[data-show]
|
|
312
|
+
@apply visible pointer-events-auto
|
|
313
|
+
</style>
|