@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,10 @@
1
+ import { g as globalScripts, b as bootstrapLazy } from './index-CGXZllj2.js';
2
+ export { s as setNonce } from './index-CGXZllj2.js';
3
+
4
+ const defineCustomElements = async (win, options) => {
5
+ if (typeof window === 'undefined') return undefined;
6
+ await globalScripts();
7
+ return bootstrapLazy([["job-selector-demo",[[512,"job-selector-demo",{"afHideHeader":[4,"af-hide-header"],"afHidePreamble":[4,"af-hide-preamble"],"variant":[32],"version":[32],"required":[32],"allowFreeText":[32],"history":[32],"size":[32],"framework":[32],"codeInstallationMode":[32],"lastSingleSelection":[32],"lastMultiSelection":[32],"implementationCode":[32],"readmeMainContent":[32],"readmeCodeContent":[32],"availableYvVersions":[32],"latestYvDataVersion":[32],"latestVersion":[32],"latestDate":[32],"latestType":[32],"latestChanges":[32],"isTaxonomyLoading":[32]},[[0,"afJobSelected","handleSelection"]]]]],["geo-valjaren",[[513,"geo-valjaren",{"label":[513,"af-label"],"placeholder":[513,"af-placeholder"],"selectorState":[32]},[[0,"csInput","handleInput"],[0,"csFocus","handleFocus"],[0,"csRequestHistory","handleRequestHistory"],[0,"csSelect","handleSelect"],[0,"csBlur","handleBlur"],[0,"csClear","handleClear"],[0,"csClearHistory","handleCsClearHistory"],[0,"csEditSelection","handleEdit"]]]]],["neobrutal-search",[[513,"neobrutal-search",{"engine":[32],"results":[32],"inputValue":[32],"isLoading":[32],"error":[32],"selectedItem":[32],"isFlipped":[32]}]]],["core-selector",[[785,"core-selector",{"state":[16],"config":[16],"label":[1],"labelDescription":[1,"label-description"],"componentId":[1,"component-id"],"size":[513,"cs-size"],"afFocused":[4,"af-focused"],"activeIndex":[32],"isFocusedInternal":[32],"isNavigatingWithKeyboard":[32],"setFocus":[64]},null,{"afFocused":[{"handleAfFocusedChange":0}],"config":[{"handleConfigChange":0}],"state":[{"handleStateChange":0}]}]]],["digi-service-job-selector",[[593,"digi-service-job-selector",{"name":[513],"taxonomyUrl":[513,"af-taxonomy-url"],"placeholder":[513,"af-placeholder"],"label":[513,"af-label"],"disabled":[516],"enableMultiple":[516,"af-enable-multiple"],"showSearchIcon":[516,"af-show-search-icon"],"errorMessage":[513,"af-error-message"],"labelDescription":[513,"af-label-description"],"required":[516,"af-required"],"manualInput":[516,"af-manual-input"],"history":[516,"af-history"],"popular":[516,"af-popular"],"size":[513,"af-size"],"taxonomyData":[1040],"afFocused":[32],"state":[32],"activeErrorType":[32],"animatingItemId":[32],"updateData":[64],"setSelection":[64],"setFocus":[64],"validate":[64],"checkValidity":[64],"reportValidity":[64],"getValidity":[64],"getValidationMessage":[64]},[[0,"afJobValidationChange","handleFormValidationSync"],[8,"hashchange","handleHashFocus"],[0,"csInput","handleInput"],[0,"csSelect","handleCsSelect"],[0,"csClear","handleCsClear"],[0,"csClearHistory","handleCsClearHistory"],[0,"csRequestHistory","handleCsRequestHistory"],[0,"csLoadMore","handleCsLoadMore"],[0,"csRemoveItem","handleCsRemoveItem"],[0,"csFocus","handleCsFocus"],[0,"csBlur","handleCsBlur"],[0,"csEditSelection","handleCsEditSelection"]],{"required":[{"watchRequired":0}],"manualInput":[{"watchManualInput":0}],"history":[{"watchHistory":0}],"popular":[{"watchPopular":0}],"enableMultiple":[{"watchEnableMultiple":0}],"disabled":[{"watchDisabled":0}],"taxonomyData":[{"watchTaxonomyData":0}]}]]]], options);
8
+ };
9
+
10
+ export { defineCustomElements };
@@ -0,0 +1,169 @@
1
+ import { r as registerInstance, a as getElement, h } from './index-CGXZllj2.js';
2
+ import { T as TaxonomySearchEngine } from './search.engine-nZ7AcXba.js';
3
+ import { g as getRegisteredTaxonomy } from './taxonomy-registry-Dw0VR9Aw.js';
4
+ import './fuse-BPnhMTul.js';
5
+
6
+ const neobrutalSearchCss = () => `:host{display:block;font-family:'Courier New', Courier, monospace;--bg-color:#fff4e6;--primary:#ff00ff;--secondary:#00ffff;--text:#000;--border:4px solid #000;--shadow:8px 8px 0px #000}.neobrutal-container{background-color:var(--bg-color);padding:40px;border:var(--border);box-shadow:var(--shadow);max-width:600px;margin:20px auto;min-height:600px;position:relative;box-sizing:border-box;display:flex;flex-direction:column;transition:min-height 0.6s cubic-bezier(0.23, 1, 0.32, 1)}.flip-container{perspective:1000px;width:100%}.flipper{transition:0.6s;transform-style:preserve-3d;position:relative;width:100%}.flip-container.flipped .flipper{transform:rotateY(180deg)}.front,.back{backface-visibility:hidden;top:0;left:0;width:100%}.front{z-index:2;transform:rotateY(0deg);position:relative}.flip-container.flipped .front{position:absolute}.back{transform:rotateY(180deg);box-sizing:border-box;position:absolute}.flip-container.flipped .back{position:relative;z-index:3}h1.glitch{font-size:3rem;font-weight:900;text-transform:uppercase;margin-bottom:30px;background-color:var(--primary);color:var(--text);display:inline-block;padding:5px 15px;border:var(--border);box-shadow:4px 4px 0px #000}.input-wrapper{margin-bottom:50px;padding-right:10px;padding-bottom:10px}input{width:100%;padding:20px;font-size:1.5rem;font-family:inherit;font-weight:bold;border:var(--border);background:white;outline:none;text-transform:uppercase;box-shadow:8px 8px 0px #000;transition:all 0.1s;box-sizing:border-box}.status{font-size:1.5rem;font-weight:bold;background-color:yellow;border:var(--border);padding:10px;margin-bottom:20px;text-align:center}.fire-status{font-size:1.8rem;font-weight:900;background-color:#ff4500;color:#fff;border:var(--border);padding:15px;margin-bottom:15px;text-align:center;position:relative;box-shadow:10px 10px 0px #000;animation:fire-flicker 0.2s infinite alternate}@keyframes fire-flicker{0%{transform:scale(1) rotate(-0.5deg)}100%{transform:scale(1.01) rotate(0.5deg)}}.fire-emoji{font-size:2rem;display:inline-block;margin:0 10px}.raw-data-container{margin-top:10px;margin-bottom:30px;background:#000;border:2px solid #fff;padding:15px;text-align:left;box-shadow:5px 5px 0px #ff00ff}.raw-label{font-size:0.8rem;color:#0f0;margin-bottom:5px;font-weight:bold}.raw-output{font-family:'Courier New', Courier, monospace;font-size:0.8rem;color:#0f0;margin:0;white-space:pre-wrap;word-break:break-all}.flip-btn{position:absolute;top:10px;right:10px;background:#000;color:#fff;border:2px solid #fff;padding:5px 10px;font-weight:bold;cursor:pointer;font-family:'Courier New', Courier, monospace;z-index:10}.flip-btn:hover{background:#ff00ff;color:#000}.source-view{background:#0d1117 !important;color:#e6edf3 !important;border-color:#30363d !important;padding:30px !important;display:flex;flex-direction:column}.source-header{font-size:2rem;color:#ff00ff;margin-bottom:20px;text-shadow:2px 2px 0 #000}.code-scroll-container{flex:1;background:#161b22;border:1px solid #30363d;border-radius:6px;padding:10px}.code-block{margin-bottom:25px;text-align:left}.code-label{background:#238636;color:#fff;display:inline-block;padding:4px 8px;font-weight:bold;font-size:0.8rem;border-radius:4px 4px 0 0}pre{background:#0d1117;margin:0;padding:10px;border:1px solid #30363d}pre code{font-family:'Courier New', Courier, monospace;font-size:0.85rem;line-height:1.4;background:transparent !important;color:#e6edf3}.result-card{background-color:white;border:var(--border);box-shadow:5px 5px 0px #000;padding:15px;transition:all 0.1s;cursor:pointer}.result-card:hover{transform:translate(2px, 2px);box-shadow:3px 3px 0px #000;background-color:var(--secondary)}.card-header{display:flex;justify-content:space-between;margin-bottom:10px;border-bottom:2px solid #000;padding-bottom:5px}.type-badge{background-color:yellow;padding:2px 8px;font-weight:bold;border:2px solid #000}.score-badge{background-color:lime;padding:2px 8px;font-weight:bold;border:2px solid #000}.label{font-size:1.2rem;font-weight:800}`;
7
+
8
+ // VIKTIGT: Dessa strängar representerar den FAKTISKA källkoden som användaren ser.
9
+ const SOURCE_CODE_JS = `import { Component, h, State, Element } from '@stencil/core';
10
+ import { TaxonomySearchEngine } from '../job-selector/logic/search.engine';
11
+ import { getRegisteredTaxonomy } from '../job-selector/taxonomy-registry';
12
+
13
+ @Component({ tag: 'neobrutal-search', styleUrl: 'neobrutal-search.css', shadow: true })
14
+ export class NeobrutalSearch {
15
+ @Element() el!: HTMLElement;
16
+ @State() engine: TaxonomySearchEngine | null = null;
17
+ @State() results: any[] = [];
18
+ @State() inputValue: string = '';
19
+ @State() isLoading: boolean = true;
20
+ @State() error: string = '';
21
+ @State() selectedItem: any | null = null;
22
+ @State() isFlipped: boolean = false;
23
+
24
+ async componentWillLoad() {
25
+ try {
26
+ const taxonomyData = getRegisteredTaxonomy();
27
+ this.engine = new TaxonomySearchEngine(taxonomyData);
28
+ this.isLoading = false;
29
+ } catch (err) {
30
+ this.error = 'DATA FAILURE';
31
+ this.isLoading = false;
32
+ }
33
+ }
34
+
35
+ componentDidUpdate() {
36
+ if (this.isFlipped) this.highlightCode();
37
+ }
38
+
39
+ highlightCode() {
40
+ const hljs = (window as any).hljs;
41
+ if (hljs && this.el?.shadowRoot) {
42
+ const blocks = this.el.shadowRoot.querySelectorAll('pre code');
43
+ blocks.forEach((block) => hljs.highlightElement(block));
44
+ }
45
+ }
46
+
47
+ handleInput(event: Event) {
48
+ const query = (event.target as HTMLInputElement).value;
49
+ this.inputValue = query;
50
+ this.selectedItem = null;
51
+
52
+ if (!this.engine || query.length < 2) {
53
+ this.results = [];
54
+ return;
55
+ }
56
+
57
+ this.results = this.engine.search(query, 3);
58
+ }
59
+
60
+ handleSelect(item: any) {
61
+ this.selectedItem = item;
62
+ this.results = [];
63
+ this.inputValue = item.label;
64
+ }
65
+
66
+ toggleFlip() {
67
+ this.isFlipped = !this.isFlipped;
68
+ if (this.isFlipped) setTimeout(() => this.highlightCode(), 100);
69
+ }
70
+
71
+ render() {
72
+ return (
73
+ <div class="neobrutal-container">
74
+ {/* ... UI structure ... */}
75
+ </div>
76
+ );
77
+ }
78
+ }`;
79
+ const SOURCE_CODE_CSS = `.neobrutal-container {
80
+ background-color: #fff4e6;
81
+ padding: 40px;
82
+ border: 4px solid #000;
83
+ box-shadow: 8px 8px 0px #000;
84
+ font-family: 'Courier New', Courier, monospace;
85
+ }
86
+
87
+ .fire-status {
88
+ background-color: #ff4500;
89
+ animation: fire-flicker 0.2s infinite alternate;
90
+ }
91
+
92
+ .raw-data-container {
93
+ background: #000;
94
+ color: #0f0;
95
+ padding: 15px;
96
+ box-shadow: 5px 5px 0px #ff00ff;
97
+ }`;
98
+ const NeobrutalSearch = class {
99
+ constructor(hostRef) {
100
+ registerInstance(this, hostRef);
101
+ }
102
+ get el() { return getElement(this); }
103
+ engine = null;
104
+ results = [];
105
+ inputValue = '';
106
+ isLoading = true;
107
+ error = '';
108
+ selectedItem = null;
109
+ isFlipped = false;
110
+ async componentWillLoad() {
111
+ try {
112
+ console.log('[NeobrutalSearch] Initializing...');
113
+ const taxonomyData = getRegisteredTaxonomy();
114
+ this.engine = new TaxonomySearchEngine(taxonomyData);
115
+ this.isLoading = false;
116
+ }
117
+ catch (err) {
118
+ console.error('[NeobrutalSearch] Init failed:', err);
119
+ this.error = 'DATA FAILURE';
120
+ this.isLoading = false;
121
+ }
122
+ }
123
+ componentDidUpdate() {
124
+ if (this.isFlipped) {
125
+ this.highlightCode();
126
+ }
127
+ }
128
+ highlightCode() {
129
+ const hljs = window.hljs;
130
+ if (hljs && this.el?.shadowRoot) {
131
+ const blocks = this.el.shadowRoot.querySelectorAll('pre code');
132
+ blocks.forEach((block) => {
133
+ hljs.highlightElement(block);
134
+ });
135
+ }
136
+ }
137
+ handleInput(event) {
138
+ const query = event.target.value;
139
+ this.inputValue = query;
140
+ this.selectedItem = null;
141
+ if (!this.engine || query.length < 2) {
142
+ this.results = [];
143
+ return;
144
+ }
145
+ const searchResults = this.engine.search(query, 3);
146
+ this.results = searchResults;
147
+ }
148
+ handleSelect(item) {
149
+ this.selectedItem = item;
150
+ this.results = [];
151
+ this.inputValue = item.label;
152
+ }
153
+ toggleFlip() {
154
+ this.isFlipped = !this.isFlipped;
155
+ if (this.isFlipped) {
156
+ setTimeout(() => this.highlightCode(), 100);
157
+ }
158
+ }
159
+ render() {
160
+ return (h("div", { key: '032a555551974ef504c703419db83581652a5083', class: `flip-container ${this.isFlipped ? 'flipped' : ''}` }, h("link", { key: '8af8fac02cd7b8ac1112c08c51e32be3845b7647', rel: "stylesheet", href: "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/atom-one-dark.min.css" }), h("div", { key: '5f63de826af07f1139126a64fb205f65e14f5060', class: "flipper" }, h("div", { key: 'a7878c0a9db257884cedab104366639d2edb506b', class: "front neobrutal-container" }, h("button", { key: '6d65c76d93c717e7c056f0e2da60d2f825efd781', class: "flip-btn", onClick: () => this.toggleFlip() }, "FLIP_ME \uD83D\uDD04"), h("h1", { key: '56981f916be340a827e376cb713e6b6fb5e097bb', class: "glitch", "data-text": "YRKE_S\u00D6K" }, "YRKE_S\u00D6K"), h("div", { key: 'ba3c2e76b631e0d48c5f2ecee1095a999393822e', class: "input-wrapper" }, h("input", { key: '75a8e4553a2e77992efa9591a64fba83c3dbe3ea', type: "text", placeholder: "VAD VILL DU BLI?", onInput: (e) => this.handleInput(e), value: this.inputValue, disabled: this.isLoading })), this.isLoading && h("div", { key: '46ec1526451477d7ecf90ffe46dd964986096903', class: "status" }, "LOADING_DATA..."), this.error && h("div", { key: '01bc30a4d4e17e493d8deb08c7e5b71da9c23df7', class: "status error" }, this.error), this.selectedItem && (h("div", { key: '0e6d79bc76dbecd7a79bbf0b00246acdef45eda3' }, h("div", { key: 'f942688584b54c4b43679903549781fbe346e154', class: "fire-status" }, h("span", { key: 'efde5818a4449b710d22e43e9c8148f380f89f3d', class: "fire-emoji" }, "\uD83D\uDD25 \uD83D\uDD25 \uD83D\uDD25"), "HETT VAL: ", this.selectedItem.label.toUpperCase(), "!", h("span", { key: '7764fa1ed1fd7b0541f5ad3a49e3135f4a61edfe', class: "fire-emoji" }, "\uD83D\uDD25 \uD83D\uDD25 \uD83D\uDD25")), h("div", { key: '415e1ee36443cc50cddb0f87e8750b34084fd485', class: "raw-data-container" }, h("div", { key: 'ed730d664599ecac4a89ccdf597833ea3f9fb47a', class: "raw-label" }, "RAW_JSON_DATA:"), h("pre", { key: '0921ef8ebccb5add5e9d379e31872b2798b399f8', class: "raw-output" }, JSON.stringify(this.selectedItem, null, 2))))), h("div", { key: '9af42c5d7cb9d901b6909e8ea4260da7dfee09fd', class: "results-container" }, this.results.map(result => {
161
+ const metadata = result?.metadata || {};
162
+ const original = metadata?.originalResult;
163
+ return (h("div", { class: "result-card", onClick: () => this.handleSelect(result) }, h("div", { class: "card-header" }, h("span", { class: "type-badge" }, original?.category === 'job-title' ? 'YRK' : 'GRP'), h("span", { class: "score-badge" }, "SCR: ", Math.round((metadata?.score || 0) * 10))), h("div", { class: "card-body" }, h("div", { class: "label" }, result.displayLabel || result.label))));
164
+ }))), h("div", { key: '349e56ba67845d6b63ab8616823c5909452ed593', class: "back neobrutal-container source-view" }, h("button", { key: '1de742d808b48a65bb266ea19a83ccf567a76ac6', class: "flip-btn", onClick: () => this.toggleFlip() }, "BACK \uD83D\uDD19"), h("h1", { key: 'b2400cbd8d36417df1cbb3c487fa7e3d824f4a02', class: "source-header" }, "FULL_SOURCE_CODE"), h("p", { key: '59c3e040a7177810b53200426da4543f99c7ca73', class: "source-desc" }, "Exakt den koden du ser, inga fejk snippets h\u00E4r inte:"), h("div", { key: '8ed08d5d1d79ec49c6e6bb6a5be504ddd6ed84c2', class: "code-scroll-container" }, h("div", { key: '5018114c97191ccf174ae197d56917f35848dcef', class: "code-block" }, h("div", { key: '466523ef6acb91d435248d5d399fef5a79bc2e6f', class: "code-label" }, "neobrutal-search.tsx"), h("pre", { key: '2a3ad662ac5a0346131aaa13dfd9544169338e48' }, h("code", { key: '76b3240d79589217899d74f6727b64d1c8495d7a', class: "language-typescript" }, SOURCE_CODE_JS))), h("div", { key: '2990f5d3da12a8c8ffeccbb4f786945b7eb70483', class: "code-block" }, h("div", { key: '5b957f082c75f5de3f5bd766c9fd135e1ee06471', class: "code-label" }, "neobrutal-search.css"), h("pre", { key: '8a2c509035923387c2dac463b72feda6c2c41ba2' }, h("code", { key: '581e2ccebcef975ac6dd79059da4c82cb0ffe176', class: "language-css" }, SOURCE_CODE_CSS))))))));
165
+ }
166
+ };
167
+ NeobrutalSearch.style = neobrutalSearchCss();
168
+
169
+ export { NeobrutalSearch as neobrutal_search };
@@ -0,0 +1,479 @@
1
+ import { e as entry_default } from './fuse-BPnhMTul.js';
2
+ import { l as log } from './taxonomy-registry-Dw0VR9Aw.js';
3
+
4
+ // Minimum number of characters required to trigger search
5
+ const MIN_INPUT_LENGTH = 1;
6
+ // Debounce time for search input (ms)
7
+ const DEBOUNCE_TIME = 100; // ms - Återställt till 250 baserat på sok-box.tsx initialt
8
+ // Default maximum number of results to display
9
+ const MAX_RESULTS = 10;
10
+ // Configuration for Fuse.js
11
+ const FUSE_OPTIONS = {
12
+ keys: ['preferred_label'], // Ändrat från 'label' till 'preferred_label' för att matcha datastrukturen
13
+ includeScore: true,
14
+ ignoreDiacritics: true, // Lägg till för att matcha t.ex. vard -> vård
15
+ ignoreFieldNorm: true, // Lägg till för att ignorera fältlängd vid poängsättning
16
+ threshold: 0.6, // Behåll 0.6
17
+ minMatchCharLength: MIN_INPUT_LENGTH, // Refererar till konstant ovan
18
+ ignoreLocation: true, // Match anywhere in the string
19
+ distance: 100, // Allow matches further apart
20
+ };
21
+ // UI Text Strings
22
+ const PLACEHOLDER_TEXT = "T.ex. frisör, vårdbiträde, snickare"; // Uppdaterad standardplaceholder enligt Figma-design
23
+
24
+ const LabelFormatter = {
25
+ format: (label, query, occupationLabel) => {
26
+ // 1. Highlight the main label based on query
27
+ const labelSegments = highlightText(label, query);
28
+ // 2. Append occupation label if it exists (the "metadata" part)
29
+ if (occupationLabel) {
30
+ return [
31
+ ...labelSegments,
32
+ { text: ' ', isMatch: false },
33
+ { text: `(${occupationLabel})`, isMetadata: true }
34
+ ];
35
+ }
36
+ return labelSegments;
37
+ }
38
+ };
39
+ function calculateEditDistance$1(a, b) {
40
+ const m = a.length;
41
+ const n = b.length;
42
+ const dp = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));
43
+ for (let i = 0; i <= m; i++)
44
+ dp[i][0] = i;
45
+ for (let j = 0; j <= n; j++)
46
+ dp[0][j] = j;
47
+ for (let i = 1; i <= m; i++) {
48
+ for (let j = 1; j <= n; j++) {
49
+ dp[i][j] = a[i - 1] === b[j - 1]
50
+ ? dp[i - 1][j - 1]
51
+ : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
52
+ }
53
+ }
54
+ return dp[m][n];
55
+ }
56
+ function findBestFuzzySubstring$1(text, qToken) {
57
+ const lowerText = text.toLowerCase();
58
+ const targetLen = qToken.length;
59
+ let bestDist = 99;
60
+ let bestStart = -1;
61
+ let bestLen = 0;
62
+ const minLen = Math.max(3, targetLen - 2);
63
+ const maxLen = Math.min(lowerText.length, targetLen + 2);
64
+ for (let start = 0; start <= lowerText.length - minLen; start++) {
65
+ for (let len = minLen; len <= maxLen && start + len <= lowerText.length; len++) {
66
+ const sub = lowerText.slice(start, start + len);
67
+ const dist = calculateEditDistance$1(qToken, sub);
68
+ if (dist < bestDist) {
69
+ bestDist = dist;
70
+ bestStart = start;
71
+ bestLen = len;
72
+ }
73
+ }
74
+ }
75
+ const maxAllowedDist = Math.max(2, Math.floor(targetLen * 0.25));
76
+ if (bestDist <= maxAllowedDist && bestStart !== -1) {
77
+ return { start: bestStart, length: bestLen };
78
+ }
79
+ return null;
80
+ }
81
+ /**
82
+ * Highlights matches in text based on query.
83
+ * Supports multi-word queries.
84
+ */
85
+ function highlightText(text, query) {
86
+ if (!text)
87
+ return [];
88
+ if (!query || query.trim().length === 0) {
89
+ return [{ text, isMatch: false }];
90
+ }
91
+ const lowerText = text.toLowerCase();
92
+ const tokens = query.toLowerCase().split(/\s+/).filter(t => t.length > 0);
93
+ // Set of indices in the original text that should be highlighted
94
+ const highlightedIndices = new Set();
95
+ tokens.forEach(token => {
96
+ let startIndex = 0;
97
+ while ((startIndex = lowerText.indexOf(token, startIndex)) !== -1) {
98
+ for (let i = 0; i < token.length; i++) {
99
+ highlightedIndices.add(startIndex + i);
100
+ }
101
+ startIndex += token.length;
102
+ }
103
+ });
104
+ if (highlightedIndices.size === 0) {
105
+ // Fuzzy highlight fallback: Hitta bästa matchande delsträng i sammansatta ord eller felstavningar
106
+ tokens.forEach(qToken => {
107
+ const match = findBestFuzzySubstring$1(text, qToken);
108
+ if (match) {
109
+ for (let i = 0; i < match.length; i++) {
110
+ highlightedIndices.add(match.start + i);
111
+ }
112
+ }
113
+ });
114
+ }
115
+ if (highlightedIndices.size === 0) {
116
+ return [{ text, isMatch: false }];
117
+ }
118
+ const segments = [];
119
+ let currentSegmentText = '';
120
+ let currentIsMatch = highlightedIndices.has(0);
121
+ for (let i = 0; i < text.length; i++) {
122
+ const isMatch = highlightedIndices.has(i);
123
+ if (isMatch !== currentIsMatch) {
124
+ // Push previous segment
125
+ if (currentSegmentText.length > 0) {
126
+ segments.push({ text: currentSegmentText, isMatch: currentIsMatch });
127
+ }
128
+ // Start new segment
129
+ currentSegmentText = text[i];
130
+ currentIsMatch = isMatch;
131
+ }
132
+ else {
133
+ currentSegmentText += text[i];
134
+ }
135
+ }
136
+ // Push the last segment
137
+ if (currentSegmentText.length > 0) {
138
+ segments.push({ text: currentSegmentText, isMatch: currentIsMatch });
139
+ }
140
+ return segments;
141
+ }
142
+
143
+ const MAX_WEAK_FUZZY_RESULTS = 3;
144
+ const MIN_FUZZY_SCORE = 0.4;
145
+ const MAX_FUZZY_SCORE = 0.84;
146
+ {
147
+ log.setLevel(log.levels.DEBUG); // Set log level to DEBUG for development/testing
148
+ }
149
+ const normalizeForComparison = (text) => {
150
+ if (!text) {
151
+ return '';
152
+ }
153
+ const normalized = text.toLowerCase().trim();
154
+ return normalized;
155
+ };
156
+ function formatDisplayLabel(item) {
157
+ if (item.occupation_name_preferred_label) {
158
+ return `${item.preferred_label || ''} (${item.occupation_name_preferred_label})`;
159
+ }
160
+ return item.preferred_label || '';
161
+ }
162
+ function sortResultsStrict(results) {
163
+ return results.sort((a, b) => {
164
+ const scoreA = a.score ?? 0;
165
+ const scoreB = b.score ?? 0;
166
+ if (scoreA !== scoreB) {
167
+ return scoreB - scoreA;
168
+ }
169
+ const weightA = a.weight ?? 0;
170
+ const weightB = b.weight ?? 0;
171
+ if (weightA !== weightB) {
172
+ // Buggen är fixad här
173
+ return weightB - weightA;
174
+ }
175
+ return a.displayLabel.localeCompare(b.displayLabel, 'sv');
176
+ });
177
+ }
178
+ function segmentsToHtml(segments) {
179
+ return segments.map(seg => {
180
+ if (seg.isMatch) {
181
+ return `<strong>${seg.text}</strong>`;
182
+ }
183
+ if (seg.isMetadata) {
184
+ return `<span class="occupation-variant-label">${seg.text}</span>`;
185
+ }
186
+ return seg.text;
187
+ }).join('');
188
+ }
189
+ // Keep export for controller compatibility (it was used there)
190
+ // But implement using new logic or just re-export if we want to keep it simple?
191
+ // The controller passes HTML to it.
192
+ // Actually, `styleParentheticalText` took a string (HTML) and did regex replacement.
193
+ // If the controller uses it on `item.displayLabel` (which is plain text usually, or mapped),
194
+ // the controller does: `const historyItem = { ...item, highlightedLabel: styleParentheticalText(item.displayLabel) };`
195
+ // `displayLabel` for "Frontend (System)" is "Frontend (System)".
196
+ // If we run that through `segmentsToHtml(LabelFormatter.format(label, ''))`, we get the same result!
197
+ // So let's re-implement `styleParentheticalText` using `LabelFormatter`.
198
+ const styleParentheticalText = (text) => {
199
+ if (!text)
200
+ return '';
201
+ return text.replace(/ (\([^)]+\))/g, ' <span class="occupation-variant-label">$1</span>');
202
+ };
203
+ function getDirectScore(normalizedLabel, normalizedQuery, searchTokens) {
204
+ if (normalizedLabel === normalizedQuery) {
205
+ return 1.0;
206
+ }
207
+ if (searchTokens.length > 1) {
208
+ return searchTokens.every(token => normalizedLabel.includes(token)) ? 0.98 : null;
209
+ }
210
+ if (normalizedLabel.startsWith(normalizedQuery)) {
211
+ return 0.99;
212
+ }
213
+ if (normalizedLabel.includes(normalizedQuery)) {
214
+ return 0.95;
215
+ }
216
+ return null;
217
+ }
218
+ function calculateEditDistance(a, b) {
219
+ const m = a.length;
220
+ const n = b.length;
221
+ const dp = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));
222
+ for (let i = 0; i <= m; i++)
223
+ dp[i][0] = i;
224
+ for (let j = 0; j <= n; j++)
225
+ dp[0][j] = j;
226
+ for (let i = 1; i <= m; i++) {
227
+ for (let j = 1; j <= n; j++) {
228
+ dp[i][j] = a[i - 1] === b[j - 1]
229
+ ? dp[i - 1][j - 1]
230
+ : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
231
+ }
232
+ }
233
+ return dp[m][n];
234
+ }
235
+ function findBestFuzzySubstring(text, qToken) {
236
+ const lowerText = text.toLowerCase();
237
+ const targetLen = qToken.length;
238
+ let bestDist = 99;
239
+ const minLen = Math.max(3, targetLen - 2);
240
+ const maxLen = Math.min(lowerText.length, targetLen + 2);
241
+ for (let start = 0; start <= lowerText.length - minLen; start++) {
242
+ for (let len = minLen; len <= maxLen && start + len <= lowerText.length; len++) {
243
+ const sub = lowerText.slice(start, start + len);
244
+ const dist = calculateEditDistance(qToken, sub);
245
+ if (dist < bestDist) {
246
+ bestDist = dist;
247
+ }
248
+ }
249
+ }
250
+ const maxAllowedDist = Math.max(2, Math.floor(targetLen * 0.25));
251
+ return bestDist <= maxAllowedDist ? bestDist : null;
252
+ }
253
+ function isSingleWordOrCompoundRoot(query, label) {
254
+ const normQ = query.toLowerCase().trim();
255
+ const normL = label.toLowerCase().trim();
256
+ if (normL.includes(' ')) {
257
+ const dist = calculateEditDistance(normQ, normL);
258
+ return dist <= Math.max(2, Math.floor(normQ.length * 0.25)) && Math.abs(normQ.length - normL.length) <= 2;
259
+ }
260
+ const subDist = findBestFuzzySubstring(normL, normQ);
261
+ return subDist !== null;
262
+ }
263
+ function createSearchResult(item, query, score) {
264
+ const displayLabel = formatDisplayLabel(item);
265
+ const displaySegments = LabelFormatter.format(item.preferred_label || '', query, item.occupation_name_preferred_label);
266
+ return {
267
+ id: item.id,
268
+ type: item.type,
269
+ preferred_label: item.preferred_label || '',
270
+ rawLabel: item.preferred_label || '',
271
+ displayLabel,
272
+ highlightedLabel: segmentsToHtml(displaySegments),
273
+ displaySegments,
274
+ weight: item.weight ?? 0,
275
+ score,
276
+ occupationId: item.occupation_name_id,
277
+ occupationLabel: item.occupation_name_preferred_label,
278
+ ssyk_level_4_id: item.ssyk_level_4_id,
279
+ ssyk_code_2012: item.ssyk_code_2012,
280
+ };
281
+ }
282
+ function searchConcepts(query, items, fuseInstance, maxResults) {
283
+ if (!fuseInstance) {
284
+ return [];
285
+ }
286
+ if (!items || !Array.isArray(items)) {
287
+ log.warn('[searchConcepts] Ogiltig items array.');
288
+ return [];
289
+ }
290
+ if (!query || query.length < MIN_INPUT_LENGTH) {
291
+ return [];
292
+ }
293
+ const normalizedQuery = normalizeForComparison(query);
294
+ const searchTokens = normalizedQuery.split(' ').filter(t => t.length > 0);
295
+ const directResults = [];
296
+ const processedIds = new Set();
297
+ for (const item of items) {
298
+ const normalizedLabel = normalizeForComparison(item.preferred_label);
299
+ const score = getDirectScore(normalizedLabel, normalizedQuery, searchTokens);
300
+ if (score !== null) {
301
+ directResults.push(createSearchResult(item, query, score));
302
+ processedIds.add(item.id);
303
+ }
304
+ }
305
+ if (directResults.length > 0) {
306
+ return sortResultsStrict(directResults).slice(0, maxResults);
307
+ }
308
+ // Fuzzy är ren fallback när inga direkta träffar finns.
309
+ if (fuseInstance) {
310
+ const fuseSearchOutput = fuseInstance.search(normalizedQuery);
311
+ if (fuseSearchOutput.length === 0) {
312
+ return [];
313
+ }
314
+ const bestRawScore = fuseSearchOutput[0].score ?? 1.0;
315
+ const candidateResults = [];
316
+ let hasStrongRootMatch = false;
317
+ for (const fr of fuseSearchOutput) {
318
+ if (processedIds.has(fr.item.id)) {
319
+ continue;
320
+ }
321
+ const rawScore = fr.score ?? 1.0;
322
+ const baseFuzzyScore = 1 - rawScore;
323
+ if (baseFuzzyScore < MIN_FUZZY_SCORE) {
324
+ continue;
325
+ }
326
+ // Strikt gap-filter: Tillåt aldrig träffar som har mer än 0.12 sämre råpoäng än bästa träffen
327
+ if (rawScore > bestRawScore + 0.12) {
328
+ continue;
329
+ }
330
+ const label = normalizeForComparison(fr.item.preferred_label);
331
+ const weight = fr.item.weight ?? 0;
332
+ // Hitta om etiketten innehåller en rotterm eller sammansatt del som matchar sökningen
333
+ const isRootMatch = isSingleWordOrCompoundRoot(normalizedQuery, label);
334
+ if (isRootMatch && rawScore <= 0.25) {
335
+ hasStrongRootMatch = true;
336
+ }
337
+ let score = baseFuzzyScore * 0.70 + (weight * 0.10);
338
+ if (isRootMatch) {
339
+ score += 0.12;
340
+ }
341
+ const boundedScore = Math.min(MAX_FUZZY_SCORE, Math.max(MIN_FUZZY_SCORE, score));
342
+ candidateResults.push(createSearchResult(fr.item, query, boundedScore));
343
+ processedIds.add(fr.item.id);
344
+ }
345
+ const sortedFuzzy = sortResultsStrict(candidateResults);
346
+ if (sortedFuzzy.length === 0) {
347
+ return [];
348
+ }
349
+ // Dynamiskt maxantal vid fuzzy-sökningar:
350
+ // - Stark rotmatchning (t.ex. injenjör, barlnmorska): Visa upp till 5 relevanta förslag så att fritextfältet syns utan att skrolla.
351
+ // - Svag/osäker matchning (t.ex. böla fölkja, pensionär): Visa MAX 3 träffar.
352
+ const limit = hasStrongRootMatch ? Math.min(5, maxResults) : Math.min(MAX_WEAK_FUZZY_RESULTS, maxResults);
353
+ return sortedFuzzy.slice(0, limit);
354
+ }
355
+ return [];
356
+ }
357
+
358
+ const TaxonomyAdapter = {
359
+ /** Maps a raw TaxonomyItem to a GenericItem for the CoreSelector */
360
+ toGenericItem(item) {
361
+ return {
362
+ id: item.id,
363
+ label: item.preferred_label || '',
364
+ description: item.occupation_name_preferred_label,
365
+ metadata: {
366
+ original: item,
367
+ type: item.type,
368
+ ssyk_level_4_id: item.ssyk_level_4_id,
369
+ weight: item.weight
370
+ }
371
+ };
372
+ },
373
+ /** Maps a SearchResult (from our engine) to a GenericItem */
374
+ searchResultToGenericItem(result, query) {
375
+ const segments = LabelFormatter.format(result.preferred_label || '', query, result.occupation_name_preferred_label);
376
+ return {
377
+ id: result.id,
378
+ label: result.preferred_label || '',
379
+ displaySegments: segments,
380
+ highlightedLabel: segmentsToHtml(segments),
381
+ metadata: {
382
+ original: result,
383
+ ssyk_level_4_id: result.ssyk_level_4_id,
384
+ weight: result.weight
385
+ }
386
+ };
387
+ },
388
+ /** Maps a GenericItem back to our internal SearchResult format */
389
+ fromGenericItem(item) {
390
+ return {
391
+ id: item.id,
392
+ preferred_label: item.label,
393
+ weight: item.metadata?.weight,
394
+ ...item.metadata?.original
395
+ };
396
+ },
397
+ /** Maps an internal item to the public event format */
398
+ toPublicSelection(item) {
399
+ const id = item.id || '';
400
+ const preferredLabel = item.preferred_label || item.rawLabel || '';
401
+ if (!id) {
402
+ return {
403
+ type: 'manual-input',
404
+ id: null,
405
+ preferred_label: preferredLabel,
406
+ };
407
+ }
408
+ if (item.type !== 'job-title' && item.type !== 'occupation-name') {
409
+ throw new Error(`Ogiltig intern yrkestyp för ${id}: ${item.type}`);
410
+ }
411
+ const selection = {
412
+ type: item.type,
413
+ id,
414
+ preferred_label: preferredLabel,
415
+ };
416
+ if (item.ssyk_code_2012) {
417
+ selection.ssyk_code_2012 = item.ssyk_code_2012;
418
+ }
419
+ const occupationId = item.occupation_name_id || item.occupationId;
420
+ const occupationLabel = item.occupation_name_preferred_label || item.occupationLabel;
421
+ if (item.type === 'job-title' && occupationId && occupationLabel) {
422
+ selection.related = {
423
+ type: 'occupation-name',
424
+ id: occupationId,
425
+ preferred_label: occupationLabel,
426
+ };
427
+ }
428
+ return selection;
429
+ }
430
+ };
431
+
432
+ class TaxonomySearchEngine {
433
+ fuseInstance = null;
434
+ items = [];
435
+ constructor(data) {
436
+ this.items = data;
437
+ this.fuseInstance = new entry_default(data, FUSE_OPTIONS);
438
+ }
439
+ /**
440
+ * Public API: Performs a search and returns clean, official domain objects.
441
+ * This is what external consumers (headless) should use.
442
+ */
443
+ search(query, maxResults = 10) {
444
+ if (!this.fuseInstance)
445
+ return [];
446
+ const results = searchConcepts(query, this.items, this.fuseInstance, maxResults);
447
+ // Map directly to public selection objects
448
+ return results.map(result => TaxonomyAdapter.toPublicSelection(result));
449
+ }
450
+ /**
451
+ * Internal API: Performs a search and returns GenericItems for the CoreSelector UI ("Bucky").
452
+ * Includes highlighting, grouping and internal metadata.
453
+ */
454
+ searchAsGeneric(query, maxResults = 10) {
455
+ if (!this.fuseInstance)
456
+ return [];
457
+ // Use the existing robust search function
458
+ const results = searchConcepts(query, this.items, this.fuseInstance, maxResults);
459
+ // Adapt SearchResult -> GenericItem
460
+ return results.map(result => ({
461
+ id: result.id,
462
+ label: result.displayLabel, // Use the formatted label (e.g. "Nurse (Healthcare)")
463
+ description: result.occupationLabel,
464
+ group: result.type === 'job-title' ? 'Yrke' : 'Yrkesgrupp',
465
+ metadata: {
466
+ originalResult: result, // Keep full original result for consumers
467
+ highlightedLabel: result.highlightedLabel,
468
+ score: result.score,
469
+ weight: result.weight
470
+ }
471
+ }));
472
+ }
473
+ updateData(newData) {
474
+ this.items = newData;
475
+ this.fuseInstance = new entry_default(newData, FUSE_OPTIONS);
476
+ }
477
+ }
478
+
479
+ export { DEBOUNCE_TIME as D, LabelFormatter as L, MAX_RESULTS as M, PLACEHOLDER_TEXT as P, TaxonomySearchEngine as T, TaxonomyAdapter as a, MIN_INPUT_LENGTH as b, styleParentheticalText as c, segmentsToHtml as s };