@node-core/ui-components 1.0.1-a459447336d99556960d6f9e1c997327b29e4974 → 1.0.1-ab0ba1dcb1d91392c44e91b1e74e9f565e460543

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 (327) hide show
  1. package/.lintstagedrc.json +5 -0
  2. package/.postcssrc.json +6 -0
  3. package/.storybook/constants.ts +28 -0
  4. package/.storybook/main.ts +38 -0
  5. package/.storybook/preview-head.html +20 -0
  6. package/.storybook/preview.tsx +32 -0
  7. package/.stylelintignore +1 -0
  8. package/.stylelintrc.mjs +56 -0
  9. package/__design__/colors.stories.tsx +82 -0
  10. package/__design__/effects.stories.tsx +7 -0
  11. package/__design__/font-family.stories.tsx +76 -0
  12. package/__design__/list.stories.tsx +27 -0
  13. package/__design__/node-logos.stories.tsx +61 -0
  14. package/__design__/platform-logos.stories.tsx +31 -0
  15. package/__design__/social-logos.stories.tsx +33 -0
  16. package/__design__/table.stories.tsx +56 -0
  17. package/__design__/text.stories.tsx +100 -0
  18. package/eslint.config.js +61 -0
  19. package/package.json +45 -6
  20. package/src/Common/AlertBox/index.module.css +83 -0
  21. package/src/Common/AlertBox/index.stories.tsx +96 -0
  22. package/src/Common/AlertBox/index.tsx +24 -0
  23. package/src/Common/AvatarGroup/Avatar/index.module.css +40 -0
  24. package/src/Common/AvatarGroup/Avatar/index.stories.tsx +22 -0
  25. package/src/Common/AvatarGroup/Avatar/index.tsx +67 -0
  26. package/src/Common/AvatarGroup/Overlay/index.module.css +31 -0
  27. package/src/Common/AvatarGroup/Overlay/index.stories.tsx +33 -0
  28. package/src/Common/AvatarGroup/Overlay/index.tsx +37 -0
  29. package/src/Common/AvatarGroup/__tests__/index.test.jsx +55 -0
  30. package/src/Common/AvatarGroup/index.module.css +21 -0
  31. package/src/Common/AvatarGroup/index.stories.tsx +56 -0
  32. package/src/Common/AvatarGroup/index.tsx +83 -0
  33. package/src/Common/Badge/index.module.css +38 -0
  34. package/src/Common/Badge/index.stories.tsx +38 -0
  35. package/src/Common/Badge/index.tsx +35 -0
  36. package/src/Common/BadgeGroup/index.module.css +77 -0
  37. package/src/Common/BadgeGroup/index.stories.tsx +35 -0
  38. package/src/Common/BadgeGroup/index.tsx +35 -0
  39. package/src/Common/Banner/index.module.css +42 -0
  40. package/src/Common/Banner/index.stories.tsx +29 -0
  41. package/src/Common/Banner/index.tsx +18 -0
  42. package/src/Common/BaseActiveLink/__tests__/index.test.jsx +52 -0
  43. package/src/Common/BaseActiveLink/index.tsx +34 -0
  44. package/src/Common/BaseButton/index.module.css +145 -0
  45. package/src/Common/BaseButton/index.stories.tsx +67 -0
  46. package/src/Common/BaseButton/index.tsx +59 -0
  47. package/src/Common/BaseCodeBox/index.module.css +78 -0
  48. package/src/Common/BaseCodeBox/index.stories.tsx +39 -0
  49. package/src/Common/BaseCodeBox/index.tsx +122 -0
  50. package/src/Common/BaseCrossLink/index.module.css +51 -0
  51. package/src/Common/BaseCrossLink/index.stories.tsx +38 -0
  52. package/src/Common/BaseCrossLink/index.tsx +46 -0
  53. package/src/Common/BaseLinkTabs/index.module.css +43 -0
  54. package/src/Common/BaseLinkTabs/index.stories.tsx +34 -0
  55. package/src/Common/BaseLinkTabs/index.tsx +53 -0
  56. package/src/Common/BasePagination/Ellipsis/index.module.css +10 -0
  57. package/src/Common/BasePagination/Ellipsis/index.stories.tsx +10 -0
  58. package/src/Common/BasePagination/Ellipsis/index.tsx +11 -0
  59. package/src/Common/BasePagination/PaginationListItem/__tests__/index.test.jsx +58 -0
  60. package/src/Common/BasePagination/PaginationListItem/index.module.css +27 -0
  61. package/src/Common/BasePagination/PaginationListItem/index.stories.tsx +40 -0
  62. package/src/Common/BasePagination/PaginationListItem/index.tsx +39 -0
  63. package/src/Common/BasePagination/PrevNextArrow.tsx +15 -0
  64. package/src/Common/BasePagination/__tests__/index.test.jsx +180 -0
  65. package/src/Common/BasePagination/index.module.css +39 -0
  66. package/src/Common/BasePagination/index.stories.tsx +67 -0
  67. package/src/Common/BasePagination/index.tsx +77 -0
  68. package/src/Common/BasePagination/useGetPageElements.tsx +132 -0
  69. package/src/Common/Blockquote/index.module.css +29 -0
  70. package/src/Common/Blockquote/index.stories.tsx +45 -0
  71. package/src/Common/Blockquote/index.tsx +11 -0
  72. package/src/Common/Breadcrumbs/BreadcrumbHomeLink/index.module.css +5 -0
  73. package/src/Common/Breadcrumbs/BreadcrumbHomeLink/index.tsx +30 -0
  74. package/src/Common/Breadcrumbs/BreadcrumbItem/index.module.css +41 -0
  75. package/src/Common/Breadcrumbs/BreadcrumbItem/index.tsx +42 -0
  76. package/src/Common/Breadcrumbs/BreadcrumbLink/index.module.css +22 -0
  77. package/src/Common/Breadcrumbs/BreadcrumbLink/index.tsx +37 -0
  78. package/src/Common/Breadcrumbs/BreadcrumbRoot/index.module.css +9 -0
  79. package/src/Common/Breadcrumbs/BreadcrumbRoot/index.tsx +20 -0
  80. package/src/Common/Breadcrumbs/BreadcrumbTruncatedItem/index.tsx +9 -0
  81. package/src/Common/Breadcrumbs/index.stories.tsx +94 -0
  82. package/src/Common/Breadcrumbs/index.tsx +81 -0
  83. package/src/Common/ChangeHistory/index.module.css +83 -0
  84. package/src/Common/ChangeHistory/index.stories.tsx +130 -0
  85. package/src/Common/ChangeHistory/index.tsx +67 -0
  86. package/src/Common/CodeTabs/index.module.css +56 -0
  87. package/src/Common/CodeTabs/index.stories.tsx +73 -0
  88. package/src/Common/CodeTabs/index.tsx +16 -0
  89. package/src/Common/DataTag/index.module.css +56 -0
  90. package/src/Common/DataTag/index.stories.tsx +40 -0
  91. package/src/Common/DataTag/index.tsx +39 -0
  92. package/src/Common/GlowingBackdrop/index.module.css +32 -0
  93. package/src/Common/GlowingBackdrop/index.stories.tsx +10 -0
  94. package/src/Common/GlowingBackdrop/index.tsx +13 -0
  95. package/src/Common/LanguageDropDown/index.module.css +53 -0
  96. package/src/Common/LanguageDropDown/index.stories.tsx +19 -0
  97. package/src/Common/LanguageDropDown/index.tsx +56 -0
  98. package/src/Common/Modal/index.module.css +79 -0
  99. package/src/Common/Modal/index.stories.tsx +34 -0
  100. package/src/Common/Modal/index.tsx +50 -0
  101. package/src/Common/NodejsLogo/index.module.css +6 -0
  102. package/src/Common/NodejsLogo/index.stories.tsx +14 -0
  103. package/src/Common/NodejsLogo/index.tsx +26 -0
  104. package/src/Common/Notification/index.module.css +20 -0
  105. package/src/Common/Notification/index.stories.tsx +36 -0
  106. package/src/Common/Notification/index.tsx +34 -0
  107. package/src/Common/Preview/index.module.css +79 -0
  108. package/src/Common/Preview/index.stories.tsx +44 -0
  109. package/src/Common/Preview/index.tsx +25 -0
  110. package/src/Common/Select/__tests__/index.test.jsx +67 -0
  111. package/src/Common/Select/index.module.css +161 -0
  112. package/src/Common/Select/index.stories.tsx +111 -0
  113. package/src/Common/Select/index.tsx +187 -0
  114. package/src/Common/Separator/index.module.css +16 -0
  115. package/src/Common/Separator/index.stories.tsx +32 -0
  116. package/src/Common/Separator/index.tsx +27 -0
  117. package/src/Common/Skeleton/index.module.css +30 -0
  118. package/src/Common/Skeleton/index.tsx +39 -0
  119. package/src/Common/Tabs/__tests__/index.test.jsx +52 -0
  120. package/src/Common/Tabs/index.module.css +54 -0
  121. package/src/Common/Tabs/index.stories.tsx +50 -0
  122. package/src/Common/Tabs/index.tsx +54 -0
  123. package/src/Common/ThemeToggle/__tests__/index.test.jsx +35 -0
  124. package/src/Common/ThemeToggle/index.module.css +15 -0
  125. package/src/Common/ThemeToggle/index.stories.tsx +10 -0
  126. package/src/Common/ThemeToggle/index.tsx +15 -0
  127. package/src/Common/Tooltip/index.module.css +43 -0
  128. package/src/Common/Tooltip/index.stories.tsx +73 -0
  129. package/src/Common/Tooltip/index.tsx +48 -0
  130. package/src/Containers/Article/index.module.css +70 -0
  131. package/src/Containers/Article/index.stories.tsx +39 -0
  132. package/src/Containers/Article/index.tsx +9 -0
  133. package/src/Containers/DocSideBar/index.tsx +0 -0
  134. package/src/Containers/Footer/index.module.css +46 -0
  135. package/src/Containers/Footer/index.stories.tsx +27 -0
  136. package/src/Containers/Footer/index.tsx +95 -0
  137. package/src/Containers/MetaBar/__tests__/index.test.jsx +63 -0
  138. package/src/Containers/MetaBar/index.module.css +91 -0
  139. package/src/Containers/MetaBar/index.stories.tsx +80 -0
  140. package/src/Containers/MetaBar/index.tsx +72 -0
  141. package/src/Containers/NavBar/NavItem/index.module.css +60 -0
  142. package/src/Containers/NavBar/NavItem/index.stories.tsx +38 -0
  143. package/src/Containers/NavBar/NavItem/index.tsx +44 -0
  144. package/src/Containers/NavBar/index.module.css +125 -0
  145. package/src/Containers/NavBar/index.stories.tsx +45 -0
  146. package/src/Containers/NavBar/index.tsx +94 -0
  147. package/src/Containers/Sidebar/ProgressionIcon/index.tsx +16 -0
  148. package/src/Containers/Sidebar/SidebarGroup/index.module.css +64 -0
  149. package/src/Containers/Sidebar/SidebarGroup/index.stories.tsx +36 -0
  150. package/src/Containers/Sidebar/SidebarGroup/index.tsx +49 -0
  151. package/src/Containers/Sidebar/SidebarItem/index.module.css +56 -0
  152. package/src/Containers/Sidebar/SidebarItem/index.stories.tsx +15 -0
  153. package/src/Containers/Sidebar/SidebarItem/index.tsx +43 -0
  154. package/src/Containers/Sidebar/index.module.css +30 -0
  155. package/src/Containers/Sidebar/index.stories.tsx +88 -0
  156. package/src/Containers/Sidebar/index.tsx +70 -0
  157. package/src/Icons/HexagonGrid.stories.tsx +10 -0
  158. package/src/Icons/HexagonGrid.tsx +1434 -0
  159. package/src/Icons/InstallationMethod/Choco.tsx +78 -0
  160. package/src/Icons/InstallationMethod/Devbox.tsx +21 -0
  161. package/src/Icons/InstallationMethod/Docker.tsx +20 -0
  162. package/src/Icons/InstallationMethod/FNM.tsx +132 -0
  163. package/src/Icons/InstallationMethod/Homebrew.tsx +69 -0
  164. package/src/Icons/InstallationMethod/N.tsx +32 -0
  165. package/src/Icons/InstallationMethod/NVM.tsx +63 -0
  166. package/src/Icons/InstallationMethod/Volta.tsx +34 -0
  167. package/{Icons/InstallationMethod/index.js → src/Icons/InstallationMethod/index.ts} +1 -0
  168. package/src/Icons/Logos/JsGreen.tsx +24 -0
  169. package/src/Icons/Logos/JsWhite.tsx +37 -0
  170. package/src/Icons/Logos/Nodejs.tsx +372 -0
  171. package/src/Icons/Logos/NodejsStackedBlack.tsx +98 -0
  172. package/src/Icons/Logos/NodejsStackedDark.tsx +124 -0
  173. package/src/Icons/Logos/NodejsStackedLight.tsx +123 -0
  174. package/src/Icons/Logos/NodejsStackedWhite.tsx +98 -0
  175. package/src/Icons/Logos/index.ts +17 -0
  176. package/src/Icons/OperatingSystem/AIX.tsx +46 -0
  177. package/src/Icons/OperatingSystem/Apple.tsx +23 -0
  178. package/src/Icons/OperatingSystem/Linux.tsx +969 -0
  179. package/src/Icons/OperatingSystem/Microsoft.tsx +19 -0
  180. package/{Icons/OperatingSystem/index.js → src/Icons/OperatingSystem/index.ts} +1 -0
  181. package/src/Icons/PackageManager/Npm.tsx +21 -0
  182. package/src/Icons/PackageManager/Pnpm.tsx +22 -0
  183. package/src/Icons/PackageManager/Yarn.tsx +22 -0
  184. package/{Icons/PackageManager/index.js → src/Icons/PackageManager/index.ts} +1 -0
  185. package/src/Icons/Social/Bluesky.tsx +19 -0
  186. package/src/Icons/Social/Discord.tsx +20 -0
  187. package/src/Icons/Social/GitHub.tsx +16 -0
  188. package/src/Icons/Social/LinkedIn.tsx +16 -0
  189. package/src/Icons/Social/Mastodon.tsx +36 -0
  190. package/src/Icons/Social/Slack.tsx +31 -0
  191. package/src/Icons/Social/X.tsx +16 -0
  192. package/{Icons/Social/index.js → src/Icons/Social/index.ts} +1 -0
  193. package/src/MDX/CodeTabs.tsx +47 -0
  194. package/src/global.d.ts +4 -0
  195. package/src/stylelint/__tests__/index.test.mjs +80 -0
  196. package/src/stylelint/one-utility-class-per-line.mjs +64 -0
  197. package/{stylelint → src/stylelint}/utils.mjs +25 -19
  198. package/src/styles/animations.css +47 -0
  199. package/src/styles/base.css +17 -0
  200. package/src/styles/effects.css +12 -0
  201. package/src/styles/index.css +38 -0
  202. package/src/styles/markdown.css +173 -0
  203. package/src/styles/theme.css +175 -0
  204. package/src/types.ts +25 -0
  205. package/tsconfig.json +20 -0
  206. package/turbo.json +31 -0
  207. package/Common/AlertBox/index.js +0 -5
  208. package/Common/AlertBox/index.module.css +0 -77
  209. package/Common/AvatarGroup/Avatar/index.js +0 -11
  210. package/Common/AvatarGroup/Avatar/index.module.css +0 -60
  211. package/Common/AvatarGroup/Overlay/index.js +0 -6
  212. package/Common/AvatarGroup/Overlay/index.module.css +0 -38
  213. package/Common/AvatarGroup/index.js +0 -21
  214. package/Common/AvatarGroup/index.module.css +0 -22
  215. package/Common/Badge/index.js +0 -7
  216. package/Common/Badge/index.module.css +0 -46
  217. package/Common/BadgeGroup/index.js +0 -6
  218. package/Common/BadgeGroup/index.module.css +0 -101
  219. package/Common/Banner/index.js +0 -4
  220. package/Common/Banner/index.module.css +0 -45
  221. package/Common/BaseActiveLink/index.js +0 -14
  222. package/Common/BaseButton/index.js +0 -10
  223. package/Common/BaseButton/index.module.css +0 -372
  224. package/Common/BaseCodeBox/index.js +0 -50
  225. package/Common/BaseCodeBox/index.module.css +0 -96
  226. package/Common/BaseCrossLink/index.js +0 -12
  227. package/Common/BaseCrossLink/index.module.css +0 -69
  228. package/Common/BaseLinkTabs/index.js +0 -5
  229. package/Common/BaseLinkTabs/index.module.css +0 -77
  230. package/Common/BasePagination/Ellipsis/index.js +0 -4
  231. package/Common/BasePagination/Ellipsis/index.module.css +0 -16
  232. package/Common/BasePagination/PaginationListItem/index.js +0 -6
  233. package/Common/BasePagination/PaginationListItem/index.module.css +0 -42
  234. package/Common/BasePagination/PrevNextArrow.js +0 -7
  235. package/Common/BasePagination/index.js +0 -10
  236. package/Common/BasePagination/index.module.css +0 -40
  237. package/Common/BasePagination/useGetPageElements.js +0 -77
  238. package/Common/Blockquote/index.js +0 -4
  239. package/Common/Blockquote/index.module.css +0 -50
  240. package/Common/Breadcrumbs/BreadcrumbHomeLink/index.js +0 -9
  241. package/Common/Breadcrumbs/BreadcrumbHomeLink/index.module.css +0 -5
  242. package/Common/Breadcrumbs/BreadcrumbItem/index.js +0 -6
  243. package/Common/Breadcrumbs/BreadcrumbItem/index.module.css +0 -52
  244. package/Common/Breadcrumbs/BreadcrumbLink/index.js +0 -5
  245. package/Common/Breadcrumbs/BreadcrumbLink/index.module.css +0 -32
  246. package/Common/Breadcrumbs/BreadcrumbRoot/index.js +0 -4
  247. package/Common/Breadcrumbs/BreadcrumbRoot/index.module.css +0 -10
  248. package/Common/Breadcrumbs/BreadcrumbTruncatedItem/index.js +0 -4
  249. package/Common/Breadcrumbs/index.js +0 -22
  250. package/Common/ChangeHistory/index.js +0 -9
  251. package/Common/ChangeHistory/index.module.css +0 -198
  252. package/Common/CodeTabs/index.js +0 -5
  253. package/Common/CodeTabs/index.module.css +0 -67
  254. package/Common/DataTag/index.js +0 -18
  255. package/Common/DataTag/index.module.css +0 -54
  256. package/Common/GlowingBackdrop/index.js +0 -5
  257. package/Common/GlowingBackdrop/index.module.css +0 -130
  258. package/Common/LanguageDropDown/index.js +0 -11
  259. package/Common/LanguageDropDown/index.module.css +0 -151
  260. package/Common/Modal/index.js +0 -10
  261. package/Common/Modal/index.module.css +0 -234
  262. package/Common/NodejsLogo/index.js +0 -7
  263. package/Common/NodejsLogo/index.module.css +0 -5
  264. package/Common/Notification/index.js +0 -6
  265. package/Common/Notification/index.module.css +0 -104
  266. package/Common/Preview/index.js +0 -7
  267. package/Common/Preview/index.module.css +0 -283
  268. package/Common/Select/index.js +0 -49
  269. package/Common/Select/index.module.css +0 -328
  270. package/Common/Separator/index.js +0 -7
  271. package/Common/Separator/index.module.css +0 -13
  272. package/Common/Skeleton/index.js +0 -18
  273. package/Common/Skeleton/index.module.css +0 -127
  274. package/Common/Tabs/index.js +0 -6
  275. package/Common/Tabs/index.module.css +0 -72
  276. package/Common/ThemeToggle/index.js +0 -7
  277. package/Common/ThemeToggle/index.module.css +0 -22
  278. package/Common/Tooltip/index.js +0 -8
  279. package/Common/Tooltip/index.module.css +0 -133
  280. package/Containers/Article/index.js +0 -4
  281. package/Containers/Article/index.module.css +0 -139
  282. package/Containers/DocSideBar/index.js +0 -1
  283. package/Containers/Footer/index.js +0 -22
  284. package/Containers/Footer/index.module.css +0 -61
  285. package/Containers/MetaBar/index.js +0 -12
  286. package/Containers/MetaBar/index.module.css +0 -123
  287. package/Containers/NavBar/NavItem/index.js +0 -7
  288. package/Containers/NavBar/NavItem/index.module.css +0 -74
  289. package/Containers/NavBar/index.js +0 -18
  290. package/Containers/NavBar/index.module.css +0 -205
  291. package/Containers/Sidebar/ProgressionIcon/index.js +0 -3
  292. package/Containers/Sidebar/SidebarGroup/index.js +0 -9
  293. package/Containers/Sidebar/SidebarGroup/index.module.css +0 -192
  294. package/Containers/Sidebar/SidebarItem/index.js +0 -11
  295. package/Containers/Sidebar/SidebarItem/index.module.css +0 -67
  296. package/Containers/Sidebar/index.js +0 -15
  297. package/Containers/Sidebar/index.module.css +0 -48
  298. package/Icons/HexagonGrid.js +0 -3
  299. package/Icons/InstallationMethod/Choco.js +0 -3
  300. package/Icons/InstallationMethod/Devbox.js +0 -3
  301. package/Icons/InstallationMethod/Docker.js +0 -3
  302. package/Icons/InstallationMethod/FNM.js +0 -3
  303. package/Icons/InstallationMethod/Homebrew.js +0 -3
  304. package/Icons/InstallationMethod/N.js +0 -5
  305. package/Icons/InstallationMethod/NVM.js +0 -3
  306. package/Icons/InstallationMethod/Volta.js +0 -3
  307. package/Icons/Logos/JsWhite.js +0 -3
  308. package/Icons/Logos/Nodejs.js +0 -12
  309. package/Icons/Logos/index.js +0 -3
  310. package/Icons/OperatingSystem/AIX.js +0 -3
  311. package/Icons/OperatingSystem/Apple.js +0 -3
  312. package/Icons/OperatingSystem/Linux.js +0 -3
  313. package/Icons/OperatingSystem/Microsoft.js +0 -3
  314. package/Icons/PackageManager/Npm.js +0 -3
  315. package/Icons/PackageManager/Pnpm.js +0 -3
  316. package/Icons/PackageManager/Yarn.js +0 -3
  317. package/Icons/Social/Bluesky.js +0 -3
  318. package/Icons/Social/Discord.js +0 -3
  319. package/Icons/Social/GitHub.js +0 -3
  320. package/Icons/Social/LinkedIn.js +0 -3
  321. package/Icons/Social/Mastodon.js +0 -3
  322. package/Icons/Social/Slack.js +0 -3
  323. package/Icons/Social/X.js +0 -3
  324. package/MDX/CodeTabs.js +0 -16
  325. package/stylelint/one-utility-class-per-line.mjs +0 -48
  326. package/styles/index.css +0 -1136
  327. package/types.js +0 -1
