fds-vue-core 2.0.88 → 2.1.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 (331) hide show
  1. package/README.md +1 -0
  2. package/configs/eslint.config.base.js +262 -0
  3. package/configs/prettier.config.js +13 -0
  4. package/configs/tsconfig.base.json +17 -0
  5. package/configs/vscode-settings.json +74 -0
  6. package/dist/fds-vue-core.cjs.js +5367 -5374
  7. package/dist/fds-vue-core.cjs.js.map +1 -1
  8. package/dist/fds-vue-core.es.js +5368 -5375
  9. package/dist/fds-vue-core.es.js.map +1 -1
  10. package/dist/global-components.d.ts +36 -36
  11. package/dist/index.d.ts +2 -80
  12. package/dist/slot-styles.css +1 -1
  13. package/dist/tokens.css +0 -1
  14. package/package.json +15 -6
  15. package/src/.DS_Store +0 -0
  16. package/src/App.vue +133 -0
  17. package/src/apply.css +60 -0
  18. package/src/assets/icons.ts +517 -0
  19. package/src/components/Blocks/FdsBlockAlert/FdsBlockAlert.stories.ts +94 -0
  20. package/src/components/Blocks/FdsBlockAlert/FdsBlockAlert.vue +112 -0
  21. package/src/components/Blocks/FdsBlockAlert/types.ts +12 -0
  22. package/src/components/Blocks/FdsBlockContent/FdsBlockContent.stories.ts +110 -0
  23. package/src/components/Blocks/FdsBlockContent/FdsBlockContent.vue +66 -0
  24. package/src/components/Blocks/FdsBlockContent/types.ts +6 -0
  25. package/src/components/Blocks/FdsBlockExpander/FdsBlockExpander.stories.ts +123 -0
  26. package/src/components/Blocks/FdsBlockExpander/FdsBlockExpander.vue +87 -0
  27. package/src/components/Blocks/FdsBlockExpander/types.ts +8 -0
  28. package/src/components/Blocks/FdsBlockInfo/FdsBlockInfo.stories.ts +110 -0
  29. package/src/components/Blocks/FdsBlockInfo/FdsBlockInfo.vue +98 -0
  30. package/src/components/Blocks/FdsBlockInfo/types.ts +8 -0
  31. package/src/components/Blocks/FdsBlockLink/FdsBlockLink.css +9 -0
  32. package/src/components/Blocks/FdsBlockLink/FdsBlockLink.stories.ts +179 -0
  33. package/src/components/Blocks/FdsBlockLink/FdsBlockLink.vue +149 -0
  34. package/src/components/Blocks/FdsBlockLink/types.ts +14 -0
  35. package/src/components/Buttons/ButtonBaseProps.ts +18 -0
  36. package/src/components/Buttons/FdsButtonCopy/FdsButtonCopy.stories.ts +53 -0
  37. package/src/components/Buttons/FdsButtonCopy/FdsButtonCopy.vue +87 -0
  38. package/src/components/Buttons/FdsButtonCopy/types.ts +8 -0
  39. package/src/components/Buttons/FdsButtonDownload/FdsButtonDownload.stories.ts +111 -0
  40. package/src/components/Buttons/FdsButtonDownload/FdsButtonDownload.vue +187 -0
  41. package/src/components/Buttons/FdsButtonIcon/FdsButtonIcon.stories.ts +55 -0
  42. package/src/components/Buttons/FdsButtonIcon/FdsButtonIcon.vue +57 -0
  43. package/src/components/Buttons/FdsButtonIcon/types.ts +12 -0
  44. package/src/components/Buttons/FdsButtonMinor/FdsButtonMinor.stories.ts +68 -0
  45. package/src/components/Buttons/FdsButtonMinor/FdsButtonMinor.vue +126 -0
  46. package/src/components/Buttons/FdsButtonPrimary/FdsButtonPrimary.stories.ts +86 -0
  47. package/src/components/Buttons/FdsButtonPrimary/FdsButtonPrimary.vue +107 -0
  48. package/src/components/Buttons/FdsButtonSecondary/FdsButtonSecondary.stories.ts +68 -0
  49. package/src/components/Buttons/FdsButtonSecondary/FdsButtonSecondary.vue +107 -0
  50. package/src/components/FdsIcon/FdsIcon.stories.ts +69 -0
  51. package/src/components/FdsIcon/FdsIcon.vue +34 -0
  52. package/src/components/FdsIcon/types.ts +9 -0
  53. package/src/components/FdsModal/FdsModal.stories.ts +241 -0
  54. package/src/components/FdsModal/FdsModal.vue +261 -0
  55. package/src/components/FdsModal/types.ts +12 -0
  56. package/src/components/FdsPagination/FdsPagination.stories.ts +109 -0
  57. package/src/components/FdsPagination/FdsPagination.vue +193 -0
  58. package/src/components/FdsPagination/types.ts +6 -0
  59. package/src/components/FdsSearchSelect/FdsSearchSelect.stories.ts +428 -0
  60. package/src/components/FdsSearchSelect/FdsSearchSelect.vue +610 -0
  61. package/src/components/FdsSearchSelect/types.ts +25 -0
  62. package/src/components/FdsSpinner/FdsSpinner.stories.ts +31 -0
  63. package/src/components/FdsSpinner/FdsSpinner.vue +90 -0
  64. package/src/components/FdsSpinner/types.ts +6 -0
  65. package/src/components/FdsSticker/FdsSticker.stories.ts +148 -0
  66. package/src/components/FdsSticker/FdsSticker.vue +44 -0
  67. package/src/components/FdsSticker/types.ts +4 -0
  68. package/src/components/FdsTreeView/FdsTreeView.stories.ts +136 -0
  69. package/src/components/FdsTreeView/FdsTreeView.vue +162 -0
  70. package/src/components/FdsTreeView/TreeNode.vue +383 -0
  71. package/src/components/FdsTreeView/types.ts +141 -0
  72. package/src/components/FdsTreeView/useTreeState.ts +607 -0
  73. package/src/components/FdsTreeView/utils.ts +65 -0
  74. package/src/components/FdsTruncatedText/FdsTruncatedText.stories.ts +78 -0
  75. package/src/components/FdsTruncatedText/FdsTruncatedText.vue +85 -0
  76. package/src/components/FdsTruncatedText/types.ts +6 -0
  77. package/src/components/Form/FdsCheckbox/FdsCheckbox.stories.ts +275 -0
  78. package/src/components/Form/FdsCheckbox/FdsCheckbox.vue +155 -0
  79. package/src/components/Form/FdsCheckbox/types.ts +10 -0
  80. package/src/components/Form/FdsInput/FdsInput.stories.ts +319 -0
  81. package/src/components/Form/FdsInput/FdsInput.vue +233 -0
  82. package/src/components/Form/FdsInput/types.ts +25 -0
  83. package/src/components/Form/FdsRadio/FdsRadio.stories.ts +63 -0
  84. package/src/components/Form/FdsRadio/FdsRadio.vue +88 -0
  85. package/src/components/Form/FdsRadio/types.ts +12 -0
  86. package/src/components/Form/FdsSelect/FdsSelect.stories.ts +78 -0
  87. package/src/components/Form/FdsSelect/FdsSelect.vue +136 -0
  88. package/src/components/Form/FdsSelect/types.ts +13 -0
  89. package/src/components/Form/FdsTextarea/FdsTextarea.stories.ts +52 -0
  90. package/src/components/Form/FdsTextarea/FdsTextarea.vue +110 -0
  91. package/src/components/Form/FdsTextarea/types.ts +12 -0
  92. package/src/components/Table/FdsTable/FdsTable.stories.ts +221 -0
  93. package/src/components/Table/FdsTable/FdsTable.vue +25 -0
  94. package/src/components/Table/FdsTable/types.ts +4 -0
  95. package/src/components/Table/FdsTableHead/FdsTableHead.stories.ts +151 -0
  96. package/src/components/Table/FdsTableHead/FdsTableHead.vue +54 -0
  97. package/src/components/Table/FdsTableHead/types.ts +5 -0
  98. package/src/components/Tabs/FdsTabs/FdsTabs.stories.ts +247 -0
  99. package/src/components/Tabs/FdsTabs/FdsTabs.vue +27 -0
  100. package/src/components/Tabs/FdsTabs/types.ts +4 -0
  101. package/src/components/Tabs/FdsTabsItem/FdsTabsItem.vue +125 -0
  102. package/src/components/Tabs/FdsTabsItem/types.ts +16 -0
  103. package/src/components/Typography/FdsHeading/FdsHeading.stories.ts +93 -0
  104. package/src/components/Typography/FdsHeading/FdsHeading.vue +51 -0
  105. package/src/components/Typography/FdsHeading/types.ts +5 -0
  106. package/src/components/Typography/FdsListHeading/FdsListHeading.stories.ts +58 -0
  107. package/src/components/Typography/FdsListHeading/FdsListHeading.vue +62 -0
  108. package/src/components/Typography/FdsListHeading/types.ts +8 -0
  109. package/src/components/Typography/FdsSeparator/FdsSeparator.stories.ts +31 -0
  110. package/src/components/Typography/FdsSeparator/FdsSeparator.vue +5 -0
  111. package/src/components/Typography/FdsText/FdsText.stories.ts +66 -0
  112. package/src/components/Typography/FdsText/FdsText.vue +28 -0
  113. package/src/components/Typography/FdsText/types.ts +3 -0
  114. package/src/composables/useBoldQuery.ts +29 -0
  115. package/src/composables/useElementFinalSize.ts +24 -0
  116. package/src/composables/useHasSlots.ts +17 -0
  117. package/src/composables/useIsPid.ts +48 -0
  118. package/src/docs/Start/Start.mdx +12 -0
  119. package/src/docs/Usage.md +117 -0
  120. package/src/fonts.css +28 -0
  121. package/src/global-components.ts +38 -0
  122. package/src/index.ts +180 -0
  123. package/src/main.ts +7 -0
  124. package/src/slot-styles.css +93 -0
  125. package/src/style.css +89 -0
  126. package/src/tokens.css +252 -0
  127. package/tsconfig.base.json +4 -0
  128. package/dist/App.vue.d.ts +0 -3
  129. package/dist/App.vue.d.ts.map +0 -1
  130. package/dist/assets/icons.d.ts +0 -5
  131. package/dist/assets/icons.d.ts.map +0 -1
  132. package/dist/components/Blocks/FdsBlockAlert/FdsBlockAlert.stories.d.ts +0 -9
  133. package/dist/components/Blocks/FdsBlockAlert/FdsBlockAlert.stories.d.ts.map +0 -1
  134. package/dist/components/Blocks/FdsBlockAlert/FdsBlockAlert.vue.d.ts +0 -30
  135. package/dist/components/Blocks/FdsBlockAlert/FdsBlockAlert.vue.d.ts.map +0 -1
  136. package/dist/components/Blocks/FdsBlockAlert/types.d.ts +0 -12
  137. package/dist/components/Blocks/FdsBlockAlert/types.d.ts.map +0 -1
  138. package/dist/components/Blocks/FdsBlockContent/FdsBlockContent.stories.d.ts +0 -9
  139. package/dist/components/Blocks/FdsBlockContent/FdsBlockContent.stories.d.ts.map +0 -1
  140. package/dist/components/Blocks/FdsBlockContent/FdsBlockContent.vue.d.ts +0 -19
  141. package/dist/components/Blocks/FdsBlockContent/FdsBlockContent.vue.d.ts.map +0 -1
  142. package/dist/components/Blocks/FdsBlockContent/types.d.ts +0 -7
  143. package/dist/components/Blocks/FdsBlockContent/types.d.ts.map +0 -1
  144. package/dist/components/Blocks/FdsBlockExpander/FdsBlockExpander.stories.d.ts +0 -11
  145. package/dist/components/Blocks/FdsBlockExpander/FdsBlockExpander.stories.d.ts.map +0 -1
  146. package/dist/components/Blocks/FdsBlockExpander/FdsBlockExpander.vue.d.ts +0 -23
  147. package/dist/components/Blocks/FdsBlockExpander/FdsBlockExpander.vue.d.ts.map +0 -1
  148. package/dist/components/Blocks/FdsBlockExpander/types.d.ts +0 -8
  149. package/dist/components/Blocks/FdsBlockExpander/types.d.ts.map +0 -1
  150. package/dist/components/Blocks/FdsBlockInfo/FdsBlockInfo.stories.d.ts +0 -9
  151. package/dist/components/Blocks/FdsBlockInfo/FdsBlockInfo.stories.d.ts.map +0 -1
  152. package/dist/components/Blocks/FdsBlockInfo/FdsBlockInfo.vue.d.ts +0 -20
  153. package/dist/components/Blocks/FdsBlockInfo/FdsBlockInfo.vue.d.ts.map +0 -1
  154. package/dist/components/Blocks/FdsBlockInfo/types.d.ts +0 -8
  155. package/dist/components/Blocks/FdsBlockInfo/types.d.ts.map +0 -1
  156. package/dist/components/Blocks/FdsBlockLink/FdsBlockLink.stories.d.ts +0 -14
  157. package/dist/components/Blocks/FdsBlockLink/FdsBlockLink.stories.d.ts.map +0 -1
  158. package/dist/components/Blocks/FdsBlockLink/FdsBlockLink.vue.d.ts +0 -30
  159. package/dist/components/Blocks/FdsBlockLink/FdsBlockLink.vue.d.ts.map +0 -1
  160. package/dist/components/Blocks/FdsBlockLink/types.d.ts +0 -14
  161. package/dist/components/Blocks/FdsBlockLink/types.d.ts.map +0 -1
  162. package/dist/components/Buttons/ButtonBaseProps.d.ts +0 -18
  163. package/dist/components/Buttons/ButtonBaseProps.d.ts.map +0 -1
  164. package/dist/components/Buttons/FdsButtonCopy/FdsButtonCopy.stories.d.ts +0 -7
  165. package/dist/components/Buttons/FdsButtonCopy/FdsButtonCopy.stories.d.ts.map +0 -1
  166. package/dist/components/Buttons/FdsButtonCopy/FdsButtonCopy.vue.d.ts +0 -14
  167. package/dist/components/Buttons/FdsButtonCopy/FdsButtonCopy.vue.d.ts.map +0 -1
  168. package/dist/components/Buttons/FdsButtonCopy/types.d.ts +0 -9
  169. package/dist/components/Buttons/FdsButtonCopy/types.d.ts.map +0 -1
  170. package/dist/components/Buttons/FdsButtonDownload/FdsButtonDownload.stories.d.ts +0 -10
  171. package/dist/components/Buttons/FdsButtonDownload/FdsButtonDownload.stories.d.ts.map +0 -1
  172. package/dist/components/Buttons/FdsButtonDownload/FdsButtonDownload.vue.d.ts +0 -25
  173. package/dist/components/Buttons/FdsButtonDownload/FdsButtonDownload.vue.d.ts.map +0 -1
  174. package/dist/components/Buttons/FdsButtonIcon/FdsButtonIcon.stories.d.ts +0 -7
  175. package/dist/components/Buttons/FdsButtonIcon/FdsButtonIcon.stories.d.ts.map +0 -1
  176. package/dist/components/Buttons/FdsButtonIcon/FdsButtonIcon.vue.d.ts +0 -14
  177. package/dist/components/Buttons/FdsButtonIcon/FdsButtonIcon.vue.d.ts.map +0 -1
  178. package/dist/components/Buttons/FdsButtonIcon/types.d.ts +0 -12
  179. package/dist/components/Buttons/FdsButtonIcon/types.d.ts.map +0 -1
  180. package/dist/components/Buttons/FdsButtonMinor/FdsButtonMinor.stories.d.ts +0 -7
  181. package/dist/components/Buttons/FdsButtonMinor/FdsButtonMinor.stories.d.ts.map +0 -1
  182. package/dist/components/Buttons/FdsButtonMinor/FdsButtonMinor.vue.d.ts +0 -25
  183. package/dist/components/Buttons/FdsButtonMinor/FdsButtonMinor.vue.d.ts.map +0 -1
  184. package/dist/components/Buttons/FdsButtonPrimary/FdsButtonPrimary.stories.d.ts +0 -9
  185. package/dist/components/Buttons/FdsButtonPrimary/FdsButtonPrimary.stories.d.ts.map +0 -1
  186. package/dist/components/Buttons/FdsButtonPrimary/FdsButtonPrimary.vue.d.ts +0 -20
  187. package/dist/components/Buttons/FdsButtonPrimary/FdsButtonPrimary.vue.d.ts.map +0 -1
  188. package/dist/components/Buttons/FdsButtonSecondary/FdsButtonSecondary.stories.d.ts +0 -7
  189. package/dist/components/Buttons/FdsButtonSecondary/FdsButtonSecondary.stories.d.ts.map +0 -1
  190. package/dist/components/Buttons/FdsButtonSecondary/FdsButtonSecondary.vue.d.ts +0 -20
  191. package/dist/components/Buttons/FdsButtonSecondary/FdsButtonSecondary.vue.d.ts.map +0 -1
  192. package/dist/components/FdsIcon/FdsIcon.stories.d.ts +0 -8
  193. package/dist/components/FdsIcon/FdsIcon.stories.d.ts.map +0 -1
  194. package/dist/components/FdsIcon/FdsIcon.vue.d.ts +0 -7
  195. package/dist/components/FdsIcon/FdsIcon.vue.d.ts.map +0 -1
  196. package/dist/components/FdsIcon/types.d.ts +0 -8
  197. package/dist/components/FdsIcon/types.d.ts.map +0 -1
  198. package/dist/components/FdsModal/FdsModal.stories.d.ts +0 -13
  199. package/dist/components/FdsModal/FdsModal.stories.d.ts.map +0 -1
  200. package/dist/components/FdsModal/FdsModal.vue.d.ts +0 -33
  201. package/dist/components/FdsModal/FdsModal.vue.d.ts.map +0 -1
  202. package/dist/components/FdsModal/types.d.ts +0 -13
  203. package/dist/components/FdsModal/types.d.ts.map +0 -1
  204. package/dist/components/FdsPagination/FdsPagination.stories.d.ts +0 -11
  205. package/dist/components/FdsPagination/FdsPagination.stories.d.ts.map +0 -1
  206. package/dist/components/FdsPagination/FdsPagination.vue.d.ts +0 -21
  207. package/dist/components/FdsPagination/FdsPagination.vue.d.ts.map +0 -1
  208. package/dist/components/FdsPagination/types.d.ts +0 -7
  209. package/dist/components/FdsPagination/types.d.ts.map +0 -1
  210. package/dist/components/FdsSearchSelect/FdsSearchSelect.stories.d.ts +0 -15
  211. package/dist/components/FdsSearchSelect/FdsSearchSelect.stories.d.ts.map +0 -1
  212. package/dist/components/FdsSearchSelect/FdsSearchSelect.vue.d.ts +0 -41
  213. package/dist/components/FdsSearchSelect/FdsSearchSelect.vue.d.ts.map +0 -1
  214. package/dist/components/FdsSearchSelect/types.d.ts +0 -29
  215. package/dist/components/FdsSearchSelect/types.d.ts.map +0 -1
  216. package/dist/components/FdsSpinner/FdsSpinner.stories.d.ts +0 -7
  217. package/dist/components/FdsSpinner/FdsSpinner.stories.d.ts.map +0 -1
  218. package/dist/components/FdsSpinner/FdsSpinner.vue.d.ts +0 -15
  219. package/dist/components/FdsSpinner/FdsSpinner.vue.d.ts.map +0 -1
  220. package/dist/components/FdsSpinner/types.d.ts +0 -7
  221. package/dist/components/FdsSpinner/types.d.ts.map +0 -1
  222. package/dist/components/FdsSticker/FdsSticker.stories.d.ts +0 -15
  223. package/dist/components/FdsSticker/FdsSticker.stories.d.ts.map +0 -1
  224. package/dist/components/FdsSticker/FdsSticker.vue.d.ts +0 -17
  225. package/dist/components/FdsSticker/FdsSticker.vue.d.ts.map +0 -1
  226. package/dist/components/FdsSticker/types.d.ts +0 -5
  227. package/dist/components/FdsSticker/types.d.ts.map +0 -1
  228. package/dist/components/FdsTreeView/FdsTreeView.stories.d.ts +0 -7
  229. package/dist/components/FdsTreeView/FdsTreeView.stories.d.ts.map +0 -1
  230. package/dist/components/FdsTreeView/FdsTreeView.vue.d.ts +0 -29
  231. package/dist/components/FdsTreeView/FdsTreeView.vue.d.ts.map +0 -1
  232. package/dist/components/FdsTreeView/TreeNode.vue.d.ts +0 -21
  233. package/dist/components/FdsTreeView/TreeNode.vue.d.ts.map +0 -1
  234. package/dist/components/FdsTreeView/types.d.ts +0 -122
  235. package/dist/components/FdsTreeView/types.d.ts.map +0 -1
  236. package/dist/components/FdsTreeView/useTreeState.d.ts +0 -48
  237. package/dist/components/FdsTreeView/useTreeState.d.ts.map +0 -1
  238. package/dist/components/FdsTreeView/utils.d.ts +0 -4
  239. package/dist/components/FdsTreeView/utils.d.ts.map +0 -1
  240. package/dist/components/FdsTruncatedText/FdsTruncatedText.stories.d.ts +0 -9
  241. package/dist/components/FdsTruncatedText/FdsTruncatedText.stories.d.ts.map +0 -1
  242. package/dist/components/FdsTruncatedText/FdsTruncatedText.vue.d.ts +0 -26
  243. package/dist/components/FdsTruncatedText/FdsTruncatedText.vue.d.ts.map +0 -1
  244. package/dist/components/FdsTruncatedText/types.d.ts +0 -7
  245. package/dist/components/FdsTruncatedText/types.d.ts.map +0 -1
  246. package/dist/components/Form/FdsCheckbox/FdsCheckbox.stories.d.ts +0 -12
  247. package/dist/components/Form/FdsCheckbox/FdsCheckbox.stories.d.ts.map +0 -1
  248. package/dist/components/Form/FdsCheckbox/FdsCheckbox.vue.d.ts +0 -38
  249. package/dist/components/Form/FdsCheckbox/FdsCheckbox.vue.d.ts.map +0 -1
  250. package/dist/components/Form/FdsCheckbox/types.d.ts +0 -11
  251. package/dist/components/Form/FdsCheckbox/types.d.ts.map +0 -1
  252. package/dist/components/Form/FdsInput/FdsInput.stories.d.ts +0 -18
  253. package/dist/components/Form/FdsInput/FdsInput.stories.d.ts.map +0 -1
  254. package/dist/components/Form/FdsInput/FdsInput.vue.d.ts +0 -39
  255. package/dist/components/Form/FdsInput/FdsInput.vue.d.ts.map +0 -1
  256. package/dist/components/Form/FdsInput/types.d.ts +0 -26
  257. package/dist/components/Form/FdsInput/types.d.ts.map +0 -1
  258. package/dist/components/Form/FdsRadio/FdsRadio.stories.d.ts +0 -8
  259. package/dist/components/Form/FdsRadio/FdsRadio.stories.d.ts.map +0 -1
  260. package/dist/components/Form/FdsRadio/FdsRadio.vue.d.ts +0 -36
  261. package/dist/components/Form/FdsRadio/FdsRadio.vue.d.ts.map +0 -1
  262. package/dist/components/Form/FdsRadio/types.d.ts +0 -13
  263. package/dist/components/Form/FdsRadio/types.d.ts.map +0 -1
  264. package/dist/components/Form/FdsSelect/FdsSelect.stories.d.ts +0 -10
  265. package/dist/components/Form/FdsSelect/FdsSelect.stories.d.ts.map +0 -1
  266. package/dist/components/Form/FdsSelect/FdsSelect.vue.d.ts +0 -45
  267. package/dist/components/Form/FdsSelect/FdsSelect.vue.d.ts.map +0 -1
  268. package/dist/components/Form/FdsSelect/types.d.ts +0 -18
  269. package/dist/components/Form/FdsSelect/types.d.ts.map +0 -1
  270. package/dist/components/Form/FdsTextarea/FdsTextarea.stories.d.ts +0 -8
  271. package/dist/components/Form/FdsTextarea/FdsTextarea.stories.d.ts.map +0 -1
  272. package/dist/components/Form/FdsTextarea/FdsTextarea.vue.d.ts +0 -27
  273. package/dist/components/Form/FdsTextarea/FdsTextarea.vue.d.ts.map +0 -1
  274. package/dist/components/Form/FdsTextarea/types.d.ts +0 -13
  275. package/dist/components/Form/FdsTextarea/types.d.ts.map +0 -1
  276. package/dist/components/Table/FdsTable/FdsTable.stories.d.ts +0 -10
  277. package/dist/components/Table/FdsTable/FdsTable.stories.d.ts.map +0 -1
  278. package/dist/components/Table/FdsTable/FdsTable.vue.d.ts +0 -16
  279. package/dist/components/Table/FdsTable/FdsTable.vue.d.ts.map +0 -1
  280. package/dist/components/Table/FdsTable/types.d.ts +0 -5
  281. package/dist/components/Table/FdsTable/types.d.ts.map +0 -1
  282. package/dist/components/Table/FdsTableHead/FdsTableHead.stories.d.ts +0 -12
  283. package/dist/components/Table/FdsTableHead/FdsTableHead.stories.d.ts.map +0 -1
  284. package/dist/components/Table/FdsTableHead/FdsTableHead.vue.d.ts +0 -24
  285. package/dist/components/Table/FdsTableHead/FdsTableHead.vue.d.ts.map +0 -1
  286. package/dist/components/Table/FdsTableHead/types.d.ts +0 -6
  287. package/dist/components/Table/FdsTableHead/types.d.ts.map +0 -1
  288. package/dist/components/Tabs/FdsTabs/FdsTabs.stories.d.ts +0 -14
  289. package/dist/components/Tabs/FdsTabs/FdsTabs.stories.d.ts.map +0 -1
  290. package/dist/components/Tabs/FdsTabs/FdsTabs.vue.d.ts +0 -17
  291. package/dist/components/Tabs/FdsTabs/FdsTabs.vue.d.ts.map +0 -1
  292. package/dist/components/Tabs/FdsTabs/types.d.ts +0 -5
  293. package/dist/components/Tabs/FdsTabs/types.d.ts.map +0 -1
  294. package/dist/components/Tabs/FdsTabsItem/FdsTabsItem.vue.d.ts +0 -22
  295. package/dist/components/Tabs/FdsTabsItem/FdsTabsItem.vue.d.ts.map +0 -1
  296. package/dist/components/Tabs/FdsTabsItem/types.d.ts +0 -17
  297. package/dist/components/Tabs/FdsTabsItem/types.d.ts.map +0 -1
  298. package/dist/components/Typography/FdsHeading/FdsHeading.stories.d.ts +0 -11
  299. package/dist/components/Typography/FdsHeading/FdsHeading.stories.d.ts.map +0 -1
  300. package/dist/components/Typography/FdsHeading/FdsHeading.vue.d.ts +0 -6
  301. package/dist/components/Typography/FdsHeading/FdsHeading.vue.d.ts.map +0 -1
  302. package/dist/components/Typography/FdsHeading/types.d.ts +0 -6
  303. package/dist/components/Typography/FdsHeading/types.d.ts.map +0 -1
  304. package/dist/components/Typography/FdsListHeading/FdsListHeading.stories.d.ts +0 -11
  305. package/dist/components/Typography/FdsListHeading/FdsListHeading.stories.d.ts.map +0 -1
  306. package/dist/components/Typography/FdsListHeading/FdsListHeading.vue.d.ts +0 -7
  307. package/dist/components/Typography/FdsListHeading/FdsListHeading.vue.d.ts.map +0 -1
  308. package/dist/components/Typography/FdsListHeading/types.d.ts +0 -9
  309. package/dist/components/Typography/FdsListHeading/types.d.ts.map +0 -1
  310. package/dist/components/Typography/FdsSeparator/FdsSeparator.stories.d.ts +0 -7
  311. package/dist/components/Typography/FdsSeparator/FdsSeparator.stories.d.ts.map +0 -1
  312. package/dist/components/Typography/FdsSeparator/FdsSeparator.vue.d.ts +0 -3
  313. package/dist/components/Typography/FdsSeparator/FdsSeparator.vue.d.ts.map +0 -1
  314. package/dist/components/Typography/FdsText/FdsText.stories.d.ts +0 -9
  315. package/dist/components/Typography/FdsText/FdsText.stories.d.ts.map +0 -1
  316. package/dist/components/Typography/FdsText/FdsText.vue.d.ts +0 -16
  317. package/dist/components/Typography/FdsText/FdsText.vue.d.ts.map +0 -1
  318. package/dist/components/Typography/FdsText/types.d.ts +0 -4
  319. package/dist/components/Typography/FdsText/types.d.ts.map +0 -1
  320. package/dist/composables/useBoldQuery.d.ts +0 -10
  321. package/dist/composables/useBoldQuery.d.ts.map +0 -1
  322. package/dist/composables/useElementFinalSize.d.ts +0 -3
  323. package/dist/composables/useElementFinalSize.d.ts.map +0 -1
  324. package/dist/composables/useHasSlots.d.ts +0 -6
  325. package/dist/composables/useHasSlots.d.ts.map +0 -1
  326. package/dist/composables/useIsPid.d.ts +0 -16
  327. package/dist/composables/useIsPid.d.ts.map +0 -1
  328. package/dist/global-components.d.ts.map +0 -1
  329. package/dist/index.d.ts.map +0 -1
  330. package/dist/main.d.ts +0 -2
  331. package/dist/main.d.ts.map +0 -1
