@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
- const target = e.target as HTMLInputElement;
176
- if (target) {
177
- if (Number.isInteger(lazy.value) || lazy.value) {
178
- debounceUpdateModelValue(target.value);
179
- }
175
+ isComposing.value = false;
180
176
 
181
- emit("update:modelValue", target.value);
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 && !inputEvent.isComposing) {
188
- isComposing.value = false;
182
+ if (isComposing.value || inputEvent.isComposing) {
189
183
  return;
190
184
  }
191
185
 
192
- const target = inputEvent.target as HTMLInputElement;
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>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mptw/skylens-ui",
3
3
  "type": "module",
4
- "version": "1.2.21",
4
+ "version": "1.3.0",
5
5
  "main": "./nuxt.config.ts",
6
6
  "scripts": {
7
7
  "dev": "nuxi dev .playground",