@nyaruka/temba-components 0.113.0 → 0.114.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/CHANGELOG.md +21 -2
- package/demo/index.html +1 -1
- package/dist/temba-components.js +793 -966
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/aliaseditor/AliasEditor.js.map +1 -1
- package/out-tsc/src/button/Button.js +6 -2
- package/out-tsc/src/button/Button.js.map +1 -1
- package/out-tsc/src/chat/Chat.js +29 -7
- package/out-tsc/src/chat/Chat.js.map +1 -1
- package/out-tsc/src/compose/Compose.js +10 -5
- package/out-tsc/src/compose/Compose.js.map +1 -1
- package/out-tsc/src/contacts/ContactChat.js +240 -114
- package/out-tsc/src/contacts/ContactChat.js.map +1 -1
- package/out-tsc/src/contacts/ContactFieldEditor.js.map +1 -1
- package/out-tsc/src/contacts/events.js.map +1 -1
- package/out-tsc/src/contacts/helpers.js +5 -1
- package/out-tsc/src/contacts/helpers.js.map +1 -1
- package/out-tsc/src/contactsearch/ContactSearch.js +1 -1
- package/out-tsc/src/contactsearch/ContactSearch.js.map +1 -1
- package/out-tsc/src/dropdown/Dropdown.js +121 -108
- package/out-tsc/src/dropdown/Dropdown.js.map +1 -1
- package/out-tsc/src/interfaces.js +2 -0
- package/out-tsc/src/interfaces.js.map +1 -1
- package/out-tsc/src/list/ContentMenu.js +11 -8
- package/out-tsc/src/list/ContentMenu.js.map +1 -1
- package/out-tsc/src/list/RunList.js.map +1 -1
- package/out-tsc/src/list/TembaList.js +21 -14
- package/out-tsc/src/list/TembaList.js.map +1 -1
- package/out-tsc/src/list/TembaMenu.js +11 -12
- package/out-tsc/src/list/TembaMenu.js.map +1 -1
- package/out-tsc/src/list/TicketList.js +10 -0
- package/out-tsc/src/list/TicketList.js.map +1 -1
- package/out-tsc/src/omnibox/Omnibox.js +33 -90
- package/out-tsc/src/omnibox/Omnibox.js.map +1 -1
- package/out-tsc/src/options/Options.js +49 -47
- package/out-tsc/src/options/Options.js.map +1 -1
- package/out-tsc/src/select/PopupSelect.js +57 -0
- package/out-tsc/src/select/PopupSelect.js.map +1 -0
- package/out-tsc/src/select/Select.js +194 -144
- package/out-tsc/src/select/Select.js.map +1 -1
- package/out-tsc/src/select/UserSelect.js +67 -0
- package/out-tsc/src/select/UserSelect.js.map +1 -0
- package/out-tsc/src/store/Store.js +65 -14
- package/out-tsc/src/store/Store.js.map +1 -1
- package/out-tsc/src/tabpane/TabPane.js +72 -115
- package/out-tsc/src/tabpane/TabPane.js.map +1 -1
- package/out-tsc/src/textinput/TextInput.js +1 -0
- package/out-tsc/src/textinput/TextInput.js.map +1 -1
- package/out-tsc/src/user/TembaUser.js +24 -37
- package/out-tsc/src/user/TembaUser.js.map +1 -1
- package/out-tsc/src/utils/index.js +13 -6
- package/out-tsc/src/utils/index.js.map +1 -1
- package/out-tsc/temba-modules.js +4 -2
- package/out-tsc/temba-modules.js.map +1 -1
- package/out-tsc/test/temba-omnibox.test.js +43 -4
- package/out-tsc/test/temba-omnibox.test.js.map +1 -1
- package/out-tsc/test/temba-select.test.js +121 -65
- package/out-tsc/test/temba-select.test.js.map +1 -1
- package/out-tsc/test/utils.test.js +4 -0
- package/out-tsc/test/utils.test.js.map +1 -1
- package/package.json +1 -1
- package/screenshots/truth/compose/attachments-tab.png +0 -0
- package/screenshots/truth/compose/attachments-with-files-focused.png +0 -0
- package/screenshots/truth/compose/attachments-with-files.png +0 -0
- package/screenshots/truth/compose/intial-text.png +0 -0
- package/screenshots/truth/compose/no-counter.png +0 -0
- package/screenshots/truth/compose/wraps-text-and-spaces.png +0 -0
- package/screenshots/truth/compose/wraps-text-and-url.png +0 -0
- package/screenshots/truth/compose/wraps-text-no-spaces.png +0 -0
- package/screenshots/truth/contacts/chat-failure.png +0 -0
- package/screenshots/truth/contacts/chat-for-active-contact.png +0 -0
- package/screenshots/truth/contacts/chat-for-archived-contact.png +0 -0
- package/screenshots/truth/contacts/chat-for-blocked-contact.png +0 -0
- package/screenshots/truth/contacts/chat-for-stopped-contact.png +0 -0
- package/screenshots/truth/contacts/chat-sends-attachments-only.png +0 -0
- package/screenshots/truth/contacts/chat-sends-text-and-attachments.png +0 -0
- package/screenshots/truth/contacts/chat-sends-text-only.png +0 -0
- package/screenshots/truth/content-menu/item-no-buttons.png +0 -0
- package/screenshots/truth/content-menu/items-and-buttons.png +0 -0
- package/screenshots/truth/omnibox/selected.png +0 -0
- package/screenshots/truth/select/enabled-multi-selection.png +0 -0
- package/screenshots/truth/select/endpoint-initial-value-updated.png +0 -0
- package/screenshots/truth/select/endpoint-initial-value.png +0 -0
- package/screenshots/truth/select/expressions.png +0 -0
- package/screenshots/truth/select/functions.png +0 -0
- package/screenshots/truth/select/initial-value.png +0 -0
- package/screenshots/truth/select/multi-with-endpoint.png +0 -0
- package/screenshots/truth/select/multiple-initial-values.png +0 -0
- package/screenshots/truth/select/selected-multi-test.png +0 -0
- package/screenshots/truth/select/static-initial-value.png +0 -0
- package/screenshots/truth/select/static-initial-via-selected.png +0 -0
- package/screenshots/truth/select/value-initial.png +0 -0
- package/src/aliaseditor/AliasEditor.ts +1 -1
- package/src/button/Button.ts +6 -2
- package/src/chat/Chat.ts +28 -6
- package/src/compose/Compose.ts +11 -6
- package/src/contacts/ContactChat.ts +260 -118
- package/src/contacts/ContactFieldEditor.ts +1 -1
- package/src/contacts/events.ts +1 -0
- package/src/contacts/helpers.ts +8 -1
- package/src/contactsearch/ContactSearch.ts +3 -3
- package/src/dropdown/Dropdown.ts +142 -103
- package/src/interfaces.ts +4 -1
- package/src/list/ContentMenu.ts +11 -9
- package/src/list/RunList.ts +3 -1
- package/src/list/TembaList.ts +24 -14
- package/src/list/TembaMenu.ts +14 -15
- package/src/list/TicketList.ts +11 -0
- package/src/omnibox/Omnibox.ts +34 -95
- package/src/options/Options.ts +57 -60
- package/src/select/PopupSelect.ts +53 -0
- package/src/select/Select.ts +182 -112
- package/src/select/UserSelect.ts +71 -0
- package/src/store/Store.ts +70 -21
- package/src/tabpane/TabPane.ts +79 -113
- package/src/textinput/TextInput.ts +1 -0
- package/src/user/TembaUser.ts +30 -41
- package/src/utils/index.ts +12 -8
- package/temba-modules.ts +4 -2
- package/test/temba-omnibox.test.ts +56 -4
- package/test/temba-select.test.ts +170 -56
- package/test/utils.test.ts +5 -0
- package/test-assets/select/omnibox.json +55 -0
- package/web-test-runner.config.mjs +16 -4
- package/out-tsc/src/contacts/ContactTickets.js +0 -462
- package/out-tsc/src/contacts/ContactTickets.js.map +0 -1
- package/out-tsc/test/temba-contact-tickets.test.js +0 -36
- package/out-tsc/test/temba-contact-tickets.test.js.map +0 -1
- package/src/contacts/ContactTickets.ts +0 -490
- package/test/temba-contact-tickets.test.ts +0 -52
|
@@ -13,62 +13,10 @@ import { Icon } from '../vectoricon';
|
|
|
13
13
|
import { msg } from '@lit/localize';
|
|
14
14
|
const LOOK_AHEAD = 20;
|
|
15
15
|
export class Select extends FormElement {
|
|
16
|
-
constructor() {
|
|
17
|
-
super(...arguments);
|
|
18
|
-
this.hiddenInputs = [];
|
|
19
|
-
this.inputStyle = {};
|
|
20
|
-
this.multi = false;
|
|
21
|
-
this.searchOnFocus = false;
|
|
22
|
-
this.placeholder = '';
|
|
23
|
-
this.name = '';
|
|
24
|
-
this.nameKey = 'name';
|
|
25
|
-
this.valueKey = 'value';
|
|
26
|
-
this.queryParam = null;
|
|
27
|
-
this.input = '';
|
|
28
|
-
this.visibleOptions = [];
|
|
29
|
-
this.completionOptions = [];
|
|
30
|
-
this.quietMillis = 0;
|
|
31
|
-
this.searchable = false;
|
|
32
|
-
this.cache = true;
|
|
33
|
-
this.cacheKey = '';
|
|
34
|
-
this.focused = false;
|
|
35
|
-
this.disabled = false;
|
|
36
|
-
this.selectedIndex = -1;
|
|
37
|
-
this.anchorPosition = { left: 0, top: 0 };
|
|
38
|
-
this.tags = false;
|
|
39
|
-
this.flavor = 'default';
|
|
40
|
-
this.infoText = '';
|
|
41
|
-
this.values = [];
|
|
42
|
-
this.getName = (option) => option[this.nameKey || 'name'];
|
|
43
|
-
this.isMatch = (option, q) => {
|
|
44
|
-
const name = this.getName(option) || '';
|
|
45
|
-
return name.toLowerCase().indexOf(q) > -1;
|
|
46
|
-
};
|
|
47
|
-
this.getValue = (option) => option[this.valueKey || 'value'] || option.id;
|
|
48
|
-
this.sortFunction = null;
|
|
49
|
-
this.renderOptionDetail = () => html ``;
|
|
50
|
-
this.renderSelectedItem = this.renderSelectedItemDefault;
|
|
51
|
-
this.createArbitraryOption = this.createArbitraryOptionDefault;
|
|
52
|
-
this.getOptions = this.getOptionsDefault;
|
|
53
|
-
this.prepareOptions = (options) => options;
|
|
54
|
-
this.isComplete = this.isCompleteDefault;
|
|
55
|
-
this.staticOptions = [];
|
|
56
|
-
this.alphaSort = (a, b) => {
|
|
57
|
-
// by default, all endpoint values are sorted by name
|
|
58
|
-
if (this.endpoint) {
|
|
59
|
-
return this.getName(a).localeCompare(this.getName(b));
|
|
60
|
-
}
|
|
61
|
-
return 0;
|
|
62
|
-
};
|
|
63
|
-
this.next = null;
|
|
64
|
-
this.lruCache = lru(20, 60000);
|
|
65
|
-
this.getNameInternal = (option) => {
|
|
66
|
-
return this.getName(option);
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
16
|
static get styles() {
|
|
70
17
|
return css `
|
|
71
18
|
:host {
|
|
19
|
+
--transition-speed: 0;
|
|
72
20
|
font-family: var(--font-family);
|
|
73
21
|
transition: all ease-in-out var(--transition-speed);
|
|
74
22
|
display: inline;
|
|
@@ -81,6 +29,7 @@ export class Select extends FormElement {
|
|
|
81
29
|
temba-options {
|
|
82
30
|
--temba-options-font-size: var(--temba-select-selected-font-size);
|
|
83
31
|
--icon-color: var(--color-text-dark);
|
|
32
|
+
--color-options-bg: #fff;
|
|
84
33
|
}
|
|
85
34
|
|
|
86
35
|
:host:focus {
|
|
@@ -361,8 +310,69 @@ export class Select extends FormElement {
|
|
|
361
310
|
}
|
|
362
311
|
`;
|
|
363
312
|
}
|
|
313
|
+
constructor() {
|
|
314
|
+
super();
|
|
315
|
+
this.hiddenInputs = [];
|
|
316
|
+
this.inputStyle = {};
|
|
317
|
+
this.multi = false;
|
|
318
|
+
this.searchOnFocus = false;
|
|
319
|
+
this.placeholder = '';
|
|
320
|
+
this.name = '';
|
|
321
|
+
this.nameKey = 'name';
|
|
322
|
+
this.valueKey = 'value';
|
|
323
|
+
this.queryParam = null;
|
|
324
|
+
this.input = '';
|
|
325
|
+
this.visibleOptions = [];
|
|
326
|
+
this.completionOptions = [];
|
|
327
|
+
this.quietMillis = 0;
|
|
328
|
+
this.searchable = false;
|
|
329
|
+
this.cache = true;
|
|
330
|
+
this.cacheKey = '';
|
|
331
|
+
this.focused = false;
|
|
332
|
+
this.disabled = false;
|
|
333
|
+
this.selectedIndex = -1;
|
|
334
|
+
this.anchorPosition = { left: 0, top: 0 };
|
|
335
|
+
this.tags = false;
|
|
336
|
+
this.flavor = 'default';
|
|
337
|
+
this.infoText = '';
|
|
338
|
+
this.values = [];
|
|
339
|
+
this.getName = (option) => option[this.nameKey || 'name'];
|
|
340
|
+
this.isMatch = this.isMatchDefault;
|
|
341
|
+
this.getValue = (option) => option[this.valueKey || 'value'] || option.id;
|
|
342
|
+
this.sortFunction = null;
|
|
343
|
+
this.renderOptionDetail = () => html ``;
|
|
344
|
+
this.renderSelectedItem = this.renderSelectedItemDefault;
|
|
345
|
+
this.createArbitraryOption = this.createArbitraryOptionDefault;
|
|
346
|
+
this.getOptions = this.getOptionsDefault;
|
|
347
|
+
this.prepareOptions = this.prepareOptionsDefault;
|
|
348
|
+
this.isComplete = this.isCompleteDefault;
|
|
349
|
+
this.staticOptions = [];
|
|
350
|
+
this.alphaSort = (a, b) => {
|
|
351
|
+
// by default, all endpoint values are sorted by name
|
|
352
|
+
if (this.endpoint) {
|
|
353
|
+
return this.getName(a).localeCompare(this.getName(b));
|
|
354
|
+
}
|
|
355
|
+
return 0;
|
|
356
|
+
};
|
|
357
|
+
this.next = null;
|
|
358
|
+
this.lruCache = lru(20, 60000);
|
|
359
|
+
this.getNameInternal = (option) => {
|
|
360
|
+
return this.getName(option);
|
|
361
|
+
};
|
|
362
|
+
this.renderOptionDefault = this.renderOptionDefault.bind(this);
|
|
363
|
+
this.renderSelectedItemDefault = this.renderSelectedItemDefault.bind(this);
|
|
364
|
+
this.prepareOptionsDefault = this.prepareOptionsDefault.bind(this);
|
|
365
|
+
this.isMatchDefault = this.isMatchDefault.bind(this);
|
|
366
|
+
}
|
|
367
|
+
prepareOptionsDefault(options) {
|
|
368
|
+
return options;
|
|
369
|
+
}
|
|
370
|
+
isMatchDefault(option, q) {
|
|
371
|
+
const name = this.getName(option) || '';
|
|
372
|
+
return name.toLowerCase().indexOf(q) > -1;
|
|
373
|
+
}
|
|
364
374
|
handleSlotChange() {
|
|
365
|
-
if (this.staticOptions.length === 0) {
|
|
375
|
+
if (this.staticOptions && this.staticOptions.length === 0) {
|
|
366
376
|
for (const child of this.children) {
|
|
367
377
|
if (child.tagName === 'TEMBA-OPTION') {
|
|
368
378
|
const option = {};
|
|
@@ -370,10 +380,23 @@ export class Select extends FormElement {
|
|
|
370
380
|
option[attribute.name] = attribute.value;
|
|
371
381
|
}
|
|
372
382
|
if (option) {
|
|
383
|
+
let selected = false;
|
|
384
|
+
// if the option is marked as selected then accept it
|
|
385
|
+
if (option['selected'] !== undefined) {
|
|
386
|
+
delete option['selected'];
|
|
387
|
+
selected = true;
|
|
388
|
+
}
|
|
389
|
+
// the option value might also match the widget value
|
|
390
|
+
const selectValue = this.value || this.getAttribute('value');
|
|
391
|
+
if (selectValue) {
|
|
392
|
+
const optionValue = this.getValue(option);
|
|
393
|
+
if (optionValue == selectValue) {
|
|
394
|
+
selected = true;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
373
397
|
this.staticOptions.push(option);
|
|
374
|
-
if (
|
|
375
|
-
|
|
376
|
-
if (this.getAttribute('multi') !== null) {
|
|
398
|
+
if (selected) {
|
|
399
|
+
if (this.multi) {
|
|
377
400
|
this.addValue(option);
|
|
378
401
|
}
|
|
379
402
|
else {
|
|
@@ -384,43 +407,47 @@ export class Select extends FormElement {
|
|
|
384
407
|
}
|
|
385
408
|
}
|
|
386
409
|
}
|
|
387
|
-
this.checkSelectedOption();
|
|
388
410
|
if (this.searchable && this.staticOptions.length === 0) {
|
|
389
411
|
this.quietMillis = 200;
|
|
390
412
|
}
|
|
391
413
|
}
|
|
392
414
|
checkSelectedOption() {
|
|
393
|
-
if
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
415
|
+
// see if we need fetch to select an option
|
|
416
|
+
if (this.value &&
|
|
417
|
+
this.values.length == 0 &&
|
|
418
|
+
this.staticOptions.length == 0 &&
|
|
419
|
+
this.endpoint) {
|
|
420
|
+
const value = this.value;
|
|
421
|
+
this.resolving = true;
|
|
422
|
+
fetchResults(this.endpoint).then((results) => {
|
|
423
|
+
if (results && results.length > 0) {
|
|
424
|
+
if (value) {
|
|
425
|
+
// if we started with a value, see if we can find it in the results
|
|
426
|
+
const existing = results.find((option) => {
|
|
427
|
+
return this.getValue(option) === value;
|
|
428
|
+
});
|
|
429
|
+
if (existing) {
|
|
430
|
+
this.resolving = false;
|
|
431
|
+
this.fetching = false;
|
|
432
|
+
this.setValues([existing]);
|
|
433
|
+
return;
|
|
408
434
|
}
|
|
409
|
-
this.setValues([results[0]]);
|
|
410
435
|
}
|
|
411
|
-
|
|
436
|
+
this.setValues([results[0]]);
|
|
437
|
+
this.resolving = false;
|
|
438
|
+
}
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
else if (this.staticOptions.length > 0) {
|
|
442
|
+
if (this.getAttribute('multi') !== null) {
|
|
443
|
+
this.addValue(this.staticOptions[0]);
|
|
412
444
|
}
|
|
413
|
-
else
|
|
414
|
-
if (this.getAttribute('
|
|
415
|
-
this.
|
|
445
|
+
else {
|
|
446
|
+
if (this.getAttribute('value')) {
|
|
447
|
+
this.setSelectedValue(this.getAttribute('value'));
|
|
416
448
|
}
|
|
417
449
|
else {
|
|
418
|
-
|
|
419
|
-
this.setSelectedValue(this.getAttribute('value'));
|
|
420
|
-
}
|
|
421
|
-
else {
|
|
422
|
-
this.setValues([this.staticOptions[0]]);
|
|
423
|
-
}
|
|
450
|
+
this.setValues([this.staticOptions[0]]);
|
|
424
451
|
}
|
|
425
452
|
}
|
|
426
453
|
}
|
|
@@ -430,31 +457,30 @@ export class Select extends FormElement {
|
|
|
430
457
|
this.anchorElement = this.shadowRoot.querySelector('.select-container');
|
|
431
458
|
this.anchorExpressions = this.shadowRoot.querySelector('#anchor');
|
|
432
459
|
this.shadowRoot.addEventListener('slotchange', this.handleSlotChange.bind(this));
|
|
433
|
-
this.checkSelectedOption();
|
|
434
460
|
}
|
|
435
|
-
updated(
|
|
436
|
-
super.updated(
|
|
437
|
-
if (
|
|
461
|
+
updated(changes) {
|
|
462
|
+
super.updated(changes);
|
|
463
|
+
if (changes.has('sorted')) {
|
|
438
464
|
this.sortFunction = this.sorted ? this.alphaSort : null;
|
|
439
465
|
}
|
|
440
|
-
if (
|
|
466
|
+
if (changes.has('value')) {
|
|
467
|
+
if (this.value && !this.values.length) {
|
|
468
|
+
this.setSelectedValue(this.value);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
if (changes.has('values')) {
|
|
441
472
|
this.updateInputs();
|
|
442
|
-
if (this.
|
|
443
|
-
this.values.length === 1 ||
|
|
444
|
-
// fire change if being cleared
|
|
445
|
-
(this.values.length == 0 &&
|
|
446
|
-
changedProperties.get('values') &&
|
|
447
|
-
changedProperties.get('values').length > 0)) {
|
|
473
|
+
if (this.hasChanges(changes.get('values'))) {
|
|
448
474
|
this.fireEvent('change');
|
|
449
475
|
}
|
|
450
476
|
}
|
|
451
477
|
// if our cache key changes, clear it out
|
|
452
|
-
if (
|
|
478
|
+
if (changes.has('cacheKey')) {
|
|
453
479
|
this.lruCache.clear();
|
|
454
480
|
}
|
|
455
|
-
if (
|
|
456
|
-
!
|
|
457
|
-
!
|
|
481
|
+
if (changes.has('input') &&
|
|
482
|
+
!changes.has('values') &&
|
|
483
|
+
!changes.has('options') &&
|
|
458
484
|
this.focused) {
|
|
459
485
|
if (this.lastQuery) {
|
|
460
486
|
window.clearTimeout(this.lastQuery);
|
|
@@ -468,14 +494,13 @@ export class Select extends FormElement {
|
|
|
468
494
|
}
|
|
469
495
|
}, this.quietMillis);
|
|
470
496
|
}
|
|
471
|
-
if (this.endpoint &&
|
|
497
|
+
if (this.endpoint && changes.has('fetching')) {
|
|
472
498
|
if (!this.fetching && !this.isPastFetchThreshold()) {
|
|
473
499
|
this.fireCustomEvent(CustomEventType.FetchComplete);
|
|
474
500
|
}
|
|
475
501
|
}
|
|
476
502
|
// if our cursor changed, lets make sure our scrollbox is showing it
|
|
477
|
-
if ((
|
|
478
|
-
changedProperties.has('visibleOptions')) &&
|
|
503
|
+
if ((changes.has('cursorIndex') || changes.has('visibleOptions')) &&
|
|
479
504
|
this.endpoint &&
|
|
480
505
|
!this.fetching) {
|
|
481
506
|
if (this.isPastFetchThreshold()) {
|
|
@@ -487,10 +512,6 @@ export class Select extends FormElement {
|
|
|
487
512
|
}
|
|
488
513
|
}
|
|
489
514
|
}
|
|
490
|
-
// if they set an inital value, look through our static options for it
|
|
491
|
-
if (changedProperties.has('value') && this.value && !this.values.length) {
|
|
492
|
-
this.setSelectedValue(this.value);
|
|
493
|
-
}
|
|
494
515
|
// default to the first option if we don't have a placeholder
|
|
495
516
|
if (this.values.length === 0 &&
|
|
496
517
|
!this.placeholder &&
|
|
@@ -498,6 +519,25 @@ export class Select extends FormElement {
|
|
|
498
519
|
this.setValues([this.staticOptions[0]]);
|
|
499
520
|
}
|
|
500
521
|
}
|
|
522
|
+
hasChanges(prev) {
|
|
523
|
+
if (prev === undefined) {
|
|
524
|
+
return false;
|
|
525
|
+
}
|
|
526
|
+
let prevValues = undefined;
|
|
527
|
+
if (prev !== undefined) {
|
|
528
|
+
prevValues = (prev || [])
|
|
529
|
+
.map((option) => {
|
|
530
|
+
return this.getValue(option);
|
|
531
|
+
})
|
|
532
|
+
.join(',');
|
|
533
|
+
}
|
|
534
|
+
const newValues = (this.values || [])
|
|
535
|
+
.map((option) => {
|
|
536
|
+
return this.getValue(option);
|
|
537
|
+
})
|
|
538
|
+
.join(',');
|
|
539
|
+
return prevValues !== newValues;
|
|
540
|
+
}
|
|
501
541
|
setSelectedValue(value) {
|
|
502
542
|
if (this.staticOptions.length > 0) {
|
|
503
543
|
const existing = this.staticOptions.find((option) => {
|
|
@@ -507,6 +547,9 @@ export class Select extends FormElement {
|
|
|
507
547
|
this.setValues([existing]);
|
|
508
548
|
}
|
|
509
549
|
}
|
|
550
|
+
else {
|
|
551
|
+
this.checkSelectedOption();
|
|
552
|
+
}
|
|
510
553
|
}
|
|
511
554
|
updateInputs() {
|
|
512
555
|
for (let ele = null; (ele = this.hiddenInputs.pop());) {
|
|
@@ -560,6 +603,8 @@ export class Select extends FormElement {
|
|
|
560
603
|
(this.cursorIndex || 0) > this.visibleOptions.length - LOOK_AHEAD);
|
|
561
604
|
}
|
|
562
605
|
handleOptionSelection(event) {
|
|
606
|
+
event.preventDefault();
|
|
607
|
+
event.stopPropagation();
|
|
563
608
|
const selected = event.detail.selected;
|
|
564
609
|
// check if we should post it
|
|
565
610
|
if (selected.post && this.endpoint) {
|
|
@@ -607,7 +652,7 @@ export class Select extends FormElement {
|
|
|
607
652
|
return null;
|
|
608
653
|
}
|
|
609
654
|
open() {
|
|
610
|
-
this.
|
|
655
|
+
this.shadowRoot.querySelector('.select-container').click();
|
|
611
656
|
}
|
|
612
657
|
isOpen() {
|
|
613
658
|
return this.visibleOptions.length > 0;
|
|
@@ -698,10 +743,6 @@ export class Select extends FormElement {
|
|
|
698
743
|
this.completionOptions = [];
|
|
699
744
|
if (!this.fetching) {
|
|
700
745
|
this.fetching = true;
|
|
701
|
-
// make sure we cancel any previous request
|
|
702
|
-
// if (this.cancelToken) {
|
|
703
|
-
// this.cancelToken.cancel();
|
|
704
|
-
// }
|
|
705
746
|
const options = [...this.staticOptions];
|
|
706
747
|
const q = (query || '').trim().toLowerCase();
|
|
707
748
|
if (this.tags && q) {
|
|
@@ -815,9 +856,6 @@ export class Select extends FormElement {
|
|
|
815
856
|
handleFocus() {
|
|
816
857
|
if (!this.focused && this.visibleOptions.length === 0) {
|
|
817
858
|
this.focused = true;
|
|
818
|
-
if (this.searchOnFocus && !this.removingSelection) {
|
|
819
|
-
this.requestUpdate('input');
|
|
820
|
-
}
|
|
821
859
|
}
|
|
822
860
|
}
|
|
823
861
|
handleBlur() {
|
|
@@ -941,30 +979,33 @@ export class Select extends FormElement {
|
|
|
941
979
|
];
|
|
942
980
|
}
|
|
943
981
|
handleArrowClick(event) {
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
this.
|
|
948
|
-
}
|
|
949
|
-
else {
|
|
950
|
-
this.handleContainerClick(event);
|
|
982
|
+
if (this.isOpen()) {
|
|
983
|
+
event.preventDefault();
|
|
984
|
+
event.stopPropagation();
|
|
985
|
+
this.blur();
|
|
951
986
|
}
|
|
952
987
|
}
|
|
953
|
-
|
|
988
|
+
renderOptionDefault(option) {
|
|
954
989
|
if (!option) {
|
|
955
990
|
return null;
|
|
956
991
|
}
|
|
992
|
+
// special case for icons on any option type
|
|
993
|
+
const icon = option.icon;
|
|
957
994
|
return html `
|
|
958
995
|
<div class="option-name" style="display:flex">
|
|
959
|
-
${
|
|
996
|
+
${icon
|
|
960
997
|
? html `<temba-icon
|
|
961
|
-
name="${
|
|
998
|
+
name="${icon}"
|
|
962
999
|
style="margin-right:0.5em;"
|
|
963
1000
|
></temba-icon>`
|
|
964
1001
|
: null}<span>${this.getName(option)}</span>
|
|
965
1002
|
</div>
|
|
966
1003
|
`;
|
|
967
1004
|
}
|
|
1005
|
+
renderSelectedItemDefault(option) {
|
|
1006
|
+
const renderFn = this.renderOption || this.renderOptionDefault;
|
|
1007
|
+
return renderFn(option, true);
|
|
1008
|
+
}
|
|
968
1009
|
serializeValue(value) {
|
|
969
1010
|
// static options just use their value
|
|
970
1011
|
if (!this.jsonValue && (this.staticOptions.length > 0 || this.tags)) {
|
|
@@ -974,8 +1015,8 @@ export class Select extends FormElement {
|
|
|
974
1015
|
}
|
|
975
1016
|
setSelection(value) {
|
|
976
1017
|
for (const option of this.staticOptions) {
|
|
977
|
-
if (this.getValue(option
|
|
978
|
-
if (this.values.length === 0 || this.values[0].value
|
|
1018
|
+
if (this.getValue(option) === value) {
|
|
1019
|
+
if (this.values.length === 0 || this.values[0].value != '' + value) {
|
|
979
1020
|
this.setValues([option]);
|
|
980
1021
|
}
|
|
981
1022
|
return;
|
|
@@ -990,29 +1031,37 @@ export class Select extends FormElement {
|
|
|
990
1031
|
this.visibleOptions = [];
|
|
991
1032
|
this.requestUpdate();
|
|
992
1033
|
}
|
|
1034
|
+
this.fireCustomEvent(CustomEventType.Selection, {
|
|
1035
|
+
selected: null
|
|
1036
|
+
});
|
|
993
1037
|
}
|
|
994
1038
|
setValues(values) {
|
|
1039
|
+
const oldValues = this.values;
|
|
995
1040
|
this.values = values;
|
|
996
|
-
this.requestUpdate('values');
|
|
1041
|
+
this.requestUpdate('values', oldValues);
|
|
997
1042
|
}
|
|
998
1043
|
addValue(value) {
|
|
1044
|
+
const oldValues = [...this.values];
|
|
999
1045
|
this.values.push(value);
|
|
1000
|
-
this.requestUpdate('values');
|
|
1046
|
+
this.requestUpdate('values', oldValues);
|
|
1001
1047
|
}
|
|
1002
1048
|
removeValue(valueToRemove) {
|
|
1049
|
+
const oldValues = [...this.values];
|
|
1003
1050
|
const idx = this.values.indexOf(valueToRemove);
|
|
1004
1051
|
if (idx > -1) {
|
|
1005
1052
|
this.values.splice(idx, 1);
|
|
1006
1053
|
}
|
|
1007
|
-
this.requestUpdate('values');
|
|
1054
|
+
this.requestUpdate('values', oldValues);
|
|
1008
1055
|
}
|
|
1009
1056
|
popValue() {
|
|
1057
|
+
const oldValues = [...this.values];
|
|
1010
1058
|
this.values.pop();
|
|
1011
|
-
this.requestUpdate('values');
|
|
1059
|
+
this.requestUpdate('values', oldValues);
|
|
1012
1060
|
}
|
|
1013
1061
|
clear() {
|
|
1062
|
+
const oldValues = this.values;
|
|
1014
1063
|
this.values = [];
|
|
1015
|
-
this.requestUpdate('values');
|
|
1064
|
+
this.requestUpdate('values', oldValues);
|
|
1016
1065
|
}
|
|
1017
1066
|
render() {
|
|
1018
1067
|
const placeholder = this.values.length === 0 ? this.placeholder : '';
|
|
@@ -1081,11 +1130,15 @@ export class Select extends FormElement {
|
|
|
1081
1130
|
class="select-container ${classes}"
|
|
1082
1131
|
@click=${this.handleContainerClick}
|
|
1083
1132
|
>
|
|
1084
|
-
|
|
1085
|
-
<div class="left-side">
|
|
1133
|
+
<div class="left-side" >
|
|
1086
1134
|
<slot name="prefix"></slot>
|
|
1087
|
-
<div class="selected">
|
|
1088
|
-
${
|
|
1135
|
+
<div class="selected" >
|
|
1136
|
+
${this.resolving
|
|
1137
|
+
? html `<temba-loading
|
|
1138
|
+
style="margin-left:1em"
|
|
1139
|
+
></temba-loading>`
|
|
1140
|
+
: null}
|
|
1141
|
+
${!this.multi && !this.resolving ? input : null}
|
|
1089
1142
|
${this.values.map((selected, index) => html `
|
|
1090
1143
|
<div
|
|
1091
1144
|
class="selected-item ${index === this.selectedIndex
|
|
@@ -1097,12 +1150,6 @@ export class Select extends FormElement {
|
|
|
1097
1150
|
<div
|
|
1098
1151
|
class="remove-item"
|
|
1099
1152
|
style="margin-top:1px"
|
|
1100
|
-
@mousedown=${() => {
|
|
1101
|
-
this.removingSelection = true;
|
|
1102
|
-
}}
|
|
1103
|
-
@mouseup=${() => {
|
|
1104
|
-
this.removingSelection = false;
|
|
1105
|
-
}}
|
|
1106
1153
|
@click=${(evt) => {
|
|
1107
1154
|
evt.preventDefault();
|
|
1108
1155
|
evt.stopPropagation();
|
|
@@ -1129,7 +1176,7 @@ export class Select extends FormElement {
|
|
|
1129
1176
|
<slot name="right"></slot>
|
|
1130
1177
|
${!this.tags
|
|
1131
1178
|
? html `<div
|
|
1132
|
-
class="right-side"
|
|
1179
|
+
class="right-side arrow"
|
|
1133
1180
|
style="display:block;margin-right:5px"
|
|
1134
1181
|
@click=${this.handleArrowClick}
|
|
1135
1182
|
>
|
|
@@ -1153,13 +1200,13 @@ export class Select extends FormElement {
|
|
|
1153
1200
|
.cursorIndex=${this.cursorIndex}
|
|
1154
1201
|
.renderOptionDetail=${this.renderOptionDetail}
|
|
1155
1202
|
.renderOptionName=${this.renderOptionName}
|
|
1156
|
-
.renderOption=${this.renderOption}
|
|
1203
|
+
.renderOption=${this.renderOption || this.renderOptionDefault}
|
|
1157
1204
|
.anchorTo=${this.anchorElement}
|
|
1158
1205
|
.options=${this.visibleOptions}
|
|
1159
1206
|
.spaceSelect=${this.spaceSelect}
|
|
1160
1207
|
.nameKey=${this.nameKey}
|
|
1161
1208
|
.getName=${this.getNameInternal}
|
|
1162
|
-
static-width=${this.optionWidth}
|
|
1209
|
+
?static-width=${this.optionWidth}
|
|
1163
1210
|
?anchor-right=${this.anchorRight}
|
|
1164
1211
|
?visible=${this.visibleOptions.length > 0}
|
|
1165
1212
|
></temba-options>
|
|
@@ -1234,6 +1281,9 @@ __decorate([
|
|
|
1234
1281
|
__decorate([
|
|
1235
1282
|
property({ type: Boolean })
|
|
1236
1283
|
], Select.prototype, "fetching", void 0);
|
|
1284
|
+
__decorate([
|
|
1285
|
+
property({ type: Boolean })
|
|
1286
|
+
], Select.prototype, "resolving", void 0);
|
|
1237
1287
|
__decorate([
|
|
1238
1288
|
property({ type: Boolean })
|
|
1239
1289
|
], Select.prototype, "searchable", void 0);
|