@verdaccio/ui-components 5.0.0-next-9.23 → 5.0.0-next-9.25

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 (306) hide show
  1. package/README.md +20 -0
  2. package/build/api/use-data.d.ts +2 -2
  3. package/build/api/use-data.js +2 -2
  4. package/build/api/use-data.js.map +1 -1
  5. package/build/api/use-data.mjs +2 -2
  6. package/build/api/use-data.mjs.map +1 -1
  7. package/build/components/CopyClipboard/CopyToClipBoard.d.ts +1 -0
  8. package/build/components/CopyClipboard/CopyToClipBoard.js +36 -17
  9. package/build/components/CopyClipboard/CopyToClipBoard.js.map +1 -1
  10. package/build/components/CopyClipboard/CopyToClipBoard.mjs +36 -19
  11. package/build/components/CopyClipboard/CopyToClipBoard.mjs.map +1 -1
  12. package/build/components/CopyClipboard/utils.d.ts +2 -1
  13. package/build/components/CopyClipboard/utils.js +6 -4
  14. package/build/components/CopyClipboard/utils.js.map +1 -1
  15. package/build/components/CopyClipboard/utils.mjs +6 -4
  16. package/build/components/CopyClipboard/utils.mjs.map +1 -1
  17. package/build/components/DocsLink/DocsLink.d.ts +8 -0
  18. package/build/components/DocsLink/DocsLink.js +40 -0
  19. package/build/components/DocsLink/DocsLink.js.map +1 -0
  20. package/build/components/DocsLink/DocsLink.mjs +35 -0
  21. package/build/components/DocsLink/DocsLink.mjs.map +1 -0
  22. package/build/components/DocsLink/index.d.ts +1 -0
  23. package/build/components/DocsLink/index.js +3 -0
  24. package/build/components/DocsLink/index.mjs +1 -0
  25. package/build/components/Help/Help.d.ts +13 -0
  26. package/build/components/Help/Help.js +243 -36
  27. package/build/components/Help/Help.js.map +1 -1
  28. package/build/components/Help/Help.mjs +237 -39
  29. package/build/components/Help/Help.mjs.map +1 -1
  30. package/build/components/Help/styles.d.ts +29 -0
  31. package/build/components/Help/styles.js +86 -1
  32. package/build/components/Help/styles.js.map +1 -1
  33. package/build/components/Help/styles.mjs +82 -2
  34. package/build/components/Help/styles.mjs.map +1 -1
  35. package/build/components/Icons/Managers/Bun.d.ts +2 -0
  36. package/build/components/Icons/Managers/Bun2.js +18 -0
  37. package/build/components/Icons/Managers/Bun2.js.map +1 -0
  38. package/build/components/Icons/Managers/Bun2.mjs +16 -0
  39. package/build/components/Icons/Managers/Bun2.mjs.map +1 -0
  40. package/build/components/Icons/Managers/bun.js +6 -0
  41. package/build/components/Icons/Managers/bun.js.map +1 -0
  42. package/build/components/Icons/Managers/bun.mjs +6 -0
  43. package/build/components/Icons/Managers/bun.mjs.map +1 -0
  44. package/build/components/Icons/Managers/bun.svg +1 -0
  45. package/build/components/Icons/Managers/index.d.ts +1 -0
  46. package/build/components/Icons/Managers/index.js +2 -0
  47. package/build/components/Icons/Managers/index.mjs +2 -1
  48. package/build/components/Icons/index.js +3 -0
  49. package/build/components/Icons/index.mjs +3 -1
  50. package/build/components/Install/Install.d.ts +2 -0
  51. package/build/components/Install/Install.js +30 -2
  52. package/build/components/Install/Install.js.map +1 -1
  53. package/build/components/Install/Install.mjs +30 -3
  54. package/build/components/Install/Install.mjs.map +1 -1
  55. package/build/components/Install/InstallListItem.d.ts +2 -1
  56. package/build/components/Install/InstallListItem.js +17 -0
  57. package/build/components/Install/InstallListItem.js.map +1 -1
  58. package/build/components/Install/InstallListItem.mjs +17 -0
  59. package/build/components/Install/InstallListItem.mjs.map +1 -1
  60. package/build/components/Loading/PackageListSkeleton.d.ts +3 -0
  61. package/build/components/Loading/PackageListSkeleton.js +70 -0
  62. package/build/components/Loading/PackageListSkeleton.js.map +1 -0
  63. package/build/components/Loading/PackageListSkeleton.mjs +65 -0
  64. package/build/components/Loading/PackageListSkeleton.mjs.map +1 -0
  65. package/build/components/Loading/VersionSkeleton.d.ts +3 -0
  66. package/build/components/Loading/VersionSkeleton.js +119 -0
  67. package/build/components/Loading/VersionSkeleton.js.map +1 -0
  68. package/build/components/Loading/VersionSkeleton.mjs +111 -0
  69. package/build/components/Loading/VersionSkeleton.mjs.map +1 -0
  70. package/build/components/Loading/index.d.ts +2 -0
  71. package/build/components/Loading/index.js +4 -0
  72. package/build/components/Loading/index.mjs +4 -1
  73. package/build/components/Package/Package.js +5 -1
  74. package/build/components/Package/Package.js.map +1 -1
  75. package/build/components/Package/Package.mjs +6 -2
  76. package/build/components/Package/Package.mjs.map +1 -1
  77. package/build/components/Package/styles.d.ts +3 -0
  78. package/build/components/Package/styles.js +8 -0
  79. package/build/components/Package/styles.js.map +1 -1
  80. package/build/components/Package/styles.mjs +8 -1
  81. package/build/components/Package/styles.mjs.map +1 -1
  82. package/build/components/PackageList/PackageList.js +4 -4
  83. package/build/components/PackageList/PackageList.js.map +1 -1
  84. package/build/components/PackageList/PackageList.mjs +5 -5
  85. package/build/components/PackageList/PackageList.mjs.map +1 -1
  86. package/build/components/PackageList/PackageListToolbar.d.ts +15 -0
  87. package/build/components/PackageList/PackageListToolbar.js +127 -0
  88. package/build/components/PackageList/PackageListToolbar.js.map +1 -0
  89. package/build/components/PackageList/PackageListToolbar.mjs +119 -0
  90. package/build/components/PackageList/PackageListToolbar.mjs.map +1 -0
  91. package/build/components/PackageList/filterPackages.d.ts +16 -0
  92. package/build/components/PackageList/filterPackages.js +37 -0
  93. package/build/components/PackageList/filterPackages.js.map +1 -0
  94. package/build/components/PackageList/filterPackages.mjs +34 -0
  95. package/build/components/PackageList/filterPackages.mjs.map +1 -0
  96. package/build/components/RegistryInfoDialog/RegistryInfoDialog.js +18 -7
  97. package/build/components/RegistryInfoDialog/RegistryInfoDialog.js.map +1 -1
  98. package/build/components/RegistryInfoDialog/RegistryInfoDialog.mjs +18 -7
  99. package/build/components/RegistryInfoDialog/RegistryInfoDialog.mjs.map +1 -1
  100. package/build/components/RegistryInfoDialog/types.d.ts +1 -0
  101. package/build/components/Search/AutoComplete/AutoComplete.d.ts +3 -0
  102. package/build/components/Search/AutoComplete/AutoComplete.js +3 -1
  103. package/build/components/Search/AutoComplete/AutoComplete.js.map +1 -1
  104. package/build/components/Search/AutoComplete/AutoComplete.mjs +3 -1
  105. package/build/components/Search/AutoComplete/AutoComplete.mjs.map +1 -1
  106. package/build/components/Search/Search.js +28 -1
  107. package/build/components/Search/Search.js.map +1 -1
  108. package/build/components/Search/Search.mjs +31 -5
  109. package/build/components/Search/Search.mjs.map +1 -1
  110. package/build/components/Search/SearchItem.d.ts +12 -1
  111. package/build/components/Search/SearchItem.js +53 -70
  112. package/build/components/Search/SearchItem.js.map +1 -1
  113. package/build/components/Search/SearchItem.mjs +51 -67
  114. package/build/components/Search/SearchItem.mjs.map +1 -1
  115. package/build/components/Search/utils.d.ts +10 -0
  116. package/build/components/Search/utils.js +28 -1
  117. package/build/components/Search/utils.js.map +1 -1
  118. package/build/components/Search/utils.mjs +26 -2
  119. package/build/components/Search/utils.mjs.map +1 -1
  120. package/build/components/SettingsMenu/SettingsMenu.js +2 -2
  121. package/build/components/SettingsMenu/SettingsMenu.mjs +1 -1
  122. package/build/components/Versions/Versions.js +8 -2
  123. package/build/components/Versions/Versions.js.map +1 -1
  124. package/build/components/Versions/Versions.mjs +8 -2
  125. package/build/components/Versions/Versions.mjs.map +1 -1
  126. package/build/components/VisuallyHidden/index.d.ts +5 -0
  127. package/build/components/VisuallyHidden/index.js +17 -0
  128. package/build/components/VisuallyHidden/index.js.map +1 -0
  129. package/build/components/VisuallyHidden/index.mjs +15 -0
  130. package/build/components/VisuallyHidden/index.mjs.map +1 -0
  131. package/build/configuration.js +2 -1
  132. package/build/configuration.js.map +1 -1
  133. package/build/configuration.mjs +2 -1
  134. package/build/configuration.mjs.map +1 -1
  135. package/build/i18n/ABOUT_TRANSLATIONS.md +19 -0
  136. package/build/i18n/crowdin/ui.js +378 -0
  137. package/build/i18n/crowdin/ui.js.map +1 -0
  138. package/build/i18n/crowdin/ui.json +345 -0
  139. package/build/i18n/crowdin/ui.mjs +355 -0
  140. package/build/i18n/crowdin/ui.mjs.map +1 -0
  141. package/build/i18n/download_translations/cs-CZ/ui.js +376 -0
  142. package/build/i18n/download_translations/cs-CZ/ui.js.map +1 -0
  143. package/build/i18n/download_translations/cs-CZ/ui.json +345 -0
  144. package/build/i18n/download_translations/cs-CZ/ui.mjs +354 -0
  145. package/build/i18n/download_translations/cs-CZ/ui.mjs.map +1 -0
  146. package/build/i18n/download_translations/de-DE/ui.js +376 -0
  147. package/build/i18n/download_translations/de-DE/ui.js.map +1 -0
  148. package/build/i18n/download_translations/de-DE/ui.json +345 -0
  149. package/build/i18n/download_translations/de-DE/ui.mjs +354 -0
  150. package/build/i18n/download_translations/de-DE/ui.mjs.map +1 -0
  151. package/build/i18n/download_translations/es-ES/ui.js +376 -0
  152. package/build/i18n/download_translations/es-ES/ui.js.map +1 -0
  153. package/build/i18n/download_translations/es-ES/ui.json +345 -0
  154. package/build/i18n/download_translations/es-ES/ui.mjs +354 -0
  155. package/build/i18n/download_translations/es-ES/ui.mjs.map +1 -0
  156. package/build/i18n/download_translations/fr-FR/ui.js +376 -0
  157. package/build/i18n/download_translations/fr-FR/ui.js.map +1 -0
  158. package/build/i18n/download_translations/fr-FR/ui.json +345 -0
  159. package/build/i18n/download_translations/fr-FR/ui.mjs +354 -0
  160. package/build/i18n/download_translations/fr-FR/ui.mjs.map +1 -0
  161. package/build/i18n/download_translations/ga-IE/ui.js +376 -0
  162. package/build/i18n/download_translations/ga-IE/ui.js.map +1 -0
  163. package/build/i18n/download_translations/ga-IE/ui.json +345 -0
  164. package/build/i18n/download_translations/ga-IE/ui.mjs +354 -0
  165. package/build/i18n/download_translations/ga-IE/ui.mjs.map +1 -0
  166. package/build/i18n/download_translations/gl-ES/ui.js +376 -0
  167. package/build/i18n/download_translations/gl-ES/ui.js.map +1 -0
  168. package/build/i18n/download_translations/gl-ES/ui.json +345 -0
  169. package/build/i18n/download_translations/gl-ES/ui.mjs +354 -0
  170. package/build/i18n/download_translations/gl-ES/ui.mjs.map +1 -0
  171. package/build/i18n/download_translations/it-IT/ui.js +376 -0
  172. package/build/i18n/download_translations/it-IT/ui.js.map +1 -0
  173. package/build/i18n/download_translations/it-IT/ui.json +345 -0
  174. package/build/i18n/download_translations/it-IT/ui.mjs +354 -0
  175. package/build/i18n/download_translations/it-IT/ui.mjs.map +1 -0
  176. package/build/i18n/download_translations/ko-KR/ui.js +376 -0
  177. package/build/i18n/download_translations/ko-KR/ui.js.map +1 -0
  178. package/build/i18n/download_translations/ko-KR/ui.json +345 -0
  179. package/build/i18n/download_translations/ko-KR/ui.mjs +354 -0
  180. package/build/i18n/download_translations/ko-KR/ui.mjs.map +1 -0
  181. package/build/i18n/download_translations/pl-PL/ui.js +376 -0
  182. package/build/i18n/download_translations/pl-PL/ui.js.map +1 -0
  183. package/build/i18n/download_translations/pl-PL/ui.json +345 -0
  184. package/build/i18n/download_translations/pl-PL/ui.mjs +354 -0
  185. package/build/i18n/download_translations/pl-PL/ui.mjs.map +1 -0
  186. package/build/i18n/download_translations/pt-BR/ui.js +376 -0
  187. package/build/i18n/download_translations/pt-BR/ui.js.map +1 -0
  188. package/build/i18n/download_translations/pt-BR/ui.json +345 -0
  189. package/build/i18n/download_translations/pt-BR/ui.mjs +354 -0
  190. package/build/i18n/download_translations/pt-BR/ui.mjs.map +1 -0
  191. package/build/i18n/download_translations/ru-RU/ui.js +376 -0
  192. package/build/i18n/download_translations/ru-RU/ui.js.map +1 -0
  193. package/build/i18n/download_translations/ru-RU/ui.json +345 -0
  194. package/build/i18n/download_translations/ru-RU/ui.mjs +354 -0
  195. package/build/i18n/download_translations/ru-RU/ui.mjs.map +1 -0
  196. package/build/i18n/download_translations/sr-CS/ui.js +373 -0
  197. package/build/i18n/download_translations/sr-CS/ui.js.map +1 -0
  198. package/build/i18n/download_translations/sr-CS/ui.json +345 -0
  199. package/build/i18n/download_translations/sr-CS/ui.mjs +352 -0
  200. package/build/i18n/download_translations/sr-CS/ui.mjs.map +1 -0
  201. package/build/i18n/download_translations/tr-TR/ui.js +376 -0
  202. package/build/i18n/download_translations/tr-TR/ui.js.map +1 -0
  203. package/build/i18n/download_translations/tr-TR/ui.json +345 -0
  204. package/build/i18n/download_translations/tr-TR/ui.mjs +354 -0
  205. package/build/i18n/download_translations/tr-TR/ui.mjs.map +1 -0
  206. package/build/i18n/download_translations/vi-VN/ui.js +373 -0
  207. package/build/i18n/download_translations/vi-VN/ui.js.map +1 -0
  208. package/build/i18n/download_translations/vi-VN/ui.json +345 -0
  209. package/build/i18n/download_translations/vi-VN/ui.mjs +352 -0
  210. package/build/i18n/download_translations/vi-VN/ui.mjs.map +1 -0
  211. package/build/i18n/download_translations/yo-NG/ui.js +373 -0
  212. package/build/i18n/download_translations/yo-NG/ui.js.map +1 -0
  213. package/build/i18n/download_translations/yo-NG/ui.json +345 -0
  214. package/build/i18n/download_translations/yo-NG/ui.mjs +352 -0
  215. package/build/i18n/download_translations/yo-NG/ui.mjs.map +1 -0
  216. package/build/i18n/download_translations/zh-CN/ui.js +376 -0
  217. package/build/i18n/download_translations/zh-CN/ui.js.map +1 -0
  218. package/build/i18n/download_translations/zh-CN/ui.json +345 -0
  219. package/build/i18n/download_translations/zh-CN/ui.mjs +354 -0
  220. package/build/i18n/download_translations/zh-CN/ui.mjs.map +1 -0
  221. package/build/i18n/download_translations/zh-TW/ui.js +376 -0
  222. package/build/i18n/download_translations/zh-TW/ui.js.map +1 -0
  223. package/build/i18n/download_translations/zh-TW/ui.json +345 -0
  224. package/build/i18n/download_translations/zh-TW/ui.mjs +354 -0
  225. package/build/i18n/download_translations/zh-TW/ui.mjs.map +1 -0
  226. package/build/i18n/loadTranslationFile.d.ts +6 -0
  227. package/build/i18n/loadTranslationFile.js +52 -0
  228. package/build/i18n/loadTranslationFile.js.map +1 -0
  229. package/build/i18n/loadTranslationFile.mjs +51 -0
  230. package/build/i18n/loadTranslationFile.mjs.map +1 -0
  231. package/build/i18n/translationProgress.d.ts +6 -0
  232. package/build/i18n/translationProgress.js +29 -0
  233. package/build/i18n/translationProgress.js.map +1 -0
  234. package/build/i18n/translationProgress.mjs +29 -0
  235. package/build/i18n/translationProgress.mjs.map +1 -0
  236. package/build/index.d.ts +2 -0
  237. package/build/index.js +11 -0
  238. package/build/index.mjs +5 -2
  239. package/build/mockServiceWorker.js +1 -0
  240. package/build/pages/Version/Version.js +2 -2
  241. package/build/pages/Version/Version.js.map +1 -1
  242. package/build/pages/Version/Version.mjs +2 -2
  243. package/build/pages/Version/Version.mjs.map +1 -1
  244. package/build/providers/AppConfigurationProvider/AppConfigurationProvider.js +3 -1
  245. package/build/providers/AppConfigurationProvider/AppConfigurationProvider.js.map +1 -1
  246. package/build/providers/AppConfigurationProvider/AppConfigurationProvider.mjs +3 -1
  247. package/build/providers/AppConfigurationProvider/AppConfigurationProvider.mjs.map +1 -1
  248. package/build/providers/ManifestsProvider/ManifestsProvider.d.ts +3 -0
  249. package/build/providers/ManifestsProvider/ManifestsProvider.js +9 -2
  250. package/build/providers/ManifestsProvider/ManifestsProvider.js.map +1 -1
  251. package/build/providers/ManifestsProvider/ManifestsProvider.mjs +10 -4
  252. package/build/providers/ManifestsProvider/ManifestsProvider.mjs.map +1 -1
  253. package/build/sections/Detail/ContainerContent.js +8 -0
  254. package/build/sections/Detail/ContainerContent.js.map +1 -1
  255. package/build/sections/Detail/ContainerContent.mjs +8 -1
  256. package/build/sections/Detail/ContainerContent.mjs.map +1 -1
  257. package/build/sections/Detail/Detail.d.ts +3 -6
  258. package/build/sections/Detail/Detail.js +13 -14
  259. package/build/sections/Detail/Detail.js.map +1 -1
  260. package/build/sections/Detail/Detail.mjs +14 -15
  261. package/build/sections/Detail/Detail.mjs.map +1 -1
  262. package/build/sections/Detail/Tabs.d.ts +3 -2
  263. package/build/sections/Detail/Tabs.js +9 -4
  264. package/build/sections/Detail/Tabs.js.map +1 -1
  265. package/build/sections/Detail/Tabs.mjs +9 -4
  266. package/build/sections/Detail/Tabs.mjs.map +1 -1
  267. package/build/sections/Footer/Footer.js +24 -3
  268. package/build/sections/Footer/Footer.js.map +1 -1
  269. package/build/sections/Footer/Footer.mjs +24 -4
  270. package/build/sections/Footer/Footer.mjs.map +1 -1
  271. package/build/sections/Footer/styles.d.ts +6 -0
  272. package/build/sections/Footer/styles.js +21 -2
  273. package/build/sections/Footer/styles.js.map +1 -1
  274. package/build/sections/Footer/styles.mjs +21 -3
  275. package/build/sections/Footer/styles.mjs.map +1 -1
  276. package/build/sections/Header/HeaderSettingsDialog.js +30 -8
  277. package/build/sections/Header/HeaderSettingsDialog.js.map +1 -1
  278. package/build/sections/Header/HeaderSettingsDialog.mjs +30 -8
  279. package/build/sections/Header/HeaderSettingsDialog.mjs.map +1 -1
  280. package/build/sections/Header/LanguageSwitch.js +95 -70
  281. package/build/sections/Header/LanguageSwitch.js.map +1 -1
  282. package/build/sections/Header/LanguageSwitch.mjs +94 -71
  283. package/build/sections/Header/LanguageSwitch.mjs.map +1 -1
  284. package/build/sections/Header/RegistryInfoContent/RegistryInfoContent.d.ts +1 -4
  285. package/build/sections/Header/RegistryInfoContent/RegistryInfoContent.js +83 -13
  286. package/build/sections/Header/RegistryInfoContent/RegistryInfoContent.js.map +1 -1
  287. package/build/sections/Header/RegistryInfoContent/RegistryInfoContent.mjs +85 -13
  288. package/build/sections/Header/RegistryInfoContent/RegistryInfoContent.mjs.map +1 -1
  289. package/build/sections/Home/Home.js +58 -2
  290. package/build/sections/Home/Home.js.map +1 -1
  291. package/build/sections/Home/Home.mjs +60 -4
  292. package/build/sections/Home/Home.mjs.map +1 -1
  293. package/build/utils/cli-utils.d.ts +10 -0
  294. package/build/utils/cli-utils.js +26 -0
  295. package/build/utils/cli-utils.js.map +1 -1
  296. package/build/utils/cli-utils.mjs +23 -1
  297. package/build/utils/cli-utils.mjs.map +1 -1
  298. package/build/utils/index.d.ts +1 -1
  299. package/build/utils/index.js +4 -0
  300. package/build/utils/index.mjs +2 -2
  301. package/build/utils/markdown.d.ts +6 -0
  302. package/build/utils/markdown.js +14 -0
  303. package/build/utils/markdown.js.map +1 -0
  304. package/build/utils/markdown.mjs +12 -0
  305. package/build/utils/markdown.mjs.map +1 -0
  306. package/package.json +8 -9
