@refinitiv-ui/elements 6.0.0-next.3 → 6.0.2

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 (193) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +3 -15
  3. package/lib/accordion/index.js +2 -2
  4. package/lib/autosuggest/custom-elements.json +5 -15
  5. package/lib/autosuggest/custom-elements.md +14 -14
  6. package/lib/autosuggest/helpers/renderer.d.ts +8 -0
  7. package/lib/autosuggest/helpers/renderer.js +35 -0
  8. package/lib/autosuggest/helpers/types.d.ts +101 -1
  9. package/lib/autosuggest/helpers/utils.d.ts +1 -8
  10. package/lib/autosuggest/helpers/utils.js +0 -27
  11. package/lib/autosuggest/index.d.ts +34 -32
  12. package/lib/autosuggest/index.js +246 -202
  13. package/lib/autosuggest/themes/halo/dark/index.js +1 -1
  14. package/lib/autosuggest/themes/halo/light/index.js +1 -1
  15. package/lib/autosuggest/themes/solar/charcoal/index.js +1 -1
  16. package/lib/autosuggest/themes/solar/pearl/index.js +1 -1
  17. package/lib/button/index.js +2 -1
  18. package/lib/button/themes/halo/dark/index.js +1 -1
  19. package/lib/button/themes/halo/light/index.js +1 -1
  20. package/lib/button/themes/solar/charcoal/index.js +1 -1
  21. package/lib/button/themes/solar/pearl/index.js +1 -1
  22. package/lib/calendar/index.d.ts +1 -1
  23. package/lib/calendar/themes/halo/dark/index.js +1 -1
  24. package/lib/calendar/themes/halo/light/index.js +1 -1
  25. package/lib/calendar/themes/solar/charcoal/index.js +1 -1
  26. package/lib/calendar/themes/solar/pearl/index.js +1 -1
  27. package/lib/chart/plugins/doughnut-center-label.js +1 -1
  28. package/lib/chart/themes/halo/dark/index.js +1 -1
  29. package/lib/chart/themes/halo/light/index.js +1 -1
  30. package/lib/checkbox/index.d.ts +8 -15
  31. package/lib/checkbox/index.js +19 -41
  32. package/lib/checkbox/themes/halo/dark/index.js +1 -1
  33. package/lib/checkbox/themes/halo/light/index.js +1 -1
  34. package/lib/checkbox/themes/solar/charcoal/index.js +1 -1
  35. package/lib/checkbox/themes/solar/pearl/index.js +1 -1
  36. package/lib/clock/custom-elements.json +10 -10
  37. package/lib/clock/custom-elements.md +1 -1
  38. package/lib/clock/index.d.ts +44 -16
  39. package/lib/clock/index.js +178 -61
  40. package/lib/clock/themes/halo/dark/index.js +1 -1
  41. package/lib/clock/themes/halo/light/index.js +1 -1
  42. package/lib/clock/themes/solar/charcoal/index.js +1 -1
  43. package/lib/clock/themes/solar/pearl/index.js +1 -1
  44. package/lib/combo-box/index.d.ts +4 -3
  45. package/lib/combo-box/index.js +7 -3
  46. package/lib/combo-box/themes/halo/dark/index.js +1 -1
  47. package/lib/combo-box/themes/halo/light/index.js +1 -1
  48. package/lib/combo-box/themes/solar/charcoal/index.js +1 -1
  49. package/lib/combo-box/themes/solar/pearl/index.js +1 -1
  50. package/lib/datetime-field/index.d.ts +1 -1
  51. package/lib/datetime-field/utils.d.ts +1 -1
  52. package/lib/datetime-picker/themes/halo/dark/index.js +1 -1
  53. package/lib/datetime-picker/themes/halo/light/index.js +1 -1
  54. package/lib/datetime-picker/themes/solar/charcoal/index.js +1 -1
  55. package/lib/datetime-picker/themes/solar/pearl/index.js +1 -1
  56. package/lib/email-field/themes/halo/dark/index.js +1 -1
  57. package/lib/email-field/themes/halo/light/index.js +1 -1
  58. package/lib/email-field/themes/solar/charcoal/index.js +1 -1
  59. package/lib/email-field/themes/solar/pearl/index.js +1 -1
  60. package/lib/flag/utils/FlagLoader.d.ts +2 -32
  61. package/lib/flag/utils/FlagLoader.js +2 -69
  62. package/lib/heatmap/index.d.ts +2 -2
  63. package/lib/heatmap/themes/halo/dark/index.js +1 -1
  64. package/lib/heatmap/themes/halo/light/index.js +1 -1
  65. package/lib/icon/utils/IconLoader.d.ts +2 -37
  66. package/lib/icon/utils/IconLoader.js +2 -76
  67. package/lib/index.d.ts +1 -1
  68. package/lib/index.js +1 -1
  69. package/lib/interactive-chart/themes/halo/dark/index.js +1 -1
  70. package/lib/interactive-chart/themes/halo/light/index.js +1 -1
  71. package/lib/item/helpers/types.d.ts +6 -6
  72. package/lib/item/index.d.ts +2 -2
  73. package/lib/item/index.js +0 -1
  74. package/lib/item/themes/halo/dark/index.js +1 -1
  75. package/lib/item/themes/halo/light/index.js +1 -1
  76. package/lib/list/elements/list-item.d.ts +30 -0
  77. package/lib/list/elements/list-item.js +19 -0
  78. package/lib/list/elements/list.d.ts +307 -0
  79. package/lib/list/elements/list.js +632 -0
  80. package/lib/list/helpers/renderer.d.ts +0 -1
  81. package/lib/list/helpers/renderer.js +1 -3
  82. package/lib/list/index.d.ts +3 -317
  83. package/lib/list/index.js +3 -641
  84. package/lib/list/themes/halo/dark/index.js +4 -1
  85. package/lib/list/themes/halo/light/index.js +5 -2
  86. package/lib/list/themes/solar/charcoal/index.js +4 -1
  87. package/lib/list/themes/solar/pearl/index.js +4 -1
  88. package/lib/multi-input/index.d.ts +1 -5
  89. package/lib/multi-input/index.js +17 -18
  90. package/lib/notification/themes/halo/dark/index.js +1 -1
  91. package/lib/notification/themes/halo/light/index.js +1 -1
  92. package/lib/notification/themes/solar/charcoal/index.js +1 -1
  93. package/lib/notification/themes/solar/pearl/index.js +1 -1
  94. package/lib/number-field/themes/halo/dark/index.js +1 -1
  95. package/lib/number-field/themes/halo/light/index.js +1 -1
  96. package/lib/number-field/themes/solar/charcoal/index.js +1 -1
  97. package/lib/number-field/themes/solar/pearl/index.js +1 -1
  98. package/lib/overlay/index.d.ts +2 -1
  99. package/lib/overlay-menu/helpers/constants.d.ts +6 -0
  100. package/lib/overlay-menu/helpers/constants.js +7 -0
  101. package/lib/overlay-menu/helpers/types.d.ts +0 -6
  102. package/lib/overlay-menu/helpers/types.js +1 -7
  103. package/lib/overlay-menu/index.d.ts +1 -1
  104. package/lib/overlay-menu/index.js +1 -1
  105. package/lib/password-field/themes/halo/dark/index.js +1 -1
  106. package/lib/password-field/themes/halo/light/index.js +1 -1
  107. package/lib/password-field/themes/solar/charcoal/index.js +1 -1
  108. package/lib/password-field/themes/solar/pearl/index.js +1 -1
  109. package/lib/pill/index.d.ts +11 -3
  110. package/lib/pill/index.js +25 -11
  111. package/lib/radio-button/index.d.ts +7 -11
  112. package/lib/radio-button/index.js +14 -25
  113. package/lib/radio-button/themes/halo/dark/index.js +1 -1
  114. package/lib/radio-button/themes/halo/light/index.js +1 -1
  115. package/lib/radio-button/themes/solar/charcoal/index.js +1 -1
  116. package/lib/radio-button/themes/solar/pearl/index.js +1 -1
  117. package/lib/rating/custom-elements.json +4 -4
  118. package/lib/rating/custom-elements.md +2 -2
  119. package/lib/rating/index.d.ts +84 -32
  120. package/lib/rating/index.js +209 -80
  121. package/lib/rating/themes/halo/dark/index.js +1 -1
  122. package/lib/rating/themes/halo/light/index.js +1 -1
  123. package/lib/rating/themes/solar/charcoal/index.js +1 -1
  124. package/lib/rating/themes/solar/pearl/index.js +1 -1
  125. package/lib/rating/utils.d.ts +9 -0
  126. package/lib/rating/utils.js +11 -0
  127. package/lib/search-field/themes/halo/dark/index.js +1 -1
  128. package/lib/search-field/themes/halo/light/index.js +1 -1
  129. package/lib/search-field/themes/solar/charcoal/index.js +1 -1
  130. package/lib/search-field/themes/solar/pearl/index.js +1 -1
  131. package/lib/select/index.d.ts +13 -1
  132. package/lib/select/index.js +25 -7
  133. package/lib/select/themes/halo/dark/index.js +1 -1
  134. package/lib/select/themes/halo/light/index.js +1 -1
  135. package/lib/select/themes/solar/charcoal/index.js +1 -1
  136. package/lib/select/themes/solar/pearl/index.js +1 -1
  137. package/lib/slider/constants.d.ts +5 -1
  138. package/lib/slider/constants.js +6 -1
  139. package/lib/slider/index.d.ts +112 -49
  140. package/lib/slider/index.js +331 -182
  141. package/lib/slider/themes/halo/dark/index.js +1 -1
  142. package/lib/slider/themes/halo/light/index.js +1 -1
  143. package/lib/slider/themes/solar/charcoal/index.js +1 -1
  144. package/lib/slider/themes/solar/pearl/index.js +1 -1
  145. package/lib/slider/utils.d.ts +1 -9
  146. package/lib/slider/utils.js +1 -18
  147. package/lib/sparkline/themes/halo/dark/index.js +1 -1
  148. package/lib/sparkline/themes/halo/light/index.js +1 -1
  149. package/lib/tab/themes/halo/dark/index.js +1 -1
  150. package/lib/tab/themes/halo/light/index.js +1 -1
  151. package/lib/tab/themes/solar/charcoal/index.js +1 -1
  152. package/lib/tab/themes/solar/pearl/index.js +1 -1
  153. package/lib/tab-bar/index.d.ts +6 -7
  154. package/lib/tab-bar/index.js +12 -10
  155. package/lib/tab-bar/themes/halo/dark/index.js +1 -0
  156. package/lib/tab-bar/themes/halo/light/index.js +1 -0
  157. package/lib/tab-bar/themes/solar/charcoal/index.js +1 -0
  158. package/lib/tab-bar/themes/solar/pearl/index.js +1 -0
  159. package/lib/text-field/index.js +2 -3
  160. package/lib/text-field/themes/halo/dark/index.js +1 -1
  161. package/lib/text-field/themes/halo/light/index.js +1 -1
  162. package/lib/text-field/themes/solar/charcoal/index.js +1 -1
  163. package/lib/text-field/themes/solar/pearl/index.js +1 -1
  164. package/lib/toggle/index.d.ts +7 -10
  165. package/lib/toggle/index.js +14 -24
  166. package/lib/toggle/themes/halo/dark/index.js +1 -1
  167. package/lib/toggle/themes/halo/light/index.js +1 -1
  168. package/lib/toggle/themes/solar/charcoal/index.js +1 -1
  169. package/lib/toggle/themes/solar/pearl/index.js +1 -1
  170. package/lib/tooltip/helpers/overflow-tooltip.d.ts +11 -4
  171. package/lib/tooltip/helpers/overflow-tooltip.js +34 -6
  172. package/lib/tooltip/index.d.ts +2 -2
  173. package/lib/tooltip/index.js +2 -2
  174. package/lib/tree/elements/tree-item.d.ts +4 -0
  175. package/lib/tree/elements/tree-item.js +5 -2
  176. package/lib/tree/elements/tree.d.ts +7 -0
  177. package/lib/tree/elements/tree.js +12 -1
  178. package/lib/tree/helpers/renderer.d.ts +0 -1
  179. package/lib/tree/helpers/renderer.js +0 -2
  180. package/lib/tree/index.d.ts +2 -1
  181. package/lib/tree/themes/halo/dark/index.js +2 -2
  182. package/lib/tree/themes/halo/light/index.js +3 -3
  183. package/lib/tree/themes/solar/charcoal/index.js +2 -2
  184. package/lib/tree/themes/solar/pearl/index.js +2 -2
  185. package/lib/tree-select/index.js +15 -5
  186. package/lib/tree-select/themes/halo/dark/index.js +1 -1
  187. package/lib/tree-select/themes/halo/light/index.js +1 -1
  188. package/lib/tree-select/themes/solar/charcoal/index.js +1 -1
  189. package/lib/tree-select/themes/solar/pearl/index.js +1 -1
  190. package/lib/version.js +1 -1
  191. package/package.json +20 -19
  192. package/lib/clock/utils/timestamps.d.ts +0 -6
  193. package/lib/clock/utils/timestamps.js +0 -6
