@watermarkinsights/ripple 5.6.0-8 → 5.7.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 (81) hide show
  1. package/dist/cjs/{global-9662b435.js → global-b4e48f66.js} +1 -1
  2. package/dist/cjs/loader.cjs.js +2 -2
  3. package/dist/cjs/priv-option-list.cjs.entry.js +32 -6
  4. package/dist/cjs/ripple.cjs.js +2 -2
  5. package/dist/cjs/wm-line-chart.cjs.entry.js +7 -22
  6. package/dist/cjs/wm-modal.cjs.entry.js +1 -1
  7. package/dist/cjs/wm-nested-select.cjs.entry.js +45 -34
  8. package/dist/cjs/wm-optgroup.cjs.entry.js +12 -10
  9. package/dist/cjs/wm-option_2.cjs.entry.js +9 -9
  10. package/dist/collection/collection-manifest.json +1 -1
  11. package/dist/collection/components/charts/wm-line-chart/wm-line-chart.js +7 -22
  12. package/dist/collection/components/selects/priv-option-list/priv-option-list.css +32 -5
  13. package/dist/collection/components/selects/priv-option-list/priv-option-list.js +76 -5
  14. package/dist/collection/components/selects/wm-nested-select/wm-nested-select.css +16 -4
  15. package/dist/collection/components/selects/wm-nested-select/wm-nested-select.js +46 -41
  16. package/dist/collection/components/selects/wm-optgroup/wm-optgroup.css +0 -26
  17. package/dist/collection/components/selects/wm-optgroup/wm-optgroup.js +20 -9
  18. package/dist/collection/components/{wm-option → selects/wm-option}/wm-option.css +1 -1
  19. package/dist/collection/components/{wm-option → selects/wm-option}/wm-option.js +4 -9
  20. package/dist/collection/components/{wm-option → selects/wm-option}/wm-option.spec.js +1 -1
  21. package/dist/collection/components/selects/wm-select/wm-select.css +7 -0
  22. package/dist/collection/components/selects/wm-select/wm-select.js +6 -6
  23. package/dist/collection/components/selects/wm-select/wm-select.spec.js +1 -1
  24. package/dist/collection/components/wm-modal/wm-modal.js +1 -1
  25. package/dist/collection/dev/nested-select.js +31 -57
  26. package/dist/esm/{global-f1582c2f.js → global-8a4502dd.js} +1 -1
  27. package/dist/esm/loader.js +2 -2
  28. package/dist/esm/priv-option-list.entry.js +32 -6
  29. package/dist/esm/ripple.js +2 -2
  30. package/dist/esm/wm-line-chart.entry.js +7 -22
  31. package/dist/esm/wm-modal.entry.js +1 -1
  32. package/dist/esm/wm-nested-select.entry.js +46 -35
  33. package/dist/esm/wm-optgroup.entry.js +12 -10
  34. package/dist/esm/wm-option_2.entry.js +9 -9
  35. package/dist/esm-es5/{global-f1582c2f.js → global-8a4502dd.js} +1 -1
  36. package/dist/esm-es5/loader.js +1 -1
  37. package/dist/esm-es5/priv-option-list.entry.js +1 -1
  38. package/dist/esm-es5/ripple.js +1 -1
  39. package/dist/esm-es5/wm-line-chart.entry.js +1 -1
  40. package/dist/esm-es5/wm-modal.entry.js +1 -1
  41. package/dist/esm-es5/wm-nested-select.entry.js +1 -1
  42. package/dist/esm-es5/wm-optgroup.entry.js +1 -1
  43. package/dist/esm-es5/wm-option_2.entry.js +1 -1
  44. package/dist/ripple/p-01addccd.entry.js +1 -0
  45. package/dist/ripple/{p-bfeb6ef8.system.js → p-01e29a2a.system.js} +1 -1
  46. package/dist/ripple/p-0c259c1a.system.entry.js +1 -0
  47. package/dist/ripple/p-1796b85d.entry.js +1 -0
  48. package/dist/ripple/p-1c170fb3.entry.js +1 -0
  49. package/dist/ripple/p-3d02b293.system.entry.js +1 -0
  50. package/dist/ripple/p-45dc49e8.entry.js +1 -0
  51. package/dist/ripple/p-54f7d3d4.system.entry.js +1 -0
  52. package/dist/ripple/p-725230dd.system.entry.js +1 -0
  53. package/dist/ripple/{p-465d44f0.system.entry.js → p-84603f1f.system.entry.js} +1 -1
  54. package/dist/ripple/p-947f8f0d.system.entry.js +1 -0
  55. package/dist/ripple/p-99058787.entry.js +1 -0
  56. package/dist/ripple/p-db9f8841.system.js +1 -0
  57. package/dist/ripple/{p-cf55659f.js → p-de8f5e92.js} +1 -1
  58. package/dist/ripple/p-e687176d.entry.js +1 -0
  59. package/dist/ripple/ripple.esm.js +1 -1
  60. package/dist/ripple/ripple.js +1 -1
  61. package/dist/types/components/charts/wm-line-chart/wm-line-chart.d.ts +1 -1
  62. package/dist/types/components/selects/priv-option-list/priv-option-list.d.ts +73 -0
  63. package/dist/types/components/selects/wm-nested-select/wm-nested-select.d.ts +58 -0
  64. package/dist/types/components/selects/wm-optgroup/wm-optgroup.d.ts +17 -0
  65. package/dist/types/components/selects/wm-option/wm-option.d.ts +40 -0
  66. package/dist/types/components/selects/wm-select/wm-select.d.ts +1 -0
  67. package/dist/types/components.d.ts +8 -2
  68. package/package.json +2 -2
  69. package/dist/ripple/p-104c0e9b.system.entry.js +0 -1
  70. package/dist/ripple/p-17c8aac1.system.entry.js +0 -1
  71. package/dist/ripple/p-24ba754f.entry.js +0 -1
  72. package/dist/ripple/p-2fb58947.entry.js +0 -1
  73. package/dist/ripple/p-4564a101.system.entry.js +0 -1
  74. package/dist/ripple/p-4ca5ed96.entry.js +0 -1
  75. package/dist/ripple/p-5b9babd9.system.entry.js +0 -1
  76. package/dist/ripple/p-8835adfb.entry.js +0 -1
  77. package/dist/ripple/p-885c3527.entry.js +0 -1
  78. package/dist/ripple/p-ba422994.entry.js +0 -1
  79. package/dist/ripple/p-cf2121f3.system.entry.js +0 -1
  80. package/dist/ripple/p-f6fd623f.system.js +0 -1
  81. /package/dist/collection/components/{wm-option → selects/wm-option}/wm-option.e2e.js +0 -0