@@ -1,18 +1,20 @@
1
1
  import { Route as Route$1 } from "../../utils/routes.mjs";
2
2
  import "../../utils/index.mjs";
3
+ import { useConfig } from "../../providers/AppConfigurationProvider/AppConfigurationProvider.mjs";
3
4
  import { useSearch } from "../../providers/SearchProvider/SearchProvider.mjs";
4
5
  import AutoComplete from "./AutoComplete/AutoComplete.mjs";
5
6
  import "./AutoComplete/index.mjs";
6
- import { normalizeSearchOption } from "./utils.mjs";
7
- import SearchItem from "./SearchItem.mjs";
7
+ import { normalizeSearchOption, sortByOrigin } from "./utils.mjs";
8
+ import SearchItem, { ORIGIN_ICONS } from "./SearchItem.mjs";
8
9
  import { StyledInputAdornment, StyledTextField } from "./styles.mjs";
9
10
  import "../../index.mjs";
10
- import { useCallback, useEffect, useMemo, useRef, useState } from "react";
11
+ import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
11
12
  import { useTranslation } from "react-i18next";
12
- import { jsx } from "react/jsx-runtime";
13
+ import { jsx, jsxs } from "react/jsx-runtime";
13
14
  import { debounce } from "lodash-es";
14
15
  import { useNavigate } from "react-router";
15
16
  import SearchMui from "@mui/icons-material/Search";
17
+ import ListSubheader from "@mui/material/ListSubheader";
16
18
  //#region src/components/Search/Search.tsx
