@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 min-w-0 px-2 s('py-1.5')
113
+ @apply px-2 s('py-1.5')
114
114
 
115
115
  &.radio-group--xs
116
116
  .radio
117
117
  label
118
- @apply min-w-0 px-4 s('py-0.5') text-sm
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 min-w-0 px-2 s('py-0.75') text-sm
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 min-w-0 px-2 py-px text-sm
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 s('min-w-[4.5rem]') s('p-1.25') bg-bg rounded text-base leading-normal text-primary-hover cursor-pointer transition
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
- 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.20",
4
+ "version": "1.3.0",
5
5
  "main": "./nuxt.config.ts",
6
6
  "scripts": {
7
7
  "dev": "nuxi dev .playground",