@watermarkinsights/ripple 4.0.0-9 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. package/dist/cjs/{chartFunctions-33cb3097.js → chartFunctions-f5ded027.js} +1 -1
  2. package/dist/cjs/{functions-833ccc83.js → functions-e7db4a26.js} +67 -824
  3. package/dist/cjs/{global-d57c118b.js → global-b33cf49b.js} +1 -1
  4. package/dist/cjs/{intl-ab07bd0b.js → intl-9ef93563.js} +3 -3
  5. package/dist/cjs/loader.cjs.js +3 -3
  6. package/dist/cjs/priv-chart-popover.cjs.entry.js +1 -1
  7. package/dist/cjs/priv-datepicker.cjs.entry.js +1 -1
  8. package/dist/cjs/ripple.cjs.js +3 -3
  9. package/dist/cjs/wm-action-menu_2.cjs.entry.js +2 -2
  10. package/dist/cjs/wm-button.cjs.entry.js +1 -1
  11. package/dist/cjs/wm-chart.cjs.entry.js +4 -4
  12. package/dist/cjs/wm-datepicker.cjs.entry.js +1 -1
  13. package/dist/cjs/wm-file.cjs.entry.js +7 -4
  14. package/dist/cjs/wm-input.cjs.entry.js +4 -9
  15. package/dist/cjs/wm-line-chart.cjs.entry.js +3 -3
  16. package/dist/cjs/wm-modal-header.cjs.entry.js +2 -2
  17. package/dist/cjs/wm-modal.cjs.entry.js +1 -1
  18. package/dist/cjs/wm-navigation_3.cjs.entry.js +2 -2
  19. package/dist/cjs/wm-navigator.cjs.entry.js +1 -1
  20. package/dist/cjs/wm-option_2.cjs.entry.js +68 -119
  21. package/dist/cjs/wm-pagination.cjs.entry.js +1 -1
  22. package/dist/cjs/wm-progress-indicator_3.cjs.entry.js +4 -4
  23. package/dist/cjs/wm-search.cjs.entry.js +2 -2
  24. package/dist/cjs/wm-snackbar.cjs.entry.js +2 -2
  25. package/dist/cjs/wm-tab-item_3.cjs.entry.js +2 -2
  26. package/dist/cjs/wm-tag-input.cjs.entry.js +521 -617
  27. package/dist/cjs/wm-tag-option.cjs.entry.js +43 -0
  28. package/dist/cjs/wm-timepicker.cjs.entry.js +1 -1
  29. package/dist/cjs/wm-toggletip.cjs.entry.js +1 -1
  30. package/dist/cjs/wm-uploader.cjs.entry.js +2 -2
  31. package/dist/collection/collection-manifest.json +3 -3
  32. package/dist/collection/components/charts/wm-chart/wm-chart.css +0 -1
  33. package/dist/collection/components/charts/wm-progress-monitor/wm-progress-indicator.css +0 -1
  34. package/dist/collection/components/charts/wm-progress-monitor/wm-progress-monitor.css +9 -1
  35. package/dist/collection/components/wm-file/wm-file.js +23 -3
  36. package/dist/collection/components/wm-file/wm-file.spec.js +83 -34
  37. package/dist/collection/components/wm-file-list/wm-file-list.spec.js +32 -59
  38. package/dist/collection/components/wm-input/wm-input.js +1 -8
  39. package/dist/collection/components/wm-menuitem/wm-menuitem.js +1 -1
  40. package/dist/collection/components/wm-option/wm-option.css +6 -6
  41. package/dist/collection/components/wm-option/wm-option.js +47 -3
  42. package/dist/collection/components/wm-select/wm-select.e2e.js +60 -114
  43. package/dist/collection/components/wm-select/wm-select.js +80 -141
  44. package/dist/collection/components/wm-select/wm-select.spec.js +9 -11
  45. package/dist/collection/components/wm-tabs/wm-tab-list/wm-tab-list.css +0 -1
  46. package/dist/collection/components/wm-tag-input/wm-tag-input.css +19 -22
  47. package/dist/collection/components/wm-tag-input/wm-tag-input.e2e.js +3 -3
  48. package/dist/collection/components/wm-tag-input/wm-tag-input.js +597 -726
  49. package/dist/collection/components/wm-tag-input/wm-tag-option/wm-tag-option.js +241 -0
  50. package/dist/collection/components/wm-uploader/wm-uploader.e2e.js +26 -47
  51. package/dist/collection/components/wm-uploader/wm-uploader.js +3 -3
  52. package/dist/collection/components/wm-uploader/wm-uploader.spec.js +67 -140
  53. package/dist/collection/global/functions.js +22 -10
  54. package/dist/collection/global/intl.js +2 -2
  55. package/dist/collection/lang/lang.spec.js +2 -2
  56. package/dist/esm/{chartFunctions-36eb2d1a.js → chartFunctions-2a4603c6.js} +1 -1
  57. package/dist/esm/{functions-061ab506.js → functions-358a1a02.js} +66 -824
  58. package/dist/esm/{global-509460f7.js → global-ba03a879.js} +1 -1
  59. package/dist/esm/{intl-d698d52f.js → intl-48057c4d.js} +3 -3
  60. package/dist/esm/loader.js +3 -3
  61. package/dist/esm/polyfills/core-js.js +0 -0
  62. package/dist/esm/polyfills/dom.js +0 -0
  63. package/dist/esm/polyfills/es5-html-element.js +0 -0
  64. package/dist/esm/polyfills/index.js +0 -0
  65. package/dist/esm/polyfills/system.js +0 -0
  66. package/dist/esm/priv-chart-popover.entry.js +1 -1
  67. package/dist/esm/priv-datepicker.entry.js +1 -1
  68. package/dist/esm/ripple.js +3 -3
  69. package/dist/esm/wm-action-menu_2.entry.js +2 -2
  70. package/dist/esm/wm-button.entry.js +1 -1
  71. package/dist/esm/wm-chart.entry.js +4 -4
  72. package/dist/esm/wm-datepicker.entry.js +1 -1
  73. package/dist/esm/wm-file.entry.js +7 -4
  74. package/dist/esm/wm-input.entry.js +4 -9
  75. package/dist/esm/wm-line-chart.entry.js +3 -3
  76. package/dist/esm/wm-modal-header.entry.js +2 -2
  77. package/dist/esm/wm-modal.entry.js +1 -1
  78. package/dist/esm/wm-navigation_3.entry.js +2 -2
  79. package/dist/esm/wm-navigator.entry.js +1 -1
  80. package/dist/esm/wm-option_2.entry.js +68 -119
  81. package/dist/esm/wm-pagination.entry.js +1 -1
  82. package/dist/esm/wm-progress-indicator_3.entry.js +4 -4
  83. package/dist/esm/wm-search.entry.js +2 -2
  84. package/dist/esm/wm-snackbar.entry.js +2 -2
  85. package/dist/esm/wm-tab-item_3.entry.js +2 -2
  86. package/dist/esm/wm-tag-input.entry.js +522 -618
  87. package/dist/esm/wm-tag-option.entry.js +39 -0
  88. package/dist/esm/wm-timepicker.entry.js +1 -1
  89. package/dist/esm/wm-toggletip.entry.js +1 -1
  90. package/dist/esm/wm-uploader.entry.js +2 -2
  91. package/dist/esm-es5/{chartFunctions-36eb2d1a.js → chartFunctions-2a4603c6.js} +1 -1
  92. package/dist/esm-es5/functions-358a1a02.js +1 -0
  93. package/dist/esm-es5/global-ba03a879.js +1 -0
  94. package/dist/esm-es5/{intl-d698d52f.js → intl-48057c4d.js} +1 -1
  95. package/dist/esm-es5/loader.js +1 -1
  96. package/dist/esm-es5/priv-chart-popover.entry.js +1 -1
  97. package/dist/esm-es5/priv-datepicker.entry.js +1 -1
  98. package/dist/esm-es5/ripple.js +1 -1
  99. package/dist/esm-es5/wm-action-menu_2.entry.js +1 -1
  100. package/dist/esm-es5/wm-button.entry.js +1 -1
  101. package/dist/esm-es5/wm-chart.entry.js +1 -1
  102. package/dist/esm-es5/wm-datepicker.entry.js +1 -1
  103. package/dist/esm-es5/wm-file.entry.js +1 -1
  104. package/dist/esm-es5/wm-input.entry.js +1 -1
  105. package/dist/esm-es5/wm-line-chart.entry.js +1 -1
  106. package/dist/esm-es5/wm-modal-header.entry.js +1 -1
  107. package/dist/esm-es5/wm-modal.entry.js +1 -1
  108. package/dist/esm-es5/wm-navigation_3.entry.js +1 -1
  109. package/dist/esm-es5/wm-navigator.entry.js +1 -1
  110. package/dist/esm-es5/wm-option_2.entry.js +1 -1
  111. package/dist/esm-es5/wm-pagination.entry.js +1 -1
  112. package/dist/esm-es5/wm-progress-indicator_3.entry.js +1 -1
  113. package/dist/esm-es5/wm-search.entry.js +1 -1
  114. package/dist/esm-es5/wm-snackbar.entry.js +1 -1
  115. package/dist/esm-es5/wm-tab-item_3.entry.js +1 -1
  116. package/dist/esm-es5/wm-tag-input.entry.js +1 -1
  117. package/dist/esm-es5/wm-tag-option.entry.js +1 -0
  118. package/dist/esm-es5/wm-timepicker.entry.js +1 -1
  119. package/dist/esm-es5/wm-toggletip.entry.js +1 -1
  120. package/dist/esm-es5/wm-uploader.entry.js +1 -1
  121. package/dist/ripple/{p-3f159fa3.entry.js → p-05ef4092.entry.js} +1 -1
  122. package/dist/ripple/p-11d629cb.system.entry.js +1 -0
  123. package/dist/ripple/p-126fbcdb.entry.js +1 -0
  124. package/dist/ripple/p-12a140e0.system.entry.js +1 -0
  125. package/dist/ripple/{p-e61e2d7f.entry.js → p-191fafc6.entry.js} +1 -1
  126. package/dist/ripple/p-1ab62a21.system.entry.js +1 -0
  127. package/dist/ripple/{p-d8287161.entry.js → p-1e7e2ca4.entry.js} +1 -1
  128. package/dist/ripple/{p-fef28649.system.entry.js → p-1ee49e28.system.entry.js} +1 -1
  129. package/dist/ripple/{p-e82eae12.entry.js → p-299bf10c.entry.js} +1 -1
  130. package/dist/ripple/{p-c20c248a.entry.js → p-2d6bb6d7.entry.js} +1 -1
  131. package/dist/ripple/{p-a31e736a.entry.js → p-366a9608.entry.js} +1 -1
  132. package/dist/ripple/p-3a20b1ed.system.entry.js +1 -0
  133. package/dist/ripple/p-3bb79457.entry.js +1 -0
  134. package/dist/ripple/{p-1f7a67cc.system.js → p-426fa249.system.js} +1 -1
  135. package/dist/ripple/p-44d4705c.system.js +1 -0
  136. package/dist/ripple/p-492dd748.system.entry.js +1 -0
  137. package/dist/ripple/p-4aa8e2cf.entry.js +1 -0
  138. package/dist/ripple/{p-ff891d67.js → p-52f5ec85.js} +1 -1
  139. package/dist/ripple/{p-484d57e1.entry.js → p-546d5c1d.entry.js} +1 -1
  140. package/dist/ripple/{p-d231aed1.system.entry.js → p-585732f7.system.entry.js} +1 -1
  141. package/dist/ripple/p-6767b009.system.js +1 -0
  142. package/dist/ripple/{p-c6ba5d3d.system.entry.js → p-681c9539.system.entry.js} +1 -1
  143. package/dist/ripple/{p-d2c9264d.entry.js → p-68cade03.entry.js} +1 -1
  144. package/dist/ripple/{p-260fd686.system.entry.js → p-6c27afee.system.entry.js} +1 -1
  145. package/dist/ripple/{p-d108107c.entry.js → p-7740db9a.entry.js} +1 -1
  146. package/dist/ripple/{p-055d1c23.system.entry.js → p-7d005413.system.entry.js} +1 -1
  147. package/dist/ripple/{p-c9830db6.system.entry.js → p-7e2c2c46.system.entry.js} +1 -1
  148. package/dist/ripple/p-7fa84884.system.entry.js +1 -0
  149. package/dist/ripple/{p-9a3d8f0b.system.entry.js → p-8b143e9d.system.entry.js} +1 -1
  150. package/dist/ripple/{p-0790bfed.entry.js → p-8ea235b6.entry.js} +1 -1
  151. package/dist/ripple/{p-4eae76a6.entry.js → p-8fadf5dd.entry.js} +1 -1
  152. package/dist/ripple/{p-8df34bf3.system.entry.js → p-94c65a69.system.entry.js} +1 -1
  153. package/dist/ripple/{p-3bd6839a.entry.js → p-9690de6c.entry.js} +1 -1
  154. package/dist/ripple/p-acb0156f.system.entry.js +1 -0
  155. package/dist/ripple/p-ae7290c2.entry.js +1 -0
  156. package/dist/ripple/{p-030b527a.js → p-aea9a33a.js} +1 -1
  157. package/dist/ripple/p-b6e5408c.js +1 -0
  158. package/dist/ripple/p-b75c0973.system.js +1 -0
  159. package/dist/ripple/{p-21f73fee.system.entry.js → p-b858d526.system.entry.js} +1 -1
  160. package/dist/ripple/{p-40b5b7d1.system.entry.js → p-b92c2e16.system.entry.js} +1 -1
  161. package/dist/ripple/p-be79e95d.entry.js +1 -0
  162. package/dist/ripple/{p-b623fdc8.entry.js → p-bfff12b4.entry.js} +1 -1
  163. package/dist/ripple/{p-68d7cf2b.entry.js → p-c028f29c.entry.js} +1 -1
  164. package/dist/ripple/p-c19ed569.entry.js +1 -0
  165. package/dist/ripple/{p-f42031f5.system.js → p-c3da681d.system.js} +1 -1
  166. package/dist/ripple/{p-9b94467e.entry.js → p-c5105455.entry.js} +1 -1
  167. package/dist/ripple/{p-15457a4b.system.entry.js → p-c86a7f4d.system.entry.js} +1 -1
  168. package/dist/ripple/{p-b9283910.entry.js → p-db58d96b.entry.js} +1 -1
  169. package/dist/ripple/p-dd92850a.js +1 -0
  170. package/dist/ripple/p-e39e6c2b.entry.js +1 -0
  171. package/dist/ripple/{p-a8ea87d1.system.entry.js → p-ec831e59.system.entry.js} +1 -1
  172. package/dist/ripple/{p-f1029090.system.entry.js → p-ee51efe0.system.entry.js} +1 -1
  173. package/dist/ripple/{p-777ced5b.entry.js → p-eec01bbe.entry.js} +1 -1
  174. package/dist/ripple/{p-5ed1b0a2.system.entry.js → p-f339d590.system.entry.js} +1 -1
  175. package/dist/ripple/{p-5b593411.system.entry.js → p-f3407959.system.entry.js} +1 -1
  176. package/dist/ripple/{p-da727af8.system.entry.js → p-f3a374ff.system.entry.js} +1 -1
  177. package/dist/ripple/{p-867b20a9.system.entry.js → p-f43fda55.system.entry.js} +1 -1
  178. package/dist/ripple/ripple.esm.js +1 -1
  179. package/dist/ripple/ripple.js +1 -1
  180. package/dist/types/components/wm-file/wm-file.d.ts +1 -1
  181. package/dist/types/components/wm-input/wm-input.d.ts +0 -1
  182. package/dist/types/components/wm-option/wm-option.d.ts +2 -0
  183. package/dist/types/components/wm-select/wm-select.d.ts +7 -7
  184. package/dist/types/components/wm-tag-input/wm-tag-input.d.ts +65 -85
  185. package/dist/types/components/wm-tag-input/wm-tag-option/wm-tag-option.d.ts +18 -0
  186. package/dist/types/components/wm-uploader/wm-uploader.d.ts +1 -1
  187. package/dist/types/components.d.ts +30 -27
  188. package/dist/types/global/functions.d.ts +2 -1
  189. package/dist/types/global/intl.d.ts +2 -2
  190. package/package.json +1 -1
  191. package/dist/cjs/wm-tag-input-row.cjs.entry.js +0 -23
  192. package/dist/collection/components/wm-tag-input/wm-tag-input-row/wm-tag-input-row.js +0 -122
  193. package/dist/collection/components/wm-tag-input/wm-tag-input.spec.js +0 -1039
  194. package/dist/esm/wm-tag-input-row.entry.js +0 -19
  195. package/dist/esm-es5/functions-061ab506.js +0 -1
  196. package/dist/esm-es5/global-509460f7.js +0 -1
  197. package/dist/esm-es5/wm-tag-input-row.entry.js +0 -1
  198. package/dist/ripple/p-1c3ba701.system.entry.js +0 -1
  199. package/dist/ripple/p-4a8c95b9.system.entry.js +0 -1
  200. package/dist/ripple/p-5f2c09f6.entry.js +0 -1
  201. package/dist/ripple/p-647a4a4a.system.entry.js +0 -1
  202. package/dist/ripple/p-7011accc.entry.js +0 -1
  203. package/dist/ripple/p-707383d5.system.js +0 -1
  204. package/dist/ripple/p-7c2e47bc.system.entry.js +0 -1
  205. package/dist/ripple/p-839d7e0f.system.js +0 -1
  206. package/dist/ripple/p-928cc755.system.entry.js +0 -1
  207. package/dist/ripple/p-9888c825.js +0 -1
  208. package/dist/ripple/p-a5308115.js +0 -1
  209. package/dist/ripple/p-b45a2fc3.entry.js +0 -1
  210. package/dist/ripple/p-b4b57baf.system.entry.js +0 -1
  211. package/dist/ripple/p-c15f29e5.system.js +0 -1
  212. package/dist/ripple/p-d38882eb.entry.js +0 -1
  213. package/dist/ripple/p-d601c5a1.entry.js +0 -1
  214. package/dist/ripple/p-d68678d2.entry.js +0 -1
  215. package/dist/ripple/p-e703d9cd.entry.js +0 -1
  216. package/dist/ripple/p-eb0d569a.system.entry.js +0 -1
  217. package/dist/types/components/wm-tag-input/wm-tag-input-row/wm-tag-input-row.d.ts +0 -11