17
19
  var CONSTANTS = {
18
20
  API_DELAY: 300,
@@ -22,6 +24,9 @@ var Search = () => {
22
24
  const { t } = useTranslation();
23
25
  const navigate = useNavigate();
24
26
  const { searchResults, isLoading, isError, doSearch, resetSearch } = useSearch();
27
+ const { configOptions } = useConfig();
28
+ const groupByOrigin = configOptions?.showUplinks === true;
29
+ const suggestions = useMemo(() => groupByOrigin && searchResults ? sortByOrigin(searchResults) : searchResults, [groupByOrigin, searchResults]);
25
30
  const abortControllerRef = useRef(null);
26
31
  const cancelAllSearchRequests = useCallback(() => {
27
32
  if (abortControllerRef.current) {
@@ -104,19 +109,40 @@ var Search = () => {
104
109
  variant: "standard"
105
110
  });
106
111
  };
112
+ const getOptionGroup = (option) => normalizeSearchOption(option).origin ?? "";
113
+ const renderGroup = ({ key, group, children }) => {
114
+ if (!group) return /* @__PURE__ */ jsx(React.Fragment, { children }, key);
115
+ const OriginIcon = ORIGIN_ICONS[group];
116
+ return /* @__PURE__ */ jsxs("li", { children: [/* @__PURE__ */ jsxs(ListSubheader, {
117
+ component: "div",
118
+ "data-testid": `search-group-${group}`,
119
+ sx: {
120
+ display: "flex",
121
+ alignItems: "center",
122
+ gap: 1,
123
+ lineHeight: "36px"
124
+ },
125
+ children: [OriginIcon && /* @__PURE__ */ jsx(OriginIcon, { fontSize: "small" }), t(`search.group.${group}`, { count: React.Children.count(children) })]
126
+ }), /* @__PURE__ */ jsx("ul", {
127
+ style: { padding: 0 },
128
+ children
129
+ })] }, key);
130
+ };
107
131
  const getOptionLabel = (option) => {
108
132
  return normalizeSearchOption(option).name;
109
133
  };
110
134
  return /* @__PURE__ */ jsx(AutoComplete, {
111
135
  getOptionLabel,
136
+ groupBy: groupByOrigin ? getOptionGroup : void 0,
112
137
  hasError: isError,
113
138
  onCleanSuggestions: handleOnBlur,
114
139
  onSelectItem: handleClickSearch,
115
140
  onSuggestionsFetch: handleSuggestionsFetch,
116
141
  placeholder: t("search.packages"),
142
+ renderGroup: groupByOrigin ? renderGroup : void 0,
117
143
  renderInput,
118
144
  renderOption,
119
- suggestions: searchResults,
145
+ suggestions,
120
146
  suggestionsLoading: isLoading || isDebouncing
121
147
  });
122
148
  };
@@ -1 +1 @@
1
- {"version":3,"file":"Search.mjs","names":["Route"],"sources":["../../../src/components/Search/Search.tsx"],"sourcesContent":["import SearchMui from '@mui/icons-material/Search';\nimport { debounce } from 'lodash-es';\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { useNavigate } from 'react-router';\n\nimport { useSearch } from '../../';\nimport { Route } from '../../utils';\nimport AutoComplete from './AutoComplete';\nimport SearchItem from './SearchItem';\nimport { StyledInputAdornment, StyledTextField } from './styles';\nimport { normalizeSearchOption } from './utils';\n\nconst CONSTANTS = {\n API_DELAY: 300,\n ABORT_ERROR: 'AbortError',\n};\n\nconst Search: React.FC = () => {\n const { t } = useTranslation();\n const navigate = useNavigate();\n const { searchResults, isLoading, isError, doSearch, resetSearch } = useSearch();\n\n const abortControllerRef = useRef<AbortController | null>(null);\n\n const cancelAllSearchRequests = useCallback(() => {\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n abortControllerRef.current = null;\n }\n }, []);\n\n const handleOnBlur = useCallback(\n (event: React.SyntheticEvent) => {\n event.stopPropagation();\n cancelAllSearchRequests();\n },\n [cancelAllSearchRequests]\n );\n\n const handleClickSearch = useCallback(\n (event: React.SyntheticEvent, value: any, reason: string): void => {\n event.stopPropagation();\n if (reason === 'selectOption') {\n const { name } = normalizeSearchOption(value);\n if (name) {\n navigate(`${Route.DETAIL}${name}`);\n }\n }\n },\n [navigate]\n );\n\n // Use a ref to always access the latest doSearch without re-creating the debounced function\n const doSearchRef = useRef(doSearch);\n doSearchRef.current = doSearch;\n\n // shows the dropdown as loading during the debounce window; without it the\n // immediate reset below reads as \"no results found\" on every keystroke\n const [isDebouncing, setIsDebouncing] = useState(false);\n\n /**\n * Stable fetch function that reads the latest doSearch from a ref,\n * avoiding dependency changes that would break the debounce.\n */\n const handleFetchPackages = useCallback(\n async ({ value }: { value: string }) => {\n setIsDebouncing(false);\n if (value?.trim() !== '') {\n // Abort any previous pending request before starting a new one\n cancelAllSearchRequests();\n\n // Create a new controller for the current request\n const controller = new AbortController();\n abortControllerRef.current = controller;\n\n try {\n await doSearchRef.current?.({\n text: value,\n signal: controller.signal,\n });\n } catch (err: any) {\n if (err.name === CONSTANTS.ABORT_ERROR) {\n console.warn('Search request aborted');\n } else {\n console.error('Search error:', err);\n }\n }\n }\n },\n [cancelAllSearchRequests]\n );\n\n // Memoize the debounced function so a single instance is reused across renders,\n // ensuring the debounce timer works correctly instead of creating a new timer per render.\n const debouncedFetch = useMemo(\n () => debounce(handleFetchPackages, CONSTANTS.API_DELAY),\n [handleFetchPackages]\n );\n\n // clear the previous query's results right away so the dropdown never lists\n // stale suggestions under the new input while the debounce timer runs\n const handleSuggestionsFetch = useCallback(\n ({ value }: { value: string }) => {\n resetSearch?.();\n if (value?.trim() !== '') {\n setIsDebouncing(true);\n }\n debouncedFetch({ value });\n },\n [resetSearch, debouncedFetch]\n );\n\n useEffect(() => {\n return () => {\n debouncedFetch.cancel?.();\n cancelAllSearchRequests();\n };\n }, [debouncedFetch, cancelAllSearchRequests]);\n\n const renderOption = (props, option) => {\n const { key, ...otherProps } = props;\n const { name, version, description, isPrivate, isCached, isRemote } =\n normalizeSearchOption(option);\n return (\n <SearchItem\n key={key}\n {...otherProps}\n description={description}\n isCached={isCached}\n isPrivate={isPrivate}\n isRemote={isRemote}\n name={name}\n version={version}\n />\n );\n };\n\n const renderInput = (params) => {\n return (\n <StyledTextField\n {...params}\n InputProps={{\n ...params.InputProps,\n startAdornment: (\n <StyledInputAdornment position=\"start\">\n <SearchMui />\n </StyledInputAdornment>\n ),\n }}\n label=\"\"\n placeholder={t('search.packages')}\n variant=\"standard\"\n />\n );\n };\n\n const getOptionLabel = (option) => {\n return normalizeSearchOption(option).name;\n };\n\n return (\n <AutoComplete\n getOptionLabel={getOptionLabel}\n hasError={isError}\n onCleanSuggestions={handleOnBlur}\n onSelectItem={handleClickSearch}\n onSuggestionsFetch={handleSuggestionsFetch}\n placeholder={t('search.packages')}\n renderInput={renderInput}\n renderOption={renderOption}\n suggestions={searchResults}\n suggestionsLoading={isLoading || isDebouncing}\n />\n );\n};\n\nexport default Search;\n"],"mappings":";;;;;;;;;;;;;;;;AAaA,IAAM,YAAY;CAChB,WAAW;CACX,aAAa;AACf;AAEA,IAAM,eAAyB;CAC7B,MAAM,EAAE,MAAM,eAAe;CAC7B,MAAM,WAAW,YAAY;CAC7B,MAAM,EAAE,eAAe,WAAW,SAAS,UAAU,gBAAgB,UAAU;CAE/E,MAAM,qBAAqB,OAA+B,IAAI;CAE9D,MAAM,0BAA0B,kBAAkB;EAChD,IAAI,mBAAmB,SAAS;GAC9B,mBAAmB,QAAQ,MAAM;GACjC,mBAAmB,UAAU;EAC/B;CACF,GAAG,CAAC,CAAC;CAEL,MAAM,eAAe,aAClB,UAAgC;EAC/B,MAAM,gBAAgB;EACtB,wBAAwB;CAC1B,GACA,CAAC,uBAAuB,CAC1B;CAEA,MAAM,oBAAoB,aACvB,OAA6B,OAAY,WAAyB;EACjE,MAAM,gBAAgB;EACtB,IAAI,WAAW,gBAAgB;GAC7B,MAAM,EAAE,SAAS,sBAAsB,KAAK;GAC5C,IAAI,MACF,SAAS,GAAGA,QAAM,SAAS,MAAM;EAErC;CACF,GACA,CAAC,QAAQ,CACX;CAGA,MAAM,cAAc,OAAO,QAAQ;CACnC,YAAY,UAAU;CAItB,MAAM,CAAC,cAAc,mBAAmB,SAAS,KAAK;;;;;CAMtD,MAAM,sBAAsB,YAC1B,OAAO,EAAE,YAA+B;EACtC,gBAAgB,KAAK;EACrB,IAAI,OAAO,KAAK,MAAM,IAAI;GAExB,wBAAwB;GAGxB,MAAM,aAAa,IAAI,gBAAgB;GACvC,mBAAmB,UAAU;GAE7B,IAAI;IACF,MAAM,YAAY,UAAU;KAC1B,MAAM;KACN,QAAQ,WAAW;IACrB,CAAC;GACH,SAAS,KAAU;IACjB,IAAI,IAAI,SAAS,UAAU,aACzB,QAAQ,KAAK,wBAAwB;SAErC,QAAQ,MAAM,iBAAiB,GAAG;GAEtC;EACF;CACF,GACA,CAAC,uBAAuB,CAC1B;CAIA,MAAM,iBAAiB,cACf,SAAS,qBAAqB,UAAU,SAAS,GACvD,CAAC,mBAAmB,CACtB;CAIA,MAAM,yBAAyB,aAC5B,EAAE,YAA+B;EAChC,cAAc;EACd,IAAI,OAAO,KAAK,MAAM,IACpB,gBAAgB,IAAI;EAEtB,eAAe,EAAE,MAAM,CAAC;CAC1B,GACA,CAAC,aAAa,cAAc,CAC9B;CAEA,gBAAgB;EACd,aAAa;GACX,eAAe,SAAS;GACxB,wBAAwB;EAC1B;CACF,GAAG,CAAC,gBAAgB,uBAAuB,CAAC;CAE5C,MAAM,gBAAgB,OAAO,WAAW;EACtC,MAAM,EAAE,KAAK,GAAG,eAAe;EAC/B,MAAM,EAAE,MAAM,SAAS,aAAa,WAAW,UAAU,aACvD,sBAAsB,MAAM;EAC9B,OACE,oBAAC,YAAD;GAEE,GAAI;GACS;GACH;GACC;GACD;GACJ;GACG;EACV,GARM,GAQN;CAEL;CAEA,MAAM,eAAe,WAAW;EAC9B,OACE,oBAAC,iBAAD;GACE,GAAI;GACJ,YAAY;IACV,GAAG,OAAO;IACV,gBACE,oBAAC,sBAAD;KAAsB,UAAS;KAC7B,UAAA,oBAAC,WAAD,CAAY,CAAA;IACQ,CAAA;GAE1B;GACA,OAAM;GACN,aAAa,EAAE,iBAAiB;GAChC,SAAQ;EACT,CAAA;CAEL;CAEA,MAAM,kBAAkB,WAAW;EACjC,OAAO,sBAAsB,MAAM,CAAC,CAAC;CACvC;CAEA,OACE,oBAAC,cAAD;EACkB;EAChB,UAAU;EACV,oBAAoB;EACpB,cAAc;EACd,oBAAoB;EACpB,aAAa,EAAE,iBAAiB;EACnB;EACC;EACd,aAAa;EACb,oBAAoB,aAAa;CAClC,CAAA;AAEL"}
1
+ {"version":3,"file":"Search.mjs","names":["Route"],"sources":["../../../src/components/Search/Search.tsx"],"sourcesContent":["import SearchMui from '@mui/icons-material/Search';\nimport type { AutocompleteRenderGroupParams } from '@mui/material/Autocomplete';\nimport ListSubheader from '@mui/material/ListSubheader';\nimport { debounce } from 'lodash-es';\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { useNavigate } from 'react-router';\n\nimport { useConfig, useSearch } from '../../';\nimport { Route } from '../../utils';\nimport AutoComplete from './AutoComplete';\nimport SearchItem, { ORIGIN_ICONS } from './SearchItem';\nimport { StyledInputAdornment, StyledTextField } from './styles';\nimport type { SearchOrigin } from './utils';\nimport { normalizeSearchOption, sortByOrigin } from './utils';\n\nconst CONSTANTS = {\n API_DELAY: 300,\n ABORT_ERROR: 'AbortError',\n};\n\nconst Search: React.FC = () => {\n const { t } = useTranslation();\n const navigate = useNavigate();\n const { searchResults, isLoading, isError, doSearch, resetSearch } = useSearch();\n const { configOptions } = useConfig();\n const groupByOrigin = configOptions?.showUplinks === true;\n const suggestions = useMemo(\n () => (groupByOrigin && searchResults ? sortByOrigin(searchResults) : searchResults),\n [groupByOrigin, searchResults]\n );\n\n const abortControllerRef = useRef<AbortController | null>(null);\n\n const cancelAllSearchRequests = useCallback(() => {\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n abortControllerRef.current = null;\n }\n }, []);\n\n const handleOnBlur = useCallback(\n (event: React.SyntheticEvent) => {\n event.stopPropagation();\n cancelAllSearchRequests();\n },\n [cancelAllSearchRequests]\n );\n\n const handleClickSearch = useCallback(\n (event: React.SyntheticEvent, value: any, reason: string): void => {\n event.stopPropagation();\n if (reason === 'selectOption') {\n const { name } = normalizeSearchOption(value);\n if (name) {\n navigate(`${Route.DETAIL}${name}`);\n }\n }\n },\n [navigate]\n );\n\n // Use a ref to always access the latest doSearch without re-creating the debounced function\n const doSearchRef = useRef(doSearch);\n doSearchRef.current = doSearch;\n\n // shows the dropdown as loading during the debounce window; without it the\n // immediate reset below reads as \"no results found\" on every keystroke\n const [isDebouncing, setIsDebouncing] = useState(false);\n\n /**\n * Stable fetch function that reads the latest doSearch from a ref,\n * avoiding dependency changes that would break the debounce.\n */\n const handleFetchPackages = useCallback(\n async ({ value }: { value: string }) => {\n setIsDebouncing(false);\n if (value?.trim() !== '') {\n // Abort any previous pending request before starting a new one\n cancelAllSearchRequests();\n\n // Create a new controller for the current request\n const controller = new AbortController();\n abortControllerRef.current = controller;\n\n try {\n await doSearchRef.current?.({\n text: value,\n signal: controller.signal,\n });\n } catch (err: any) {\n if (err.name === CONSTANTS.ABORT_ERROR) {\n console.warn('Search request aborted');\n } else {\n console.error('Search error:', err);\n }\n }\n }\n },\n [cancelAllSearchRequests]\n );\n\n // Memoize the debounced function so a single instance is reused across renders,\n // ensuring the debounce timer works correctly instead of creating a new timer per render.\n const debouncedFetch = useMemo(\n () => debounce(handleFetchPackages, CONSTANTS.API_DELAY),\n [handleFetchPackages]\n );\n\n // clear the previous query's results right away so the dropdown never lists\n // stale suggestions under the new input while the debounce timer runs\n const handleSuggestionsFetch = useCallback(\n ({ value }: { value: string }) => {\n resetSearch?.();\n if (value?.trim() !== '') {\n setIsDebouncing(true);\n }\n debouncedFetch({ value });\n },\n [resetSearch, debouncedFetch]\n );\n\n useEffect(() => {\n return () => {\n debouncedFetch.cancel?.();\n cancelAllSearchRequests();\n };\n }, [debouncedFetch, cancelAllSearchRequests]);\n\n const renderOption = (props, option) => {\n const { key, ...otherProps } = props;\n const { name, version, description, isPrivate, isCached, isRemote } =\n normalizeSearchOption(option);\n return (\n <SearchItem\n key={key}\n {...otherProps}\n description={description}\n isCached={isCached}\n isPrivate={isPrivate}\n isRemote={isRemote}\n name={name}\n version={version}\n />\n );\n };\n\n const renderInput = (params) => {\n return (\n <StyledTextField\n {...params}\n InputProps={{\n ...params.InputProps,\n startAdornment: (\n <StyledInputAdornment position=\"start\">\n <SearchMui />\n </StyledInputAdornment>\n ),\n }}\n label=\"\"\n placeholder={t('search.packages')}\n variant=\"standard\"\n />\n );\n };\n\n const getOptionGroup = (option) => normalizeSearchOption(option).origin ?? '';\n\n const renderGroup = ({ key, group, children }: AutocompleteRenderGroupParams) => {\n if (!group) {\n return <React.Fragment key={key}>{children}</React.Fragment>;\n }\n const OriginIcon = ORIGIN_ICONS[group as SearchOrigin];\n return (\n <li key={key}>\n {/* a div: the default <li> would nest a list item inside the group's <li> */}\n <ListSubheader\n component=\"div\"\n data-testid={`search-group-${group}`}\n sx={{ display: 'flex', alignItems: 'center', gap: 1, lineHeight: '36px' }}\n >\n {OriginIcon && <OriginIcon fontSize=\"small\" />}\n {t(`search.group.${group}`, { count: React.Children.count(children) })}\n </ListSubheader>\n <ul style={{ padding: 0 }}>{children}</ul>\n </li>\n );\n };\n\n const getOptionLabel = (option) => {\n return normalizeSearchOption(option).name;\n };\n\n return (\n <AutoComplete\n getOptionLabel={getOptionLabel}\n groupBy={groupByOrigin ? getOptionGroup : undefined}\n hasError={isError}\n onCleanSuggestions={handleOnBlur}\n onSelectItem={handleClickSearch}\n onSuggestionsFetch={handleSuggestionsFetch}\n placeholder={t('search.packages')}\n renderGroup={groupByOrigin ? renderGroup : undefined}\n renderInput={renderInput}\n renderOption={renderOption}\n suggestions={suggestions}\n suggestionsLoading={isLoading || isDebouncing}\n />\n );\n};\n\nexport default Search;\n"],"mappings":"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"}
@@ -8,11 +8,22 @@ type SearchItemProps = {
8
8
  isCached?: boolean;
9
9
  isRemote?: boolean;
10
10
  };
11
+ export declare const ORIGIN_ICONS: {
12
+ private: import("@mui/material/OverridableComponent").OverridableComponent<import("@mui/material").SvgIconTypeMap<{}, "svg">> & {
13
+ muiName: string;
14
+ };
15
+ cached: import("@mui/material/OverridableComponent").OverridableComponent<import("@mui/material").SvgIconTypeMap<{}, "svg">> & {
16
+ muiName: string;
17
+ };
18
+ remote: import("@mui/material/OverridableComponent").OverridableComponent<import("@mui/material").SvgIconTypeMap<{}, "svg">> & {
19
+ muiName: string;
20
+ };
21
+ };
11
22
  export declare const Description: import("@emotion/styled").StyledComponent<{
12
23
  theme?: import("@emotion/react").Theme;
13
24
  as?: React.ElementType;
14
25
  } & {
15
26
  theme?: Theme;
16
- }, React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;
27
+ }, React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, {}>;
17
28
  declare const SearchItem: React.FC<SearchItemProps>;
18
29
  export default SearchItem;
@@ -8,92 +8,75 @@ let react = require("react");
8
8
  react = require_runtime.__toESM(react);
9
9
  let react_i18next = require("react-i18next");
10
10
  let react_jsx_runtime = require("react/jsx-runtime");
11
- let _mui_material_Stack = require("@mui/material/Stack");
12
- _mui_material_Stack = require_runtime.__toESM(_mui_material_Stack);
13
- let _mui_material_Chip = require("@mui/material/Chip");
14
- _mui_material_Chip = require_runtime.__toESM(_mui_material_Chip);
15
- let _mui_icons_material_Cached = require("@mui/icons-material/Cached");
16
- _mui_icons_material_Cached = require_runtime.__toESM(_mui_icons_material_Cached);
17
- let _mui_icons_material_Https = require("@mui/icons-material/Https");
18
- _mui_icons_material_Https = require_runtime.__toESM(_mui_icons_material_Https);
19
- let _mui_icons_material_SyncAlt = require("@mui/icons-material/SyncAlt");
20
- _mui_icons_material_SyncAlt = require_runtime.__toESM(_mui_icons_material_SyncAlt);
11
+ let _mui_icons_material_LockOutlined = require("@mui/icons-material/LockOutlined");
12
+ _mui_icons_material_LockOutlined = require_runtime.__toESM(_mui_icons_material_LockOutlined);
13
+ let _mui_icons_material_CloudOutlined = require("@mui/icons-material/CloudOutlined");
14
+ _mui_icons_material_CloudOutlined = require_runtime.__toESM(_mui_icons_material_CloudOutlined);
15
+ let _mui_icons_material_Inventory2Outlined = require("@mui/icons-material/Inventory2Outlined");
16
+ _mui_icons_material_Inventory2Outlined = require_runtime.__toESM(_mui_icons_material_Inventory2Outlined);
21
17
  //#region src/components/Search/SearchItem.tsx
22
- var Wrapper = _emotion_styled.default.div({
18
+ var ORIGIN_ICONS = {
19
+ [require_utils.SearchOrigin.PRIVATE]: _mui_icons_material_LockOutlined.default,
20
+ [require_utils.SearchOrigin.CACHED]: _mui_icons_material_Inventory2Outlined.default,
21
+ [require_utils.SearchOrigin.REMOTE]: _mui_icons_material_CloudOutlined.default
22
+ };
23
+ var Row = (0, _emotion_styled.default)("div")({
23
24
  display: "flex",
24
25
  alignItems: "center",
25
- width: "100%"
26
+ gap: 12,
27
+ width: "100%",
28
+ minWidth: 0
26
29
  });
27
- var Description = (0, _emotion_styled.default)("div")(({ theme }) => ({
28
- display: "none",
29
- color: theme.palette.greyLight2,
30
- lineHeight: "1.5rem",
31
- whiteSpace: "nowrap",
32
- textOverflow: "ellipsis",
33
- alignItems: "center",
34
- overflow: "hidden",
35
- paddingLeft: theme.spacing(),
36
- fontSize: theme.fontSize.ssm,
37
- [`@media (min-width: ${theme.breakPoints.medium}px)`]: {
38
- display: "block",
39
- width: "300px"
40
- },
41
- [`@media (min-width: ${theme.breakPoints.large}px)`]: {
42
- display: "block",
43
- width: "500px"
44
- },
45
- [`@media (min-width: 1440px)`]: {
46
- display: "block",
47
- width: "600px"
48
- }
49
- }));
50
- var NameGroup = _emotion_styled.default.span({
30
+ var Text = (0, _emotion_styled.default)("div")({
31
+ display: "flex",
32
+ flexDirection: "column",
33
+ flex: 1,
34
+ minWidth: 0
35
+ });
36
+ var TitleLine = (0, _emotion_styled.default)("div")({
51
37
  display: "flex",
52
- flex: "1"
38
+ alignItems: "baseline",
39
+ gap: 8
53
40
  });
54
41
  var Name = (0, _emotion_styled.default)("span")(({ theme }) => ({
55
- fontWeight: "700",
56
- fontSize: theme.fontSize.sm
42
+ fontWeight: 700,
43
+ fontSize: theme.fontSize.sm,
44
+ overflow: "hidden",
45
+ textOverflow: "ellipsis",
46
+ whiteSpace: "nowrap"
47
+ }));
48
+ var Version = (0, _emotion_styled.default)("span")(({ theme }) => ({
49
+ marginLeft: "auto",
50
+ flexShrink: 0,
51
+ fontSize: theme.fontSize.ssm,
52
+ color: theme.palette.text.secondary
53
+ }));
54
+ var Description = (0, _emotion_styled.default)("span")(({ theme }) => ({
55
+ color: theme.palette.text.secondary,
56
+ fontSize: theme.fontSize.ssm,
57
+ lineHeight: 1.5,
58
+ overflow: "hidden",
59
+ textOverflow: "ellipsis",
60
+ whiteSpace: "nowrap"
57
61
  }));
58
- var Version = (0, _emotion_styled.default)("span")(({ theme }) => ({ fontSize: theme.fontSize.ssm }));
59
62
  var SearchItem = ({ name, description, isPrivate = false, isRemote = false, isCached = false, version, ...props }) => {
60
63
  const { t } = (0, react_i18next.useTranslation)();
61
64
  const { configOptions } = require_AppConfigurationProvider.useConfig();
62
- const handleDelete = () => {};
63
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
65
+ const origin = isPrivate ? require_utils.SearchOrigin.PRIVATE : isCached ? require_utils.SearchOrigin.CACHED : isRemote ? require_utils.SearchOrigin.REMOTE : void 0;
66
+ const OriginIcon = configOptions?.showUplinks && origin ? ORIGIN_ICONS[origin] : void 0;
67
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
64
68
  ...props,
65
- style: { flexDirection: "column" },
66
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Wrapper, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(NameGroup, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Name, { children: name }), description && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Description, { children: require_utils.cleanDescription(description) })] }), version && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Version, { children: version })] }), configOptions?.showUplinks && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Wrapper, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_Stack.default, {
67
- direction: "row",
68
- spacing: 1,
69
- children: [
70
- isPrivate && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Chip.default, {
71
- color: "primary",
72
- deleteIcon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_icons_material_Https.default, {}),
73
- label: t("search.isPrivate"),
74
- onDelete: handleDelete,
75
- size: "small"
76
- }),
77
- isRemote && !isPrivate && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Chip.default, {
78
- deleteIcon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_icons_material_SyncAlt.default, {}),
79
- label: t("search.isRemote"),
80
- onDelete: handleDelete,
81
- size: "small",
82
- variant: "outlined"
83
- }),
84
- isCached && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Chip.default, {
85
- deleteIcon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_icons_material_Cached.default, {}),
86
- label: t("search.isCached"),
87
- onDelete: handleDelete,
88
- size: "small",
89
- variant: "outlined"
90
- })
91
- ]
92
- }) })]
69
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Row, { children: [OriginIcon && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OriginIcon, {
70
+ color: origin === require_utils.SearchOrigin.PRIVATE ? "primary" : "action",
71
+ "data-testid": `search-origin-${origin}`,
72
+ fontSize: "small",
73
+ titleAccess: t(`search.origin.${origin}`)
74
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Text, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(TitleLine, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Name, { children: name }), version && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Version, { children: version })] }), description && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Description, { children: require_utils.cleanDescription(description) })] })] })
93
75
  });