@@ -38,6 +38,7 @@ export class PrivOptionList {
38
38
  this.selectAll = false;
39
39
  this.searchPlaceholder = undefined;
40
40
  this.maxHeight = undefined;
41
+ this.optgroupLabel = undefined;
41
42
  this.announcement = "";
42
43
  this.searchTerm = "";
43
44
  }
@@ -151,9 +152,11 @@ export class PrivOptionList {
151
152
  }
152
153
  }
153
154
  async clearSearch() {
154
- this.searchFieldEl.value = "";
155
- this.searchTerm = "";
156
- this.optionListSearchChanged.emit({ searchTerm: this.searchTerm });
155
+ if (this.search) {
156
+ this.searchFieldEl.value = "";
157
+ this.searchTerm = "";
158
+ this.optionListSearchChanged.emit({ searchTerm: this.searchTerm });
159
+ }
157
160
  }
158
161
  async focusOption(option) {
159
162
  this.allOptionEls.forEach((i) => (i.focused = i === option));
@@ -249,9 +252,16 @@ export class PrivOptionList {
249
252
  ev.preventDefault();
250
253
  this.moveUp(ev.target);
251
254
  break;
255
+ case "ArrowLeft":
256
+ // if an optgroupLabel was passed, we are within a Nested Select
257
+ if (!!this.optgroupLabel) {
258
+ ev.preventDefault();
259
+ this.wmKeyLeftPressed.emit();
260
+ }
261
+ break;
252
262
  case "Escape":
253
263
  ev.preventDefault();
254
- this.close();
264
+ this.wmEscKeyPressed.emit();
255
265
  break;
256
266
  case "Enter":
257
267
  if (el === this.selectAllEl) {
@@ -293,6 +303,10 @@ export class PrivOptionList {
293
303
  if (this.searchFieldEl) {
294
304
  focusableEls.unshift(this.searchFieldEl);
295
305
  }
306
+ // if an optgroupLabel was passed, we are is within a Nested Select
307
+ if (!!this.optgroupLabel) {
308
+ focusableEls.unshift(this.returnBtnEl);
309
+ }
296
310
  const prevEl = focusableEls[focusableEls.indexOf(el) - 1] || focusableEls[focusableEls.length - 1];
297
311
  if (prevEl) {
298
312
  this.focusOption(prevEl);
@@ -306,6 +320,10 @@ export class PrivOptionList {
306
320
  if (this.searchFieldEl) {
307
321
  focusableEls.unshift(this.searchFieldEl);
308
322
  }
323
+ // if an optgroupLabel was passed, we are is within a Nested Select
324
+ if (!!this.optgroupLabel) {
325
+ focusableEls.unshift(this.returnBtnEl);
326
+ }
309
327
  const nextEl = focusableEls[focusableEls.indexOf(el) + 1] || focusableEls[0];
310
328
  if (nextEl) {
311
329
  this.focusOption(nextEl);
@@ -345,6 +363,12 @@ export class PrivOptionList {
345
363
  }
346
364
  this.announcement = message;
347
365
  }
366
+ renderReturnBtn() {
367
+ return (h("button", { ref: (el) => (this.returnBtnEl = el), id: "return-btn", class: "return-btn", onKeyDown: (ev) => this.handleKeyDown(ev), onClick: () => {
368
+ //@ts-ignore -- Check out this one weird trick TypeScript doesn't want you to know about
369
+ this.el.getRootNode().host.isExpanded = false;
370
+ } }, this.optgroupLabel));
371
+ }
348
372
  renderSearchField() {
349
373
  return (h("div", { class: "search" }, h("div", { class: "searchfield-wrapper", ref: (el) => (this.searchFieldWrapperEl = el) }, h("div", { class: "icon" }), h("input", { ref: (el) => (this.searchFieldEl = el), class: "searchfield", role: "combobox", "aria-controls": "list",
350
374
  // aria-expanded={this.isExpanded ? "true" : "false"}
@@ -363,7 +387,7 @@ export class PrivOptionList {
363
387
  });
364
388
  }
365
389
  render() {
366
- return (h("div", { class: "list-wrapper" }, this.search && this.renderSearchField(), this.visibleSelectAllButton && this.renderSelectAllButton(), h("div", { id: "list", class: "options-wrapper", tabindex: -1, role: "listbox", "aria-multiselectable": this.multiple ? "true" : null, "aria-labelledby": "label", ref: (el) => (this.listboxEl = el) }, this.searchTerm && this.filteredOptions.length === 0 && this.renderSearchFailedMessage(), this.multiple && this.renderCloneOptions(), h("slot", null)), h("div", { id: "optionlist-announcement", "aria-live": "polite", "aria-atomic": "true", class: "sr-only", ref: (el) => (this.liveRegionEl = el) }, this.announcement)));
390
+ return (h("div", { class: "list-wrapper" }, !!this.optgroupLabel && this.renderReturnBtn(), this.search && this.renderSearchField(), this.visibleSelectAllButton && this.renderSelectAllButton(), h("div", { id: "list", class: "options-wrapper", tabindex: -1, role: "listbox", "aria-multiselectable": this.multiple ? "true" : null, "aria-labelledby": "label", ref: (el) => (this.listboxEl = el) }, this.searchTerm && this.filteredOptions.length === 0 && this.renderSearchFailedMessage(), this.multiple && this.renderCloneOptions(), h("slot", null)), h("div", { id: "optionlist-announcement", "aria-live": "polite", "aria-atomic": "true", class: "sr-only", ref: (el) => (this.liveRegionEl = el) }, this.announcement)));
367
391
  }
368
392
  static get is() { return "priv-option-list"; }
369
393
  static get originalStyleUrls() {
@@ -465,6 +489,23 @@ export class PrivOptionList {
465
489
  },
466
490
  "attribute": "max-height",
467
491
  "reflect": false
492
+ },
493
+ "optgroupLabel": {
494
+ "type": "string",
495
+ "mutable": false,
496
+ "complexType": {
497
+ "original": "string",
498
+ "resolved": "string | undefined",
499
+ "references": {}
500
+ },
501
+ "required": false,
502
+ "optional": true,
503
+ "docs": {
504
+ "tags": [],
505
+ "text": ""
506
+ },
507
+ "attribute": "optgroup-label",
508
+ "reflect": false
468
509
  }
469
510
  };
470
511
  }
@@ -540,6 +581,36 @@ export class PrivOptionList {
540
581
  "resolved": "any",
541
582
  "references": {}
542
583
  }
584
+ }, {
585
+ "method": "wmEscKeyPressed",
586
+ "name": "wmEscKeyPressed",
587
+ "bubbles": true,
588
+ "cancelable": true,
589
+ "composed": true,
590
+ "docs": {
591
+ "tags": [],
592
+ "text": ""
593
+ },
594
+ "complexType": {
595
+ "original": "any",
596
+ "resolved": "any",
597
+ "references": {}
598
+ }
599
+ }, {
600
+ "method": "wmKeyLeftPressed",
601
+ "name": "wmKeyLeftPressed",
602
+ "bubbles": true,
603
+ "cancelable": true,
604
+ "composed": true,
605
+ "docs": {
606
+ "tags": [],
607
+ "text": ""
608
+ },
609
+ "complexType": {
610
+ "original": "any",
611
+ "resolved": "any",
612
+ "references": {}
613
+ }
543
614
  }];
544
615
  }
545
616
  static get methods() {
@@ -172,6 +172,9 @@
172
172
  pointer-events: none;
173
173
  font-size: 1.12rem;
174
174
  }
175
+ .button-wrapper .displayedoption.expanded:before {
176
+ content: "\f143";
177
+ }
175
178
  .button-wrapper .displayedoption:hover:not(:disabled):not(.-disabled):not(.-raised) {
176
179
  background: var(--wmcolor-select-background);
177
180
  text-decoration: none;
@@ -282,7 +285,7 @@
282
285
  }
283
286
  .dropdown.upwards {
284
287
  top: unset;
285
- bottom: calc(100% - 2.5rem);
288
+ bottom: 100%;
286
289
  -ms-transform-origin: center bottom;
287
290
  -webkit-transform-origin: center bottom;
288
291
  -moz-transform-origin: center bottom;
@@ -357,11 +360,20 @@
357
360
  .option-list-wrapper {
358
361
  background: white;
359
362
  width: 100%;
360
- transform: translateX(100%);
363
+ transform: translateX(0%);
361
364
  transition: transform 0.2s cubic-bezier(0.04, 0, 0.2, 1);
362
365
  }
363
- .option-list-wrapper.visible {
364
- transform: translateX(0%);
366
+ .option-list-wrapper.hidden {
367
+ transform: translateX(100%);
368
+ position: absolute;
369
+ top: 0px;
370
+ }
371
+
372
+ .measurement-area {
373
+ position: absolute;
374
+ visibility: hidden;
375
+ height: 0px;
376
+ pointer-events: none;
365
377
  }
366
378
 
367
379
  .sr-only {
@@ -1,8 +1,9 @@
1
1
  import { h, Host, forceUpdate } from "@stencil/core";
2
- import { getTextDir, intl, isElOrChild, toBool } from "../../../global/functions";
2
+ import { getTextDir, intl, isElOrChild, shouldOpenUp, toBool } from "../../../global/functions";
3
3
  import { globalMessages } from "../../../global/intl";
4
4
  export class NestedSelect {
5
5
  constructor() {
6
+ this.openUp = false;
6
7
  this.overflowCount = 0;
7
8
  this.displayedOptions = [];
8
9
  this.clearSelectionMessage = this.multiple
@@ -47,7 +48,7 @@ export class NestedSelect {
47
48
  description: "Text displayed when all options are selected",
48
49
  });
49
50
  this.isExpanded = false;
50
- this.optgroupExpanded = false;
51
+ this.showClearSelectionButton = false;
51
52
  }
52
53
  get isDisabled() {
53
54
  // string "false" needs to be treated as bool False because react wrappers convert bool to string.
@@ -76,7 +77,6 @@ export class NestedSelect {
76
77
  }
77
78
  componentDidLoad() {
78
79
  if (this.maxHeight) {
79
- // this.listboxEl.style.maxHeight = this.maxHeight;
80
80
  this.dropdownEl.style.maxHeight = this.maxHeight;
81
81
  }
82
82
  }
@@ -97,14 +97,14 @@ export class NestedSelect {
97
97
  const paddingLeft = parseInt(computedStyle.getPropertyValue("padding-left").slice(0, -2));
98
98
  const paddingRight = parseInt(computedStyle.getPropertyValue("padding-right").slice(0, -2));
99
99
  const availableSpace = this.buttonEl.clientWidth - paddingLeft - paddingRight - overflowCounterWidth;
100
- let optionsWidths = this.displayedOptions.map((x) => x.shadowRoot.querySelector(".option-text").clientWidth);
101
- let optionsTotalWidth = optionsWidths.reduce((acc, x) => acc + x, 0);
102
100
  this.overflowCount = 0;
101
+ this.measurementAreaEl.textContent = this.displayedOptions.map((x) => x.textContent).join(", ");
102
+ let optionsTotalWidth = this.measurementAreaEl.clientWidth;
103
103
  while (optionsTotalWidth > availableSpace && this.displayedOptions.length > 1) {
104
104
  this.overflowCount++;
105
- optionsTotalWidth -= optionsWidths[optionsWidths.length - 1];
106
- optionsWidths.pop();
107
105
  this.displayedOptions.pop();
106
+ this.measurementAreaEl.textContent = this.displayedOptions.map((x) => x.textContent).join(", ");
107
+ optionsTotalWidth = this.measurementAreaEl.clientWidth;
108
108
  }
109
109
  }
110
110
  }
@@ -124,17 +124,12 @@ export class NestedSelect {
124
124
  closePopupOnEscape() {
125
125
  this.close();
126
126
  }
127
- handleOptionKeyLeft(ev) {
128
- const parentOptgroup = ev.detail.parentElement;
129
- parentOptgroup.isExpanded = false;
130
- this.focusFirstMenuitem();
131
- }
132
127
  close(returnFocus = true) {
133
128
  if (this.isExpanded) {
134
129
  this.isExpanded = false;
135
- this.optgroupEls.forEach((optgroupEl) => (optgroupEl.isExpanded = false));
130
+ this.dropdownEl.classList.remove("open");
136
131
  window.setTimeout(() => {
137
- this.dropdownEl.classList.remove("open");
132
+ this.optgroupEls.forEach((optgroupEl) => (optgroupEl.isExpanded = false));
138
133
  if (returnFocus) {
139
134
  this.buttonEl.focus();
140
135
  }
@@ -142,12 +137,16 @@ export class NestedSelect {
142
137
  }
143
138
  }
144
139
  open() {
145
- // TODO implement opening upwards if not enough space below
146
- this.isExpanded = true;
147
- this.dropdownEl.classList.add("open");
148
- window.requestAnimationFrame(() => {
149
- this.focusFirstMenuitem();
150
- });
140
+ if (!this.isDisabled) {
141
+ this.showClearSelectionButton = this.childOptions.some((o) => o.selected);
142
+ this.isExpanded = true;
143
+ this.dropdownEl.classList.add("open");
144
+ const elHeight = this.el.clientHeight;
145
+ this.openUp = shouldOpenUp(this.el, this.dropdownEl.clientHeight, elHeight, 0);
146
+ window.requestAnimationFrame(() => {
147
+ this.focusFirstMenuitem();
148
+ });
149
+ }
151
150
  }
152
151
  focusFirstMenuitem() {
153
152
  if (this.menuitemEls.length > 0) {
@@ -215,10 +214,16 @@ export class NestedSelect {
215
214
  }
216
215
  }
217
216
  handleOptgroupExpanded() {
218
- this.optgroupExpanded = true;
217
+ this.menuEl.classList.add("hidden");
218
+ this.optListWrapperEl.classList.remove("hidden");
219
219
  }
220
- handleOptgroupHidden() {
221
- this.optgroupExpanded = false;
220
+ handleOptgroupHidden(ev) {
221
+ this.showClearSelectionButton = this.childOptions.some((o) => o.selected);
222
+ this.menuEl.classList.remove("hidden");
223
+ this.optListWrapperEl.classList.add("hidden");
224
+ // focus back to nested select
225
+ const elToFocus = this.el.shadowRoot.querySelector(`button[data-label=${ev.detail}]`);
226
+ elToFocus.focus();
222
227
  }
223
228
  renderButtonText() {
224
229
  if (this.displayedOptions.length < 1) {
@@ -232,29 +237,35 @@ export class NestedSelect {
232
237
  }
233
238
  }
234
239
  renderOverflowCount() {
235
- // TODO overflow count not appearing due to refactor, in both regular select and nested select
236
240
  if (this.overflowCount > 0) {
237
241
  return (h("span", null, h("span", { class: "overflow-counter" }, "+", this.overflowCount)));
238
242
  }
239
243
  }
240
244
  handleClearSelection() {
241
245
  this.optgroupEls.forEach((optgroupEl) => optgroupEl.emitDeselection());
246
+ if (!this.multiple) {
247
+ this.close();
248
+ }
242
249
  }
243
250
  renderClearSelectionButton() {
244
- let selectedCount = this.childOptions.some((o) => o.selected);
245
- if (selectedCount) {
251
+ if (this.showClearSelectionButton) {
246
252
  return (h("button", { class: "menuitem", onClick: () => this.handleClearSelection(), tabindex: -1, onKeyDown: (ev) => this.handleMenuitemKeydown(ev) }, this.clearSelectionMessage));
247
253
  }
248
254
  }
249
255
  renderSelectionCount(optgroupEl) {
250
256
  const selectionCount = this.countOptgroupSelected(optgroupEl);
251
257
  if (selectionCount) {
252
- const selectionCountMessage = intl.formatMessage({
253
- id: "select.optgroupSelectionCount",
254
- defaultMessage: "{numSelected, plural, one {Item} other {#}} Selected",
255
- description: "Text indicating number of selected in a group.",
258
+ const singleSelectionCountMessage = intl.formatMessage({
259
+ id: "select.optgroupSingleSelectionCount",
260
+ defaultMessage: "Item Selected",
261
+ description: "Text indicating number of selected in a group, where only a single selection is possible.",
262
+ }, { numSelected: selectionCount });
263
+ const multipleSelectionCountMessage = intl.formatMessage({
264
+ id: "select.optgroupMultipleSelectionCount",
265
+ defaultMessage: "{numSelected} Selected",
266
+ description: "Text indicating number of selected in a group, where multiple selections are possible.",
256
267
  }, { numSelected: selectionCount });
257
- return (h("div", { class: "selection-count" }, h("span", null, selectionCountMessage)));
268
+ return (h("div", { class: "selection-count" }, h("span", null, this.multiple ? multipleSelectionCountMessage : singleSelectionCountMessage)));
258
269
  }
259
270
  }
260
271
  render() {
@@ -271,12 +282,12 @@ export class NestedSelect {
271
282
  };
272
283
  return (h(Host, { onBlur: (ev) => this.handleComponentBlur(ev) }, h("div", { class: `wrapper ${getTextDir()} label-${this.labelPosition} ${this.errorMessage ? "invalid" : ""}` }, h("div", { class: "label-wrapper" }, h("label", { class: "label", id: "label", htmlFor: "selectbtn" }, this.label,
273
284
  // we can't use aria-required or required attributes because it's invalid on the elements we're using (button controlling a listbox)
274
- this.requiredField ? (h("span", { class: "required" }, h("span", { class: "sr-only" }, globalMessages.requiredField), h("span", { "aria-hidden": "true" }, "*"))) : (""))), h("div", { class: "button-wrapper" }, h("button", Object.assign({}, buttonProps, { class: "displayedoption", ref: (el) => (this.buttonEl = el), onBlur: (ev) => this.handleButtonBlur(ev), onFocus: () => this.close() }), h("span", { class: "overflowcontrol" }, h("span", { class: "button-text" }, this.renderButtonText())), this.renderOverflowCount()), h("div", { class: "dropdown", ref: (el) => (this.dropdownEl = el) }, h("div", { class: `menu ${this.optgroupExpanded ? "hidden" : ""}` }, this.renderClearSelectionButton(), this.optgroupEls.map((optgroupEl) => {
275
- return (h("button", { class: "menuitem group-btn", role: "menuitem", tabindex: -1, onClick: () => {
285
+ this.requiredField ? (h("span", { class: "required" }, h("span", { class: "sr-only" }, globalMessages.requiredField), h("span", { "aria-hidden": "true" }, "*"))) : (""))), h("div", { class: "button-wrapper" }, h("button", Object.assign({}, buttonProps, { class: `displayedoption ${this.isExpanded ? "expanded" : ""}`, ref: (el) => (this.buttonEl = el), onBlur: (ev) => this.handleButtonBlur(ev), onFocus: () => this.close() }), h("span", { class: "overflowcontrol" }, h("span", { class: "button-text" }, this.renderButtonText())), this.renderOverflowCount(), h("div", { ref: (el) => (this.measurementAreaEl = el), class: "measurement-area", "aria-hidden": "true" })), h("div", { class: `dropdown ${this.openUp ? "upwards" : ""}`, ref: (el) => (this.dropdownEl = el) }, h("div", { ref: (el) => (this.menuEl = el), class: "menu" }, this.renderClearSelectionButton(), this.optgroupEls.map((optgroupEl) => {
286
+ return (h("button", { class: "menuitem group-btn", role: "menuitem", "data-label": optgroupEl.label, tabindex: -1, onClick: () => {
276
287
  optgroupEl.isExpanded = !optgroupEl.isExpanded;
277
288
  forceUpdate(this.el);
278
289
  }, onKeyDown: (ev) => this.handleMenuitemKeydown(ev) }, h("span", null, optgroupEl.label), this.renderSelectionCount(optgroupEl)));
279
- })), h("div", { class: `option-list-wrapper ${this.optgroupExpanded ? "visible" : ""}` }, h("slot", null))), h("div", { id: "error", class: this.errorMessage ? "error-message" : "" }, this.errorMessage)))));
290
+ })), h("div", { ref: (el) => (this.optListWrapperEl = el), class: "option-list-wrapper hidden" }, h("slot", null))), h("div", { id: "error", class: this.errorMessage ? "error-message" : "" }, this.errorMessage)))));
280
291
  }
281
292
  static get is() { return "wm-nested-select"; }
282
293
  static get encapsulation() { return "shadow"; }
@@ -511,7 +522,7 @@ export class NestedSelect {
511
522
  static get states() {
512
523
  return {
513
524
  "isExpanded": {},
514
- "optgroupExpanded": {}
525
+ "showClearSelectionButton": {}
515
526
  };
516
527
  }
517
528
  static get events() {
@@ -552,12 +563,6 @@ export class NestedSelect {
552
563
  "target": undefined,
553
564
  "capture": false,
554
565
  "passive": false
555
- }, {
556
- "name": "wmKeyLeftPressed",
557
- "method": "handleOptionKeyLeft",
558
- "target": undefined,
559
- "capture": false,
560
- "passive": false
561
566
  }, {
562
567
  "name": "click",
563
568
  "method": "handleClick",
@@ -48,30 +48,4 @@
48
48
 
49
49
  :host(.visible) {
50
50
  display: unset;
51
- }
52
-
53
- .return-btn {
54
- cursor: pointer;
55
- padding: 1.25rem;
56
- display: flex;
57
- align-items: center;
58
- font-weight: 600;
59
- font-size: 0.875rem;
60
- border-bottom: 1px solid #4a4a4a;
61
- }
62
- .return-btn:before {
63
- display: inline-block;
64
- font: normal normal normal 24px/1 "Material Design Icons";
65
- font-size: inherit;
66
- text-rendering: auto;
67
- line-height: inherit;
68
- -webkit-font-smoothing: antialiased;
69
- -moz-osx-font-smoothing: grayscale;
70
- content: "\f141";
71
- pointer-events: none;
72
- font-size: 1.12rem;
73
- }
74
- .return-btn:hover {
75
- background: var(--wmcolor-select-option-background-hover);
76
- outline: none;
77
51
  }
@@ -10,6 +10,7 @@ export class Optgroup {
10
10
  }
11
11
  isExpandedChanged() {
12
12
  if (this.isExpanded) {
13
+ this.el.classList.add("visible");
13
14
  this.optgroupExpanded.emit();
14
15
  window.setTimeout(() => {
15
16
  // wait for slide in animation to complete before assigning focus
@@ -17,21 +18,22 @@ export class Optgroup {
17
18
  }, 250);
18
19
  }
19
20
  else {
20
- this.optgroupHidden.emit();
21
+ this.optgroupHidden.emit(this.label);
22
+ this.optionListEl.clearSearch();
23
+ window.setTimeout(() => {
24
+ // wait for slide out animation to complete before hiding
25
+ this.el.classList.remove("visible");
26
+ }, 250);
21
27
  }
22
28
  }
23
29
  async emitDeselection() {
24
30
  this.wmOptgroupAllDeselected.emit();
25
31
  }
26
- /*
27
- componentWillLoad() {
28
- this.multiple = this.parentNestedSelect.multiple;
29
- }
30
- */
32
+ handleOptionKeyLeft() {
33
+ this.isExpanded = false;
34
+ }
31
35
  render() {
32
- return (h(Host, { class: `${this.isExpanded ? "visible" : ""}` }, h("div", { class: "return-btn", onClick: () => {
33
- this.isExpanded = false;
34
- } }, this.label), h("div", { class: `list-wrapper` }, h("priv-option-list", { ref: (el) => (this.optionListEl = el), multiple: this.parentNestedSelect.multiple, search: this.parentNestedSelect.search, searchPlaceholder: this.parentNestedSelect.searchPlaceholder, selectAll: this.parentNestedSelect.selectAll, onOptionListAllSelected: () => this.wmOptgroupAllSelected.emit(), onOptionListAllDeselected: () => this.wmOptgroupAllDeselected.emit() }, h("slot", null)))));
36
+ return (h(Host, null, h("div", { class: `list-wrapper` }, h("priv-option-list", { ref: (el) => (this.optionListEl = el), multiple: this.parentNestedSelect.multiple, search: this.parentNestedSelect.search, searchPlaceholder: this.parentNestedSelect.searchPlaceholder, optgroupLabel: this.label, selectAll: this.parentNestedSelect.selectAll, onOptionListAllSelected: () => this.wmOptgroupAllSelected.emit(), onOptionListAllDeselected: () => this.wmOptgroupAllDeselected.emit() }, h("slot", null)))));
35
37
  }
36
38
  static get is() { return "wm-optgroup"; }
37
39
  static get encapsulation() { return "shadow"; }
@@ -194,4 +196,13 @@ export class Optgroup {
194
196
  "methodName": "isExpandedChanged"
195
197
  }];
196
198
  }
199
+ static get listeners() {
200
+ return [{
201
+ "name": "wmKeyLeftPressed",
202
+ "method": "handleOptionKeyLeft",
203
+ "target": undefined,
204
+ "capture": false,
205
+ "passive": false
206
+ }];
207
+ }
197
208
  }
@@ -153,7 +153,7 @@
153
153
 
154
154
  :host(:focus) {
155
155
  outline: none;
156
- background: var(--wmcolor-select-option-background-hover);
156
+ background: var(--wmcolor-select-option-background-focus);
157
157
  }
158
158
 
159
159
  :host(:hover) {
@@ -61,7 +61,7 @@ export class Option {
61
61
  break;
62
62
  case "ArrowLeft":
63
63
  ev.preventDefault();
64
- this.wmKeyLeftPressed.emit(this.el);
64
+ this.wmKeyLeftPressed.emit();
65
65
  break;
66
66
  default:
67
67
  if (ev.key.length === 1) {
@@ -367,14 +367,9 @@ export class Option {
367
367
  "text": ""
368
368
  },
369
369
  "complexType": {
370
- "original": "HTMLWmOptionElement",
371
- "resolved": "HTMLWmOptionElement",
372
- "references": {
373
- "HTMLWmOptionElement": {
374
- "location": "global",
375
- "id": "global::HTMLWmOptionElement"
376
- }
377
- }
370
+ "original": "any",
371
+ "resolved": "any",
372
+ "references": {}
378
373
  }
379
374
  }, {
380
375
  "method": "wmEscKeyPressed",
@@ -1,6 +1,6 @@
1
1
  import { newSpecPage } from "@stencil/core/testing";
2
2
  import { Option } from "./wm-option";
3
- import { Select } from "../selects/wm-select/wm-select";
3
+ import { Select } from "../wm-select/wm-select";
4
4
  // mock MutationObserver
5
5
  global.MutationObserver = jest.fn().mockImplementation(() => ({
6
6
  observe: jest.fn(),
@@ -302,6 +302,13 @@
302
302
  overflow: auto;
303
303
  }
304
304
 
305
+ .measurement-area {
306
+ position: absolute;
307
+ visibility: hidden;
308
+ height: 0px;
309
+ pointer-events: none;
310
+ }
311
+
305
312
  .rtl > .dropdown {
306
313
  -ms-transform-origin: left top;
307
314
  -webkit-transform-origin: left top;
@@ -118,8 +118,8 @@ export class Select {
118
118
  handleChildChange(_) {
119
119
  // on update of children or children selected state, reset button text and rerender
120
120
  this.setButtonText();
121
- forceUpdate(this.el);
122
121
  this.optionListEl.handleChildChange(_);
122
+ forceUpdate(this.el);
123
123
  }
124
124
  componentDidLoad() {
125
125
  this.wmSelectDidLoad.emit();
@@ -197,14 +197,14 @@ export class Select {
197
197
  const paddingLeft = parseInt(computedStyle.getPropertyValue("padding-left").slice(0, -2));
198
198
  const paddingRight = parseInt(computedStyle.getPropertyValue("padding-right").slice(0, -2));
199
199
  const availableSpace = this.buttonEl.clientWidth - paddingLeft - paddingRight - overflowCounterWidth;
200
- let optionsWidths = this.displayedOptions.map((x) => x.shadowRoot.querySelector(".option-text").clientWidth);
201
- let optionsTotalWidth = optionsWidths.reduce((acc, x) => acc + x, 0);
202
200
  this.overflowCount = 0;
201
+ this.measurementAreaEl.textContent = this.displayedOptions.map((x) => x.textContent).join(", ");
202
+ let optionsTotalWidth = this.measurementAreaEl.clientWidth;
203
203
  while (optionsTotalWidth > availableSpace && this.displayedOptions.length > 1) {
204
204
  this.overflowCount++;
205
- optionsTotalWidth -= optionsWidths[optionsWidths.length - 1];
206
- optionsWidths.pop();
207
205
  this.displayedOptions.pop();
206
+ this.measurementAreaEl.textContent = this.displayedOptions.map((x) => x.textContent).join(", ");
207
+ optionsTotalWidth = this.measurementAreaEl.clientWidth;
208
208
  }
209
209
  }
210
210
  }
@@ -244,7 +244,7 @@ export class Select {
244
244
  };
245
245
  return (h(Host, { onBlur: (ev) => this.handleComponentBlur(ev) }, h("div", { class: `wrapper ${getTextDir()} label-${this.labelPosition} ${this.errorMessage ? "invalid" : ""}` }, h("div", { class: "label-wrapper" }, h("label", { class: "label", id: "label", htmlFor: "selectbtn" }, this.label,
246
246
  // we can't use aria-required or required attributes because it's invalid on the elements we're using (button controlling a listbox)
247
- this.requiredField ? (h("span", { class: "required" }, h("span", { class: "sr-only" }, globalMessages.requiredField), h("span", { "aria-hidden": "true" }, "*"))) : (""))), h("div", { class: "button-wrapper" }, h("button", Object.assign({}, buttonProps, { class: "displayedoption", ref: (el) => (this.buttonEl = el), onBlur: (ev) => this.handleButtonBlur(ev), onFocus: () => this.close() }), h("span", { class: `overflowcontrol ${showSubinfo ? "hassubinfo" : ""}` }, h("span", { class: "button-text" }, this.renderButtonText()), showSubinfo && h("span", { class: "subinfo" }, this.selectedOptions[0].subinfo)), this.renderOverflowCount()), h("div", { class: `dropdown ${this.isExpanded ? "open" : ""} ${this.openUp ? "upwards" : ""}`, ref: (el) => (this.dropdownEl = el) }, h("priv-option-list", { ref: (el) => (this.optionListEl = el), multiple: this.multiple, search: this.search, selectAll: this.selectAll, searchPlaceholder: this.searchPlaceholder, onOptionListCloseRequested: () => this.close(), onOptionListAllSelected: () => this.wmSelectAllSelected.emit(), onOptionListAllDeselected: () => this.wmSelectAllDeselected.emit() }, h("slot", null))), h("div", { id: "error", class: this.errorMessage ? "error-message" : "" }, this.errorMessage), h("div", { id: "announcement", "aria-live": "polite", "aria-atomic": "true", class: "sr-only", ref: (el) => (this.liveRegionEl = el) }, this.announcement)))));
247
+ this.requiredField ? (h("span", { class: "required" }, h("span", { class: "sr-only" }, globalMessages.requiredField), h("span", { "aria-hidden": "true" }, "*"))) : (""))), h("div", { class: "button-wrapper" }, h("button", Object.assign({}, buttonProps, { class: "displayedoption", ref: (el) => (this.buttonEl = el), onBlur: (ev) => this.handleButtonBlur(ev), onFocus: () => this.close() }), h("span", { class: `overflowcontrol ${showSubinfo ? "hassubinfo" : ""}` }, h("span", { class: "button-text" }, this.renderButtonText()), showSubinfo && h("span", { class: "subinfo" }, this.selectedOptions[0].subinfo)), this.renderOverflowCount(), h("div", { ref: (el) => (this.measurementAreaEl = el), class: "measurement-area", "aria-hidden": "true" })), h("div", { class: `dropdown ${this.isExpanded ? "open" : ""} ${this.openUp ? "upwards" : ""}`, ref: (el) => (this.dropdownEl = el) }, h("priv-option-list", { ref: (el) => (this.optionListEl = el), multiple: this.multiple, search: this.search, selectAll: this.selectAll, searchPlaceholder: this.searchPlaceholder, onOptionListCloseRequested: () => this.close(), onOptionListAllSelected: () => this.wmSelectAllSelected.emit(), onOptionListAllDeselected: () => this.wmSelectAllDeselected.emit() }, h("slot", null))), h("div", { id: "error", class: this.errorMessage ? "error-message" : "" }, this.errorMessage), h("div", { id: "announcement", "aria-live": "polite", "aria-atomic": "true", class: "sr-only", ref: (el) => (this.liveRegionEl = el) }, this.announcement)))));
248
248
  }
249
249
  static get is() { return "wm-select"; }
250
250
  static get encapsulation() { return "shadow"; }
@@ -2,7 +2,7 @@ import { newSpecPage } from "@stencil/core/testing";
2
2
  import * as globalFuncs from "../../../global/functions";
3
3
  jest.spyOn(globalFuncs, "getTextDir").mockImplementation(() => "rtl");
4
4
  import { Select } from "./wm-select";
5
- import { Option } from "../../wm-option/wm-option";
5
+ import { Option } from "../wm-option/wm-option";
6
6
  // mock MutationObserver
7
7
  global.MutationObserver = jest.fn().mockImplementation(() => ({
8
8
  observe: jest.fn(),
@@ -65,7 +65,7 @@ export class Modal {
65
65
  componentWillLoad() {
66
66
  if (this.elementToFocus === "primary" || this.elementToFocus === "secondary") {
67
67
  if (!this.el.id) {
68
- console.error("For accessibility purposes you need to set the modal content wrapper's id to 'content-[id of wm-modal].");
68
+ console.error("For accessibility purposes you need to set the modal content wrapper's id to 'content-[id of wm-modal]'.");
69
69
  }
70
70
  }
71
71
  this.el.focus = () => {