@@ -1,85 +1,145 @@
1
- import { h, Host, forceUpdate, } from "@stencil/core";
2
- import { csvToArray, debounce, generateId, hideTooltip, intl, measureText, safeParseJSON, shouldOpenUp, showTooltip, truncateText, } from "../../global/functions";
1
+ import { h, forceUpdate } from "@stencil/core";
2
+ import { csvToArray, debounce, hideTooltip, intl, measureText, shouldOpenUp, showTooltip, truncateText, findPrev, findNext, } from "../../global/functions";
3
3
  import { globalMessages } from "../../global/intl";
4
4
  export class TagInput {
5
5
  constructor() {
6
- this.uid = this.el.id ? this.el.id : generateId();
6
+ this.addNewHelpText = intl.formatMessage({
7
+ id: "tagInput.addNewHelpText",
8
+ defaultMessage: "Press the Enter or Comma key to add a new tag.",
9
+ description: "Help text appearing in a dropdown. Use imperative",
10
+ });
11
+ this.selectionHelpText = intl.formatMessage({
12
+ id: "tagInput.selectionHelpText",
13
+ defaultMessage: "Search and select a tag.",
14
+ description: "Help text appearing in a dropdown. Use imperative",
15
+ });
16
+ this.maxTagsReachedMessage = intl.formatMessage({
17
+ id: "tagInput.maxTagsReached",
18
+ defaultMessage: "No more tags can be added because the limit has been reached.",
19
+ });
20
+ this.tagAreaInstructions = intl.formatMessage({
21
+ id: "tagInput.tagAreaInstructions",
22
+ defaultMessage: "tag selection. Press Backspace or Delete to remove a tag.",
23
+ });
24
+ this.tagsAddedMessage = intl.formatMessage({
25
+ id: "tagInput.tagsAdded",
26
+ defaultMessage: "Tags added",
27
+ description: "Full message for context: 'Tags added: x/y",
28
+ });
7
29
  this.openUp = false;
8
30
  this.inModal = false;
31
+ this.lastAddedTags = []; // the tag(s) added by the user on their last action (for highlighting)
9
32
  this.debouncedUpdate = debounce(() => forceUpdate(this.el), 30);
10
33
  this.label = undefined;
11
- this.labelPosition = "top";
12
- this.options = "";
13
- this.selectedTags = "";
14
- this.info = undefined;
15
34
  this.errorMessage = undefined;
16
- this.addNew = true;
35
+ this.info = undefined;
36
+ this.labelPosition = "top";
37
+ this.maxTags = undefined;
17
38
  this.placeholder = undefined;
18
39
  this.requiredField = false;
19
- this.characterLimit = 50;
20
- this.maxTags = undefined;
21
40
  this.tagInputType = "dropdown";
41
+ this.helpText = undefined;
42
+ this.addNew = true;
43
+ this.characterLimit = 50;
22
44
  this.colHeaders = undefined;
23
45
  this.colWidths = undefined;
24
46
  this.colWrap = undefined;
25
- this.messageConfig = "";
26
- this.focusedListItem = undefined;
27
- this.focusedTag = null;
28
- this.tablePosition = { row: 0, column: 1 };
29
47
  this.isExpanded = false;
30
- this.tagsList = csvToArray(this.selectedTags);
31
- this.optionsList = csvToArray(this.options);
32
- this.charCount = 0;
33
48
  this.liveRegionMessage = "";
49
+ this.focusedOption = undefined;
50
+ this.focusedColumn = 0;
51
+ this.focusedTagIndex = undefined;
52
+ this.tagsList = [];
53
+ }
54
+ get isDropdown() {
55
+ return this.tagInputType === "dropdown";
56
+ }
57
+ get isTable() {
58
+ return this.tagInputType === "table";
59
+ }
60
+ get charCount() {
61
+ return this.inputEl ? this.inputEl.value.length : 0;
34
62
  }
35
63
  get tooltipVisible() {
36
64
  return document.getElementById("wm-tooltip").classList.contains("show");
37
65
  }
38
- get focusedElement() {
39
- return this.el.shadowRoot.activeElement;
66
+ get optionEls() {
67
+ return Array.from(this.el.querySelectorAll("wm-tag-option"));
68
+ }
69
+ // list of options matching user query
70
+ get filteredOptionEls() {
71
+ const query = this.inputEl ? this.inputEl.value.toLowerCase() : "";
72
+ const list = Array.from(this.optionEls).filter((o) => {
73
+ let values = "";
74
+ if (this.isDropdown) {
75
+ values = o.textContent.toLowerCase();
76
+ }
77
+ else if (this.isTable) {
78
+ values = [o.col1, o.col2, o.col3, o.col4].join("").toLowerCase();
79
+ }
80
+ return values.includes(query);
81
+ });
82
+ return list;
40
83
  }
41
- get listItemEls() {
42
- return Array.from(this.dropdownEl.querySelectorAll("li"));
84
+ // the ones that should be rendered as tags
85
+ get taggedOptions() {
86
+ return this.optionEls.filter((o) => o.selected || o.locked);
43
87
  }
44
- get tagEls() {
88
+ // for visual stuff (measuring, truncating...)
89
+ get _tagEls() {
45
90
  return this.tagAreaEl ? Array.from(this.tagAreaEl.querySelectorAll(".tag")) : [];
46
91
  }
47
- get nonLockedTagEls() {
48
- return this.tagEls.filter((tag) => !tag.classList.contains("locked"));
92
+ // unlocked and selected tags, i.e. the ones that the user can interact with.
93
+ // (as opposed to locked tags who can't be focused / deleted)
94
+ // used for focus logic
95
+ get focusableTags() {
96
+ return this._tagEls.filter((t) => !t.classList.contains("locked"));
49
97
  }
50
- get optionEls() {
51
- return Array.from(this.dropdownEl.querySelectorAll(".option"));
98
+ get focusedTag() {
99
+ if (this.focusedTagIndex !== undefined && this.focusedTagIndex >= 0)
100
+ return this.focusableTags[this.focusedTagIndex];
52
101
  }
53
- get wmRowEls() {
54
- return Array.from(this.el.querySelectorAll("wm-tag-input-row"));
102
+ // get the wm-tag-option, given the internal representation (dropdown li or table tr)
103
+ tagOptionFromEl(el) {
104
+ return el.id === "add-new-btn" ? undefined : this.el.querySelector("#" + el.id);
55
105
  }
56
- get localRowEls() {
57
- return Array.from(this.el.shadowRoot.querySelectorAll("tr"));
106
+ // get the wm-tag-option, given the internal representation of a tag
107
+ tagOptionFromTag(el) {
108
+ const id = el.id.replace("tag-", "");
109
+ return this.el.querySelector("#" + id);
58
110
  }
59
- get filteredRows() {
60
- return this.wmRowEls.filter((row) => {
61
- const query = this.inputEl ? this.inputEl.value.toLowerCase() : "";
62
- const colValues = [row.col1, row.col2, row.col3, row.col4].join("").toLowerCase();
63
- return colValues.includes(query);
64
- });
111
+ // get the internal representation of a wm-tag-option
112
+ elFromTagOption(el) {
113
+ return this.el.shadowRoot.querySelector("#" + el.id);
65
114
  }
66
- get nonLockedTagsList() {
67
- let list = [];
68
- if (this.tagInputType === "table") {
69
- this.tagsList.forEach((id) => {
70
- const correspondingRowEl = this.wmRowEls.filter((row) => id === row.id)[0];
71
- if (!correspondingRowEl.locked) {
72
- list.push(id);
73
- }
74
- });
115
+ // focusedOption state refers to the wm-tag-option. This gets the corresponding element in the shadow DOM, or the "Add New" button.
116
+ get _focusedOption() {
117
+ if (!!this.focusedOption) {
118
+ return this.elFromTagOption(this.focusedOption);
75
119
  }
76
- else if (this.tagInputType === "dropdown") {
77
- list = this.tagsList;
120
+ else if (this.addNewButton && this.addNewButton.classList.contains("focused")) {
121
+ return this.addNewButton;
122
+ }
123
+ }
124
+ get _focusedCell() {
125
+ if (!!this._focusedOption) {
126
+ const allCells = Array.from(this._focusedOption.querySelectorAll("td"));
127
+ const index = this.focusedColumn || 0;
128
+ return allCells[index];
78
129
  }
79
- return list;
130
+ }
131
+ get inputActiveDescendantId() {
132
+ if (this._focusedOption) {
133
+ if (this.isTable) {
134
+ const cells = Array.from(this._focusedOption.querySelectorAll("td"));
135
+ return cells[this.focusedColumn].id;
136
+ }
137
+ return this._focusedOption.id;
138
+ }
139
+ return null;
80
140
  }
81
141
  get tagLimitReached() {
82
- return !!(this.maxTags && this.tagsList.length >= this.maxTags);
142
+ return !!(this.maxTags && this.taggedOptions.length >= this.maxTags);
83
143
  }
84
144
  get noResultsMessage() {
85
145
  return intl.formatMessage({
@@ -88,78 +148,62 @@ export class TagInput {
88
148
  description: "Message displayed when a user's search returns empty.",
89
149
  });
90
150
  }
91
- get componentMessages() {
92
- const addNewHelpText = intl.formatMessage({
93
- id: "tagInput.addNewHelpText",
94
- defaultMessage: "Press the Enter or Comma key to add a new tag.",
95
- description: "Help text appearing in a dropdown. Use imperative",
96
- });
97
- const selectionHelpText = intl.formatMessage({
98
- id: "tagInput.selectionHelpText",
99
- defaultMessage: "Search and select a tag.",
100
- description: "Help text appearing in a dropdown. Use imperative",
101
- });
102
- const maxTagsReachedMessage = intl.formatMessage({
103
- id: "tagInput.maxTagsReached",
104
- defaultMessage: "No more tags can be added because the limit has been reached.",
105
- });
106
- const tagAreaInstructions = intl.formatMessage({
107
- id: "tagInput.tagAreaInstructions",
108
- defaultMessage: "tag selection. Press Backspace or Delete to remove a tag.",
109
- });
110
- const tagsAddedMessage = intl.formatMessage({
111
- id: "tagInput.tagsAdded",
112
- defaultMessage: "Tags added",
113
- description: "For the user to understand how close they are to the tag limit, followed by x/y count",
114
- });
115
- const defaultConfig = {
116
- addNewHelpText: addNewHelpText,
117
- selectionHelpText: selectionHelpText,
118
- maxTagsReached: maxTagsReachedMessage,
119
- tagAreaInstructions: tagAreaInstructions,
120
- tagsAdded: tagsAddedMessage,
121
- };
122
- const userProvidedConfig = safeParseJSON(this.messageConfig);
123
- return userProvidedConfig ? Object.assign(Object.assign({}, defaultConfig), userProvidedConfig) : defaultConfig;
124
- }
125
151
  get inputMinimumWidth() {
126
- // 150px is the minimum width of the input field, or the length of the placeholder text
127
- const inputElStyles = getComputedStyle(this.inputEl);
128
- const tagElStyles = getComputedStyle(this.tagEls[this.tagEls.length - 1]);
129
- const inputElBuffer = [
130
- inputElStyles.paddingLeft,
131
- inputElStyles.paddingRight,
132
- inputElStyles.marginLeft,
133
- inputElStyles.marginRight,
134
- tagElStyles.marginRight,
135
- ].reduce((prev, curr) => prev + parseInt(curr.replace("px", "")), 0);
136
- const minimumWidth = Math.max(150, measureText(this.inputEl, this.placeholder).width + inputElBuffer);
137
- return minimumWidth;
138
- }
139
- generateTagAddedMessage(tag) {
152
+ if (this._tagEls) {
153
+ // 150px is the minimum width of the input field, or the length of the placeholder text
154
+ const inputElStyles = getComputedStyle(this.inputEl);
155
+ const tagElStyles = getComputedStyle(this._tagEls[this._tagEls.length - 1]);
156
+ const inputElBuffer = [
157
+ inputElStyles.paddingLeft,
158
+ inputElStyles.paddingRight,
159
+ inputElStyles.marginLeft,
160
+ inputElStyles.marginRight,
161
+ tagElStyles.marginRight,
162
+ ].reduce((prev, curr) => prev + parseInt(curr.replace("px", "")), 0);
163
+ const minimumWidth = Math.max(150, measureText(this.inputEl, this.placeholder).width + inputElBuffer);
164
+ return minimumWidth;
165
+ }
166
+ else {
167
+ return 150;
168
+ }
169
+ }
170
+ getTagName(o) {
171
+ // when the user is typing and adding a new option, all we can pass is the text typed. so for the dropdown type the tag name is the identifier. It also takes care of duplicates. Table variant requires an id as the tag name is the first column but we want to allow duplicates here (e.g. people with the same name)
172
+ return this.isDropdown ? o.textContent : o.col1;
173
+ }
174
+ tagAddedMessage(tag) {
140
175
  return intl.formatMessage({
141
176
  id: "tagInput.tagAdded",
142
177
  defaultMessage: "{tagName} added.",
143
178
  description: "A confirmation for adding a tag.",
144
179
  }, { tagName: tag });
145
180
  }
146
- generateTagAlreadyAddedMessage(tag) {
181
+ tagRemovedMessage(tag) {
182
+ return intl.formatMessage({
183
+ id: "tagInput.tagRemoved",
184
+ defaultMessage: "{tagName} removed.",
185
+ description: "A confirmation for removing a tag.",
186
+ }, { tagName: tag });
187
+ }
188
+ tagAlreadyAddedMessage(tag) {
147
189
  return intl.formatMessage({
148
190
  id: "tagInput.tagAlreadyAdded",
149
191
  defaultMessage: "{tagName} has already been added.",
150
192
  description: "An alert for adding a tag that is already present.",
151
193
  }, { tagName: tag });
152
194
  }
195
+ isElOrChild(el) {
196
+ return el === this.el || this.el.shadowRoot.contains(el) || this.el.contains(el);
197
+ }
153
198
  componentWillLoad() {
154
199
  if (!this.placeholder) {
155
- this.placeholder = this.createPlaceholderDefault(this.addNew, !!this.options);
200
+ this.placeholder = this.createPlaceholderDefault(this.addNew, !!this.optionEls);
156
201
  }
157
202
  if (!this.label) {
158
203
  console.error("wm-tag-input must have a label property");
159
204
  }
160
- this.consolidateSelectedTags();
161
205
  this.el.focus = () => {
162
- const firstFocusableTag = this.nonLockedTagEls[0];
206
+ const firstFocusableTag = this.focusableTags[0];
163
207
  if (firstFocusableTag) {
164
208
  this.tagAreaEl.focus();
165
209
  this.focusTag(firstFocusableTag);
@@ -175,36 +219,114 @@ export class TagInput {
175
219
  if (this.el.closest("wm-modal")) {
176
220
  this.inModal = true;
177
221
  }
222
+ const lockedTags = [];
223
+ const regularTags = [];
224
+ this.optionEls.forEach((o) => {
225
+ if (o.locked) {
226
+ lockedTags.push(o);
227
+ }
228
+ else if (o.selected) {
229
+ regularTags.push(o);
230
+ }
231
+ });
232
+ this.tagsList = [...lockedTags, ...regularTags];
178
233
  }
179
234
  componentDidLoad() {
180
- // prevent highlighting of pre-selected tags
181
- this.tagEls.forEach((el) => el.classList.remove("highlight"));
235
+ // Set up observer to announce changes in selected tags, or removed user-added tags
236
+ const observerAnnouncer = new MutationObserver((optionListMutations) => optionListMutations.forEach((mutationRecord) => this.handleChangeAnnouncement(mutationRecord)));
237
+ observerAnnouncer.observe(this.el, {
238
+ subtree: true,
239
+ attributes: true,
240
+ attributeFilter: ["selected"],
241
+ childList: true,
242
+ });
243
+ // Set up observer that ensures parent reload
244
+ // when children wm-tag-options are removed
245
+ const optionListObserver = new MutationObserver((optionListMutations) => optionListMutations.forEach((mutationRecord) => this.handleOptionListChange(mutationRecord)));
246
+ optionListObserver.observe(this.el, {
247
+ childList: true,
248
+ });
249
+ // Set up the observer that will handle focus
250
+ // when tag list changes
251
+ if (!!this.tagAreaEl) {
252
+ const tagListObserver = new MutationObserver((tagListMutations) => tagListMutations.forEach((mutationRecord) => this.handleTagListChange(mutationRecord)));
253
+ tagListObserver.observe(this.tagAreaEl, {
254
+ childList: true,
255
+ });
256
+ }
257
+ }
258
+ handleChangeAnnouncement(mutationRecord) {
259
+ const tagOptionEl = mutationRecord.target;
260
+ if (mutationRecord.type == "childList" && mutationRecord.removedNodes.length > 0) {
261
+ // announce deselection of user-added tag, whose element removal is picked up
262
+ this.announce(this.tagRemovedMessage(mutationRecord.removedNodes[0].textContent));
263
+ }
264
+ else if (mutationRecord.type == "attributes") {
265
+ // announce selection or deselection of all kinds of tags
266
+ if (tagOptionEl.selected) {
267
+ this.announce(this.tagAddedMessage(tagOptionEl.textContent));
268
+ }
269
+ else {
270
+ this.announce(this.tagRemovedMessage(tagOptionEl.textContent));
271
+ }
272
+ }
273
+ }
274
+ handleOptionListChange(record) {
275
+ const addedNodes = Array.from(record.addedNodes);
276
+ if (addedNodes.length > 0) {
277
+ addedNodes.forEach((n) => !this.tagsList.includes(n) && this.tagsList.push(n));
278
+ }
279
+ const removedNodes = Array.from(record.removedNodes);
280
+ if (removedNodes.length > 0) {
281
+ this.tagsList = this.tagsList.filter((t) => !removedNodes.includes(t));
282
+ }
283
+ }
284
+ handleTagOptionSelected(ev) {
285
+ const selOption = ev.target;
286
+ this.tagsList = this.tagsList.concat(selOption);
287
+ }
288
+ handleTagOptionDeselected(ev) {
289
+ const deselOption = ev.target;
290
+ this.tagsList = this.tagsList.filter((t) => t != deselOption);
291
+ }
292
+ handleTagListChange(mutationRecord) {
293
+ // there are 2 cases: the option still exists but is no longer selected,
294
+ // or it was removed altogether
295
+ const removedTag = mutationRecord.removedNodes[0];
296
+ if (!!removedTag) {
297
+ // this is a trick. focusedTag gets the ref from an index. When an element
298
+ // is removed it will fall back on the new element with that index if it exists
299
+ if (this.focusedTag) {
300
+ this.focusTag(this.focusedTag);
301
+ }
302
+ else if (this.focusableTags.length > 0) {
303
+ // Otherwise the last tag was deleted and we reassign to the new last tag.
304
+ const tagToFocus = this.focusableTags[this.focusableTags.length - 1];
305
+ this.focusTag(tagToFocus);
306
+ }
307
+ else {
308
+ // unless there are no more tags...
309
+ this.inputEl.focus();
310
+ }
311
+ this.lastAddedTags = [];
312
+ }
182
313
  }
183
314
  componentDidRender() {
184
315
  this.positionInput();
185
316
  // check each tag if truncation is needed
186
- this.tagEls.forEach((tag) => {
317
+ this._tagEls.forEach((tag) => {
187
318
  const textEl = tag.querySelector(".tag-text");
188
319
  const wrapper = this.el.shadowRoot.querySelector(".tags-and-input-wrapper");
189
320
  const leftBound = textEl.getBoundingClientRect().left;
190
321
  // the numbers represent spacing values for padding, margin, and delete icon
191
322
  const rightBound = wrapper.getBoundingClientRect().right - 10 - 8 - 28;
192
- let displayText = tag.dataset.tag;
193
- if (this.tagInputType === "table") {
194
- // table variant doesn't display the tag id, but the contents of the first column
195
- const referencedRow = this.el.querySelector(`#${displayText}`);
196
- displayText = referencedRow ? referencedRow.col1 : "";
197
- }
198
- textEl.textContent = truncateText(textEl, displayText, rightBound - leftBound, 5);
199
- });
200
- }
201
- consolidateSelectedTags() {
202
- this.tagsList.forEach((tag) => {
203
- if (!this.includesCaseInsensitive(this.optionsList, tag)) {
204
- this.options += `${this.options.length > 0 ? "," : ""}${tag}`;
323
+ const id = tag.id.replace("tag-", "");
324
+ const optionEl = id && this.el.querySelector("#" + id);
325
+ if (optionEl) {
326
+ // tag text for table variant is first column text
327
+ textEl.textContent = truncateText(textEl, this.getTagName(optionEl), rightBound - leftBound, 5);
205
328
  }
206
329
  });
207
- this.optionsList = csvToArray(this.options);
208
330
  }
209
331
  createPlaceholderDefault(addNew, hasOptions) {
210
332
  const addAndSearchPlaceholder = intl.formatMessage({
@@ -234,38 +356,40 @@ export class TagInput {
234
356
  }
235
357
  return placeholder;
236
358
  }
237
- reflectSelectedTags(newValue, oldValue) {
238
- const isAddition = newValue.length > oldValue.length;
239
- let changedTag = "";
240
- let selectedTags = this.tagsList;
241
- if (isAddition) {
242
- changedTag = newValue.filter((val) => !oldValue.includes(val))[0];
243
- }
244
- else {
245
- changedTag = oldValue.filter((val) => !newValue.includes(val))[0];
246
- }
247
- // event emitted by type table uses element references instead of strings
248
- if (this.tagInputType === "table") {
249
- changedTag = this.wmRowEls.filter((row) => row.id === changedTag)[0];
250
- selectedTags = this.tagsList.map((id) => this.el.querySelector(`#${id}`));
251
- }
252
- this.selectedTags = this.listToCSV(this.tagsList);
253
- let detail = { value: selectedTags, tagChanged: changedTag };
254
- this.wmTagInputChanged.emit(detail);
255
- }
256
359
  handleErrorMessageChange() {
257
360
  if (this.errorMessage) {
258
361
  this.announce(this.errorMessage);
259
362
  }
260
363
  }
261
- handleRowUpdate() {
262
- forceUpdate(this.el);
263
- }
264
- closeIfNotElOrChild(ev) {
265
- const isntElOrChild = ev.target !== this.el && !this.el.shadowRoot.contains(ev.target);
266
- if (this.tagInputType === "dropdown" && isntElOrChild && this.isExpanded) {
364
+ handleClick(ev) {
365
+ const el = ev.target;
366
+ if (this.isDropdown && !this.el.contains(el) && this.isExpanded) {
267
367
  this.closeDropdown();
268
368
  }
369
+ else if (Array.from(this.el.children).includes(el)) {
370
+ const option = el;
371
+ const tagName = this.getTagName(option);
372
+ this.lastAddedTags = [tagName];
373
+ }
374
+ }
375
+ handleOptionClick(ev) {
376
+ ev.preventDefault();
377
+ this.resetInput();
378
+ let option;
379
+ if (this.isTable) {
380
+ option = ev.target;
381
+ option = this.tagOptionFromEl(option.closest("tr"));
382
+ }
383
+ else {
384
+ option = this.tagOptionFromEl(ev.target);
385
+ }
386
+ // if someone wants to attach a click event listener on wm-tag-option
387
+ option.click();
388
+ if (!option.locked) {
389
+ option.selected
390
+ ? this.isTable && option.emitDeselectedEvent() // dropdown doesn't deselect on option click
391
+ : option.emitSelectedEvent();
392
+ }
269
393
  }
270
394
  // From wm-button
271
395
  // we need to listen for scroll events during the capture phase because they do not bubble up
@@ -277,8 +401,8 @@ export class TagInput {
277
401
  }
278
402
  }
279
403
  handleInputKeyDown(ev) {
280
- if (/^.$/.test(ev.key) && this.inputEl.value.length >= this.characterLimit) {
281
- this.announce(this.generateCharacterLimitWarning(this.inputEl.value.length, this.characterLimit));
404
+ if (/^.$/.test(ev.key) && this.charCount >= this.characterLimit) {
405
+ this.announce(this.generateCharacterLimitWarning(this.charCount, this.characterLimit));
282
406
  }
283
407
  // prevent keydown triggering on tag area
284
408
  ev.stopPropagation();
@@ -296,19 +420,19 @@ export class TagInput {
296
420
  this.handleInputArrowUp();
297
421
  break;
298
422
  case "ArrowLeft":
299
- if (this.tagInputType === "table" && this.tablePosition.row) {
423
+ if (this.isTable) {
300
424
  ev.preventDefault();
301
- this.moveLeftCell();
425
+ this.focusPrevCell();
302
426
  }
303
427
  break;
304
428
  case "ArrowRight":
305
- if (this.tagInputType === "table" && this.tablePosition.row) {
429
+ if (this.isTable) {
306
430
  ev.preventDefault();
307
- this.moveRightCell();
431
+ this.focusNextCell();
308
432
  }
309
433
  break;
310
434
  case "Escape":
311
- if (this.tagInputType === "dropdown" && this.isExpanded) {
435
+ if (this.isDropdown && this.isExpanded) {
312
436
  this.closeDropdown();
313
437
  }
314
438
  break;
@@ -319,17 +443,14 @@ export class TagInput {
319
443
  }
320
444
  }
321
445
  handleInputFocus() {
322
- if (this.tagInputType === "dropdown") {
446
+ if (this.isDropdown) {
323
447
  this.openDropdown();
324
- this.clearListItemFocus();
448
+ this.clearOptionFocus();
325
449
  }
326
- // force update needed to apply styled state of field-wrapper el
327
- forceUpdate(this.el);
328
450
  }
329
- handleInputChanged(value) {
330
- this.charCount = value.length;
331
- if (this.tagInputType === "dropdown") {
332
- this.clearListItemFocus();
451
+ handleInputChanged(ev) {
452
+ this.clearOptionFocus();
453
+ if (this.isDropdown) {
333
454
  if (this.charCount >= this.characterLimit - 5) {
334
455
  this.announce(this.generateCharacterLimitWarning(this.charCount, this.characterLimit));
335
456
  }
@@ -337,415 +458,208 @@ export class TagInput {
337
458
  this.openDropdown();
338
459
  }
339
460
  }
340
- else if (this.tagInputType === "table") {
341
- this.clearCellFocus();
342
- }
343
- if (value.includes(",") && this.addNew) {
344
- // covers both typing "," and pasting in text that includes ","
345
- value.split(",").forEach((tag) => this.submitInput(this.addNew, tag.trim()));
346
- this.announce(this.generateTagAddedMessage(value.split(",").join(", ")));
461
+ const val = ev.target.value;
462
+ if (val.includes(",") && this.addNew) {
463
+ this.addTags(val);
347
464
  }
348
465
  else {
349
466
  this.announceExistingOptions();
350
467
  }
351
468
  }
352
469
  handleInputEnter() {
353
- if (this.tagInputType === "dropdown") {
354
- if (this.focusedListItem) {
355
- this.handleListItemClick(this.focusedListItem);
356
- }
357
- else {
358
- this.submitInput(this.addNew, this.inputEl.value.trim());
359
- }
360
- }
361
- else if (this.tagInputType === "table" && this.tablePosition.row > 0) {
362
- this.handleTableRowClick(this.localRowEls[this.tablePosition.row].id);
363
- }
364
- }
365
- submitInput(canAddNew, value) {
366
- const hasNonWhiteSpaceCharacters = value.match(/\S/);
367
- if (canAddNew && hasNonWhiteSpaceCharacters) {
368
- this.addTag(value);
369
- this.optionsList = this.addOption(value);
470
+ // user has selected an option in the list
471
+ if (this.focusedOption) {
472
+ const tagName = this.getTagName(this.focusedOption);
473
+ this.lastAddedTags = [tagName];
474
+ this.focusedOption.click();
475
+ this.focusedOption.selected
476
+ ? this.isTable && this.focusedOption.emitDeselectedEvent()
477
+ : this.focusedOption.emitSelectedEvent();
370
478
  this.resetInput();
371
479
  }
480
+ else if (this.isDropdown) {
481
+ // user is adding a new tag
482
+ const tagName = this.inputEl.value;
483
+ if (!!tagName) {
484
+ this.isExistingTag(tagName) ? this.announce(this.tagAlreadyAddedMessage(tagName)) : this.addTags(tagName);
485
+ this.resetInput();
486
+ }
487
+ }
372
488
  }
373
489
  handleInputArrowDown() {
374
- if (this.tagInputType === "table") {
375
- this.moveDownRow();
376
- }
377
- else if (this.tagInputType === "dropdown" && this.isExpanded) {
378
- this.moveDownListItem();
490
+ if (this.isDropdown) {
491
+ if (!this.isExpanded) {
492
+ this.openDropdown();
493
+ }
494
+ else {
495
+ let items = [];
496
+ // the id check prevents a bug where the ref is reassigned to the first option causing it to be added twice (after adding a new user option)
497
+ if (this.addNewButton && this.addNewButton.id === "add-new-btn") {
498
+ items.push(this.addNewButton);
499
+ }
500
+ this.filteredOptionEls.forEach((o) => {
501
+ items.push(this.elFromTagOption(o));
502
+ });
503
+ const next = findNext(items, this._focusedOption, true);
504
+ this.focusOption(next);
505
+ }
379
506
  }
380
- else if (this.tagInputType === "dropdown") {
381
- this.openDropdown();
507
+ else {
508
+ const items = this.filteredOptionEls.filter((o) => !o.locked).map((o) => this.elFromTagOption(o));
509
+ const next = findNext(items, this._focusedOption, true);
510
+ this.focusOption(next);
382
511
  }
383
512
  }
384
513
  handleInputArrowUp() {
385
- if (this.tagInputType === "table") {
386
- this.moveUpRow();
387
- }
388
- else if (this.tagInputType === "dropdown" && this.isExpanded) {
389
- this.moveUpListItem();
514
+ if (this.isDropdown) {
515
+ if (!this.isExpanded) {
516
+ this.openDropdown();
517
+ }
518
+ else {
519
+ let items = [];
520
+ if (this.addNewButton) {
521
+ items.push(this.addNewButton);
522
+ }
523
+ this.filteredOptionEls.forEach((o) => {
524
+ items.push(this.elFromTagOption(o));
525
+ });
526
+ const prev = findPrev(items, this._focusedOption, true);
527
+ this.focusOption(prev);
528
+ }
390
529
  }
391
- else if (this.tagInputType === "dropdown") {
392
- this.openDropdown();
530
+ else {
531
+ const items = this.filteredOptionEls.filter((o) => !o.locked).map((o) => this.elFromTagOption(o));
532
+ const prev = findPrev(items, this._focusedOption, true);
533
+ this.focusOption(prev);
393
534
  }
394
535
  }
395
536
  handleInputBackspace() {
396
- if (this.inputEl.value === "" && this.tagsList.length > 0) {
537
+ if (this.inputEl.value === "" && this.focusableTags.length > 0) {
397
538
  // wait for events to finish firing before redirecting focus
398
539
  // prevents double input in input area and tag area
399
540
  window.requestAnimationFrame(() => {
400
- if (this.nonLockedTagsList.length > 0) {
401
- this.tagAreaEl.focus();
402
- this.focusTag(this.tagEls[this.tagEls.length - 1]);
403
- }
541
+ this.tagAreaEl.focus();
542
+ this.focusTag(this.focusableTags[this.focusableTags.length - 1]);
404
543
  });
405
544
  }
406
545
  }
407
- handleListItemKeyDown(ev) {
408
- const typedEvTarget = ev.target;
409
- switch (ev.key) {
410
- case "Enter":
411
- case " ":
412
- ev.preventDefault();
413
- typedEvTarget.click();
414
- break;
415
- case "ArrowDown":
416
- ev.preventDefault();
417
- this.moveDownListItem();
418
- break;
419
- case "ArrowUp":
420
- ev.preventDefault();
421
- this.moveUpListItem();
422
- break;
423
- case "Escape":
424
- if (this.focusedElement !== this.inputEl) {
425
- this.inputEl.focus();
426
- }
427
- else if (this.tagInputType === "dropdown") {
428
- this.closeDropdown();
429
- }
430
- break;
431
- }
432
- }
433
- handleListItemClick(item) {
434
- const tag = item.dataset.option.trim() || "";
435
- if (this.includesCaseInsensitive(this.tagsList, tag)) {
436
- this.announce(this.generateTagAlreadyAddedMessage(tag));
437
- }
438
- else {
439
- this.resetInput();
440
- this.addTag(tag);
441
- this.optionsList = this.addOption(tag);
442
- this.focusedListItem = null;
443
- }
444
- }
445
- handleTableRowClick(rowId) {
446
- const referencedRow = this.el.querySelector(`#${rowId}`);
447
- const isLocked = referencedRow.locked;
448
- if (!isLocked) {
449
- if (this.includesCaseInsensitive(this.tagsList, rowId)) {
450
- this.removeTag(rowId);
451
- }
452
- else if (!this.tagLimitReached) {
453
- this.addTag(rowId);
454
- this.resetInput();
455
- }
456
- }
457
- }
458
546
  handleTagAreaKeyDown(ev) {
459
547
  switch (ev.key) {
460
548
  case "ArrowLeft":
461
549
  case "ArrowUp":
462
550
  ev.preventDefault();
463
- this.moveLeftTag();
551
+ if (this.focusedTag) {
552
+ const prev = findPrev(this.focusableTags, this.focusedTag, true);
553
+ this.focusTag(prev);
554
+ }
464
555
  break;
465
556
  case "ArrowRight":
466
557
  case "ArrowDown":
467
558
  ev.preventDefault();
468
- this.moveRightTag();
559
+ if (this.focusedTag) {
560
+ const next = findNext(this.focusableTags, this.focusedTag, true);
561
+ this.focusTag(next);
562
+ }
469
563
  break;
470
564
  case "Backspace":
471
565
  case "Delete":
472
- this.handleTagAreaDelete();
566
+ if (this.focusedTag) {
567
+ const option = this.tagOptionFromTag(this.focusedTag);
568
+ if (!option.locked) {
569
+ option.emitDeselectedEvent();
570
+ }
571
+ }
473
572
  break;
474
573
  }
475
574
  }
476
- handleTagAreaDelete() {
477
- const isLocked = this.focusedTag && this.focusedTag.classList.contains("locked");
478
- if (this.focusedTag && !isLocked) {
479
- this.removeTag(this.focusedTag.dataset.tag);
480
- if (this.nonLockedTagsList.length === 0) {
481
- // focus input if no tags are left
482
- this.inputEl.focus();
483
- }
484
- else {
485
- const removingLastTag = this.focusedTag === this.tagEls[this.tagEls.length - 1];
486
- // if removing the last tag, reassign focused tag to previous task
487
- this.focusedTag = removingLastTag ? this.tagEls[this.tagEls.length - 2] : this.focusedTag;
488
- this.focusTag(this.focusedTag);
489
- }
490
- }
491
- }
492
- handleBlur(ev, component) {
493
- const isntElOrChild = ev.relatedTarget !== component && !this.el.shadowRoot.contains(ev.relatedTarget);
575
+ handleBlur(ev) {
494
576
  this.dismissTooltip();
495
- this.clearCellFocus();
496
- if (isntElOrChild) {
577
+ this.clearOptionFocus();
578
+ const relTarget = ev.relatedTarget;
579
+ if (!this.isElOrChild(relTarget)) {
497
580
  this.fieldWrapperEl.classList.remove("focused");
498
- if (this.tagInputType === "dropdown") {
581
+ if (this.isDropdown) {
499
582
  this.closeDropdown();
500
583
  }
501
584
  }
502
585
  }
503
- handleCellMouseEnter(ev) {
504
- const cell = ev.target;
505
- const contentWrapper = cell.querySelector(".cell-content-wrapper");
506
- const isTruncated = contentWrapper.scrollWidth > contentWrapper.clientWidth;
507
- if (isTruncated) {
508
- // innerText is necessary vs textContent, as innerText ignores sr-only / display: none text
509
- showTooltip("bottom", cell, cell.innerText);
510
- }
511
- }
512
- handleTagAreaFocus() {
513
- if (this.tagInputType === "dropdown") {
586
+ handleTagAreaFocus(ev) {
587
+ if (this.isDropdown) {
514
588
  this.closeDropdown();
515
589
  }
516
- const firstFocusableTag = this.nonLockedTagEls[0];
517
- firstFocusableTag && this.focusTag(firstFocusableTag);
518
- }
519
- handleRemoveButtonClick(tag) {
520
- this.moveLeftTag();
521
- this.removeTag(tag);
522
- }
523
- moveDownListItem() {
524
- if (this.listItemEls.length > 0) {
525
- const firstListItem = this.listItemEls[0];
526
- if (!this.focusedListItem) {
527
- this.focusListItem(firstListItem);
528
- }
529
- else if (this.focusedListItem.nextElementSibling) {
530
- this.focusListItem(this.focusedListItem.nextElementSibling);
590
+ if (this.focusableTags.length > 0) {
591
+ const relTarget = ev.relatedTarget;
592
+ if (relTarget && relTarget.id === "input") {
593
+ const lastFocusableTag = this.focusableTags[this.focusableTags.length - 1];
594
+ this.focusTag(lastFocusableTag);
531
595
  }
532
596
  else {
533
- this.focusListItem(firstListItem);
597
+ const firstFocusableTag = this.focusableTags[0];
598
+ this.focusTag(firstFocusableTag);
534
599
  }
535
600
  }
536
601
  }
537
- moveUpListItem() {
538
- if (this.listItemEls.length > 0) {
539
- const lastListItem = this.listItemEls[this.listItemEls.length - 1];
540
- if (!this.focusedListItem) {
541
- this.focusListItem(lastListItem);
542
- }
543
- else if (this.focusedListItem.previousElementSibling) {
544
- this.focusListItem(this.focusedListItem.previousElementSibling);
545
- }
546
- else {
547
- this.clearListItemFocus();
602
+ focusPrevCell() {
603
+ if (this.focusedOption) {
604
+ if (this.focusedColumn > 0) {
605
+ this.focusedColumn -= 1;
548
606
  }
549
607
  }
550
608
  }
551
- moveDownRow() {
552
- if (this.filteredRows.length > 0) {
553
- if (this.tablePosition.row === 0) {
554
- this.tablePosition.row = 1;
555
- }
556
- else if (this.tablePosition.row === this.filteredRows.length) {
557
- this.tablePosition.row = 1;
558
- }
559
- else {
560
- this.tablePosition.row++;
561
- }
562
- // skip locked rows
563
- const rowToFocus = this.filteredRows[this.tablePosition.row - 1];
564
- if (rowToFocus.locked) {
565
- this.moveDownRow();
566
- }
567
- else {
568
- this.focusCell(this.tablePosition);
609
+ focusNextCell() {
610
+ if (this._focusedOption) {
611
+ const lastCellIdx = this._focusedOption.querySelectorAll("td").length - 1;
612
+ if (this.focusedColumn < lastCellIdx) {
613
+ this.focusedColumn += 1;
569
614
  }
570
615
  }
571
616
  }
572
- moveUpRow() {
573
- if (this.filteredRows.length > 0) {
574
- if (this.tablePosition.row === 0) {
575
- this.tablePosition.row = this.filteredRows.length;
576
- }
577
- else if (this.tablePosition.row === 1) {
578
- this.tablePosition.row = 0;
617
+ focusOption(optionToFocus) {
618
+ if (optionToFocus) {
619
+ // will be undefined for the "Add New" button
620
+ this.focusedOption = this.tagOptionFromEl(optionToFocus);
621
+ if (optionToFocus === this.addNewButton) {
622
+ this.addNewButton.classList.add("focused");
579
623
  }
580
624
  else {
581
- this.tablePosition.row--;
582
- }
583
- // skip locked rows
584
- const rowToFocus = this.filteredRows[this.tablePosition.row - 1];
585
- if (rowToFocus && rowToFocus.locked) {
586
- this.moveUpRow();
587
- }
588
- else if (rowToFocus) {
589
- this.focusCell(this.tablePosition);
625
+ this.addNewButton && this.addNewButton.classList.remove("focused");
590
626
  }
591
- else {
592
- this.clearCellFocus();
593
- }
594
- }
595
- }
596
- moveLeftCell() {
597
- if (this.tablePosition.column != 1) {
598
- this.tablePosition.column--;
599
- this.focusCell(this.tablePosition);
600
- }
601
- }
602
- moveRightCell() {
603
- const numCols = csvToArray(this.colHeaders).length;
604
- if (this.tablePosition.column < numCols) {
605
- this.tablePosition.column++;
606
- this.focusCell(this.tablePosition);
607
- }
608
- }
609
- moveLeftTag() {
610
- const lastTag = this.tagEls[this.tagEls.length - 1];
611
- if (this.focusedTag && this.tagEls.includes(this.focusedTag.previousElementSibling)) {
612
- this.focusedTag = this.focusedTag.previousElementSibling;
613
- }
614
- else {
615
- this.focusedTag = lastTag;
616
- }
617
- // skip locked tags
618
- if (this.focusedTag.classList.contains("locked") && this.nonLockedTagEls.length > 0) {
619
- this.moveLeftTag();
620
- }
621
- else {
622
- this.focusTag(this.focusedTag);
623
- }
624
- }
625
- moveRightTag() {
626
- const firstTag = this.tagEls[0];
627
- if (this.focusedTag && this.tagEls.includes(this.focusedTag.nextElementSibling)) {
628
- this.focusedTag = this.focusedTag.nextElementSibling;
629
- }
630
- else {
631
- this.focusedTag = firstTag;
632
- }
633
- // skip locked tags
634
- if (this.focusedTag.classList.contains("locked")) {
635
- this.moveRightTag();
636
- }
637
- else {
638
- this.focusTag(this.focusedTag);
639
- }
640
- }
641
- addOption(option) {
642
- let newOptionsList = this.optionsList;
643
- const optionAlreadyExists = this.includesCaseInsensitive(this.optionsList, option);
644
- if (!optionAlreadyExists) {
645
- newOptionsList = newOptionsList.concat(option);
646
- }
647
- return newOptionsList;
648
- }
649
- removeOption(option) {
650
- this.optionsList = this.filterCaseInsensitive(this.optionsList, option);
651
- }
652
- addTag(tag) {
653
- let newTagsList = this.tagsList;
654
- const tagAlreadyAdded = this.includesCaseInsensitive(this.tagsList, tag);
655
- const tagExistsAsOption = this.optionsList.filter((x) => x.toLowerCase() === tag.toLowerCase())[0];
656
- if (!tagAlreadyAdded) {
657
- let textToAnnounce = tag;
658
- if (this.tagInputType === "table") {
659
- const referencedRow = this.el.querySelector(`#${tag}`);
660
- textToAnnounce = referencedRow.col1;
661
- }
662
- this.announce(this.generateTagAddedMessage(textToAnnounce));
663
- this.tagsList = newTagsList.concat(tagExistsAsOption || tag);
664
- // if maxTags has been reached, focus should go to the tagArea
665
- // otherwise, input field should be focused and in view
666
- if (this.tagLimitReached) {
667
- this.tagAreaEl.focus();
668
- }
669
- else {
670
- // wait for component to render new selected tag before bringing bottom of wrapper in view
671
- window.requestAnimationFrame(() => (this.tagsAndInputWrapperEl.scrollTop = this.tagsAndInputWrapperEl.scrollHeight));
627
+ if (this.isTable) {
628
+ // tooltip
629
+ const contentWrapper = this._focusedOption.querySelector(".cell-content-wrapper");
630
+ const isTruncated = contentWrapper.scrollWidth > contentWrapper.clientWidth;
631
+ this.dismissTooltip();
632
+ if (isTruncated) {
633
+ // innerText is necessary vs textContent, as innerText ignores sr-only / display: none text
634
+ showTooltip("bottom", this._focusedOption, this._focusedOption.innerText);
635
+ }
672
636
  }
637
+ optionToFocus.scrollIntoView({ block: "nearest" });
673
638
  }
674
639
  }
675
- removeTag(tag) {
676
- let textToAnnounce = tag;
677
- if (this.tagInputType === "table") {
678
- const referencedRow = this.el.querySelector(`#${tag}`);
679
- textToAnnounce = referencedRow.col1;
680
- }
681
- const tagRemovedMessage = intl.formatMessage({ id: "tagInput.tagRemoved", defaultMessage: "{tag} removed" }, { tag: textToAnnounce });
682
- this.announce(tagRemovedMessage);
683
- this.tagsList = this.filterCaseInsensitive(this.tagsList, tag);
684
- if (this.tagInputType === "dropdown") {
685
- // if a tag was introduced by the user, also remove it from the dropdown options
686
- const devOptionsList = csvToArray(this.options);
687
- if (this.includesCaseInsensitive(this.optionsList, tag) && !this.includesCaseInsensitive(devOptionsList, tag)) {
688
- this.removeOption(tag);
640
+ showTooltipIfTruncated(el) {
641
+ const displayedText = el.querySelector(".tag-text").textContent;
642
+ const id = el.id.replace("tag-", "");
643
+ if (id) {
644
+ const tagEl = this.el.querySelector("#" + id);
645
+ const fullText = this.getTagName(tagEl);
646
+ if (displayedText !== fullText && displayedText.includes("...")) {
647
+ showTooltip("bottom", el, fullText);
689
648
  }
690
649
  }
691
650
  }
692
- focusListItem(item) {
693
- this.focusedListItem = item;
694
- this.inputEl.setAttribute("aria-activedescendant", this.focusedListItem.id);
695
- item.scrollIntoView({ block: "nearest" });
696
- }
697
651
  focusTag(element) {
698
- if (element.classList.contains("locked")) {
699
- this.focusedTag = null;
700
- this.tagAreaEl.setAttribute("aria-activedescendant", "");
701
- }
702
- else {
703
- this.focusedTag = element;
704
- this.tagAreaEl.setAttribute("aria-activedescendant", this.focusedTag.id);
705
- this.focusedTag.scrollIntoView({ block: "nearest" });
706
- }
652
+ // technically it's the tag area that has focus. This function handles the aria-activedescendant value within that parent
653
+ this.focusedTagIndex = this.focusableTags.indexOf(element);
654
+ element.scrollIntoView({ block: "nearest" });
707
655
  window.requestAnimationFrame(() => {
708
656
  hideTooltip();
709
- const textEl = element.querySelector(".tag-text");
710
- const fullText = element.dataset.tag;
711
- const isTruncated = fullText !== textEl.textContent && textEl.textContent.includes("...");
712
- isTruncated && showTooltip("bottom", element, fullText);
657
+ this.showTooltipIfTruncated(element);
713
658
  });
714
659
  }
715
- focusCell(position) {
716
- this.clearCellFocus(false);
717
- if (position.row) {
718
- const rowToFocus = this.localRowEls[position.row];
719
- const rowCells = rowToFocus.querySelectorAll("td");
720
- const cellToFocus = rowCells[position.column - 1];
721
- const contentWrapper = cellToFocus.querySelector(".cell-content-wrapper");
722
- const isTruncated = contentWrapper.scrollWidth > contentWrapper.clientWidth;
723
- rowToFocus.classList.add("focused");
724
- cellToFocus.classList.add("focused");
725
- cellToFocus.scrollIntoView({ block: "nearest" });
726
- this.inputEl.setAttribute("aria-activedescendant", cellToFocus.id);
727
- this.dismissTooltip();
728
- if (isTruncated) {
729
- // innerText is necessary vs textContent, as innerText ignores sr-only / display: none text
730
- showTooltip("bottom", cellToFocus, cellToFocus.innerText);
731
- }
732
- }
733
- }
734
- clearTagFocus() {
735
- this.tagAreaEl.setAttribute("aria-activedescendant", "");
736
- this.focusedTag = null;
737
- }
738
- clearCellFocus(resetPosition = true) {
739
- this.inputEl.setAttribute("aria-activedescendant", "");
740
- if (resetPosition) {
741
- this.tablePosition = { row: 0, column: 1 };
742
- }
743
- this.localRowEls.forEach((row) => {
744
- row.classList.remove("focused");
745
- row.querySelectorAll("td").forEach((cell) => {
746
- cell.classList.remove("focused");
747
- });
748
- });
660
+ clearOptionFocus() {
661
+ this.focusedOption = undefined;
662
+ this.focusedColumn = 0;
749
663
  }
750
664
  openDropdown() {
751
665
  // offset of -2px to avoid overlapping the focus border
@@ -753,18 +667,10 @@ export class TagInput {
753
667
  this.isExpanded = true;
754
668
  }
755
669
  closeDropdown() {
756
- this.clearListItemFocus();
670
+ this.clearOptionFocus();
757
671
  this.isExpanded = false;
758
672
  }
759
- clearListItemFocus() {
760
- this.focusedListItem = null;
761
- this.inputEl.setAttribute("aria-activedescendant", "");
762
- this.listItemEls.forEach((el) => {
763
- el.classList.remove("focused");
764
- });
765
- }
766
673
  resetInput() {
767
- this.charCount = 0;
768
674
  this.inputEl.value = "";
769
675
  }
770
676
  announce(message) {
@@ -774,15 +680,25 @@ export class TagInput {
774
680
  }
775
681
  this.liveRegionMessage = message;
776
682
  }
683
+ addTags(tagNames) {
684
+ // covers both typing "," and pasting in text that includes ","
685
+ // if tag added without "," (typing enter), split puts the whole string in an array
686
+ this.lastAddedTags = tagNames.split(",").filter((t) => t.match(/\S/));
687
+ this.lastAddedTags.forEach((tag) => {
688
+ this.wmTagInputTagAdded.emit(tag);
689
+ });
690
+ this.announce(this.tagAddedMessage(this.lastAddedTags.join(", ")));
691
+ this.resetInput();
692
+ }
777
693
  announceExistingOptions() {
778
694
  // request animation frame to wait for re-rendering of filtered options
779
695
  window.requestAnimationFrame(() => {
780
696
  let numResults = 0;
781
- if (this.tagInputType === "dropdown") {
697
+ if (this.isDropdown) {
782
698
  numResults = this.optionEls.length;
783
699
  }
784
- else if (this.tagInputType === "table") {
785
- numResults = this.filteredRows.length;
700
+ else if (this.isTable) {
701
+ numResults = this.filteredOptionEls.length;
786
702
  }
787
703
  const existingOptionsMessage = intl.formatMessage({
788
704
  id: "tagInput.existingOptions",
@@ -799,117 +715,61 @@ export class TagInput {
799
715
  return message;
800
716
  }
801
717
  positionInput() {
802
- const lastTag = this.tagEls[this.tagEls.length - 1];
803
- // default placement to fall back to when no tags are present, or not enough space is available
804
- this.inputEl.style.position = "static";
805
- this.inputEl.style.width = "100%";
806
- this.inputEl.classList.add("extended");
807
- if (lastTag) {
808
- const spaceAvailable = this.tagAreaEl.getBoundingClientRect().right - lastTag.getBoundingClientRect().right;
809
- if (spaceAvailable >= this.inputMinimumWidth) {
810
- // because the input has right: 0px
811
- // all thats needed to properly place it is setting position: absolute, top, and width
812
- this.inputEl.style.position = "absolute";
813
- this.inputEl.style.top = lastTag.offsetTop.toString() + "px";
814
- this.inputEl.style.width = (spaceAvailable - 8).toString() + "px";
815
- this.inputEl.classList.remove("extended");
718
+ if (this.tagAreaEl) {
719
+ const lastTag = this._tagEls[this._tagEls.length - 1];
720
+ // default placement to fall back to when no tags are present, or not enough space is available
721
+ this.inputEl.style.position = "static";
722
+ this.inputEl.style.width = "100%";
723
+ this.inputEl.classList.add("extended");
724
+ if (lastTag) {
725
+ const spaceAvailable = this.tagAreaEl.getBoundingClientRect().right - lastTag.getBoundingClientRect().right;
726
+ if (spaceAvailable >= this.inputMinimumWidth) {
727
+ // because the input has right: 0px
728
+ // all thats needed to properly place it is setting position: absolute, top, and width
729
+ this.inputEl.style.position = "absolute";
730
+ this.inputEl.style.top = lastTag.offsetTop.toString() + "px";
731
+ this.inputEl.style.width = (spaceAvailable - 8).toString() + "px";
732
+ this.inputEl.classList.remove("extended");
733
+ }
816
734
  }
817
735
  }
818
736
  }
819
737
  handleTagMouseEnter(ev) {
820
- const displayedText = ev.target.querySelector(".tag-text").textContent;
821
- const fullText = ev.target.dataset.tag;
822
- const isTruncated = displayedText !== fullText && displayedText.includes("...");
823
- isTruncated && showTooltip("bottom", ev.target, fullText);
738
+ this.showTooltipIfTruncated(ev.target);
824
739
  }
825
740
  /// Helpers
826
741
  listToCSV(list) {
827
742
  return list.join(",");
828
743
  }
829
- includesCaseInsensitive(list, element) {
830
- const lowercaseList = list.map((str) => str.toLowerCase());
831
- return lowercaseList.includes(element.toLowerCase());
832
- }
833
- filterCaseInsensitive(list, element) {
834
- return list.filter((x) => x.toLowerCase() !== element.toLowerCase());
835
- }
836
- sortCaseInsensitive(list) {
837
- // The vanilla .sort method places words that start with capital letters above others (ASCII order)
838
- // so we need to pass in our own compare function to sort case-insensitive
839
- return list.sort((a, b) => {
840
- a = a.toLowerCase();
841
- b = b.toLowerCase();
842
- return a > b ? 1 : a < b ? -1 : 0;
843
- });
844
- }
845
- /// Renders
846
- renderTags() {
847
- let lockedTags = [];
848
- let unlockedTags = [];
849
- this.tagsList.forEach((tag, idx) => {
850
- const id = `tag${idx + 1}`;
851
- let tagText = "";
852
- let isLocked = false;
853
- if (this.tagInputType === "dropdown") {
854
- tagText = tag;
855
- }
856
- else if (this.tagInputType === "table") {
857
- // display table tags using col1 of the row with the same id
858
- // if one can't be found, display as empty
859
- const referencedRow = this.el.querySelector(`#${tag}`);
860
- tagText = referencedRow ? referencedRow.col1 : "";
861
- isLocked = referencedRow ? referencedRow.locked : false;
862
- }
863
- // make sure locked tags always appear in front of list
864
- const targetList = isLocked ? lockedTags : unlockedTags;
865
- targetList.push(h("li", { id: id, class: `tag highlight ${this.focusedTag && this.focusedTag.id === id ? "focused" : ""} ${isLocked ? "locked" : ""}`, "data-tag": tag, role: "option", onMouseEnter: (ev) => this.handleTagMouseEnter(ev), onMouseLeave: hideTooltip }, h("span", { class: "sr-only" }, tag), h("span", { class: "tag-text", "aria-hidden": "true" }, tagText), isLocked ? (h("div", { class: "icon lock" })) : (h("button", { class: "icon remove-btn", tabIndex: -1, onClick: () => this.handleRemoveButtonClick(tag) }))));
866
- });
867
- return [...lockedTags, ...unlockedTags];
744
+ isExistingTag(tag) {
745
+ const list = this.optionEls.map((o) => this.getTagName(o).toLowerCase());
746
+ return list.includes(tag.toLowerCase());
868
747
  }
869
748
  renderDropdown() {
870
- return (h("div", { class: `dropdown-wrapper ${this.isExpanded ? "open" : ""} ${this.openUp ? "upwards" : ""}`, ref: (el) => (this.dropdownEl = el) }, h("div", { id: "help-text", class: "help-text" }, this.renderHelpText()), h("ul", { class: "dropdown", id: "dropdown", role: "listbox", "aria-multiselectable": "true", "aria-expanded": this.isExpanded ? "true" : false, "aria-label": this.label, tabindex: -1 }, this.inputEl && this.renderAddNewButton(), this.renderListItems(this.optionsList))));
871
- }
872
- renderListItems(optionsList) {
873
- optionsList = this.sortCaseInsensitive(optionsList);
874
- // filter by input
875
- if (this.inputEl && this.inputEl.value) {
876
- optionsList = this.optionsList.filter((option) => option.toLowerCase().includes(this.inputEl.value.toLowerCase()));
877
- }
878
- return optionsList.map((option, idx) => {
879
- const id = `option${idx + 1}`;
880
- const isFocused = this.focusedListItem && this.focusedListItem.id === id;
881
- const isSelected = this.includesCaseInsensitive(this.tagsList, option);
882
- return (h("li", { class: `option ${isFocused ? "focused" : ""}`, role: "option", id: id, "data-option": option, "aria-selected": isSelected ? "true" : "false", "aria-disabled": isSelected ? "true" : "false", onKeyDown: (ev) => this.handleListItemKeyDown(ev), onBlur: (ev) => this.handleBlur(ev, this.el), onClick: (ev) => this.handleListItemClick(ev.target) }, option));
883
- });
884
- }
885
- renderAddNewButton() {
886
- const hasNonWhiteSpaceCharacters = this.inputEl.value.match(/\S/);
887
- const optionAlreadyExists = this.includesCaseInsensitive(this.optionsList, this.inputEl.value.trim());
888
- if (this.addNew && hasNonWhiteSpaceCharacters && !optionAlreadyExists) {
889
- const id = `add-new-btn`;
890
- const isFocused = this.focusedListItem && this.focusedListItem.id === id;
891
- return (h("li", { role: "option", class: `add-new-btn ${isFocused ? "focused" : ""}`, id: id, "data-option": this.inputEl.value, onKeyDown: (ev) => this.handleListItemKeyDown(ev), onBlur: (ev) => this.handleBlur(ev, this.el), onClick: (ev) => this.handleListItemClick(ev.target), tabIndex: isFocused ? 0 : -1 }, `Add "${this.inputEl.value.trim()}"`));
892
- }
893
- else
894
- return "";
749
+ return (h("div", { class: `dropdown-wrapper ${this.isExpanded ? "open" : ""} ${this.openUp ? "upwards" : ""}`, ref: (el) => (this.dropdownEl = el) }, h("div", { id: "help-text", class: "help-text" }, this.renderHelpText()), h("ul", { class: "dropdown", id: "dropdown", role: "listbox", "aria-multiselectable": "true", "aria-expanded": this.isExpanded ? "true" : "false", "aria-label": this.label, tabindex: -1 }, this.inputEl && this.renderAddNewButton(), this.filteredOptionEls.map((o) => this.renderListItem(o)))));
895
750
  }
896
751
  renderHelpText() {
752
+ if (this.helpText)
753
+ return this.helpText;
897
754
  let helpText = "";
898
- if (this.optionsList.length > 0) {
899
- helpText += this.componentMessages.selectionHelpText;
755
+ if (this._tagEls.length > 0) {
756
+ helpText += this.selectionHelpText;
900
757
  }
901
758
  if (this.addNew) {
902
- helpText += " " + this.componentMessages.addNewHelpText;
759
+ helpText += " " + this.addNewHelpText;
903
760
  }
904
761
  return helpText;
905
762
  }
906
- renderTagCounter() {
907
- if (this.maxTags) {
908
- return (h("div", { class: "lower-row" }, h("div", { id: "max-tags" }, `${this.componentMessages.tagsAdded}: ${this.tagsList.length}/${this.maxTags}`, this.tagLimitReached && ` - ${this.componentMessages.maxTagsReached}`)));
909
- }
763
+ renderAddNewButton() {
764
+ const inputValue = this.inputEl.value.trim();
765
+ const hasNonWhiteSpaceCharacters = this.inputEl.value.match(/\S/);
766
+ const optionAlreadyExists = this.isExistingTag(this.inputEl.value.trim());
767
+ return (this.addNew &&
768
+ hasNonWhiteSpaceCharacters &&
769
+ !optionAlreadyExists && (h("li", { ref: (el) => (this.addNewButton = el), id: "add-new-btn", class: "add-new-btn", onClick: () => this.addTags(inputValue) }, "Add " + inputValue)));
910
770
  }
911
771
  renderTable() {
912
- return (h("div", { class: "table-wrapper", onScroll: () => this.dismissTooltip() }, h("table", { id: "table", role: "grid", class: `${this.colWidths ? "fixed-widths" : ""}`, "aria-label": this.label, "aria-multiselectable": "true" }, this.renderTableHeaders(), this.filteredRows.length ? this.renderTableRows() : h("div", { class: "no-results" }, this.noResultsMessage))));
772
+ return (h("div", { class: "table-wrapper", onScroll: () => this.dismissTooltip() }, h("table", { id: "table", role: "grid", class: `${this.colWidths ? "fixed-widths" : ""}`, "aria-label": this.label, "aria-multiselectable": "true" }, this.renderTableHeaders(), this.filteredOptionEls.length ? (this.filteredOptionEls.map((o) => this.renderTableRow(o))) : (h("div", { class: "no-results" }, this.noResultsMessage)))));
913
773
  }
914
774
  renderTableHeaders() {
915
775
  return (h("tr", { class: "headers", role: "row" }, csvToArray(this.colHeaders).map((header, idx) => {
@@ -922,31 +782,76 @@ export class TagInput {
922
782
  width: this.colWidths ? csvToArray(this.colWidths)[idx] : "" }, header));
923
783
  })));
924
784
  }
925
- renderTableRows() {
926
- return this.filteredRows.map((row) => {
927
- const isSelected = this.includesCaseInsensitive(this.tagsList, row.id);
928
- return (h("tr", { id: row.id, class: `${row.locked ? "locked" : ""} ${isSelected ? "selected" : ""}`, role: "row", onClick: () => this.handleTableRowClick(row.id) }, this.renderTableCells(row)));
929
- });
785
+ renderTag(o) {
786
+ const focused = this.focusedTag && this.focusedTag.id === "tag-" + o.id ? "focused" : "";
787
+ const tagName = this.getTagName(o);
788
+ const highlight = this.lastAddedTags.includes(tagName) ? "highlight" : "";
789
+ return (h("li", { id: "tag-" + o.id, role: "option", class: `tag ${highlight} ${focused} ${o.locked ? "locked" : ""}`, onMouseEnter: (ev) => this.handleTagMouseEnter(ev), onMouseLeave: hideTooltip }, h("span", { class: "sr-only" }, tagName), h("span", { class: "tag-text", "aria-hidden": "true" }, tagName), o.locked ? (h("div", { class: "icon lock" })) : (h("button", { class: "icon remove-btn", tabIndex: -1, onClick: () => o.emitDeselectedEvent() }))));
790
+ }
791
+ renderTags() {
792
+ return this.tagsList.map((o) => this.renderTag(o));
793
+ }
794
+ renderTagCounter() {
795
+ if (this.maxTags) {
796
+ return (h("div", { class: "lower-row" }, h("div", { id: "max-tags" }, this.renderMaxTags())));
797
+ }
798
+ }
799
+ renderMaxTags() {
800
+ if (this.helpText) {
801
+ return this.helpText;
802
+ }
803
+ else {
804
+ let msg = `${this.tagsAddedMessage}: ${this.taggedOptions.length}/${this.maxTags}`;
805
+ if (this.tagLimitReached) {
806
+ msg += `- ${this.maxTagsReachedMessage}`;
807
+ }
808
+ return msg;
809
+ }
810
+ }
811
+ handleCellMouseEnter(ev) {
812
+ const cell = ev.target;
813
+ const contentWrapper = cell.querySelector(".cell-content-wrapper");
814
+ const isTruncated = contentWrapper.scrollWidth > contentWrapper.clientWidth;
815
+ if (isTruncated) {
816
+ // innerText is necessary vs textContent, as innerText ignores sr-only / display: none text
817
+ showTooltip("bottom", cell, cell.innerText);
818
+ }
930
819
  }
931
- renderTableCells(row) {
932
- const colValues = [row.col1, row.col2, row.col3, row.col4].filter((val) => !!val);
933
- const isSelected = this.includesCaseInsensitive(this.tagsList, row.id);
820
+ renderTableCells(o) {
821
+ const colValues = [o.col1, o.col2, o.col3, o.col4].filter((val) => !!val);
934
822
  return colValues.map((val, idx) => {
935
- const localId = `${row.id}-col${idx + 1}`;
823
+ const cellId = `${o.id}-col${idx + 1}`;
936
824
  let overflowRule = "wrap";
937
825
  if (this.colWrap && csvToArray(this.colWrap)[idx]) {
938
826
  overflowRule = csvToArray(this.colWrap)[idx];
939
827
  }
940
- return (h("td", { id: localId, role: "gridcell", "aria-describedby": `${localId}-description`, "aria-selected": isSelected.toString(), onMouseEnter: (ev) => this.handleCellMouseEnter(ev), onMouseLeave: () => this.dismissTooltip() }, h("div", { class: `cell-content-wrapper ${overflowRule}` }, val), h("div", { class: "description", id: `${localId}-description` }, row.locked ? "locked" : "")));
828
+ const classes = {
829
+ focused: !!this._focusedCell && cellId === this._focusedCell.id,
830
+ };
831
+ return (h("td", { id: cellId, class: classes, role: "gridcell", "aria-describedby": `${cellId}-description`, "aria-selected": o.selected ? "true" : "false", onMouseEnter: (ev) => this.handleCellMouseEnter(ev), onMouseLeave: () => hideTooltip() }, h("div", { class: `cell-content-wrapper ${overflowRule}` }, val), h("div", { class: "description", id: `${cellId}-description` }, o.locked ? "locked" : "")));
941
832
  });
942
833
  }
834
+ renderTableRow(o) {
835
+ const classes = {
836
+ selected: o.selected,
837
+ locked: o.locked,
838
+ focused: this.focusedOption && o === this.focusedOption ? true : false,
839
+ };
840
+ return (h("tr", { id: o.id, class: classes, onClick: (ev) => this.handleOptionClick(ev) }, this.renderTableCells(o)));
841
+ }
842
+ renderListItem(o) {
843
+ if (!!this.inputEl) {
844
+ const isFocused = this.focusedOption && o === this.focusedOption;
845
+ return (h("li", { id: o.id, role: "option", class: `option ${isFocused ? "focused" : ""}`, "aria-selected": o.selected ? "true" : "false", onClick: (ev) => this.handleOptionClick(ev) }, o.textContent));
846
+ }
847
+ }
943
848
  render() {
944
- return (h(Host, { id: this.uid }, h("div", { class: `wrapper label-${this.labelPosition} ${this.errorMessage ? "invalid" : ""}` }, h("div", { class: "label-wrapper" }, h("label", { class: "label", htmlFor: `input${this.uid}` }, this.label, this.requiredField && (h("span", { class: "required", "aria-hidden": "true" }, "*")))), h("div", { class: `field-wrapper ${this.focusedElement ? "focused" : ""} ${this.errorMessage ? "invalid" : ""}`, ref: (el) => (this.fieldWrapperEl = el) }, h("div", { class: "upper-row" }, h("div", { class: `tags-and-input-wrapper ${this.inModal ? "in-modal" : ""}`, ref: (el) => (this.tagsAndInputWrapperEl = el) }, this.tagsList.length > 0 && (h("ul", { ref: (el) => (this.tagAreaEl = el), class: "tag-area", role: "listbox", "aria-activedescendant": "", "aria-orientation": "horizontal", "aria-label": `${this.label} ${this.tagsList.length > 0 ? this.componentMessages.tagAreaInstructions : ""}`, tabindex: this.nonLockedTagsList.length > 0 ? 0 : -1, "aria-describedby": `info max-tags`, onFocus: () => this.handleTagAreaFocus(), onBlur: (ev) => {
945
- this.clearTagFocus();
946
- this.handleBlur(ev, this.el);
947
- }, onKeyDown: (ev) => this.handleTagAreaKeyDown(ev) }, this.renderTags())), h("input", { id: `input${this.uid}`, class: `input ${this.tagLimitReached ? "hidden" : ""}`, role: "combobox", ref: (el) => (this.inputEl = el), autocomplete: "off", "aria-required": this.requiredField ? "true" : null, "aria-controls": this.tagInputType, "aria-describedby": `help-text${this.errorMessage ? " error " : ""}`, "aria-label": `${this.label} ${this.tagInputType === "dropdown" ? globalMessages.getCharacterLimit(this.characterLimit) : ""}`, "aria-expanded": this.tagInputType === "dropdown" ? this.isExpanded.toString() : null, placeholder: this.placeholder, maxLength: this.tagInputType === "dropdown" ? this.characterLimit : undefined, onInput: () => this.handleInputChanged(this.inputEl.value), onBlur: (ev) => {
948
- this.handleBlur(ev, this.el);
949
- }, onFocus: () => this.handleInputFocus(), onKeyDown: (ev) => this.handleInputKeyDown(ev) })), this.tagInputType === "dropdown" && (h("div", { class: "character-count" }, this.charCount, "/", this.characterLimit))), this.renderTagCounter(), this.tagInputType === "dropdown" && this.renderDropdown()), this.info && (h("div", { id: "info", class: "info-text" }, this.info)), this.errorMessage && h("div", { id: "error" }, this.errorMessage), h("div", { class: "sr-only", "aria-live": "assertive", ref: (el) => (this.liveRegionEl = el), "aria-atomic": "true" }, this.liveRegionMessage), this.tagInputType === "table" && this.renderTable())));
849
+ return (h("div", { class: `wrapper label-${this.labelPosition} ${this.errorMessage ? "invalid" : ""}` }, h("div", { class: "label-wrapper" }, h("label", { class: "label", htmlFor: "input" }, this.label, this.requiredField && (h("span", { class: "required", "aria-hidden": "true" }, "*")))), h("div", { class: `field-wrapper ${this.el.shadowRoot.activeElement === this.inputEl ? "focused" : ""} ${this.errorMessage ? "invalid" : ""}`, ref: (el) => (this.fieldWrapperEl = el) }, h("div", { class: "upper-row" }, h("div", { class: `tags-and-input-wrapper ${this.inModal ? "in-modal" : ""}` }, h("ul", { ref: (el) => (this.tagAreaEl = el), class: `tag-area ${this.taggedOptions.length === 0 && "empty"}`, role: "listbox", "aria-activedescendant": this.focusedTag ? this.focusedTag.id : null, "aria-orientation": "horizontal", "aria-label": `${this.label} ${this.tagAreaInstructions}`, tabindex: this.focusableTags.length > 0 ? 0 : -1, "aria-describedby": `info max-tags`, onFocus: (ev) => this.handleTagAreaFocus(ev), onBlur: (ev) => {
850
+ this.focusedTagIndex = undefined;
851
+ this.handleBlur(ev);
852
+ }, onKeyDown: (ev) => this.handleTagAreaKeyDown(ev) }, this.renderTags()), h("input", { id: "input", class: "input", role: "combobox", ref: (el) => (this.inputEl = el), autocomplete: "off", "aria-required": this.requiredField ? "true" : null, "aria-controls": this.tagInputType, "aria-describedby": `help-text${this.errorMessage ? " error " : ""}`, "aria-label": `${this.label} ${this.isDropdown ? globalMessages.getCharacterLimit(this.characterLimit) : ""}`, "aria-expanded": this.isDropdown ? this.isExpanded.toString() : null, "aria-activedescendant": this.inputActiveDescendantId, placeholder: this.placeholder, maxLength: this.isDropdown ? this.characterLimit : undefined, onInput: (ev) => this.handleInputChanged(ev), onBlur: (ev) => {
853
+ this.handleBlur(ev);
854
+ }, onFocus: () => this.handleInputFocus(), onKeyDown: (ev) => this.handleInputKeyDown(ev) })), this.isDropdown && (h("div", { class: "character-count" }, this.charCount, "/", this.characterLimit))), this.renderTagCounter(), this.isDropdown && this.renderDropdown()), this.info && (h("div", { id: "info", class: "info-text" }, this.info)), this.errorMessage && h("div", { id: "error" }, this.errorMessage), h("div", { class: "sr-only", "aria-live": "assertive", ref: (el) => (this.liveRegionEl = el), "aria-atomic": "true" }, this.liveRegionMessage), this.isTable && this.renderTable()));
950
855
  }
951
856
  static get is() { return "wm-tag-input"; }
952
857
  static get encapsulation() { return "shadow"; }
@@ -980,59 +885,22 @@ export class TagInput {
980
885
  "attribute": "label",
981
886
  "reflect": false
982
887
  },
983
- "labelPosition": {
888
+ "errorMessage": {
984
889
  "type": "string",
985
890
  "mutable": false,
986
- "complexType": {
987
- "original": "\"top\" | \"left\" | \"none\"",
988
- "resolved": "\"left\" | \"none\" | \"top\"",
989
- "references": {}
990
- },
991
- "required": false,
992
- "optional": false,
993
- "docs": {
994
- "tags": [],
995
- "text": ""
996
- },
997
- "attribute": "label-position",
998
- "reflect": false,
999
- "defaultValue": "\"top\""
1000
- },
1001
- "options": {
1002
- "type": "string",
1003
- "mutable": true,
1004
- "complexType": {
1005
- "original": "string",
1006
- "resolved": "string",
1007
- "references": {}
1008
- },
1009
- "required": false,
1010
- "optional": false,
1011
- "docs": {
1012
- "tags": [],
1013
- "text": ""
1014
- },
1015
- "attribute": "options",
1016
- "reflect": false,
1017
- "defaultValue": "\"\""
1018
- },
1019
- "selectedTags": {
1020
- "type": "string",
1021
- "mutable": true,
1022
891
  "complexType": {
1023
892
  "original": "string",
1024
- "resolved": "string",
893
+ "resolved": "string | undefined",
1025
894
  "references": {}
1026
895
  },
1027
896
  "required": false,
1028
- "optional": false,
897
+ "optional": true,
1029
898
  "docs": {
1030
899
  "tags": [],
1031
900
  "text": ""
1032
901
  },
1033
- "attribute": "selected-tags",
1034
- "reflect": true,
1035
- "defaultValue": "\"\""
902
+ "attribute": "error-message",
903
+ "reflect": false
1036
904
  },
1037
905
  "info": {
1038
906
  "type": "string",
@@ -1051,40 +919,40 @@ export class TagInput {
1051
919
  "attribute": "info",
1052
920
  "reflect": false
1053
921
  },
1054
- "errorMessage": {
922
+ "labelPosition": {
1055
923
  "type": "string",
1056
924
  "mutable": false,
1057
925
  "complexType": {
1058
- "original": "string",
1059
- "resolved": "string | undefined",
926
+ "original": "\"top\" | \"left\" | \"none\"",
927
+ "resolved": "\"left\" | \"none\" | \"top\"",
1060
928
  "references": {}
1061
929
  },
1062
930
  "required": false,
1063
- "optional": true,
931
+ "optional": false,
1064
932
  "docs": {
1065
933
  "tags": [],
1066
934
  "text": ""
1067
935
  },
1068
- "attribute": "error-message",
1069
- "reflect": false
936
+ "attribute": "label-position",
937
+ "reflect": false,
938
+ "defaultValue": "\"top\""
1070
939
  },
1071
- "addNew": {
1072
- "type": "boolean",
940
+ "maxTags": {
941
+ "type": "number",
1073
942
  "mutable": false,
1074
943
  "complexType": {
1075
- "original": "boolean",
1076
- "resolved": "boolean",
944
+ "original": "number",
945
+ "resolved": "number | undefined",
1077
946
  "references": {}
1078
947
  },
1079
948
  "required": false,
1080
- "optional": false,
949
+ "optional": true,
1081
950
  "docs": {
1082
951
  "tags": [],
1083
952
  "text": ""
1084
953
  },
1085
- "attribute": "add-new",
1086
- "reflect": false,
1087
- "defaultValue": "true"
954
+ "attribute": "max-tags",
955
+ "reflect": false
1088
956
  },
1089
957
  "placeholder": {
1090
958
  "type": "string",
@@ -1121,12 +989,12 @@ export class TagInput {
1121
989
  "reflect": false,
1122
990
  "defaultValue": "false"
1123
991
  },
1124
- "characterLimit": {
1125
- "type": "number",
992
+ "tagInputType": {
993
+ "type": "string",
1126
994
  "mutable": false,
1127
995
  "complexType": {
1128
- "original": "number",
1129
- "resolved": "number",
996
+ "original": "\"dropdown\" | \"table\"",
997
+ "resolved": "\"dropdown\" | \"table\"",
1130
998
  "references": {}
1131
999
  },
1132
1000
  "required": false,
@@ -1135,16 +1003,16 @@ export class TagInput {
1135
1003
  "tags": [],
1136
1004
  "text": ""
1137
1005
  },
1138
- "attribute": "character-limit",
1006
+ "attribute": "tag-input-type",
1139
1007
  "reflect": false,
1140
- "defaultValue": "50"
1008
+ "defaultValue": "\"dropdown\""
1141
1009
  },
1142
- "maxTags": {
1143
- "type": "number",
1010
+ "helpText": {
1011
+ "type": "string",
1144
1012
  "mutable": false,
1145
1013
  "complexType": {
1146
- "original": "number",
1147
- "resolved": "number | undefined",
1014
+ "original": "string",
1015
+ "resolved": "string | undefined",
1148
1016
  "references": {}
1149
1017
  },
1150
1018
  "required": false,
@@ -1153,15 +1021,15 @@ export class TagInput {
1153
1021
  "tags": [],
1154
1022
  "text": ""
1155
1023
  },
1156
- "attribute": "max-tags",
1024
+ "attribute": "help-text",
1157
1025
  "reflect": false
1158
1026
  },
1159
- "tagInputType": {
1160
- "type": "string",
1027
+ "addNew": {
1028
+ "type": "boolean",
1161
1029
  "mutable": false,
1162
1030
  "complexType": {
1163
- "original": "\"dropdown\" | \"table\"",
1164
- "resolved": "\"dropdown\" | \"table\"",
1031
+ "original": "boolean",
1032
+ "resolved": "boolean",
1165
1033
  "references": {}
1166
1034
  },
1167
1035
  "required": false,
@@ -1170,9 +1038,27 @@ export class TagInput {
1170
1038
  "tags": [],
1171
1039
  "text": ""
1172
1040
  },
1173
- "attribute": "tag-input-type",
1041
+ "attribute": "add-new",
1174
1042
  "reflect": false,
1175
- "defaultValue": "\"dropdown\""
1043
+ "defaultValue": "true"
1044
+ },
1045
+ "characterLimit": {
1046
+ "type": "number",
1047
+ "mutable": false,
1048
+ "complexType": {
1049
+ "original": "number",
1050
+ "resolved": "number",
1051
+ "references": {}
1052
+ },
1053
+ "required": false,
1054
+ "optional": false,
1055
+ "docs": {
1056
+ "tags": [],
1057
+ "text": ""
1058
+ },
1059
+ "attribute": "character-limit",
1060
+ "reflect": false,
1061
+ "defaultValue": "50"
1176
1062
  },
1177
1063
  "colHeaders": {
1178
1064
  "type": "string",
@@ -1224,43 +1110,23 @@ export class TagInput {
1224
1110
  },
1225
1111
  "attribute": "col-wrap",
1226
1112
  "reflect": false
1227
- },
1228
- "messageConfig": {
1229
- "type": "string",
1230
- "mutable": false,
1231
- "complexType": {
1232
- "original": "string",
1233
- "resolved": "string",
1234
- "references": {}
1235
- },
1236
- "required": false,
1237
- "optional": false,
1238
- "docs": {
1239
- "tags": [],
1240
- "text": ""
1241
- },
1242
- "attribute": "message-config",
1243
- "reflect": false,
1244
- "defaultValue": "\"\""
1245
1113
  }
1246
1114
  };
1247
1115
  }
1248
1116
  static get states() {
1249
1117
  return {
1250
- "focusedListItem": {},
1251
- "focusedTag": {},
1252
- "tablePosition": {},
1253
1118
  "isExpanded": {},
1254
- "tagsList": {},
1255
- "optionsList": {},
1256
- "charCount": {},
1257
- "liveRegionMessage": {}
1119
+ "liveRegionMessage": {},
1120
+ "focusedOption": {},
1121
+ "focusedColumn": {},
1122
+ "focusedTagIndex": {},
1123
+ "tagsList": {}
1258
1124
  };
1259
1125
  }
1260
1126
  static get events() {
1261
1127
  return [{
1262
- "method": "wmTagInputChanged",
1263
- "name": "wmTagInputChanged",
1128
+ "method": "wmTagInputTagAdded",
1129
+ "name": "wmTagInputTagAdded",
1264
1130
  "bubbles": true,
1265
1131
  "cancelable": true,
1266
1132
  "composed": true,
@@ -1269,36 +1135,35 @@ export class TagInput {
1269
1135
  "text": ""
1270
1136
  },
1271
1137
  "complexType": {
1272
- "original": "{\n value: string[] | HTMLWmTagInputRowElement[];\n tagChanged: string | HTMLWmTagInputRowElement;\n }",
1273
- "resolved": "{ value: string[] | HTMLWmTagInputRowElement[]; tagChanged: string | HTMLWmTagInputRowElement; }",
1274
- "references": {
1275
- "HTMLWmTagInputRowElement": {
1276
- "location": "global"
1277
- }
1278
- }
1138
+ "original": "any",
1139
+ "resolved": "any",
1140
+ "references": {}
1279
1141
  }
1280
1142
  }];
1281
1143
  }
1282
1144
  static get elementRef() { return "el"; }
1283
1145
  static get watchers() {
1284
1146
  return [{
1285
- "propName": "tagsList",
1286
- "methodName": "reflectSelectedTags"
1287
- }, {
1288
1147
  "propName": "errorMessage",
1289
1148
  "methodName": "handleErrorMessageChange"
1290
1149
  }];
1291
1150
  }
1292
1151
  static get listeners() {
1293
1152
  return [{
1294
- "name": "wmTagInputRowUpdated",
1295
- "method": "handleRowUpdate",
1153
+ "name": "privTagOptionSelected",
1154
+ "method": "handleTagOptionSelected",
1155
+ "target": undefined,
1156
+ "capture": false,
1157
+ "passive": false
1158
+ }, {
1159
+ "name": "privTagOptionDeselected",
1160
+ "method": "handleTagOptionDeselected",
1296
1161
  "target": undefined,
1297
1162
  "capture": false,
1298
1163
  "passive": false
1299
1164
  }, {
1300
1165
  "name": "click",
1301
- "method": "closeIfNotElOrChild",
1166
+ "method": "handleClick",
1302
1167
  "target": "document",
1303
1168
  "capture": false,
1304
1169
  "passive": false
@@ -1308,6 +1173,12 @@ export class TagInput {
1308
1173
  "target": "window",
1309
1174
  "capture": true,
1310
1175
  "passive": true
1176
+ }, {
1177
+ "name": "blur",
1178
+ "method": "handleBlur",
1179
+ "target": undefined,
1180
+ "capture": false,
1181
+ "passive": false
1311
1182
  }];
1312
1183
  }
1313
1184
  }