94
76
  };
95
77
  //#endregion
96
78
  exports.Description = Description;
79
+ exports.ORIGIN_ICONS = ORIGIN_ICONS;
97
80
  exports.default = SearchItem;
98
81
 
99
82
  //# sourceMappingURL=SearchItem.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SearchItem.js","names":["styled","useTranslation","useConfig","cleanDescription","Stack","Chip","HttpsIcon","SyncAlt","Cached"],"sources":["../../../src/components/Search/SearchItem.tsx"],"sourcesContent":["import styled from '@emotion/styled';\nimport Cached from '@mui/icons-material/Cached';\nimport HttpsIcon from '@mui/icons-material/Https';\nimport SyncAlt from '@mui/icons-material/SyncAlt';\nimport type { Theme } from '@mui/material';\nimport Chip from '@mui/material/Chip';\nimport Stack from '@mui/material/Stack';\nimport React from 'react';\nimport { useTranslation } from 'react-i18next';\n\nimport { useConfig } from '../../';\nimport { cleanDescription } from './utils';\n\ntype SearchItemProps = {\n name: string;\n version?: string;\n description?: string;\n isPrivate?: boolean;\n isCached?: boolean;\n isRemote?: boolean;\n};\n\nconst Wrapper = styled.div({\n display: 'flex',\n alignItems: 'center',\n width: '100%',\n});\n\nexport const Description = styled('div')<{ theme?: Theme }>(({ theme }) => ({\n display: 'none',\n color: theme.palette.greyLight2,\n lineHeight: '1.5rem',\n whiteSpace: 'nowrap',\n textOverflow: 'ellipsis',\n alignItems: 'center',\n overflow: 'hidden',\n paddingLeft: theme.spacing(),\n fontSize: theme.fontSize.ssm,\n [`@media (min-width: ${theme.breakPoints.medium}px)`]: {\n display: 'block',\n width: '300px',\n },\n [`@media (min-width: ${theme.breakPoints.large}px)`]: {\n display: 'block',\n width: '500px',\n },\n [`@media (min-width: 1440px)`]: {\n display: 'block',\n width: '600px',\n },\n}));\n\nconst NameGroup = styled.span({\n display: 'flex',\n flex: '1',\n});\n\nconst Name = styled('span')<{ theme?: Theme }>(({ theme }) => ({\n fontWeight: '700',\n fontSize: theme.fontSize.sm,\n}));\n\nconst Version = styled('span')<{ theme?: Theme }>(({ theme }) => ({\n fontSize: theme.fontSize.ssm,\n}));\n\nconst SearchItem: React.FC<SearchItemProps> = ({\n name,\n description,\n isPrivate = false,\n isRemote = false,\n isCached = false,\n version,\n ...props\n}) => {\n const { t } = useTranslation();\n const { configOptions } = useConfig();\n const handleDelete = () => {\n // no action assigned by default\n };\n return (\n <li {...props} style={{ flexDirection: 'column' }}>\n <Wrapper>\n <NameGroup>\n <Name>{name}</Name>\n {description && <Description>{cleanDescription(description)}</Description>}\n </NameGroup>\n {version && <Version>{version}</Version>}\n </Wrapper>\n {configOptions?.showUplinks && (\n <Wrapper>\n <Stack direction=\"row\" spacing={1}>\n {isPrivate && (\n <Chip\n color=\"primary\"\n deleteIcon={<HttpsIcon />}\n label={t('search.isPrivate')}\n onDelete={handleDelete}\n size=\"small\"\n />\n )}\n {isRemote && !isPrivate && (\n <Chip\n deleteIcon={<SyncAlt />}\n label={t('search.isRemote')}\n onDelete={handleDelete}\n size=\"small\"\n variant=\"outlined\"\n />\n )}\n {isCached && (\n <Chip\n deleteIcon={<Cached />}\n label={t('search.isCached')}\n onDelete={handleDelete}\n size=\"small\"\n variant=\"outlined\"\n />\n )}\n </Stack>\n </Wrapper>\n )}\n </li>\n );\n};\n\nexport default SearchItem;\n"],"mappings":"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"}
