@watermarkinsights/ripple 3.12.0 → 3.13.0-9

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 (176) hide show
  1. package/dist/cjs/{chartFunctions-44ae2eee.js → chartFunctions-34fdd3ce.js} +1 -1
  2. package/dist/cjs/{functions-1a67b971.js → functions-120449cf.js} +245 -32
  3. package/dist/cjs/{global-122fc638.js → global-1d1d0ab3.js} +7 -5
  4. package/dist/cjs/loader.cjs.js +2 -2
  5. package/dist/cjs/priv-chart-popover.cjs.entry.js +1 -1
  6. package/dist/cjs/priv-datepicker.cjs.entry.js +1 -1
  7. package/dist/cjs/ripple.cjs.js +2 -2
  8. package/dist/cjs/wm-action-menu_2.cjs.entry.js +1 -1
  9. package/dist/cjs/wm-button.cjs.entry.js +50 -38
  10. package/dist/cjs/wm-chart.cjs.entry.js +2 -2
  11. package/dist/cjs/wm-datepicker.cjs.entry.js +1 -1
  12. package/dist/cjs/wm-input.cjs.entry.js +1 -1
  13. package/dist/cjs/wm-modal-footer.cjs.entry.js +1 -1
  14. package/dist/cjs/wm-modal-header.cjs.entry.js +1 -1
  15. package/dist/cjs/wm-modal.cjs.entry.js +1 -1
  16. package/dist/cjs/wm-navigation_3.cjs.entry.js +1 -1
  17. package/dist/cjs/wm-navigator.cjs.entry.js +1 -1
  18. package/dist/cjs/wm-network-uploader.cjs.entry.js +6 -4
  19. package/dist/cjs/wm-option_2.cjs.entry.js +345 -122
  20. package/dist/cjs/wm-pagination.cjs.entry.js +1 -1
  21. package/dist/cjs/wm-progress-indicator_3.cjs.entry.js +2 -2
  22. package/dist/cjs/wm-search.cjs.entry.js +1 -1
  23. package/dist/cjs/wm-snackbar.cjs.entry.js +1 -1
  24. package/dist/cjs/wm-tab-item_3.cjs.entry.js +1 -1
  25. package/dist/cjs/wm-tag-input.cjs.entry.js +1 -1
  26. package/dist/cjs/wm-timepicker.cjs.entry.js +1 -1
  27. package/dist/cjs/wm-toggletip.cjs.entry.js +4 -4
  28. package/dist/cjs/wm-uploader.cjs.entry.js +9 -11
  29. package/dist/collection/components/wm-button/wm-button.css +1 -0
  30. package/dist/collection/components/wm-button/wm-button.js +50 -40
  31. package/dist/collection/components/wm-modal/wm-modal-footer.js +1 -1
  32. package/dist/collection/components/wm-option/wm-option.css +12 -0
  33. package/dist/collection/components/wm-option/wm-option.js +34 -29
  34. package/dist/collection/components/wm-select/wm-select.css +76 -23
  35. package/dist/collection/components/wm-select/wm-select.js +385 -125
  36. package/dist/collection/components/wm-toggletip/wm-toggletip.js +5 -5
  37. package/dist/collection/components/wm-uploader/wm-network-uploader/wm-network-uploader.css +0 -3
  38. package/dist/collection/components/wm-uploader/wm-network-uploader/wm-network-uploader.js +4 -2
  39. package/dist/collection/components/wm-uploader/wm-uploader.css +1 -5
  40. package/dist/collection/components/wm-uploader/wm-uploader.js +7 -9
  41. package/dist/collection/global/__mocks__/functions.js +9 -0
  42. package/dist/collection/global/functions.js +1 -28
  43. package/dist/collection/global/global.js +6 -4
  44. package/dist/esm/{chartFunctions-8fa800a6.js → chartFunctions-20f05eb5.js} +1 -1
  45. package/dist/esm/{functions-61c7bb1f.js → functions-036af8dc.js} +245 -32
  46. package/dist/esm/{global-5902ef31.js → global-590c515d.js} +7 -5
  47. package/dist/esm/loader.js +2 -2
  48. package/dist/esm/priv-chart-popover.entry.js +1 -1
  49. package/dist/esm/priv-datepicker.entry.js +1 -1
  50. package/dist/esm/ripple.js +2 -2
  51. package/dist/esm/wm-action-menu_2.entry.js +1 -1
  52. package/dist/esm/wm-button.entry.js +51 -39
  53. package/dist/esm/wm-chart.entry.js +2 -2
  54. package/dist/esm/wm-datepicker.entry.js +1 -1
  55. package/dist/esm/wm-input.entry.js +1 -1
  56. package/dist/esm/wm-modal-footer.entry.js +1 -1
  57. package/dist/esm/wm-modal-header.entry.js +1 -1
  58. package/dist/esm/wm-modal.entry.js +1 -1
  59. package/dist/esm/wm-navigation_3.entry.js +1 -1
  60. package/dist/esm/wm-navigator.entry.js +1 -1
  61. package/dist/esm/wm-network-uploader.entry.js +6 -4
  62. package/dist/esm/wm-option_2.entry.js +345 -122
  63. package/dist/esm/wm-pagination.entry.js +1 -1
  64. package/dist/esm/wm-progress-indicator_3.entry.js +2 -2
  65. package/dist/esm/wm-search.entry.js +1 -1
  66. package/dist/esm/wm-snackbar.entry.js +1 -1
  67. package/dist/esm/wm-tab-item_3.entry.js +1 -1
  68. package/dist/esm/wm-tag-input.entry.js +1 -1
  69. package/dist/esm/wm-timepicker.entry.js +1 -1
  70. package/dist/esm/wm-toggletip.entry.js +4 -4
  71. package/dist/esm/wm-uploader.entry.js +9 -11
  72. package/dist/esm-es5/{chartFunctions-8fa800a6.js → chartFunctions-20f05eb5.js} +1 -1
  73. package/dist/esm-es5/{functions-61c7bb1f.js → functions-036af8dc.js} +2 -2
  74. package/dist/esm-es5/global-590c515d.js +1 -0
  75. package/dist/esm-es5/loader.js +1 -1
  76. package/dist/esm-es5/priv-chart-popover.entry.js +1 -1
  77. package/dist/esm-es5/priv-datepicker.entry.js +1 -1
  78. package/dist/esm-es5/ripple.js +1 -1
  79. package/dist/esm-es5/wm-action-menu_2.entry.js +1 -1
  80. package/dist/esm-es5/wm-button.entry.js +1 -1
  81. package/dist/esm-es5/wm-chart.entry.js +1 -1
  82. package/dist/esm-es5/wm-datepicker.entry.js +1 -1
  83. package/dist/esm-es5/wm-input.entry.js +1 -1
  84. package/dist/esm-es5/wm-modal-footer.entry.js +1 -1
  85. package/dist/esm-es5/wm-modal-header.entry.js +1 -1
  86. package/dist/esm-es5/wm-modal.entry.js +1 -1
  87. package/dist/esm-es5/wm-navigation_3.entry.js +1 -1
  88. package/dist/esm-es5/wm-navigator.entry.js +1 -1
  89. package/dist/esm-es5/wm-network-uploader.entry.js +1 -1
  90. package/dist/esm-es5/wm-option_2.entry.js +1 -1
  91. package/dist/esm-es5/wm-pagination.entry.js +1 -1
  92. package/dist/esm-es5/wm-progress-indicator_3.entry.js +1 -1
  93. package/dist/esm-es5/wm-search.entry.js +1 -1
  94. package/dist/esm-es5/wm-snackbar.entry.js +1 -1
  95. package/dist/esm-es5/wm-tab-item_3.entry.js +1 -1
  96. package/dist/esm-es5/wm-tag-input.entry.js +1 -1
  97. package/dist/esm-es5/wm-timepicker.entry.js +1 -1
  98. package/dist/esm-es5/wm-toggletip.entry.js +1 -1
  99. package/dist/esm-es5/wm-uploader.entry.js +1 -1
  100. package/dist/ripple/{p-28bf6a2e.system.js → p-04d8b674.system.js} +1 -1
  101. package/dist/ripple/{p-d3ed8b65.system.entry.js → p-04e44b30.system.entry.js} +1 -1
  102. package/dist/ripple/{p-fdc4a599.system.entry.js → p-0556279c.system.entry.js} +1 -1
  103. package/dist/ripple/{p-1242752c.system.entry.js → p-06adbeb9.system.entry.js} +1 -1
  104. package/dist/ripple/{p-42aa51fe.system.entry.js → p-0e9ccc6f.system.entry.js} +1 -1
  105. package/dist/ripple/{p-520b0f54.entry.js → p-17ceb8c1.entry.js} +1 -1
  106. package/dist/ripple/{p-8caae464.entry.js → p-1887286e.entry.js} +1 -1
  107. package/dist/ripple/{p-c873b490.system.entry.js → p-1ccd994d.system.entry.js} +1 -1
  108. package/dist/ripple/p-1d795f42.entry.js +1 -0
  109. package/dist/ripple/p-2996bfe6.entry.js +1 -0
  110. package/dist/ripple/{p-30745db6.entry.js → p-2f860b24.entry.js} +1 -1
  111. package/dist/ripple/p-3489b502.js +1 -0
  112. package/dist/ripple/{p-cd4fda75.entry.js → p-3680b55d.entry.js} +1 -1
  113. package/dist/ripple/p-3745c620.system.js +1 -0
  114. package/dist/ripple/{p-f12a510f.entry.js → p-3a1d6fc4.entry.js} +1 -1
  115. package/dist/ripple/p-42337590.entry.js +1 -0
  116. package/dist/ripple/{p-68155230.system.entry.js → p-49fd7ede.system.entry.js} +1 -1
  117. package/dist/ripple/{p-8aa9f811.js → p-4ecd3430.js} +1 -1
  118. package/dist/ripple/{p-5471864e.system.entry.js → p-62eac2d6.system.entry.js} +1 -1
  119. package/dist/ripple/{p-5e041c35.entry.js → p-6aa6a818.entry.js} +1 -1
  120. package/dist/ripple/{p-487f7419.system.entry.js → p-6bf5cbf4.system.entry.js} +1 -1
  121. package/dist/ripple/{p-e180001c.system.entry.js → p-7173b0a7.system.entry.js} +1 -1
  122. package/dist/ripple/p-726c979a.system.js +15 -0
  123. package/dist/ripple/{p-eacd33cc.system.entry.js → p-752da0fb.system.entry.js} +1 -1
  124. package/dist/ripple/{p-f36b74bf.entry.js → p-7ae1a630.entry.js} +1 -1
  125. package/dist/ripple/{p-8d347cd5.entry.js → p-7ecbf258.entry.js} +1 -1
  126. package/dist/ripple/{p-75ef731b.system.entry.js → p-7ef6a7cf.system.entry.js} +1 -1
  127. package/dist/ripple/p-8612829b.system.entry.js +1 -0
  128. package/dist/ripple/{p-398b2486.system.entry.js → p-895f5ec5.system.entry.js} +1 -1
  129. package/dist/ripple/{p-d3603def.entry.js → p-8de546e8.entry.js} +1 -1
  130. package/dist/ripple/{p-35cfcf9f.entry.js → p-93dee724.entry.js} +1 -1
  131. package/dist/ripple/{p-0f33461d.entry.js → p-97c2b06f.entry.js} +1 -1
  132. package/dist/ripple/{p-9f12284b.system.entry.js → p-995ba16f.system.entry.js} +1 -1
  133. package/dist/ripple/p-9c92c93f.entry.js +1 -0
  134. package/dist/ripple/p-9e09d7a1.entry.js +1 -0
  135. package/dist/ripple/{p-f0656464.entry.js → p-a04ba6c8.entry.js} +1 -1
  136. package/dist/ripple/{p-44035b02.system.entry.js → p-af3ce4fc.system.entry.js} +1 -1
  137. package/dist/ripple/p-bbcafbd6.system.entry.js +1 -0
  138. package/dist/ripple/{p-eee347b4.system.entry.js → p-c1443a0e.system.entry.js} +1 -1
  139. package/dist/ripple/{p-212aac05.system.entry.js → p-ca383a43.system.entry.js} +1 -1
  140. package/dist/ripple/{p-ca2fbd1b.system.js → p-cc247ee1.system.js} +1 -1
  141. package/dist/ripple/{p-73d66b0a.system.entry.js → p-cd3d74d1.system.entry.js} +1 -1
  142. package/dist/ripple/p-d1ac96e1.system.entry.js +1 -0
  143. package/dist/ripple/{p-3f1d8211.system.entry.js → p-d48c56c7.system.entry.js} +1 -1
  144. package/dist/ripple/{p-15b1c11b.js → p-de3367ee.js} +2 -2
  145. package/dist/ripple/{p-e748e22b.entry.js → p-e083fca6.entry.js} +1 -1
  146. package/dist/ripple/{p-3e6498ea.system.entry.js → p-e4439bc3.system.entry.js} +1 -1
  147. package/dist/ripple/{p-e49b9a96.entry.js → p-e524d462.entry.js} +1 -1
  148. package/dist/ripple/{p-92226595.entry.js → p-e8d39f68.entry.js} +1 -1
  149. package/dist/ripple/{p-00fa3d4b.entry.js → p-ed91be1a.entry.js} +1 -1
  150. package/dist/ripple/{p-d81a4e7c.system.entry.js → p-f23b3986.system.entry.js} +1 -1
  151. package/dist/ripple/{p-e75e75e0.entry.js → p-fda61e7e.entry.js} +1 -1
  152. package/dist/ripple/p-fe952112.entry.js +1 -0
  153. package/dist/ripple/ripple.esm.js +1 -1
  154. package/dist/ripple/ripple.js +1 -1
  155. package/dist/types/components/wm-button/wm-button.d.ts +4 -4
  156. package/dist/types/components/wm-option/wm-option.d.ts +5 -2
  157. package/dist/types/components/wm-select/wm-select.d.ts +39 -12
  158. package/dist/types/components/wm-toggletip/wm-toggletip.d.ts +2 -2
  159. package/dist/types/components.d.ts +10 -6
  160. package/dist/types/global/__mocks__/functions.d.ts +1 -0
  161. package/dist/types/global/functions.d.ts +2 -2
  162. package/dist/types/global/interfaces.d.ts +1 -1
  163. package/package.json +1 -1
  164. package/dist/esm-es5/global-5902ef31.js +0 -1
  165. package/dist/ripple/p-1b058a44.entry.js +0 -1
  166. package/dist/ripple/p-2077203e.system.js +0 -1
  167. package/dist/ripple/p-379b125b.entry.js +0 -1
  168. package/dist/ripple/p-49bf0b81.js +0 -1
  169. package/dist/ripple/p-584fef7f.system.entry.js +0 -1
  170. package/dist/ripple/p-72eb5064.system.entry.js +0 -1
  171. package/dist/ripple/p-76ca7498.system.js +0 -15
  172. package/dist/ripple/p-9fe64cec.entry.js +0 -1
  173. package/dist/ripple/p-a82d37d8.entry.js +0 -1
  174. package/dist/ripple/p-ac2485a6.system.entry.js +0 -1
  175. package/dist/ripple/p-ba168596.entry.js +0 -1
  176. package/dist/ripple/p-ed657559.entry.js +0 -1
