@refinitiv-ui/elements 6.0.0-next.1 → 6.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 (171) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/lib/accordion/index.d.ts +5 -0
  3. package/lib/appstate-bar/index.d.ts +5 -0
  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 +38 -32
  12. package/lib/autosuggest/index.js +246 -191
  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/button/index.d.ts +5 -0
  16. package/lib/button/index.js +1 -1
  17. package/lib/button/themes/halo/dark/index.js +1 -1
  18. package/lib/button/themes/halo/light/index.js +1 -1
  19. package/lib/button-bar/index.d.ts +5 -0
  20. package/lib/calendar/index.d.ts +5 -0
  21. package/lib/calendar/themes/halo/dark/index.js +1 -1
  22. package/lib/calendar/themes/halo/light/index.js +1 -1
  23. package/lib/canvas/index.d.ts +5 -0
  24. package/lib/card/index.d.ts +21 -0
  25. package/lib/card/index.js +31 -8
  26. package/lib/card/themes/halo/dark/index.js +1 -1
  27. package/lib/card/themes/halo/light/index.js +1 -1
  28. package/lib/chart/index.d.ts +5 -0
  29. package/lib/checkbox/index.d.ts +5 -0
  30. package/lib/clock/custom-elements.json +10 -10
  31. package/lib/clock/custom-elements.md +1 -1
  32. package/lib/clock/index.d.ts +49 -16
  33. package/lib/clock/index.js +178 -61
  34. package/lib/clock/themes/halo/dark/index.js +1 -1
  35. package/lib/clock/themes/halo/light/index.js +1 -1
  36. package/lib/clock/themes/solar/charcoal/index.js +1 -1
  37. package/lib/clock/themes/solar/pearl/index.js +1 -1
  38. package/lib/collapse/index.d.ts +5 -0
  39. package/lib/collapse/themes/halo/dark/index.js +1 -1
  40. package/lib/collapse/themes/halo/light/index.js +1 -1
  41. package/lib/color-dialog/elements/color-palettes.d.ts +5 -0
  42. package/lib/color-dialog/elements/grayscale-palettes.d.ts +5 -0
  43. package/lib/color-dialog/index.d.ts +5 -0
  44. package/lib/color-dialog/index.js +11 -6
  45. package/lib/combo-box/custom-elements.json +0 -22
  46. package/lib/combo-box/custom-elements.md +0 -7
  47. package/lib/combo-box/index.d.ts +5 -0
  48. package/lib/combo-box/themes/halo/dark/index.js +1 -1
  49. package/lib/combo-box/themes/halo/light/index.js +1 -1
  50. package/lib/counter/index.d.ts +5 -0
  51. package/lib/counter/themes/halo/dark/index.js +1 -1
  52. package/lib/counter/themes/halo/light/index.js +1 -1
  53. package/lib/datetime-field/custom-elements.json +0 -75
  54. package/lib/datetime-field/custom-elements.md +27 -36
  55. package/lib/datetime-field/index.d.ts +5 -0
  56. package/lib/datetime-picker/index.d.ts +5 -0
  57. package/lib/dialog/index.d.ts +5 -0
  58. package/lib/dialog/themes/halo/dark/index.js +1 -1
  59. package/lib/dialog/themes/halo/light/index.js +1 -1
  60. package/lib/email-field/index.d.ts +5 -0
  61. package/lib/flag/index.d.ts +5 -0
  62. package/lib/flag/utils/FlagLoader.d.ts +2 -32
  63. package/lib/flag/utils/FlagLoader.js +2 -69
  64. package/lib/header/index.d.ts +5 -0
  65. package/lib/heatmap/index.d.ts +5 -0
  66. package/lib/icon/index.d.ts +5 -0
  67. package/lib/icon/utils/IconLoader.d.ts +2 -37
  68. package/lib/icon/utils/IconLoader.js +2 -76
  69. package/lib/interactive-chart/index.d.ts +5 -0
  70. package/lib/interactive-chart/themes/halo/dark/index.js +1 -1
  71. package/lib/interactive-chart/themes/halo/light/index.js +1 -1
  72. package/lib/item/index.d.ts +5 -0
  73. package/lib/item/themes/halo/dark/index.js +1 -1
  74. package/lib/item/themes/halo/light/index.js +1 -1
  75. package/lib/label/index.d.ts +5 -0
  76. package/lib/layout/index.d.ts +5 -0
  77. package/lib/led-gauge/index.d.ts +5 -0
  78. package/lib/list/index.d.ts +5 -0
  79. package/lib/list/themes/halo/dark/index.js +1 -1
  80. package/lib/list/themes/halo/light/index.js +1 -1
  81. package/lib/loader/index.d.ts +6 -0
  82. package/lib/loader/index.js +4 -0
  83. package/lib/multi-input/index.d.ts +5 -0
  84. package/lib/multi-input/themes/halo/dark/index.js +1 -1
  85. package/lib/multi-input/themes/halo/light/index.js +1 -1
  86. package/lib/notification/elements/notification-tray.d.ts +5 -0
  87. package/lib/notification/elements/notification.d.ts +5 -0
  88. package/lib/number-field/custom-elements.json +0 -48
  89. package/lib/number-field/custom-elements.md +20 -26
  90. package/lib/number-field/index.d.ts +5 -0
  91. package/lib/number-field/themes/halo/dark/index.js +1 -1
  92. package/lib/number-field/themes/halo/light/index.js +1 -1
  93. package/lib/overlay/elements/overlay-backdrop.d.ts +5 -0
  94. package/lib/overlay/elements/overlay-viewport.d.ts +5 -0
  95. package/lib/overlay/elements/overlay.d.ts +5 -0
  96. package/lib/overlay/managers/focus-manager.js +9 -3
  97. package/lib/overlay/themes/halo/dark/index.js +1 -1
  98. package/lib/overlay/themes/halo/light/index.js +1 -1
  99. package/lib/overlay-menu/index.d.ts +5 -0
  100. package/lib/overlay-menu/themes/halo/dark/index.js +1 -1
  101. package/lib/overlay-menu/themes/halo/light/index.js +1 -1
  102. package/lib/pagination/index.d.ts +5 -0
  103. package/lib/panel/index.d.ts +5 -0
  104. package/lib/password-field/custom-elements.json +0 -7
  105. package/lib/password-field/custom-elements.md +0 -6
  106. package/lib/password-field/index.d.ts +5 -0
  107. package/lib/pill/index.d.ts +5 -0
  108. package/lib/pill/themes/halo/dark/index.js +1 -1
  109. package/lib/pill/themes/halo/light/index.js +1 -1
  110. package/lib/progress-bar/index.d.ts +5 -0
  111. package/lib/radio-button/index.d.ts +5 -0
  112. package/lib/rating/custom-elements.json +4 -4
  113. package/lib/rating/custom-elements.md +2 -2
  114. package/lib/rating/index.d.ts +89 -32
  115. package/lib/rating/index.js +209 -80
  116. package/lib/rating/themes/halo/dark/index.js +1 -1
  117. package/lib/rating/themes/halo/light/index.js +1 -1
  118. package/lib/rating/themes/solar/charcoal/index.js +1 -1
  119. package/lib/rating/themes/solar/pearl/index.js +1 -1
  120. package/lib/rating/utils.d.ts +9 -0
  121. package/lib/rating/utils.js +11 -0
  122. package/lib/search-field/custom-elements.json +0 -7
  123. package/lib/search-field/custom-elements.md +0 -6
  124. package/lib/search-field/index.d.ts +5 -0
  125. package/lib/select/index.d.ts +5 -0
  126. package/lib/select/themes/halo/dark/index.js +1 -1
  127. package/lib/select/themes/halo/light/index.js +1 -1
  128. package/lib/sidebar-layout/index.d.ts +5 -0
  129. package/lib/sidebar-layout/themes/halo/dark/index.js +1 -1
  130. package/lib/sidebar-layout/themes/halo/light/index.js +1 -1
  131. package/lib/slider/constants.d.ts +5 -1
  132. package/lib/slider/constants.js +6 -1
  133. package/lib/slider/index.d.ts +117 -49
  134. package/lib/slider/index.js +331 -182
  135. package/lib/slider/themes/halo/dark/index.js +1 -1
  136. package/lib/slider/themes/halo/light/index.js +1 -1
  137. package/lib/slider/themes/solar/charcoal/index.js +1 -1
  138. package/lib/slider/themes/solar/pearl/index.js +1 -1
  139. package/lib/slider/utils.d.ts +1 -9
  140. package/lib/slider/utils.js +1 -18
  141. package/lib/sparkline/index.d.ts +5 -0
  142. package/lib/swing-gauge/index.d.ts +5 -0
  143. package/lib/tab/index.d.ts +5 -0
  144. package/lib/tab/themes/halo/dark/index.js +1 -1
  145. package/lib/tab/themes/halo/light/index.js +1 -1
  146. package/lib/tab-bar/index.d.ts +5 -0
  147. package/lib/tab-bar/themes/halo/dark/index.js +1 -1
  148. package/lib/tab-bar/themes/halo/light/index.js +1 -1
  149. package/lib/text-field/custom-elements.json +0 -22
  150. package/lib/text-field/custom-elements.md +0 -7
  151. package/lib/text-field/index.d.ts +5 -0
  152. package/lib/time-picker/index.d.ts +5 -0
  153. package/lib/toggle/index.d.ts +5 -0
  154. package/lib/toggle/themes/halo/dark/index.js +1 -1
  155. package/lib/toggle/themes/halo/light/index.js +1 -1
  156. package/lib/tooltip/elements/tooltip-element.d.ts +1 -2
  157. package/lib/tooltip/index.d.ts +5 -0
  158. package/lib/tornado-chart/elements/tornado-chart.d.ts +5 -0
  159. package/lib/tornado-chart/elements/tornado-item.d.ts +5 -0
  160. package/lib/tree/elements/tree-item.d.ts +5 -0
  161. package/lib/tree/elements/tree.d.ts +5 -0
  162. package/lib/tree/helpers/renderer.js +14 -15
  163. package/lib/tree/themes/halo/dark/index.js +2 -2
  164. package/lib/tree/themes/halo/light/index.js +2 -2
  165. package/lib/tree-select/index.d.ts +5 -0
  166. package/lib/tree-select/themes/halo/dark/index.js +1 -1
  167. package/lib/tree-select/themes/halo/light/index.js +1 -1
  168. package/lib/version.js +1 -1
  169. package/package.json +16 -16
  170. package/lib/clock/utils/timestamps.d.ts +0 -6
  171. package/lib/clock/utils/timestamps.js +0 -6