1
+ {"version":3,"file":"SearchItem.js","names":["SearchOrigin","LockOutlined","Inventory2Outlined","CloudOutlined","styled","useTranslation","useConfig","cleanDescription"],"sources":["../../../src/components/Search/SearchItem.tsx"],"sourcesContent":["import styled from '@emotion/styled';\nimport CloudOutlined from '@mui/icons-material/CloudOutlined';\nimport Inventory2Outlined from '@mui/icons-material/Inventory2Outlined';\nimport LockOutlined from '@mui/icons-material/LockOutlined';\nimport type { Theme } from '@mui/material';\nimport React from 'react';\nimport { useTranslation } from 'react-i18next';\n\nimport { useConfig } from '../../';\nimport { SearchOrigin, cleanDescription } from './utils';\n\ntype SearchItemProps = {\n name: string;\n version?: string;\n description?: string;\n isPrivate?: boolean;\n isCached?: boolean;\n isRemote?: boolean;\n};\n\nexport const ORIGIN_ICONS = {\n [SearchOrigin.PRIVATE]: LockOutlined,\n [SearchOrigin.CACHED]: Inventory2Outlined,\n [SearchOrigin.REMOTE]: CloudOutlined,\n};\n\nconst Row = styled('div')({\n display: 'flex',\n alignItems: 'center',\n gap: 12,\n width: '100%',\n minWidth: 0,\n});\n\nconst Text = styled('div')({\n display: 'flex',\n flexDirection: 'column',\n flex: 1,\n minWidth: 0,\n});\n\nconst TitleLine = styled('div')({\n display: 'flex',\n alignItems: 'baseline',\n gap: 8,\n});\n\nconst Name = styled('span')<{ theme?: Theme }>(({ theme }) => ({\n fontWeight: 700,\n fontSize: theme.fontSize.sm,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n}));\n\nconst Version = styled('span')<{ theme?: Theme }>(({ theme }) => ({\n marginLeft: 'auto',\n flexShrink: 0,\n fontSize: theme.fontSize.ssm,\n color: theme.palette.text.secondary,\n}));\n\nexport const Description = styled('span')<{ theme?: Theme }>(({ theme }) => ({\n color: theme.palette.text.secondary,\n fontSize: theme.fontSize.ssm,\n lineHeight: 1.5,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n}));\n\nconst SearchItem: React.FC<SearchItemProps> = ({\n name,\n description,\n isPrivate = false,\n isRemote = false,\n isCached = false,\n version,\n ...props\n}) => {\n const { t } = useTranslation();\n const { configOptions } = useConfig();\n const origin = isPrivate\n ? SearchOrigin.PRIVATE\n : isCached\n ? SearchOrigin.CACHED\n : isRemote\n ? SearchOrigin.REMOTE\n : undefined;\n const OriginIcon = configOptions?.showUplinks && origin ? ORIGIN_ICONS[origin] : undefined;\n\n return (\n <li {...props}>\n <Row>\n {OriginIcon && (\n <OriginIcon\n color={origin === SearchOrigin.PRIVATE ? 'primary' : 'action'}\n data-testid={`search-origin-${origin}`}\n fontSize=\"small\"\n titleAccess={t(`search.origin.${origin}`)}\n />\n )}\n <Text>\n <TitleLine>\n <Name>{name}</Name>\n {version && <Version>{version}</Version>}\n </TitleLine>\n {description && <Description>{cleanDescription(description)}</Description>}\n </Text>\n </Row>\n </li>\n );\n};\n\nexport default SearchItem;\n"],"mappings":";;;;;;;;;;;;;;;;;AAoBA,IAAa,eAAe;EACzBA,cAAAA,aAAa,UAAUC,iCAAAA;EACvBD,cAAAA,aAAa,SAASE,uCAAAA;EACtBF,cAAAA,aAAa,SAASG,kCAAAA;AACzB;AAEA,IAAM,OAAA,GAAMC,gBAAAA,QAAAA,CAAO,KAAK,CAAC,CAAC;CACxB,SAAS;CACT,YAAY;CACZ,KAAK;CACL,OAAO;CACP,UAAU;AACZ,CAAC;AAED,IAAM,QAAA,GAAOA,gBAAAA,QAAAA,CAAO,KAAK,CAAC,CAAC;CACzB,SAAS;CACT,eAAe;CACf,MAAM;CACN,UAAU;AACZ,CAAC;AAED,IAAM,aAAA,GAAYA,gBAAAA,QAAAA,CAAO,KAAK,CAAC,CAAC;CAC9B,SAAS;CACT,YAAY;CACZ,KAAK;AACP,CAAC;AAED,IAAM,QAAA,GAAOA,gBAAAA,QAAAA,CAAO,MAAM,CAAC,EAAqB,EAAE,aAAa;CAC7D,YAAY;CACZ,UAAU,MAAM,SAAS;CACzB,UAAU;CACV,cAAc;CACd,YAAY;AACd,EAAE;AAEF,IAAM,WAAA,GAAUA,gBAAAA,QAAAA,CAAO,MAAM,CAAC,EAAqB,EAAE,aAAa;CAChE,YAAY;CACZ,YAAY;CACZ,UAAU,MAAM,SAAS;CACzB,OAAO,MAAM,QAAQ,KAAK;AAC5B,EAAE;AAEF,IAAa,eAAA,GAAcA,gBAAAA,QAAAA,CAAO,MAAM,CAAC,EAAqB,EAAE,aAAa;CAC3E,OAAO,MAAM,QAAQ,KAAK;CAC1B,UAAU,MAAM,SAAS;CACzB,YAAY;CACZ,UAAU;CACV,cAAc;CACd,YAAY;AACd,EAAE;AAEF,IAAM,cAAyC,EAC7C,MACA,aACA,YAAY,OACZ,WAAW,OACX,WAAW,OACX,SACA,GAAG,YACC;CACJ,MAAM,EAAE,OAAA,GAAMC,cAAAA,eAAAA,CAAe;CAC7B,MAAM,EAAE,kBAAkBC,iCAAAA,UAAU;CACpC,MAAM,SAAS,YACXN,cAAAA,aAAa,UACb,WACEA,cAAAA,aAAa,SACb,WACEA,cAAAA,aAAa,SACb,KAAA;CACR,MAAM,aAAa,eAAe,eAAe,SAAS,aAAa,UAAU,KAAA;CAEjF,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD;EAAI,GAAI;EACN,UAAA,iBAAA,GAAA,kBAAA,KAAA,CAAC,KAAD,EAAA,UAAA,CACG,cACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,YAAD;GACE,OAAO,WAAWA,cAAAA,aAAa,UAAU,YAAY;GACrD,eAAa,iBAAiB;GAC9B,UAAS;GACT,aAAa,EAAE,iBAAiB,QAAQ;EACzC,CAAA,GAEH,iBAAA,GAAA,kBAAA,KAAA,CAAC,MAAD,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,WAAD,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD,EAAA,UAAO,KAAW,CAAA,GACjB,WAAW,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD,EAAA,UAAU,QAAiB,CAAA,CAC9B,EAAA,CAAA,GACV,eAAe,iBAAA,GAAA,kBAAA,IAAA,CAAC,aAAD,EAAA,UAAcO,cAAAA,iBAAiB,WAAW,EAAe,CAAA,CACrE,EAAA,CAAA,CACH,EAAA,CAAA;CACH,CAAA;AAER"}
@@ -1,90 +1,74 @@
1
1
  import { useConfig } from "../../providers/AppConfigurationProvider/AppConfigurationProvider.mjs";
