@watermarkinsights/ripple 5.20.0-alpha.1 → 5.20.0-alpha.10

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 (178) hide show
  1. package/dist/cjs/{app-globals-e741af80.js → app-globals-259a270b.js} +1 -1
  2. package/dist/cjs/loader.cjs.js +2 -2
  3. package/dist/cjs/priv-option-list.cjs.entry.js +2 -4
  4. package/dist/cjs/ripple.cjs.js +2 -2
  5. package/dist/cjs/wm-option_2.cjs.entry.js +175 -95
  6. package/dist/cjs/wm-tab-item_3.cjs.entry.js +74 -110
  7. package/dist/cjs/wm-tag-input.cjs.entry.js +2 -2
  8. package/dist/cjs/wm-textarea.cjs.entry.js +1 -1
  9. package/dist/cjs/wm-timepicker.cjs.entry.js +2 -2
  10. package/dist/cjs/wm-toggletip.cjs.entry.js +3 -3
  11. package/dist/cjs/wm-uploader.cjs.entry.js +2 -2
  12. package/dist/collection/components/selects/priv-option-list/priv-option-list.js +2 -4
  13. package/dist/collection/components/selects/wm-select/wm-select.css +67 -55
  14. package/dist/collection/components/selects/wm-select/wm-select.js +186 -110
  15. package/dist/collection/components/wm-tabs/wm-tab-item/wm-tab-item.css +4 -3
  16. package/dist/collection/components/wm-tabs/wm-tab-item/wm-tab-item.js +2 -13
  17. package/dist/collection/components/wm-tabs/wm-tab-list/wm-tab-list.css +17 -5
  18. package/dist/collection/components/wm-tabs/wm-tab-list/wm-tab-list.js +76 -110
  19. package/dist/collection/components/wm-tabs/wm-tab-panel/wm-tab-panel.js +1 -1
  20. package/dist/collection/components/wm-tag-input/wm-tag-input.js +2 -2
  21. package/dist/collection/components/wm-textarea/wm-textarea.js +1 -1
  22. package/dist/collection/components/wm-timepicker/wm-timepicker.js +2 -2
  23. package/dist/collection/components/wm-toggletip/wm-toggletip.js +3 -3
  24. package/dist/collection/components/wm-uploader/wm-uploader.js +2 -2
  25. package/dist/esm/{app-globals-8edefb94.js → app-globals-ed8cd888.js} +1 -1
  26. package/dist/esm/{chartFunctions-3a54f8ac.js → chartFunctions-613e9c87.js} +1 -1
  27. package/dist/esm/{functions-669184a6.js → functions-38e392cb.js} +1 -1
  28. package/dist/esm/{intl-7906e2d7.js → intl-0b8f342e.js} +1 -1
  29. package/dist/esm/loader.js +2 -2
  30. package/dist/esm/priv-calendar.entry.js +1 -1
  31. package/dist/esm/priv-chart-popover.entry.js +1 -1
  32. package/dist/esm/priv-option-list.entry.js +4 -6
  33. package/dist/esm/ripple.js +2 -2
  34. package/dist/esm/wm-action-menu_2.entry.js +1 -1
  35. package/dist/esm/wm-button.entry.js +1 -1
  36. package/dist/esm/wm-chart.entry.js +3 -3
  37. package/dist/esm/wm-date-range.entry.js +1 -1
  38. package/dist/esm/wm-datepicker.entry.js +1 -1
  39. package/dist/esm/wm-file.entry.js +1 -1
  40. package/dist/esm/wm-flyout.entry.js +2 -2
  41. package/dist/esm/wm-input.entry.js +2 -2
  42. package/dist/esm/wm-line-chart.entry.js +3 -3
  43. package/dist/esm/wm-modal-pss_3.entry.js +2 -2
  44. package/dist/esm/wm-modal_3.entry.js +2 -2
  45. package/dist/esm/wm-navigation_3.entry.js +2 -2
  46. package/dist/esm/wm-navigator.entry.js +1 -1
  47. package/dist/esm/wm-nested-select.entry.js +2 -2
  48. package/dist/esm/wm-optgroup.entry.js +1 -1
  49. package/dist/esm/wm-option_2.entry.js +177 -97
  50. package/dist/esm/wm-pagination.entry.js +2 -2
  51. package/dist/esm/wm-progress-indicator_3.entry.js +2 -2
  52. package/dist/esm/wm-search.entry.js +2 -2
  53. package/dist/esm/wm-snackbar.entry.js +2 -2
  54. package/dist/esm/wm-tab-item_3.entry.js +75 -111
  55. package/dist/esm/wm-tag-input.entry.js +4 -4
  56. package/dist/esm/wm-tag-option.entry.js +1 -1
  57. package/dist/esm/wm-textarea.entry.js +3 -3
  58. package/dist/esm/wm-timepicker.entry.js +3 -3
  59. package/dist/esm/wm-toggletip.entry.js +4 -4
  60. package/dist/esm/wm-uploader.entry.js +4 -4
  61. package/dist/esm-es5/app-globals-ed8cd888.js +1 -0
  62. package/dist/esm-es5/{chartFunctions-3a54f8ac.js → chartFunctions-613e9c87.js} +1 -1
  63. package/dist/esm-es5/{functions-669184a6.js → functions-38e392cb.js} +1 -1
  64. package/dist/esm-es5/{intl-7906e2d7.js → intl-0b8f342e.js} +1 -1
  65. package/dist/esm-es5/loader.js +1 -1
  66. package/dist/esm-es5/priv-calendar.entry.js +1 -1
  67. package/dist/esm-es5/priv-chart-popover.entry.js +1 -1
  68. package/dist/esm-es5/priv-option-list.entry.js +1 -1
  69. package/dist/esm-es5/ripple.js +1 -1
  70. package/dist/esm-es5/wm-action-menu_2.entry.js +1 -1
  71. package/dist/esm-es5/wm-button.entry.js +1 -1
  72. package/dist/esm-es5/wm-chart.entry.js +1 -1
  73. package/dist/esm-es5/wm-date-range.entry.js +1 -1
  74. package/dist/esm-es5/wm-datepicker.entry.js +1 -1
  75. package/dist/esm-es5/wm-file.entry.js +1 -1
  76. package/dist/esm-es5/wm-flyout.entry.js +1 -1
  77. package/dist/esm-es5/wm-input.entry.js +1 -1
  78. package/dist/esm-es5/wm-line-chart.entry.js +1 -1
  79. package/dist/esm-es5/wm-modal-pss_3.entry.js +1 -1
  80. package/dist/esm-es5/wm-modal_3.entry.js +1 -1
  81. package/dist/esm-es5/wm-navigation_3.entry.js +1 -1
  82. package/dist/esm-es5/wm-navigator.entry.js +1 -1
  83. package/dist/esm-es5/wm-nested-select.entry.js +1 -1
  84. package/dist/esm-es5/wm-optgroup.entry.js +1 -1
  85. package/dist/esm-es5/wm-option_2.entry.js +1 -1
  86. package/dist/esm-es5/wm-pagination.entry.js +1 -1
  87. package/dist/esm-es5/wm-progress-indicator_3.entry.js +1 -1
  88. package/dist/esm-es5/wm-search.entry.js +1 -1
  89. package/dist/esm-es5/wm-snackbar.entry.js +1 -1
  90. package/dist/esm-es5/wm-tab-item_3.entry.js +1 -1
  91. package/dist/esm-es5/wm-tag-input.entry.js +1 -1
  92. package/dist/esm-es5/wm-tag-option.entry.js +1 -1
  93. package/dist/esm-es5/wm-textarea.entry.js +1 -1
  94. package/dist/esm-es5/wm-timepicker.entry.js +1 -1
  95. package/dist/esm-es5/wm-toggletip.entry.js +1 -1
  96. package/dist/esm-es5/wm-uploader.entry.js +1 -1
  97. package/dist/ripple/{p-6d32911c.system.entry.js → p-00eaa361.system.entry.js} +1 -1
  98. package/dist/ripple/{p-c85dae6b.entry.js → p-0825151e.entry.js} +1 -1
  99. package/dist/ripple/{p-c70fa14f.entry.js → p-0bce3f83.entry.js} +1 -1
  100. package/dist/ripple/{p-69b38da5.entry.js → p-118093e1.entry.js} +1 -1
  101. package/dist/ripple/{p-ba6d438c.system.entry.js → p-17964357.system.entry.js} +1 -1
  102. package/dist/ripple/{p-bd37b0f9.system.entry.js → p-1a89139d.system.entry.js} +1 -1
  103. package/dist/ripple/{p-03759d86.system.entry.js → p-1fcf0ea8.system.entry.js} +1 -1
  104. package/dist/ripple/{p-bdac9bec.entry.js → p-2508b801.entry.js} +1 -1
  105. package/dist/ripple/{p-c34346d5.entry.js → p-26ffcd83.entry.js} +1 -1
  106. package/dist/ripple/{p-55cdfcb4.system.entry.js → p-2b7259cb.system.entry.js} +1 -1
  107. package/dist/ripple/{p-ff6b7376.system.entry.js → p-2db6573e.system.entry.js} +1 -1
  108. package/dist/ripple/{p-1efa25b5.system.entry.js → p-3133ce3c.system.entry.js} +1 -1
  109. package/dist/ripple/{p-9ac6957b.entry.js → p-31bac55d.entry.js} +1 -1
  110. package/dist/ripple/p-3422832f.entry.js +1 -0
  111. package/dist/ripple/{p-24e17026.entry.js → p-3612ee73.entry.js} +1 -1
  112. package/dist/ripple/{p-21c100d8.entry.js → p-39a4934f.entry.js} +1 -1
  113. package/dist/ripple/{p-54759960.entry.js → p-41664372.entry.js} +1 -1
  114. package/dist/ripple/{p-c8dfc321.system.entry.js → p-44cc05f6.system.entry.js} +1 -1
  115. package/dist/ripple/{p-c73882de.system.entry.js → p-4602304a.system.entry.js} +1 -1
  116. package/dist/ripple/{p-bb364d6b.entry.js → p-4b8f7d1e.entry.js} +1 -1
  117. package/dist/ripple/{p-b55883ee.entry.js → p-4d0abf7a.entry.js} +1 -1
  118. package/dist/ripple/{p-e2239af2.entry.js → p-4df8346a.entry.js} +1 -1
  119. package/dist/ripple/{p-23c44c11.system.entry.js → p-507ea41f.system.entry.js} +1 -1
  120. package/dist/ripple/{p-26ab5004.system.entry.js → p-5405df80.system.entry.js} +1 -1
  121. package/dist/ripple/{p-9499fa62.entry.js → p-56b6d9f6.entry.js} +1 -1
  122. package/dist/ripple/{p-4d5de385.system.entry.js → p-56e376b2.system.entry.js} +1 -1
  123. package/dist/ripple/p-598faa0e.js +1 -0
  124. package/dist/ripple/{p-88a7ccee.system.js → p-608971f2.system.js} +1 -1
  125. package/dist/ripple/{p-6ec4129b.entry.js → p-60e16c79.entry.js} +1 -1
  126. package/dist/ripple/{p-95f19440.system.js → p-65abcbb4.system.js} +1 -1
  127. package/dist/ripple/{p-65d3f9c4.system.entry.js → p-667fdcbb.system.entry.js} +1 -1
  128. package/dist/ripple/{p-68e90b50.system.entry.js → p-6a70dc0b.system.entry.js} +1 -1
  129. package/dist/ripple/{p-7394f4e9.system.entry.js → p-7134a305.system.entry.js} +1 -1
  130. package/dist/ripple/{p-b6eef7d1.entry.js → p-72e1fdb5.entry.js} +1 -1
  131. package/dist/ripple/{p-047e510d.entry.js → p-7c3bf608.entry.js} +1 -1
  132. package/dist/ripple/{p-176dcfc0.system.js → p-7edd25f7.system.js} +1 -1
  133. package/dist/ripple/p-7f132a0e.system.js +1 -0
  134. package/dist/ripple/{p-ebfa5876.entry.js → p-86a61a2a.entry.js} +1 -1
  135. package/dist/ripple/{p-8f4b4e29.system.entry.js → p-8d1e0f23.system.entry.js} +1 -1
  136. package/dist/ripple/{p-009a6e5a.entry.js → p-8e2f3a45.entry.js} +1 -1
  137. package/dist/ripple/{p-a0ef456d.entry.js → p-8ec6ec53.entry.js} +1 -1
  138. package/dist/ripple/{p-71cc21a4.entry.js → p-908057b2.entry.js} +1 -1
  139. package/dist/ripple/{p-dbc3a44d.entry.js → p-9202d9e9.entry.js} +1 -1
  140. package/dist/ripple/{p-0ae9b6d3.js → p-92c8361f.js} +1 -1
  141. package/dist/ripple/{p-ad10664f.entry.js → p-957f13fb.entry.js} +1 -1
  142. package/dist/ripple/{p-1ad6c15b.entry.js → p-9609d8e7.entry.js} +1 -1
  143. package/dist/ripple/{p-3c9972a6.system.entry.js → p-960d2cf0.system.entry.js} +1 -1
  144. package/dist/ripple/{p-22d4c7e0.system.entry.js → p-96f86eb4.system.entry.js} +1 -1
  145. package/dist/ripple/{p-ea10c498.entry.js → p-9e89655f.entry.js} +1 -1
  146. package/dist/ripple/{p-f8fd7172.system.entry.js → p-a14dee02.system.entry.js} +1 -1
  147. package/dist/ripple/{p-222624ae.entry.js → p-a5c5c64c.entry.js} +1 -1
  148. package/dist/ripple/p-a6f9a3b2.system.js +1 -0
  149. package/dist/ripple/{p-dfa30c3d.entry.js → p-a7cde3fc.entry.js} +1 -1
  150. package/dist/ripple/{p-acb4d87c.system.entry.js → p-abcdd7be.system.entry.js} +1 -1
  151. package/dist/ripple/{p-335a45e6.system.entry.js → p-b0da7ad4.system.entry.js} +1 -1
  152. package/dist/ripple/{p-6a40014e.system.entry.js → p-b1fb99e4.system.entry.js} +1 -1
  153. package/dist/ripple/{p-91669f66.js → p-b511ebfd.js} +1 -1
  154. package/dist/ripple/p-b921ee01.entry.js +1 -0
  155. package/dist/ripple/{p-036fd03b.system.entry.js → p-bde7e77b.system.entry.js} +1 -1
  156. package/dist/ripple/{p-c0f4f1ea.system.entry.js → p-c7f3ef7f.system.entry.js} +1 -1
  157. package/dist/ripple/p-cf5ad12d.system.entry.js +1 -0
  158. package/dist/ripple/{p-1806e50b.js → p-d815809f.js} +1 -1
  159. package/dist/ripple/{p-fb61a10e.system.entry.js → p-e5c34af5.system.entry.js} +1 -1
  160. package/dist/ripple/{p-e1a15515.system.entry.js → p-e660d0b8.system.entry.js} +1 -1
  161. package/dist/ripple/{p-66489ded.entry.js → p-ecd1c2ba.entry.js} +1 -1
  162. package/dist/ripple/{p-5bf2eb50.system.entry.js → p-f4390a0a.system.entry.js} +1 -1
  163. package/dist/ripple/{p-ae2520e4.entry.js → p-f91fc18d.entry.js} +1 -1
  164. package/dist/ripple/{p-1841c319.system.entry.js → p-f9bbb123.system.entry.js} +1 -1
  165. package/dist/ripple/{p-25c17efe.system.entry.js → p-fbad04d7.system.entry.js} +1 -1
  166. package/dist/ripple/ripple.esm.js +1 -1
  167. package/dist/ripple/ripple.js +1 -1
  168. package/dist/types/components/selects/wm-select/wm-select.d.ts +16 -9
  169. package/dist/types/components/wm-tabs/wm-tab-list/wm-tab-list.d.ts +10 -10
  170. package/dist/types/components.d.ts +0 -2
  171. package/package.json +2 -2
  172. package/dist/esm-es5/app-globals-8edefb94.js +0 -1
  173. package/dist/ripple/p-74786c48.system.entry.js +0 -1
  174. package/dist/ripple/p-7b185f34.system.js +0 -1
  175. package/dist/ripple/p-9e1ea6e2.entry.js +0 -1
  176. package/dist/ripple/p-b9db60d3.js +0 -1
  177. package/dist/ripple/p-c650cd07.system.js +0 -1
  178. package/dist/ripple/p-ca11a1be.entry.js +0 -1
