@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.
- package/dist/cjs/{chartFunctions-33cb3097.js → chartFunctions-f5ded027.js} +1 -1
- package/dist/cjs/{functions-833ccc83.js → functions-e7db4a26.js} +67 -824
- package/dist/cjs/{global-d57c118b.js → global-b33cf49b.js} +1 -1
- package/dist/cjs/{intl-ab07bd0b.js → intl-9ef93563.js} +3 -3
- package/dist/cjs/loader.cjs.js +3 -3
- package/dist/cjs/priv-chart-popover.cjs.entry.js +1 -1
- package/dist/cjs/priv-datepicker.cjs.entry.js +1 -1
- package/dist/cjs/ripple.cjs.js +3 -3
- package/dist/cjs/wm-action-menu_2.cjs.entry.js +2 -2
- package/dist/cjs/wm-button.cjs.entry.js +1 -1
- package/dist/cjs/wm-chart.cjs.entry.js +4 -4
- package/dist/cjs/wm-datepicker.cjs.entry.js +1 -1
- package/dist/cjs/wm-file.cjs.entry.js +7 -4
- package/dist/cjs/wm-input.cjs.entry.js +4 -9
- package/dist/cjs/wm-line-chart.cjs.entry.js +3 -3
- package/dist/cjs/wm-modal-header.cjs.entry.js +2 -2
- package/dist/cjs/wm-modal.cjs.entry.js +1 -1
- package/dist/cjs/wm-navigation_3.cjs.entry.js +2 -2
- package/dist/cjs/wm-navigator.cjs.entry.js +1 -1
- package/dist/cjs/wm-option_2.cjs.entry.js +68 -119
- package/dist/cjs/wm-pagination.cjs.entry.js +1 -1
- package/dist/cjs/wm-progress-indicator_3.cjs.entry.js +4 -4
- package/dist/cjs/wm-search.cjs.entry.js +2 -2
- package/dist/cjs/wm-snackbar.cjs.entry.js +2 -2
- package/dist/cjs/wm-tab-item_3.cjs.entry.js +2 -2
- package/dist/cjs/wm-tag-input.cjs.entry.js +521 -617
- package/dist/cjs/wm-tag-option.cjs.entry.js +43 -0
- package/dist/cjs/wm-timepicker.cjs.entry.js +1 -1
- package/dist/cjs/wm-toggletip.cjs.entry.js +1 -1
- package/dist/cjs/wm-uploader.cjs.entry.js +2 -2
- package/dist/collection/collection-manifest.json +3 -3
- package/dist/collection/components/charts/wm-chart/wm-chart.css +0 -1
- package/dist/collection/components/charts/wm-progress-monitor/wm-progress-indicator.css +0 -1
- package/dist/collection/components/charts/wm-progress-monitor/wm-progress-monitor.css +9 -1
- package/dist/collection/components/wm-file/wm-file.js +23 -3
- package/dist/collection/components/wm-file/wm-file.spec.js +83 -34
- package/dist/collection/components/wm-file-list/wm-file-list.spec.js +32 -59
- package/dist/collection/components/wm-input/wm-input.js +1 -8
- package/dist/collection/components/wm-menuitem/wm-menuitem.js +1 -1
- package/dist/collection/components/wm-option/wm-option.css +6 -6
- package/dist/collection/components/wm-option/wm-option.js +47 -3
- package/dist/collection/components/wm-select/wm-select.e2e.js +60 -114
- package/dist/collection/components/wm-select/wm-select.js +80 -141
- package/dist/collection/components/wm-select/wm-select.spec.js +9 -11
- package/dist/collection/components/wm-tabs/wm-tab-list/wm-tab-list.css +0 -1
- package/dist/collection/components/wm-tag-input/wm-tag-input.css +19 -22
- package/dist/collection/components/wm-tag-input/wm-tag-input.e2e.js +3 -3
- package/dist/collection/components/wm-tag-input/wm-tag-input.js +597 -726
- package/dist/collection/components/wm-tag-input/wm-tag-option/wm-tag-option.js +241 -0
- package/dist/collection/components/wm-uploader/wm-uploader.e2e.js +26 -47
- package/dist/collection/components/wm-uploader/wm-uploader.js +3 -3
- package/dist/collection/components/wm-uploader/wm-uploader.spec.js +67 -140
- package/dist/collection/global/functions.js +22 -10
- package/dist/collection/global/intl.js +2 -2
- package/dist/collection/lang/lang.spec.js +2 -2
- package/dist/esm/{chartFunctions-36eb2d1a.js → chartFunctions-2a4603c6.js} +1 -1
- package/dist/esm/{functions-061ab506.js → functions-358a1a02.js} +66 -824
- package/dist/esm/{global-509460f7.js → global-ba03a879.js} +1 -1
- package/dist/esm/{intl-d698d52f.js → intl-48057c4d.js} +3 -3
- package/dist/esm/loader.js +3 -3
- package/dist/esm/polyfills/core-js.js +0 -0
- package/dist/esm/polyfills/dom.js +0 -0
- package/dist/esm/polyfills/es5-html-element.js +0 -0
- package/dist/esm/polyfills/index.js +0 -0
- package/dist/esm/polyfills/system.js +0 -0
- package/dist/esm/priv-chart-popover.entry.js +1 -1
- package/dist/esm/priv-datepicker.entry.js +1 -1
- package/dist/esm/ripple.js +3 -3
- package/dist/esm/wm-action-menu_2.entry.js +2 -2
- package/dist/esm/wm-button.entry.js +1 -1
- package/dist/esm/wm-chart.entry.js +4 -4
- package/dist/esm/wm-datepicker.entry.js +1 -1
- package/dist/esm/wm-file.entry.js +7 -4
- package/dist/esm/wm-input.entry.js +4 -9
- package/dist/esm/wm-line-chart.entry.js +3 -3
- package/dist/esm/wm-modal-header.entry.js +2 -2
- package/dist/esm/wm-modal.entry.js +1 -1
- package/dist/esm/wm-navigation_3.entry.js +2 -2
- package/dist/esm/wm-navigator.entry.js +1 -1
- package/dist/esm/wm-option_2.entry.js +68 -119
- package/dist/esm/wm-pagination.entry.js +1 -1
- package/dist/esm/wm-progress-indicator_3.entry.js +4 -4
- package/dist/esm/wm-search.entry.js +2 -2
- package/dist/esm/wm-snackbar.entry.js +2 -2
- package/dist/esm/wm-tab-item_3.entry.js +2 -2
- package/dist/esm/wm-tag-input.entry.js +522 -618
- package/dist/esm/wm-tag-option.entry.js +39 -0
- package/dist/esm/wm-timepicker.entry.js +1 -1
- package/dist/esm/wm-toggletip.entry.js +1 -1
- package/dist/esm/wm-uploader.entry.js +2 -2
- package/dist/esm-es5/{chartFunctions-36eb2d1a.js → chartFunctions-2a4603c6.js} +1 -1
- package/dist/esm-es5/functions-358a1a02.js +1 -0
- package/dist/esm-es5/global-ba03a879.js +1 -0
- package/dist/esm-es5/{intl-d698d52f.js → intl-48057c4d.js} +1 -1
- package/dist/esm-es5/loader.js +1 -1
- package/dist/esm-es5/priv-chart-popover.entry.js +1 -1
- package/dist/esm-es5/priv-datepicker.entry.js +1 -1
- package/dist/esm-es5/ripple.js +1 -1
- package/dist/esm-es5/wm-action-menu_2.entry.js +1 -1
- package/dist/esm-es5/wm-button.entry.js +1 -1
- package/dist/esm-es5/wm-chart.entry.js +1 -1
- package/dist/esm-es5/wm-datepicker.entry.js +1 -1
- package/dist/esm-es5/wm-file.entry.js +1 -1
- package/dist/esm-es5/wm-input.entry.js +1 -1
- package/dist/esm-es5/wm-line-chart.entry.js +1 -1
- package/dist/esm-es5/wm-modal-header.entry.js +1 -1
- package/dist/esm-es5/wm-modal.entry.js +1 -1
- package/dist/esm-es5/wm-navigation_3.entry.js +1 -1
- package/dist/esm-es5/wm-navigator.entry.js +1 -1
- package/dist/esm-es5/wm-option_2.entry.js +1 -1
- package/dist/esm-es5/wm-pagination.entry.js +1 -1
- package/dist/esm-es5/wm-progress-indicator_3.entry.js +1 -1
- package/dist/esm-es5/wm-search.entry.js +1 -1
- package/dist/esm-es5/wm-snackbar.entry.js +1 -1
- package/dist/esm-es5/wm-tab-item_3.entry.js +1 -1
- package/dist/esm-es5/wm-tag-input.entry.js +1 -1
- package/dist/esm-es5/wm-tag-option.entry.js +1 -0
- package/dist/esm-es5/wm-timepicker.entry.js +1 -1
- package/dist/esm-es5/wm-toggletip.entry.js +1 -1
- package/dist/esm-es5/wm-uploader.entry.js +1 -1
- package/dist/ripple/{p-3f159fa3.entry.js → p-05ef4092.entry.js} +1 -1
- package/dist/ripple/p-11d629cb.system.entry.js +1 -0
- package/dist/ripple/p-126fbcdb.entry.js +1 -0
- package/dist/ripple/p-12a140e0.system.entry.js +1 -0
- package/dist/ripple/{p-e61e2d7f.entry.js → p-191fafc6.entry.js} +1 -1
- package/dist/ripple/p-1ab62a21.system.entry.js +1 -0
- package/dist/ripple/{p-d8287161.entry.js → p-1e7e2ca4.entry.js} +1 -1
- package/dist/ripple/{p-fef28649.system.entry.js → p-1ee49e28.system.entry.js} +1 -1
- package/dist/ripple/{p-e82eae12.entry.js → p-299bf10c.entry.js} +1 -1
- package/dist/ripple/{p-c20c248a.entry.js → p-2d6bb6d7.entry.js} +1 -1
- package/dist/ripple/{p-a31e736a.entry.js → p-366a9608.entry.js} +1 -1
- package/dist/ripple/p-3a20b1ed.system.entry.js +1 -0
- package/dist/ripple/p-3bb79457.entry.js +1 -0
- package/dist/ripple/{p-1f7a67cc.system.js → p-426fa249.system.js} +1 -1
- package/dist/ripple/p-44d4705c.system.js +1 -0
- package/dist/ripple/p-492dd748.system.entry.js +1 -0
- package/dist/ripple/p-4aa8e2cf.entry.js +1 -0
- package/dist/ripple/{p-ff891d67.js → p-52f5ec85.js} +1 -1
- package/dist/ripple/{p-484d57e1.entry.js → p-546d5c1d.entry.js} +1 -1
- package/dist/ripple/{p-d231aed1.system.entry.js → p-585732f7.system.entry.js} +1 -1
- package/dist/ripple/p-6767b009.system.js +1 -0
- package/dist/ripple/{p-c6ba5d3d.system.entry.js → p-681c9539.system.entry.js} +1 -1
- package/dist/ripple/{p-d2c9264d.entry.js → p-68cade03.entry.js} +1 -1
- package/dist/ripple/{p-260fd686.system.entry.js → p-6c27afee.system.entry.js} +1 -1
- package/dist/ripple/{p-d108107c.entry.js → p-7740db9a.entry.js} +1 -1
- package/dist/ripple/{p-055d1c23.system.entry.js → p-7d005413.system.entry.js} +1 -1
- package/dist/ripple/{p-c9830db6.system.entry.js → p-7e2c2c46.system.entry.js} +1 -1
- package/dist/ripple/p-7fa84884.system.entry.js +1 -0
- package/dist/ripple/{p-9a3d8f0b.system.entry.js → p-8b143e9d.system.entry.js} +1 -1
- package/dist/ripple/{p-0790bfed.entry.js → p-8ea235b6.entry.js} +1 -1
- package/dist/ripple/{p-4eae76a6.entry.js → p-8fadf5dd.entry.js} +1 -1
- package/dist/ripple/{p-8df34bf3.system.entry.js → p-94c65a69.system.entry.js} +1 -1
- package/dist/ripple/{p-3bd6839a.entry.js → p-9690de6c.entry.js} +1 -1
- package/dist/ripple/p-acb0156f.system.entry.js +1 -0
- package/dist/ripple/p-ae7290c2.entry.js +1 -0
- package/dist/ripple/{p-030b527a.js → p-aea9a33a.js} +1 -1
- package/dist/ripple/p-b6e5408c.js +1 -0
- package/dist/ripple/p-b75c0973.system.js +1 -0
- package/dist/ripple/{p-21f73fee.system.entry.js → p-b858d526.system.entry.js} +1 -1
- package/dist/ripple/{p-40b5b7d1.system.entry.js → p-b92c2e16.system.entry.js} +1 -1
- package/dist/ripple/p-be79e95d.entry.js +1 -0
- package/dist/ripple/{p-b623fdc8.entry.js → p-bfff12b4.entry.js} +1 -1
- package/dist/ripple/{p-68d7cf2b.entry.js → p-c028f29c.entry.js} +1 -1
- package/dist/ripple/p-c19ed569.entry.js +1 -0
- package/dist/ripple/{p-f42031f5.system.js → p-c3da681d.system.js} +1 -1
- package/dist/ripple/{p-9b94467e.entry.js → p-c5105455.entry.js} +1 -1
- package/dist/ripple/{p-15457a4b.system.entry.js → p-c86a7f4d.system.entry.js} +1 -1
- package/dist/ripple/{p-b9283910.entry.js → p-db58d96b.entry.js} +1 -1
- package/dist/ripple/p-dd92850a.js +1 -0
- package/dist/ripple/p-e39e6c2b.entry.js +1 -0
- package/dist/ripple/{p-a8ea87d1.system.entry.js → p-ec831e59.system.entry.js} +1 -1
- package/dist/ripple/{p-f1029090.system.entry.js → p-ee51efe0.system.entry.js} +1 -1
- package/dist/ripple/{p-777ced5b.entry.js → p-eec01bbe.entry.js} +1 -1
- package/dist/ripple/{p-5ed1b0a2.system.entry.js → p-f339d590.system.entry.js} +1 -1
- package/dist/ripple/{p-5b593411.system.entry.js → p-f3407959.system.entry.js} +1 -1
- package/dist/ripple/{p-da727af8.system.entry.js → p-f3a374ff.system.entry.js} +1 -1
- package/dist/ripple/{p-867b20a9.system.entry.js → p-f43fda55.system.entry.js} +1 -1
- package/dist/ripple/ripple.esm.js +1 -1
- package/dist/ripple/ripple.js +1 -1
- package/dist/types/components/wm-file/wm-file.d.ts +1 -1
- package/dist/types/components/wm-input/wm-input.d.ts +0 -1
- package/dist/types/components/wm-option/wm-option.d.ts +2 -0
- package/dist/types/components/wm-select/wm-select.d.ts +7 -7
- package/dist/types/components/wm-tag-input/wm-tag-input.d.ts +65 -85
- package/dist/types/components/wm-tag-input/wm-tag-option/wm-tag-option.d.ts +18 -0
- package/dist/types/components/wm-uploader/wm-uploader.d.ts +1 -1
- package/dist/types/components.d.ts +30 -27
- package/dist/types/global/functions.d.ts +2 -1
- package/dist/types/global/intl.d.ts +2 -2
- package/package.json +1 -1
- package/dist/cjs/wm-tag-input-row.cjs.entry.js +0 -23
- package/dist/collection/components/wm-tag-input/wm-tag-input-row/wm-tag-input-row.js +0 -122
- package/dist/collection/components/wm-tag-input/wm-tag-input.spec.js +0 -1039
- package/dist/esm/wm-tag-input-row.entry.js +0 -19
- package/dist/esm-es5/functions-061ab506.js +0 -1
- package/dist/esm-es5/global-509460f7.js +0 -1
- package/dist/esm-es5/wm-tag-input-row.entry.js +0 -1
- package/dist/ripple/p-1c3ba701.system.entry.js +0 -1
- package/dist/ripple/p-4a8c95b9.system.entry.js +0 -1
- package/dist/ripple/p-5f2c09f6.entry.js +0 -1
- package/dist/ripple/p-647a4a4a.system.entry.js +0 -1
- package/dist/ripple/p-7011accc.entry.js +0 -1
- package/dist/ripple/p-707383d5.system.js +0 -1
- package/dist/ripple/p-7c2e47bc.system.entry.js +0 -1
- package/dist/ripple/p-839d7e0f.system.js +0 -1
- package/dist/ripple/p-928cc755.system.entry.js +0 -1
- package/dist/ripple/p-9888c825.js +0 -1
- package/dist/ripple/p-a5308115.js +0 -1
- package/dist/ripple/p-b45a2fc3.entry.js +0 -1
- package/dist/ripple/p-b4b57baf.system.entry.js +0 -1
- package/dist/ripple/p-c15f29e5.system.js +0 -1
- package/dist/ripple/p-d38882eb.entry.js +0 -1
- package/dist/ripple/p-d601c5a1.entry.js +0 -1
- package/dist/ripple/p-d68678d2.entry.js +0 -1
- package/dist/ripple/p-e703d9cd.entry.js +0 -1
- package/dist/ripple/p-eb0d569a.system.entry.js +0 -1
- 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,
|
|
2
|
-
import { csvToArray, debounce,
|
|
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.
|
|
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.
|
|
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
|
|
39
|
-
return this.el.
|
|
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
|
-
|
|
42
|
-
|
|
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
|
-
|
|
88
|
+
// for visual stuff (measuring, truncating...)
|
|
89
|
+
get _tagEls() {
|
|
45
90
|
return this.tagAreaEl ? Array.from(this.tagAreaEl.querySelectorAll(".tag")) : [];
|
|
46
91
|
}
|
|
47
|
-
|
|
48
|
-
|
|
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
|
|
51
|
-
|
|
98
|
+
get focusedTag() {
|
|
99
|
+
if (this.focusedTagIndex !== undefined && this.focusedTagIndex >= 0)
|
|
100
|
+
return this.focusableTags[this.focusedTagIndex];
|
|
52
101
|
}
|
|
53
|
-
get
|
|
54
|
-
|
|
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
|
|
57
|
-
|
|
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
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
67
|
-
|
|
68
|
-
if (this.
|
|
69
|
-
this.
|
|
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.
|
|
77
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
-
//
|
|
181
|
-
|
|
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.
|
|
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
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
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
|
-
|
|
262
|
-
|
|
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.
|
|
281
|
-
this.announce(this.generateCharacterLimitWarning(this.
|
|
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.
|
|
423
|
+
if (this.isTable) {
|
|
300
424
|
ev.preventDefault();
|
|
301
|
-
this.
|
|
425
|
+
this.focusPrevCell();
|
|
302
426
|
}
|
|
303
427
|
break;
|
|
304
428
|
case "ArrowRight":
|
|
305
|
-
if (this.
|
|
429
|
+
if (this.isTable) {
|
|
306
430
|
ev.preventDefault();
|
|
307
|
-
this.
|
|
431
|
+
this.focusNextCell();
|
|
308
432
|
}
|
|
309
433
|
break;
|
|
310
434
|
case "Escape":
|
|
311
|
-
if (this.
|
|
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.
|
|
446
|
+
if (this.isDropdown) {
|
|
323
447
|
this.openDropdown();
|
|
324
|
-
this.
|
|
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(
|
|
330
|
-
this.
|
|
331
|
-
if (this.
|
|
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
|
-
|
|
341
|
-
|
|
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
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
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.
|
|
375
|
-
this.
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
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
|
|
381
|
-
this.
|
|
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.
|
|
386
|
-
this.
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
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
|
|
392
|
-
this.
|
|
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.
|
|
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
|
-
|
|
401
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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.
|
|
496
|
-
|
|
577
|
+
this.clearOptionFocus();
|
|
578
|
+
const relTarget = ev.relatedTarget;
|
|
579
|
+
if (!this.isElOrChild(relTarget)) {
|
|
497
580
|
this.fieldWrapperEl.classList.remove("focused");
|
|
498
|
-
if (this.
|
|
581
|
+
if (this.isDropdown) {
|
|
499
582
|
this.closeDropdown();
|
|
500
583
|
}
|
|
501
584
|
}
|
|
502
585
|
}
|
|
503
|
-
|
|
504
|
-
|
|
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
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
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.
|
|
597
|
+
const firstFocusableTag = this.focusableTags[0];
|
|
598
|
+
this.focusTag(firstFocusableTag);
|
|
534
599
|
}
|
|
535
600
|
}
|
|
536
601
|
}
|
|
537
|
-
|
|
538
|
-
if (this.
|
|
539
|
-
|
|
540
|
-
|
|
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
|
-
|
|
552
|
-
if (this.
|
|
553
|
-
|
|
554
|
-
|
|
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
|
-
|
|
573
|
-
if (
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
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.
|
|
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
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
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
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
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
|
-
|
|
699
|
-
|
|
700
|
-
|
|
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
|
-
|
|
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
|
-
|
|
716
|
-
this.
|
|
717
|
-
|
|
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.
|
|
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.
|
|
697
|
+
if (this.isDropdown) {
|
|
782
698
|
numResults = this.optionEls.length;
|
|
783
699
|
}
|
|
784
|
-
else if (this.
|
|
785
|
-
numResults = this.
|
|
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
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
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
|
-
|
|
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
|
-
|
|
830
|
-
const
|
|
831
|
-
return
|
|
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.
|
|
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.
|
|
899
|
-
helpText += this.
|
|
755
|
+
if (this._tagEls.length > 0) {
|
|
756
|
+
helpText += this.selectionHelpText;
|
|
900
757
|
}
|
|
901
758
|
if (this.addNew) {
|
|
902
|
-
helpText += " " + this.
|
|
759
|
+
helpText += " " + this.addNewHelpText;
|
|
903
760
|
}
|
|
904
761
|
return helpText;
|
|
905
762
|
}
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
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.
|
|
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
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
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(
|
|
932
|
-
const colValues = [
|
|
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
|
|
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
|
-
|
|
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(
|
|
945
|
-
this.
|
|
946
|
-
this.handleBlur(ev
|
|
947
|
-
}, onKeyDown: (ev) => this.handleTagAreaKeyDown(ev) }, this.renderTags())
|
|
948
|
-
this.handleBlur(ev
|
|
949
|
-
}, onFocus: () => this.handleInputFocus(), onKeyDown: (ev) => this.handleInputKeyDown(ev) })), this.
|
|
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
|
-
"
|
|
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":
|
|
897
|
+
"optional": true,
|
|
1029
898
|
"docs": {
|
|
1030
899
|
"tags": [],
|
|
1031
900
|
"text": ""
|
|
1032
901
|
},
|
|
1033
|
-
"attribute": "
|
|
1034
|
-
"reflect":
|
|
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
|
-
"
|
|
922
|
+
"labelPosition": {
|
|
1055
923
|
"type": "string",
|
|
1056
924
|
"mutable": false,
|
|
1057
925
|
"complexType": {
|
|
1058
|
-
"original": "
|
|
1059
|
-
"resolved": "
|
|
926
|
+
"original": "\"top\" | \"left\" | \"none\"",
|
|
927
|
+
"resolved": "\"left\" | \"none\" | \"top\"",
|
|
1060
928
|
"references": {}
|
|
1061
929
|
},
|
|
1062
930
|
"required": false,
|
|
1063
|
-
"optional":
|
|
931
|
+
"optional": false,
|
|
1064
932
|
"docs": {
|
|
1065
933
|
"tags": [],
|
|
1066
934
|
"text": ""
|
|
1067
935
|
},
|
|
1068
|
-
"attribute": "
|
|
1069
|
-
"reflect": false
|
|
936
|
+
"attribute": "label-position",
|
|
937
|
+
"reflect": false,
|
|
938
|
+
"defaultValue": "\"top\""
|
|
1070
939
|
},
|
|
1071
|
-
"
|
|
1072
|
-
"type": "
|
|
940
|
+
"maxTags": {
|
|
941
|
+
"type": "number",
|
|
1073
942
|
"mutable": false,
|
|
1074
943
|
"complexType": {
|
|
1075
|
-
"original": "
|
|
1076
|
-
"resolved": "
|
|
944
|
+
"original": "number",
|
|
945
|
+
"resolved": "number | undefined",
|
|
1077
946
|
"references": {}
|
|
1078
947
|
},
|
|
1079
948
|
"required": false,
|
|
1080
|
-
"optional":
|
|
949
|
+
"optional": true,
|
|
1081
950
|
"docs": {
|
|
1082
951
|
"tags": [],
|
|
1083
952
|
"text": ""
|
|
1084
953
|
},
|
|
1085
|
-
"attribute": "
|
|
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
|
-
"
|
|
1125
|
-
"type": "
|
|
992
|
+
"tagInputType": {
|
|
993
|
+
"type": "string",
|
|
1126
994
|
"mutable": false,
|
|
1127
995
|
"complexType": {
|
|
1128
|
-
"original": "
|
|
1129
|
-
"resolved": "
|
|
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": "
|
|
1006
|
+
"attribute": "tag-input-type",
|
|
1139
1007
|
"reflect": false,
|
|
1140
|
-
"defaultValue": "
|
|
1008
|
+
"defaultValue": "\"dropdown\""
|
|
1141
1009
|
},
|
|
1142
|
-
"
|
|
1143
|
-
"type": "
|
|
1010
|
+
"helpText": {
|
|
1011
|
+
"type": "string",
|
|
1144
1012
|
"mutable": false,
|
|
1145
1013
|
"complexType": {
|
|
1146
|
-
"original": "
|
|
1147
|
-
"resolved": "
|
|
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": "
|
|
1024
|
+
"attribute": "help-text",
|
|
1157
1025
|
"reflect": false
|
|
1158
1026
|
},
|
|
1159
|
-
"
|
|
1160
|
-
"type": "
|
|
1027
|
+
"addNew": {
|
|
1028
|
+
"type": "boolean",
|
|
1161
1029
|
"mutable": false,
|
|
1162
1030
|
"complexType": {
|
|
1163
|
-
"original": "
|
|
1164
|
-
"resolved": "
|
|
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": "
|
|
1041
|
+
"attribute": "add-new",
|
|
1174
1042
|
"reflect": false,
|
|
1175
|
-
"defaultValue": "
|
|
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
|
-
"
|
|
1255
|
-
"
|
|
1256
|
-
"
|
|
1257
|
-
"
|
|
1119
|
+
"liveRegionMessage": {},
|
|
1120
|
+
"focusedOption": {},
|
|
1121
|
+
"focusedColumn": {},
|
|
1122
|
+
"focusedTagIndex": {},
|
|
1123
|
+
"tagsList": {}
|
|
1258
1124
|
};
|
|
1259
1125
|
}
|
|
1260
1126
|
static get events() {
|
|
1261
1127
|
return [{
|
|
1262
|
-
"method": "
|
|
1263
|
-
"name": "
|
|
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": "
|
|
1273
|
-
"resolved": "
|
|
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": "
|
|
1295
|
-
"method": "
|
|
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": "
|
|
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
|
}
|