2
- import { cleanDescription } from "./utils.mjs";
2
+ import { SearchOrigin, cleanDescription } from "./utils.mjs";
3
3
  import "../../index.mjs";
4
4
  import styled from "@emotion/styled";
5
5
  import "react";
6
6
  import { useTranslation } from "react-i18next";
7
7
  import { jsx, jsxs } from "react/jsx-runtime";
8
- import Stack from "@mui/material/Stack";
9
- import Chip from "@mui/material/Chip";
10
- import Cached from "@mui/icons-material/Cached";
11
- import HttpsIcon from "@mui/icons-material/Https";
12
- import SyncAlt from "@mui/icons-material/SyncAlt";
8
+ import LockOutlined from "@mui/icons-material/LockOutlined";
9
+ import CloudOutlined from "@mui/icons-material/CloudOutlined";
10
+ import Inventory2Outlined from "@mui/icons-material/Inventory2Outlined";
13
11
  //#region src/components/Search/SearchItem.tsx
14
- var Wrapper = styled.div({
12
+ var ORIGIN_ICONS = {
13
+ [SearchOrigin.PRIVATE]: LockOutlined,
14
+ [SearchOrigin.CACHED]: Inventory2Outlined,
15
+ [SearchOrigin.REMOTE]: CloudOutlined
16
+ };
17
+ var Row = styled("div")({
15
18
  display: "flex",
16
19
  alignItems: "center",
17
- width: "100%"
20
+ gap: 12,
21
+ width: "100%",
22
+ minWidth: 0
18
23
  });
19
- var Description = styled("div")(({ theme }) => ({
20
- display: "none",
21
- color: theme.palette.greyLight2,
22
- lineHeight: "1.5rem",
23
- whiteSpace: "nowrap",
24
- textOverflow: "ellipsis",
25
- alignItems: "center",
26
- overflow: "hidden",
27
- paddingLeft: theme.spacing(),
28
- fontSize: theme.fontSize.ssm,
29
- [`@media (min-width: ${theme.breakPoints.medium}px)`]: {
30
- display: "block",
31
- width: "300px"
32
- },
33
- [`@media (min-width: ${theme.breakPoints.large}px)`]: {
34
- display: "block",
35
- width: "500px"
36
- },
37
- [`@media (min-width: 1440px)`]: {
38
- display: "block",
39
- width: "600px"
40
- }
41
- }));
42
- var NameGroup = styled.span({
24
+ var Text = styled("div")({
25
+ display: "flex",
26
+ flexDirection: "column",
27
+ flex: 1,
28
+ minWidth: 0
29
+ });
30
+ var TitleLine = styled("div")({
43
31
  display: "flex",
44
- flex: "1"
32
+ alignItems: "baseline",
33
+ gap: 8
45
34
  });
46
35
  var Name = styled("span")(({ theme }) => ({
47
- fontWeight: "700",
48
- fontSize: theme.fontSize.sm
36
+ fontWeight: 700,
37
+ fontSize: theme.fontSize.sm,
38
+ overflow: "hidden",
39
+ textOverflow: "ellipsis",
40
+ whiteSpace: "nowrap"
41
+ }));
42
+ var Version = styled("span")(({ theme }) => ({
43
+ marginLeft: "auto",
44
+ flexShrink: 0,
45
+ fontSize: theme.fontSize.ssm,
46
+ color: theme.palette.text.secondary
47
+ }));
48
+ var Description = styled("span")(({ theme }) => ({
49
+ color: theme.palette.text.secondary,
50
+ fontSize: theme.fontSize.ssm,
51
+ lineHeight: 1.5,
52
+ overflow: "hidden",
53
+ textOverflow: "ellipsis",
54
+ whiteSpace: "nowrap"
49
55
  }));
50
- var Version = styled("span")(({ theme }) => ({ fontSize: theme.fontSize.ssm }));
51
56
  var SearchItem = ({ name, description, isPrivate = false, isRemote = false, isCached = false, version, ...props }) => {
52
57
  const { t } = useTranslation();
53
58
  const { configOptions } = useConfig();
54
- const handleDelete = () => {};
55
- return /* @__PURE__ */ jsxs("li", {
59
+ const origin = isPrivate ? SearchOrigin.PRIVATE : isCached ? SearchOrigin.CACHED : isRemote ? SearchOrigin.REMOTE : void 0;
60
+ const OriginIcon = configOptions?.showUplinks && origin ? ORIGIN_ICONS[origin] : void 0;
61
+ return /* @__PURE__ */ jsx("li", {
56
62
  ...props,
57
- style: { flexDirection: "column" },
58
- children: [/* @__PURE__ */ jsxs(Wrapper, { children: [/* @__PURE__ */ jsxs(NameGroup, { children: [/* @__PURE__ */ jsx(Name, { children: name }), description && /* @__PURE__ */ jsx(Description, { children: cleanDescription(description) })] }), version && /* @__PURE__ */ jsx(Version, { children: version })] }), configOptions?.showUplinks && /* @__PURE__ */ jsx(Wrapper, { children: /* @__PURE__ */ jsxs(Stack, {
59
- direction: "row",
60
- spacing: 1,
61
- children: [
62
- isPrivate && /* @__PURE__ */ jsx(Chip, {
63
- color: "primary",
64
- deleteIcon: /* @__PURE__ */ jsx(HttpsIcon, {}),
65
- label: t("search.isPrivate"),
66
- onDelete: handleDelete,
67
- size: "small"
68
- }),
69
- isRemote && !isPrivate && /* @__PURE__ */ jsx(Chip, {
70
- deleteIcon: /* @__PURE__ */ jsx(SyncAlt, {}),
71
- label: t("search.isRemote"),
72
- onDelete: handleDelete,
73
- size: "small",
74
- variant: "outlined"
75
- }),
76
- isCached && /* @__PURE__ */ jsx(Chip, {
77
- deleteIcon: /* @__PURE__ */ jsx(Cached, {}),
78
- label: t("search.isCached"),
79
- onDelete: handleDelete,
80
- size: "small",
81
- variant: "outlined"
82
- })
83
- ]
84
- }) })]
63
+ children: /* @__PURE__ */ jsxs(Row, { children: [OriginIcon && /* @__PURE__ */ jsx(OriginIcon, {
64
+ color: origin === SearchOrigin.PRIVATE ? "primary" : "action",
65
+ "data-testid": `search-origin-${origin}`,
66
+ fontSize: "small",
67
+ titleAccess: t(`search.origin.${origin}`)
68
+ }), /* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsxs(TitleLine, { children: [/* @__PURE__ */ jsx(Name, { children: name }), version && /* @__PURE__ */ jsx(Version, { children: version })] }), description && /* @__PURE__ */ jsx(Description, { children: cleanDescription(description) })] })] })
85
69
  });
86
70
  };
87
71
  //#endregion
88
- export { Description, SearchItem as default };
72
+ export { Description, ORIGIN_ICONS, SearchItem as default };
89
73
 
