@arbetsformedlingen/yrkesvaljaren 2.0.5

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 (146) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +369 -0
  3. package/dist/cjs/af-validation-message-BzY5H0xU.js +16 -0
  4. package/dist/cjs/core-selector.cjs.entry.js +476 -0
  5. package/dist/cjs/digi-service-job-selector.cjs.entry.js +1619 -0
  6. package/dist/cjs/fuse-BTLNKxuL.js +1631 -0
  7. package/dist/cjs/geo-valjaren.cjs.entry.js +14910 -0
  8. package/dist/cjs/index-BOuTGlEp.js +1817 -0
  9. package/dist/cjs/index.cjs.js +14 -0
  10. package/dist/cjs/job-selector-demo.cjs.entry.js +692 -0
  11. package/dist/cjs/loader.cjs.js +12 -0
  12. package/dist/cjs/neobrutal-search.cjs.entry.js +171 -0
  13. package/dist/cjs/search.engine-D0cMelRi.js +489 -0
  14. package/dist/cjs/taxonomy-registry-DVmuDUpM.js +435 -0
  15. package/dist/cjs/types-CtHBl6Ra.js +14 -0
  16. package/dist/cjs/yrkesvaljaren.cjs.js +24 -0
  17. package/dist/collection/collection-manifest.json +15 -0
  18. package/dist/collection/components/core-selector/core-selector.css +803 -0
  19. package/dist/collection/components/core-selector/core-selector.js +761 -0
  20. package/dist/collection/components/core-selector/types.js +1 -0
  21. package/dist/collection/components/design-compat/af-icon.js +13 -0
  22. package/dist/collection/components/design-compat/af-label.js +2 -0
  23. package/dist/collection/components/design-compat/af-tag.js +6 -0
  24. package/dist/collection/components/design-compat/af-validation-message.js +11 -0
  25. package/dist/collection/components/design-compat/index.js +4 -0
  26. package/dist/collection/components/geovaljaren/geovaljaren.css +21 -0
  27. package/dist/collection/components/geovaljaren/geovaljaren.js +304 -0
  28. package/dist/collection/components/geovaljaren/logic/adapter.utils.js +20 -0
  29. package/dist/collection/components/geovaljaren/logic/data.utils.js +12 -0
  30. package/dist/collection/components/geovaljaren/logic/history-service.js +25 -0
  31. package/dist/collection/components/geovaljaren/logic/search.engine.js +28 -0
  32. package/dist/collection/components/job-selector/constants.js +26 -0
  33. package/dist/collection/components/job-selector/history-service.js +41 -0
  34. package/dist/collection/components/job-selector/job-selector-controller.js +835 -0
  35. package/dist/collection/components/job-selector/job-selector.css +318 -0
  36. package/dist/collection/components/job-selector/job-selector.js +1378 -0
  37. package/dist/collection/components/job-selector/keyboard-handlers.js +84 -0
  38. package/dist/collection/components/job-selector/logic/adapter.utils.js +75 -0
  39. package/dist/collection/components/job-selector/logic/label-formatter.js +118 -0
  40. package/dist/collection/components/job-selector/logic/search.engine.js +50 -0
  41. package/dist/collection/components/job-selector/search-logic.js +35 -0
  42. package/dist/collection/components/job-selector/search.utils.js +224 -0
  43. package/dist/collection/components/job-selector/suggestions-list.js +31 -0
  44. package/dist/collection/components/job-selector/taxonomy-registry.js +60 -0
  45. package/dist/collection/components/job-selector/test-data.mock.js +33 -0
  46. package/dist/collection/components/job-selector/types.js +10 -0
  47. package/dist/collection/components/job-selector/validation-message.js +24 -0
  48. package/dist/collection/demo-data.js +20 -0
  49. package/dist/collection/index.js +7 -0
  50. package/dist/collection/verkstad/verkstad.js +407 -0
  51. package/dist/components/core-selector.d.ts +11 -0
  52. package/dist/components/core-selector.js +1 -0
  53. package/dist/components/core-selector2.js +1 -0
  54. package/dist/components/digi-service-job-selector.d.ts +11 -0
  55. package/dist/components/digi-service-job-selector.js +1 -0
  56. package/dist/components/fuse.js +1 -0
  57. package/dist/components/geo-valjaren.d.ts +11 -0
  58. package/dist/components/geo-valjaren.js +1 -0
  59. package/dist/components/index.d.ts +35 -0
  60. package/dist/components/index.js +1 -0
  61. package/dist/components/job-selector-demo.d.ts +11 -0
  62. package/dist/components/job-selector-demo.js +1 -0
  63. package/dist/components/job-selector.js +1 -0
  64. package/dist/components/neobrutal-search.d.ts +11 -0
  65. package/dist/components/neobrutal-search.js +1 -0
  66. package/dist/components/search.engine.js +1 -0
  67. package/dist/components/types.js +1 -0
  68. package/dist/esm/af-validation-message-F8NIH2rC.js +14 -0
  69. package/dist/esm/core-selector.entry.js +474 -0
  70. package/dist/esm/digi-service-job-selector.entry.js +1617 -0
  71. package/dist/esm/fuse-BPnhMTul.js +1629 -0
  72. package/dist/esm/geo-valjaren.entry.js +14908 -0
  73. package/dist/esm/index-CGXZllj2.js +1806 -0
  74. package/dist/esm/index.js +10 -0
  75. package/dist/esm/job-selector-demo.entry.js +690 -0
  76. package/dist/esm/loader.js +10 -0
  77. package/dist/esm/neobrutal-search.entry.js +169 -0
  78. package/dist/esm/search.engine-nZ7AcXba.js +479 -0
  79. package/dist/esm/taxonomy-registry-Dw0VR9Aw.js +430 -0
  80. package/dist/esm/types-DHUftoZJ.js +12 -0
  81. package/dist/esm/yrkesvaljaren.js +20 -0
  82. package/dist/index.cjs.js +1 -0
  83. package/dist/index.js +1 -0
  84. package/dist/types/components/core-selector/core-selector.d.ts +46 -0
  85. package/dist/types/components/core-selector/types.d.ts +1 -0
  86. package/dist/types/components/design-compat/af-icon.d.ts +7 -0
  87. package/dist/types/components/design-compat/af-label.d.ts +8 -0
  88. package/dist/types/components/design-compat/af-tag.d.ts +8 -0
  89. package/dist/types/components/design-compat/af-validation-message.d.ts +9 -0
  90. package/dist/types/components/design-compat/index.d.ts +5 -0
  91. package/dist/types/components/geovaljaren/geovaljaren.d.ts +24 -0
  92. package/dist/types/components/geovaljaren/logic/adapter.utils.d.ts +7 -0
  93. package/dist/types/components/geovaljaren/logic/data.utils.d.ts +7 -0
  94. package/dist/types/components/geovaljaren/logic/history-service.d.ts +6 -0
  95. package/dist/types/components/geovaljaren/logic/search.engine.d.ts +7 -0
  96. package/dist/types/components/job-selector/ambient.d.ts +4 -0
  97. package/dist/types/components/job-selector/constants.d.ts +13 -0
  98. package/dist/types/components/job-selector/history-service.d.ts +6 -0
  99. package/dist/types/components/job-selector/job-selector-controller.d.ts +82 -0
  100. package/dist/types/components/job-selector/job-selector.d.ts +140 -0
  101. package/dist/types/components/job-selector/keyboard-handlers.d.ts +13 -0
  102. package/dist/types/components/job-selector/logic/adapter.utils.d.ts +12 -0
  103. package/dist/types/components/job-selector/logic/label-formatter.d.ts +4 -0
  104. package/dist/types/components/job-selector/logic/search.engine.d.ts +21 -0
  105. package/dist/types/components/job-selector/search-logic.d.ts +17 -0
  106. package/dist/types/components/job-selector/search.utils.d.ts +10 -0
  107. package/dist/types/components/job-selector/suggestions-list.d.ts +13 -0
  108. package/dist/types/components/job-selector/taxonomy-registry.d.ts +20 -0
  109. package/dist/types/components/job-selector/test-data.mock.d.ts +7 -0
  110. package/dist/types/components/job-selector/types.d.ts +107 -0
  111. package/dist/types/components/job-selector/validation-message.d.ts +8 -0
  112. package/dist/types/components/job-selector-demo/job-selector-demo.d.ts +55 -0
  113. package/dist/types/components/neobrutal-search/neobrutal-search.d.ts +18 -0
  114. package/dist/types/components.d.ts +425 -0
  115. package/dist/types/demo-data.d.ts +16 -0
  116. package/dist/types/index.d.ts +5 -0
  117. package/dist/types/stencil-public-runtime.d.ts +1873 -0
  118. package/dist/types/verkstad/verkstad.d.ts +1 -0
  119. package/dist/yrkesvaljaren/fuse-B0eHOxow.js.map +1 -0
  120. package/dist/yrkesvaljaren/index-Cy4BCo5s.js.map +1 -0
  121. package/dist/yrkesvaljaren/index-DfJXTQqL.js.map +1 -0
  122. package/dist/yrkesvaljaren/index.esm.js +1 -0
  123. package/dist/yrkesvaljaren/index.esm.js.map +1 -0
  124. package/dist/yrkesvaljaren/p-16636162.entry.js +1 -0
  125. package/dist/yrkesvaljaren/p-273cf6df.entry.js +1 -0
  126. package/dist/yrkesvaljaren/p-9e48afa4.entry.js +1 -0
  127. package/dist/yrkesvaljaren/p-BPnhMTul.js +1 -0
  128. package/dist/yrkesvaljaren/p-CGXZllj2.js +3 -0
  129. package/dist/yrkesvaljaren/p-DHUftoZJ.js +1 -0
  130. package/dist/yrkesvaljaren/p-DYFAzvqX.js +1 -0
  131. package/dist/yrkesvaljaren/p-Dw0VR9Aw.js +1 -0
  132. package/dist/yrkesvaljaren/p-aef7b5ae.entry.js +1 -0
  133. package/dist/yrkesvaljaren/p-b0f16abd.entry.js +1 -0
  134. package/dist/yrkesvaljaren/p-uBrs3sSs.js +1 -0
  135. package/dist/yrkesvaljaren/search.engine-DPT6roRm.js.map +1 -0
  136. package/dist/yrkesvaljaren/taxonomy-registry-s5khf6s4.js.map +1 -0
  137. package/dist/yrkesvaljaren/types-DHUftoZJ.js.map +1 -0
  138. package/dist/yrkesvaljaren/yrkesvaljaren.css +1 -0
  139. package/dist/yrkesvaljaren/yrkesvaljaren.esm.js +1 -0
  140. package/dist/yrkesvaljaren/yrkesvaljaren.esm.js.map +1 -0
  141. package/loader/cdn.js +1 -0
  142. package/loader/index.cjs.js +1 -0
  143. package/loader/index.d.ts +24 -0
  144. package/loader/index.es2017.js +1 -0
  145. package/loader/index.js +2 -0
  146. package/package.json +126 -0