@@ -4,15 +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';
7
8
  import { unsafeHTML } from '@refinitiv-ui/core/directives/unsafe-html.js';
8
9
  import { VERSION } from '../version.js';
9
10
  import { AnimationTaskRunner, TimeoutTaskRunner } from '@refinitiv-ui/utils/async.js';
10
- import { escapeRegExp, itemHighlightable, itemRenderer, queryWordSelect } from './helpers/utils.js';
11
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';
12
15
  import { Overlay } from '../overlay/index.js';
13
16
  import '../loader/index.js';
14
17
  import '../item/index.js';
15
- 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
+ };
16
22
  /**
17
23
  * Shows suggestions based on users' query.
18
24
  * It can be used by attaching to text form control
@@ -41,9 +47,9 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
41
47
  */
42
48
  constructor() {
43
49
  super();
50
+ this.defaultRole = 'listbox';
44
51
  /**
45
52
  * An HTML Element or CSS selector
46
- * @type {AutosuggestTargetElement | string | null}
47
53
  */
48
54
  this.attach = null;
49
55
  /**
@@ -58,14 +64,13 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
58
64
  * Custom text for More Search
59
65
  * @default More results for {0}
60
66
  */
61
- this.moreSearchText = Autosuggest_1.defaultMoreSearchText;
67
+ this.moreSearchText = '';
62
68
  /**
63
69
  * If set to true show loading mask
64
70
  */
65
71
  this.loading = false;
66
72
  /**
67
73
  * An object that represents a query from attach target
68
- * @type {AutosuggestQuery | null}
69
74
  */
70
75
  this.query = null;
71
76
  /**
@@ -77,19 +82,16 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
77
82
  /**
78
83
  * A renderer applied to suggestion.
79
84
  * By default a render maps data to item attributes
80
- * @type {AutosuggestRenderer}
81
85
  */
82
- this.renderer = itemRenderer;
86
+ this.renderer = renderer;
83
87
  /**
84
88
  * A function that is applied to every suggestion during the render process
85
89
  * to say whether the item can be highlighted and selected. Only items that return true are considered.
86
90
  * By default the function checks for `item` `highlightable` property.
87
- * @type {AutosuggestHighlightable}
88
91
  */
89
92
  this.highlightable = itemHighlightable;
90
93
  /**
91
94
  * A list of suggestion items
92
- * @type {AutosuggestItem[]}
93
95
  */
94
96
  this.suggestions = [];
95
97
  /**
@@ -98,6 +100,10 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
98
100
  * may have performance benefits in frameworks that use virtual DOM (such as `Vue`, `React`, `hyperHTML` and others)
99
101
  */
100
102
  this.htmlRenderer = false;
103
+ this.contentSlotRef = createRef();
104
+ this.contentElementRef = createRef();
105
+ this.headerElementRef = createRef();
106
+ this.footerElementRef = createRef();
101
107
  // used to map render elements with data
102
108
  this.suggestionMap = new Map();
103
109
  this.highlightedItem = null;
@@ -110,86 +116,9 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
110
116
  this.attachChangeRunner = new AnimationTaskRunner();
111
117
  this.moreResultsRunner = new AnimationTaskRunner();
112
118
  this.loadingRunner = new AnimationTaskRunner();
113
- /**
114
- * Run when document click event happens.
115
- * @param event object
116
- * @returns {void}
117
- */
118
- this.onOutsideClick = (event) => {
119
- const path = event.composedPath();
120
- // outside click
121
- if (!path.includes(this) && this.attachTarget && !path.includes(this.attachTarget)) {
122
- this.setOpened(false);
123
- }
124
- };
125
- /**
126
- * fire event and reinit listeners if attach was changed
127
- * @returns {void}
128
- */
129
- this.attachChangeFrameCallback = () => {
130
- this.dispatchAttachEventsRemoveAction();
131
- const attachTarget = (typeof this.attach === 'string' ? document.querySelector(this.attach) : this.attach);
132
- if (attachTarget && attachTarget.nodeType === document.ELEMENT_NODE) {
133
- this.attachTarget = attachTarget;
134
- if (!this.positionTarget) {
135
- this.positionTarget = attachTarget; // in most cases attachTarget and positionTarget must be the same
136
- }
137
- /**
138
- * @event add-attach-target-events
139
- * Fired when attach has been set.
140
- * Add attach target listeners.
141
- */
142
- this.dispatchEventDefault(new CustomEvent('add-attach-target-events', {
143
- cancelable: true
144
- }), this.attachEventsAddAction);
145
- }
146
- };
147
- /**
148
- * set opened state due to status of focus and content
149
- * @returns {void}
150
- */
151
- this.moreResultsFrameCallback = () => {
152
- this.setOpened(this.attachTargetFocused && this.hasContent);
153
- };
154
- /**
155
- * initialize opened state depends on focus and content
156
- * @returns {void}
157
- */
158
- this.loadingFrameCallback = () => {
159
- if (this.loading && !this.opened && this.attachTargetFocused) {
160
- this.setOpened(true);
161
- }
162
- else if (!this.loading && this.opened && !this.hasContent) {
163
- this.setOpened(false);
164
- }
165
- };
166
- this.removeChildNode = (el) => {
167
- el.parentNode && el.parentNode.removeChild(el);
168
- };
169
- this.generateSuggestionsFragment = (fragment, suggestion) => {
170
- const el = this.renderer(suggestion, this.preservedQueryValue);
171
- fragment.appendChild(el);
172
- return fragment;
173
- };
174
- /**
175
- * Fired when mouse down event happens. Select the item
176
- * @param event Mouse down event
177
- * @returns {void}
178
- */
179
- this.onItemMousedown = (event) => {
180
- // do not loose focus from input when click happens on the popup
181
- // note, in IE when scrolling the focus is lost regardless, so
182
- // do hacking here and with on blur
183
- /* istanbul ignore next */
184
- requestAnimationFrame(() => {
185
- // Ignore any focus query events!
186
- this.focusSuspended = true;
187
- this.attachTarget && this.attachTarget.focus();
188
- this.focusSuspended = false;
189
- });
190
- event.stopPropagation();
191
- event.preventDefault();
192
- };
119
+ // Used to escape unsafe string character
120
+ // TODO: think of a nicer way to do this
121
+ this.xmlSerializer = null;
193
122
  /**
194
123
  * @ignore
195
124
  */
@@ -214,6 +143,10 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
214
143
  * @ignore
215
144
  */
216
145
  this.withShadow = false;
146
+ /**
147
+ * @ignore
148
+ */
149
+ this.noFocusManagement = true;
217
150
  /**
218
151
  * @ignore
219
152
  */
@@ -245,10 +178,6 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
245
178
  /**
246
179
  * @ignore
247
180
  */
248
- this.highlightText = this.highlightText.bind(this);
249
- /**
250
- * @ignore
251
- */
252
181
  this.suggestionsFetchRequestedAction = this.suggestionsFetchRequestedAction.bind(this);
253
182
  /**
254
183
  * @ignore
@@ -262,6 +191,14 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
262
191
  * @ignore
263
192
  */
264
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);
265
202
  }