@@ -1,14 +1,20 @@
1
1
  import { h, Host } from "@stencil/core";
2
2
  import { forceUpdate } from "@stencil/core";
3
- import { getTextDir, shouldOpenUp, isElOrChild, toBool, handleDisabledAttribute, showTooltip, hideTooltip } from "../../../global/functions";
3
+ import { getTextDir, toBool, handleDisabledAttribute, showTooltip, hideTooltip, debounce, findAllScrollableParents, } from "../../../global/functions";
4
4
  import { globalMessages, selectMessages } from "../../../global/intl";
5
5
  export class Select {
6
6
  constructor() {
7
- this.openUp = false;
7
+ this.scrollableParents = [];
8
+ this.returnFocus = false;
9
+ this.hasAnchor = CSS.supports("top", "anchor(bottom)"); // for FF polyfill
8
10
  //////////////////////////////////////
9
11
  // for multiselect button text
10
12
  this.overflowCount = 0;
11
13
  this.displayedOptions = [];
14
+ this.previousDisplayedOptions = [];
15
+ this.debouncedReposition = debounce(() => {
16
+ this.dropdownPosition();
17
+ }, 100);
12
18
  this.disabled = false;
13
19
  this.maxHeight = "200px";
14
20
  this.label = undefined;
@@ -22,6 +28,8 @@ export class Select {
22
28
  this.searchPlaceholder = selectMessages.searchPlaceholder;
23
29
  this.allSelectedMessage = selectMessages.allSelected;
24
30
  this.isExpanded = false;
31
+ this.isHidden = false;
32
+ this.openUp = false;
25
33
  this.announcement = "";
26
34
  }
27
35
  get childOptions() {
@@ -40,58 +48,152 @@ export class Select {
40
48
  //////////////////////////////////////
41
49
  handleOptionSelection() {
42
50
  if (!this.multiple) {
43
- this.close();
51
+ this.returnFocus = true;
52
+ this.dropdownEl.hidePopover();
44
53
  }
45
54
  }
46
55
  handleChildEnter() {
47
56
  // only occurs for multiselects. handle the click, then close
48
- this.close();
49
- }
50
- closePopupOnEscape() {
51
- this.close();
52
- }
53
- handleOptionBlur(ev) {
54
- // if the Option is blurred to something other than the component emit a blur event with the appropriate relatedTarget
55
- // keeps our component's blur events accurate, and closes when focusing browser address bar
56
- if (!isElOrChild(this.el, ev.detail.relatedTarget)) {
57
- const event = new CustomEvent("blur");
58
- // @ts-ignore
59
- event.relatedTarget = ev.detail.relatedTarget;
60
- this.el.dispatchEvent(event);
57
+ this.returnFocus = true;
58
+ this.dropdownEl.hidePopover();
59
+ }
60
+ closeDropdownOnEscape() {
61
+ this.returnFocus = true;
62
+ this.dropdownEl.hidePopover();
63
+ }
64
+ handleBeforeToggle() {
65
+ if (!this.hasAnchor) {
66
+ // Start hidden to prevent flash during positioning calculation
67
+ this.isHidden = true;
61
68
  }
62
69
  }
63
- handleClick(ev) {
64
- if (!isElOrChild(this.el, ev.target)) {
65
- this.close();
70
+ handleToggle(ev) {
71
+ ev.newState === "open" ? this.open() : this.close();
72
+ }
73
+ dropdownPosition() {
74
+ // polyfill for opening up or down + positioning according to screen
75
+ // (must recalculate on scroll, resize)
76
+ // Using transform for better performance - only affects composite layer, no layout recalculation
77
+ const buttonElRect = this.buttonEl.getBoundingClientRect();
78
+ const spaceAbove = buttonElRect.top;
79
+ const spaceBelow = document.documentElement.clientHeight - buttonElRect.bottom;
80
+ const dropdownHeight = this.dropdownEl.clientHeight;
81
+ // Clear any previously set positioning properties
82
+ this.el.style.removeProperty("--dropdown-translate-y");
83
+ this.el.style.removeProperty("--dropdown-max-height");
84
+ this.el.style.removeProperty("--dropdown-left");
85
+ // Set horizontal position and width to match button
86
+ this.el.style.setProperty("--dropdown-left", buttonElRect.left + "px");
87
+ this.el.style.setProperty("--button-width", buttonElRect.width + "px");
88
+ if (dropdownHeight <= spaceBelow) {
89
+ // Case 1: Enough space below - position dropdown below the button
90
+ this.el.style.setProperty("--dropdown-translate-y", buttonElRect.bottom + "px");
91
+ }
92
+ else if (dropdownHeight <= spaceAbove) {
93
+ // Case 2: Not enough space below, but enough above - position dropdown above the button
94
+ this.el.style.setProperty("--dropdown-translate-y", buttonElRect.top - dropdownHeight + "px");
95
+ }
96
+ else {
97
+ // Case 3: Not enough space in either direction - use the larger available space and constrain height
98
+ if (spaceBelow >= spaceAbove) {
99
+ // Use space below and constrain dropdown height
100
+ this.el.style.setProperty("--dropdown-translate-y", buttonElRect.bottom + "px");
101
+ this.el.style.setProperty("--dropdown-max-height", spaceBelow + "px");
102
+ }
103
+ else {
104
+ // Use space above and constrain dropdown height
105
+ this.el.style.setProperty("--dropdown-translate-y", "0px");
106
+ this.el.style.setProperty("--dropdown-max-height", spaceAbove + "px");
107
+ }
66
108
  }
109
+ this.isHidden = false;
67
110
  }
68
- handleButtonBlur(ev) {
69
- if (isElOrChild(this.el, ev.relatedTarget)) {
70
- // do not emit a blur event when opening the dropdown and focusing the Options
71
- ev.stopPropagation();
111
+ open() {
112
+ if (!this.isExpanded && !this.isDisabled) {
113
+ // polyfill for browsers without anchor() support (FF)
114
+ if (!this.hasAnchor) {
115
+ this.dropdownPosition();
116
+ }
117
+ requestAnimationFrame(() => {
118
+ const anchorRect = this.buttonEl.getBoundingClientRect();
119
+ const hasSpaceBelow = this.dropdownEl.offsetHeight <= document.documentElement.clientHeight - anchorRect.bottom;
120
+ const hasSpaceAbove = this.dropdownEl.offsetHeight <= anchorRect.top;
121
+ this.openUp = !hasSpaceBelow && hasSpaceAbove;
122
+ this.isExpanded = true;
123
+ });
124
+ setTimeout(() => {
125
+ // focusing doesn't work when within requestAnimationFrame
126
+ this.optionListEl.handleInitialFocus(this.elToFocus);
127
+ this.elToFocus = undefined;
128
+ }, 50);
129
+ }
130
+ }
131
+ close() {
132
+ if (this.isExpanded) {
133
+ this.optionListEl.unfocusAll();
134
+ window.setTimeout(() => {
135
+ if (!this.hasAnchor) {
136
+ this.isHidden = true;
137
+ }
138
+ if (this.optionListEl.multiple) {
139
+ this.optionListEl.updateOptionVisibility();
140
+ }
141
+ // clear search field, reset filtered / bolded state of wm-options
142
+ if (this.search) {
143
+ this.optionListEl.clearSearch();
144
+ }
145
+ this.isExpanded = false;
146
+ }, 150);
147
+ if (this.returnFocus) {
148
+ requestAnimationFrame(() => {
149
+ this.buttonEl.focus();
150
+ this.returnFocus = false;
151
+ });
152
+ }
72
153
  }
73
154
  }
74
155
  handleKey(ev) {
75
156
  switch (ev.key) {
76
157
  case "Tab":
77
158
  // if tabbing backwards, close and return focus to button. Otherwise, close but do not redirect focus.
78
- this.close(ev.shiftKey ? true : false);
159
+ if (this.isExpanded && ev.shiftKey) {
160
+ this.returnFocus = true;
161
+ }
162
+ this.dropdownEl.hidePopover();
79
163
  break;
80
164
  case "ArrowDown":
81
165
  if (this.isExpanded === false) {
82
166
  ev.preventDefault();
83
- this.open("next");
167
+ this.elToFocus = "next";
168
+ this.dropdownEl.showPopover();
84
169
  }
85
170
  break;
86
171
  case "ArrowUp":
87
172
  if (this.isExpanded === false) {
88
173
  ev.preventDefault();
89
- this.open("previous");
174
+ this.elToFocus = "previous";
175
+ this.dropdownEl.showPopover();
90
176
  }
91
177
  break;
92
178
  }
93
179
  }
180
+ handleResize() {
181
+ if (!this.hasAnchor && this.isExpanded) {
182
+ this.isHidden = true;
183
+ this.debouncedReposition();
184
+ }
185
+ }
186
+ handleScroll() {
187
+ if (this.isExpanded) {
188
+ this.isHidden = true;
189
+ this.debouncedReposition();
190
+ }
191
+ }
94
192
  componentWillLoad() {
193
+ if (!this.hasAnchor) {
194
+ // Start hidden to prevent flash on first load
195
+ this.isHidden = true;
196
+ }
95
197
  if (!this.label) {
96
198
  console.error("For accessibility purposes, this component requires a label (even if `label-position` is set to `none`).");
97
199
  }
@@ -108,8 +210,6 @@ export class Select {
108
210
  });
109
211
  }
110
212
  handleChildChange() {
111
- // on update of children or children selected state, reset button text and rerender
112
- this.setButtonText();
113
213
  forceUpdate(this.el);
114
214
  if (this.multiple) {
115
215
  // update state of clone options
@@ -118,43 +218,19 @@ export class Select {
118
218
  }
119
219
  componentDidLoad() {
120
220
  this.wmSelectDidLoad.emit();
121
- this.dropdownEl.classList.add("hidden");
122
- forceUpdate(this.el);
123
- this.setButtonText();
124
- }
125
- open(optionToSelect) {
126
- if (!this.isDisabled) {
127
- this.openUp = shouldOpenUp(this.el, this.dropdownEl.clientHeight, this.labelEl.clientHeight);
128
- this.isExpanded = true;
129
- this.dropdownEl.classList.add("open");
130
- this.dropdownEl.classList.remove("hidden");
131
- window.requestAnimationFrame(() => {
132
- this.optionListEl.handleInitialFocus(optionToSelect);
133
- });
134
- }
135
- }
136
- close(returnFocus = true) {
137
- if (this.isExpanded) {
138
- this.isExpanded = false;
139
- this.optionListEl.unfocusAll();
140
- this.dropdownEl.classList.remove("open");
141
- window.setTimeout(() => {
142
- this.dropdownEl.classList.add("hidden");
143
- if (this.optionListEl.multiple) {
144
- this.optionListEl.updateOptionVisibility();
221
+ if (!this.hasAnchor) {
222
+ this.scrollableParents = findAllScrollableParents(this.el);
223
+ // Add scroll listeners to all scrollable parents
224
+ this.scrollableParents.forEach((parent) => {
225
+ if (parent === document.documentElement) {
226
+ // For document element, listen to window scroll event
227
+ window.addEventListener("scroll", () => this.handleScroll());
145
228
  }
146
- // clear search field, reset filtered / bolded state of wm-options
147
- if (this.search) {
148
- this.optionListEl.clearSearch();
149
- }
150
- // Returns focus to button after popup closes (no need if user is tabbing)
151
- // Delay is necessary for screenreader to get new expanded state before focus
152
- // window.requestAnimationFrame is probably enough, but since we are already using setTimeout it may as well be here
153
- // also UX wise, it makes sense for the button to only be focused after the animation is complete
154
- if (returnFocus) {
155
- this.buttonEl.focus();
229
+ else {
230
+ // For regular elements, listen to their scroll event
231
+ parent.addEventListener("scroll", () => this.handleScroll());
156
232
  }
157
- }, 150);
233
+ });
158
234
  }
159
235
  }
160
236
  announceError() {
@@ -168,7 +244,6 @@ export class Select {
168
244
  handleComponentBlur(ev) {
169
245
  // Do not close or emit custom blur event when blurring to an element inside (wm-option)
170
246
  if (!this.el.contains(ev.relatedTarget)) {
171
- this.close(false);
172
247
  this.wmSelectBlurred.emit();
173
248
  }
174
249
  }
@@ -178,28 +253,6 @@ export class Select {
178
253
  showTooltip("right", ev.target, this.label);
179
254
  }
180
255
  }
181
- setButtonText() {
182
- this.displayedOptions = this.childOptions.filter((x) => x.selected);
183
- // handle overflow + counter for multiselect
184
- if (this.multiple) {
185
- // this is a fixed measurement accounting for the max width of a 3 character overflow counter
186
- const overflowCounterWidth = 38;
187
- const computedStyle = window.getComputedStyle(this.buttonEl);
188
- // there seems to be no quick way to get an elements width without padding, except for subtracting padding manually
189
- const paddingLeft = parseInt(computedStyle.getPropertyValue("padding-left").slice(0, -2));
190
- const paddingRight = parseInt(computedStyle.getPropertyValue("padding-right").slice(0, -2));
191
- const availableSpace = this.buttonEl.clientWidth - paddingLeft - paddingRight - overflowCounterWidth;
192
- this.overflowCount = 0;
193
- this.measurementAreaEl.textContent = this.displayedOptions.map((x) => x.textContent).join(", ");
194
- let optionsTotalWidth = this.measurementAreaEl.clientWidth;
195
- while (optionsTotalWidth > availableSpace && this.displayedOptions.length > 1) {
196
- this.overflowCount++;
197
- this.displayedOptions.pop();
198
- this.measurementAreaEl.textContent = this.displayedOptions.map((x) => x.textContent).join(", ");
199
- optionsTotalWidth = this.measurementAreaEl.clientWidth;
200
- }
201
- }
202
- }
203
256
  announce(message) {
204
257
  // \u00A0 is a non-breaking space character, which causes the message to be read as a new one
205
258
  if (this.liveRegionEl.textContent === message) {
@@ -208,6 +261,7 @@ export class Select {
208
261
  this.announcement = message;
209
262
  }
210
263
  renderButtonText() {
264
+ this.displayedOptions = this.childOptions.filter((x) => x.selected);
211
265
  if (this.multiple && this.displayedOptions.length < 1) {
212
266
  return h("span", null, this.placeholder);
213
267
  }
@@ -215,6 +269,28 @@ export class Select {
215
269
  return this.allSelectedMessage;
216
270
  }
217
271
  else {
272
+ // handle overflow + counter for multiselect
273
+ // only bother if things have changed
274
+ const hasChanged = this.displayedOptions !== this.previousDisplayedOptions;
275
+ if (this.multiple && hasChanged) {
276
+ // this is a fixed measurement accounting for the max width of a 3 character overflow counter
277
+ const overflowCounterWidth = 38;
278
+ const computedStyle = window.getComputedStyle(this.buttonEl);
279
+ // there seems to be no quick way to get an elements width without padding, except for subtracting padding manually
280
+ const paddingLeft = parseInt(computedStyle.getPropertyValue("padding-left").slice(0, -2));
281
+ const paddingRight = parseInt(computedStyle.getPropertyValue("padding-right").slice(0, -2));
282
+ const availableSpace = this.buttonEl.clientWidth - paddingLeft - paddingRight - overflowCounterWidth;
283
+ this.overflowCount = 0;
284
+ this.measurementAreaEl.textContent = this.displayedOptions.map((x) => x.textContent).join(", ");
285
+ let optionsTotalWidth = this.measurementAreaEl.clientWidth;
286
+ while (optionsTotalWidth > availableSpace && this.displayedOptions.length > 1) {
287
+ this.overflowCount++;
288
+ this.displayedOptions.pop();
289
+ this.measurementAreaEl.textContent = this.displayedOptions.map((x) => x.textContent).join(", ");
290
+ optionsTotalWidth = this.measurementAreaEl.clientWidth;
291
+ }
292
+ this.previousDisplayedOptions = this.displayedOptions;
293
+ }
218
294
  return this.displayedOptions.map((x, idx) => (h("span", null, idx > 0 ? ", " : "", x.textContent)));
219
295
  }
220
296
  }
@@ -225,18 +301,22 @@ export class Select {
225
301
  }
226
302
  render() {
227
303
  const showSubinfo = !this.multiple && this.selectedOptions.length > 0 && this.selectedOptions[0].subinfo;
228
- const buttonProps = {
229
- id: "selectbtn",
230
- ["disabled"]: this.isDisabled,
231
- ["aria-controls"]: "list",
232
- ["aria-labelledby"]: "label selectbtn",
233
- ["aria-describedby"]: "error",
234
- ["aria-expanded"]: this.isExpanded ? "true" : "false",
235
- onClick: () => (this.isExpanded ? this.close() : this.open()),
236
- };
237
- return (h(Host, { key: '27f57d30b836eac8dc27ae98a425015d86a0948b', onBlur: (ev) => this.handleComponentBlur(ev) }, h("div", { key: '8f48d8e8d616244350e61d6e81f350640131bbf0', class: `wrapper ${getTextDir()} label-${this.labelPosition} ${this.errorMessage ? "invalid" : ""}` }, h("div", { key: '39d3bcec9b67d671a6bdbb6a3ee738832189ea51', ref: (el) => (this.labelEl = el), class: "label-wrapper" }, h("label", { key: 'b0bb90a215ac20de94afa8dba56e839bdc590dc1', class: "label", id: "label", htmlFor: "selectbtn", onMouseEnter: (ev) => this.handleLabelMouseEnter(ev), onMouseLeave: () => hideTooltip() }, this.label),
304
+ return (h(Host, { key: '4ec7d687b40ffcef80fbce21e6880680c72d03a7', onBlur: (ev) => this.handleComponentBlur(ev) }, h("div", { key: 'c400196d862a763af6f4f5d4663a8f3e805a9ddd', class: `wrapper ${getTextDir()} label-${this.labelPosition} ${this.errorMessage ? "invalid" : ""}` }, h("div", { key: '1c7df9eee5ebc62a12bd36e97918e144c7e4dc72', class: "label-wrapper" }, h("label", { key: '752c9ce6491c959afda2105a5e2c6063ce4ee52e', class: "label", id: "label", htmlFor: "selectbtn", onMouseEnter: (ev) => this.handleLabelMouseEnter(ev), onMouseLeave: () => hideTooltip() }, this.label),
238
305
  // we can't use aria-required because the listbox is in a sub-component and it is not announced
239
- this.requiredField && (h("span", { key: '4a5648503a023ff1eba34db936d49709e14da9f1', class: "required" }, h("span", { key: '3fe783c7174d3d827b20589cad412d32fa4cd978', class: "sr-only" }, globalMessages.requiredField), h("span", { key: '85ac4ca35f1077ade1bdda403b8888cc206ff28e', "aria-hidden": "true" }, "*")))), h("div", { key: 'c2e70d87db2d533713ac9c5a877ddba98a9a9a2f', class: "button-wrapper" }, h("button", Object.assign({ key: '460c6ac5cde8637b0098201966ca4268301ac2b7' }, buttonProps, { class: "displayedoption", ref: (el) => (this.buttonEl = el), onBlur: (ev) => this.handleButtonBlur(ev) }), h("span", { key: '3af3357f45ceacc5689e90e2bdc6459cab591c2f', class: `overflowcontrol ${showSubinfo ? "hassubinfo" : ""}` }, h("span", { key: 'bd9869db1146e54cc47c2965ebe2776873e2a18e', class: "button-text" }, this.renderButtonText()), showSubinfo && h("span", { key: 'b22d952625e93fab98ebb1b688101fd8891a4af7', class: "subinfo" }, this.selectedOptions[0].subinfo)), h("div", { key: '1f6448ee167d1847eff8fb5bc7a30e0a964e6efe', class: `expand-icon svg-icon ${this.isExpanded ? "svg-expand-less" : "svg-expand-more"}` }), this.renderOverflowCount(), h("div", { key: '0d550b97a3e08e9b708f2f4c3d91f9cac76ba5d8', ref: (el) => (this.measurementAreaEl = el), class: "measurement-area", "aria-hidden": "true" })), h("div", { key: '59cc7fcfa25d9d3eab8e4d70cdcd365e36e160ad', class: `dropdown ${this.isExpanded ? "open" : ""} ${this.openUp ? "upwards" : ""}`, ref: (el) => (this.dropdownEl = el) }, h("priv-option-list", { key: '9fb7d0396527bc18bb8f5d00d64c858470d0698d', ref: (el) => (this.optionListEl = el), multiple: this.multiple, search: this.search, selectAll: this.selectAll, maxHeight: this.maxHeight, searchPlaceholder: this.searchPlaceholder, onOptionListCloseRequested: () => this.close(), onOptionListAllSelected: () => this.wmSelectAllSelected.emit(), onOptionListAllDeselected: () => this.wmSelectAllDeselected.emit() }, h("slot", { key: '4c307bca5104ec962ca050b46adf882fb78bb74a' }))), h("div", { key: '06f11b61b475cc6cd78c2a8278b8455a79405e17', id: "error", class: this.errorMessage ? "error-message" : "" }, this.errorMessage), h("div", { key: '86cf865fbb7fd0e2c88290fe92e6062ada7d9ab6', id: "announcement", "aria-live": "polite", "aria-atomic": "true", class: "sr-only", ref: (el) => (this.liveRegionEl = el) }, this.announcement)))));
306
+ this.requiredField && (h("span", { key: 'c0b4660ed16129c1a3aaf5252aa5e7c71eb42f20', class: "required" }, h("span", { key: '8c4a41df3473c88021f8d73f09fdfd33e3ad1c48', class: "sr-only" }, globalMessages.requiredField), h("span", { key: '303e6f18bef3d30b32508c6192ac363bbc8fb80c', "aria-hidden": "true" }, "*")))), h("div", { key: '7acc269a0e60042549cbc3fc6879b3e471f1b016', class: "button-wrapper" }, h("button", { key: 'd1e7751c22951130f92ca6fdc2c9f253e4e63b5b', id: "selectbtn", disabled: this.isDisabled, "aria-labelledby": "label selectbtn", "aria-describedby": "error", popoverTarget: "dropdown", popoverTargetAction: "toggle", class: "displayedoption", ref: (el) => (this.buttonEl = el) }, h("span", { key: '6236a027968e849c873e1d09bf89910ca627b760', class: `overflowcontrol ${showSubinfo ? "hassubinfo" : ""}` }, h("span", { key: '3af139e809e636873cd53dfb53141c0c606e4963', class: "button-text" }, this.renderButtonText()), showSubinfo && h("span", { key: '5894b37ef490101b0ba38547745f450c0521a8ea', class: "subinfo" }, this.selectedOptions[0].subinfo)), h("div", { key: '6bce5cbddd6160c0d2eeb8de27ed7f0d46fffb38', class: `expand-icon svg-icon ${this.isExpanded ? "svg-expand-less" : "svg-expand-more"}` }), this.renderOverflowCount(), h("div", { key: 'a0d9da60b818f8a576f6fcaab422b9ec31d42fd4', ref: (el) => (this.measurementAreaEl = el), class: "measurement-area", "aria-hidden": "true" })), h("div", { key: 'dc70db1f203700702cf3586412eef64ab108b86f',
307
+ // is-open is for the CSS transition in modern browsers
308
+ // hidden is to wait for position calculations in Firefox
309
+ class: `dropdown ${this.isExpanded ? "is-open" : ""} ${this.isHidden ? "hidden" : ""} ${this.openUp ? "upward" : ""}`, id: "dropdown", popover: "auto", ref: (el) => (this.dropdownEl = el),
310
+ // @ts-ignore -- don't tell typescript but we're in the future
311
+ onToggle: (ev) => this.handleToggle(ev) }, h("priv-option-list", { key: '09db81570f9990ec4cf87f16b52320ec82701a04', ref: (el) => (this.optionListEl = el), multiple: this.multiple, search: this.search, selectAll: this.selectAll, maxHeight: this.maxHeight, searchPlaceholder: this.searchPlaceholder, onOptionListCloseRequested: () => {
312
+ this.dropdownEl.hidePopover();
313
+ }, onOptionListAllSelected: () => {
314
+ this.returnFocus = true;
315
+ this.wmSelectAllSelected.emit();
316
+ }, onOptionListAllDeselected: () => {
317
+ this.returnFocus = true;
318
+ this.wmSelectAllDeselected.emit();
319
+ } }, h("slot", { key: '420515d805ad1039ed3b72bd2968a0a29c27a5fc' }))), h("div", { key: '3bda216f90f3d6b10b92034996d3bdc90a4ffd60', id: "error", class: this.errorMessage ? "error-message" : "" }, this.errorMessage), h("div", { key: '032fb47f7c64c04d518740dbcb31efcd761baed6', id: "announcement", "aria-live": "polite", "aria-atomic": "true", class: "sr-only", ref: (el) => (this.liveRegionEl = el) }, this.announcement)))));
240
320
  }
241
321
  static get is() { return "wm-select"; }
242
322
  static get encapsulation() { return "shadow"; }
@@ -472,6 +552,8 @@ export class Select {
472
552
  static get states() {
473
553
  return {
474
554
  "isExpanded": {},
555
+ "isHidden": {},
556
+ "openUp": {},
475
557
  "announcement": {}
476
558
  };
477
559
  }
@@ -563,28 +645,22 @@ export class Select {
563
645
  "passive": false
564
646
  }, {
565
647
  "name": "wmEscKeyPressed",
566
- "method": "closePopupOnEscape",
648
+ "method": "closeDropdownOnEscape",
567
649
  "target": undefined,
568
650
  "capture": false,
569
651
  "passive": false
570
- }, {
571
- "name": "wmOptionBlurred",
572
- "method": "handleOptionBlur",
573
- "target": undefined,
574
- "capture": false,
575
- "passive": false
576
- }, {
577
- "name": "click",
578
- "method": "handleClick",
579
- "target": "document",
580
- "capture": true,
581
- "passive": false
582
652
  }, {
583
653
  "name": "keydown",
584
654
  "method": "handleKey",
585
655
  "target": undefined,
586
656
  "capture": false,
587
657
  "passive": false
658
+ }, {
659
+ "name": "resize",
660
+ "method": "handleResize",
661
+ "target": "window",
662
+ "capture": false,
663
+ "passive": true
588
664
  }];
589
665
  }
590
666
  }
@@ -870,10 +870,10 @@
870
870
  align-self: stretch;
871
871
  max-width: 80%;
872
872
  flex: 0 0 auto;
873
+ min-width: min-content;
873
874
  }
874
875
 
875
876
  .tab-item {
876
- padding-block: 0.75rem;
877
877
  display: flex;
878
878
  align-self: stretch;
879
879
  list-style-type: none;
@@ -899,10 +899,11 @@
899
899
  position: relative;
900
900
  display: flex;
901
901
  align-items: center;
902
- padding-inline: 1.5rem;
902
+ padding: 0.75rem 1.5rem;
903
903
  white-space: normal;
904
904
  word-break: break-word;
905
905
  width: 100%;
906
+ text-align: center;
906
907
  }
907
908
  .tab-item .tab[aria-selected=true] {
908
909
  font-weight: 700;
@@ -925,5 +926,5 @@
925
926
  }
926
927
  .tab-item:has(:focus-visible) {
927
928
  outline: 3px solid var(--wmcolor-interactive-focus);
928
- outline-offset: -3px;
929
+ outline-offset: -10px;
929
930
  }
@@ -27,20 +27,9 @@ export class TabItem {
27
27
  }
28
28
  render() {
29
29
  const isDark = this.parentTabList && this.parentTabList.customBackground == "dark";
30
- let styles = {};
31
- const padding = this.parentTabList && this.parentTabList.customPadding;
32
- if (padding) {
33
- const bkgSize = parseInt(padding, 10) * 2 || 0;
34
- const units = padding.split(/([0-9]+)/).pop();
35
- styles = {
36
- "padding-left": this.parentTabList.customPadding,
37
- "padding-right": this.parentTabList.customPadding,
38
- "background-size": `calc(100% - ${bkgSize}${units}) 3px`,
39
- };
40
- }
41
- return (h(Host, { key: 'c4233132fdeffae370245ddb4d62e05fc59ac68d', role: "presentation" }, h("li", { key: '43d23f45217e39a9c6e8d6d0f3f5401c1fa7f252', class: `tab-item ${isDark ? "dark" : ""}`, role: "presentation" }, h("a", { key: '4606d7b99a4ebe3e92bc71089458ce4356ef318a', class: `tab`, style: styles, role: "tab", ref: (el) => (this.linkEl = el), onClick: this.tabClicked, id: `tab-link-${this.tabId}`, onKeyDown: (ev) => this.tabPressed(ev), "aria-selected": this.selected ? "true" : "false", tabindex: this.selected ? 0 : -1, onFocus: () => {
30
+ return (h(Host, { key: 'd767cecfc366c666d0920361e1af1eeb2cb120f8', role: "presentation" }, h("li", { key: '05626b99685379b2c774a59eb10d4774f01dcd83', class: `tab-item ${isDark ? "dark" : ""}`, role: "presentation" }, h("a", { key: '3ae61be7ebb1bd1c45cd4a4badddebf990dc5c06', class: `tab`, role: "tab", ref: (el) => (this.linkEl = el), id: `tab-link-${this.tabId}`, onKeyDown: (ev) => this.tabPressed(ev), "aria-selected": this.selected ? "true" : "false", tabindex: this.selected ? 0 : -1, onClick: this.tabClicked, onFocus: () => {
42
31
  this.wmIntTabFocused.emit({ tabItem: this.el });
43
- } }, h("slot", { key: '0ec5fa05c84e7b1e6eb51a3f6e6da39568c44a5c' })))));
32
+ } }, h("slot", { key: '128c129d643610993747736efe64018cdaf5ab31' })))));
44
33
  }
45
34
  static get is() { return "wm-tab-item"; }
46
35
  static get encapsulation() { return "shadow"; }
@@ -872,8 +872,7 @@
872
872
  background: var(--wmcolor-tab-background);
873
873
  display: block;
874
874
  position: relative;
875
- width: fit-content;
876
- max-width: 100%;
875
+ width: 100%;
877
876
  }
878
877
  :host .component-wrapper {
879
878
  display: flex;
@@ -899,7 +898,7 @@
899
898
  }
900
899
  :host .tabcontainer.dark {
901
900
  margin: 0;
902
- padding-inline-start: 0.125rem;
901
+ padding-inline: 0.125rem;
903
902
  }
904
903
  :host .tabcontainer.fade-left.fade-right {
905
904
  mask-image: linear-gradient(90deg, transparent 0, black var(--fade-distance), black calc(100% - var(--fade-distance)), transparent 100%);
@@ -912,6 +911,7 @@
912
911
  }
913
912
  :host wm-button.left-arrow,
914
913
  :host wm-button.right-arrow {
914
+ --icon-size: 1.25rem;
915
915
  display: none;
916
916
  flex-shrink: 0;
917
917
  }
@@ -920,8 +920,20 @@
920
920
  display: block;
921
921
  }
922
922
  :host wm-button.left-arrow {
923
- margin-inline-start: 0.5rem;
923
+ margin-inline: 0.125rem 0.5rem;
924
924
  }
925
925
  :host wm-button.right-arrow {
926
- margin-inline-end: 0.5rem;
926
+ margin-inline: 0.5rem 0.125rem;
927
+ }
928
+ :host .sr-only {
929
+ position: absolute !important;
930
+ width: 1px !important;
931
+ height: 1px !important;
932
+ padding: 0 !important;
933
+ border: 0 !important;
934
+ overflow: hidden !important;
935
+ clip: rect(0, 0, 0, 0) !important;
936
+ clip-path: inset(50%) !important;
937
+ white-space: nowrap !important;
938
+ margin: -1px !important;
927
939
  }