@@ -4,14 +4,21 @@ import { css, html } from '@refinitiv-ui/core';
4
4
  import { customElement } from '@refinitiv-ui/core/decorators/custom-element.js';
5
5
  import { query } from '@refinitiv-ui/core/decorators/query.js';
6
6
  import { property } from '@refinitiv-ui/core/decorators/property.js';
7
+ import { ref, createRef } from '@refinitiv-ui/core/directives/ref.js';
8
+ import { unsafeHTML } from '@refinitiv-ui/core/directives/unsafe-html.js';
7
9
  import { VERSION } from '../version.js';
8
10
  import { AnimationTaskRunner, TimeoutTaskRunner } from '@refinitiv-ui/utils/async.js';
9
- import { escapeRegExp, itemHighlightable, itemRenderer, queryWordSelect } from './helpers/utils.js';
10
11
  import { isIE, isMobile } from '@refinitiv-ui/utils/browser.js';
12
+ import { translate, TranslatePropertyKey } from '@refinitiv-ui/translate';
13
+ import { escapeRegExp, itemHighlightable, queryWordSelect } from './helpers/utils.js';
14
+ import { renderer } from './helpers/renderer.js';
11
15
  import { Overlay } from '../overlay/index.js';
12
16
  import '../loader/index.js';
13
17
  import '../item/index.js';