90
74
  //# sourceMappingURL=SearchItem.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"SearchItem.mjs","names":[],"sources":["../../../src/components/Search/SearchItem.tsx"],"sourcesContent":["import styled from '@emotion/styled';\nimport Cached from '@mui/icons-material/Cached';\nimport HttpsIcon from '@mui/icons-material/Https';\nimport SyncAlt from '@mui/icons-material/SyncAlt';\nimport type { Theme } from '@mui/material';\nimport Chip from '@mui/material/Chip';\nimport Stack from '@mui/material/Stack';\nimport React from 'react';\nimport { useTranslation } from 'react-i18next';\n\nimport { useConfig } from '../../';\nimport { cleanDescription } from './utils';\n\ntype SearchItemProps = {\n name: string;\n version?: string;\n description?: string;\n isPrivate?: boolean;\n isCached?: boolean;\n isRemote?: boolean;\n};\n\nconst Wrapper = styled.div({\n display: 'flex',\n alignItems: 'center',\n width: '100%',\n});\n\nexport const Description = styled('div')<{ theme?: Theme }>(({ theme }) => ({\n display: 'none',\n color: theme.palette.greyLight2,\n lineHeight: '1.5rem',\n whiteSpace: 'nowrap',\n textOverflow: 'ellipsis',\n alignItems: 'center',\n overflow: 'hidden',\n paddingLeft: theme.spacing(),\n fontSize: theme.fontSize.ssm,\n [`@media (min-width: ${theme.breakPoints.medium}px)`]: {\n display: 'block',\n width: '300px',\n },\n [`@media (min-width: ${theme.breakPoints.large}px)`]: {\n display: 'block',\n width: '500px',\n },\n [`@media (min-width: 1440px)`]: {\n display: 'block',\n width: '600px',\n },\n}));\n\nconst NameGroup = styled.span({\n display: 'flex',\n flex: '1',\n});\n\nconst Name = styled('span')<{ theme?: Theme }>(({ theme }) => ({\n fontWeight: '700',\n fontSize: theme.fontSize.sm,\n}));\n\nconst Version = styled('span')<{ theme?: Theme }>(({ theme }) => ({\n fontSize: theme.fontSize.ssm,\n}));\n\nconst SearchItem: React.FC<SearchItemProps> = ({\n name,\n description,\n isPrivate = false,\n isRemote = false,\n isCached = false,\n version,\n ...props\n}) => {\n const { t } = useTranslation();\n const { configOptions } = useConfig();\n const handleDelete = () => {\n // no action assigned by default\n };\n return (\n <li {...props} style={{ flexDirection: 'column' }}>\n <Wrapper>\n <NameGroup>\n <Name>{name}</Name>\n {description && <Description>{cleanDescription(description)}</Description>}\n </NameGroup>\n {version && <Version>{version}</Version>}\n </Wrapper>\n {configOptions?.showUplinks && (\n <Wrapper>\n <Stack direction=\"row\" spacing={1}>\n {isPrivate && (\n <Chip\n color=\"primary\"\n deleteIcon={<HttpsIcon />}\n label={t('search.isPrivate')}\n onDelete={handleDelete}\n size=\"small\"\n />\n )}\n {isRemote && !isPrivate && (\n <Chip\n deleteIcon={<SyncAlt />}\n label={t('search.isRemote')}\n onDelete={handleDelete}\n size=\"small\"\n variant=\"outlined\"\n />\n )}\n {isCached && (\n <Chip\n deleteIcon={<Cached />}\n label={t('search.isCached')}\n onDelete={handleDelete}\n size=\"small\"\n variant=\"outlined\"\n />\n )}\n </Stack>\n </Wrapper>\n )}\n </li>\n );\n};\n\nexport default SearchItem;\n"],"mappings":";;;;;;;;;;;;;AAsBA,IAAM,UAAU,OAAO,IAAI;CACzB,SAAS;CACT,YAAY;CACZ,OAAO;AACT,CAAC;AAED,IAAa,cAAc,OAAO,KAAK,CAAC,EAAqB,EAAE,aAAa;CAC1E,SAAS;CACT,OAAO,MAAM,QAAQ;CACrB,YAAY;CACZ,YAAY;CACZ,cAAc;CACd,YAAY;CACZ,UAAU;CACV,aAAa,MAAM,QAAQ;CAC3B,UAAU,MAAM,SAAS;EACxB,sBAAsB,MAAM,YAAY,OAAO,OAAO;EACrD,SAAS;EACT,OAAO;CACT;EACC,sBAAsB,MAAM,YAAY,MAAM,OAAO;EACpD,SAAS;EACT,OAAO;CACT;EACC,+BAA+B;EAC9B,SAAS;EACT,OAAO;CACT;AACF,EAAE;AAEF,IAAM,YAAY,OAAO,KAAK;CAC5B,SAAS;CACT,MAAM;AACR,CAAC;AAED,IAAM,OAAO,OAAO,MAAM,CAAC,EAAqB,EAAE,aAAa;CAC7D,YAAY;CACZ,UAAU,MAAM,SAAS;AAC3B,EAAE;AAEF,IAAM,UAAU,OAAO,MAAM,CAAC,EAAqB,EAAE,aAAa,EAChE,UAAU,MAAM,SAAS,IAC3B,EAAE;AAEF,IAAM,cAAyC,EAC7C,MACA,aACA,YAAY,OACZ,WAAW,OACX,WAAW,OACX,SACA,GAAG,YACC;CACJ,MAAM,EAAE,MAAM,eAAe;CAC7B,MAAM,EAAE,kBAAkB,UAAU;CACpC,MAAM,qBAAqB,CAE3B;CACA,OACE,qBAAC,MAAD;EAAI,GAAI;EAAO,OAAO,EAAE,eAAe,SAAS;EAAhD,UAAA,CACE,qBAAC,SAAD,EAAA,UAAA,CACE,qBAAC,WAAD,EAAA,UAAA,CACE,oBAAC,MAAD,EAAA,UAAO,KAAW,CAAA,GACjB,eAAe,oBAAC,aAAD,EAAA,UAAc,iBAAiB,WAAW,EAAe,CAAA,CAChE,EAAA,CAAA,GACV,WAAW,oBAAC,SAAD,EAAA,UAAU,QAAiB,CAAA,CAChC,EAAA,CAAA,GACR,eAAe,eACd,oBAAC,SAAD,EAAA,UACE,qBAAC,OAAD;GAAO,WAAU;GAAM,SAAS;GAAhC,UAAA;IACG,aACC,oBAAC,MAAD;KACE,OAAM;KACN,YAAY,oBAAC,WAAD,CAAY,CAAA;KACxB,OAAO,EAAE,kBAAkB;KAC3B,UAAU;KACV,MAAK;IACN,CAAA;IAEF,YAAY,CAAC,aACZ,oBAAC,MAAD;KACE,YAAY,oBAAC,SAAD,CAAU,CAAA;KACtB,OAAO,EAAE,iBAAiB;KAC1B,UAAU;KACV,MAAK;KACL,SAAQ;IACT,CAAA;IAEF,YACC,oBAAC,MAAD;KACE,YAAY,oBAAC,QAAD,CAAS,CAAA;KACrB,OAAO,EAAE,iBAAiB;KAC1B,UAAU;KACV,MAAK;KACL,SAAQ;IACT,CAAA;GAEE;EACA,CAAA,EAAA,CAAA,CAET;;AAER"}
