jb-select 6.5.0 → 7.0.1
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 +5 -7
- package/dist/i18n.d.ts +2 -2
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.br +0 -0
- package/dist/index.cjs.js.gz +0 -0
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.br +0 -0
- package/dist/index.js.gz +0 -0
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.br +0 -0
- package/dist/index.umd.js.gz +0 -0
- package/dist/index.umd.js.map +1 -1
- package/dist/jb-option/jb-option.d.ts.map +1 -1
- package/dist/jb-select.d.ts +6 -4
- package/dist/jb-select.d.ts.map +1 -1
- package/dist/render.d.ts.map +1 -1
- package/dist/types.d.ts +6 -1
- package/dist/types.d.ts.map +1 -1
- package/lib/i18n.ts +2 -2
- package/lib/jb-option/jb-option.ts +22 -16
- package/lib/jb-select.css +120 -193
- package/lib/jb-select.ts +54 -19
- package/lib/render.ts +20 -23
- package/lib/types.ts +6 -1
- package/lib/variables.css +14 -10
- package/package.json +4 -2
package/lib/jb-select.css
CHANGED
|
@@ -1,151 +1,61 @@
|
|
|
1
1
|
/* @use "~jb-core/styles/medias.scss" as *; */
|
|
2
2
|
|
|
3
3
|
@custom-media --tablet-until (max-width: 768px);
|
|
4
|
+
@custom-media --tablet-from (min-width: 769px);
|
|
4
5
|
|
|
5
6
|
.jb-select-web-component {
|
|
6
7
|
width: var(--jb-select-width, 100%);
|
|
7
8
|
margin: var(--jb-select-margin, 0 0);
|
|
8
|
-
position: relative;
|
|
9
9
|
box-sizing: border-box;
|
|
10
10
|
|
|
11
|
-
&.--focused {
|
|
12
|
-
@media(--tablet-until) {
|
|
13
|
-
position: fixed;
|
|
14
|
-
bottom: 0;
|
|
15
|
-
top: initial;
|
|
16
|
-
left: 0;
|
|
17
|
-
background-color: var(--overlay-bg-color);
|
|
18
|
-
width: 100vw;
|
|
19
|
-
height: var(--mobile-modal-height);
|
|
20
|
-
border-radius: var(--jb-select-mobile-modal-border-radius, 0) var(--jb-select-mobile-modal-border-radius, 0) 0 0;
|
|
21
|
-
margin: 0;
|
|
22
|
-
padding: 16px 8px;
|
|
23
|
-
z-index: var(--mobile-modal-z-index);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
.select-box {
|
|
27
|
-
@media(--tablet-until) {
|
|
28
|
-
height: var(--jb-select-mobile-search-input-height, var(--jb-select-height, 40px));
|
|
29
|
-
background-color: var(--jb-select-mobile-input-bgcolor, var(--select-box-bg-color));
|
|
30
|
-
border-width: var(--jb-select-mobile-search-border-width, var(--border-width));
|
|
31
|
-
border-color: var(--jb-select-mobile-search-border-color, var(--border-color));
|
|
32
|
-
border-bottom-width: var(--jb-select-mobile-search-border-bottom-width, var(--border-bottom-width));
|
|
33
|
-
border-bottom-color: var(--jb-select-mobile-search-border-bottom-color, var(--jb-select-border-bottom-color, var(--border-color)));
|
|
34
|
-
border-radius: var(--jb-select-mobile-search-border-radius, var(--border-radius));
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
.front-box {
|
|
38
|
-
.arrow-icon {
|
|
39
|
-
@media(--tablet-until) {
|
|
40
|
-
display: none;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
.selected-value-wrapper {
|
|
46
|
-
@media(--tablet-until) {
|
|
47
|
-
opacity: 0;
|
|
48
|
-
transition: none;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
.selected-value {}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
.middle-divider {
|
|
56
|
-
display: block;
|
|
57
|
-
|
|
58
|
-
@media(--tablet-until) {
|
|
59
|
-
margin: var(--jb-select-middle-div-mobile-margin, 16px 0 0 0);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
.select-list-wrapper {
|
|
64
|
-
@media(--tablet-until) {
|
|
65
|
-
position: initial;
|
|
66
|
-
margin: var(--jb-select-mobile-item-list-margin, 16px 0);
|
|
67
|
-
border-radius: var(--jb-select-mobile-item-list-border-radius, var(--border-radius));
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
.label-wrapper {
|
|
72
|
-
@media(--tablet-until) {
|
|
73
|
-
display: flex;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
label {
|
|
77
|
-
@media(--tablet-until) {
|
|
78
|
-
color: var(--modal-label-color);
|
|
79
|
-
font-size: 1.5em;
|
|
80
|
-
display: flex;
|
|
81
|
-
align-items: center;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
.close-button {
|
|
86
|
-
display: none;
|
|
87
|
-
|
|
88
|
-
@media(--tablet-until) {
|
|
89
|
-
display: flex;
|
|
90
|
-
width: 48px;
|
|
91
|
-
height: 48px;
|
|
92
|
-
justify-content: center;
|
|
93
|
-
align-items: center;
|
|
94
|
-
color: var(--modal-close-color);
|
|
95
|
-
|
|
96
|
-
.close-btn-svg-bg {
|
|
97
|
-
opacity: var(--jb-select-close-bg-opacity, 0.4);
|
|
98
|
-
fill: var(--close-bg-color);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
.close-btn-svg-path {
|
|
102
|
-
fill: var(--modal-close-color);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
11
|
&.--has-value {
|
|
110
12
|
|
|
111
|
-
/*if user select a option and value is
|
|
13
|
+
/*if user select a option and value is set and not null*/
|
|
112
14
|
.select-box {
|
|
113
15
|
border-color: var(--jb-select-border-color-selected, var(--border-color));
|
|
114
16
|
background-color: var(--jb-select-bgcolor-selected, var(--select-box-bg-color));
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.select-box .end-section .clear-button {
|
|
20
|
+
display: block;
|
|
120
21
|
}
|
|
121
22
|
}
|
|
122
23
|
|
|
123
24
|
.label-wrapper {
|
|
124
25
|
label {
|
|
26
|
+
|
|
27
|
+
|
|
125
28
|
width: 100%;
|
|
126
|
-
margin:
|
|
29
|
+
margin: var(--label-margin);
|
|
127
30
|
display: block;
|
|
128
|
-
font-size: var(--
|
|
129
|
-
font-weight: var(--jb-select-label-font-weight, normal);
|
|
31
|
+
font-size: var(--label-font-size);
|
|
130
32
|
color: var(--label-color);
|
|
33
|
+
|
|
34
|
+
font-weight: var(--jb-input-label-font-weight, 300);
|
|
131
35
|
|
|
132
36
|
&.--hide {
|
|
133
37
|
display: none;
|
|
134
38
|
}
|
|
135
39
|
}
|
|
40
|
+
}
|
|
136
41
|
|
|
137
|
-
|
|
138
|
-
|
|
42
|
+
&:focus-within .select-box {
|
|
43
|
+
|
|
44
|
+
@media(--tablet-from) {
|
|
45
|
+
/*when there is focus on whole select means menu is open so we change select styles*/
|
|
46
|
+
border-color: var(--border-color);
|
|
47
|
+
border-bottom-color: transparent;
|
|
48
|
+
border-radius: var(--rounded) var(--rounded) 0 0;
|
|
139
49
|
}
|
|
140
50
|
}
|
|
141
51
|
|
|
142
52
|
.select-box {
|
|
143
53
|
width: 100%;
|
|
144
54
|
box-sizing: border-box;
|
|
145
|
-
height: var(--
|
|
55
|
+
height: var(--height);
|
|
146
56
|
border: solid var(--border-width) var(--border-color);
|
|
147
57
|
border-bottom: solid var(--border-bottom-width) var(--border-color);
|
|
148
|
-
border-radius: var(--border-radius);
|
|
58
|
+
border-radius: var(--box-border-radius);
|
|
149
59
|
background-color: var(--select-box-bg-color);
|
|
150
60
|
margin: var(--jb-select-select-box-margin, 4px 0px 0px 0px);
|
|
151
61
|
overflow: hidden;
|
|
@@ -154,16 +64,6 @@
|
|
|
154
64
|
gap: 0.5rem;
|
|
155
65
|
align-items: center;
|
|
156
66
|
|
|
157
|
-
&:focus-within {
|
|
158
|
-
border-color: var(--jb-select-border-color, var(--border-color));
|
|
159
|
-
border-bottom-color: var(--jb-select-border-color, var(--border-color));
|
|
160
|
-
border-radius: var(--border-radius) var(--border-radius) 0 0;
|
|
161
|
-
|
|
162
|
-
@media(--tablet-until) {
|
|
163
|
-
border-radius: var(--jb-select-mobile-search-border-radius, var(--border-radius));
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
67
|
.start-section {
|
|
168
68
|
height: 100%;
|
|
169
69
|
width: auto;
|
|
@@ -219,17 +119,11 @@
|
|
|
219
119
|
overflow: hidden;
|
|
220
120
|
z-index: 2;
|
|
221
121
|
|
|
222
|
-
input {
|
|
223
|
-
border: none;
|
|
224
|
-
width: 100%;
|
|
225
|
-
box-sizing: border-box;
|
|
122
|
+
.search-input {
|
|
226
123
|
height: 100%;
|
|
227
124
|
background-color: transparent;
|
|
228
125
|
padding: 2px 12px 0 12px;
|
|
229
126
|
display: block;
|
|
230
|
-
font-family: inherit;
|
|
231
|
-
font-size: var(--jb-select-value-font-size, 1.1rem);
|
|
232
|
-
color: var(--value-color);
|
|
233
127
|
margin: 0;
|
|
234
128
|
border-radius: 0;
|
|
235
129
|
|
|
@@ -246,9 +140,20 @@
|
|
|
246
140
|
}
|
|
247
141
|
|
|
248
142
|
.end-section {
|
|
143
|
+
display: flex;
|
|
144
|
+
gap: 1.5rem;
|
|
145
|
+
align-items: center;
|
|
146
|
+
|
|
249
147
|
.arrow-icon {
|
|
250
148
|
margin: var(--jb-select-arrow-icon-margin, 0 0 0 0);
|
|
251
149
|
}
|
|
150
|
+
|
|
151
|
+
.clear-button {
|
|
152
|
+
/*show when there is value*/
|
|
153
|
+
display: none;
|
|
154
|
+
--jb-button-padding-xs: 0;
|
|
155
|
+
--jb-button-height-xs: 1rem;
|
|
156
|
+
}
|
|
252
157
|
}
|
|
253
158
|
|
|
254
159
|
|
|
@@ -260,92 +165,114 @@
|
|
|
260
165
|
|
|
261
166
|
}
|
|
262
167
|
|
|
263
|
-
.middle-divider {
|
|
264
|
-
display: none;
|
|
265
|
-
position: relative;
|
|
266
|
-
z-index: calc(var(--base-z-index) + 3);
|
|
267
|
-
width: 100%;
|
|
268
|
-
height: var(--middle-div-height);
|
|
269
|
-
background-color: var(--jb-select-middle-div-color, var(--border-color));
|
|
270
|
-
margin: var(--jb-select-middle-div-margin, calc(-1 * var(--border-bottom-width)) 0);
|
|
271
|
-
border-radius: var(--jb-select-middle-div-radius, 0px);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
168
|
.message-box {
|
|
275
|
-
font-size: var(--
|
|
276
|
-
|
|
277
|
-
padding: 4px 8px;
|
|
169
|
+
font-size: var(--message-font-size);
|
|
170
|
+
padding: 0.125rem var(--inline-space);
|
|
278
171
|
color: var(--message-color);
|
|
279
|
-
|
|
172
|
+
display: var(--jb-select-message-box-display, block);
|
|
280
173
|
&:empty {
|
|
281
174
|
padding: 0;
|
|
282
175
|
}
|
|
283
|
-
|
|
284
|
-
&.--error {
|
|
285
|
-
color: red;
|
|
286
|
-
}
|
|
287
176
|
}
|
|
288
177
|
|
|
289
|
-
.
|
|
290
|
-
|
|
291
|
-
position: absolute;
|
|
292
|
-
margin: calc(-1 * var(--border-bottom-width)) 0;
|
|
293
|
-
height: auto;
|
|
294
|
-
overflow: hidden;
|
|
295
|
-
width: 100%;
|
|
296
|
-
background-color: var(--select-box-bg-color);
|
|
297
|
-
border-radius: 0 0 var(--border-radius) var(--border-radius);
|
|
298
|
-
border: solid var(--jb-select-list-border-width, 1px) var(--border-color);
|
|
299
|
-
border-top: none;
|
|
300
|
-
border-bottom: solid var(--border-bottom-width) var(--border-color);
|
|
301
|
-
box-shadow: var(--jb-select-list-box-shadow);
|
|
302
|
-
box-sizing: border-box;
|
|
303
|
-
z-index: calc(var(--base-z-index) + 2);
|
|
178
|
+
.popover-wrapper {
|
|
179
|
+
position: relative;
|
|
304
180
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
181
|
+
.select-list-wrapper {
|
|
182
|
+
@media(--tablet-from) {
|
|
183
|
+
width: 100%;
|
|
184
|
+
--jb-popover-border-radius: var(--list-border-radius);
|
|
185
|
+
--jb-popover-bg-color: var(--select-box-bg-color);
|
|
186
|
+
--jb-popover-top: 0;
|
|
187
|
+
}
|
|
308
188
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
padding: 0;
|
|
189
|
+
&::part(content) {
|
|
190
|
+
|
|
191
|
+
@media(--tablet-from) {
|
|
192
|
+
/*in desktop*/
|
|
193
|
+
border: solid var(--border-width) var(--border-color);
|
|
194
|
+
border-bottom: solid var(--border-bottom-width) var(--border-color);
|
|
195
|
+
border-top: none;
|
|
317
196
|
}
|
|
318
197
|
}
|
|
319
198
|
|
|
199
|
+
.mobile-search-input-wrapper {
|
|
200
|
+
display: none;
|
|
201
|
+
|
|
202
|
+
@media(--tablet-until) {
|
|
203
|
+
display: block;
|
|
204
|
+
margin-block-end: 1rem;
|
|
205
|
+
margin-inline: 0.75rem;
|
|
206
|
+
|
|
207
|
+
.search-input {
|
|
208
|
+
background-color: var(--jb-select-mobile-input-bgcolor, var(--select-box-bg-color));
|
|
209
|
+
border-radius: var(--box-border-radius);
|
|
210
|
+
width: 100%;
|
|
211
|
+
height: var(--height);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
320
214
|
|
|
321
|
-
@media(--tablet-until) {
|
|
322
|
-
max-height: calc(var(--mobile-modal-height) - 15rem);
|
|
323
215
|
}
|
|
324
216
|
|
|
325
|
-
/* option style places */
|
|
326
217
|
|
|
327
|
-
|
|
328
|
-
width:
|
|
329
|
-
|
|
330
|
-
|
|
218
|
+
.select-list {
|
|
219
|
+
width: 100%;
|
|
220
|
+
max-height: var(--jb-select-list-max-height, 400px);
|
|
221
|
+
overflow-y: auto;
|
|
222
|
+
|
|
223
|
+
slot {
|
|
224
|
+
padding: var(--jb-select-list-padding, 16px 0);
|
|
225
|
+
|
|
226
|
+
&:empty {
|
|
227
|
+
padding: 0;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/* option style places */
|
|
331
232
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
233
|
+
&::-webkit-scrollbar {
|
|
234
|
+
width: 9px;
|
|
235
|
+
background-color: transparent;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
&::-webkit-scrollbar-thumb {
|
|
239
|
+
background-color: var(--list-scroll-color);
|
|
240
|
+
border-radius: var(--jb-select-list-scroll-border-radius, 4px);
|
|
241
|
+
}
|
|
335
242
|
}
|
|
336
|
-
}
|
|
337
243
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
244
|
+
.empty-list-placeholder {
|
|
245
|
+
display: none;
|
|
246
|
+
text-align: center;
|
|
247
|
+
color: var(--empty-list-placeholder-color);
|
|
248
|
+
font-style: italic;
|
|
249
|
+
padding: 8px 0;
|
|
344
250
|
|
|
345
|
-
|
|
346
|
-
|
|
251
|
+
&.--show {
|
|
252
|
+
display: block;
|
|
253
|
+
}
|
|
347
254
|
}
|
|
255
|
+
|
|
348
256
|
}
|
|
257
|
+
}
|
|
349
258
|
|
|
259
|
+
.search-input {
|
|
260
|
+
border: none;
|
|
261
|
+
width: 100%;
|
|
262
|
+
box-sizing: border-box;
|
|
263
|
+
padding: 2px 12px 0 12px;
|
|
264
|
+
display: block;
|
|
265
|
+
font-family: inherit;
|
|
266
|
+
font-size: var(--jb-select-value-font-size, 1.1rem);
|
|
267
|
+
color: var(--value-color);
|
|
268
|
+
|
|
269
|
+
&:focus {
|
|
270
|
+
outline: none;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
&::placeholder {
|
|
274
|
+
color: var(--placeholder-color);
|
|
275
|
+
font-size: var(--jb-select-placeholder-font-size, 1.1em);
|
|
276
|
+
}
|
|
350
277
|
}
|
|
351
278
|
}
|
package/lib/jb-select.ts
CHANGED
|
@@ -1,25 +1,31 @@
|
|
|
1
|
+
import "jb-button";
|
|
2
|
+
import "jb-popover";
|
|
1
3
|
import CSS from "./jb-select.css";
|
|
2
4
|
import VariablesCSS from "./variables.css";
|
|
3
|
-
import {
|
|
5
|
+
import type {
|
|
4
6
|
JBSelectCallbacks,
|
|
5
7
|
JBSelectElements,
|
|
6
8
|
ValidationValue,
|
|
7
9
|
} from "./types";
|
|
8
|
-
import { ShowValidationErrorParameters, ValidationHelper, type ValidationItem, type ValidationResult, type WithValidation } from "jb-validation";
|
|
10
|
+
import { type ShowValidationErrorParameters, ValidationHelper, type ValidationItem, type ValidationResult, type WithValidation } from "jb-validation";
|
|
9
11
|
import { isMobile } from "jb-core";
|
|
10
|
-
import { JBFormInputStandards } from 'jb-form';
|
|
12
|
+
import type { JBFormInputStandards } from 'jb-form';
|
|
11
13
|
// eslint-disable-next-line no-duplicate-imports
|
|
12
14
|
import { JBOptionWebComponent } from "./jb-option/jb-option";
|
|
13
15
|
import { registerDefaultVariables } from 'jb-core/theme';
|
|
14
16
|
import { renderHTML } from "./render";
|
|
15
17
|
import { dictionary } from "./i18n";
|
|
16
18
|
import { i18n } from "jb-core/i18n";
|
|
19
|
+
import type { JBButtonWebComponent } from "jb-button";
|
|
17
20
|
|
|
21
|
+
//TODO: add clean button to empty the select box after value selection
|
|
18
22
|
//TODO: add IncludeInputInList or freeSolo so user can select item that he wrote without even it exist in select list
|
|
19
23
|
//TODO: handleHomeEndKeys to move focus inside the popup with the Home and End keys.
|
|
20
24
|
/**
|
|
21
25
|
* TValue is the type of value we extract from option
|
|
22
26
|
*/
|
|
27
|
+
|
|
28
|
+
// biome-ignore lint/suspicious/noExplicitAny: <we support any type of value and there is no limitation on value type>
|
|
23
29
|
export class JBSelectWebComponent<TValue = any> extends HTMLElement implements WithValidation<ValidationValue<TValue>>, JBFormInputStandards<TValue> {
|
|
24
30
|
static get formAssociated() {
|
|
25
31
|
return true;
|
|
@@ -124,7 +130,7 @@ export class JBSelectWebComponent<TValue = any> extends HTMLElement implements W
|
|
|
124
130
|
#required = false;
|
|
125
131
|
set required(value: boolean) {
|
|
126
132
|
this.#required = value;
|
|
127
|
-
this.#internals.ariaRequired = value?"true":"false";
|
|
133
|
+
this.#internals.ariaRequired = value ? "true" : "false";
|
|
128
134
|
this.#validation.checkValiditySync({ showError: false });
|
|
129
135
|
}
|
|
130
136
|
get required() {
|
|
@@ -150,6 +156,7 @@ export class JBSelectWebComponent<TValue = any> extends HTMLElement implements W
|
|
|
150
156
|
if (typeof this.attachInternals == "function") {
|
|
151
157
|
//some browser dont support attachInternals
|
|
152
158
|
this.#internals = this.attachInternals();
|
|
159
|
+
this.#internals.role = "combobox"
|
|
153
160
|
}
|
|
154
161
|
this.#initWebComponent();
|
|
155
162
|
this.#initProp();
|
|
@@ -173,29 +180,45 @@ export class JBSelectWebComponent<TValue = any> extends HTMLElement implements W
|
|
|
173
180
|
delegatesFocus: true,
|
|
174
181
|
});
|
|
175
182
|
registerDefaultVariables();
|
|
176
|
-
const html = `<style>${CSS} ${VariablesCSS}</style
|
|
183
|
+
const html = `<style>${CSS} ${VariablesCSS}</style>\n${renderHTML()}`;
|
|
177
184
|
const element = document.createElement("template");
|
|
178
185
|
element.innerHTML = html;
|
|
179
186
|
shadowRoot.appendChild(element.content.cloneNode(true));
|
|
180
187
|
this.elements = {
|
|
181
|
-
input: shadowRoot.querySelector(".
|
|
188
|
+
input: shadowRoot.querySelector(".search-input")!,
|
|
182
189
|
componentWrapper: shadowRoot.querySelector(".jb-select-web-component")!,
|
|
183
|
-
selectedValueWrapper: shadowRoot.querySelector(
|
|
184
|
-
".selected-value-wrapper"
|
|
185
|
-
)!,
|
|
190
|
+
selectedValueWrapper: shadowRoot.querySelector(".selected-value-wrapper")!,
|
|
186
191
|
messageBox: shadowRoot.querySelector(".message-box")!,
|
|
187
192
|
optionList: shadowRoot.querySelector(".select-list")!,
|
|
188
193
|
optionListWrapper: shadowRoot.querySelector(".select-list-wrapper")!,
|
|
189
194
|
optionListSlot: shadowRoot.querySelector(".select-list-wrapper .select-list slot")!,
|
|
190
195
|
arrowIcon: shadowRoot.querySelector(".arrow-icon")!,
|
|
196
|
+
clearButton: shadowRoot.querySelector(".clear-button") as JBButtonWebComponent,
|
|
191
197
|
label: {
|
|
192
198
|
wrapper: shadowRoot.querySelector("label")!,
|
|
193
199
|
text: shadowRoot.querySelector("label .label-value")!,
|
|
194
200
|
},
|
|
195
201
|
emptyListPlaceholder: shadowRoot.querySelector(".empty-list-placeholder")!,
|
|
202
|
+
mobileSearchInputWrapper: shadowRoot.querySelector(".mobile-search-input-wrapper"),
|
|
203
|
+
frontBox: shadowRoot.querySelector(".front-box"),
|
|
196
204
|
};
|
|
197
205
|
this.#registerEventListener();
|
|
198
206
|
this.#updateListEmptyPlaceholder();
|
|
207
|
+
this.#setupDeviceRelates();
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* place code that change on select resize between mobile & desktop
|
|
211
|
+
*/
|
|
212
|
+
#setupDeviceRelates() {
|
|
213
|
+
const onResize = ()=> {
|
|
214
|
+
if (isMobile()) {
|
|
215
|
+
this.elements.mobileSearchInputWrapper.appendChild(this.elements.input)
|
|
216
|
+
} else {
|
|
217
|
+
this.elements.frontBox.appendChild(this.elements.input);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
addEventListener("resize", onResize);
|
|
221
|
+
onResize();
|
|
199
222
|
}
|
|
200
223
|
#registerEventListener() {
|
|
201
224
|
this.elements.input.addEventListener("change", (e: Event) => {
|
|
@@ -205,9 +228,10 @@ export class JBSelectWebComponent<TValue = any> extends HTMLElement implements W
|
|
|
205
228
|
this.elements.input.addEventListener("keyup", this.#onInputKeyup.bind(this));
|
|
206
229
|
this.elements.input.addEventListener("beforeinput", this.#onInputBeforeInput.bind(this));
|
|
207
230
|
this.elements.input.addEventListener("input", (e) => { this.#onInputInput(e as unknown as InputEvent); });
|
|
208
|
-
this.
|
|
231
|
+
this.addEventListener("focus", this.#onSelectFocus.bind(this));
|
|
209
232
|
this.elements.input.addEventListener("blur", this.#onInputBlur.bind(this));
|
|
210
233
|
this.elements.arrowIcon.addEventListener("click", this.#onArrowKeyClick.bind(this));
|
|
234
|
+
this.elements.clearButton.addEventListener("click", this.#onClearButtonClick.bind(this));
|
|
211
235
|
//events to work with options
|
|
212
236
|
this.addEventListener("select", this.#onOptionSelect.bind(this));
|
|
213
237
|
this.addEventListener("jb-option-connected", this.#onOptionConnected.bind(this));
|
|
@@ -230,7 +254,7 @@ export class JBSelectWebComponent<TValue = any> extends HTMLElement implements W
|
|
|
230
254
|
"error",
|
|
231
255
|
];
|
|
232
256
|
}
|
|
233
|
-
attributeChangedCallback(name: string,
|
|
257
|
+
attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
|
|
234
258
|
// do something when an attribute has changed
|
|
235
259
|
this.#onAttributeChange(name, newValue);
|
|
236
260
|
}
|
|
@@ -288,12 +312,12 @@ export class JBSelectWebComponent<TValue = any> extends HTMLElement implements W
|
|
|
288
312
|
}
|
|
289
313
|
#setValueOnOptionListChanged() {
|
|
290
314
|
//when option list changed we see if current value is valid for new optionlist we set it if not we reset value to null.
|
|
291
|
-
//in some scenario value is
|
|
315
|
+
//in some scenario value is set before optionList attached so we store it on this.#notFoundedValue and after option list set we set value from this.#notFoundedValue
|
|
292
316
|
if (this.#notFoundedValue) {
|
|
293
317
|
//if select has no prev value or pending not found value we don't set it because user may input some search terms in input box and developer-user update list base on that value
|
|
294
318
|
//if we set it to null the search term and this.textValue will become null and empty too and it make impossible for user to search in dynamic back-end provided searchable list so we put this condition to prevent it
|
|
295
|
-
const
|
|
296
|
-
if (
|
|
319
|
+
const isSet = this.#setValueFromOutside(this.#notFoundedValue);
|
|
320
|
+
if (isSet) {
|
|
297
321
|
//after list update and when not founded value is found in new option list we clear old not founded value
|
|
298
322
|
this.#notFoundedValue = null;
|
|
299
323
|
}
|
|
@@ -324,7 +348,7 @@ export class JBSelectWebComponent<TValue = any> extends HTMLElement implements W
|
|
|
324
348
|
}
|
|
325
349
|
//null option mean deselect all
|
|
326
350
|
#changeSelectedOption(option: JBOptionWebComponent<TValue> | null) {
|
|
327
|
-
this.#optionList.forEach((x) => x.selected = false);
|
|
351
|
+
this.#optionList.forEach((x) => { x.selected = false });
|
|
328
352
|
if (option) {
|
|
329
353
|
option.selected = true;
|
|
330
354
|
this.#selectedOption = option;
|
|
@@ -363,6 +387,13 @@ export class JBSelectWebComponent<TValue = any> extends HTMLElement implements W
|
|
|
363
387
|
this.focus();
|
|
364
388
|
}
|
|
365
389
|
}
|
|
390
|
+
#onClearButtonClick(e:MouseEvent) {
|
|
391
|
+
e.stopPropagation();
|
|
392
|
+
e.preventDefault();
|
|
393
|
+
this.#setValue(null,null);
|
|
394
|
+
this.#checkValidity(true);
|
|
395
|
+
this.#dispatchOnChangeEvent();
|
|
396
|
+
}
|
|
366
397
|
#onInputKeyPress(e: KeyboardEvent) {
|
|
367
398
|
const eventOptions: KeyboardEventInit = {
|
|
368
399
|
altKey: e.altKey,
|
|
@@ -383,7 +414,7 @@ export class JBSelectWebComponent<TValue = any> extends HTMLElement implements W
|
|
|
383
414
|
const event = new KeyboardEvent("keypress", eventOptions);
|
|
384
415
|
this.dispatchEvent(event);
|
|
385
416
|
}
|
|
386
|
-
#onInputBeforeInput(
|
|
417
|
+
#onInputBeforeInput(_e: InputEvent) {
|
|
387
418
|
// const inputtedText = e.data || "";
|
|
388
419
|
//TODO: add cancelable event dispatch here
|
|
389
420
|
}
|
|
@@ -453,6 +484,9 @@ export class JBSelectWebComponent<TValue = any> extends HTMLElement implements W
|
|
|
453
484
|
//here is the rare time we update _text_value directly because we want trigger event that may read value directly from dom
|
|
454
485
|
this.#textValue = inputText;
|
|
455
486
|
}
|
|
487
|
+
#onSelectFocus() {
|
|
488
|
+
this.focus();
|
|
489
|
+
}
|
|
456
490
|
#onInputFocus() {
|
|
457
491
|
this.focus();
|
|
458
492
|
}
|
|
@@ -470,13 +504,14 @@ export class JBSelectWebComponent<TValue = any> extends HTMLElement implements W
|
|
|
470
504
|
focus() {
|
|
471
505
|
this.elements.input.focus();
|
|
472
506
|
this.#showOptionList();
|
|
473
|
-
this.elements.
|
|
507
|
+
this.elements.optionListWrapper.open();
|
|
474
508
|
if (this.isMobileDevice) {
|
|
475
509
|
this.elements.input.placeholder = this.#searchPlaceholder;
|
|
476
510
|
}
|
|
477
511
|
}
|
|
478
512
|
blur() {
|
|
479
|
-
this.elements.componentWrapper.classList.remove("--focused");
|
|
513
|
+
// this.elements.componentWrapper.classList.remove("--focused");
|
|
514
|
+
this.elements.optionListWrapper.close();
|
|
480
515
|
this.textValue = "";
|
|
481
516
|
this.#handleSelectedValueDisplay("");
|
|
482
517
|
this.#hideOptionList();
|
|
@@ -599,7 +634,7 @@ export class JBSelectWebComponent<TValue = any> extends HTMLElement implements W
|
|
|
599
634
|
}
|
|
600
635
|
if (this.required) {
|
|
601
636
|
const label = this.getAttribute("label") || "";
|
|
602
|
-
const message = dictionary.get(i18n,"requireMessage")(label || null);
|
|
637
|
+
const message = dictionary.get(i18n, "requireMessage")(label || null);
|
|
603
638
|
validationList.push({
|
|
604
639
|
validator: ({ value }) => {
|
|
605
640
|
return value !== null && value !== undefined;
|
package/lib/render.ts
CHANGED
|
@@ -1,18 +1,8 @@
|
|
|
1
1
|
export function renderHTML(): string {
|
|
2
|
-
|
|
2
|
+
return /* html */ `
|
|
3
3
|
<div class="jb-select-web-component">
|
|
4
4
|
<div class="label-wrapper">
|
|
5
5
|
<label class="--hide"><span class="label-value"></span></label>
|
|
6
|
-
<!-- close button will be visible on mobile modal -->
|
|
7
|
-
<div class="close-button">
|
|
8
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
|
|
9
|
-
<path class="close-btn-svg-bg" opacity="0.4"
|
|
10
|
-
d="M16.3399 1.9998H7.66988C4.27988 1.9998 1.99988 4.3798 1.99988 7.9198V16.0898C1.99988 19.6198 4.27988 21.9998 7.66988 21.9998H16.3399C19.7299 21.9998 21.9999 19.6198 21.9999 16.0898V7.9198C21.9999 4.3798 19.7299 1.9998 16.3399 1.9998Z" />
|
|
11
|
-
<path class="close-btn-svg-path"
|
|
12
|
-
d="M15.0156 13.7703L13.2366 11.9923L15.0146 10.2143C15.3566 9.8733 15.3566 9.3183 15.0146 8.9773C14.6726 8.6333 14.1196 8.6343 13.7776 8.9763L11.9986 10.7543L10.2196 8.9743C9.87758 8.6323 9.32358 8.6343 8.98158 8.9743C8.64058 9.3163 8.64058 9.8713 8.98158 10.2123L10.7616 11.9923L8.98558 13.7673C8.64358 14.1093 8.64358 14.6643 8.98558 15.0043C9.15658 15.1763 9.37958 15.2613 9.60358 15.2613C9.82858 15.2613 10.0516 15.1763 10.2226 15.0053L11.9986 13.2293L13.7786 15.0083C13.9496 15.1793 14.1726 15.2643 14.3966 15.2643C14.6206 15.2643 14.8446 15.1783 15.0156 15.0083C15.3576 14.6663 15.3576 14.1123 15.0156 13.7703Z"
|
|
13
|
-
fill="#200E32" />
|
|
14
|
-
</svg>
|
|
15
|
-
</div>
|
|
16
6
|
</div>
|
|
17
7
|
<div class="select-box">
|
|
18
8
|
<div class="start-section">
|
|
@@ -21,11 +11,16 @@ export function renderHTML(): string {
|
|
|
21
11
|
<div class="middle-section">
|
|
22
12
|
<div class="selected-value-wrapper"></div>
|
|
23
13
|
<div class="front-box">
|
|
24
|
-
<input class="input" />
|
|
25
|
-
|
|
14
|
+
<input class="search-input" />
|
|
26
15
|
</div>
|
|
27
16
|
</div>
|
|
28
17
|
<div class="end-section">
|
|
18
|
+
<jb-button class="clear-button" color="dark" variant="ghost" size="xs">
|
|
19
|
+
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
20
|
+
<path d="M2.11183 24C1.57504 24 1.03826 23.8023 0.614479 23.3786C-0.204826 22.5596 -0.204826 21.2039 0.614479 20.3848L20.3908 0.614298C21.2101 -0.204766 22.5662 -0.204766 23.3855 0.614298C24.2048 1.43336 24.2048 2.78905 23.3855 3.60811L3.60918 23.3786C3.1854 23.8023 2.64861 24 2.11183 24Z" fill="currentColor"/>
|
|
21
|
+
<path d="M21.8882 24C21.3514 24 20.8146 23.8023 20.3908 23.3786L0.614479 3.60811C-0.204826 2.78905 -0.204826 1.43336 0.614479 0.614298C1.43378 -0.204766 2.78987 -0.204766 3.60918 0.614298L23.3855 20.3848C24.2048 21.2039 24.2048 22.5596 23.3855 23.3786C22.9617 23.8023 22.425 24 21.8882 24Z" fill="currentColor"/>
|
|
22
|
+
</svg>
|
|
23
|
+
</jb-button>
|
|
29
24
|
<div class="arrow-icon" tabindex="-1">
|
|
30
25
|
<slot name="select-arrow-icon">
|
|
31
26
|
<svg width='8' height='8' id='Layer_1' x='0px' y='0px' viewBox='0 0 494.1 371.1'
|
|
@@ -37,16 +32,18 @@ export function renderHTML(): string {
|
|
|
37
32
|
</div>
|
|
38
33
|
</div>
|
|
39
34
|
</div>
|
|
40
|
-
<div class="
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
<
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
<
|
|
49
|
-
|
|
35
|
+
<div class="popover-wrapper">
|
|
36
|
+
<jb-popover class="select-list-wrapper">
|
|
37
|
+
<div class="mobile-search-input-wrapper">
|
|
38
|
+
<!-- Here we put search input in Mobile -->
|
|
39
|
+
</div>
|
|
40
|
+
<div class="select-list" tabindex="-1" role="listbox">
|
|
41
|
+
<slot></slot>
|
|
42
|
+
</div>
|
|
43
|
+
<div class="empty-list-placeholder">
|
|
44
|
+
<slot name="empty-list-message">no item available</slot>
|
|
45
|
+
</div>
|
|
46
|
+
</jb-popover>
|
|
50
47
|
</div>
|
|
51
48
|
<div class="message-box"></div>
|
|
52
49
|
</div>
|