@@ -0,0 +1,610 @@
1
+ <script setup lang="ts">
2
+ import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
3
+ import { useBoldQuery } from '@/composables/useBoldQuery'
4
+ import { isPidString, useIsPid } from '@/composables/useIsPid'
5
+ import FdsIcon from '@/components/FdsIcon/FdsIcon.vue'
6
+ import FdsPagination from '@/components/FdsPagination/FdsPagination.vue'
7
+ import FdsSpinner from '@/components/FdsSpinner/FdsSpinner.vue'
8
+ import FdsInput from '@/components/Form/FdsInput/FdsInput.vue'
9
+ import type { FdsSearchSelectProps } from './types'
10
+
11
+ const props = withDefaults(defineProps<FdsSearchSelectProps>(), {
12
+ items: () => [],
13
+ page: undefined,
14
+ totalPages: undefined,
15
+ totalCount: undefined,
16
+ loading: false,
17
+ searchFields: () => [],
18
+ preserveOrder: false,
19
+ initialValue: '',
20
+ disabled: false,
21
+ dropdownAbsolute: false,
22
+ labelLeft: false,
23
+ label: '',
24
+ meta: undefined,
25
+ singleItemLabel: '',
26
+ searchContext: () => ({ context: '', linkWord: '' }),
27
+ valid: undefined,
28
+ invalidMessage: '',
29
+ noResultPrompt: '',
30
+ borderless: false,
31
+ marginless: false,
32
+ maxListHeight: undefined,
33
+ locale: 'sv',
34
+ clearTrigger: false,
35
+ })
36
+
37
+ const emit = defineEmits<{
38
+ (e: 'searchSelected', value: Record<string, unknown> | null): void
39
+ (e: 'paginate', value: number): void
40
+ (e: 'total', value: number): void
41
+ (e: 'change', value: string): void
42
+ }>()
43
+
44
+ const dropdownVisible = ref(false)
45
+ const singleItemName = ref('')
46
+ const searchTerm = ref('')
47
+ const matchingItems = ref<Array<Record<string, unknown>>>([])
48
+ const displayedItems = ref<Array<Record<string, unknown>>>([])
49
+ const selectedItem = ref<Record<string, unknown> | null>(null)
50
+ const focusedIndex = ref<number>(-1)
51
+ const valid = ref<string | undefined>(props.valid)
52
+
53
+ // Use prop.totalCount if provided, otherwise calculate from items.length
54
+ const totalCount = computed(() => {
55
+ if (props.totalCount !== undefined) {
56
+ return props.totalCount
57
+ }
58
+ return props.items?.length || 0
59
+ })
60
+
61
+ watch(
62
+ () => props.valid,
63
+ (newValue) => {
64
+ valid.value = newValue
65
+ },
66
+ )
67
+
68
+ const componentRef = ref<HTMLElement | null>(null)
69
+ const inputId = `searchSelectInput-${Math.random().toString(36).slice(2, 9)}`
70
+
71
+ const hasInputValue = computed(() => searchTerm.value.length > 0)
72
+
73
+ const listWrapperClasses = computed(() => [
74
+ 'rounded-md box-border overflow-hidden z-4 w-full bg-white mt-2',
75
+ props.marginless ? 'mb-0' : 'mb-8',
76
+ props.borderless ? 'shadow-lg border-none' : 'border border-gray-200',
77
+ props.dropdownAbsolute ? 'absolute right-0 z-50' : 'relative',
78
+ props.maxListHeight && 'overflow-y-scroll',
79
+ ])
80
+
81
+ const listItemClasses = computed(() => [
82
+ 'block m-0',
83
+ 'outline-none! hover:bg-blue_t-100 active:bg-blue_t-200',
84
+ props.borderless && 'border-b border-blue_t-200',
85
+ ])
86
+
87
+ const listWrapperStyle = computed(() => {
88
+ if (!props.maxListHeight) return null
89
+
90
+ // Convert to number in case it's passed as a string
91
+ const maxHeight = typeof props.maxListHeight === 'string' ? parseInt(props.maxListHeight, 10) : props.maxListHeight
92
+
93
+ return { maxHeight: `${maxHeight}px` }
94
+ })
95
+
96
+ const sortResponse = (response: Array<Record<string, unknown>>) => {
97
+ const allKeys = [...props.searchFields, ...Object.keys(response[0]).filter((k) => !props.searchFields.includes(k))]
98
+ return response.map((item) => {
99
+ const sorted: Record<string, unknown> = {}
100
+ allKeys.forEach((key) => {
101
+ sorted[key] = item[key] || `${key}: den här uppgiften saknas.`
102
+ })
103
+ return sorted
104
+ })
105
+ }
106
+
107
+ const matchesSearchTerm = (item: Record<string, unknown>): boolean => {
108
+ if (!searchTerm.value) return true
109
+
110
+ // When mask is active, use unmasked value (digits only) for searching
111
+ // This ensures we can search even when user has partially typed a PID
112
+ const searchValue = isPid.value ? searchTerm.value.replace(/\D/g, '') : searchTerm.value
113
+
114
+ const searchLower = searchValue.toLowerCase()
115
+ const pidRegex = /^\d{8}[a-zA-Z0-9]{4}$/
116
+
117
+ // If search term matches PID pattern (unmasked), include all items
118
+ if (pidRegex.test(searchValue)) return true
119
+
120
+ // Check if any searchFields field contains the search term
121
+ // For PID fields, also check unmasked version
122
+ return props.searchFields.some((key) => {
123
+ const value = item[key]
124
+ if (!value) return false
125
+
126
+ const stringValue = String(value)
127
+ const valueLower = stringValue.toLowerCase()
128
+ const unmaskedValue = stringValue.replace(/\D/g, '')
129
+
130
+ // Check both masked and unmasked versions
131
+ return valueLower.includes(searchLower) || (unmaskedValue.length > 0 && unmaskedValue.includes(searchValue))
132
+ })
133
+ }
134
+
135
+ const filterAndPaginate = () => {
136
+ if (!props.items?.length) {
137
+ matchingItems.value = []
138
+ displayedItems.value = []
139
+ emit('total', 0)
140
+ return
141
+ }
142
+
143
+ // Filter items based on search term
144
+ let sourceData = props.items
145
+ if (props.preserveOrder && sourceData.length) {
146
+ sourceData = sortResponse(sourceData)
147
+ }
148
+
149
+ const matchedArray = sourceData.filter((item) => matchesSearchTerm(item))
150
+ matchingItems.value = matchedArray
151
+
152
+ // Never paginate internally - just show all filtered items
153
+ // Parent component is responsible for pagination if needed
154
+ displayedItems.value = matchedArray
155
+
156
+ emit('total', matchingItems.value.length)
157
+ }
158
+
159
+ const handleClear = () => {
160
+ searchTerm.value = ''
161
+ selectedItem.value = null
162
+ valid.value = 'null'
163
+ emit('searchSelected', null)
164
+ dropdownVisible.value = false
165
+ filterAndPaginate()
166
+ }
167
+
168
+ watch(
169
+ () => props.clearTrigger,
170
+ (value) => value && handleClear(),
171
+ )
172
+
173
+ watch(
174
+ () => props.items,
175
+ () => {
176
+ filterAndPaginate()
177
+ },
178
+ { immediate: true },
179
+ )
180
+
181
+ const formatPidWithDash = (value: string): string => {
182
+ // Only format if it looks like a personnummer
183
+ if (!isPidString(value)) {
184
+ // If it's not a PID, remove any trailing dash that might be left
185
+ return value.replace(/-$/, '')
186
+ }
187
+
188
+ // Remove all non-digits
189
+ const digits = value.replace(/\D/g, '')
190
+
191
+ // Only add dash if there are digits after the first 8
192
+ if (digits.length > 8) {
193
+ return `${digits.substring(0, 8)}-${digits.substring(8)}`
194
+ }
195
+
196
+ // If exactly 8 digits or less, return without dash
197
+ return digits
198
+ }
199
+
200
+ const debounce = <T extends (...args: any[]) => void>(fn: T, delay: number) => {
201
+ let timeout: ReturnType<typeof setTimeout>
202
+ return (...args: Parameters<T>) => {
203
+ clearTimeout(timeout)
204
+ timeout = setTimeout(() => fn(...args), delay)
205
+ }
206
+ }
207
+
208
+ const debouncedEmitChange = debounce((value: string) => {
209
+ const formattedValue = formatPidWithDash(value)
210
+ emit('change', formattedValue)
211
+ }, 500)
212
+
213
+ watch(
214
+ () => searchTerm.value,
215
+ (newValue) => {
216
+ filterAndPaginate()
217
+ if (selectedItem.value === null) {
218
+ debouncedEmitChange(newValue)
219
+ }
220
+ },
221
+ )
222
+
223
+ watch(
224
+ () => props.page,
225
+ () => {
226
+ filterAndPaginate()
227
+ },
228
+ )
229
+
230
+ // Reset focused index when items change
231
+ watch(
232
+ () => displayedItems.value,
233
+ () => {
234
+ focusedIndex.value = -1
235
+ },
236
+ )
237
+
238
+ const onClickOutside = (e: PointerEvent) => {
239
+ const target = e.target as Element
240
+ if (componentRef.value?.contains(target)) return
241
+
242
+ dropdownVisible.value = false
243
+ if (props.initialValue === searchTerm.value && props.initialValue.length) {
244
+ valid.value = 'true'
245
+ } else if (searchTerm.value.length > 0 && selectedItem.value === null) {
246
+ valid.value = 'false'
247
+ }
248
+ }
249
+
250
+ const totalPages = computed(() => {
251
+ // Only return totalPages if both page and totalPages props are provided
252
+ if (props.page !== undefined && props.totalPages !== undefined) {
253
+ return props.totalPages
254
+ }
255
+ return null
256
+ })
257
+
258
+ const handleInput = (e: Event) => {
259
+ const target = e.target as HTMLInputElement
260
+ const { value } = target
261
+
262
+ searchTerm.value = value
263
+ dropdownVisible.value = true
264
+ selectedItem.value = null
265
+ focusedIndex.value = -1
266
+ valid.value = 'null'
267
+ filterAndPaginate()
268
+ }
269
+
270
+ // Personnummer detection using composable
271
+ const { isPid } = useIsPid(searchTerm)
272
+
273
+ // Bold query matches using composable
274
+ const { boldQuery } = useBoldQuery(searchTerm)
275
+
276
+ // Mask configuration for personnummer (yyyymmdd-nnnn)
277
+ const pidMask = computed(() => {
278
+ if (isPid.value) {
279
+ return '00000000-0000'
280
+ }
281
+ return undefined
282
+ })
283
+
284
+ const handleMatchingString = (item: Record<string, unknown>): string => {
285
+ const values = props.searchFields.map((key) => String(item[key] || ''))
286
+
287
+ let result = ''
288
+ if (values.length === 1) {
289
+ result = values[0] || ''
290
+ } else {
291
+ // Format PID if second value is 12 digits
292
+ if (values[1]?.length === 12 && parseInt(values[1])) {
293
+ values[1] = formatPidWithDash(values[1])
294
+ }
295
+
296
+ if (props.preserveOrder) {
297
+ // Combine first two values, then join remaining with <br>
298
+ const combined = `${values[0]} (${values[1]})`
299
+ const rest = values.slice(2).join('<br>')
300
+ result = rest ? `${combined}<br>${rest}` : combined
301
+ } else {
302
+ result = `${values.join(' (')})`
303
+ }
304
+ }
305
+
306
+ if (searchTerm.value) {
307
+ const formattedTerm = formatPidWithDash(searchTerm.value)
308
+ if (formattedTerm !== searchTerm.value) {
309
+ searchTerm.value = formattedTerm
310
+ }
311
+
312
+ const escaped = formattedTerm.replace(/[()]/g, '\\$&')
313
+ if (new RegExp(escaped, 'i').test(result)) {
314
+ return boldQuery(result)
315
+ }
316
+ }
317
+
318
+ return result
319
+ }
320
+
321
+ const handlePagination = (payload: { target: { id: string }; detail: number }) => {
322
+ const newPage = payload.detail
323
+ emit('paginate', newPage)
324
+ }
325
+
326
+ const selectItem = (item: Record<string, unknown>) => {
327
+ selectedItem.value = item
328
+ valid.value = 'true'
329
+ emit('searchSelected', item)
330
+ }
331
+
332
+ const handleClick = (e: MouseEvent | KeyboardEvent, item: Record<string, unknown>) => {
333
+ const keyEvent = e as KeyboardEvent
334
+ if (keyEvent.key === 'Enter' || keyEvent.code === 'Space' || e.type === 'mouseup') {
335
+ // Prevent event from bubbling and triggering other handlers
336
+ e.preventDefault()
337
+ e.stopPropagation()
338
+
339
+ searchTerm.value = (item[props.searchFields[0]] as string) || ''
340
+ selectItem(item)
341
+ focusedIndex.value = -1
342
+ dropdownVisible.value = false
343
+
344
+ // Focus input after a short delay to prevent dropdown from reopening
345
+ setTimeout(() => {
346
+ const input = document.getElementById(inputId) as HTMLInputElement
347
+ if (input) {
348
+ input.focus()
349
+ }
350
+ }, 100)
351
+ }
352
+ }
353
+
354
+ const handleInputFocus = () => {
355
+ // Only open dropdown if an item hasn't been selected and there are items to show
356
+ if (!selectedItem.value && displayedItems.value.length > 0) {
357
+ dropdownVisible.value = true
358
+ }
359
+ }
360
+
361
+ const handleListKeyDown = (e: KeyboardEvent) => {
362
+ // Handle keyboard events when focus is anywhere in the list (including radio buttons)
363
+ // Only handle if the target is a radio button or list item
364
+ const target = e.target as HTMLElement
365
+ const isRadioButton = target.tagName === 'INPUT' && (target as HTMLInputElement).type === 'radio'
366
+ const isListItem = target.closest('li[role="option"]')
367
+ if (isRadioButton || isListItem) {
368
+ handleInputKeyDown(e)
369
+ }
370
+ }
371
+
372
+ const handleInputKeyDown = (e: KeyboardEvent) => {
373
+ if (!dropdownVisible.value && displayedItems.value.length > 0) {
374
+ if (e.key === 'ArrowDown' || e.key === 'Enter') {
375
+ e.preventDefault()
376
+ dropdownVisible.value = true
377
+ focusedIndex.value = 0
378
+ setTimeout(() => {
379
+ const firstRadioButton = document.getElementById(`search-select-radio-0`) as HTMLInputElement
380
+ if (firstRadioButton) {
381
+ firstRadioButton.focus()
382
+ firstRadioButton.setAttribute('checked', 'true')
383
+ }
384
+ }, 0)
385
+ return
386
+ }
387
+ }
388
+
389
+ if (!dropdownVisible.value) return
390
+
391
+ switch (e.key) {
392
+ case 'ArrowDown':
393
+ e.preventDefault()
394
+ e.stopPropagation()
395
+ if (focusedIndex.value < displayedItems.value.length - 1) {
396
+ focusedIndex.value++
397
+ } else {
398
+ focusedIndex.value = 0
399
+ }
400
+ break
401
+
402
+ case 'ArrowUp':
403
+ e.preventDefault()
404
+ e.stopPropagation()
405
+ if (focusedIndex.value > 0) {
406
+ focusedIndex.value--
407
+ } else {
408
+ focusedIndex.value = displayedItems.value.length - 1
409
+ }
410
+ break
411
+
412
+ case 'Enter':
413
+ e.preventDefault()
414
+ if (focusedIndex.value >= 0 && focusedIndex.value < displayedItems.value.length) {
415
+ handleClick(e, displayedItems.value[focusedIndex.value])
416
+ } else if (displayedItems.value.length === 1) {
417
+ handleClick(e, displayedItems.value[0])
418
+ }
419
+ break
420
+
421
+ case 'Escape':
422
+ e.preventDefault()
423
+ dropdownVisible.value = false
424
+ focusedIndex.value = -1
425
+ const input = document.getElementById(inputId) as HTMLInputElement
426
+ input?.focus()
427
+ break
428
+
429
+ case 'Tab':
430
+ // Let default tab behavior handle focus navigation
431
+ // When list is open, first list-item has tabindex="0" so Tab will go there
432
+ // When list is closed, Tab will go to next element normally
433
+ if (!dropdownVisible.value) {
434
+ dropdownVisible.value = false
435
+ focusedIndex.value = -1
436
+ }
437
+ break
438
+ }
439
+ }
440
+
441
+ onMounted(() => {
442
+ if (props.initialValue) {
443
+ searchTerm.value = props.initialValue
444
+ valid.value = 'true'
445
+ }
446
+
447
+ window.addEventListener('mouseup', onClickOutside as EventListener)
448
+
449
+ nextTick(() => {
450
+ const input = document.getElementById(inputId)
451
+ if (input) {
452
+ input.addEventListener('keydown', handleInputKeyDown)
453
+ input.addEventListener('focus', handleInputFocus)
454
+ }
455
+ })
456
+
457
+ filterAndPaginate()
458
+ })
459
+
460
+ onBeforeUnmount(() => {
461
+ window.removeEventListener('mouseup', onClickOutside as EventListener)
462
+ const input = document.getElementById(inputId)
463
+ if (input) {
464
+ input.removeEventListener('keydown', handleInputKeyDown)
465
+ input.removeEventListener('focus', handleInputFocus)
466
+ }
467
+ })
468
+ </script>
469
+
470
+ <template>
471
+ <div
472
+ ref="componentRef"
473
+ class="fds-search-select block mb-6"
474
+ >
475
+ <div class="relative block">
476
+ <div
477
+ v-if="!singleItemName.length"
478
+ class="relative"
479
+ >
480
+ <div class="relative">
481
+ <FdsInput
482
+ :label="label"
483
+ :meta="meta ?? undefined"
484
+ :labelLeft="labelLeft"
485
+ class="relative mb-0! w-full!"
486
+ :valid="valid"
487
+ :invalidMessage="invalidMessage"
488
+ :disabled="disabled"
489
+ :locale="locale"
490
+ type="search"
491
+ :value="searchTerm"
492
+ :id="inputId"
493
+ :clearButton="!!searchTerm"
494
+ :mask="pidMask"
495
+ :maskOptions="{ lazy: true }"
496
+ @input="handleInput"
497
+ @clearInput="handleClear"
498
+ />
499
+ <FdsIcon
500
+ v-if="!disabled && !hasInputValue"
501
+ name="search"
502
+ :size="24"
503
+ class="absolute right-3 bottom-6 translate-y-1/2 fill-blue-500"
504
+ />
505
+ </div>
506
+ </div>
507
+ <div v-else>
508
+ <div class="font-bold mb-2 tracking-wide">{{ singleItemLabel }}</div>
509
+ <div>{{ singleItemName }}</div>
510
+ </div>
511
+
512
+ <!-- Dropdown List -->
513
+ <div
514
+ v-if="dropdownVisible && !singleItemName.length && !disabled"
515
+ :class="listWrapperClasses"
516
+ :style="listWrapperStyle"
517
+ aria-haspopup="listbox"
518
+ aria-expanded="false"
519
+ aria-controls="select-dropdown"
520
+ >
521
+ <!-- Loading -->
522
+ <div
523
+ v-if="loading"
524
+ class="flex justify-center p-4"
525
+ >
526
+ <FdsSpinner
527
+ color="blue"
528
+ size="48px"
529
+ />
530
+ </div>
531
+
532
+ <!-- Results -->
533
+ <template v-else-if="displayedItems && displayedItems.length">
534
+ <!-- Header -->
535
+ <div
536
+ v-if="searchTerm && searchTerm.length"
537
+ class="block m-0 font-light p-6 border-b border-gray-200 rounded-t-md"
538
+ >
539
+ {{ displayedItems.length }} {{ searchContext.linkWord }} {{ totalCount }}
540
+ {{ searchContext.context }}
541
+ </div>
542
+ <div
543
+ v-else-if="!searchTerm.length"
544
+ class="block m-0 font-light p-4 border-b border-gray-200 rounded-t-md"
545
+ >
546
+ {{ totalCount }} {{ searchContext.context }}
547
+ </div>
548
+
549
+ <!-- List -->
550
+ <ul
551
+ class="block m-0 list-none p-0"
552
+ role="listbox"
553
+ id="select-dropdown"
554
+ @keydown="handleListKeyDown"
555
+ >
556
+ <li
557
+ v-for="(item, index) in displayedItems"
558
+ :key="index"
559
+ :id="`search-select-item-${index}`"
560
+ class="block m-0 hover:outline-none focus:outline-2 focus:outline-blue-500 -outline-offset-2"
561
+ :class="[focusedIndex === index && 'outline-dashed outline-2 outline-blue-500 -outline-offset-2 ']"
562
+ role="option"
563
+ :aria-selected="focusedIndex === index"
564
+ :tabindex="dropdownVisible && focusedIndex === index ? 0 : -1"
565
+ @mouseup="(e) => handleClick(e, item)"
566
+ @mouseenter="focusedIndex = index"
567
+ @keydown.enter="(e) => handleClick(e, item)"
568
+ @keydown.space.prevent="(e) => handleClick(e, item)"
569
+ >
570
+ <input
571
+ type="radio"
572
+ :id="`search-select-radio-${index}`"
573
+ name="social-account"
574
+ class="absolute left-0 opacity-0"
575
+ :checked="focusedIndex === index"
576
+ :key="`radio-${index}-${focusedIndex}`"
577
+ tabindex="-1"
578
+ />
579
+ <label
580
+ :for="`search-select-radio-${index}`"
581
+ class="block p-4 text-gray-700 cursor-pointer no-underline"
582
+ :class="listItemClasses"
583
+ v-html="handleMatchingString(item)"
584
+ ></label>
585
+ </li>
586
+ </ul>
587
+
588
+ <!-- Pagination -->
589
+ <FdsPagination
590
+ v-if="page !== undefined && totalPages !== null && totalPages > 1"
591
+ :current="page"
592
+ :max="totalPages"
593
+ @paginate="handlePagination"
594
+ class="my-4! px-2"
595
+ />
596
+ </template>
597
+
598
+ <!-- No Results -->
599
+ <ul
600
+ v-else-if="!loading"
601
+ class="block m-0 list-none p-0"
602
+ >
603
+ <li class="p-4">
604
+ {{ noResultPrompt }}
605
+ </li>
606
+ </ul>
607
+ </div>
608
+ </div>
609
+ </div>
610
+ </template>
@@ -0,0 +1,25 @@
1
+ export interface FdsSearchSelectProps {
2
+ items: Array<Record<string, unknown>>
3
+ page?: number
4
+ totalPages?: number
5
+ totalCount?: number
6
+ loading?: boolean
7
+ searchFields?: string[]
8
+ preserveOrder?: boolean
9
+ initialValue?: string
10
+ disabled?: boolean
11
+ dropdownAbsolute?: boolean
12
+ labelLeft?: boolean
13
+ label?: string
14
+ meta?: string | null
15
+ singleItemLabel?: string
16
+ searchContext?: { context: string; linkWord: string }
17
+ valid?: string
18
+ invalidMessage?: string
19
+ noResultPrompt?: string
20
+ borderless?: boolean
21
+ marginless?: boolean
22
+ maxListHeight?: number | string
23
+ locale?: 'sv' | 'en'
24
+ clearTrigger?: boolean
25
+ }
@@ -0,0 +1,31 @@
1
+ import type { Meta, StoryObj } from '@storybook/vue3'
2
+ import FdsSpinner from './FdsSpinner.vue'
3
+
4
+ const meta: Meta<typeof FdsSpinner> = {
5
+ title: 'FDS/FdsSpinner',
6
+ component: FdsSpinner,
7
+ tags: ['autodocs'],
8
+ argTypes: {
9
+ size: { control: { type: 'text' } },
10
+ color: { control: { type: 'inline-radio' }, options: ['inherit', 'black', 'white', 'blue'] },
11
+ label: { control: { type: 'text' } },
12
+ labelPosition: { control: { type: 'inline-radio' }, options: ['right', 'bottom'] },
13
+ },
14
+ args: {
15
+ size: '48px',
16
+ color: 'inherit',
17
+ label: '',
18
+ labelPosition: 'bottom',
19
+ },
20
+ }
21
+
22
+ export default meta
23
+ type Story = StoryObj<typeof meta>
24
+
25
+ export const Basic: Story = {
26
+ render: (args) => ({
27
+ components: { FdsSpinner },
28
+ setup: () => ({ args }),
29
+ template: '<FdsSpinner v-bind="args" />',
30
+ }),
31
+ }