@mptw/skylens-ui 1.2.20 → 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.
|
@@ -110,26 +110,26 @@ export default defineComponent({
|
|
|
110
110
|
&.radio-group--sm
|
|
111
111
|
.radio
|
|
112
112
|
label
|
|
113
|
-
@apply
|
|
113
|
+
@apply px-2 s('py-1.5')
|
|
114
114
|
|
|
115
115
|
&.radio-group--xs
|
|
116
116
|
.radio
|
|
117
117
|
label
|
|
118
|
-
@apply
|
|
118
|
+
@apply px-4 s('py-0.5') text-sm
|
|
119
119
|
|
|
120
120
|
&.radio-group--xxs
|
|
121
121
|
@apply s('p-0.75')
|
|
122
122
|
|
|
123
123
|
.radio
|
|
124
124
|
label
|
|
125
|
-
@apply
|
|
125
|
+
@apply px-2 s('py-0.75') text-sm
|
|
126
126
|
|
|
127
127
|
&.radio-group--3xs
|
|
128
128
|
@apply s('p-0.75')
|
|
129
129
|
|
|
130
130
|
.radio
|
|
131
131
|
label
|
|
132
|
-
@apply
|
|
132
|
+
@apply px-2 py-px text-sm
|
|
133
133
|
|
|
134
134
|
&.radio-group--third-hover
|
|
135
135
|
@apply bg-third-hover border-third
|
|
@@ -191,7 +191,7 @@ export default defineComponent({
|
|
|
191
191
|
@apply absolute s('left-1/2') s('top-1/2') transform s('-translate-x-1/2') s('-translate-y-1/2')
|
|
192
192
|
|
|
193
193
|
label
|
|
194
|
-
@apply inline-flex justify-center items-center relative
|
|
194
|
+
@apply inline-flex justify-center items-center relative px-3 s('py-1.25') bg-bg rounded text-base leading-normal text-primary-hover cursor-pointer transition
|
|
195
195
|
|
|
196
196
|
input:checked + label
|
|
197
197
|
@apply bg-white text-primary shadow
|
|
@@ -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>
|