@kws3/ui 1.1.0 → 1.2.2

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.
@@ -1,438 +0,0 @@
1
- <!--
2
- @component
3
-
4
- @param {string} [value=""] - Bind value, Default: `""`
5
- @param {string} [filter=""] - Filter, Default: `""`
6
- @param {string} [style=""] - Inline styles, Default: `""`
7
- @param {string} [classes=""] - Additional classes, Default: `""`
8
- @param {string} [dd_class=""] - Dropdown class, Default: `""`
9
- @param {string} [cy=""] - data-cy attribute for cypress, Default: `""`
10
- @param {string} [searchKey="null"] - which key to search in each data object, Default: `"null"`
11
- @param {string} [searchValue="null"] - which value to search in each data object, Default: `"null"`
12
- @param {object} [data={}] - Object of option values, Default: `{}`
13
- @param {boolean} [open=false] - Open - true/false, Default: `false`
14
- @param {boolean} [disabled=false] - Disabled - true/false, Default: `false`
15
- @param {string} [placeholder=""] - Placeholder string, Default: `""`
16
-
17
- -->
18
- <svelte:window on:resize={close} />
19
- <div
20
- bind:this={searchableselect}
21
- class="searchableselect input is-shadowless {disabled
22
- ? ' is-disabled '
23
- : ' '} {klass}"
24
- on:click={openDropdown}
25
- {style}
26
- data-cy="select-container">
27
- <span class="name-wrapper">
28
- <span class="name"> {_name || placeholder} </span>
29
- </span>
30
-
31
- <input
32
- type="text"
33
- use:keyboardEvents
34
- bind:value={filter}
35
- on:focus={openDropdown}
36
- on:enter={onEnter}
37
- on:uparrow={onUparrow}
38
- on:downarrow={onDownarrow}
39
- on:escape={onEscape} />
40
-
41
- <ul
42
- bind:this={dropdown}
43
- class="dropdown {open ? ' open ' : ' '} {dd_class}"
44
- data-cy={cy}>
45
- <li
46
- class={selected && highlighted < 0 ? "selected" : ""}
47
- on:click={() => select(null)}>
48
- {placeholder}
49
- </li>
50
- {#if items && items.length}
51
- {#each items as item, i}
52
- <li
53
- class="{highlighted == i ? ' selecting ' : ' '} {selected == i
54
- ? 'selected '
55
- : ' '}"
56
- on:click={() => select(item, i)}>
57
- {item[searchKey]}
58
- </li>
59
- {/each}
60
- {/if}
61
- </ul>
62
- </div>
63
-
64
- <script>
65
- import { onMount, onDestroy, tick } from "svelte";
66
- import { keyboardEvents } from "../utils/keyboard-events";
67
-
68
- let dropdownId = "searchableselect-dropdown-container";
69
-
70
- let searchableselect, el, dropdown, _dropdown, input_el, selected_el;
71
-
72
- /**
73
- * Bind value
74
- */
75
- export let value = "",
76
- /**
77
- * Filter
78
- */
79
- filter = "",
80
- /**
81
- * Inline CSS for the displayed text
82
- */
83
- style = "",
84
- /**
85
- * CSS classes for the dropdown
86
- */
87
- dd_class = "",
88
- /**
89
- * data-cy attribute for cypress
90
- */
91
- cy = "",
92
- /**
93
- * Key to be searched in each data object
94
- */
95
- searchKey = null,
96
- /**
97
- * Value to be searched in each data object
98
- */
99
- searchValue = null,
100
- /**
101
- * All searchable options as objects in an array
102
- */
103
- data = [],
104
- /**
105
- * Determines whether the dropdown is currently open
106
- */
107
- open = false,
108
- /**
109
- * Disables the component
110
- */
111
- disabled = false,
112
- /**
113
- * Placeholder string
114
- */
115
- placeholder = "";
116
-
117
- /**
118
- * CSS classes for the component
119
- */
120
- let klass = "";
121
- export { klass as class };
122
-
123
- let _name = "",
124
- scrollTarget = null,
125
- highlighted = -1, // for dropdown
126
- selected = -1, // for selected items
127
- items;
128
-
129
- function prepareItems(_data, _filter) {
130
- _filter = _filter.toLowerCase();
131
- let _items = _data || [];
132
-
133
- if (!_items || !(_items instanceof Array)) return null;
134
-
135
- items = _items.slice().filter(function (item) {
136
- // filter out items that don't match `filter`
137
- if (typeof item === "object") {
138
- if (searchKey) {
139
- if (
140
- typeof item[searchKey] === "string" &&
141
- item[searchKey].toLowerCase().indexOf(filter) > -1
142
- )
143
- return true;
144
- } else {
145
- for (var key in item) {
146
- if (
147
- typeof item[key] === "string" &&
148
- item[key].toLowerCase().indexOf(filter) > -1
149
- )
150
- return true;
151
- }
152
- }
153
- } else {
154
- return item.toLowerCase().indexOf(filter) > -1;
155
- }
156
- });
157
-
158
- console.log(items);
159
- }
160
-
161
- let clickHandler = function (e) {
162
- e.stopImmediatePropagation();
163
- let el = searchableselect;
164
- if (!el) {
165
- return;
166
- }
167
- let dropdown = el.querySelector(".dropdown");
168
-
169
- let target = e.target;
170
-
171
- if (el.contains(target) || target === dropdown) return;
172
-
173
- open = false;
174
- };
175
-
176
- let scrollHandler = function (e) {
177
- e.stopImmediatePropagation();
178
- e.stopPropagation();
179
-
180
- console.log(e);
181
-
182
- if (!scrollTarget) {
183
- scrollTarget = window;
184
- } else if (typeof scrollTarget === "string") {
185
- scrollTarget = document.getElementById(scrollTarget);
186
- }
187
- if (open && e.target == scrollTarget) {
188
- close();
189
- }
190
- };
191
-
192
- function onUparrow(e) {
193
- e.stopPropagation();
194
- e.stopImmediatePropagation();
195
- e.preventDefault();
196
-
197
- selected = -1;
198
- if (highlighted <= -1) return;
199
-
200
- // increase highlighted until we find a non group
201
- do {
202
- highlighted--;
203
- } while (highlighted == -1);
204
-
205
- highlighted = Math.max(-1, highlighted);
206
-
207
- updateBounds();
208
- }
209
-
210
- function onDownarrow(e) {
211
- e.stopPropagation();
212
- e.stopImmediatePropagation();
213
- e.preventDefault();
214
-
215
- selected = -1;
216
-
217
- if (highlighted >= items.length - 1) return;
218
-
219
- if (!open) {
220
- openDropdown();
221
- }
222
-
223
- do {
224
- highlighted++;
225
- } while (highlighted == items.length);
226
-
227
- highlighted = Math.min(items.length, highlighted);
228
-
229
- updateBounds();
230
- }
231
-
232
- function onEnter(e) {
233
- e.stopPropagation();
234
- e.stopImmediatePropagation();
235
- e.preventDefault();
236
-
237
- if (highlighted !== -1) {
238
- if (open) {
239
- select(items[highlighted], highlighted);
240
- }
241
- }
242
-
243
- if (highlighted < 0) {
244
- select(null);
245
- }
246
- }
247
-
248
- function onEscape(e) {
249
- e.stopPropagation();
250
- e.stopImmediatePropagation();
251
- e.preventDefault();
252
-
253
- close();
254
- }
255
-
256
- function openDropdown() {
257
- console.log("openDropdown");
258
- if (!disabled) {
259
- open = true;
260
- }
261
- updateBounds();
262
- }
263
-
264
- function close() {
265
- open = false;
266
- }
267
-
268
- function select(item, i) {
269
- if (!item) {
270
- (value = ""), (_name = ""), (selected = null);
271
- } else {
272
- (value = item[searchValue]),
273
- (_name = item[searchKey]),
274
- (selected = +i),
275
- (highlighted = +i);
276
- }
277
- filter = "";
278
- close();
279
- updateBounds();
280
- }
281
-
282
- function updateName(_value) {
283
- if (_value === "") {
284
- _name = "";
285
- filter = "";
286
- highlighted = -1;
287
- selected = -1;
288
- } else {
289
- for (let i in data) {
290
- if (data[i][searchValue] == _value) {
291
- _name = data[i][searchKey];
292
- selected = i;
293
- highlighted = i;
294
- break;
295
- }
296
- }
297
- }
298
- }
299
-
300
- function updateHandler(_open) {
301
- if (!scrollTarget) {
302
- scrollTarget = window;
303
- } else if (typeof scrollTarget === "string") {
304
- scrollTarget = document.getElementById(scrollTarget);
305
- }
306
-
307
- updateBounds();
308
- console.log(scrollTarget);
309
- if (_open) {
310
- document.addEventListener("click", clickHandler);
311
- scrollTarget.addEventListener("scroll", scrollHandler);
312
- } else {
313
- document.removeEventListener("click", clickHandler);
314
- scrollTarget.removeEventListener("scroll", scrollHandler);
315
- }
316
- }
317
-
318
- async function updateElementState() {
319
- await tick();
320
- if (!open) {
321
- input_el.style.display = "none";
322
- selected_el.style.display = "block";
323
-
324
- if (value === "") {
325
- (highlighted = -1), (selected = -1);
326
- }
327
- } else {
328
- input_el.style.display = "block";
329
- selected_el.style.display = "none";
330
- input_el.focus();
331
- input_el.select();
332
- }
333
- }
334
-
335
- function updateBounds() {
336
- if (!dropdown) {
337
- return;
338
- }
339
-
340
- let highlightedElement = dropdown.querySelector(".selecting");
341
- let selectedElement = dropdown.querySelector(".selected");
342
-
343
- let bounds = el.getBoundingClientRect();
344
-
345
- // match dropdown width with el width
346
- _dropdown.style.width = bounds.width + "px";
347
-
348
- dropdown = _dropdown;
349
-
350
- // console.log(bounds);
351
-
352
- if (open) {
353
- if (highlightedElement != null) {
354
- if (highlightedElement.offsetTop > 358) {
355
- dropdown.scrollTop = highlightedElement.offsetTop - 358;
356
- } else {
357
- dropdown.scrollTop = 0;
358
- }
359
- }
360
-
361
- if (selectedElement != null) {
362
- if (selectedElement.offsetTop > 358) {
363
- dropdown.scrollTop = selectedElement.offsetTop - 358;
364
- } else {
365
- dropdown.scrollTop = 0;
366
- }
367
- }
368
-
369
- dropdown.style.left = bounds.left + "px";
370
- let top = bounds.bottom,
371
- inht = window.innerHeight;
372
- if (top + dropdown.offsetHeight > inht) {
373
- //not enough space to render drop down below input,
374
- //render it above
375
- dropdown.style.bottom = inht - (bounds.top - 3) + "px";
376
- dropdown.style.top = "auto";
377
- } else {
378
- dropdown.style.top = top + "px";
379
- dropdown.style.bottom = "auto";
380
- }
381
- } else {
382
- dropdown.style.left = "-9999px";
383
- }
384
- }
385
-
386
- function init() {
387
- input_el.style.display = "none";
388
- selected_el.style.display = "block";
389
-
390
- if (!data) {
391
- data = [];
392
- }
393
-
394
- //hoist the dropdowns into a container on the body
395
- dropdown = searchableselect.querySelector(".dropdown");
396
-
397
- _dropdown = dropdown; // cache for later
398
-
399
- let container = document.getElementById(dropdownId);
400
-
401
- if (!container) {
402
- container = document.createElement("div");
403
- container.id = dropdownId;
404
- container.className = "searchableselect";
405
- document.body.appendChild(container);
406
- }
407
- container.appendChild(dropdown);
408
- updateBounds();
409
- }
410
-
411
- $: data, prepareItems(data, filter);
412
- $: value, updateName(value);
413
- $: open, updateHandler(open), updateBounds(), updateElementState();
414
-
415
- onMount(() => {
416
- el = searchableselect;
417
- selected_el = el.querySelector(".name");
418
- input_el = el.querySelector("input");
419
- init();
420
- });
421
-
422
- onDestroy(() => {
423
- searchableselect.removeEventListener("click", clickHandler);
424
- window.removeEventListener("click", clickHandler);
425
- document.removeEventListener("scroll", scrollHandler);
426
-
427
- //have to manually clean this up since we hoisted it from under svelte's nose
428
- if (_dropdown) {
429
- _dropdown.parentNode.removeChild(_dropdown);
430
- }
431
-
432
- let container = document.getElementById(dropdownId);
433
-
434
- if (container && container.childNodes.length == 0) {
435
- container.parentNode.removeChild(container);
436
- }
437
- });
438
- </script>
@@ -1,128 +0,0 @@
1
- $kws-ss-item-selected-bg-color:#0071bc !default;
2
- $kws-ss-item-selected-text-color:#ffffff !default;
3
- $kws-ss-item-selecting-bg-color:#0071bc !default;
4
- $kws-ss-item-selecting-text-color:#ffffff !default;
5
- $kws-ss-dropdown-bg-color: #ffffff !default;
6
- $kws-ss-dropdown-text-color: #333 !default;
7
- $kws-ss-caret-color: #0071bc !default;
8
- .searchableselect {
9
- flex-wrap: wrap;
10
- height: auto;
11
- min-height: 32px;
12
- padding: 2px;
13
- overflow: hidden;
14
- cursor: pointer;
15
- &.is-disabled {
16
- background-color: #fff;
17
- border-color: #fff;
18
- box-shadow: none;
19
- color: #7a7a7a;
20
- cursor: not-allowed;
21
- &:active,
22
- &:focus,
23
- &:hover {
24
- border: none;
25
- }
26
- }
27
-
28
- &.is-shadowless {
29
- box-shadow: none;
30
- }
31
-
32
- &,
33
- *,
34
- *:before,
35
- *:after {
36
- box-sizing: border-box;
37
- }
38
- input {
39
- flex: 1 1 auto;
40
- background: none;
41
- border: none;
42
- box-shadow: none;
43
- outline: none;
44
- font-size: 14px;
45
- height: 24px;
46
- max-height: 24px;
47
- line-height: 24px;
48
- padding: 3px 8px;
49
- position: relative;
50
- vertical-align: top;
51
- width: 100%;
52
- }
53
- .name-wrapper {
54
- display: block;
55
- padding-right: 35px;
56
- overflow: hidden;
57
- padding-left: 8px;
58
- .name {
59
- position: relative;
60
- overflow: hidden;
61
- display: block;
62
- text-overflow: ellipsis;
63
- white-space: nowrap;
64
- }
65
- &:hover:after {
66
- border-color: #222324;
67
- }
68
- &:after {
69
- border: 1px solid $kws-ss-caret-color;
70
- border-right: 0;
71
- border-top: 0;
72
- content: " ";
73
- display: block;
74
- height: 7px;
75
- pointer-events: none;
76
- position: absolute;
77
- transform: rotate(-45deg);
78
- width: 7px;
79
- margin-top: -6px;
80
- right: 16px;
81
- top: 50%;
82
- }
83
- }
84
- .dropdown {
85
- margin: 3px 0 0 0; // for user-agent ul styles
86
- background: #fff;
87
- color: #333;
88
- border-radius: 3px;
89
- padding: 2px 0;
90
- cursor: default;
91
- list-style: none;
92
- z-index: 50;
93
- box-shadow: 0 3px 9px rgba(0, 0, 0, 0.4);
94
- max-height: 400px; // decent default
95
- overflow-y: auto;
96
- display: block;
97
- &:not(.open) {
98
- display: none;
99
- }
100
- }
101
- li {
102
- padding: 0.3em 0.5em;
103
- border-top: 1px solid transparent;
104
- border-bottom: 1px solid transparent;
105
- &:hover {
106
- background: lightgrey;
107
- }
108
- &.selecting {
109
- background: lighten($kws-ss-item-selecting-bg-color, 10%);
110
- color: $kws-ss-item-selecting-text-color;
111
- }
112
- &.selected {
113
- background: lighten($kws-ss-item-selected-bg-color, 10%);
114
- color: $kws-ss-item-selected-text-color;
115
- border-top-color: $kws-ss-item-selected-bg-color;
116
- border-bottom-color: $kws-ss-item-selected-bg-color;
117
- }
118
- }
119
- }
120
-
121
- #searchableselect-dropdown-container {
122
- position: absolute;
123
- z-index: 2000;
124
- .dropdown {
125
- position: fixed;
126
- left: -9999px;
127
- }
128
- }