@@ -0,0 +1,761 @@
1
+ // src/components/core-selector/core-selector.tsx
2
+ import { h } from "@stencil/core";
3
+ import { reconcileActiveIndex, shouldShowManualInput } from "@taxonomy/core/selector-navigation";
4
+ import { AfIcon, AfLabel, AfTag, AfValidationMessage } from "../design-compat";
5
+ export class CoreSelector {
6
+ historyRequestTimer;
7
+ disconnectedCallback() {
8
+ clearTimeout(this.historyRequestTimer);
9
+ this.historyRequestTimer = undefined;
10
+ }
11
+ static nextId = 0;
12
+ hostElement;
13
+ state;
14
+ config = {
15
+ disabled: false,
16
+ placeholder: 'Sök...',
17
+ minLength: 1,
18
+ maxResults: 10,
19
+ enableMultiple: false,
20
+ showSearchIcon: true,
21
+ requireSelection: true,
22
+ size: 'medium'
23
+ };
24
+ label = '';
25
+ labelDescription;
26
+ componentId = `cs-${CoreSelector.nextId++}`;
27
+ size = 'medium';
28
+ csInput;
29
+ csSelect;
30
+ csClear;
31
+ csRemoveItem;
32
+ csBlur;
33
+ csEditSelection;
34
+ csFocus;
35
+ csLoadMore;
36
+ csClearHistory;
37
+ csRequestHistory;
38
+ afFocused = false;
39
+ activeIndex = -1;
40
+ isFocusedInternal = false;
41
+ isNavigatingWithKeyboard = false;
42
+ async setFocus() {
43
+ if (this.inputRef) {
44
+ this.inputRef.focus();
45
+ const len = this.inputRef.value.length;
46
+ this.inputRef.setSelectionRange(len, len);
47
+ }
48
+ else {
49
+ this.shouldFocusAfterRender = true;
50
+ }
51
+ }
52
+ inputRef;
53
+ listRef;
54
+ shouldFocusAfterRender = false;
55
+ handleKeyDown = (event) => {
56
+ if (this.config.disabled) {
57
+ event.preventDefault();
58
+ return;
59
+ }
60
+ if (!this.state)
61
+ return;
62
+ if (event.target.tagName === 'BUTTON')
63
+ return;
64
+ if (event.key !== 'ArrowUp' && event.key !== 'ArrowDown' && event.key !== 'Enter' && event.key !== 'Escape') {
65
+ this.isNavigatingWithKeyboard = false;
66
+ }
67
+ if (this.state.status === 'itemSelected') {
68
+ if (event.key !== 'Tab' && event.key !== 'Shift' && !event.ctrlKey && !event.metaKey) {
69
+ this.csEditSelection.emit();
70
+ return;
71
+ }
72
+ }
73
+ if (this.state.status !== 'searching' && this.state.status !== 'multiSelect')
74
+ return;
75
+ const suggestions = this.state.suggestions;
76
+ const showManualInput = shouldShowManualInput(this.state, this.config.requireSelection);
77
+ const totalOptions = suggestions.length + (showManualInput ? 1 : 0);
78
+ switch (event.key) {
79
+ case 'ArrowDown':
80
+ if (totalOptions > 0) {
81
+ event.preventDefault();
82
+ this.isNavigatingWithKeyboard = true;
83
+ if (this.activeIndex < totalOptions - 1) {
84
+ this.activeIndex = this.activeIndex + 1;
85
+ this.scrollToActive();
86
+ }
87
+ if (this.activeIndex >= suggestions.length - 3) {
88
+ this.csLoadMore.emit();
89
+ }
90
+ }
91
+ else {
92
+ this.csFocus.emit();
93
+ }
94
+ break;
95
+ case 'ArrowUp':
96
+ if (totalOptions > 0) {
97
+ event.preventDefault();
98
+ this.isNavigatingWithKeyboard = true;
99
+ if (this.activeIndex > 0) {
100
+ this.activeIndex = this.activeIndex - 1;
101
+ this.scrollToActive();
102
+ }
103
+ else if (this.activeIndex === 0 || this.activeIndex === -1) {
104
+ // Wrap around to the last option (which might be manual input)
105
+ this.activeIndex = totalOptions - 1;
106
+ this.scrollToActive();
107
+ }
108
+ }
109
+ break;
110
+ case ' ':
111
+ case 'Enter':
112
+ // Only handle Space if we have an active suggestion (keyboard navigation)
113
+ // If index is -1, let the space go through to the input field
114
+ if (event.key === ' ' && this.activeIndex === -1) {
115
+ return;
116
+ }
117
+ if (this.activeIndex >= 0 && this.activeIndex < suggestions.length) {
118
+ event.preventDefault();
119
+ const item = suggestions[this.activeIndex];
120
+ this.shouldFocusAfterRender = true;
121
+ if (item.isSelected) {
122
+ this.csRemoveItem.emit(item);
123
+ }
124
+ else {
125
+ this.csSelect.emit(item);
126
+ }
127
+ }
128
+ else if (showManualInput && this.activeIndex === suggestions.length && this.isNavigatingWithKeyboard) {
129
+ event.preventDefault();
130
+ this.handleManualSelect();
131
+ }
132
+ else if (event.key === 'Enter') {
133
+ // If Enter is pressed but no item is active,
134
+ // we prevent default to avoid accidental form submission
135
+ // and ensure the dropdown stays open if manual input is available.
136
+ if (showManualInput || suggestions.length > 0) {
137
+ event.preventDefault();
138
+ this.isNavigatingWithKeyboard = true;
139
+ }
140
+ }
141
+ break;
142
+ case 'Escape':
143
+ this.activeIndex = -1;
144
+ this.csClear.emit();
145
+ break;
146
+ }
147
+ };
148
+ onWrapperFocusIn = () => {
149
+ if (this.config.disabled)
150
+ return;
151
+ if (!this.state || !this.isFocusedInternal) {
152
+ if (this.state) {
153
+ this.isFocusedInternal = true;
154
+ this.activeIndex = -1;
155
+ this.csFocus.emit();
156
+ if (this.state.inputValue.trim() === '') {
157
+ this.csRequestHistory.emit();
158
+ }
159
+ }
160
+ }
161
+ };
162
+ onWrapperFocusOut = () => {
163
+ if (this.shouldFocusAfterRender)
164
+ return;
165
+ // Use requestAnimationFrame to wait for the next frame where focus
166
+ // will have settled on the new element.
167
+ requestAnimationFrame(() => {
168
+ const root = this.hostElement.shadowRoot;
169
+ const activeElement = root?.activeElement || document.activeElement;
170
+ // Check if the currently focused element is inside the component or its shadow DOM
171
+ const isInside = (activeElement && this.hostElement.contains(activeElement)) ||
172
+ (root && root.contains(activeElement));
173
+ if (!isInside) {
174
+ this.isFocusedInternal = false;
175
+ this.activeIndex = -1;
176
+ this.csBlur.emit();
177
+ }
178
+ });
179
+ };
180
+ handleAfFocusedChange(newValue) {
181
+ this.isFocusedInternal = newValue;
182
+ if (newValue) {
183
+ this.shouldFocusAfterRender = true;
184
+ }
185
+ }
186
+ handleConfigChange(newConfig) {
187
+ if (newConfig.disabled) {
188
+ this.isFocusedInternal = false;
189
+ this.activeIndex = -1;
190
+ this.shouldFocusAfterRender = false;
191
+ }
192
+ }
193
+ handleStateChange(newState, oldState) {
194
+ const result = reconcileActiveIndex({
195
+ activeIndex: this.activeIndex,
196
+ newState,
197
+ oldState,
198
+ requireSelection: this.config.requireSelection,
199
+ });
200
+ this.activeIndex = result.activeIndex;
201
+ if (result.shouldRestoreFocus) {
202
+ this.shouldFocusAfterRender = true;
203
+ }
204
+ }
205
+ componentDidUpdate() {
206
+ if (this.shouldFocusAfterRender) {
207
+ this.performFocusRestoration();
208
+ }
209
+ }
210
+ performFocusRestoration(retryCount = 0) {
211
+ if (this.config.disabled) {
212
+ this.shouldFocusAfterRender = false;
213
+ return;
214
+ }
215
+ if (this.inputRef) {
216
+ this.isFocusedInternal = true; // Ensure UI thinks it's focused to show suggestions
217
+ this.inputRef.focus();
218
+ const currentActive = this.hostElement.shadowRoot?.activeElement;
219
+ if (currentActive === this.inputRef || retryCount > 20) {
220
+ const len = this.inputRef.value.length;
221
+ this.inputRef.setSelectionRange(len, len);
222
+ this.shouldFocusAfterRender = false;
223
+ }
224
+ else {
225
+ requestAnimationFrame(() => this.performFocusRestoration(retryCount + 1));
226
+ }
227
+ }
228
+ }
229
+ handleScroll(event) {
230
+ if (!this.config.enableInfiniteScroll)
231
+ return;
232
+ const target = event.target;
233
+ const threshold = 50;
234
+ const remaining = target.scrollHeight - (target.scrollTop + target.clientHeight);
235
+ if (remaining < threshold) {
236
+ this.csLoadMore.emit();
237
+ }
238
+ }
239
+ scrollToActive() {
240
+ if (!this.listRef || !this.state)
241
+ return;
242
+ const optionId = this.activeIndex === this.state.suggestions.length
243
+ ? `${this.componentId}-list-option-manual-input`
244
+ : `${this.componentId}-list-option-${this.activeIndex}`;
245
+ const activeElement = this.listRef.querySelector(`#${optionId}`);
246
+ activeElement?.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
247
+ }
248
+ handleManualSelect() {
249
+ const item = { id: '', label: this.state.inputValue.trim(), metadata: { type: 'ManualInput' } };
250
+ this.shouldFocusAfterRender = true;
251
+ this.csSelect.emit(item);
252
+ if (this.config.enableMultiple && this.state?.inputValue?.trim() === '') {
253
+ this.csRequestHistory.emit();
254
+ }
255
+ }
256
+ render() {
257
+ if (!this.state)
258
+ return null;
259
+ const isSelected = this.state.status === 'itemSelected';
260
+ return (h("div", { class: { 'core-selector-wrapper': true, 'is-disabled': !!this.config.disabled }, "aria-disabled": this.config.disabled ? 'true' : 'false', onKeyDown: (e) => this.handleKeyDown(e), onMouseMove: () => { this.isNavigatingWithKeyboard = false; }, onFocusin: this.onWrapperFocusIn, onFocusout: this.onWrapperFocusOut }, this.label && (h(AfLabel, { label: this.label, forId: `${this.componentId}-input`, description: this.labelDescription })), this.labelDescription && (h("div", { id: `${this.componentId}-description`, class: "visually-hidden" }, this.labelDescription)), this.state && this.state.status === 'loading' && h("div", { class: "loading-indicator" }, "Laddar..."), this.state && this.state.status === 'error' && h("div", { class: "error-message" }, this.state.message), this.state && ['searching', 'itemSelected', 'multiSelect'].includes(this.state.status) && (h("div", { class: "combobox-container" }, this.renderSearchContainer(), this.isFocusedInternal && !isSelected && this.renderSuggestionsList())), this.state && this.state.validation !== 'idle' && this.state.status !== 'itemSelected' && (h(AfValidationMessage, { id: `${this.componentId}-validation-message`, variant: this.state.validation === 'error' ? 'error' : 'success', role: this.state.validation === 'error' ? 'alert' : undefined, class: "selector-validation-message" }, this.state.message))));
261
+ }
262
+ renderSearchContainer() {
263
+ const isSelected = this.state.status === 'itemSelected';
264
+ const displayValue = isSelected ? (this.state.selectedItem?.label || '') : this.state.inputValue;
265
+ const isMulti = this.state.status === 'multiSelect';
266
+ const hasInput = displayValue.length > 0;
267
+ const hasTags = isMulti && this.state.selectedItems.length > 0;
268
+ const hasSuggestions = this.state && (this.state.suggestions.length > 0 || shouldShowManualInput(this.state, this.config.requireSelection));
269
+ const activeDescendantId = (this.activeIndex >= 0 && this.isNavigatingWithKeyboard)
270
+ ? (this.activeIndex === this.state.suggestions.length
271
+ ? `${this.componentId}-list-option-manual-input`
272
+ : `${this.componentId}-list-option-${this.activeIndex}`)
273
+ : undefined;
274
+ const descriptionId = `${this.componentId}-description`;
275
+ const validationMessageId = `${this.componentId}-validation-message`;
276
+ const hasDescription = !!this.labelDescription;
277
+ const hasError = this.state && this.state.validation === 'error' && this.state.message;
278
+ const describedByList = [];
279
+ if (hasDescription && displayValue.length === 0)
280
+ describedByList.push(descriptionId);
281
+ if (hasError)
282
+ describedByList.push(validationMessageId);
283
+ const ariaDescribedBy = describedByList.length > 0 ? describedByList.join(' ') : undefined;
284
+ return (h("div", { class: {
285
+ 'search-container': true,
286
+ 'is-inactive-selected': isSelected,
287
+ 'multi-search-container': isMulti,
288
+ 'has-tags': hasTags,
289
+ 'has-validation-error': this.state?.validation === 'error',
290
+ 'has-positive-validation': !isSelected && this.state?.validation === 'success',
291
+ }, onClick: () => {
292
+ if (this.config.disabled)
293
+ return;
294
+ if (isSelected) {
295
+ this.csEditSelection.emit();
296
+ }
297
+ else if (this.state.inputValue.trim() === '') {
298
+ this.csRequestHistory.emit();
299
+ }
300
+ } }, isMulti && this.state.selectedItems.length > 0 && (h("div", { class: "selected-tags-wrapper" }, this.state.selectedItems.map((item) => (h(AfTag, { key: item.id, text: item.label, breakWords: true, onRemove: () => {
301
+ this.shouldFocusAfterRender = true;
302
+ this.csRemoveItem.emit(item);
303
+ } }))))), h("div", { class: "input-controls-wrapper" }, h(AfIcon, { name: "search", class: {
304
+ 'search-icon-container': true,
305
+ 'selector-search-icon': true,
306
+ 'is-hidden': !this.config.showSearchIcon || hasInput || hasTags,
307
+ } }), h("div", { class: { 'input-area': true, 'has-value': !this.config.showSearchIcon || hasInput || hasTags } }, isSelected && (h("span", { class: "selected-text-in-box" }, displayValue)), h("input", { class: {
308
+ 'selector-input-field': true,
309
+ 'visually-hidden-selected': isSelected
310
+ }, ref: (el) => this.inputRef = el, id: `${this.componentId}-input`, type: "text", placeholder: this.config.placeholder, value: displayValue, onInput: (e) => {
311
+ if (this.config.disabled)
312
+ return;
313
+ this.isNavigatingWithKeyboard = false;
314
+ this.csInput.emit(e.target.value);
315
+ }, autocomplete: "off", role: "combobox", "aria-label": this.label, "aria-autocomplete": "list", "aria-haspopup": "listbox", "aria-expanded": !isSelected && hasSuggestions && this.isNavigatingWithKeyboard ? 'true' : 'false', "aria-controls": !isSelected && hasSuggestions && this.isNavigatingWithKeyboard ? `${this.componentId}-listbox` : undefined, "aria-activedescendant": activeDescendantId, "aria-invalid": hasError ? 'true' : 'false', "aria-describedby": ariaDescribedBy, readOnly: isSelected, disabled: !!this.config.disabled })), h("button", { type: "button", class: { 'clear-button': true, 'is-visible': hasInput || isSelected }, tabIndex: hasInput || isSelected ? 0 : -1, disabled: !!this.config.disabled, "aria-label": "Rensa inmatad text", onMouseDown: (e) => e.preventDefault(), onClick: () => {
316
+ if (this.config.disabled)
317
+ return;
318
+ this.csInput.emit('');
319
+ this.shouldFocusAfterRender = true;
320
+ this.csClear.emit();
321
+ this.csRequestHistory.emit();
322
+ } }, h(AfIcon, { name: "x" })))));
323
+ }
324
+ renderSuggestionsList() {
325
+ if (this.state.status === 'itemSelected')
326
+ return null;
327
+ const hasSearchInput = Boolean(this.state.inputValue && this.state.inputValue.trim().length > 0);
328
+ const showManualInput = shouldShowManualInput(this.state, this.config.requireSelection);
329
+ const hasSuggestions = Boolean(this.state.suggestions && this.state.suggestions.length > 0);
330
+ const noResults = hasSearchInput && !hasSuggestions && !showManualInput;
331
+ if (!hasSuggestions && !showManualInput && !noResults) {
332
+ return null;
333
+ }
334
+ const listHeader = this.state.listHeader || this.config.listHeader;
335
+ const showHistoryHeader = this.state.showHistoryHeader || (this.state.isHistoryView && this.config.showHistoryHeader);
336
+ return (h("div", { class: "suggestions-box-container" }, h("div", { class: "suggestions-box", ref: (el) => (this.listRef = el), onScroll: (e) => this.handleScroll(e) }, (listHeader || showHistoryHeader) && (h("div", { class: "list-header-container" }, h("slot", { name: "suggestions-overlay" }), listHeader && (h("div", { class: "list-header" }, h("span", null, listHeader))), showHistoryHeader && (h("div", { class: "list-header history-header" }, h("span", null, "Din privata historik"), " - ", h("button", { type: "button", class: "history-clear-link", "aria-label": "Rensa historik", disabled: !!this.config.disabled, onMouseDown: (e) => e.preventDefault(), onClick: () => {
337
+ if (!this.config.disabled)
338
+ this.csClearHistory.emit();
339
+ } }, "Rensa"))))), !listHeader && !showHistoryHeader && h("slot", { name: "suggestions-overlay" }), h("div", { id: `${this.componentId}-listbox`, role: "listbox" }, noResults && (h("div", { class: "suggestion-item no-results" }, "Inga resultat matchade din s\u00F6kning")), !noResults && this.state.suggestions.map((item, index) => (h("div", { key: item.id || index, role: "option", id: `${this.componentId}-list-option-${index}`, "aria-selected": !!item.isSelected, "aria-current": index === this.activeIndex ? 'true' : 'false', class: {
340
+ 'suggestion-item': true,
341
+ 'active-suggestion': index === this.activeIndex,
342
+ 'is-selected': !!item.isSelected,
343
+ 'is-keyboard-focus': index === this.activeIndex && this.isNavigatingWithKeyboard
344
+ }, onMouseDown: (e) => {
345
+ e.preventDefault();
346
+ if (this.config.disabled)
347
+ return;
348
+ this.shouldFocusAfterRender = true;
349
+ if (item.isSelected) {
350
+ this.csRemoveItem.emit(item);
351
+ }
352
+ else {
353
+ this.csSelect.emit(item);
354
+ }
355
+ if (this.config.enableMultiple) {
356
+ // Trigger history refresh if we are in multi-mode
357
+ clearTimeout(this.historyRequestTimer);
358
+ this.historyRequestTimer = setTimeout(() => {
359
+ this.csRequestHistory.emit();
360
+ this.historyRequestTimer = undefined;
361
+ }, 50);
362
+ }
363
+ }, onMouseEnter: () => {
364
+ if (this.config.disabled)
365
+ return;
366
+ if (!item.isSelected) {
367
+ this.activeIndex = index;
368
+ this.isNavigatingWithKeyboard = false;
369
+ }
370
+ } }, h(AfIcon, { name: "check", class: "selection-indicator-icon" }), item.displaySegments ? (h("span", null, item.displaySegments.map((segment, segmentIndex) => (h("span", { key: segmentIndex, class: {
371
+ 'match-highlight': !!segment.isMatch,
372
+ 'metadata-dimmed': !!segment.isMetadata
373
+ } }, segment.text))))) : (h("span", null, item.label))))), !noResults && shouldShowManualInput(this.state, this.config.requireSelection) && (h("div", { role: "option", id: `${this.componentId}-list-option-manual-input`, class: {
374
+ 'suggestion-item': true,
375
+ 'active-suggestion': this.activeIndex === this.state.suggestions.length,
376
+ 'is-keyboard-focus': this.activeIndex === this.state.suggestions.length && this.isNavigatingWithKeyboard
377
+ }, onMouseDown: (e) => {
378
+ e.preventDefault();
379
+ if (!this.config.disabled)
380
+ this.handleManualSelect();
381
+ }, onMouseEnter: () => {
382
+ if (this.config.disabled)
383
+ return;
384
+ this.activeIndex = this.state.suggestions.length;
385
+ this.isNavigatingWithKeyboard = false;
386
+ } }, h("span", null, "Anv\u00E4nd \"", h("strong", null, this.state.inputValue.trim()), "\"")))))));
387
+ }
388
+ static get is() { return "core-selector"; }
389
+ static get encapsulation() { return "shadow"; }
390
+ static get delegatesFocus() { return true; }
391
+ static get originalStyleUrls() {
392
+ return {
393
+ "$": ["core-selector.css"]
394
+ };
395
+ }
396
+ static get styleUrls() {
397
+ return {
398
+ "$": ["core-selector.css"]
399
+ };
400
+ }
401
+ static get properties() {
402
+ return {
403
+ "state": {
404
+ "type": "unknown",
405
+ "mutable": false,
406
+ "complexType": {
407
+ "original": "SelectorState",
408
+ "resolved": "SelectorState",
409
+ "references": {
410
+ "SelectorState": {
411
+ "location": "import",
412
+ "path": "./types",
413
+ "id": "src/components/core-selector/types.ts::SelectorState",
414
+ "referenceLocation": "SelectorState"
415
+ }
416
+ }
417
+ },
418
+ "required": true,
419
+ "optional": false,
420
+ "docs": {
421
+ "tags": [],
422
+ "text": ""
423
+ },
424
+ "getter": false,
425
+ "setter": false
426
+ },
427
+ "config": {
428
+ "type": "unknown",
429
+ "mutable": false,
430
+ "complexType": {
431
+ "original": "SelectorConfig",
432
+ "resolved": "SelectorConfig",
433
+ "references": {
434
+ "SelectorConfig": {
435
+ "location": "import",
436
+ "path": "./types",
437
+ "id": "src/components/core-selector/types.ts::SelectorConfig",
438
+ "referenceLocation": "SelectorConfig"
439
+ }
440
+ }
441
+ },
442
+ "required": false,
443
+ "optional": false,
444
+ "docs": {
445
+ "tags": [],
446
+ "text": ""
447
+ },
448
+ "getter": false,
449
+ "setter": false,
450
+ "defaultValue": "{\n disabled: false,\n placeholder: 'S\u00F6k...',\n minLength: 1,\n maxResults: 10,\n enableMultiple: false,\n showSearchIcon: true,\n requireSelection: true,\n size: 'medium'\n }"
451
+ },
452
+ "label": {
453
+ "type": "string",
454
+ "mutable": false,
455
+ "complexType": {
456
+ "original": "string",
457
+ "resolved": "string",
458
+ "references": {}
459
+ },
460
+ "required": false,
461
+ "optional": false,
462
+ "docs": {
463
+ "tags": [],
464
+ "text": ""
465
+ },
466
+ "getter": false,
467
+ "setter": false,
468
+ "reflect": false,
469
+ "attribute": "label",
470
+ "defaultValue": "''"
471
+ },
472
+ "labelDescription": {
473
+ "type": "string",
474
+ "mutable": false,
475
+ "complexType": {
476
+ "original": "string",
477
+ "resolved": "string | undefined",
478
+ "references": {}
479
+ },
480
+ "required": false,
481
+ "optional": true,
482
+ "docs": {
483
+ "tags": [],
484
+ "text": ""
485
+ },
486
+ "getter": false,
487
+ "setter": false,
488
+ "reflect": false,
489
+ "attribute": "label-description"
490
+ },
491
+ "componentId": {
492
+ "type": "string",
493
+ "mutable": false,
494
+ "complexType": {
495
+ "original": "string",
496
+ "resolved": "string",
497
+ "references": {}
498
+ },
499
+ "required": false,
500
+ "optional": false,
501
+ "docs": {
502
+ "tags": [],
503
+ "text": ""
504
+ },
505
+ "getter": false,
506
+ "setter": false,
507
+ "reflect": false,
508
+ "attribute": "component-id",
509
+ "defaultValue": "`cs-${CoreSelector.nextId++}`"
510
+ },
511
+ "size": {
512
+ "type": "string",
513
+ "mutable": false,
514
+ "complexType": {
515
+ "original": "'small' | 'medium' | 'large'",
516
+ "resolved": "\"large\" | \"medium\" | \"small\"",
517
+ "references": {}
518
+ },
519
+ "required": false,
520
+ "optional": false,
521
+ "docs": {
522
+ "tags": [],
523
+ "text": ""
524
+ },
525
+ "getter": false,
526
+ "setter": false,
527
+ "reflect": true,
528
+ "attribute": "cs-size",
529
+ "defaultValue": "'medium'"
530
+ },
531
+ "afFocused": {
532
+ "type": "boolean",
533
+ "mutable": false,
534
+ "complexType": {
535
+ "original": "boolean",
536
+ "resolved": "boolean",
537
+ "references": {}
538
+ },
539
+ "required": false,
540
+ "optional": false,
541
+ "docs": {
542
+ "tags": [],
543
+ "text": ""
544
+ },
545
+ "getter": false,
546
+ "setter": false,
547
+ "reflect": false,
548
+ "attribute": "af-focused",
549
+ "defaultValue": "false"
550
+ }
551
+ };
552
+ }
553
+ static get states() {
554
+ return {
555
+ "activeIndex": {},
556
+ "isFocusedInternal": {},
557
+ "isNavigatingWithKeyboard": {}
558
+ };
559
+ }
560
+ static get events() {
561
+ return [{
562
+ "method": "csInput",
563
+ "name": "csInput",
564
+ "bubbles": true,
565
+ "cancelable": true,
566
+ "composed": true,
567
+ "docs": {
568
+ "tags": [],
569
+ "text": ""
570
+ },
571
+ "complexType": {
572
+ "original": "string",
573
+ "resolved": "string",
574
+ "references": {}
575
+ }
576
+ }, {
577
+ "method": "csSelect",
578
+ "name": "csSelect",
579
+ "bubbles": true,
580
+ "cancelable": true,
581
+ "composed": true,
582
+ "docs": {
583
+ "tags": [],
584
+ "text": ""
585
+ },
586
+ "complexType": {
587
+ "original": "GenericItem",
588
+ "resolved": "GenericItem<unknown>",
589
+ "references": {
590
+ "GenericItem": {
591
+ "location": "import",
592
+ "path": "./types",
593
+ "id": "src/components/core-selector/types.ts::GenericItem",
594
+ "referenceLocation": "GenericItem"
595
+ }
596
+ }
597
+ }
598
+ }, {
599
+ "method": "csClear",
600
+ "name": "csClear",
601
+ "bubbles": true,
602
+ "cancelable": true,
603
+ "composed": true,
604
+ "docs": {
605
+ "tags": [],
606
+ "text": ""
607
+ },
608
+ "complexType": {
609
+ "original": "void",
610
+ "resolved": "void",
611
+ "references": {}
612
+ }
613
+ }, {
614
+ "method": "csRemoveItem",
615
+ "name": "csRemoveItem",
616
+ "bubbles": true,
617
+ "cancelable": true,
618
+ "composed": true,
619
+ "docs": {
620
+ "tags": [],
621
+ "text": ""
622
+ },
623
+ "complexType": {
624
+ "original": "GenericItem",
625
+ "resolved": "GenericItem<unknown>",
626
+ "references": {
627
+ "GenericItem": {
628
+ "location": "import",
629
+ "path": "./types",
630
+ "id": "src/components/core-selector/types.ts::GenericItem",
631
+ "referenceLocation": "GenericItem"
632
+ }
633
+ }
634
+ }
635
+ }, {
636
+ "method": "csBlur",
637
+ "name": "csBlur",
638
+ "bubbles": true,
639
+ "cancelable": true,
640
+ "composed": true,
641
+ "docs": {
642
+ "tags": [],
643
+ "text": ""
644
+ },
645
+ "complexType": {
646
+ "original": "void",
647
+ "resolved": "void",
648
+ "references": {}
649
+ }
650
+ }, {
651
+ "method": "csEditSelection",
652
+ "name": "csEditSelection",
653
+ "bubbles": true,
654
+ "cancelable": true,
655
+ "composed": true,
656
+ "docs": {
657
+ "tags": [],
658
+ "text": ""
659
+ },
660
+ "complexType": {
661
+ "original": "void",
662
+ "resolved": "void",
663
+ "references": {}
664
+ }
665
+ }, {
666
+ "method": "csFocus",
667
+ "name": "csFocus",
668
+ "bubbles": true,
669
+ "cancelable": true,
670
+ "composed": true,
671
+ "docs": {
672
+ "tags": [],
673
+ "text": ""
674
+ },
675
+ "complexType": {
676
+ "original": "void",
677
+ "resolved": "void",
678
+ "references": {}
679
+ }
680
+ }, {
681
+ "method": "csLoadMore",
682
+ "name": "csLoadMore",
683
+ "bubbles": true,
684
+ "cancelable": true,
685
+ "composed": true,
686
+ "docs": {
687
+ "tags": [],
688
+ "text": ""
689
+ },
690
+ "complexType": {
691
+ "original": "void",
692
+ "resolved": "void",
693
+ "references": {}
694
+ }
695
+ }, {
696
+ "method": "csClearHistory",
697
+ "name": "csClearHistory",
698
+ "bubbles": true,
699
+ "cancelable": true,
700
+ "composed": true,
701
+ "docs": {
702
+ "tags": [],
703
+ "text": ""
704
+ },
705
+ "complexType": {
706
+ "original": "void",
707
+ "resolved": "void",
708
+ "references": {}
709
+ }
710
+ }, {
711
+ "method": "csRequestHistory",
712
+ "name": "csRequestHistory",
713
+ "bubbles": true,
714
+ "cancelable": true,
715
+ "composed": true,
716
+ "docs": {
717
+ "tags": [],
718
+ "text": ""
719
+ },
720
+ "complexType": {
721
+ "original": "void",
722
+ "resolved": "void",
723
+ "references": {}
724
+ }
725
+ }];
726
+ }
727
+ static get methods() {
728
+ return {
729
+ "setFocus": {
730
+ "complexType": {
731
+ "signature": "() => Promise<void>",
732
+ "parameters": [],
733
+ "references": {
734
+ "Promise": {
735
+ "location": "global",
736
+ "id": "global::Promise"
737
+ }
738
+ },
739
+ "return": "Promise<void>"
740
+ },
741
+ "docs": {
742
+ "text": "",
743
+ "tags": []
744
+ }
745
+ }
746
+ };
747
+ }
748
+ static get elementRef() { return "hostElement"; }
749
+ static get watchers() {
750
+ return [{
751
+ "propName": "afFocused",
752
+ "methodName": "handleAfFocusedChange"
753
+ }, {
754
+ "propName": "config",
755
+ "methodName": "handleConfigChange"
756
+ }, {
757
+ "propName": "state",
758
+ "methodName": "handleStateChange"
759
+ }];
760
+ }
761
+ }