14
- export { queryWordSelect, itemRenderer, escapeRegExp, itemHighlightable, updateElementContent } from './helpers/utils.js';
18
+ import '@refinitiv-ui/phrasebook/locale/en/autosuggest.js';
19
+ export { updateElementContent } from './helpers/utils.js';
20
+ export { itemHighlightable, escapeRegExp, queryWordSelect, renderer, renderer as itemRenderer // compatibility
21
+ };
15
22
  /**
16
23
  * Shows suggestions based on users' query.
17
24
  * It can be used by attaching to text form control
@@ -40,9 +47,9 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
40
47
  */
41
48
  constructor() {
42
49
  super();
50
+ this.defaultRole = 'listbox';
43
51
  /**
44
52
  * An HTML Element or CSS selector
45
- * @type {AutosuggestTargetElement | string | null}
46
53
  */
47
54
  this.attach = null;
48
55
  /**
@@ -57,14 +64,13 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
57
64
  * Custom text for More Search
58
65
  * @default More results for {0}
59
66
  */
60
- this.moreSearchText = Autosuggest_1.defaultMoreSearchText;
67
+ this.moreSearchText = '';
61
68
  /**
62
69
  * If set to true show loading mask
63
70
  */
64
71
  this.loading = false;
65
72
  /**
66
73
  * An object that represents a query from attach target
67
- * @type {AutosuggestQuery | null}
68
74
  */
69
75
  this.query = null;
70
76
  /**
@@ -76,19 +82,16 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
76
82
  /**
77
83
  * A renderer applied to suggestion.
78
84
  * By default a render maps data to item attributes
79
- * @type {AutosuggestRenderer}
80
85
  */
81
- this.renderer = itemRenderer;
86
+ this.renderer = renderer;
82
87
  /**
83
88
  * A function that is applied to every suggestion during the render process
84
89
  * to say whether the item can be highlighted and selected. Only items that return true are considered.
85
90
  * By default the function checks for `item` `highlightable` property.
86
- * @type {AutosuggestHighlightable}
87
91
  */
88
92
  this.highlightable = itemHighlightable;
89
93
  /**
90
94
  * A list of suggestion items
91
- * @type {AutosuggestItem[]}
92
95
  */
93
96
  this.suggestions = [];
94
97
  /**
@@ -97,6 +100,10 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
97
100
  * may have performance benefits in frameworks that use virtual DOM (such as `Vue`, `React`, `hyperHTML` and others)
98
101
  */
99
102
  this.htmlRenderer = false;
103
+ this.contentSlotRef = createRef();
104
+ this.contentElementRef = createRef();
105
+ this.headerElementRef = createRef();
106
+ this.footerElementRef = createRef();
100
107
  // used to map render elements with data
101
108
  this.suggestionMap = new Map();
102
109
  this.highlightedItem = null;
@@ -109,86 +116,9 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
109
116
  this.attachChangeRunner = new AnimationTaskRunner();
110
117
  this.moreResultsRunner = new AnimationTaskRunner();
111
118
  this.loadingRunner = new AnimationTaskRunner();
112
- /**
113
- * Run when document click event happens.
114
- * @param event object
115
- * @returns {void}
116
- */
117
- this.onOutsideClick = (event) => {
118
- const path = event.composedPath();
119
- // outside click
120
- if (!path.includes(this) && this.attachTarget && !path.includes(this.attachTarget)) {
121
- this.setOpened(false);
122
- }
123
- };
124
- /**
125
- * fire event and reinit listeners if attach was changed
126
- * @returns {void}
127
- */
128
- this.attachChangeFrameCallback = () => {
129
- this.dispatchAttachEventsRemoveAction();
130
- const attachTarget = (typeof this.attach === 'string' ? document.querySelector(this.attach) : this.attach);
131
- if (attachTarget && attachTarget.nodeType === document.ELEMENT_NODE) {
132
- this.attachTarget = attachTarget;
133
- if (!this.positionTarget) {
134
- this.positionTarget = attachTarget; // in most cases attachTarget and positionTarget must be the same
135
- }
136
- /**
137
- * @event add-attach-target-events
138
- * Fired when attach has been set.
139
- * Add attach target listeners.
140
- */
141
- this.dispatchEventDefault(new CustomEvent('add-attach-target-events', {
142
- cancelable: true
143
- }), this.attachEventsAddAction);
144
- }
145
- };
146
- /**
147
- * set opened state due to status of focus and content
148
- * @returns {void}
149
- */
150
- this.moreResultsFrameCallback = () => {
151
- this.setOpened(this.attachTargetFocused && this.hasContent);
152
- };
153
- /**
154
- * initialize opened state depends on focus and content
155
- * @returns {void}
156
- */
157
- this.loadingFrameCallback = () => {
158
- if (this.loading && !this.opened && this.attachTargetFocused) {
159
- this.setOpened(true);
160
- }
161
- else if (!this.loading && this.opened && !this.hasContent) {
162
- this.setOpened(false);
163
- }
164
- };
165
- this.removeChildNode = (el) => {
166
- el.parentNode && el.parentNode.removeChild(el);
167
- };
168
- this.generateSuggestionsFragment = (fragment, suggestion) => {
169
- const el = this.renderer(suggestion, this.preservedQueryValue);
170
- fragment.appendChild(el);
171
- return fragment;
172
- };
173
- /**
174
- * Fired when mouse down event happens. Select the item
175
- * @param event Mouse down event
176
- * @returns {void}
177
- */
178
- this.onItemMousedown = (event) => {
179
- // do not loose focus from input when click happens on the popup
180
- // note, in IE when scrolling the focus is lost regardless, so
181
- // do hacking here and with on blur
182
- /* istanbul ignore next */
183
- requestAnimationFrame(() => {
184
- // Ignore any focus query events!
185
- this.focusSuspended = true;
186
- this.attachTarget && this.attachTarget.focus();
187
- this.focusSuspended = false;
188
- });
189
- event.stopPropagation();
190
- event.preventDefault();
191
- };
119
+ // Used to escape unsafe string character
120
+ // TODO: think of a nicer way to do this
121
+ this.xmlSerializer = null;
192
122
  /**
193
123
  * @ignore
194
124
  */
@@ -213,6 +143,10 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
213
143
  * @ignore
214
144
  */
215
145
  this.withShadow = false;
146
+ /**
147
+ * @ignore
148
+ */
149
+ this.noFocusManagement = true;
216
150
  /**
217
151
  * @ignore
218
152
  */
@@ -244,10 +178,6 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
244
178
  /**
245
179
  * @ignore
246
180
  */
247
- this.highlightText = this.highlightText.bind(this);
248
- /**
249
- * @ignore
250
- */
251
181
  this.suggestionsFetchRequestedAction = this.suggestionsFetchRequestedAction.bind(this);
252
182
  /**
253
183
  * @ignore
@@ -261,6 +191,14 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
261
191
  * @ignore
262
192
  */
263
193
  this.attachEventsRemoveAction = this.attachEventsRemoveAction.bind(this);
194
+ /**
195
+ * @ignore
196
+ */
197
+ this.onItemMousedown = this.onItemMousedown.bind(this);
198
+ /**
199
+ * @ignore
200
+ */
201
+ this.onOutsideClick = this.onOutsideClick.bind(this);
264
202
  }