266
203
  /**
267
204
  * Element version number
@@ -314,7 +251,7 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
314
251
  * @returns item
315
252
  */
316
253
  static ItemRenderer(suggestion, query) {
317
- return itemRenderer(suggestion, query);
254
+ return renderer(suggestion, query);
318
255
  }
319
256
  /**
320
257
  * Replace forbidden characters in regular expressions
@@ -384,21 +321,29 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
384
321
  * @returns {void}
385
322
  */
386
323
  onInputKeyDown(event) {
387
- if (event.key === 'Up' || event.key === 'ArrowUp') {
388
- this.onUpKey();
389
- }
390
- else if (event.key === 'Down' || event.key === 'ArrowDown') {
391
- this.onDownKey();
392
- }
393
- else if (event.key === 'Esc' || event.key === 'Escape') {
394
- this.onEscKey();
395
- }
396
- else if (event.key === 'Enter' || event.key === 'Return') {
397
- this.onEnterKey(event);
398
- }
399
- else {
324
+ if (event.defaultPrevented) {
400
325
  return;
401
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
+ }
402
347
  event.preventDefault();
403
348
  }
404
349
  /**
@@ -411,51 +356,6 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
411
356
  super.resizedCallback(size);
412
357
  this.calculateContentMaxHeight(size);
413
358
  }
414
- /**
415
- * @returns template of loader if currently query loading
416
- */
417
- get loaderTemplate() {
418
- if (!this.loading) {
419
- return null;
420
- }
421
- return html `
422
- <div part="loader">
423
- <div part="backdrop"></div>
424
- <ef-loader size="medium"></ef-loader>
425
- </div>
426
- `;
427
- }
428
- /**
429
- * @returns template of moreResults
430
- */
431
- get moreResultsTemplate() {
432
- if (!this.moreResults) {
433
- return null;
434
- }
435
- return html `
436
- <ef-item id="moreResults" part="more-results">${this.highlightText(this.moreResults, this.moreSearchText, this.query)}</ef-item>
437
- `;
438
- }
439
- /**
440
- * A `TemplateResult` that will be used
441
- * to render the updated internal template.
442
- * @return Render template
443
- */
444
- render() {
445
- return html `
446
- <div part="header">
447
- <slot id="headerSlot" name="header"></slot>
448
- </div>
449
- <div id="content" part="content" @mousemove="${this.onItemMouseMove}" @mouseleave="${this.onItemMouseLeave}" @tap="${this.onItemMouseClick}">
450
- <slot id="contentSlot" @slotchange="${this.onSlotChange}"></slot>
451
- ${this.moreResultsTemplate}
452
- </div>
453
- <div part="footer">
454
- <slot id="footerSlot" name="footer"></slot>
455
- </div>
456
- ${this.loaderTemplate}
457
- `;
458
- }
459
359
  /**
460
360
  * Called once after the component is first rendered
461
361
  * @param changedProperties map of changed properties with old values
@@ -497,7 +397,8 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
497
397
  */
498
398
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
499
399
  onSlotChange(event) {
500
- const nodes = (this.contentSlot && this.contentSlot.assignedNodes()) || [];
400
+ const contentSlot = this.contentSlotRef.value;
401
+ const nodes = (contentSlot && contentSlot.assignedNodes()) || [];
501
402
  this.setOpened(this.attachTargetFocused && this.hasContent);
502
403
  // make a brave assumption that suggestions are populated as well
503
404
  const suggestions = this.suggestions;
@@ -545,9 +446,12 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
545
446
  const oldTarget = event.detail.oldTarget;
546
447
  if (target) {
547
448
  target.highlighted = true;
449
+ // Required for aria-activedescendant to work correctly
450
+ target.setAttribute('aria-selected', 'true');
548
451
  }
549
452
  if (oldTarget) {
550
453
  oldTarget.highlighted = false;
454
+ oldTarget.setAttribute('aria-selected', 'false');
551
455
  }
552
456
  }
553
457
  /**
@@ -644,19 +548,23 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
644
548
  }
645
549
  /**
646
550
  * Calculate more search text inner html
647
- * @param moreResults True if has more results
648
- * @param moreSearchText More search text template
649
- * @param query A query
650
551
  * @returns innerHTML
651
552
  */
652
- highlightText(moreResults, moreSearchText, query) {
653
- if (!moreResults) {
553
+ get moreResultsTextTemplate() {
554
+ if (!this.moreResults) {
654
555
  return null;
655
556
  }
557
+ if (!this.xmlSerializer) {
558
+ this.xmlSerializer = new XMLSerializer();
559
+ }
560
+ const query = this.xmlSerializer.serializeToString(document.createTextNode(this.query ? this.query.toString() : ''));
656
561
  return html `
657
- <span part="more-results-text">
658
- ${unsafeHTML(moreSearchText.replace(/{0\}/g, `<mark>${query ? query.toString() : ''}</mark>`))}
659
- </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>
660
568
  <span part="more-results-keys" slot="right"><kbd>SHIFT</kbd> + <kbd>ENTER</kbd></span>
661
569
  `;
662
570
  }
@@ -865,7 +773,10 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
865
773
  * @returns {void}
866
774
  */
867
775
  onItemMouseClick(event) {
868
- this.selectItem(this.getTarget(event), 'click');
776
+ const target = this.getTarget(event);
777
+ if (target) {
778
+ this.selectItem(target, 'click');
779
+ }
869
780
  }
870
781
  /**
871
782
  * check some of native properties was modified
@@ -873,17 +784,41 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
873
784
  * @returns true if some of changedProperties modified
874
785
  */
875
786
  shouldAutosuggestUpdate(changedProperties) {
876
- 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
+ }
877
806
  }
878
807
  changedCallbacks(changedProperties) {
879
808
  if (changedProperties.has('attach')) {
880
- this.attachChangeRunner.schedule(this.attachChangeFrameCallback);
809
+ this.attachChangeRunner.schedule(() => {
810
+ this.attachChangeFrameCallback();
811
+ });
881
812
  }
882
813
  if (changedProperties.has('moreResults')) {
883
- this.moreResultsRunner.schedule(this.moreResultsFrameCallback);
814
+ this.moreResultsRunner.schedule(() => {
815
+ this.moreResultsFrameCallback();
816
+ });
884
817
  }
885
818
  if (changedProperties.has('loading')) {
886
- this.loadingRunner.schedule(this.loadingFrameCallback);
819
+ this.loadingRunner.schedule(() => {
820
+ this.loadingFrameCallback();
821
+ });
887
822
  }
888
823
  if (changedProperties.has('opened')) {
889
824
  this.handleAfterOpened();
@@ -907,6 +842,29 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
907
842
  this.jobRunner.fulfil();
908
843
  this.jobRunner = new TimeoutTaskRunner(this.debounceRate);
909
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
+ }
910
868
  /**
911
869
  * Dispatch attach events remove action event
912
870
  * @returns {void}
@@ -922,16 +880,27 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
922
880
  cancelable: true
923
881
  }), this.attachEventsRemoveAction);
924
882
  this.attachTarget = null;
883
+ this.focusBoundary = null;
925
884
  }
926
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
+ }
927
893
  /**
928
894
  * Run when suggestions get changed
929
895
  * NB: this function is only run when htmlRenderer is set to false
930
896
  * @returns {void}
931
897
  */
932
898
  suggestionsChange() {
933
- this.contentSlot && this.contentSlot.assignedNodes().forEach(this.removeChildNode);
934
- 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()));
935
904
  }
936
905
  /**
937
906
  * Dispatch item select event
@@ -945,7 +914,7 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
945
914
  /**
946
915
  * @event item-select
947
916
  * Fired when an item gets selected
948
- * @param {AutosuggestMethodType} method Select method
917
+ * @param method Select method
949
918
  * @param {HTMLElement} target Selection target
950
919
  * @param {*} [suggestion] Selected suggestion or null
951
920
  * @param {*} [query] Saved query object or null
@@ -1056,7 +1025,8 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
1056
1025
  return true;
1057
1026
  }
1058
1027
  // Space characters (e.g. space, tab, EOL) don't count as having content
1059
- const nodes = this.contentSlot && this.contentSlot.assignedNodes() || [];
1028
+ const contentSlot = this.contentSlotRef.value;
1029
+ const nodes = contentSlot && contentSlot.assignedNodes() || [];
1060
1030
  return nodes.some(({ nodeType, textContent }) => nodeType === Node.ELEMENT_NODE || (textContent && textContent.search(/\S/) >= 0)); // If node is element always return true
1061
1031
  }
1062
1032
  /**
@@ -1132,6 +1102,18 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
1132
1102
  });
1133
1103
  }
1134
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
+ }
1135
1117
  /**
1136
1118
  * @returns {void}
1137
1119
  */
@@ -1145,6 +1127,11 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
1145
1127
  this.suggestionsChange();
1146
1128
  }
