@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.
Files changed (79) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/85f2e730.js +356 -0
  3. package/dist/index.js +356 -1
  4. package/dist/static/icons/symbol-defs.svg +53 -20
  5. package/dist/sw.js +1 -1
  6. package/dist/sw.js.map +1 -1
  7. package/dist/templates/components-body.html +1 -1
  8. package/dist/templates/components-head.html +1 -1
  9. package/out-tsc/src/anchor/Anchor.js +25 -0
  10. package/out-tsc/src/anchor/Anchor.js.map +1 -0
  11. package/out-tsc/src/checkbox/Checkbox.js +29 -14
  12. package/out-tsc/src/checkbox/Checkbox.js.map +1 -1
  13. package/out-tsc/src/contacts/ContactDetails.js +9 -4
  14. package/out-tsc/src/contacts/ContactDetails.js.map +1 -1
  15. package/out-tsc/src/contacts/events.js +33 -7
  16. package/out-tsc/src/contacts/events.js.map +1 -1
  17. package/out-tsc/src/contactsearch/ContactSearch.js +146 -72
  18. package/out-tsc/src/contactsearch/ContactSearch.js.map +1 -1
  19. package/out-tsc/src/dialog/Dialog.js +11 -2
  20. package/out-tsc/src/dialog/Dialog.js.map +1 -1
  21. package/out-tsc/src/dialog/Modax.js +23 -4
  22. package/out-tsc/src/dialog/Modax.js.map +1 -1
  23. package/out-tsc/src/interfaces.js +1 -0
  24. package/out-tsc/src/interfaces.js.map +1 -1
  25. package/out-tsc/src/list/TembaMenu.js +139 -39
  26. package/out-tsc/src/list/TembaMenu.js.map +1 -1
  27. package/out-tsc/src/omnibox/Omnibox.js +7 -1
  28. package/out-tsc/src/omnibox/Omnibox.js.map +1 -1
  29. package/out-tsc/src/select/Select.js +7 -1
  30. package/out-tsc/src/select/Select.js.map +1 -1
  31. package/out-tsc/src/textinput/TextInput.js +42 -1
  32. package/out-tsc/src/textinput/TextInput.js.map +1 -1
  33. package/out-tsc/src/utils/index.js +13 -14
  34. package/out-tsc/src/utils/index.js.map +1 -1
  35. package/out-tsc/src/vectoricon/VectorIcon.js +2 -1
  36. package/out-tsc/src/vectoricon/VectorIcon.js.map +1 -1
  37. package/out-tsc/temba-modules.js +2 -0
  38. package/out-tsc/temba-modules.js.map +1 -1
  39. package/package.json +1 -1
  40. package/screenshots/truth/checkbox/checked.png +0 -0
  41. package/screenshots/truth/checkbox/default.png +0 -0
  42. package/screenshots/truth/contacts/history-expanded.png +0 -0
  43. package/screenshots/truth/list/menu-submenu.png +0 -0
  44. package/src/anchor/Anchor.ts +26 -0
  45. package/src/checkbox/Checkbox.ts +31 -16
  46. package/src/contacts/ContactDetails.ts +9 -4
  47. package/src/contacts/events.ts +33 -7
  48. package/src/contactsearch/ContactSearch.ts +157 -80
  49. package/src/dialog/Dialog.ts +12 -2
  50. package/src/dialog/Modax.ts +20 -4
  51. package/src/interfaces.ts +1 -0
  52. package/src/list/TembaMenu.ts +158 -42
  53. package/src/omnibox/Omnibox.ts +9 -1
  54. package/src/select/Select.ts +9 -1
  55. package/src/textinput/TextInput.ts +47 -1
  56. package/src/utils/index.ts +17 -16
  57. package/src/vectoricon/VectorIcon.ts +2 -1
  58. package/static/icons/Read Me.txt +1 -1
  59. package/static/icons/SVG/channel.svg +5 -0
  60. package/static/icons/SVG/cloud1.svg +5 -0
  61. package/static/icons/SVG/codepen.svg +5 -0
  62. package/static/icons/SVG/codesandbox.svg +5 -0
  63. package/static/icons/SVG/git-pull-request.svg +5 -0
  64. package/static/icons/SVG/grid.svg +5 -0
  65. package/static/icons/SVG/hard-drive.svg +5 -0
  66. package/static/icons/SVG/layout.svg +5 -0
  67. package/static/icons/SVG/list.svg +5 -0
  68. package/static/icons/SVG/map-pin.svg +5 -0
  69. package/static/icons/SVG/package.svg +5 -0
  70. package/static/icons/SVG/zapier.svg +5 -0
  71. package/static/icons/demo-external-svg.html +228 -173
  72. package/static/icons/demo-files/demo.css +4 -4
  73. package/static/icons/demo.html +281 -193
  74. package/static/icons/selection.json +625 -348
  75. package/static/icons/style.css +4 -4
  76. package/static/icons/symbol-defs.svg +53 -20
  77. package/temba-modules.ts +2 -0
  78. package/dist/b708bdad.js +0 -1
  79. package/static/icons/SVG/zendesk1.svg +0 -5