1
+ {"version":3,"file":"SearchItem.mjs","names":[],"sources":["../../../src/components/Search/SearchItem.tsx"],"sourcesContent":["import styled from '@emotion/styled';\nimport CloudOutlined from '@mui/icons-material/CloudOutlined';\nimport Inventory2Outlined from '@mui/icons-material/Inventory2Outlined';\nimport LockOutlined from '@mui/icons-material/LockOutlined';\nimport type { Theme } from '@mui/material';\nimport React from 'react';\nimport { useTranslation } from 'react-i18next';\n\nimport { useConfig } from '../../';\nimport { SearchOrigin, cleanDescription } from './utils';\n\ntype SearchItemProps = {\n name: string;\n version?: string;\n description?: string;\n isPrivate?: boolean;\n isCached?: boolean;\n isRemote?: boolean;\n};\n\nexport const ORIGIN_ICONS = {\n [SearchOrigin.PRIVATE]: LockOutlined,\n [SearchOrigin.CACHED]: Inventory2Outlined,\n [SearchOrigin.REMOTE]: CloudOutlined,\n};\n\nconst Row = styled('div')({\n display: 'flex',\n alignItems: 'center',\n gap: 12,\n width: '100%',\n minWidth: 0,\n});\n\nconst Text = styled('div')({\n display: 'flex',\n flexDirection: 'column',\n flex: 1,\n minWidth: 0,\n});\n\nconst TitleLine = styled('div')({\n display: 'flex',\n alignItems: 'baseline',\n gap: 8,\n});\n\nconst Name = styled('span')<{ theme?: Theme }>(({ theme }) => ({\n fontWeight: 700,\n fontSize: theme.fontSize.sm,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n}));\n\nconst Version = styled('span')<{ theme?: Theme }>(({ theme }) => ({\n marginLeft: 'auto',\n flexShrink: 0,\n fontSize: theme.fontSize.ssm,\n color: theme.palette.text.secondary,\n}));\n\nexport const Description = styled('span')<{ theme?: Theme }>(({ theme }) => ({\n color: theme.palette.text.secondary,\n fontSize: theme.fontSize.ssm,\n lineHeight: 1.5,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n}));\n\nconst SearchItem: React.FC<SearchItemProps> = ({\n name,\n description,\n isPrivate = false,\n isRemote = false,\n isCached = false,\n version,\n ...props\n}) => {\n const { t } = useTranslation();\n const { configOptions } = useConfig();\n const origin = isPrivate\n ? SearchOrigin.PRIVATE\n : isCached\n ? SearchOrigin.CACHED\n : isRemote\n ? SearchOrigin.REMOTE\n : undefined;\n const OriginIcon = configOptions?.showUplinks && origin ? ORIGIN_ICONS[origin] : undefined;\n\n return (\n <li {...props}>\n <Row>\n {OriginIcon && (\n <OriginIcon\n color={origin === SearchOrigin.PRIVATE ? 'primary' : 'action'}\n data-testid={`search-origin-${origin}`}\n fontSize=\"small\"\n titleAccess={t(`search.origin.${origin}`)}\n />\n )}\n <Text>\n <TitleLine>\n <Name>{name}</Name>\n {version && <Version>{version}</Version>}\n </TitleLine>\n {description && <Description>{cleanDescription(description)}</Description>}\n </Text>\n </Row>\n </li>\n );\n};\n\nexport default SearchItem;\n"],"mappings":";;;;;;;;;;;AAoBA,IAAa,eAAe;EACzB,aAAa,UAAU;EACvB,aAAa,SAAS;EACtB,aAAa,SAAS;AACzB;AAEA,IAAM,MAAM,OAAO,KAAK,CAAC,CAAC;CACxB,SAAS;CACT,YAAY;CACZ,KAAK;CACL,OAAO;CACP,UAAU;AACZ,CAAC;AAED,IAAM,OAAO,OAAO,KAAK,CAAC,CAAC;CACzB,SAAS;CACT,eAAe;CACf,MAAM;CACN,UAAU;AACZ,CAAC;AAED,IAAM,YAAY,OAAO,KAAK,CAAC,CAAC;CAC9B,SAAS;CACT,YAAY;CACZ,KAAK;AACP,CAAC;AAED,IAAM,OAAO,OAAO,MAAM,CAAC,EAAqB,EAAE,aAAa;CAC7D,YAAY;CACZ,UAAU,MAAM,SAAS;CACzB,UAAU;CACV,cAAc;CACd,YAAY;AACd,EAAE;AAEF,IAAM,UAAU,OAAO,MAAM,CAAC,EAAqB,EAAE,aAAa;CAChE,YAAY;CACZ,YAAY;CACZ,UAAU,MAAM,SAAS;CACzB,OAAO,MAAM,QAAQ,KAAK;AAC5B,EAAE;AAEF,IAAa,cAAc,OAAO,MAAM,CAAC,EAAqB,EAAE,aAAa;CAC3E,OAAO,MAAM,QAAQ,KAAK;CAC1B,UAAU,MAAM,SAAS;CACzB,YAAY;CACZ,UAAU;CACV,cAAc;CACd,YAAY;AACd,EAAE;AAEF,IAAM,cAAyC,EAC7C,MACA,aACA,YAAY,OACZ,WAAW,OACX,WAAW,OACX,SACA,GAAG,YACC;CACJ,MAAM,EAAE,MAAM,eAAe;CAC7B,MAAM,EAAE,kBAAkB,UAAU;CACpC,MAAM,SAAS,YACX,aAAa,UACb,WACE,aAAa,SACb,WACE,aAAa,SACb,KAAA;CACR,MAAM,aAAa,eAAe,eAAe,SAAS,aAAa,UAAU,KAAA;CAEjF,OACE,oBAAC,MAAD;EAAI,GAAI;EACN,UAAA,qBAAC,KAAD,EAAA,UAAA,CACG,cACC,oBAAC,YAAD;GACE,OAAO,WAAW,aAAa,UAAU,YAAY;GACrD,eAAa,iBAAiB;GAC9B,UAAS;GACT,aAAa,EAAE,iBAAiB,QAAQ;EACzC,CAAA,GAEH,qBAAC,MAAD,EAAA,UAAA,CACE,qBAAC,WAAD,EAAA,UAAA,CACE,oBAAC,MAAD,EAAA,UAAO,KAAW,CAAA,GACjB,WAAW,oBAAC,SAAD,EAAA,UAAU,QAAiB,CAAA,CAC9B,EAAA,CAAA,GACV,eAAe,oBAAC,aAAD,EAAA,UAAc,iBAAiB,WAAW,EAAe,CAAA,CACrE,EAAA,CAAA,CACH,EAAA,CAAA;CACH,CAAA;AAER"}
@@ -1,3 +1,10 @@
1
+ /** Where a search result lives: published here, cached from an uplink, or only on an uplink. */
2
+ export declare enum SearchOrigin {
3
+ PRIVATE = "private",
4
+ CACHED = "cached",
5
+ REMOTE = "remote"
6
+ }
7
+ export declare const SEARCH_ORIGIN_ORDER: SearchOrigin[];
1
8
  export type NormalizedSearchOption = {
2
9
  name: string;
3
10
  version?: string;
@@ -5,6 +12,7 @@ export type NormalizedSearchOption = {
5
12
  isPrivate: boolean;
6
13
  isCached: boolean;
7
14
  isRemote: boolean;
15
+ origin?: SearchOrigin;
8
16
  };
9
17
  /**
10
18
  * Normalize a raw search result into a unified shape the UI can render,
@@ -19,4 +27,6 @@ export type NormalizedSearchOption = {
19
27
  * default to `false` and the UI simply omits the corresponding badges.
20
28
  */
21
29
  export declare function normalizeSearchOption(option: any): NormalizedSearchOption;
30
+ /** Orders results private, cached, remote (stable inside each group), as grouping requires. */
31
+ export declare function sortByOrigin<T>(options: T[]): T[];
22
32
  export declare function cleanDescription(description: string): string;
@@ -1,4 +1,16 @@
1
1
  //#region src/components/Search/utils.ts
2
+ /** Where a search result lives: published here, cached from an uplink, or only on an uplink. */
3
+ var SearchOrigin = /* @__PURE__ */ function(SearchOrigin) {
4
+ SearchOrigin["PRIVATE"] = "private";
5
+ SearchOrigin["CACHED"] = "cached";
6
+ SearchOrigin["REMOTE"] = "remote";
7
+ return SearchOrigin;
8
+ }({});
9
+ var SEARCH_ORIGIN_ORDER = [
10
+ "private",
11
+ "cached",
12
+ "remote"
13
+ ];
2
14
  /**
3
15
  * Normalize a raw search result into a unified shape the UI can render,
4
16
  * regardless of which backend response format was returned:
@@ -22,7 +34,8 @@ function normalizeSearchOption(option) {
22
34
  description: pkg.description,
23
35
  isPrivate,
24
36
  isCached,
25
- isRemote: !isCached && !isPrivate
37
+ isRemote: !isCached && !isPrivate,
38
+ origin: isPrivate ? "private" : isCached ? "cached" : "remote"
26
39
  };
27
40
  }
28
41
  const flat = option ?? {};
@@ -35,6 +48,17 @@ function normalizeSearchOption(option) {
35
48
  isRemote: false
36
49
  };
37
50
  }
51
+ /** Orders results private, cached, remote (stable inside each group), as grouping requires. */
52
+ function sortByOrigin(options) {
53
+ const rank = (option) => {
54
+ const origin = normalizeSearchOption(option).origin;
55
+ return origin ? SEARCH_ORIGIN_ORDER.indexOf(origin) : SEARCH_ORIGIN_ORDER.length;
56
+ };
57
+ return options.map((option, index) => ({
58
+ option,
59
+ index
60
+ })).sort((a, b) => rank(a.option) - rank(b.option) || a.index - b.index).map(({ option }) => option);
61
+ }
38
62
  function removeHtmlTags(input) {
39
63
  let previous;
40
64
  do {
@@ -50,7 +74,10 @@ function cleanDescription(description) {
50
74
  return output;
51
75
  }
52
76
  //#endregion
77
+ exports.SEARCH_ORIGIN_ORDER = SEARCH_ORIGIN_ORDER;
78
+ exports.SearchOrigin = SearchOrigin;
53
79
  exports.cleanDescription = cleanDescription;
54
80
  exports.normalizeSearchOption = normalizeSearchOption;
81
+ exports.sortByOrigin = sortByOrigin;
55
82
 
56
83
  //# sourceMappingURL=utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","names":[],"sources":["../../../src/components/Search/utils.ts"],"sourcesContent":["export type NormalizedSearchOption = {\n name: string;\n version?: string;\n description?: string;\n isPrivate: boolean;\n isCached: boolean;\n isRemote: boolean;\n};\n\n/**\n * Normalize a raw search result into a unified shape the UI can render,\n * regardless of which backend response format was returned:\n *\n * 1) npm-style \"search objects\" response where each entry is wrapped in\n * `{ package: { name, version, description, ... }, verdaccioPrivate, verdaccioPkgCached }`.\n * 2) Flat packument-style response where each entry exposes `name`, `version`,\n * `description`, `dist`, etc. directly at the top level.\n *\n * The second shape carries no uplink metadata, so private/remote/cached flags\n * default to `false` and the UI simply omits the corresponding badges.\n */\nexport function normalizeSearchOption(option: any): NormalizedSearchOption {\n if (option && typeof option === 'object' && option.package) {\n const pkg = option.package ?? {};\n const isPrivate = Boolean(option.verdaccioPrivate);\n const isCached = Boolean(option.verdaccioPkgCached);\n return {\n name: pkg.name,\n version: pkg.version,\n description: pkg.description,\n isPrivate,\n isCached,\n isRemote: !isCached && !isPrivate,\n };\n }\n\n const flat = option ?? {};\n return {\n name: flat.name,\n version: flat.version,\n description: flat.description,\n isPrivate: false,\n isCached: false,\n isRemote: false,\n };\n}\n\nfunction removeHtmlTags(input: string): string {\n let previous;\n do {\n previous = input;\n input = input.replace(/<[^>]*>?/gm, '');\n } while (input !== previous);\n return input;\n}\n\nexport function cleanDescription(description: string): string {\n let output = description;\n // remove html tags from description (e.g. <h1...>)\n output = removeHtmlTags(output);\n // remove markdown links from description (e.g. [link](url))\n output = output.replace(/\\(.*?\\)/gm, '').replace(/(\\[!?|\\])/gm, '');\n return output;\n}\n"],"mappings":";;;;;;;;;;;;;AAqBA,SAAgB,sBAAsB,QAAqC;CACzE,IAAI,UAAU,OAAO,WAAW,YAAY,OAAO,SAAS;EAC1D,MAAM,MAAM,OAAO,WAAW,CAAC;EAC/B,MAAM,YAAY,QAAQ,OAAO,gBAAgB;EACjD,MAAM,WAAW,QAAQ,OAAO,kBAAkB;EAClD,OAAO;GACL,MAAM,IAAI;GACV,SAAS,IAAI;GACb,aAAa,IAAI;GACjB;GACA;GACA,UAAU,CAAC,YAAY,CAAC;EAC1B;CACF;CAEA,MAAM,OAAO,UAAU,CAAC;CACxB,OAAO;EACL,MAAM,KAAK;EACX,SAAS,KAAK;EACd,aAAa,KAAK;EAClB,WAAW;EACX,UAAU;EACV,UAAU;CACZ;AACF;AAEA,SAAS,eAAe,OAAuB;CAC7C,IAAI;CACJ,GAAG;EACD,WAAW;EACX,QAAQ,MAAM,QAAQ,cAAc,EAAE;CACxC,SAAS,UAAU;CACnB,OAAO;AACT;AAEA,SAAgB,iBAAiB,aAA6B;CAC5D,IAAI,SAAS;CAEb,SAAS,eAAe,MAAM;CAE9B,SAAS,OAAO,QAAQ,aAAa,EAAE,CAAC,CAAC,QAAQ,eAAe,EAAE;CAClE,OAAO;AACT"}
1
+ {"version":3,"file":"utils.js","names":[],"sources":["../../../src/components/Search/utils.ts"],"sourcesContent":["/** Where a search result lives: published here, cached from an uplink, or only on an uplink. */\nexport enum SearchOrigin {\n PRIVATE = 'private',\n CACHED = 'cached',\n REMOTE = 'remote',\n}\n\nexport const SEARCH_ORIGIN_ORDER = [SearchOrigin.PRIVATE, SearchOrigin.CACHED, SearchOrigin.REMOTE];\n\nexport type NormalizedSearchOption = {\n name: string;\n version?: string;\n description?: string;\n isPrivate: boolean;\n isCached: boolean;\n isRemote: boolean;\n origin?: SearchOrigin;\n};\n\n/**\n * Normalize a raw search result into a unified shape the UI can render,\n * regardless of which backend response format was returned:\n *\n * 1) npm-style \"search objects\" response where each entry is wrapped in\n * `{ package: { name, version, description, ... }, verdaccioPrivate, verdaccioPkgCached }`.\n * 2) Flat packument-style response where each entry exposes `name`, `version`,\n * `description`, `dist`, etc. directly at the top level.\n *\n * The second shape carries no uplink metadata, so private/remote/cached flags\n * default to `false` and the UI simply omits the corresponding badges.\n */\nexport function normalizeSearchOption(option: any): NormalizedSearchOption {\n if (option && typeof option === 'object' && option.package) {\n const pkg = option.package ?? {};\n const isPrivate = Boolean(option.verdaccioPrivate);\n const isCached = Boolean(option.verdaccioPkgCached);\n return {\n name: pkg.name,\n version: pkg.version,\n description: pkg.description,\n isPrivate,\n isCached,\n isRemote: !isCached && !isPrivate,\n origin: isPrivate\n ? SearchOrigin.PRIVATE\n : isCached\n ? SearchOrigin.CACHED\n : SearchOrigin.REMOTE,\n };\n }\n\n const flat = option ?? {};\n return {\n name: flat.name,\n version: flat.version,\n description: flat.description,\n isPrivate: false,\n isCached: false,\n isRemote: false,\n };\n}\n\n/** Orders results private, cached, remote (stable inside each group), as grouping requires. */\nexport function sortByOrigin<T>(options: T[]): T[] {\n const rank = (option: T) => {\n const origin = normalizeSearchOption(option).origin;\n return origin ? SEARCH_ORIGIN_ORDER.indexOf(origin) : SEARCH_ORIGIN_ORDER.length;\n };\n return options\n .map((option, index) => ({ option, index }))\n .sort((a, b) => rank(a.option) - rank(b.option) || a.index - b.index)\n .map(({ option }) => option);\n}\n\nfunction removeHtmlTags(input: string): string {\n let previous;\n do {\n previous = input;\n input = input.replace(/<[^>]*>?/gm, '');\n } while (input !== previous);\n return input;\n}\n\nexport function cleanDescription(description: string): string {\n let output = description;\n // remove html tags from description (e.g. <h1...>)\n output = removeHtmlTags(output);\n // remove markdown links from description (e.g. [link](url))\n output = output.replace(/\\(.*?\\)/gm, '').replace(/(\\[!?|\\])/gm, '');\n return output;\n}\n"],"mappings":";;AACA,IAAY,eAAL,yBAAA,cAAA;CACL,aAAA,aAAA;CACA,aAAA,YAAA;CACA,aAAA,YAAA;;AACF,EAAA,CAAA,CAAA;AAEA,IAAa,sBAAsB;;;;AAA+D;;;;;;;;;;;;;AAwBlG,SAAgB,sBAAsB,QAAqC;CACzE,IAAI,UAAU,OAAO,WAAW,YAAY,OAAO,SAAS;EAC1D,MAAM,MAAM,OAAO,WAAW,CAAC;EAC/B,MAAM,YAAY,QAAQ,OAAO,gBAAgB;EACjD,MAAM,WAAW,QAAQ,OAAO,kBAAkB;EAClD,OAAO;GACL,MAAM,IAAI;GACV,SAAS,IAAI;GACb,aAAa,IAAI;GACjB;GACA;GACA,UAAU,CAAC,YAAY,CAAC;GACxB,QAAQ,YAAA,YAEJ,WAAA,WAAA;EAGN;CACF;CAEA,MAAM,OAAO,UAAU,CAAC;CACxB,OAAO;EACL,MAAM,KAAK;EACX,SAAS,KAAK;EACd,aAAa,KAAK;EAClB,WAAW;EACX,UAAU;EACV,UAAU;CACZ;AACF;;AAGA,SAAgB,aAAgB,SAAmB;CACjD,MAAM,QAAQ,WAAc;EAC1B,MAAM,SAAS,sBAAsB,MAAM,CAAC,CAAC;EAC7C,OAAO,SAAS,oBAAoB,QAAQ,MAAM,IAAI,oBAAoB;CAC5E;CACA,OAAO,QACJ,KAAK,QAAQ,WAAW;EAAE;EAAQ;CAAM,EAAE,CAAC,CAC3C,MAAM,GAAG,MAAM,KAAK,EAAE,MAAM,IAAI,KAAK,EAAE,MAAM,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,CACpE,KAAK,EAAE,aAAa,MAAM;AAC/B;AAEA,SAAS,eAAe,OAAuB;CAC7C,IAAI;CACJ,GAAG;EACD,WAAW;EACX,QAAQ,MAAM,QAAQ,cAAc,EAAE;CACxC,SAAS,UAAU;CACnB,OAAO;AACT;AAEA,SAAgB,iBAAiB,aAA6B;CAC5D,IAAI,SAAS;CAEb,SAAS,eAAe,MAAM;CAE9B,SAAS,OAAO,QAAQ,aAAa,EAAE,CAAC,CAAC,QAAQ,eAAe,EAAE;CAClE,OAAO;AACT"}