@nyaruka/temba-components 0.21.0 → 0.24.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/CHANGELOG.md +31 -0
- package/dist/85f2e730.js +356 -0
- package/dist/index.js +356 -1
- package/dist/static/icons/symbol-defs.svg +53 -20
- package/dist/sw.js +1 -1
- package/dist/sw.js.map +1 -1
- package/dist/templates/components-body.html +1 -1
- package/dist/templates/components-head.html +1 -1
- package/out-tsc/src/anchor/Anchor.js +25 -0
- package/out-tsc/src/anchor/Anchor.js.map +1 -0
- package/out-tsc/src/checkbox/Checkbox.js +29 -14
- package/out-tsc/src/checkbox/Checkbox.js.map +1 -1
- package/out-tsc/src/contacts/ContactDetails.js +9 -4
- package/out-tsc/src/contacts/ContactDetails.js.map +1 -1
- package/out-tsc/src/contacts/events.js +33 -7
- package/out-tsc/src/contacts/events.js.map +1 -1
- package/out-tsc/src/contactsearch/ContactSearch.js +146 -72
- package/out-tsc/src/contactsearch/ContactSearch.js.map +1 -1
- package/out-tsc/src/dialog/Dialog.js +11 -2
- package/out-tsc/src/dialog/Dialog.js.map +1 -1
- package/out-tsc/src/dialog/Modax.js +23 -4
- package/out-tsc/src/dialog/Modax.js.map +1 -1
- package/out-tsc/src/interfaces.js +1 -0
- package/out-tsc/src/interfaces.js.map +1 -1
- package/out-tsc/src/list/TembaMenu.js +139 -39
- package/out-tsc/src/list/TembaMenu.js.map +1 -1
- package/out-tsc/src/omnibox/Omnibox.js +7 -1
- package/out-tsc/src/omnibox/Omnibox.js.map +1 -1
- package/out-tsc/src/select/Select.js +7 -1
- package/out-tsc/src/select/Select.js.map +1 -1
- package/out-tsc/src/textinput/TextInput.js +42 -1
- package/out-tsc/src/textinput/TextInput.js.map +1 -1
- package/out-tsc/src/utils/index.js +13 -14
- package/out-tsc/src/utils/index.js.map +1 -1
- package/out-tsc/src/vectoricon/VectorIcon.js +2 -1
- package/out-tsc/src/vectoricon/VectorIcon.js.map +1 -1
- package/out-tsc/temba-modules.js +2 -0
- package/out-tsc/temba-modules.js.map +1 -1
- package/package.json +1 -1
- package/screenshots/truth/checkbox/checked.png +0 -0
- package/screenshots/truth/checkbox/default.png +0 -0
- package/screenshots/truth/contacts/history-expanded.png +0 -0
- package/screenshots/truth/list/menu-submenu.png +0 -0
- package/src/anchor/Anchor.ts +26 -0
- package/src/checkbox/Checkbox.ts +31 -16
- package/src/contacts/ContactDetails.ts +9 -4
- package/src/contacts/events.ts +33 -7
- package/src/contactsearch/ContactSearch.ts +157 -80
- package/src/dialog/Dialog.ts +12 -2
- package/src/dialog/Modax.ts +20 -4
- package/src/interfaces.ts +1 -0
- package/src/list/TembaMenu.ts +158 -42
- package/src/omnibox/Omnibox.ts +9 -1
- package/src/select/Select.ts +9 -1
- package/src/textinput/TextInput.ts +47 -1
- package/src/utils/index.ts +17 -16
- package/src/vectoricon/VectorIcon.ts +2 -1
- package/static/icons/Read Me.txt +1 -1
- package/static/icons/SVG/channel.svg +5 -0
- package/static/icons/SVG/cloud1.svg +5 -0
- package/static/icons/SVG/codepen.svg +5 -0
- package/static/icons/SVG/codesandbox.svg +5 -0
- package/static/icons/SVG/git-pull-request.svg +5 -0
- package/static/icons/SVG/grid.svg +5 -0
- package/static/icons/SVG/hard-drive.svg +5 -0
- package/static/icons/SVG/layout.svg +5 -0
- package/static/icons/SVG/list.svg +5 -0
- package/static/icons/SVG/map-pin.svg +5 -0
- package/static/icons/SVG/package.svg +5 -0
- package/static/icons/SVG/zapier.svg +5 -0
- package/static/icons/demo-external-svg.html +228 -173
- package/static/icons/demo-files/demo.css +4 -4
- package/static/icons/demo.html +281 -193
- package/static/icons/selection.json +625 -348
- package/static/icons/style.css +4 -4
- package/static/icons/symbol-defs.svg +53 -20
- package/temba-modules.ts +2 -0
- package/dist/b708bdad.js +0 -1
- package/static/icons/SVG/zendesk1.svg +0 -5
package/src/list/TembaMenu.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { fetchResults, getClasses } from '../utils';
|
|
|
5
5
|
|
|
6
6
|
export interface MenuItem {
|
|
7
7
|
id?: string;
|
|
8
|
+
vanity_id?: string;
|
|
8
9
|
name?: string;
|
|
9
10
|
count?: number;
|
|
10
11
|
icon?: string;
|
|
@@ -17,12 +18,18 @@ export interface MenuItem {
|
|
|
17
18
|
href?: string;
|
|
18
19
|
items?: MenuItem[];
|
|
19
20
|
inline?: boolean;
|
|
21
|
+
type?: string;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
interface MenuItemState {
|
|
23
25
|
collapsed?: string;
|
|
24
26
|
}
|
|
25
27
|
|
|
28
|
+
const findItem = (items: MenuItem[], id: string) =>
|
|
29
|
+
(items || []).find((item: MenuItem) => {
|
|
30
|
+
return item.id == id || item.vanity_id == id;
|
|
31
|
+
});
|
|
32
|
+
|
|
26
33
|
export class TembaMenu extends RapidElement {
|
|
27
34
|
static get styles() {
|
|
28
35
|
return css`
|
|
@@ -58,6 +65,7 @@ export class TembaMenu extends RapidElement {
|
|
|
58
65
|
-webkit-user-select: none;
|
|
59
66
|
display: flex;
|
|
60
67
|
font-size: 1.15em;
|
|
68
|
+
--icon-color: var(--color-text-dark);
|
|
61
69
|
}
|
|
62
70
|
|
|
63
71
|
.item.selected {
|
|
@@ -135,6 +143,9 @@ export class TembaMenu extends RapidElement {
|
|
|
135
143
|
margin-top: 0.1em;
|
|
136
144
|
border-radius: var(--curvature);
|
|
137
145
|
display: flex;
|
|
146
|
+
|
|
147
|
+
min-width: 12em;
|
|
148
|
+
max-width: 12em;
|
|
138
149
|
}
|
|
139
150
|
|
|
140
151
|
.item > temba-icon {
|
|
@@ -142,7 +153,7 @@ export class TembaMenu extends RapidElement {
|
|
|
142
153
|
}
|
|
143
154
|
|
|
144
155
|
.item.inline > temba-icon {
|
|
145
|
-
margin-right: 0em;
|
|
156
|
+
// margin-right: 0em;
|
|
146
157
|
}
|
|
147
158
|
|
|
148
159
|
.item > .details > .name {
|
|
@@ -150,12 +161,15 @@ export class TembaMenu extends RapidElement {
|
|
|
150
161
|
white-space: nowrap;
|
|
151
162
|
overflow: hidden;
|
|
152
163
|
text-overflow: ellipsis;
|
|
164
|
+
width: 0;
|
|
153
165
|
}
|
|
154
166
|
|
|
155
167
|
.level-0 > .item {
|
|
156
168
|
padding: 1em 1em;
|
|
157
169
|
margin-top: 0em;
|
|
158
170
|
border-radius: 0px;
|
|
171
|
+
min-width: inherit;
|
|
172
|
+
max-width: inherit;
|
|
159
173
|
}
|
|
160
174
|
|
|
161
175
|
.level-0 > .item > temba-icon {
|
|
@@ -203,32 +217,43 @@ export class TembaMenu extends RapidElement {
|
|
|
203
217
|
}
|
|
204
218
|
|
|
205
219
|
.inline-children {
|
|
206
|
-
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
.inline-children {
|
|
210
|
-
background: #ffffff;
|
|
220
|
+
// background: #ffffff;
|
|
211
221
|
padding: 0.5em;
|
|
212
222
|
border-bottom-right-radius: var(--curvature);
|
|
213
223
|
border-bottom-left-radius: var(--curvature);
|
|
214
|
-
font-size:
|
|
224
|
+
font-size: 1rem;
|
|
215
225
|
margin-bottom: 0.75em;
|
|
216
|
-
border: 1px solid #
|
|
226
|
+
border: 1px solid #f3f3f3;
|
|
227
|
+
// box-shadow: var(--shadow);
|
|
228
|
+
// margin-top: -1px;
|
|
229
|
+
z-index: 1000;
|
|
230
|
+
// margin-left: 1em;
|
|
231
|
+
border-top: none;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.inline-children .item {
|
|
235
|
+
max-width: 11em !important;
|
|
236
|
+
min-width: 11em !important;
|
|
237
|
+
// border: 1px solid #f1f1f1;
|
|
238
|
+
// margin-top: 0.75em;
|
|
239
|
+
// margin-right: -1em;
|
|
240
|
+
// padding-right: 0;
|
|
217
241
|
}
|
|
218
242
|
|
|
219
243
|
.item.inline {
|
|
220
|
-
border:
|
|
221
|
-
margin-top: 0.75em;
|
|
244
|
+
border: 0px solid transparent;
|
|
222
245
|
}
|
|
223
246
|
|
|
224
247
|
.item.inline.child-selected,
|
|
225
248
|
.item.inline.selected {
|
|
226
|
-
background: #
|
|
249
|
+
background: #f3f3f3;
|
|
250
|
+
border: 0px solid #f1f1f1;
|
|
227
251
|
border-bottom-right-radius: 0px !important;
|
|
228
252
|
border-bottom-left-radius: 0px !important;
|
|
229
253
|
z-index: 1000;
|
|
230
254
|
color: #444;
|
|
231
255
|
--icon-color: #444;
|
|
256
|
+
// box-shadow: var(--shadow);
|
|
232
257
|
}
|
|
233
258
|
|
|
234
259
|
.level-1,
|
|
@@ -288,6 +313,10 @@ export class TembaMenu extends RapidElement {
|
|
|
288
313
|
.item temba-icon {
|
|
289
314
|
}
|
|
290
315
|
|
|
316
|
+
.collapsed .item {
|
|
317
|
+
margin-bottom: 0.5em;
|
|
318
|
+
}
|
|
319
|
+
|
|
291
320
|
.collapsed .item .details {
|
|
292
321
|
overflow: hidden;
|
|
293
322
|
max-height: 0em;
|
|
@@ -303,18 +332,19 @@ export class TembaMenu extends RapidElement {
|
|
|
303
332
|
}
|
|
304
333
|
|
|
305
334
|
.section {
|
|
306
|
-
transition: opacity var(--transition-speed) linear !important;
|
|
307
335
|
max-width: 12em;
|
|
308
336
|
}
|
|
309
337
|
|
|
310
338
|
.collapsed .section {
|
|
311
339
|
opacity: 0;
|
|
312
340
|
max-width: 0em;
|
|
313
|
-
max-height: 0.
|
|
341
|
+
max-height: 0.6em;
|
|
314
342
|
}
|
|
315
343
|
|
|
316
344
|
.collapsed.level-1 {
|
|
317
345
|
overflow: hidden;
|
|
346
|
+
padding: 0.5em;
|
|
347
|
+
--icon-color: #999;
|
|
318
348
|
}
|
|
319
349
|
|
|
320
350
|
.collapsed .item .right {
|
|
@@ -334,6 +364,7 @@ export class TembaMenu extends RapidElement {
|
|
|
334
364
|
max-height: 0em;
|
|
335
365
|
padding: 0em;
|
|
336
366
|
min-height: 0em;
|
|
367
|
+
margin-bottom: 0em;
|
|
337
368
|
}
|
|
338
369
|
|
|
339
370
|
.divider {
|
|
@@ -349,6 +380,13 @@ export class TembaMenu extends RapidElement {
|
|
|
349
380
|
padding: 0;
|
|
350
381
|
min-height: 0px;
|
|
351
382
|
}
|
|
383
|
+
|
|
384
|
+
.sub-section {
|
|
385
|
+
font-size: 1.1rem;
|
|
386
|
+
color: #888;
|
|
387
|
+
margin-top: 1rem;
|
|
388
|
+
margin-left: 0.3rem;
|
|
389
|
+
}
|
|
352
390
|
`;
|
|
353
391
|
}
|
|
354
392
|
|
|
@@ -423,7 +461,7 @@ export class TembaMenu extends RapidElement {
|
|
|
423
461
|
while (path.length > 0) {
|
|
424
462
|
const step = path.splice(0, 1)[0];
|
|
425
463
|
if (items) {
|
|
426
|
-
item = items
|
|
464
|
+
item = findItem(items, step);
|
|
427
465
|
if (item) {
|
|
428
466
|
if (item.endpoint) {
|
|
429
467
|
item.loading = true;
|
|
@@ -432,9 +470,7 @@ export class TembaMenu extends RapidElement {
|
|
|
432
470
|
// for now we only deal with updating counts and names
|
|
433
471
|
(itemToUpdate.items || []).forEach(
|
|
434
472
|
(existing: MenuItem, index: number, items: []) => {
|
|
435
|
-
const updatedItem = updated.
|
|
436
|
-
updatedItem => updatedItem.id === existing.id
|
|
437
|
-
);
|
|
473
|
+
const updatedItem = findItem(updated, existing.id);
|
|
438
474
|
|
|
439
475
|
// we were removed!
|
|
440
476
|
if (!updatedItem) {
|
|
@@ -467,40 +503,72 @@ export class TembaMenu extends RapidElement {
|
|
|
467
503
|
}
|
|
468
504
|
}
|
|
469
505
|
|
|
506
|
+
private fireNoPath(missingId: string) {
|
|
507
|
+
const item = this.getMenuItem();
|
|
508
|
+
|
|
509
|
+
const details = {
|
|
510
|
+
item: item.id,
|
|
511
|
+
selection: '/' + this.selection.join('/'),
|
|
512
|
+
endpoint: item.endpoint,
|
|
513
|
+
path: missingId + '/' + this.pending.join('/') + document.location.search,
|
|
514
|
+
};
|
|
515
|
+
|
|
516
|
+
// remove any excess from our selection
|
|
517
|
+
const selection = this.selection.join('/');
|
|
518
|
+
selection.replace(details.path, '');
|
|
519
|
+
this.selection = selection.split('/');
|
|
520
|
+
|
|
521
|
+
this.fireCustomEvent(CustomEventType.NoPath, details);
|
|
522
|
+
this.pending = [];
|
|
523
|
+
this.requestUpdate('root');
|
|
524
|
+
}
|
|
525
|
+
|
|
470
526
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
471
|
-
private loadItems(item: MenuItem) {
|
|
527
|
+
private loadItems(item: MenuItem, selectFirst = true) {
|
|
472
528
|
if (item && item.endpoint) {
|
|
473
529
|
item.loading = true;
|
|
474
530
|
this.httpComplete = fetchResults(item.endpoint).then(
|
|
475
531
|
(items: MenuItem[]) => {
|
|
476
532
|
// update our item level
|
|
477
|
-
items.forEach(subItem =>
|
|
533
|
+
items.forEach(subItem => {
|
|
534
|
+
subItem.level = item.level + 1;
|
|
535
|
+
// if we came with preset items, set the level for them accordingly
|
|
536
|
+
if (subItem.items) {
|
|
537
|
+
subItem.items.forEach(
|
|
538
|
+
inlineItem => (inlineItem.level = item.level + 2)
|
|
539
|
+
);
|
|
540
|
+
}
|
|
541
|
+
});
|
|
542
|
+
|
|
478
543
|
item.items = items;
|
|
479
544
|
item.loading = false;
|
|
480
545
|
this.requestUpdate('root');
|
|
546
|
+
this.scrollSelectedIntoView();
|
|
481
547
|
if (this.pending && this.pending.length > 0) {
|
|
482
548
|
// auto select the next pending click
|
|
483
549
|
const nextId = this.pending.splice(0, 1)[0];
|
|
484
550
|
if (nextId && items.length > 0) {
|
|
485
|
-
const nextItem = items
|
|
551
|
+
const nextItem = findItem(items, nextId);
|
|
486
552
|
if (nextItem) {
|
|
487
553
|
this.handleItemClicked(null, nextItem);
|
|
488
554
|
} else {
|
|
489
|
-
this.
|
|
490
|
-
item: item.id,
|
|
491
|
-
endpoint: item.endpoint,
|
|
492
|
-
path: nextId + '/' + this.pending.join('/'),
|
|
493
|
-
});
|
|
555
|
+
this.fireNoPath(nextId);
|
|
494
556
|
}
|
|
495
557
|
}
|
|
496
558
|
} else {
|
|
497
559
|
// auto select the first item
|
|
498
560
|
if (
|
|
561
|
+
selectFirst &&
|
|
499
562
|
items.length > 0 &&
|
|
500
563
|
this.selection.length >= 1 &&
|
|
501
564
|
!item.inline
|
|
502
565
|
) {
|
|
503
|
-
|
|
566
|
+
for (const item of items) {
|
|
567
|
+
if (!item.type) {
|
|
568
|
+
this.handleItemClicked(null, item);
|
|
569
|
+
break;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
504
572
|
}
|
|
505
573
|
}
|
|
506
574
|
}
|
|
@@ -527,17 +595,17 @@ export class TembaMenu extends RapidElement {
|
|
|
527
595
|
|
|
528
596
|
// update our selection
|
|
529
597
|
if (menuItem.level >= this.selection.length) {
|
|
530
|
-
this.selection.push(menuItem.id);
|
|
598
|
+
this.selection.push(menuItem.vanity_id || menuItem.id);
|
|
531
599
|
} else {
|
|
532
600
|
this.selection.splice(
|
|
533
601
|
menuItem.level,
|
|
534
602
|
this.selection.length - menuItem.level,
|
|
535
|
-
menuItem.id
|
|
603
|
+
menuItem.vanity_id || menuItem.id
|
|
536
604
|
);
|
|
537
605
|
}
|
|
538
606
|
|
|
539
607
|
if (menuItem.endpoint) {
|
|
540
|
-
this.loadItems(menuItem);
|
|
608
|
+
this.loadItems(menuItem, !menuItem.href);
|
|
541
609
|
this.dispatchEvent(new Event('change'));
|
|
542
610
|
} else {
|
|
543
611
|
this.dispatchEvent(new Event('change'));
|
|
@@ -547,19 +615,29 @@ export class TembaMenu extends RapidElement {
|
|
|
547
615
|
const nextId = this.pending.splice(0, 1)[0];
|
|
548
616
|
const item = this.getMenuItem();
|
|
549
617
|
if (nextId && item && item.items && item.items.length > 0) {
|
|
550
|
-
const nextItem = item.items
|
|
618
|
+
const nextItem = findItem(item.items, nextId);
|
|
551
619
|
if (nextItem) {
|
|
552
620
|
this.handleItemClicked(null, nextItem);
|
|
553
621
|
}
|
|
622
|
+
} else {
|
|
623
|
+
this.fireNoPath(nextId);
|
|
554
624
|
}
|
|
555
625
|
}
|
|
556
|
-
|
|
557
|
-
this.pending = [];
|
|
558
626
|
this.requestUpdate('root');
|
|
559
627
|
}
|
|
560
628
|
}
|
|
561
629
|
}
|
|
562
630
|
|
|
631
|
+
public scrollSelectedIntoView() {
|
|
632
|
+
// makes sure we are scrolled into view
|
|
633
|
+
window.setTimeout(() => {
|
|
634
|
+
const eles = this.shadowRoot.querySelectorAll('.selected');
|
|
635
|
+
eles.forEach(ele => {
|
|
636
|
+
ele.scrollIntoView({ block: 'end', behavior: 'smooth' });
|
|
637
|
+
});
|
|
638
|
+
}, 0);
|
|
639
|
+
}
|
|
640
|
+
|
|
563
641
|
public clickItem(id: string): boolean {
|
|
564
642
|
const path = [...this.selection];
|
|
565
643
|
path.splice(path.length - 1, 1, id);
|
|
@@ -567,12 +645,13 @@ export class TembaMenu extends RapidElement {
|
|
|
567
645
|
|
|
568
646
|
if (item) {
|
|
569
647
|
this.handleItemClicked(null, item);
|
|
648
|
+
this.scrollSelectedIntoView();
|
|
570
649
|
return true;
|
|
571
650
|
}
|
|
572
651
|
return false;
|
|
573
652
|
}
|
|
574
653
|
|
|
575
|
-
public getMenuItem() {
|
|
654
|
+
public getMenuItem(): MenuItem {
|
|
576
655
|
return this.getMenuItemForSelection([...this.selection]);
|
|
577
656
|
}
|
|
578
657
|
|
|
@@ -583,7 +662,7 @@ export class TembaMenu extends RapidElement {
|
|
|
583
662
|
while (path.length > 0) {
|
|
584
663
|
const step = path.splice(0, 1)[0];
|
|
585
664
|
if (items) {
|
|
586
|
-
item = items
|
|
665
|
+
item = findItem(items, step);
|
|
587
666
|
if (item) {
|
|
588
667
|
items = item.items;
|
|
589
668
|
} else {
|
|
@@ -623,29 +702,65 @@ export class TembaMenu extends RapidElement {
|
|
|
623
702
|
}
|
|
624
703
|
}
|
|
625
704
|
|
|
626
|
-
public setFocusedItem(path: string) {
|
|
705
|
+
public async setFocusedItem(path: string) {
|
|
627
706
|
const focusedPath = path.split('/').filter(step => !!step);
|
|
628
|
-
|
|
707
|
+
|
|
708
|
+
// if we don't match at the first level, we are a noop
|
|
709
|
+
if (focusedPath.length > 0) {
|
|
710
|
+
const rootItem = findItem(this.root.items, focusedPath[0]);
|
|
711
|
+
if (!rootItem) {
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
const newPath = [];
|
|
717
|
+
let level = this.root;
|
|
718
|
+
while (focusedPath.length > 0) {
|
|
719
|
+
const nextId = focusedPath.shift();
|
|
720
|
+
if (nextId) {
|
|
721
|
+
if (!level.items) {
|
|
722
|
+
this.loadItems(level, false);
|
|
723
|
+
await this.httpComplete;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
level = findItem(level.items, nextId);
|
|
727
|
+
if (!level) {
|
|
728
|
+
focusedPath.splice(0, focusedPath.length);
|
|
729
|
+
} else {
|
|
730
|
+
newPath.push(nextId);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
this.selection = newPath;
|
|
629
736
|
this.requestUpdate('root');
|
|
630
737
|
}
|
|
631
738
|
|
|
632
739
|
private isSelected(menuItem: MenuItem) {
|
|
633
740
|
if (menuItem.level < this.selection.length) {
|
|
634
|
-
|
|
741
|
+
const selected =
|
|
742
|
+
this.selection[menuItem.level] == (menuItem.vanity_id || menuItem.id);
|
|
743
|
+
return selected;
|
|
635
744
|
}
|
|
636
745
|
return false;
|
|
637
746
|
}
|
|
638
747
|
|
|
639
748
|
private isExpanded(menuItem: MenuItem) {
|
|
640
|
-
const expanded = !!this.selection.find(
|
|
749
|
+
const expanded = !!this.selection.find(
|
|
750
|
+
id => id === menuItem.vanity_id || menuItem.id
|
|
751
|
+
);
|
|
641
752
|
return expanded;
|
|
642
753
|
}
|
|
643
754
|
|
|
644
755
|
private renderMenuItem = (menuItem: MenuItem): TemplateResult => {
|
|
645
|
-
if (menuItem.
|
|
756
|
+
if (menuItem.type === 'divider') {
|
|
646
757
|
return html`<div class="divider"></div>`;
|
|
647
758
|
}
|
|
648
759
|
|
|
760
|
+
if (menuItem.type === 'section') {
|
|
761
|
+
return html`<div class="sub-section">${menuItem.name}</div>`;
|
|
762
|
+
}
|
|
763
|
+
|
|
649
764
|
const isSelected = this.isSelected(menuItem);
|
|
650
765
|
const isChildSelected =
|
|
651
766
|
isSelected && this.selection.length > menuItem.level + 1;
|
|
@@ -699,7 +814,7 @@ export class TembaMenu extends RapidElement {
|
|
|
699
814
|
<div class="details" style="flex-grow:1;display:flex">
|
|
700
815
|
<div
|
|
701
816
|
class="name"
|
|
702
|
-
style="flex-grow:1; flex-shrink:0 white-space: ${this.wraps
|
|
817
|
+
style="flex-grow:1; flex-shrink:0; white-space: ${this.wraps
|
|
703
818
|
? 'normal'
|
|
704
819
|
: 'nowrap'};"
|
|
705
820
|
>
|
|
@@ -763,7 +878,8 @@ export class TembaMenu extends RapidElement {
|
|
|
763
878
|
);
|
|
764
879
|
|
|
765
880
|
this.selection.forEach((id, index) => {
|
|
766
|
-
const selected = (items
|
|
881
|
+
const selected = findItem(items, id);
|
|
882
|
+
|
|
767
883
|
let collapsed = false;
|
|
768
884
|
if (selected) {
|
|
769
885
|
items = selected.items;
|
|
@@ -775,7 +891,7 @@ export class TembaMenu extends RapidElement {
|
|
|
775
891
|
// otherwise pick a default collapse state
|
|
776
892
|
else {
|
|
777
893
|
if (this.selection.length > selected.level + 2) {
|
|
778
|
-
collapsed =
|
|
894
|
+
collapsed = false;
|
|
779
895
|
}
|
|
780
896
|
}
|
|
781
897
|
} else {
|
package/src/omnibox/Omnibox.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { TemplateResult, html, css, property } from 'lit-element';
|
|
2
2
|
import { styleMap } from 'lit-html/directives/style-map';
|
|
3
3
|
import { RapidElement } from '../RapidElement';
|
|
4
|
+
import { Select } from '../select/Select';
|
|
4
5
|
|
|
5
6
|
enum OmniType {
|
|
6
7
|
Group = 'group',
|
|
@@ -104,7 +105,9 @@ export class Omnibox extends RapidElement {
|
|
|
104
105
|
}
|
|
105
106
|
|
|
106
107
|
if (option.type === OmniType.Group) {
|
|
107
|
-
return html`
|
|
108
|
+
return html`
|
|
109
|
+
<div style=${styleMap(style)}>${option.count.toLocaleString()}</div>
|
|
110
|
+
`;
|
|
108
111
|
}
|
|
109
112
|
|
|
110
113
|
return null;
|
|
@@ -172,6 +175,11 @@ export class Omnibox extends RapidElement {
|
|
|
172
175
|
}
|
|
173
176
|
}
|
|
174
177
|
|
|
178
|
+
public getValues(): any[] {
|
|
179
|
+
const select = this.shadowRoot.querySelector('temba-select') as Select;
|
|
180
|
+
return select.values;
|
|
181
|
+
}
|
|
182
|
+
|
|
175
183
|
public render(): TemplateResult {
|
|
176
184
|
return html`
|
|
177
185
|
<temba-select
|
package/src/select/Select.ts
CHANGED
|
@@ -455,6 +455,8 @@ export class Select extends FormElement {
|
|
|
455
455
|
private next: string = null;
|
|
456
456
|
private query: string;
|
|
457
457
|
|
|
458
|
+
private removingSelection: boolean;
|
|
459
|
+
|
|
458
460
|
private lruCache = flru(20);
|
|
459
461
|
|
|
460
462
|
// http promise to monitor for completeness
|
|
@@ -854,7 +856,7 @@ export class Select extends FormElement {
|
|
|
854
856
|
private handleFocus(): void {
|
|
855
857
|
if (!this.focused && this.visibleOptions.length === 0) {
|
|
856
858
|
this.focused = true;
|
|
857
|
-
if (this.searchOnFocus) {
|
|
859
|
+
if (this.searchOnFocus && !this.removingSelection) {
|
|
858
860
|
this.requestUpdate('input');
|
|
859
861
|
}
|
|
860
862
|
}
|
|
@@ -1192,6 +1194,12 @@ export class Select extends FormElement {
|
|
|
1192
1194
|
<div
|
|
1193
1195
|
class="remove-item"
|
|
1194
1196
|
style="margin-top:1px"
|
|
1197
|
+
@mousedown=${() => {
|
|
1198
|
+
this.removingSelection = true;
|
|
1199
|
+
}}
|
|
1200
|
+
@mouseup=${() => {
|
|
1201
|
+
this.removingSelection = false;
|
|
1202
|
+
}}
|
|
1195
1203
|
@click=${(evt: MouseEvent) => {
|
|
1196
1204
|
evt.preventDefault();
|
|
1197
1205
|
evt.stopPropagation();
|
|
@@ -96,6 +96,33 @@ export class TextInput extends FormElement {
|
|
|
96
96
|
color: var(--color-placeholder);
|
|
97
97
|
font-weight: 300;
|
|
98
98
|
}
|
|
99
|
+
|
|
100
|
+
.grow-wrap {
|
|
101
|
+
display: flex;
|
|
102
|
+
align-items: stretch;
|
|
103
|
+
width: 100%;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.grow-wrap > div {
|
|
107
|
+
border: 0px solid green;
|
|
108
|
+
width: 100%;
|
|
109
|
+
padding: var(--temba-textinput-padding);
|
|
110
|
+
flex: 1;
|
|
111
|
+
margin: 0;
|
|
112
|
+
background: none;
|
|
113
|
+
color: var(--color-widget-text);
|
|
114
|
+
font-family: var(--font-family);
|
|
115
|
+
font-size: var(--temba-textinput-font-size);
|
|
116
|
+
line-height: normal;
|
|
117
|
+
cursor: text;
|
|
118
|
+
resize: none;
|
|
119
|
+
font-weight: 300;
|
|
120
|
+
width: 100%;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.grow-wrap textarea {
|
|
124
|
+
margin-left: -100%;
|
|
125
|
+
}
|
|
99
126
|
`;
|
|
100
127
|
}
|
|
101
128
|
|
|
@@ -151,6 +178,9 @@ export class TextInput extends FormElement {
|
|
|
151
178
|
@property({ type: Boolean })
|
|
152
179
|
disabled = false;
|
|
153
180
|
|
|
181
|
+
@property({ type: Boolean })
|
|
182
|
+
autogrow = false;
|
|
183
|
+
|
|
154
184
|
counterElement: CharCount = null;
|
|
155
185
|
cursorStart = -1;
|
|
156
186
|
cursorEnd = -1;
|
|
@@ -189,6 +219,13 @@ export class TextInput extends FormElement {
|
|
|
189
219
|
this.setValues([this.value]);
|
|
190
220
|
this.fireEvent('change');
|
|
191
221
|
|
|
222
|
+
if (this.textarea && this.autogrow) {
|
|
223
|
+
const autogrow = this.shadowRoot.querySelector(
|
|
224
|
+
'.grow-wrap > div'
|
|
225
|
+
) as HTMLDivElement;
|
|
226
|
+
autogrow.innerText = this.value + String.fromCharCode(10);
|
|
227
|
+
}
|
|
228
|
+
|
|
192
229
|
if (this.cursorStart > -1 && this.cursorEnd > -1) {
|
|
193
230
|
this.inputElement.setSelectionRange(this.cursorStart, this.cursorEnd);
|
|
194
231
|
this.cursorStart = -1;
|
|
@@ -288,6 +325,7 @@ export class TextInput extends FormElement {
|
|
|
288
325
|
if (this.disabled) {
|
|
289
326
|
return;
|
|
290
327
|
}
|
|
328
|
+
|
|
291
329
|
this.updateValue(update.target.value);
|
|
292
330
|
this.setValues([this.value]);
|
|
293
331
|
this.fireEvent('input');
|
|
@@ -416,10 +454,11 @@ export class TextInput extends FormElement {
|
|
|
416
454
|
}
|
|
417
455
|
}}
|
|
418
456
|
placeholder=${this.placeholder}
|
|
419
|
-
value
|
|
457
|
+
.value=${this.value}
|
|
420
458
|
.disabled=${this.disabled}
|
|
421
459
|
/>
|
|
422
460
|
`;
|
|
461
|
+
|
|
423
462
|
if (this.textarea) {
|
|
424
463
|
input = html`
|
|
425
464
|
<textarea
|
|
@@ -433,6 +472,13 @@ export class TextInput extends FormElement {
|
|
|
433
472
|
.disabled=${this.disabled}
|
|
434
473
|
></textarea>
|
|
435
474
|
`;
|
|
475
|
+
|
|
476
|
+
if (this.autogrow) {
|
|
477
|
+
input = html` <div class="grow-wrap">
|
|
478
|
+
<div></div>
|
|
479
|
+
${input}
|
|
480
|
+
</div>`;
|
|
481
|
+
}
|
|
436
482
|
}
|
|
437
483
|
|
|
438
484
|
if (this.datepicker || this.datetimepicker) {
|
package/src/utils/index.ts
CHANGED
|
@@ -39,29 +39,29 @@ export const getHTTPCookie = (name: string): string => {
|
|
|
39
39
|
return null;
|
|
40
40
|
};
|
|
41
41
|
|
|
42
|
-
export const getHeaders = (
|
|
42
|
+
export const getHeaders = (headers: any = {}) => {
|
|
43
43
|
const csrf = getHTTPCookie('csrftoken');
|
|
44
|
-
const
|
|
44
|
+
const fetchHeaders: any = csrf ? { 'X-CSRFToken': csrf } : {};
|
|
45
45
|
|
|
46
46
|
// mark us as ajax
|
|
47
|
-
|
|
47
|
+
fetchHeaders['X-Requested-With'] = 'XMLHttpRequest';
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
49
|
+
Object.keys(headers).forEach(key => {
|
|
50
|
+
fetchHeaders[key] = headers[key];
|
|
51
|
+
});
|
|
52
52
|
|
|
53
|
-
return
|
|
53
|
+
return fetchHeaders;
|
|
54
54
|
};
|
|
55
55
|
|
|
56
56
|
export const getUrl = (
|
|
57
57
|
url: string,
|
|
58
58
|
controller: AbortController = null,
|
|
59
|
-
|
|
59
|
+
headers: { [key: string]: string } = {}
|
|
60
60
|
): Promise<WebResponse> => {
|
|
61
61
|
return new Promise<WebResponse>((resolve, reject) => {
|
|
62
62
|
const options = {
|
|
63
63
|
method: 'GET',
|
|
64
|
-
headers: getHeaders(
|
|
64
|
+
headers: getHeaders(headers),
|
|
65
65
|
};
|
|
66
66
|
|
|
67
67
|
if (controller) {
|
|
@@ -183,17 +183,18 @@ export interface WebResponse {
|
|
|
183
183
|
export const postUrl = (
|
|
184
184
|
url: string,
|
|
185
185
|
payload: any,
|
|
186
|
-
|
|
186
|
+
headers: any = {},
|
|
187
187
|
contentType = null
|
|
188
188
|
): Promise<WebResponse> => {
|
|
189
|
-
const
|
|
189
|
+
const fetchHeaders = getHeaders(headers);
|
|
190
|
+
|
|
190
191
|
if (contentType) {
|
|
191
|
-
|
|
192
|
+
fetchHeaders['Content-Type'] = contentType;
|
|
192
193
|
}
|
|
193
|
-
|
|
194
|
+
|
|
194
195
|
const options = {
|
|
195
196
|
method: 'POST',
|
|
196
|
-
headers,
|
|
197
|
+
headers: fetchHeaders,
|
|
197
198
|
body: payload,
|
|
198
199
|
};
|
|
199
200
|
|
|
@@ -474,7 +475,7 @@ export const isDate = (value: string): boolean => {
|
|
|
474
475
|
return DATE_FORMAT.test(value);
|
|
475
476
|
};
|
|
476
477
|
|
|
477
|
-
export const debounce = (fn:
|
|
478
|
+
export const debounce = (fn: any, millis: number, immediate = false) => {
|
|
478
479
|
let timeout: any;
|
|
479
480
|
return function (...args: any) {
|
|
480
481
|
const context = this;
|
|
@@ -493,7 +494,7 @@ export const debounce = (fn: Function, millis: number, immediate = false) => {
|
|
|
493
494
|
};
|
|
494
495
|
};
|
|
495
496
|
|
|
496
|
-
export const throttle = (fn:
|
|
497
|
+
export const throttle = (fn: any, millis: number) => {
|
|
497
498
|
let ready = true;
|
|
498
499
|
return function (...args: any) {
|
|
499
500
|
const context = this;
|
|
@@ -3,7 +3,7 @@ import { property, LitElement, TemplateResult, html, css } from 'lit-element';
|
|
|
3
3
|
import { getClasses } from '../utils';
|
|
4
4
|
|
|
5
5
|
// for cache busting, increase whenever the icon set changes
|
|
6
|
-
const ICON_VERSION =
|
|
6
|
+
const ICON_VERSION = 5;
|
|
7
7
|
|
|
8
8
|
export class VectorIcon extends LitElement {
|
|
9
9
|
@property({ type: String })
|
|
@@ -41,6 +41,7 @@ export class VectorIcon extends LitElement {
|
|
|
41
41
|
return css`
|
|
42
42
|
:host {
|
|
43
43
|
margin: auto;
|
|
44
|
+
--color1: var(--icon-color);
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
:host([id='flow']),
|