265
203
  /**
266
204
  * Element version number
@@ -313,7 +251,7 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
313
251
  * @returns item
314
252
  */
315
253
  static ItemRenderer(suggestion, query) {
316
- return itemRenderer(suggestion, query);
254
+ return renderer(suggestion, query);
317
255
  }
318
256
  /**
319
257
  * Replace forbidden characters in regular expressions
@@ -383,21 +321,29 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
383
321
  * @returns {void}
384
322
  */
385
323
  onInputKeyDown(event) {
386
- if (event.key === 'Up' || event.key === 'ArrowUp') {
387
- this.onUpKey();
388
- }
389
- else if (event.key === 'Down' || event.key === 'ArrowDown') {
390
- this.onDownKey();
391
- }
392
- else if (event.key === 'Esc' || event.key === 'Escape') {
393
- this.onEscKey();
394
- }
395
- else if (event.key === 'Enter' || event.key === 'Return') {
396
- this.onEnterKey(event);
397
- }
398
- else {
324
+ if (event.defaultPrevented) {
399
325
  return;
400
326
  }
327
+ switch (event.key) {
328
+ case 'ArrowUp':
329
+ case 'Up':
330
+ this.onUpKey();
331
+ break;
332
+ case 'ArrowDown':
333
+ case 'Down':
334
+ this.onDownKey();
335
+ break;
336
+ case 'Escape':
337
+ case 'Esc':
338
+ this.onEscKey();
339
+ break;
340
+ case 'Return':
341
+ case 'Enter':
342
+ this.onEnterKey(event);
343
+ break;
344
+ default:
345
+ return;
346
+ }
401
347
  event.preventDefault();
402
348
  }
403
349
  /**
@@ -410,51 +356,6 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
410
356
  super.resizedCallback(size);
411
357
  this.calculateContentMaxHeight(size);
412
358
  }
413
- /**
414
- * @returns template of loader if currently query loading
415
- */
416
- get loaderTemplate() {
417
- if (!this.loading) {
418
- return null;
419
- }
420
- return html `
421
- <div part="loader">
422
- <div part="backdrop"></div>
423
- <ef-loader size="medium"></ef-loader>
424
- </div>
425
- `;
426
- }
427
- /**
428
- * @returns template of moreResults
429
- */
430
- get moreResultsTemplate() {
431
- if (!this.moreResults) {
432
- return null;
433
- }
434
- return html `
435
- <ef-item id="moreResults" part="more-results">${this.highlightText(this.moreResults, this.moreSearchText, this.query)}</ef-item>
436
- `;
437
- }
438
- /**
439
- * A `TemplateResult` that will be used
440
- * to render the updated internal template.
441
- * @return Render template
442
- */
443
- render() {
444
- return html `
445
- <div part="header">
446
- <slot id="headerSlot" name="header"></slot>
447
- </div>
448
- <div id="content" part="content" @mousemove="${this.onItemMouseMove}" @mouseleave="${this.onItemMouseLeave}" @tap="${this.onItemMouseClick}">
449
- <slot id="contentSlot" @slotchange="${this.onSlotChange}"></slot>
450
- ${this.moreResultsTemplate}
451
- </div>
452
- <div part="footer">
453
- <slot id="footerSlot" name="footer"></slot>
454
- </div>
455
- ${this.loaderTemplate}
456
- `;
457
- }
458
359
  /**
459
360
  * Called once after the component is first rendered
460
361
  * @param changedProperties map of changed properties with old values
@@ -496,7 +397,8 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
496
397
  */
497
398
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
498
399
  onSlotChange(event) {
499
- const nodes = (this.contentSlot && this.contentSlot.assignedNodes()) || [];
400
+ const contentSlot = this.contentSlotRef.value;
401
+ const nodes = (contentSlot && contentSlot.assignedNodes()) || [];
500
402
  this.setOpened(this.attachTargetFocused && this.hasContent);
501
403
  // make a brave assumption that suggestions are populated as well
502
404
  const suggestions = this.suggestions;
@@ -544,9 +446,12 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
544
446
  const oldTarget = event.detail.oldTarget;
545
447
  if (target) {
546
448
  target.highlighted = true;
449
+ // Required for aria-activedescendant to work correctly
450
+ target.setAttribute('aria-selected', 'true');
547
451
  }
548
452
  if (oldTarget) {
549
453
  oldTarget.highlighted = false;
454
+ oldTarget.setAttribute('aria-selected', 'false');
550
455
  }
551
456
  }
552
457
  /**
@@ -643,31 +548,23 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
643
548
  }
644
549
  /**
645
550
  * Calculate more search text inner html
646
- * @param moreResults True if has more results
647
- * @param moreSearchText More search text template
648
- * @param query A query
649
551
  * @returns innerHTML
650
552
  */
651
- highlightText(moreResults, moreSearchText, query) {
652
- if (!moreResults) {
553
+ get moreResultsTextTemplate() {
554
+ if (!this.moreResults) {
653
555
  return null;
654
556
  }
655
- query = query ? query.toString() : query;
656
- const htmlString = [];
657
- const pattern = /({0\})/g;
658
- let previousIndex = 0;
659
- let matches;
660
- while ((matches = pattern.exec(moreSearchText)) !== null) {
661
- const match = matches[0];
662
- const text = moreSearchText.substring(previousIndex, pattern.lastIndex - match.length);
663
- htmlString.push(html `${text}<mark>${query}</mark>`);
664
- previousIndex = pattern.lastIndex;
557
+ if (!this.xmlSerializer) {
558
+ this.xmlSerializer = new XMLSerializer();
665
559
  }
666
- htmlString.push(html `${moreSearchText.substring(previousIndex)}`);
560
+ const query = this.xmlSerializer.serializeToString(document.createTextNode(this.query ? this.query.toString() : ''));
667
561
  return html `
668
- <span part="more-results-text">
669
- ${htmlString}
670
- </span>
562
+ <span part="more-results-text">${this.moreSearchText
563
+ ? unsafeHTML(this.moreSearchText.replace(/{0\}/g, `<mark>${query}</mark>`))
564
+ : this.t('MORE_RESULTS', {
565
+ query,
566
+ mark: (chunks) => `<mark>${chunks}</mark>`
567
+ })}</span>
671
568
  <span part="more-results-keys" slot="right"><kbd>SHIFT</kbd> + <kbd>ENTER</kbd></span>
672
569
  `;
673
570
  }
@@ -876,7 +773,10 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
876
773
  * @returns {void}
877
774
  */
878
775
  onItemMouseClick(event) {
879
- this.selectItem(this.getTarget(event), 'click');
776
+ const target = this.getTarget(event);
777
+ if (target) {
778
+ this.selectItem(target, 'click');
779
+ }
880
780
  }
881
781
  /**
882
782
  * check some of native properties was modified
@@ -884,17 +784,41 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
884
784
  * @returns true if some of changedProperties modified
885
785
  */
886
786
  shouldAutosuggestUpdate(changedProperties) {
887
- return changedProperties.has('attach') || changedProperties.has('suggestions') || changedProperties.has('moreResults') || changedProperties.has('loading') || changedProperties.has('debounceRate');
787
+ return changedProperties.has('attach')
788
+ || changedProperties.has('suggestions')
789
+ || changedProperties.has('moreResults')
790
+ || changedProperties.has('moreSearchText')
791
+ || changedProperties.has('loading')
792
+ || changedProperties.has('debounceRate')
793
+ || changedProperties.has(TranslatePropertyKey);
794
+ }
795
+ /**
796
+ * Run when document click event happens.
797
+ * @param event object
798
+ * @returns {void}
799
+ */
800
+ onOutsideClick(event) {
801
+ const path = event.composedPath();
802
+ // outside click
803
+ if (!path.includes(this) && this.attachTarget && !path.includes(this.attachTarget)) {
804
+ this.setOpened(false);
805
+ }
888
806
  }
889
807
  changedCallbacks(changedProperties) {
890
808
  if (changedProperties.has('attach')) {
891
- this.attachChangeRunner.schedule(this.attachChangeFrameCallback);
809
+ this.attachChangeRunner.schedule(() => {
810
+ this.attachChangeFrameCallback();
811
+ });
892
812
  }
893
813
  if (changedProperties.has('moreResults')) {
894
- this.moreResultsRunner.schedule(this.moreResultsFrameCallback);
814
+ this.moreResultsRunner.schedule(() => {
815
+ this.moreResultsFrameCallback();
816
+ });
895
817
  }
896
818
  if (changedProperties.has('loading')) {
897
- this.loadingRunner.schedule(this.loadingFrameCallback);
819
+ this.loadingRunner.schedule(() => {
820
+ this.loadingFrameCallback();
821
+ });
898
822
  }
899
823
  if (changedProperties.has('opened')) {
900
824
  this.handleAfterOpened();
@@ -918,6 +842,29 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
918
842
  this.jobRunner.fulfil();
919
843
  this.jobRunner = new TimeoutTaskRunner(this.debounceRate);
920
844
  }
845
+ /**
846
+ * fire event and re-init listeners if attach was changed
847
+ * @returns {void}
848
+ */
849
+ attachChangeFrameCallback() {
850
+ this.dispatchAttachEventsRemoveAction();
851
+ const attachTarget = (typeof this.attach === 'string' ? document.querySelector(this.attach) : this.attach);
852
+ if (attachTarget && attachTarget.nodeType === document.ELEMENT_NODE) {
853
+ this.attachTarget = attachTarget;
854
+ this.focusBoundary = attachTarget;
855
+ if (!this.positionTarget) {
856
+ this.positionTarget = attachTarget; // in most cases attachTarget and positionTarget must be the same
857
+ }
858
+ /**
859
+ * @event add-attach-target-events
860
+ * Fired when attach has been set.
861
+ * Add attach target listeners.
862
+ */
863
+ this.dispatchEventDefault(new CustomEvent('add-attach-target-events', {
864
+ cancelable: true
865
+ }), this.attachEventsAddAction);
866
+ }
867
+ }
921
868
  /**
922
869
  * Dispatch attach events remove action event
923
870
  * @returns {void}
@@ -933,16 +880,27 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
933
880
  cancelable: true
934
881
  }), this.attachEventsRemoveAction);
935
882
  this.attachTarget = null;
883
+ this.focusBoundary = null;
936
884
  }
937
885
  }
886
+ /**
887
+ * set opened state due to status of focus and content
888
+ * @returns {void}
889
+ */
890
+ moreResultsFrameCallback() {
891
+ this.setOpened(this.attachTargetFocused && this.hasContent);
892
+ }
938
893
  /**
939
894
  * Run when suggestions get changed
940
895
  * NB: this function is only run when htmlRenderer is set to false
941
896
  * @returns {void}
942
897
  */
943
898
  suggestionsChange() {
944
- this.contentSlot && this.contentSlot.assignedNodes().forEach(this.removeChildNode);
945
- this.appendChild(this.suggestions.reduce(this.generateSuggestionsFragment, document.createDocumentFragment()));
899
+ const contentSlot = this.contentSlotRef.value;
900
+ contentSlot && contentSlot.assignedNodes().forEach((node) => {
901
+ node.parentNode && node.parentNode.removeChild(node);
902
+ });
903
+ this.appendChild(this.suggestions.reduce((fragment, suggestion) => this.generateSuggestionsFragment(fragment, suggestion), document.createDocumentFragment()));
946
904
  }
947
905
  /**
948
906
  * Dispatch item select event
@@ -956,7 +914,7 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
956
914
  /**
957
915
  * @event item-select
958
916
  * Fired when an item gets selected
959
- * @param {AutosuggestMethodType} method Select method
917
+ * @param method Select method
960
918
  * @param {HTMLElement} target Selection target
961
919
  * @param {*} [suggestion] Selected suggestion or null
962
920
  * @param {*} [query] Saved query object or null
@@ -1067,7 +1025,8 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
1067
1025
  return true;
1068
1026
  }
1069
1027
  // Space characters (e.g. space, tab, EOL) don't count as having content
1070
- const nodes = this.contentSlot && this.contentSlot.assignedNodes() || [];
1028
+ const contentSlot = this.contentSlotRef.value;
1029
+ const nodes = contentSlot && contentSlot.assignedNodes() || [];
1071
1030
  return nodes.some(({ nodeType, textContent }) => nodeType === Node.ELEMENT_NODE || (textContent && textContent.search(/\S/) >= 0)); // If node is element always return true
1072
1031
  }
1073
1032
  /**
@@ -1143,6 +1102,18 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
1143
1102
  });
1144
1103
  }
1145
1104
  }
1105
+ /**
1106
+ * initialize opened state depends on focus and content
1107
+ * @returns {void}
1108
+ */
1109
+ loadingFrameCallback() {
1110
+ if (this.loading && !this.opened && this.attachTargetFocused) {
1111
+ this.setOpened(true);
1112
+ }
1113
+ else if (!this.loading && this.opened && !this.hasContent) {
1114
+ this.setOpened(false);
1115
+ }
1116
+ }
1146
1117
  /**
1147
1118
  * @returns {void}
1148
1119
  */
@@ -1156,6 +1127,11 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
1156
1127
  this.suggestionsChange();
1157
1128
  }
1158
1129
  }
1130
+ generateSuggestionsFragment(fragment, suggestion) {
1131
+ const el = this.renderer(suggestion, this.preservedQueryValue);
1132
+ fragment.appendChild(el);
1133
+ return fragment;
1134
+ }
1159
1135
  /**
1160
1136
  * Set the width
1161
1137
  * @returns {void}
@@ -1168,6 +1144,80 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
1168
1144
  }
1169
1145
  this.restrictContentMaxHeight();
1170
1146
  }
1147
+ /**
1148
+ * Fired when mouse down event happens. Select the item
1149
+ * @param event Mouse down event
1150
+ * @returns {void}
1151
+ */
1152
+ onItemMousedown(event) {
1153
+ // do not loose focus from input when click happens on the popup
1154
+ // note, in IE when scrolling the focus is lost regardless, so
1155
+ // do hacking here and with on blur
1156
+ /* istanbul ignore next */
1157
+ requestAnimationFrame(() => {
1158
+ // Ignore any focus query events!
1159
+ this.focusSuspended = true;
1160
+ this.attachTarget && this.attachTarget.focus();
1161
+ this.focusSuspended = false;
1162
+ });
1163
+ event.stopPropagation();
1164
+ event.preventDefault();
1165
+ }
1166
+ /**
1167
+ * @returns template of loader if currently query loading
1168
+ */
1169
+ get loaderTemplate() {
1170
+ if (!this.loading) {
1171
+ return null;
1172
+ }
1173
+ return html `
1174
+ <div part="loader">
1175
+ <div part="backdrop"></div>
1176
+ <ef-loader aria-label="${this.t('LOADING')}" aria-live="assertive"></ef-loader>
1177
+ </div>
1178
+ `;
1179
+ }
1180
+ /**
1181
+ * @returns template of moreResults
1182
+ */
1183
+ get moreResultsTemplate() {
1184
+ if (!this.moreResults) {
1185
+ return null;
1186
+ }
1187
+ return html `
1188
+ <ef-item tabIndex="-1"
1189
+ role="option"
1190
+ id="moreResults"
1191
+ part="more-results">${this.moreResultsTextTemplate}</ef-item>
1192
+ `;
1193
+ }
1194
+ /**
1195
+ * A `TemplateResult` that will be used
1196
+ * to render the updated internal template.
1197
+ * @return Render template
1198
+ */
1199
+ render() {
1200
+ return html `
1201
+ <div ${ref(this.headerElementRef)}
1202
+ part="header">
1203
+ <slot id="headerSlot" name="header"></slot>
1204
+ </div>
1205
+ <div ${ref(this.contentElementRef)}
1206
+ part="content"
1207
+ @mousemove="${this.onItemMouseMove}"
1208
+ @mouseleave="${this.onItemMouseLeave}"
1209
+ @tap="${this.onItemMouseClick}">
1210
+ <slot ${ref(this.contentSlotRef)}
1211
+ @slotchange="${this.onSlotChange}"></slot>
1212
+ ${this.moreResultsTemplate}
1213
+ </div>
1214
+ <div ${ref(this.footerElementRef)}
1215
+ part="footer">
1216
+ <slot id="footerSlot" name="footer"></slot>
1217
+ </div>
1218
+ ${this.loaderTemplate}
1219
+ `;
1220
+ }
1171
1221
  /**
1172
1222
  * IE11 only: Restrict maximum height of content element
1173
1223
  * @param [maxHeight] Maximum height of content element
@@ -1175,14 +1225,15 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
1175
1225
  */
1176
1226
  /* istanbul ignore next */
1177
1227
  restrictContentMaxHeight(maxHeight) {
1178
- if (!isIE) {
1228
+ const contentElement = this.contentElementRef.value;
1229
+ if (!isIE || !contentElement) {
1179
1230
  return;
1180
1231
  }
1181
1232
  if (maxHeight) {
1182
- this.contentElement && this.contentElement.style.setProperty('max-height', `${maxHeight}px`);
1233
+ contentElement.style.setProperty('max-height', `${maxHeight}px`);
1183
1234
  }
1184
1235
  else {
1185
- this.contentElement && this.contentElement.style.removeProperty('max-height');
1236
+ contentElement.style.removeProperty('max-height');
1186
1237
  }
1187
1238
  }
1188
1239
  /**
@@ -1195,9 +1246,12 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
1195
1246
  if (!isIE) {
1196
1247
  return;
1197
1248
  }
1198
- const headerRect = this.headerElement?.getBoundingClientRect();
1199
- const footerRect = this.footerElement?.getBoundingClientRect();
1200
- const contentRect = this.contentElement?.getBoundingClientRect();
1249
+ const headerElement = this.headerElementRef.value;
1250
+ const footerElement = this.footerElementRef.value;
1251
+ const contentElement = this.contentElementRef.value;
1252
+ const headerRect = headerElement?.getBoundingClientRect();
1253
+ const footerRect = footerElement?.getBoundingClientRect();
1254
+ const contentRect = contentElement?.getBoundingClientRect();
1201
1255
  const dialogHeight = size.height;
1202
1256
  const headerHeight = headerRect ? headerRect.height : 0;
1203
1257
  const footerHeight = footerRect ? footerRect.height : 0;
@@ -1208,7 +1262,6 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
1208
1262
  }
1209
1263
  };
1210
1264
  Autosuggest.defaultDebounceRate = 100;
1211
- Autosuggest.defaultMoreSearchText = 'More results for {0}';
1212
1265
  __decorate([
1213
1266
  property({ type: String })
1214
1267
  ], Autosuggest.prototype, "attach", void 0);
@@ -1231,10 +1284,10 @@ __decorate([
1231
1284
  property({ type: Number, attribute: 'debounce-rate' })
1232
1285
  ], Autosuggest.prototype, "debounceRate", void 0);
1233
1286
  __decorate([
1234
- property({ type: Function, attribute: false })
1287
+ property({ attribute: false })
1235
1288
  ], Autosuggest.prototype, "renderer", void 0);
1236
1289
  __decorate([
1237
- property({ type: Function, attribute: false })
1290
+ property({ attribute: false })
1238
1291
  ], Autosuggest.prototype, "highlightable", void 0);
1239
1292
  __decorate([
1240
1293
  property({ type: Array, attribute: false })
@@ -1242,21 +1295,12 @@ __decorate([
1242
1295
  __decorate([
1243
1296
  property({ type: Boolean, attribute: 'html-renderer' })
1244
1297
  ], Autosuggest.prototype, "htmlRenderer", void 0);
1298
+ __decorate([
1299
+ translate({ scope: 'ef-autosuggest' })
1300
+ ], Autosuggest.prototype, "t", void 0);
1245
1301
  __decorate([
1246
1302
  query('#moreResults')
1247
1303
  ], Autosuggest.prototype, "moreResultsItem", void 0);
1248
- __decorate([
1249
- query('#contentSlot')
1250
- ], Autosuggest.prototype, "contentSlot", void 0);
1251
- __decorate([
1252
- query('[part="content"]')
1253
- ], Autosuggest.prototype, "contentElement", void 0);
1254
- __decorate([
1255
- query('[part="header"]')
1256
- ], Autosuggest.prototype, "headerElement", void 0);
1257
- __decorate([
1258
- query('[part="footer"]')
1259
- ], Autosuggest.prototype, "footerElement", void 0);
1260
1304
  Autosuggest = Autosuggest_1 = __decorate([
1261
1305
  customElement('ef-autosuggest', {
1262
1306
  alias: 'emerald-autosuggest'