@@ -0,0 +1,132 @@
1
+ import type { ComponentProps } from 'react';
2
+
3
+ import type BasePagination from '#ui/Common/BasePagination';
4
+ import Ellipsis from '#ui/Common/BasePagination/Ellipsis';
5
+ import type { PaginationListItemProps } from '#ui/Common/BasePagination/PaginationListItem';
6
+ import PaginationListItem from '#ui/Common/BasePagination/PaginationListItem';
7
+ import type { LinkLike } from '#ui/types';
8
+
9
+ const parsePages = (
10
+ pages: ComponentProps<typeof BasePagination>['pages'],
11
+ currentPage: number,
12
+ totalPages: number,
13
+ as: LinkLike,
14
+ getLabel: (pageNumber: number) => string
15
+ ): Array<PaginationListItemProps> =>
16
+ pages.map(({ url }, index) => ({
17
+ url,
18
+ pageNumber: index + 1,
19
+ currentPage,
20
+ totalPages,
21
+ label: getLabel(index + 1),
22
+ as,
23
+ }));
24
+
25
+ const createPaginationListItems = (
26
+ parsedPages: Array<PaginationListItemProps>
27
+ ) => parsedPages.map(page => <PaginationListItem key={page.url} {...page} />);
28
+
29
+ // The minimum amount of elements are first page, current page, and last page
30
+ const MINIMUM_AMOUNT_OF_ELEMENTS = 3;
31
+
32
+ // Not more than two ellipses will be shown at the same time
33
+ const MAXIMUM_AMOUNT_OF_ELLIPSES = 2;
34
+
35
+ // The logic of this custom hook has taken the internal logic of
36
+ // React MUI's Pagination component as reference. More info here:
37
+ // https://github.com/mui/material-ui/blob/master/packages/mui-material/src/usePagination/usePagination.js
38
+ export const useGetPageElements = (
39
+ currentPage: ComponentProps<typeof BasePagination>['currentPage'],
40
+ pages: ComponentProps<typeof BasePagination>['pages'],
41
+ currentPageSiblingsCount: number,
42
+ as: LinkLike,
43
+ getLabel: (pageNumber: number) => string
44
+ ) => {
45
+ const totalPages = pages.length;
46
+ const parsedPages = parsePages(pages, currentPage, totalPages, as, getLabel);
47
+ const currentPageIndex = currentPage - 1;
48
+
49
+ // We multiply it by two (2) as siblings are located on both left and right sides
50
+ // of the current page
51
+ const totalSiblingsCount = 2 * currentPageSiblingsCount;
52
+
53
+ const visiblePages =
54
+ totalSiblingsCount +
55
+ MINIMUM_AMOUNT_OF_ELEMENTS +
56
+ MAXIMUM_AMOUNT_OF_ELLIPSES;
57
+
58
+ // When there are more pages than the visible pages to be shown
59
+ // we do not need to perform any calculations
60
+ if (totalPages <= visiblePages) {
61
+ return createPaginationListItems(parsedPages);
62
+ }
63
+
64
+ // The index of the far-left sibling of the current page
65
+ const leftSiblingsFirstIndex = Math.max(
66
+ currentPageIndex - currentPageSiblingsCount,
67
+ 1
68
+ );
69
+
70
+ // The index of the far-right sibling of the current page
71
+ const rightSiblingsLastIndex = Math.min(
72
+ currentPageIndex + currentPageSiblingsCount + 1,
73
+ totalPages
74
+ );
75
+
76
+ const firstIndex = 0;
77
+ const lastIndex = totalPages - 1;
78
+
79
+ // If there are at least two (2) elements between the far-left sibling of
80
+ // the current page, and the first page, we should show left ellipsis
81
+ // between them
82
+ const hasLeftEllipsis = leftSiblingsFirstIndex > firstIndex + 2;
83
+
84
+ // If there are at least two (2) elements between the far-right sibling of
85
+ // the current page, and the last page, we should show right ellipsis
86
+ // between them
87
+ const hasRightEllipsis = rightSiblingsLastIndex < lastIndex - 1;
88
+
89
+ if (!hasLeftEllipsis && hasRightEllipsis) {
90
+ const leftPagesLastIndex = MINIMUM_AMOUNT_OF_ELEMENTS + totalSiblingsCount;
91
+
92
+ const leftPages = parsedPages.slice(firstIndex, leftPagesLastIndex);
93
+
94
+ return [
95
+ ...createPaginationListItems(leftPages),
96
+ <Ellipsis key="ellipsis" />,
97
+ ...createPaginationListItems(parsedPages.slice(lastIndex)),
98
+ ];
99
+ }
100
+
101
+ if (hasLeftEllipsis && !hasRightEllipsis) {
102
+ const rightPagesFirstIndex =
103
+ MINIMUM_AMOUNT_OF_ELEMENTS + totalSiblingsCount;
104
+
105
+ const rightPages = parsedPages.slice(totalPages - rightPagesFirstIndex);
106
+
107
+ return [
108
+ ...createPaginationListItems(
109
+ parsedPages.slice(firstIndex, firstIndex + 1)
110
+ ),
111
+ <Ellipsis key="ellipsis" />,
112
+ ...createPaginationListItems(rightPages),
113
+ ];
114
+ }
115
+
116
+ if (hasLeftEllipsis && hasRightEllipsis) {
117
+ const middlePages = parsedPages.slice(
118
+ leftSiblingsFirstIndex,
119
+ rightSiblingsLastIndex
120
+ );
121
+
122
+ return [
123
+ ...createPaginationListItems(
124
+ parsedPages.slice(firstIndex, firstIndex + 1)
125
+ ),
126
+ <Ellipsis key="ellipsis-1" />,
127
+ ...createPaginationListItems(middlePages),
128
+ <Ellipsis key="ellipsis-2" />,
129
+ ...createPaginationListItems(parsedPages.slice(lastIndex)),
130
+ ];
131
+ }
132
+ };
@@ -0,0 +1,29 @@
1
+ @reference "../../styles/index.css";
2
+
3
+ .wrapper {
4
+ @apply flex
5
+ max-w-2xl
6
+ flex-col
7
+ items-start
8
+ gap-4
9
+ self-stretch
10
+ border-l-2
11
+ border-green-600
12
+ py-2
13
+ pl-5
14
+ text-lg
15
+ font-semibold
16
+ text-neutral-900
17
+ dark:border-green-400
18
+ dark:text-white;
19
+
20
+ & cite {
21
+ @apply font-regular
22
+ text-base
23
+ not-italic;
24
+
25
+ &::before {
26
+ @apply content-['—_'];
27
+ }
28
+ }
29
+ }
@@ -0,0 +1,45 @@
1
+ import type { Meta as MetaObj, StoryObj } from '@storybook/react';
2
+
3
+ import Blockquote from '#ui/Common/Blockquote';
4
+
5
+ type Story = StoryObj<typeof Blockquote>;
6
+ type Meta = MetaObj<typeof Blockquote>;
7
+
8
+ export const Default: Story = {
9
+ args: {
10
+ children: (
11
+ <>
12
+ “An expert is a person who has made all the mistakes that can be made in
13
+ a very narrow field.”
14
+ <cite>Niels Bohr</cite>
15
+ </>
16
+ ),
17
+ },
18
+ };
19
+
20
+ export const WithoutAttribution: Story = {
21
+ args: {
22
+ children:
23
+ '“Commander Keen soared through the stars, leaving behind a galaxy of memories, adventure, and boundless imagination. In the realm of gaming, his farewell echoes as a timeless voyage into the hearts of those who dare to dream and explore the unknown.”',
24
+ },
25
+ };
26
+
27
+ export const Nested: Story = {
28
+ args: {
29
+ children: (
30
+ <>
31
+ “Words can be like X-rays, if you use them properly—they’ll go through
32
+ anything. You read and you’re pierced.”
33
+ <Blockquote>
34
+ “A thinker sees his own actions as experiments and questions--as
35
+ attempts to find out something. Success and failure are for him
36
+ answers above all.”
37
+ <cite>Friedrich Nietzsche</cite>
38
+ </Blockquote>
39
+ <cite>Aldous Huxley, Brave New World</cite>
40
+ </>
41
+ ),
42
+ },
43
+ };
44
+
45
+ export default { component: Blockquote } as Meta;
@@ -0,0 +1,11 @@
1
+ import type { ComponentProps, FC, PropsWithChildren } from 'react';
2
+
3
+ import styles from './index.module.css';
4
+
5
+ type BlockquoteProps = ComponentProps<'blockquote'>;
6
+
7
+ const Blockquote: FC<PropsWithChildren<BlockquoteProps>> = ({ children }) => (
8
+ <blockquote className={styles.wrapper}>{children}</blockquote>
9
+ );
10
+
11
+ export default Blockquote;
@@ -0,0 +1,5 @@
1
+ @reference "../../../styles/index.css";
2
+
3
+ .icon {
4
+ @apply size-4;
5
+ }
@@ -0,0 +1,30 @@
1
+ import HomeIcon from '@heroicons/react/24/outline/HomeIcon';
2
+ import type { ComponentProps, FC } from 'react';
3
+
4
+ import BreadcrumbLink from '#ui/Common/Breadcrumbs/BreadcrumbLink';
5
+
6
+ import styles from './index.module.css';
7
+
8
+ type BreadcrumbHomeLinkProps = Omit<
9
+ ComponentProps<typeof BreadcrumbLink>,
10
+ 'href'
11
+ > &
12
+ Partial<Pick<ComponentProps<typeof BreadcrumbLink>, 'href'>>;
13
+
14
+ const BreadcrumbHomeLink: FC<BreadcrumbHomeLinkProps> = ({
15
+ href = '/',
16
+ ...props
17
+ }) => {
18
+ const ariaLabel = props['aria-label'];
19
+ return (
20
+ <BreadcrumbLink href={href} {...props}>
21
+ <HomeIcon
22
+ title={ariaLabel}
23
+ aria-label={ariaLabel}
24
+ className={styles.icon}
25
+ />
26
+ </BreadcrumbLink>
27
+ );
28
+ };
29
+
30
+ export default BreadcrumbHomeLink;
@@ -0,0 +1,41 @@
1
+ @reference "../../../styles/index.css";
2
+
3
+ .item {
4
+ @apply flex
5
+ max-w-fit
6
+ items-center
7
+ gap-5
8
+ truncate
9
+ text-sm
10
+ font-medium;
11
+
12
+ &:last-child {
13
+ @apply w-full;
14
+ }
15
+
16
+ a {
17
+ @apply shrink
18
+ grow;
19
+ }
20
+
21
+ &,
22
+ > a,
23
+ > a:hover {
24
+ @apply text-neutral-800
25
+ motion-safe:transition-colors
26
+ dark:text-neutral-200;
27
+ }
28
+
29
+ &.visuallyHidden {
30
+ @apply hidden;
31
+ }
32
+
33
+ .separator {
34
+ @apply size-4
35
+ max-w-fit
36
+ shrink-0
37
+ grow
38
+ text-neutral-600
39
+ dark:text-neutral-400;
40
+ }
41
+ }
@@ -0,0 +1,42 @@
1
+ import ChevronRightIcon from '@heroicons/react/24/outline/ChevronRightIcon';
2
+ import classNames from 'classnames';
3
+ import type { ComponentProps, FC, PropsWithChildren } from 'react';
4
+
5
+ import styles from './index.module.css';
6
+
7
+ type BreadcrumbItemProps = {
8
+ disableMicrodata?: boolean;
9
+ hidden?: boolean;
10
+ hideSeparator?: boolean;
11
+ position?: number;
12
+ } & ComponentProps<'li'>;
13
+
14
+ const BreadcrumbItem: FC<PropsWithChildren<BreadcrumbItemProps>> = ({
15
+ disableMicrodata,
16
+ children,
17
+ hidden = false,
18
+ hideSeparator = false,
19
+ position,
20
+ ...props
21
+ }) => (
22
+ <li
23
+ {...props}
24
+ itemProp={!disableMicrodata ? 'itemListElement' : undefined}
25
+ itemScope={!disableMicrodata ? true : undefined}
26
+ itemType={!disableMicrodata ? 'https://schema.org/ListItem' : undefined}
27
+ className={classNames(
28
+ styles.item,
29
+ { [styles.visuallyHidden]: hidden },
30
+ props.className
31
+ )}
32
+ aria-hidden={hidden ? 'true' : undefined}
33
+ >
34
+ {children}
35
+ {position && <meta itemProp="position" content={`${position}`} />}
36
+ {!hideSeparator && (
37
+ <ChevronRightIcon aria-hidden="true" className={styles.separator} />
38
+ )}
39
+ </li>
40
+ );
41
+
42
+ export default BreadcrumbItem;
@@ -0,0 +1,22 @@
1
+ @reference "../../../styles/index.css";
2
+
3
+ .link {
4
+ @apply max-w-fit
5
+ truncate;
6
+
7
+ &.active {
8
+ @apply rounded
9
+ bg-green-600
10
+ px-2
11
+ py-1
12
+ font-semibold
13
+ text-white
14
+ motion-safe:transition-colors
15
+ dark:text-white;
16
+
17
+ &:hover {
18
+ @apply bg-green-700
19
+ text-white;
20
+ }
21
+ }
22
+ }
@@ -0,0 +1,37 @@
1
+ import classNames from 'classnames';
2
+ import type { ComponentProps, FC } from 'react';
3
+
4
+ import type { LinkLike } from '#ui/types';
5
+
6
+ import styles from './index.module.css';
7
+
8
+ type BreadcrumbLinkProps = {
9
+ active?: boolean;
10
+ as: LinkLike;
11
+ } & ComponentProps<LinkLike>;
12
+
13
+ const BreadcrumbLink: FC<BreadcrumbLinkProps> = ({
14
+ href,
15
+ active,
16
+ as: Component = 'a',
17
+ ...props
18
+ }) => (
19
+ <Component
20
+ itemScope
21
+ itemType="http://schema.org/Thing"
22
+ itemProp="item"
23
+ itemID={href?.toString()}
24
+ href={href}
25
+ className={classNames(
26
+ styles.link,
27
+ { [styles.active]: active },
28
+ props.className
29
+ )}
30
+ aria-current={active ? 'page' : undefined}
31
+ {...props}
32
+ >
33
+ <span itemProp="name">{props.children}</span>
34
+ </Component>
35
+ );
36
+
37
+ export default BreadcrumbLink;
@@ -0,0 +1,9 @@
1
+ @reference "../../../styles/index.css";
2
+
3
+ .list {
4
+ @apply xs:w-full
5
+ flex
6
+ w-screen
7
+ gap-5
8
+ px-6;
9
+ }
@@ -0,0 +1,20 @@
1
+ import type { FC, PropsWithChildren, ComponentProps } from 'react';
2
+
3
+ import styles from './index.module.css';
4
+
5
+ const BreadcrumbRoot: FC<PropsWithChildren<ComponentProps<'nav'>>> = ({
6
+ children,
7
+ ...props
8
+ }) => (
9
+ <nav aria-label="breadcrumb" {...props}>
10
+ <ol
11
+ itemScope
12
+ itemType="https://schema.org/BreadcrumbList"
13
+ className={styles.list}
14
+ >
15
+ {children}
16
+ </ol>
17
+ </nav>
18
+ );
19
+
20
+ export default BreadcrumbRoot;
@@ -0,0 +1,9 @@
1
+ import BreadcrumbItem from '#ui/Common/Breadcrumbs/BreadcrumbItem';
2
+
3
+ const BreadcrumbTruncatedItem = () => (
4
+ <BreadcrumbItem disableMicrodata>
5
+ <button disabled>…</button>
6
+ </BreadcrumbItem>
7
+ );
8
+
9
+ export default BreadcrumbTruncatedItem;
@@ -0,0 +1,94 @@
1
+ import type { Meta as MetaObj, StoryObj } from '@storybook/react';
2
+
3
+ import Breadcrumbs from '#ui/Common/Breadcrumbs';
4
+
5
+ type Story = StoryObj<typeof Breadcrumbs>;
6
+ type Meta = MetaObj<typeof Breadcrumbs>;
7
+
8
+ export const Default: Story = {
9
+ args: {
10
+ links: [
11
+ {
12
+ label: 'Learn',
13
+ href: '/learn',
14
+ },
15
+ {
16
+ label: 'Getting Started',
17
+ href: '/learn/getting-started',
18
+ },
19
+ {
20
+ label: 'Introduction to Node.js',
21
+ href: '/learn/getting-started/intro',
22
+ },
23
+ ],
24
+ },
25
+ };
26
+
27
+ export const Linkless: Story = {
28
+ args: {
29
+ links: [
30
+ {
31
+ label: 'Learn',
32
+ href: '',
33
+ },
34
+ {
35
+ label: 'Getting Started',
36
+ href: '',
37
+ },
38
+ {
39
+ label: 'Introduction to Node.js',
40
+ href: '',
41
+ },
42
+ ],
43
+ },
44
+ };
45
+
46
+ export const Truncate: Story = {
47
+ args: {
48
+ links: [
49
+ {
50
+ label: 'Learn',
51
+ href: '/learn',
52
+ },
53
+ {
54
+ label: 'Getting Started',
55
+ href: '/learn/getting-started',
56
+ },
57
+ {
58
+ label: 'Introduction to Node.js',
59
+ href: '/learn/getting-started/intro',
60
+ },
61
+ {
62
+ label: 'Installation',
63
+ href: '/learn/getting-started/intro/installation',
64
+ },
65
+ {
66
+ label: 'Documentation',
67
+ href: '/learn/getting-started/intro/installation/documentation',
68
+ },
69
+ ],
70
+ maxLength: 1,
71
+ },
72
+ };
73
+
74
+ export const HiddenHome: Story = {
75
+ args: {
76
+ hideHome: true,
77
+ links: [
78
+ {
79
+ label: 'Learn',
80
+ href: '/learn',
81
+ },
82
+ {
83
+ label: 'Getting Started',
84
+ href: '/learn/getting-started',
85
+ },
86
+ {
87
+ label: 'Introduction to Node.js',
88
+ href: '/learn/getting-started/intro',
89
+ },
90
+ ],
91
+ },
92
+ };
93
+
94
+ export default { component: Breadcrumbs } as Meta;
@@ -0,0 +1,81 @@
1
+ import type { FC } from 'react';
2
+ import { useMemo } from 'react';
3
+
4
+ import BreadcrumbHomeLink from '#ui/Common/Breadcrumbs/BreadcrumbHomeLink';
5
+ import BreadcrumbItem from '#ui/Common/Breadcrumbs/BreadcrumbItem';
6
+ import BreadcrumbLink from '#ui/Common/Breadcrumbs/BreadcrumbLink';
7
+ import BreadcrumbRoot from '#ui/Common/Breadcrumbs/BreadcrumbRoot';
8
+ import BreadcrumbTruncatedItem from '#ui/Common/Breadcrumbs/BreadcrumbTruncatedItem';
9
+ import type { FormattedMessage, LinkLike } from '#ui/types';
10
+
11
+ export type BreadcrumbLink = {
12
+ label: FormattedMessage;
13
+ href: string | undefined;
14
+ };
15
+
16
+ type BreadcrumbsProps = {
17
+ links: Array<BreadcrumbLink>;
18
+ maxLength?: number;
19
+ hideHome?: boolean;
20
+ as: LinkLike;
21
+ homeLinkAriaLabel?: string;
22
+ };
23
+
24
+ const Breadcrumbs: FC<BreadcrumbsProps> = ({
25
+ links = [],
26
+ maxLength = 5,
27
+ hideHome = false,
28
+ as = 'a',
29
+ homeLinkAriaLabel,
30
+ }) => {
31
+ const totalLength = links.length + +!hideHome;
32
+ const lengthOffset = maxLength - totalLength;
33
+ const isOverflow = lengthOffset < 0;
34
+
35
+ const items = useMemo(
36
+ () =>
37
+ links.map((link, index, items) => {
38
+ const position = index + 1;
39
+ const isLastItem = index === items.length - 1;
40
+ const hidden =
41
+ // We add 1 here to take into account of the truncated breadcrumb.
42
+ position <= Math.abs(lengthOffset) + 1 && isOverflow && !isLastItem;
43
+
44
+ return (
45
+ <BreadcrumbItem
46
+ key={link.label.toString()}
47
+ hidden={hidden}
48
+ hideSeparator={isLastItem}
49
+ position={position + +!hideHome}
50
+ >
51
+ {link.href || isLastItem ? (
52
+ <BreadcrumbLink
53
+ as={as}
54
+ href={link.href || undefined}
55
+ active={isLastItem}
56
+ >
57
+ {link.label}
58
+ </BreadcrumbLink>
59
+ ) : (
60
+ <span className="opacity-70">{link.label}</span>
61
+ )}
62
+ </BreadcrumbItem>
63
+ );
64
+ }),
65
+ [hideHome, isOverflow, lengthOffset, links]
66
+ );
67
+
68
+ return (
69
+ <BreadcrumbRoot>
70
+ {!hideHome && (
71
+ <BreadcrumbItem position={1}>
72
+ <BreadcrumbHomeLink as={as} aria-label={homeLinkAriaLabel} />
73
+ </BreadcrumbItem>
74
+ )}
75
+ {isOverflow && <BreadcrumbTruncatedItem />}
76
+ {items}
77
+ </BreadcrumbRoot>
78
+ );
79
+ };
80
+
81
+ export default Breadcrumbs;