@@ -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
- padding-left: 0.5em;
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: 0.9rem;
224
+ font-size: 1rem;
215
225
  margin-bottom: 0.75em;
216
- border: 1px solid #f1f1f1;
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: 1px solid #f1f1f1;
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: #f1f1f1;
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.3em;
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.find(mi => mi.id == step);
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.find(
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 => (subItem.level = item.level + 1));
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.find(item => item.id === nextId);
551
+ const nextItem = findItem(items, nextId);
486
552
  if (nextItem) {
487
553
  this.handleItemClicked(null, nextItem);
488
554
  } else {
489
- this.fireCustomEvent(CustomEventType.NoPath, {
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
- this.handleItemClicked(null, items[0]);
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.find(item => item.id === nextId);
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.find(mi => mi.id == step);
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
- this.selection = focusedPath;
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
- return this.selection[menuItem.level] == menuItem.id;
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(id => menuItem.id === id);
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.id === 'divider') {
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 || []).find(item => item.id === id);
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 = true;
894
+ collapsed = false;
779
895
  }
780
896
  }
781
897
  } else {
@@ -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` <div style=${styleMap(style)}>${option.count}</div> `;
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
@@ -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="${this.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) {
@@ -39,29 +39,29 @@ export const getHTTPCookie = (name: string): string => {
39
39
  return null;
40
40
  };
41
41
 
42
- export const getHeaders = (pjax = false) => {
42
+ export const getHeaders = (headers: any = {}) => {
43
43
  const csrf = getHTTPCookie('csrftoken');
44
- const headers: any = csrf ? { 'X-CSRFToken': csrf } : {};
44
+ const fetchHeaders: any = csrf ? { 'X-CSRFToken': csrf } : {};
45
45
 
46
46
  // mark us as ajax
47
- headers['X-Requested-With'] = 'XMLHttpRequest';
47
+ fetchHeaders['X-Requested-With'] = 'XMLHttpRequest';
48
48
 
49
- if (pjax) {
50
- headers['X-PJAX'] = 'true';
51
- }
49
+ Object.keys(headers).forEach(key => {
50
+ fetchHeaders[key] = headers[key];
51
+ });
52
52
 
53
- return headers;
53
+ return fetchHeaders;
54
54
  };
55
55
 
56
56
  export const getUrl = (
57
57
  url: string,
58
58
  controller: AbortController = null,
59
- pjax = false
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(pjax),
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
- pjax = false,
186
+ headers: any = {},
187
187
  contentType = null
188
188
  ): Promise<WebResponse> => {
189
- const headers = getHeaders(pjax);
189
+ const fetchHeaders = getHeaders(headers);
190
+
190
191
  if (contentType) {
191
- headers['Content-Type'] = contentType;
192
+ fetchHeaders['Content-Type'] = contentType;
192
193
  }
193
- // headers['Content-Type'] = contentType;
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: Function, millis: number, immediate = false) => {
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: Function, millis: number) => {
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 = 4;
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']),