jb-select 6.5.0 → 7.0.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.
- package/README.md +5 -6
- 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 +110 -182
- package/lib/jb-select.ts +54 -19
- package/lib/render.ts +20 -23
- package/lib/types.ts +6 -1
- package/lib/variables.css +6 -7
- package/package.json +4 -2
package/lib/jb-select.css
CHANGED
|
@@ -1,122 +1,23 @@
|
|
|
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
|
|
|
@@ -133,19 +34,25 @@
|
|
|
133
34
|
display: none;
|
|
134
35
|
}
|
|
135
36
|
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
&:focus-within .select-box {
|
|
136
40
|
|
|
137
|
-
|
|
138
|
-
|
|
41
|
+
@media(--tablet-from) {
|
|
42
|
+
/*when there is focus on whole select means menu is open so we change select styles*/
|
|
43
|
+
border-color: var(--border-color);
|
|
44
|
+
border-bottom-color: transparent;
|
|
45
|
+
border-radius: var(--rounded) var(--rounded) 0 0;
|
|
139
46
|
}
|
|
140
47
|
}
|
|
141
48
|
|
|
142
49
|
.select-box {
|
|
143
50
|
width: 100%;
|
|
144
51
|
box-sizing: border-box;
|
|
145
|
-
height: var(--
|
|
52
|
+
height: var(--height);
|
|
146
53
|
border: solid var(--border-width) var(--border-color);
|
|
147
54
|
border-bottom: solid var(--border-bottom-width) var(--border-color);
|
|
148
|
-
border-radius: var(--border-radius);
|
|
55
|
+
border-radius: var(--box-border-radius);
|
|
149
56
|
background-color: var(--select-box-bg-color);
|
|
150
57
|
margin: var(--jb-select-select-box-margin, 4px 0px 0px 0px);
|
|
151
58
|
overflow: hidden;
|
|
@@ -154,16 +61,6 @@
|
|
|
154
61
|
gap: 0.5rem;
|
|
155
62
|
align-items: center;
|
|
156
63
|
|
|
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
64
|
.start-section {
|
|
168
65
|
height: 100%;
|
|
169
66
|
width: auto;
|
|
@@ -219,17 +116,11 @@
|
|
|
219
116
|
overflow: hidden;
|
|
220
117
|
z-index: 2;
|
|
221
118
|
|
|
222
|
-
input {
|
|
223
|
-
border: none;
|
|
224
|
-
width: 100%;
|
|
225
|
-
box-sizing: border-box;
|
|
119
|
+
.search-input {
|
|
226
120
|
height: 100%;
|
|
227
121
|
background-color: transparent;
|
|
228
122
|
padding: 2px 12px 0 12px;
|
|
229
123
|
display: block;
|
|
230
|
-
font-family: inherit;
|
|
231
|
-
font-size: var(--jb-select-value-font-size, 1.1rem);
|
|
232
|
-
color: var(--value-color);
|
|
233
124
|
margin: 0;
|
|
234
125
|
border-radius: 0;
|
|
235
126
|
|
|
@@ -246,9 +137,20 @@
|
|
|
246
137
|
}
|
|
247
138
|
|
|
248
139
|
.end-section {
|
|
140
|
+
display: flex;
|
|
141
|
+
gap: 1.5rem;
|
|
142
|
+
align-items: center;
|
|
143
|
+
|
|
249
144
|
.arrow-icon {
|
|
250
145
|
margin: var(--jb-select-arrow-icon-margin, 0 0 0 0);
|
|
251
146
|
}
|
|
147
|
+
|
|
148
|
+
.clear-button {
|
|
149
|
+
/*show when there is value*/
|
|
150
|
+
display: none;
|
|
151
|
+
--jb-button-padding-xs: 0;
|
|
152
|
+
--jb-button-height-xs: 1rem;
|
|
153
|
+
}
|
|
252
154
|
}
|
|
253
155
|
|
|
254
156
|
|
|
@@ -260,17 +162,6 @@
|
|
|
260
162
|
|
|
261
163
|
}
|
|
262
164
|
|
|
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
165
|
.message-box {
|
|
275
166
|
font-size: var(--jb-select-message-font-size, 0.7em);
|
|
276
167
|
font-weight: var(--jb-select-message-font-weight, normal);
|
|
@@ -286,66 +177,103 @@
|
|
|
286
177
|
}
|
|
287
178
|
}
|
|
288
179
|
|
|
289
|
-
.
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
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);
|
|
180
|
+
.popover-wrapper {
|
|
181
|
+
position: relative;
|
|
182
|
+
.select-list-wrapper {
|
|
183
|
+
@media(--tablet-from) {
|
|
184
|
+
width: 100%;
|
|
185
|
+
--jb-popover-border-radius: var(--list-border-radius);
|
|
186
|
+
--jb-popover-bg-color: var(--select-box-bg-color);
|
|
187
|
+
--jb-popover-top: 0;
|
|
188
|
+
}
|
|
304
189
|
|
|
305
|
-
|
|
306
|
-
display: block;
|
|
307
|
-
}
|
|
190
|
+
&::part(content) {
|
|
308
191
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
padding: var(--jb-select-list-padding, 16px 0);
|
|
315
|
-
&:empty {
|
|
316
|
-
padding: 0;
|
|
192
|
+
@media(--tablet-from) {
|
|
193
|
+
/*in desktop*/
|
|
194
|
+
border: solid var(--border-width) var(--border-color);
|
|
195
|
+
border-bottom: solid var(--border-bottom-width) var(--border-color);
|
|
196
|
+
border-top: none;
|
|
317
197
|
}
|
|
318
198
|
}
|
|
319
199
|
|
|
200
|
+
.mobile-search-input-wrapper {
|
|
201
|
+
display: none;
|
|
202
|
+
|
|
203
|
+
@media(--tablet-until) {
|
|
204
|
+
display: block;
|
|
205
|
+
margin-block-end: 1rem;
|
|
206
|
+
margin-inline: 0.75rem;
|
|
207
|
+
|
|
208
|
+
.search-input {
|
|
209
|
+
background-color: var(--jb-select-mobile-input-bgcolor, var(--select-box-bg-color));
|
|
210
|
+
border-radius: var(--box-border-radius);
|
|
211
|
+
width: 100%;
|
|
212
|
+
height: var(--height);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
320
215
|
|
|
321
|
-
@media(--tablet-until) {
|
|
322
|
-
max-height: calc(var(--mobile-modal-height) - 15rem);
|
|
323
216
|
}
|
|
324
217
|
|
|
325
|
-
/* option style places */
|
|
326
218
|
|
|
327
|
-
|
|
328
|
-
width:
|
|
329
|
-
|
|
330
|
-
|
|
219
|
+
.select-list {
|
|
220
|
+
width: 100%;
|
|
221
|
+
max-height: var(--jb-select-list-max-height, 400px);
|
|
222
|
+
overflow-y: auto;
|
|
223
|
+
|
|
224
|
+
slot {
|
|
225
|
+
padding: var(--jb-select-list-padding, 16px 0);
|
|
226
|
+
|
|
227
|
+
&:empty {
|
|
228
|
+
padding: 0;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/* option style places */
|
|
233
|
+
|
|
234
|
+
&::-webkit-scrollbar {
|
|
235
|
+
width: 9px;
|
|
236
|
+
background-color: transparent;
|
|
237
|
+
}
|
|
331
238
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
239
|
+
&::-webkit-scrollbar-thumb {
|
|
240
|
+
background-color: var(--list-scroll-color);
|
|
241
|
+
border-radius: var(--jb-select-list-scroll-border-radius, 4px);
|
|
242
|
+
}
|
|
335
243
|
}
|
|
336
|
-
}
|
|
337
244
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
245
|
+
.empty-list-placeholder {
|
|
246
|
+
display: none;
|
|
247
|
+
text-align: center;
|
|
248
|
+
color: var(--empty-list-placeholder-color);
|
|
249
|
+
font-style: italic;
|
|
250
|
+
padding: 8px 0;
|
|
344
251
|
|
|
345
|
-
|
|
346
|
-
|
|
252
|
+
&.--show {
|
|
253
|
+
display: block;
|
|
254
|
+
}
|
|
347
255
|
}
|
|
256
|
+
|
|
348
257
|
}
|
|
258
|
+
}
|
|
349
259
|
|
|
260
|
+
.search-input {
|
|
261
|
+
border: none;
|
|
262
|
+
width: 100%;
|
|
263
|
+
box-sizing: border-box;
|
|
264
|
+
padding: 2px 12px 0 12px;
|
|
265
|
+
display: block;
|
|
266
|
+
font-family: inherit;
|
|
267
|
+
font-size: var(--jb-select-value-font-size, 1.1rem);
|
|
268
|
+
color: var(--value-color);
|
|
269
|
+
|
|
270
|
+
&:focus {
|
|
271
|
+
outline: none;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
&::placeholder {
|
|
275
|
+
color: var(--placeholder-color);
|
|
276
|
+
font-size: var(--jb-select-placeholder-font-size, 1.1em);
|
|
277
|
+
}
|
|
350
278
|
}
|
|
351
279
|
}
|
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>
|
package/lib/types.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { JBOptionWebComponent } from "./jb-option/jb-option";
|
|
2
2
|
import type {EventTypeWithTarget} from "jb-core";
|
|
3
3
|
import type{ JBSelectWebComponent } from "./jb-select";
|
|
4
|
+
import type {JBButtonWebComponent} from "jb-button";
|
|
5
|
+
import type { JBPopoverWebComponent } from "jb-popover";
|
|
4
6
|
export type JBSelectCallbacks<TValue> = {
|
|
5
7
|
getSelectedValueDOM?:(value:TValue,content:HTMLElement) => HTMLElement;
|
|
6
8
|
}
|
|
@@ -11,14 +13,17 @@ export type JBSelectElements = {
|
|
|
11
13
|
selectedValueWrapper: HTMLDivElement,
|
|
12
14
|
messageBox:HTMLDivElement,
|
|
13
15
|
optionList: HTMLDivElement,
|
|
14
|
-
optionListWrapper:
|
|
16
|
+
optionListWrapper: JBPopoverWebComponent,
|
|
15
17
|
optionListSlot:HTMLSlotElement,
|
|
16
18
|
arrowIcon: HTMLDivElement,
|
|
19
|
+
clearButton: JBButtonWebComponent,
|
|
17
20
|
label:{
|
|
18
21
|
wrapper: HTMLLabelElement,
|
|
19
22
|
text: HTMLSpanElement
|
|
20
23
|
},
|
|
21
24
|
emptyListPlaceholder: HTMLDivElement,
|
|
25
|
+
mobileSearchInputWrapper:HTMLDivElement,
|
|
26
|
+
frontBox:HTMLDivElement
|
|
22
27
|
}
|
|
23
28
|
export type ValidationValue<TValue> = {
|
|
24
29
|
selectedOption:JBOptionWebComponent<TValue> | null,
|