@@ -1,7 +1,7 @@
1
1
  import { r as registerInstance, c as createEvent, h, H as Host, g as getElement, f as forceUpdate } from './index-7603f98e.js';
2
- import { i as intl, g as generateId, l as shouldOpenUp, q as getTextDir } from './functions-61c7bb1f.js';
2
+ import { i as intl, d as debounce, g as generateId, l as shouldOpenUp, q as getTextDir } from './functions-036af8dc.js';
3
3
 
4
- const wmOptionCss = ":host(:not(:last-child)),wm-option:not(:last-child){border-bottom:2px solid rgba(46, 27, 70, 0.05)}:host,wm-option{display:block;cursor:pointer;position:relative;padding:1.25rem;background:#fff;font-family:inherit;list-style:none;color:#4a4a4a;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}:host:focus,:host.focus,wm-option:focus,wm-option.focus{outline:none;background:#f4f4f4}:host.icon,wm-option.icon{color:#575195}.checkbox:before{display:inline-block;font:normal normal normal 24px/1 \"Material Design Icons\";font-size:inherit;text-rendering:auto;line-height:inherit;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:\"\\f131\";display:inline;margin-right:0.25rem;color:#575195}:host([aria-selected=true]),wm-option[aria-selected=true]{background:rgba(46, 27, 70, 0.05);font-weight:500}:host([aria-selected=true]) .checkbox:before,wm-option[aria-selected=true] .checkbox:before{content:\"\\f132\"}:host([aria-disabled=true]),wm-option[aria-disabled=true]{font-style:italic;color:#6b6b6b;cursor:default}:host([aria-disabled=true]) .checkbox:before,wm-option[aria-disabled=true] .checkbox:before{color:#6b6b6b}:host(.multi-option),wm-option.multi-option{background:unset}:host(.hassubinfo),wm-option.hassubinfo{display:-ms-flexbox;display:flex}:host(.hassubinfo) .option-wrapper,wm-option.hassubinfo .option-wrapper{-ms-flex:1;flex:1}:host(.hassubinfo) .subinfo,wm-option.hassubinfo .subinfo{-ms-flex:none;flex:none}.subinfo{font-style:italic}.option-wrapper{display:inline-block}::slotted{font-family:inherit}::slotted(i){font-size:0.875rem}::slotted(i):before{display:inline-block;font:normal normal normal 24px/1 \"Material Design Icons\";font-size:inherit;text-rendering:auto;line-height:inherit;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;display:inline-block;margin-right:0.625rem;pointer-events:none}:host(:focus),wm-option:focus{outline:none;background:#f4f4f4}:host(:hover){background:#f4f4f4;outline:none}";
4
+ const wmOptionCss = ":host(:not(:last-child)),wm-option:not(:last-child){border-bottom:2px solid rgba(46, 27, 70, 0.05)}:host,wm-option{display:block;cursor:pointer;position:relative;padding:1.25rem;background:#fff;font-family:inherit;list-style:none;color:#4a4a4a;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}:host:focus,:host.focus,wm-option:focus,wm-option.focus{outline:none;background:#f4f4f4}:host.icon,wm-option.icon{color:#575195}.checkbox:before{display:inline-block;font:normal normal normal 24px/1 \"Material Design Icons\";font-size:inherit;text-rendering:auto;line-height:inherit;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:\"\\f131\";display:inline;margin-right:0.25rem;color:#575195}:host([aria-selected=true]),wm-option[aria-selected=true]{background:rgba(46, 27, 70, 0.05);font-weight:500}:host([aria-selected=true]) .checkbox:before,wm-option[aria-selected=true] .checkbox:before{content:\"\\f132\"}:host([aria-disabled=true]),wm-option[aria-disabled=true]{font-style:italic;color:#6b6b6b;cursor:default}:host([aria-disabled=true]) .checkbox:before,wm-option[aria-disabled=true] .checkbox:before{color:#6b6b6b}:host(.multi-option),wm-option.multi-option{background:unset}:host(.hidden),wm-option.hidden,:host(.filtered-out),wm-option.filtered-out{display:none}:host(.duplicate.last),wm-option.duplicate.last{border-bottom:12px solid rgba(46, 27, 70, 0.05)}:host(.hassubinfo),wm-option.hassubinfo{display:-ms-flexbox;display:flex}:host(.hassubinfo) .option-wrapper,wm-option.hassubinfo .option-wrapper{-ms-flex:1;flex:1}:host(.hassubinfo) .subinfo,wm-option.hassubinfo .subinfo{-ms-flex:none;flex:none}.subinfo{font-style:italic}.option-wrapper{display:inline-block}::slotted{font-family:inherit}::slotted(i){font-size:0.875rem}::slotted(i):before{display:inline-block;font:normal normal normal 24px/1 \"Material Design Icons\";font-size:inherit;text-rendering:auto;line-height:inherit;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;display:inline-block;margin-right:0.625rem;pointer-events:none}:host(:focus),wm-option:focus{outline:none;background:#f4f4f4}:host(:hover){background:#f4f4f4;outline:none}";
5
5
 