1147
1129
  }
1130
+ generateSuggestionsFragment(fragment, suggestion) {
1131
+ const el = this.renderer(suggestion, this.preservedQueryValue);
1132
+ fragment.appendChild(el);
1133
+ return fragment;
1134
+ }
1148
1135
  /**
1149
1136
  * Set the width
1150
1137
  * @returns {void}
@@ -1157,6 +1144,80 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
1157
1144
  }
1158
1145
  this.restrictContentMaxHeight();
1159
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
+ }
1160
1221
  /**
1161
1222
  * IE11 only: Restrict maximum height of content element
1162
1223
  * @param [maxHeight] Maximum height of content element
@@ -1164,14 +1225,15 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
1164
1225
  */
1165
1226
  /* istanbul ignore next */
1166
1227
  restrictContentMaxHeight(maxHeight) {
1167
- if (!isIE) {
1228
+ const contentElement = this.contentElementRef.value;
1229
+ if (!isIE || !contentElement) {
1168
1230
  return;
1169
1231
  }
1170
1232
  if (maxHeight) {
1171
- this.contentElement && this.contentElement.style.setProperty('max-height', `${maxHeight}px`);
1233
+ contentElement.style.setProperty('max-height', `${maxHeight}px`);
1172
1234
  }
1173
1235
  else {
1174
- this.contentElement && this.contentElement.style.removeProperty('max-height');
1236
+ contentElement.style.removeProperty('max-height');
1175
1237
  }
1176
1238
  }
1177
1239
  /**
@@ -1184,9 +1246,12 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
1184
1246
  if (!isIE) {
1185
1247
  return;
1186
1248
  }
1187
- const headerRect = this.headerElement?.getBoundingClientRect();
1188
- const footerRect = this.footerElement?.getBoundingClientRect();
1189
- 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();
1190
1255
  const dialogHeight = size.height;
1191
1256
  const headerHeight = headerRect ? headerRect.height : 0;
1192
1257
  const footerHeight = footerRect ? footerRect.height : 0;
@@ -1197,7 +1262,6 @@ let Autosuggest = Autosuggest_1 = class Autosuggest extends Overlay {
1197
1262
  }
1198
1263
  };
1199
1264
  Autosuggest.defaultDebounceRate = 100;
1200
- Autosuggest.defaultMoreSearchText = 'More results for {0}';
1201
1265
  __decorate([
1202
1266
  property({ type: String })
1203
1267
  ], Autosuggest.prototype, "attach", void 0);
@@ -1220,10 +1284,10 @@ __decorate([
1220
1284
  property({ type: Number, attribute: 'debounce-rate' })
1221
1285
  ], Autosuggest.prototype, "debounceRate", void 0);
1222
1286
  __decorate([
1223
- property({ type: Function, attribute: false })
1287
+ property({ attribute: false })
1224
1288
  ], Autosuggest.prototype, "renderer", void 0);
1225
1289
  __decorate([
1226
- property({ type: Function, attribute: false })
1290
+ property({ attribute: false })
1227
1291
  ], Autosuggest.prototype, "highlightable", void 0);
1228
1292
  __decorate([
1229
1293
  property({ type: Array, attribute: false })
@@ -1231,21 +1295,12 @@ __decorate([
1231
1295
  __decorate([
1232
1296
  property({ type: Boolean, attribute: 'html-renderer' })
1233
1297
  ], Autosuggest.prototype, "htmlRenderer", void 0);
1298
+ __decorate([
1299
+ translate({ scope: 'ef-autosuggest' })
1300
+ ], Autosuggest.prototype, "t", void 0);
1234
1301
  __decorate([
1235
1302
  query('#moreResults')
1236
1303
  ], Autosuggest.prototype, "moreResultsItem", void 0);
1237
- __decorate([
1238
- query('#contentSlot')
1239
- ], Autosuggest.prototype, "contentSlot", void 0);
1240
- __decorate([
1241
- query('[part="content"]')
1242
- ], Autosuggest.prototype, "contentElement", void 0);
1243
- __decorate([
1244
- query('[part="header"]')
1245
- ], Autosuggest.prototype, "headerElement", void 0);
1246
- __decorate([
1247
- query('[part="footer"]')
1248
- ], Autosuggest.prototype, "footerElement", void 0);
1249
1304
  Autosuggest = Autosuggest_1 = __decorate([
1250
1305
  customElement('ef-autosuggest', {
1251
1306
  alias: 'emerald-autosuggest'