6
6
  let Option = class {
7
7
  constructor(hostRef) {
@@ -12,7 +12,6 @@ let Option = class {
12
12
  this.wmEscKeyPressed = createEvent(this, "wmEscKeyPressed", 7);
13
13
  this.wmHomeKeyPressed = createEvent(this, "wmHomeKeyPressed", 7);
14
14
  this.wmEndKeyPressed = createEvent(this, "wmEndKeyPressed", 7);
15
- this.wmTabKeyPressed = createEvent(this, "wmTabKeyPressed", 7);
16
15
  this.wmEnterKeyPressed = createEvent(this, "wmEnterKeyPressed", 7);
17
16
  this.wmLetterPressed = createEvent(this, "wmLetterPressed", 7);
18
17
  this.wmOptionBlurred = createEvent(this, "wmOptionBlurred", 7);
@@ -20,16 +19,32 @@ let Option = class {
20
19
  this.disabled = false;
21
20
  this.selected = false;
22
21
  this.focused = false;
22
+ this.searchTerm = "";
23
23
  }
24
- get isMultiChild() {
24
+ get hostClasses() {
25
+ let classes = [];
26
+ if (this.subinfo) {
27
+ classes.push("hassubinfo");
28
+ }
29
+ if (this.parentSelectEl.multiple) {
30
+ classes.push("multi-option");
31
+ }
32
+ if (!this.el.textContent.toLowerCase().includes(this.searchTerm)) {
33
+ classes.push("filtered-out");
34
+ }
35
+ return classes.join(" ");
36
+ }
37
+ get parentSelectEl() {
25
38
  var _a;
26
- return (_a = this.el.parentElement) === null || _a === void 0 ? void 0 : _a.multiple;
39
+ return ((_a = this.el.parentElement) === null || _a === void 0 ? void 0 : _a.nodeName) !== "WM-SELECT"
40
+ ? this.el.getRootNode().host
41
+ : this.el.parentElement;
27
42
  }
28
43
  handleKeydown(ev) {
29
44
  switch (ev.key) {
30
45
  case "ArrowUp":
31
46
  ev.preventDefault();
32
- this.wmKeyUpPressed.emit();
47
+ this.wmKeyUpPressed.emit(this.el);
33
48
  break;
34
49
  case "ArrowDown":
35
50
  ev.preventDefault();
@@ -59,16 +74,13 @@ let Option = class {
59
74
  ev.preventDefault();
60
75
  this.wmEndKeyPressed.emit();
61
76
  break;
62
- case "Tab":
63
- this.wmTabKeyPressed.emit();
64
- break;
65
77
  default:
66
78
  this.wmLetterPressed.emit(ev.key);
67
79
  }
68
80
  }
69
81
  handleSelection() {
70
82
  if (!this.disabled) {
71
- this.wmOptionSelected.emit();
83
+ this.wmOptionSelected.emit(this.el);
72
84
  // the parent wm-select is in charge of the actual selection
73
85
  }
74
86
  }
@@ -96,13 +108,21 @@ let Option = class {
96
108
  this.el.onclick = this.onClickFunc;
97
109
  }
98
110
  }
111
+ handleSearch(ev) {
112
+ // filter is case-insensitive, so
113
+ this.searchTerm = ev.detail.searchTerm.toLowerCase();
114
+ const regexp = new RegExp(`${this.searchTerm}`, "gi");
115
+ const boldedText = this.el.textContent.replace(regexp, (match) => `<b>${match}</b>`);
116
+ this.textEl.innerHTML = `<span>${boldedText}</span>`;
117
+ }
99
118
  componentWillLoad() {
100
119
  this.syncAriaSelected();
101
120
  this.syncAriaDisabled();
102
121
  this.updateDisabledOnClick();
122
+ this.parentSelectEl.addEventListener("wmSelectSearchChanged", (ev) => this.handleSearch(ev));
103
123
  }
104
124
  render() {
105
- return (h(Host, { role: "option", tabindex: this.focused ? 0 : -1, class: `${this.subinfo ? "hassubinfo" : ""} ${this.isMultiChild ? "multi-option" : ""}` }, h("div", { class: `option-wrapper ${this.isMultiChild ? "checkbox" : ""}` }, h("slot", null)), h("div", { class: "subinfo" }, this.subinfo)));
125
+ return (h(Host, { role: "option", tabindex: this.focused ? 0 : -1, class: this.hostClasses }, h("div", { class: `option-wrapper ${this.parentSelectEl.multiple ? "checkbox" : ""}`, ref: (el) => (this.textEl = el) }, h("slot", null)), h("div", { class: "subinfo" }, this.subinfo)));
106
126
  }
107
127
  get el() { return getElement(this); }
108
128
  static get watchers() { return {
@@ -113,7 +133,7 @@ let Option = class {
113
133
  };
114
134
  Option.style = wmOptionCss;
115
135
 
116
- const wmSelectCss = ":host{position:relative;display:block;-webkit-box-sizing:border-box;box-sizing:border-box;font-family:inherit}:host .sr-only{position:absolute !important;width:1px !important;height:1px !important;padding:0 !important;border:0 !important;overflow:hidden !important;clip:rect(0, 0, 0, 0) !important;-webkit-clip-path:inset(50%) !important;clip-path:inset(50%) !important;white-space:nowrap !important;margin:-1px !important}.wrapper{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;font-size:0.875rem}.wrapper .label{display:block;line-height:normal;font-weight:600;white-space:nowrap;margin-bottom:0.25rem}.wrapper .label .required{color:#c0392b}.wrapper.label-left{-ms-flex-direction:row;flex-direction:row}.wrapper.label-left .label-wrapper{line-height:2.5rem}.wrapper.label-left .label-wrapper .label{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;min-height:2.5rem;white-space:normal;margin-bottom:0;margin-right:0.75rem}.wrapper.label-none label{position:absolute !important;width:1px !important;height:1px !important;padding:0 !important;border:0 !important;overflow:hidden !important;clip:rect(0, 0, 0, 0) !important;-webkit-clip-path:inset(50%) !important;clip-path:inset(50%) !important;white-space:nowrap !important;margin:-1px !important}.wrapper.invalid .label{color:#c0392b}.wrapper.invalid .label:after{display:inline-block;font:normal normal normal 24px/1 \"Material Design Icons\";font-size:inherit;text-rendering:auto;line-height:inherit;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:\"\\f026\";margin-left:0.3125rem}[dir=RTL] .wrapper.invalid .label:after{margin-left:0;margin-right:0.3125rem}.wrapper.rtl.label-left .label{margin-right:0;margin-left:0.75rem}.wrapper .dropdown{position:relative;-ms-flex:1;flex:1;font-size:1.125rem;color:#575195;min-width:8.75rem}.wrapper .dropdown .displayedoption{-webkit-border-radius:3px;-moz-border-radius:3px;-ms-border-radius:3px;border-radius:3px;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-wrap:nowrap;flex-wrap:nowrap;background:transparent;width:100%;border:solid 1px rgba(35, 35, 35, 0.6);padding:0 1.875rem 0 0.9375rem;cursor:pointer;height:2.5rem;line-height:normal;font-family:inherit;color:#575195;font-weight:400;font-size:0.875rem;text-transform:none;text-align:left}@media only screen and (max-width: 768px){.wrapper .dropdown .displayedoption{height:2.75rem}}.wrapper .dropdown .displayedoption:before{display:inline-block;font:normal normal normal 24px/1 \"Material Design Icons\";font-size:inherit;text-rendering:auto;line-height:inherit;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:\"\\f140\";position:absolute;right:0.5625rem;pointer-events:none}.wrapper .dropdown .displayedoption:hover:not(:disabled):not(.-disabled):not(.-raised){background:transparent;text-decoration:none}.wrapper .dropdown .displayedoption:active{-ms-transform:scale(1, 1) !important;-webkit-transform:scale(1, 1) !important;transform:scale(1, 1) !important}.wrapper .dropdown .displayedoption:focus{outline:none}.wrapper .dropdown .displayedoption::-moz-focus-inner{border:0}.wrapper .dropdown .displayedoption.user-is-tabbing:focus{-webkit-box-shadow:0 2px 2px 0 rgba(244, 243, 246, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.1), 0 0 4px 3px #61279e;-moz-box-shadow:0 2px 2px 0 rgba(244, 243, 246, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.1), 0 0 4px 3px #61279e;box-shadow:0 2px 2px 0 rgba(244, 243, 246, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.1), 0 0 4px 3px #61279e}.wrapper .dropdown .displayedoption.user-is-tabbing:focus::-moz-focus-inner{border:0}.wrapper .dropdown .displayedoption .overflowcontrol{display:block;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;-ms-flex:1;flex:1}.wrapper .dropdown .displayedoption .overflowcontrol.hassubinfo{display:-ms-flexbox;display:flex}.wrapper .dropdown .displayedoption .overflowcontrol.hassubinfo .button-text{-ms-flex:1;flex:1;text-overflow:ellipsis;overflow:hidden;min-width:0}.wrapper .dropdown .displayedoption .overflowcontrol.hassubinfo .subinfo{-ms-flex:none;flex:none;font-style:italic}.wrapper .dropdown .displayedoption .overflow-counter{font-weight:bold;margin-left:0.5rem}.wrapper .dropdown>.displayedoption[disabled]{color:#6b6b6b;border-color:#8a8a8a;background:#f0f0f0;cursor:default}.wrapper .dropdown>.options{-webkit-overflow-scrolling:touch;overflow:auto;max-height:12.5rem;-webkit-box-shadow:0 4px 15px 0 rgba(0, 0, 0, 0.2);-moz-box-shadow:0 4px 15px 0 rgba(0, 0, 0, 0.2);box-shadow:0 4px 15px 0 rgba(0, 0, 0, 0.2);-ms-transition:transform 0.25s ease;-webkit-transition:transform 0.25s ease;-moz-transition:transform 0.25s ease;-webkit-transition:-webkit-transform 0.25s ease;transition:-webkit-transform 0.25s ease;transition:transform 0.25s ease;transition:transform 0.25s ease, -webkit-transform 0.25s ease;-ms-transform:scale(1, 0);-webkit-transform:scale(1, 0);-moz-transform:scale(1, 0);transform:scale(1, 0);-ms-transform-origin:center top;-webkit-transform-origin:center top;-moz-transform-origin:center top;transform-origin:center top;-webkit-border-radius:3px;-moz-border-radius:3px;-ms-border-radius:3px;border-radius:3px;position:absolute;top:0;right:0;background:#fff;z-index:100;width:100%;font-size:0.875rem}.wrapper .dropdown>.options.upwards{top:unset;bottom:calc(100% - 2.5rem);-ms-transform-origin:center bottom;-webkit-transform-origin:center bottom;-moz-transform-origin:center bottom;transform-origin:center bottom}.wrapper .dropdown>.options.hidden{visibility:hidden}.wrapper .dropdown>.options.open{-ms-transform:scale(1, 1);-webkit-transform:scale(1, 1);-moz-transform:scale(1, 1);transform:scale(1, 1)}.wrapper.invalid .dropdown .displayedoption{-webkit-box-shadow:0 0 0 1px #c0392b;-moz-box-shadow:0 0 0 1px #c0392b;box-shadow:0 0 0 1px #c0392b;border-color:#c0392b}.wrapper .error-message{color:#c0392b;font-size:0.875rem;margin-top:0.25rem;margin-bottom:0.25rem;display:block;top:100%;left:0;font-style:italic}.rtl>.options{-ms-transform-origin:left top;-webkit-transform-origin:left top;-moz-transform-origin:left top;transform-origin:left top;left:0;right:auto}.rtl>.options .option{padding-left:3rem;padding-right:1.25rem}.rtl>.displayedoption{padding:0 0.9375rem 0 1.875rem;text-align:right}.rtl>.displayedoption:before{right:auto;left:0.5625rem}";
136
+ const wmSelectCss = ":host{position:relative;display:block;-webkit-box-sizing:border-box;box-sizing:border-box;font-family:inherit}:host .sr-only{position:absolute !important;width:1px !important;height:1px !important;padding:0 !important;border:0 !important;overflow:hidden !important;clip:rect(0, 0, 0, 0) !important;-webkit-clip-path:inset(50%) !important;clip-path:inset(50%) !important;white-space:nowrap !important;margin:-1px !important}.wrapper{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;font-size:0.875rem}.wrapper .label{display:block;line-height:normal;font-weight:600;white-space:nowrap;margin-bottom:0.25rem}.wrapper .label .required{color:#c0392b}.wrapper.label-left{-ms-flex-direction:row;flex-direction:row}.wrapper.label-left .label-wrapper{line-height:2.5rem}.wrapper.label-left .label-wrapper .label{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;min-height:2.5rem;white-space:normal;margin-bottom:0;margin-right:0.75rem}.wrapper.label-none label{position:absolute !important;width:1px !important;height:1px !important;padding:0 !important;border:0 !important;overflow:hidden !important;clip:rect(0, 0, 0, 0) !important;-webkit-clip-path:inset(50%) !important;clip-path:inset(50%) !important;white-space:nowrap !important;margin:-1px !important}.wrapper.invalid .label{color:#c0392b}.wrapper.invalid .label:after{display:inline-block;font:normal normal normal 24px/1 \"Material Design Icons\";font-size:inherit;text-rendering:auto;line-height:inherit;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:\"\\f026\";margin-left:0.3125rem}[dir=RTL] .wrapper.invalid .label:after{margin-left:0;margin-right:0.3125rem}.wrapper.rtl.label-left .label{margin-right:0;margin-left:0.75rem}.wrapper .button-wrapper{position:relative;-ms-flex:1;flex:1;font-size:1.125rem;color:#575195;min-width:8.75rem}.wrapper .button-wrapper .displayedoption{-webkit-border-radius:3px;-moz-border-radius:3px;-ms-border-radius:3px;border-radius:3px;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-wrap:nowrap;flex-wrap:nowrap;background:transparent;width:100%;border:solid 1px rgba(35, 35, 35, 0.6);padding:0 1.875rem 0 0.9375rem;cursor:pointer;height:2.5rem;line-height:normal;font-family:inherit;color:#575195;font-weight:400;font-size:0.875rem;text-transform:none;text-align:left}@media only screen and (max-width: 768px){.wrapper .button-wrapper .displayedoption{height:2.75rem}}.wrapper .button-wrapper .displayedoption:before{display:inline-block;font:normal normal normal 24px/1 \"Material Design Icons\";font-size:inherit;text-rendering:auto;line-height:inherit;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:\"\\f140\";position:absolute;right:0.5625rem;pointer-events:none}.wrapper .button-wrapper .displayedoption:hover:not(:disabled):not(.-disabled):not(.-raised){background:transparent;text-decoration:none}.wrapper .button-wrapper .displayedoption:active{-ms-transform:scale(1, 1) !important;-webkit-transform:scale(1, 1) !important;transform:scale(1, 1) !important}.wrapper .button-wrapper .displayedoption:focus{outline:none}.wrapper .button-wrapper .displayedoption::-moz-focus-inner{border:0}.wrapper .button-wrapper .displayedoption.user-is-tabbing:focus{-webkit-box-shadow:0 2px 2px 0 rgba(244, 243, 246, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.1), 0 0 4px 3px #61279e;-moz-box-shadow:0 2px 2px 0 rgba(244, 243, 246, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.1), 0 0 4px 3px #61279e;box-shadow:0 2px 2px 0 rgba(244, 243, 246, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.1), 0 0 4px 3px #61279e}.wrapper .button-wrapper .displayedoption.user-is-tabbing:focus::-moz-focus-inner{border:0}.wrapper .button-wrapper .displayedoption .overflowcontrol{display:block;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;-ms-flex:1;flex:1}.wrapper .button-wrapper .displayedoption .overflowcontrol.hassubinfo{display:-ms-flexbox;display:flex}.wrapper .button-wrapper .displayedoption .overflowcontrol.hassubinfo .button-text{-ms-flex:1;flex:1;text-overflow:ellipsis;overflow:hidden;min-width:0}.wrapper .button-wrapper .displayedoption .overflowcontrol.hassubinfo .subinfo{-ms-flex:none;flex:none;font-style:italic}.wrapper .button-wrapper .displayedoption .overflow-counter{font-weight:bold;margin-left:0.5rem}.wrapper .button-wrapper>.displayedoption[disabled]{color:#6b6b6b;border-color:#8a8a8a;background:#f0f0f0;cursor:default}.wrapper .button-wrapper>.dropdown{-webkit-overflow-scrolling:touch;overflow:auto;max-height:12.5rem;-webkit-box-shadow:0 4px 15px 0 rgba(0, 0, 0, 0.2);-moz-box-shadow:0 4px 15px 0 rgba(0, 0, 0, 0.2);box-shadow:0 4px 15px 0 rgba(0, 0, 0, 0.2);-ms-transition:transform 0.25s ease;-webkit-transition:transform 0.25s ease;-moz-transition:transform 0.25s ease;-webkit-transition:-webkit-transform 0.25s ease;transition:-webkit-transform 0.25s ease;transition:transform 0.25s ease;transition:transform 0.25s ease, -webkit-transform 0.25s ease;-ms-transform:scale(1, 0);-webkit-transform:scale(1, 0);-moz-transform:scale(1, 0);transform:scale(1, 0);-ms-transform-origin:center top;-webkit-transform-origin:center top;-moz-transform-origin:center top;transform-origin:center top;-webkit-border-radius:3px;-moz-border-radius:3px;-ms-border-radius:3px;border-radius:3px;position:absolute;top:0;right:0;background:#fff;z-index:100;width:100%;font-size:0.875rem}.wrapper .button-wrapper>.dropdown.upwards{top:unset;bottom:calc(100% - 2.5rem);-ms-transform-origin:center bottom;-webkit-transform-origin:center bottom;-moz-transform-origin:center bottom;transform-origin:center bottom}.wrapper .button-wrapper>.dropdown.hidden{visibility:hidden}.wrapper .button-wrapper>.dropdown.open{-ms-transform:scale(1, 1);-webkit-transform:scale(1, 1);-moz-transform:scale(1, 1);transform:scale(1, 1)}.wrapper.invalid .button-wrapper .displayedoption{-webkit-box-shadow:0 0 0 1px #c0392b;-moz-box-shadow:0 0 0 1px #c0392b;box-shadow:0 0 0 1px #c0392b;border-color:#c0392b}.wrapper .error-message{color:#c0392b;font-size:0.875rem;margin-top:0.25rem;margin-bottom:0.25rem;display:block;top:100%;left:0;font-style:italic}.search{-webkit-box-sizing:border-box;box-sizing:border-box;border-bottom:2px solid rgba(46, 27, 70, 0.05);padding:1.25rem}.search .searchfield-wrapper{-webkit-box-sizing:border-box;box-sizing:border-box;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;height:2.75rem;width:100%;padding:0 0.75rem;-webkit-border-radius:3px;-moz-border-radius:3px;-ms-border-radius:3px;border-radius:3px;border:1px solid #4a4a4a}.search .searchfield-wrapper:focus,.search .searchfield-wrapper.focus{-webkit-box-shadow:0 0 0 1px #20cbd4;-moz-box-shadow:0 0 0 1px #20cbd4;box-shadow:0 0 0 1px #20cbd4;outline:none;border-color:#20cbd4}.search .searchfield{width:100%;border:none;outline:none;font-family:inherit;font-size:0.875rem;margin-left:0.25rem}.search .icon:before{display:inline-block;font:normal normal normal 24px/1 \"Material Design Icons\";font-size:inherit;text-rendering:auto;line-height:inherit;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:\"\\f349\";color:#6b6b6b;font-size:0.875rem}.search-results-message{padding:1.25rem;color:#4a4a4a;font-size:0.875rem;font-style:italic}.rtl>.dropdown{-ms-transform-origin:left top;-webkit-transform-origin:left top;-moz-transform-origin:left top;transform-origin:left top;left:0;right:auto}.rtl>.dropdown .option{padding-left:3rem;padding-right:1.25rem}.rtl>.displayedoption{padding:0 0.9375rem 0 1.875rem;text-align:right}.rtl>.displayedoption:before{right:auto;left:0.5625rem}";
117
137
 
118
138
  let Select = class {
119
139
  constructor(hostRef) {
@@ -121,17 +141,24 @@ let Select = class {
121
141
  this.wmSelectDidLoad = createEvent(this, "wmSelectDidLoad", 7);
122
142
  this.wmSelectBlurred = createEvent(this, "wmSelectBlurred", 7);
123
143
  this.wmComponentBlurred = createEvent(this, "wmComponentBlurred", 7);
144
+ this.wmSelectSearchChanged = createEvent(this, "wmSelectSearchChanged", 7);
124
145
  this.disabled = false;
125
146
  this.invalid = false;
126
147
  this.labelPosition = "top";
127
148
  this.requiredField = false;
128
149
  this.errorMessage = "";
129
150
  this.multiple = false;
151
+ this.search = false;
130
152
  this.placeholder = intl.formatMessage({
131
153
  id: "select.multiPlaceholder",
132
154
  defaultMessage: "Make a selection",
133
155
  description: "Placeholder text. Use imperative",
134
156
  });
157
+ this.searchPlaceholder = intl.formatMessage({
158
+ id: "select.searchPlaceholder",
159
+ defaultMessage: "Search",
160
+ description: "Placeholder text. Use imperative",
161
+ });
135
162
  this.allSelectedMessage = intl.formatMessage({
136
163
  id: "select.allSelected",
137
164
  defaultMessage: "All selected",
@@ -143,21 +170,68 @@ let Select = class {
143
170
  });
144
171
  this.isTabbing = false;
145
172
  this.isExpanded = false;
173
+ this.announcement = "";
146
174
  this.keysSoFar = "";
147
175
  this.searchIndex = 0;
148
176
  this.keyClear = null;
149
177
  this.openUp = false;
178
+ //////////////////////////////////////
179
+ //////////////////////////////////////
150
180
  // for multiselect button text
151
181
  this.overflowCount = 0;
152
- this.displayedItems = [];
153
- this.allSelected = false;
182
+ this.displayedOptions = [];
183
+ this.debouncedSearch = debounce(() => {
184
+ this.wmSelectSearchChanged.emit({ searchTerm: this.searchTerm });
185
+ if (this.filteredOptions.length) {
186
+ this.announce(this.resultsFoundMessage);
187
+ }
188
+ else {
189
+ this.announce(this.noResultsFoundMessage);
190
+ }
191
+ }, 150);
154
192
  }
155
- get childItems() {
193
+ get childOptions() {
156
194
  return Array.from(this.el.querySelectorAll("wm-option"));
157
195
  }
158
- get selectedItems() {
196
+ get duplicateOptions() {
197
+ return Array.from(this.el.shadowRoot.querySelectorAll("wm-option"));
198
+ }
199
+ get allOptionEls() {
200
+ // this includes both slotted wm-options and internally created wm-options
201
+ return this.duplicateOptions.concat(this.childOptions);
202
+ }
203
+ get visibleOptionEls() {
204
+ return this.allOptionEls.filter((option) => !option.classList.contains("hidden") && !option.classList.contains("filtered-out"));
205
+ }
206
+ //////////////////////////////////////
207
+ // for search variants
208
+ get searchTerm() {
209
+ return this.searchFieldEl ? this.searchFieldEl.value : "";
210
+ }
211
+ get filteredOptions() {
212
+ return this.childOptions.filter((option) => { var _a; return (_a = option.textContent) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes(this.searchTerm); });
213
+ }
214
+ get selectedOptions() {
159
215
  return Array.from(this.el.querySelectorAll("wm-option")).filter((x) => x.selected);
160
216
  }
217
+ get allSelected() {
218
+ return this.childOptions.filter((option) => option.selected).length === this.childOptions.length;
219
+ }
220
+ //////////////////////////////////////
221
+ get resultsFoundMessage() {
222
+ return intl.formatMessage({
223
+ id: "select.searchResultsFound",
224
+ defaultMessage: "{numResults, plural, one {1 option found} other {# options found}}",
225
+ description: "The message read by the screen reader, indicating how many results a search returned",
226
+ }, { numResults: this.filteredOptions.length });
227
+ }
228
+ get noResultsFoundMessage() {
229
+ return intl.formatMessage({
230
+ id: "select.noSearchResults",
231
+ defaultMessage: "No results found. Please try your search again.",
232
+ description: "The message displayed when no options pass the search filter",
233
+ });
234
+ }
161
235
  toggleTabbingOn() {
162
236
  this.isTabbing = true;
163
237
  }
@@ -166,14 +240,11 @@ let Select = class {
166
240
  }
167
241
  handleOptionSelection(ev) {
168
242
  if (!this.multiple) {
169
- // ensure only one option is selected at a time
170
- this.childItems
171
- // remove selected on any other option
172
- .filter((option) => option != ev.target && !!option.selected)
173
- .map((option) => (option.selected = false));
174
- }
175
- this.focusItem(ev.target);
176
- this.selectItem(ev.target);
243
+ // ensure only one option is selected at a time, unselect all other options
244
+ this.childOptions.forEach((option) => (option.selected = option === ev.detail));
245
+ }
246
+ this.focusOption(ev.detail);
247
+ this.selectOption(ev.detail);
177
248
  if (!this.multiple) {
178
249
  this.close();
179
250
  }
@@ -183,28 +254,24 @@ let Select = class {
183
254
  this.close();
184
255
  }
185
256
  handleChildUp(ev) {
186
- this.moveUp(ev.target);
257
+ this.moveUp(ev.detail);
187
258
  }
188
259
  handleChildDown(ev) {
189
- this.moveDown(ev.target);
260
+ this.moveDown(ev.detail);
190
261
  }
191
- moveToFirstItem() {
192
- this.focusItem(this.childItems[0]);
262
+ moveToFirstOption() {
263
+ this.focusOption(this.visibleOptionEls[0]);
193
264
  }
194
- moveToLastItem() {
195
- this.focusItem(this.childItems[this.childItems.length - 1]);
196
- }
197
- handleTabKey() {
198
- this.close(false);
265
+ moveToLastOption() {
266
+ this.focusOption(this.visibleOptionEls[this.visibleOptionEls.length - 1]);
199
267
  }
200
268
  closePopupOnEscape() {
201
269
  this.close();
202
270
  }
203
271
  handleOptionBlur(ev) {
204
- const toElOrChild = ev.detail.relatedTarget === this.el || this.el.contains(ev.detail.relatedTarget);
205
272
  // if the Option is blurred to something other than the component emit a blur event with the appropriate relatedTarget
206
273
  // keeps our component's blur events accurate, and closes when focusing browser address bar
207
- if (!toElOrChild) {
274
+ if (!this.isElOrChild(ev.detail.relatedTarget)) {
208
275
  const event = new CustomEvent("blur");
209
276
  // @ts-ignore
210
277
  event.relatedTarget = ev.detail.relatedTarget;
@@ -212,18 +279,23 @@ let Select = class {
212
279
  }
213
280
  }
214
281
  handleClick(ev) {
215
- const isElOrChild = ev.target === this.el || this.el.contains(ev.target);
216
- if (!isElOrChild && this.isExpanded) {
282
+ if (!this.isElOrChild(ev.target)) {
217
283
  this.close();
218
284
  }
219
285
  }
220
286
  handleButtonBlur(ev) {
221
- const toElOrChild = ev.relatedTarget === this.el || this.el.contains(ev.relatedTarget);
222
- if (toElOrChild) {
287
+ if (this.isElOrChild(ev.relatedTarget)) {
223
288
  // do not emit a blur event when opening the dropdown and focusing the Options
224
289
  ev.stopPropagation();
225
290
  }
226
291
  }
292
+ handleSearchFieldBlur(ev) {
293
+ this.searchFieldWrapperEl.classList.remove("focus");
294
+ if (this.isElOrChild(ev.relatedTarget)) {
295
+ // do not emit a blur event when moving from searchfield to options
296
+ ev.stopPropagation();
297
+ }
298
+ }
227
299
  handleKey(ev) {
228
300
  switch (ev.key) {
229
301
  case "ArrowDown":
@@ -253,137 +325,236 @@ let Select = class {
253
325
  if (document.body.classList.contains("wmcl-user-is-tabbing")) {
254
326
  this.toggleTabbingOn();
255
327
  }
328
+ // set initial selections
329
+ if (this.selectedOptions.length > 0) {
330
+ this.selectedOptions.forEach((x) => {
331
+ this.displayedOptions.push(x);
332
+ });
333
+ // single Select only, pre-select if no default option from dev
334
+ }
335
+ else if (!this.multiple) {
336
+ this.selectOption(this.allOptionEls[0]);
337
+ }
256
338
  }
257
339
  componentDidLoad() {
258
340
  this.wmSelectDidLoad.emit();
259
- if (!this.childItems.length) {
260
- throw new Error("wm-select should have wm-option elements as children.");
261
- }
262
- if (this.multiple && this.childItems.filter((x) => x.subinfo).length > 0) {
341
+ if (this.multiple && this.allOptionEls.filter((x) => x.subinfo).length > 0) {
263
342
  throw new Error("wm-select with the multiple prop cannot have subinfo options");
264
343
  }
265
344
  if (this.multiple && !this.placeholder) {
266
345
  throw new Error("wm-select with the multiple prop needs to also use the placeholder prop.");
267
346
  }
268
- // set initial selections / button text
269
- if (this.selectedItems.length > 0) {
270
- this.selectedItems.forEach((x) => this.displayedItems.push(x));
271
- this.setButtonText();
272
- // single Select only, pre-select if no default option from dev
273
- }
274
- else if (!this.multiple) {
275
- this.selectItem(this.childItems[0]);
276
- }
277
- this.optionsEl.classList.add("hidden");
347
+ this.dropdownEl.classList.add("hidden");
278
348
  forceUpdate(this.el);
279
349
  // Dev can overwrite the max-height rule set in the Sass file
280
350
  if (this.maxHeight) {
281
- this.optionsEl.style.maxHeight = this.maxHeight;
351
+ this.dropdownEl.style.maxHeight = this.maxHeight;
352
+ }
353
+ const mutationObserver = new MutationObserver(() => this.handleSelectedMutation());
354
+ mutationObserver.observe(this.el, {
355
+ attributes: true,
356
+ attributeFilter: ["selected"],
357
+ subtree: true,
358
+ });
359
+ if (this.multiple) {
360
+ this.updateOptionVisibility();
361
+ }
362
+ this.setButtonText();
363
+ }
364
+ componentWillUpdate() {
365
+ if (this.multiple) {
366
+ // find last visible duplicate option and apply .last class
367
+ const visibleDuplicateOptions = this.visibleOptionEls.filter((option) => option.classList.contains("duplicate"));
368
+ visibleDuplicateOptions.forEach((option, idx) => {
369
+ if (idx === visibleDuplicateOptions.length - 1) {
370
+ option.classList.add("last");
371
+ }
372
+ else {
373
+ option.classList.remove("last");
374
+ }
375
+ });
282
376
  }
283
377
  }
378
+ handleSelectedMutation() {
379
+ // dispatch change event after selected options change
380
+ // mutation observer prevents emitting event when an already selected option is selected again
381
+ const event = new CustomEvent("change");
382
+ // @ts-ignore
383
+ this.el.dispatchEvent(event);
384
+ }
284
385
  moveUp(el) {
285
- const prevEl = el.previousElementSibling;
386
+ const prevEl = this.visibleOptionEls[this.visibleOptionEls.indexOf(el) - 1];
286
387
  if (prevEl) {
287
388
  // scroll option to top of dropdown if partially obscured / out of view
288
- if (prevEl.getBoundingClientRect().top < this.optionsEl.getBoundingClientRect().top) {
289
- this.optionsEl.scrollTop =
290
- prevEl.getBoundingClientRect().top - this.optionsEl.getBoundingClientRect().top + this.optionsEl.scrollTop;
389
+ if (prevEl.getBoundingClientRect().top < this.dropdownEl.getBoundingClientRect().top) {
390
+ this.scrollOptionToTop(prevEl);
291
391
  }
292
- this.focusItem(prevEl);
392
+ this.focusOption(prevEl);
393
+ }
394
+ else if (this.search) {
395
+ // if top of list and search variant, focus search field
396
+ this.searchFieldEl.focus();
293
397
  }
294
398
  else {
295
- this.focusItem(this.childItems[this.childItems.length - 1]);
399
+ // if top of list, focus last element
400
+ this.focusOption(this.visibleOptionEls[this.visibleOptionEls.length - 1]);
296
401
  }
297
402
  }
298
403
  moveDown(el) {
299
- const nextEl = el.nextElementSibling;
300
- if (nextEl && nextEl.tagName !== "INPUT") {
404
+ const nextEl = this.visibleOptionEls[this.visibleOptionEls.indexOf(el) + 1];
405
+ if (nextEl) {
301
406
  // scroll option to bottom of dropdown if partially obscured / out of view
302
- if (nextEl.getBoundingClientRect().bottom > this.optionsEl.getBoundingClientRect().bottom) {
303
- this.optionsEl.scrollTop =
304
- nextEl.getBoundingClientRect().bottom -
305
- this.optionsEl.getBoundingClientRect().top +
306
- this.optionsEl.scrollTop -
307
- this.optionsEl.offsetHeight;
407
+ if (nextEl.getBoundingClientRect().bottom > this.dropdownEl.getBoundingClientRect().bottom) {
408
+ this.scrollOptionToBottom(nextEl);
308
409
  }
309
- this.focusItem(nextEl);
410
+ this.focusOption(nextEl);
310
411
  }
311
412
  else {
312
- this.focusItem(this.childItems[0]);
413
+ // if end of list, focus first option in all variants
414
+ this.focusOption(this.visibleOptionEls[0]);
313
415
  }
314
416
  }
315
- open(itemToSelect) {
417
+ scrollOptionToTop(option) {
418
+ this.dropdownEl.scrollTop =
419
+ option.getBoundingClientRect().top - this.dropdownEl.getBoundingClientRect().top + this.dropdownEl.scrollTop;
420
+ }
421
+ scrollOptionToBottom(option) {
422
+ this.dropdownEl.scrollTop =
423
+ option.getBoundingClientRect().bottom -
424
+ this.dropdownEl.getBoundingClientRect().top +
425
+ this.dropdownEl.scrollTop -
426
+ this.dropdownEl.offsetHeight;
427
+ }
428
+ open(optionToSelect) {
316
429
  if (!this.disabled) {
317
430
  const elHeight = this.el.clientHeight;
318
431
  const buttonHeight = this.buttonEl.clientHeight;
319
- this.openUp = shouldOpenUp(this.el, this.optionsEl,
432
+ this.openUp = shouldOpenUp(this.el, this.dropdownEl,
320
433
  // when opening up, dropdown covers both label and button
321
434
  elHeight,
322
435
  // when opening down, dropdown covers only the button
323
436
  buttonHeight);
324
437
  this.isExpanded = true;
325
- this.optionsEl.classList.remove("hidden");
438
+ this.dropdownEl.classList.remove("hidden");
326
439
  window.requestAnimationFrame(() => {
327
- if (this.selectedItems.length > 0) {
328
- if (itemToSelect === "next") {
329
- this.moveDown(this.selectedItems[this.selectedItems.length - 1]);
330
- }
331
- else if (itemToSelect === "previous") {
332
- this.moveUp(this.selectedItems[0]);
333
- }
334
- else {
335
- this.focusItem(this.selectedItems[0]);
336
- }
337
- }
338
- else {
339
- this.focusItem(this.childItems[0]);
440
+ switch (optionToSelect) {
441
+ case "next":
442
+ // search variant focuses search field
443
+ // all others focus option "after" last selected option (this can be the first option)
444
+ if (this.search) {
445
+ this.searchFieldEl.focus();
446
+ this.dropdownEl.scrollTop = 0;
447
+ }
448
+ else {
449
+ this.moveDown(this.visibleOptionEls.filter((x) => x.selected).slice(-1)[0]);
450
+ }
451
+ break;
452
+ case "previous":
453
+ // search variant focuses last option
454
+ // all others focus option "above" first selected option (this can be the last option)
455
+ if (this.search) {
456
+ this.focusOption(this.visibleOptionEls[this.visibleOptionEls.length - 1]);
457
+ }
458
+ else {
459
+ this.moveUp(this.visibleOptionEls.filter((x) => x.selected)[0]);
460
+ }
461
+ break;
462
+ default:
463
+ // search variant focuses search field
464
+ // all others focus the selected option
465
+ // if no option is selected (empty multiselect), focuses first option
466
+ if (this.search) {
467
+ this.searchFieldEl.focus();
468
+ this.dropdownEl.scrollTop = 0;
469
+ }
470
+ else if (this.selectedOptions.length > 0) {
471
+ this.focusOption(this.visibleOptionEls.filter((x) => x.selected)[0]);
472
+ }
473
+ else {
474
+ this.focusOption(this.visibleOptionEls[0]);
475
+ }
476
+ break;
340
477
  }
341
478
  });
342
479
  }
343
480
  }
344
481
  close(returnFocus = true) {
345
- this.isExpanded = false;
346
- this.childItems.map((i) => (i.focused = false));
347
- window.setTimeout(() => {
348
- this.optionsEl.classList.add("hidden");
349
- // Returns focus to button after popup closes (no need if user is tabbing)
350
- // Delay is necessary for screenreader to get new expanded state before focus
351
- // window.requestAnimationFrame is probably enough, but since we are already using setTimeout it may as well be here
352
- // also UX wise, it makes sense for the button to only be focused after the animation is complete
353
- if (returnFocus) {
354
- this.el.focus();
482
+ if (this.isExpanded) {
483
+ this.isExpanded = false;
484
+ this.allOptionEls.map((i) => (i.focused = false));
485
+ window.setTimeout(() => {
486
+ this.dropdownEl.classList.add("hidden");
487
+ if (this.multiple) {
488
+ this.updateOptionVisibility();
489
+ }
490
+ // clear search field, reset filtered / bolded state of wm-options
491
+ if (this.search) {
492
+ this.searchFieldEl.value = "";
493
+ this.wmSelectSearchChanged.emit({ searchTerm: this.searchTerm });
494
+ }
495
+ // Returns focus to button after popup closes (no need if user is tabbing)
496
+ // Delay is necessary for screenreader to get new expanded state before focus
497
+ // window.requestAnimationFrame is probably enough, but since we are already using setTimeout it may as well be here
498
+ // also UX wise, it makes sense for the button to only be focused after the animation is complete
499
+ if (returnFocus) {
500
+ this.el.focus();
501
+ }
502
+ }, 150);
503
+ }
504
+ }
505
+ updateOptionVisibility() {
506
+ // this runs for search multiselects, where selected options are rendered at the top of the dropdown list
507
+ // slotted wm-options are hidden if selected, and duplicate wm-options are made visible if selected
508
+ this.childOptions.forEach((option, idx) => {
509
+ const duplicateOption = this.duplicateOptions[idx];
510
+ if (option.selected) {
511
+ option.classList.add("hidden");
512
+ duplicateOption.classList.remove("hidden");
355
513
  }
356
- }, 150);
514
+ else {
515
+ option.classList.remove("hidden");
516
+ duplicateOption.classList.add("hidden");
517
+ }
518
+ });
357
519
  }
358
- focusItem(item) {
359
- this.childItems.forEach((i) => (i.focused = i === item));
520
+ focusOption(option) {
521
+ this.allOptionEls.forEach((i) => (i.focused = i === option));
522
+ option.focus();
360
523
  }
361
- selectItem(item) {
362
- if (this.multiple) {
363
- item.selected = !item.selected;
524
+ selectOption(option) {
525
+ // this function does not necessarily change an options selected property to true
526
+ // in cases of multiselect, it toggles the selected property
527
+ if (option.classList.contains("duplicate")) {
528
+ // if clicking on a duplicate option, toggle selected property of real one, then rerender
529
+ const correspondingOption = this.findCorrespondingOption(option);
530
+ correspondingOption.selected = !correspondingOption.selected;
531
+ forceUpdate(this.el);
532
+ }
533
+ else if (this.multiple) {
534
+ option.selected = !option.selected;
364
535
  }
365
536
  else {
366
- this.childItems.forEach((i) => (i.selected = i === item));
537
+ this.allOptionEls.forEach((x) => (x.selected = x === option));
367
538
  }
368
539
  this.setButtonText();
369
540
  }
370
- findAndFocusItem(ev) {
541
+ findAndFocusOption(ev) {
371
542
  const character = ev.detail.toUpperCase();
372
543
  if (!this.keysSoFar) {
373
- for (var i = 0; i < this.childItems.length; i++) {
374
- if (this.childItems[i].focused) {
544
+ for (var i = 0; i < this.allOptionEls.length; i++) {
545
+ if (this.allOptionEls[i].focused) {
375
546
  this.searchIndex = i;
376
547
  }
377
548
  }
378
549
  }
379
550
  this.keysSoFar += character;
380
551
  this.clearKeysSoFarAfterDelay();
381
- var nextMatch = this.findMatchInRange(this.childItems, this.searchIndex + 1, this.childItems.length);
552
+ var nextMatch = this.findMatchInRange(this.allOptionEls, this.searchIndex + 1, this.allOptionEls.length);
382
553
  if (!nextMatch) {
383
- nextMatch = this.findMatchInRange(this.childItems, 0, this.searchIndex);
554
+ nextMatch = this.findMatchInRange(this.allOptionEls, 0, this.searchIndex);
384
555
  }
385
556
  if (nextMatch) {
386
- this.focusItem(nextMatch);
557
+ this.focusOption(nextMatch);
387
558
  }
388
559
  }
389
560
  clearKeysSoFarAfterDelay() {
@@ -397,8 +568,8 @@ let Select = class {
397
568
  }.bind(this), 500);
398
569
  }
399
570
  findMatchInRange(list, startIndex, endIndex) {
400
- // Find the first item starting with the keysSoFar substring, searching in
401
- // the specified range of items
571
+ // Find the first option starting with the keysSoFar substring, searching in
572
+ // the specified range of options
402
573
  for (var n = startIndex; n < endIndex; n++) {
403
574
  var label = list[n].textContent;
404
575
  if (label && label.toUpperCase().indexOf(this.keysSoFar) === 0) {
@@ -407,6 +578,19 @@ let Select = class {
407
578
  }
408
579
  return null;
409
580
  }
581
+ findCorrespondingOption(el) {
582
+ // if duplicate, returns the child wm-option
583
+ // if child wm-option, returns duplicate
584
+ const isDuplicate = el.classList.contains("duplicate");
585
+ return isDuplicate
586
+ ? this.childOptions[this.duplicateOptions.indexOf(el)]
587
+ : this.duplicateOptions[this.childOptions.indexOf(el)];
588
+ }
589
+ isElOrChild(el) {
590
+ var _a;
591
+ // determines whether or not the element is the component, a child of the component, or exists within the component's shadowroot
592
+ return el === this.el || this.el.contains(el) || ((_a = this.el.shadowRoot) === null || _a === void 0 ? void 0 : _a.contains(el));
593
+ }
410
594
  exposeErrors() {
411
595
  // When the error changes, a new id is set for the error container and the button's aria-describedby attribute is updated accordingly. This is to make sure the screen reader announces teh updated errors in Firefox. See this longstanding bug: https://bugzilla.mozilla.org/show_bug.cgi?id=493683
412
596
  const newId = generateId();
@@ -424,9 +608,30 @@ let Select = class {
424
608
  this.wmComponentBlurred.emit(); // deprecated
425
609
  }
426
610
  }
611
+ handleSearchFieldKeyDown(ev) {
612
+ switch (ev.key) {
613
+ case "ArrowDown":
614
+ ev.preventDefault();
615
+ if (this.visibleOptionEls.length) {
616
+ this.focusOption(this.visibleOptionEls[0]);
617
+ }
618
+ break;
619
+ case "ArrowUp":
620
+ ev.preventDefault();
621
+ if (this.visibleOptionEls.length) {
622
+ this.focusOption(this.visibleOptionEls[this.visibleOptionEls.length - 1]);
623
+ }
624
+ break;
625
+ case "Escape":
626
+ ev.preventDefault();
627
+ this.close();
628
+ break;
629
+ }
630
+ }
427
631
  setButtonText() {
428
- this.displayedItems = this.childItems.filter((x) => x.selected);
429
- this.allSelected = this.displayedItems.length === this.childItems.length;
632
+ this.displayedOptions = this.childOptions
633
+ .filter((x) => x.selected)
634
+ .map((y) => (!y.classList.contains("hidden") ? y : this.findCorrespondingOption(y)));
430
635
  // handle overflow + counter for multiselect
431
636
  if (this.multiple) {
432
637
  // this is a fixed measurement accounting for the max width of a 3 character overflow counter
@@ -436,32 +641,39 @@ let Select = class {
436
641
  const paddingLeft = parseInt(computedStyle.getPropertyValue("padding-left").slice(0, -2));
437
642
  const paddingRight = parseInt(computedStyle.getPropertyValue("padding-right").slice(0, -2));
438
643
  const availableSpace = this.buttonEl.clientWidth - paddingLeft - paddingRight - overflowCounterWidth;
439
- let optionsWidths = this.displayedItems.map((x) => x.shadowRoot.querySelector(".option-wrapper").clientWidth);
644
+ let optionsWidths = this.displayedOptions.map((x) => x.shadowRoot.querySelector(".option-wrapper").clientWidth);
440
645
  let optionsTotalWidth = optionsWidths.reduce((acc, x) => acc + x, 0);
441
646
  this.overflowCount = 0;
442
- while (optionsTotalWidth > availableSpace && this.displayedItems.length > 1) {
647
+ while (optionsTotalWidth > availableSpace && this.displayedOptions.length > 1) {
443
648
  this.overflowCount++;
444
649
  optionsTotalWidth -= optionsWidths[optionsWidths.length - 1];
445
650
  optionsWidths.pop();
446
- this.displayedItems.pop();
651
+ this.displayedOptions.pop();
447
652
  }
448
653
  }
449
654
  }
655
+ announce(message) {
656
+ // \u00A0 is a non-breaking space character, which causes the message to be read as a new one
657
+ if (this.liveRegionEl.textContent === message) {
658
+ message += "\u00A0";
659
+ }
660
+ this.announcement = message;
661
+ }
450
662
  renderButtonText() {
451
- if (this.multiple && this.displayedItems.length < 1) {
663
+ if (this.multiple && this.displayedOptions.length < 1) {
452
664
  return h("span", null, this.placeholder);
453
665
  }
454
666
  else if (this.multiple && this.allSelected && this.overflowCount > 0) {
455
667
  return this.allSelectedMessage;
456
668
  }
457
669
  else {
458
- return this.displayedItems.map((x, idx) => (h("span", null, idx > 0 ? ", " : "", x.textContent)));
670
+ return this.displayedOptions.map((x, idx) => (h("span", null, idx > 0 ? ", " : "", x.textContent)));
459
671
  }
460
672
  }
461
673
  renderSubinfo() {
462
674
  // multiselects cannot have subinfo for options
463
- if (!this.multiple && this.selectedItems.length > 0 && this.selectedItems[0].subinfo) {
464
- return h("span", { class: "subinfo" }, this.selectedItems[0].subinfo);
675
+ if (!this.multiple && this.selectedOptions.length > 0 && this.selectedOptions[0].subinfo) {
676
+ return h("span", { class: "subinfo" }, this.selectedOptions[0].subinfo);
465
677
  }
466
678
  }
467
679
  renderOverflowCount() {
@@ -469,6 +681,17 @@ let Select = class {
469
681
  return (h("span", null, h("span", { class: "overflow-counter" }, "+", this.overflowCount)));
470
682
  }
471
683
  }
684
+ renderSearchField() {
685
+ return (h("div", { class: "search" }, h("div", { class: "searchfield-wrapper", ref: (el) => (this.searchFieldWrapperEl = el) }, h("div", { class: "icon" }), h("input", { ref: (el) => (this.searchFieldEl = el), class: "searchfield", role: "combobox", "aria-controls": `list-${this.uid}`, "aria-expanded": this.isExpanded ? "true" : "false", onKeyDown: (ev) => this.handleSearchFieldKeyDown(ev), onFocus: () => this.searchFieldWrapperEl.classList.add("focus"), onBlur: (ev) => this.handleSearchFieldBlur(ev), onInput: () => this.debouncedSearch(), placeholder: this.searchPlaceholder }))));
686
+ }
687
+ renderSearchFailedMessage() {
688
+ return h("div", { class: "search-results-message" }, this.noResultsFoundMessage);
689
+ }
690
+ renderDuplicateOptions() {
691
+ return Array.from(this.el.children).map((option) => {
692
+ return (h("wm-option", { class: "duplicate", selected: option.selected }, option.textContent));
693
+ });
694
+ }
472
695
  render() {
473
696
  const buttonProps = {
474
697
  id: `selectbtn-${this.uid}`,
@@ -481,9 +704,9 @@ let Select = class {
481
704
  };
482
705
  return (h(Host, { onBlur: (ev) => this.handleComponentBlur(ev) }, h("div", { class: `wrapper ${getTextDir()} label-${this.labelPosition} ${this.invalid || this.errorMessage ? "invalid" : ""}` }, h("div", { class: "label-wrapper" }, h("label", { class: "label", id: `label-${this.uid}`, htmlFor: `selectbtn-${this.uid}` }, this.label,
483
706
  // we can't use aria-required or required attributes because it's invalid on the elements we're using (button controlling a listbox)
484
- this.requiredField ? (h("span", { class: "required" }, h("span", { class: "sr-only" }, this.requiredMessage), h("span", { "aria-hidden": "true" }, "*"))) : (""))), h("div", { class: "dropdown" }, h("button", Object.assign({}, buttonProps, { class: `displayedoption ${this.isTabbing ? "user-is-tabbing" : ""}`, ref: (el) => (this.buttonEl = el), onBlur: (ev) => this.handleButtonBlur(ev) }), h("span", { class: this.selectedItems.length > 0 && this.selectedItems.filter((x) => x.subinfo).length > 0
707
+ this.requiredField ? (h("span", { class: "required" }, h("span", { class: "sr-only" }, this.requiredMessage), h("span", { "aria-hidden": "true" }, "*"))) : (""))), h("div", { class: "button-wrapper" }, h("button", Object.assign({}, buttonProps, { class: `displayedoption ${this.isTabbing ? "user-is-tabbing" : ""}`, ref: (el) => (this.buttonEl = el), onBlur: (ev) => this.handleButtonBlur(ev), onFocus: () => this.close() }), h("span", { class: this.selectedOptions.length > 0 && this.selectedOptions.filter((x) => x.subinfo).length > 0
485
708
  ? "overflowcontrol hassubinfo"
486
- : "overflowcontrol" }, h("span", { class: "button-text" }, this.renderButtonText()), this.renderSubinfo()), this.renderOverflowCount()), h("div", { class: `options ${this.isExpanded ? "open" : ""} ${this.openUp ? "upwards" : ""}`, id: `list-${this.uid}`, tabindex: -1, role: "listbox", "aria-multiselectable": this.multiple ? "true" : null, "aria-labelledby": `label-${this.uid}`, ref: (el) => (this.optionsEl = el) }, h("slot", null)), this.renderErrorContainer()))));
709
+ : "overflowcontrol" }, h("span", { class: "button-text" }, this.renderButtonText()), this.renderSubinfo()), this.renderOverflowCount()), h("div", { class: `dropdown ${this.isExpanded ? "open" : ""} ${this.openUp ? "upwards" : ""}`, ref: (el) => (this.dropdownEl = el) }, this.search && this.renderSearchField(), h("div", { id: `list-${this.uid}`, tabindex: -1, role: "listbox", "aria-multiselectable": this.multiple ? "true" : null, "aria-labelledby": `label-${this.uid}` }, this.search && this.filteredOptions.length === 0 && this.renderSearchFailedMessage(), this.multiple && this.renderDuplicateOptions(), h("slot", null))), this.renderErrorContainer(), h("div", { "aria-live": "polite", class: "sr-only", ref: (el) => (this.liveRegionEl = el) }, this.announcement)))));
487
710
  }
488
711
  get el() { return getElement(this); }
489
712
  static get watchers() { return {