@shipfox/react-ui 0.0.1

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 (224) hide show
  1. package/.storybook/main.ts +18 -0
  2. package/.storybook/preview.tsx +48 -0
  3. package/.turbo/turbo-build.log +6 -0
  4. package/.turbo/turbo-check.log +6 -0
  5. package/.turbo/turbo-type.log +5 -0
  6. package/CHANGELOG.md +7 -0
  7. package/LICENSE +21 -0
  8. package/dist/colors.stories.conts.d.ts +33 -0
  9. package/dist/colors.stories.conts.d.ts.map +1 -0
  10. package/dist/colors.stories.conts.js +166 -0
  11. package/dist/colors.stories.conts.js.map +1 -0
  12. package/dist/colors.stories.js +61 -0
  13. package/dist/colors.stories.js.map +1 -0
  14. package/dist/components/button.d.ts +13 -0
  15. package/dist/components/button.d.ts.map +1 -0
  16. package/dist/components/button.js +51 -0
  17. package/dist/components/button.js.map +1 -0
  18. package/dist/components/button.stories.js +174 -0
  19. package/dist/components/button.stories.js.map +1 -0
  20. package/dist/components/icon/custom/badge.d.ts +4 -0
  21. package/dist/components/icon/custom/badge.d.ts.map +1 -0
  22. package/dist/components/icon/custom/badge.js +20 -0
  23. package/dist/components/icon/custom/badge.js.map +1 -0
  24. package/dist/components/icon/custom/check-circle-solid.d.ts +4 -0
  25. package/dist/components/icon/custom/check-circle-solid.d.ts.map +1 -0
  26. package/dist/components/icon/custom/check-circle-solid.js +34 -0
  27. package/dist/components/icon/custom/check-circle-solid.js.map +1 -0
  28. package/dist/components/icon/custom/circle-dotted-line.d.ts +4 -0
  29. package/dist/components/icon/custom/circle-dotted-line.d.ts.map +1 -0
  30. package/dist/components/icon/custom/circle-dotted-line.js +20 -0
  31. package/dist/components/icon/custom/circle-dotted-line.js.map +1 -0
  32. package/dist/components/icon/custom/component-fill.d.ts +4 -0
  33. package/dist/components/icon/custom/component-fill.d.ts.map +1 -0
  34. package/dist/components/icon/custom/component-fill.js +20 -0
  35. package/dist/components/icon/custom/component-fill.js.map +1 -0
  36. package/dist/components/icon/custom/component-line.d.ts +4 -0
  37. package/dist/components/icon/custom/component-line.d.ts.map +1 -0
  38. package/dist/components/icon/custom/component-line.js +20 -0
  39. package/dist/components/icon/custom/component-line.js.map +1 -0
  40. package/dist/components/icon/custom/ellipse-mini-solid.d.ts +4 -0
  41. package/dist/components/icon/custom/ellipse-mini-solid.d.ts.map +1 -0
  42. package/dist/components/icon/custom/ellipse-mini-solid.js +22 -0
  43. package/dist/components/icon/custom/ellipse-mini-solid.js.map +1 -0
  44. package/dist/components/icon/custom/index.d.ts +12 -0
  45. package/dist/components/icon/custom/index.d.ts.map +1 -0
  46. package/dist/components/icon/custom/index.js +13 -0
  47. package/dist/components/icon/custom/index.js.map +1 -0
  48. package/dist/components/icon/custom/info-tooltip-fill.d.ts +4 -0
  49. package/dist/components/icon/custom/info-tooltip-fill.d.ts.map +1 -0
  50. package/dist/components/icon/custom/info-tooltip-fill.js +22 -0
  51. package/dist/components/icon/custom/info-tooltip-fill.js.map +1 -0
  52. package/dist/components/icon/custom/resize.d.ts +4 -0
  53. package/dist/components/icon/custom/resize.d.ts.map +1 -0
  54. package/dist/components/icon/custom/resize.js +20 -0
  55. package/dist/components/icon/custom/resize.js.map +1 -0
  56. package/dist/components/icon/custom/spinner.d.ts +4 -0
  57. package/dist/components/icon/custom/spinner.d.ts.map +1 -0
  58. package/dist/components/icon/custom/spinner.js +145 -0
  59. package/dist/components/icon/custom/spinner.js.map +1 -0
  60. package/dist/components/icon/custom/thunder.d.ts +4 -0
  61. package/dist/components/icon/custom/thunder.d.ts.map +1 -0
  62. package/dist/components/icon/custom/thunder.js +20 -0
  63. package/dist/components/icon/custom/thunder.js.map +1 -0
  64. package/dist/components/icon/custom/x-circle-solid.d.ts +4 -0
  65. package/dist/components/icon/custom/x-circle-solid.d.ts.map +1 -0
  66. package/dist/components/icon/custom/x-circle-solid.js +34 -0
  67. package/dist/components/icon/custom/x-circle-solid.js.map +1 -0
  68. package/dist/components/icon/icon.d.ts +27 -0
  69. package/dist/components/icon/icon.d.ts.map +1 -0
  70. package/dist/components/icon/icon.js +27 -0
  71. package/dist/components/icon/icon.js.map +1 -0
  72. package/dist/components/icon/icon.stories.js +35 -0
  73. package/dist/components/icon/icon.stories.js.map +1 -0
  74. package/dist/components/icon/index.d.ts +2 -0
  75. package/dist/components/icon/index.d.ts.map +1 -0
  76. package/dist/components/icon/index.js +3 -0
  77. package/dist/components/icon/index.js.map +1 -0
  78. package/dist/components/index.d.ts +5 -0
  79. package/dist/components/index.d.ts.map +1 -0
  80. package/dist/components/index.js +6 -0
  81. package/dist/components/index.js.map +1 -0
  82. package/dist/components/theme-provider.d.ts +10 -0
  83. package/dist/components/theme-provider.d.ts.map +1 -0
  84. package/dist/components/theme-provider.js +32 -0
  85. package/dist/components/theme-provider.js.map +1 -0
  86. package/dist/components/typography/code.d.ts +11 -0
  87. package/dist/components/typography/code.d.ts.map +1 -0
  88. package/dist/components/typography/code.js +28 -0
  89. package/dist/components/typography/code.js.map +1 -0
  90. package/dist/components/typography/code.stories.js +54 -0
  91. package/dist/components/typography/code.stories.js.map +1 -0
  92. package/dist/components/typography/header.d.ts +10 -0
  93. package/dist/components/typography/header.d.ts.map +1 -0
  94. package/dist/components/typography/header.js +34 -0
  95. package/dist/components/typography/header.js.map +1 -0
  96. package/dist/components/typography/header.stories.js +34 -0
  97. package/dist/components/typography/header.stories.js.map +1 -0
  98. package/dist/components/typography/index.d.ts +4 -0
  99. package/dist/components/typography/index.d.ts.map +1 -0
  100. package/dist/components/typography/index.js +5 -0
  101. package/dist/components/typography/index.js.map +1 -0
  102. package/dist/components/typography/text.d.ts +12 -0
  103. package/dist/components/typography/text.d.ts.map +1 -0
  104. package/dist/components/typography/text.js +32 -0
  105. package/dist/components/typography/text.js.map +1 -0
  106. package/dist/components/typography/text.stories.js +105 -0
  107. package/dist/components/typography/text.stories.js.map +1 -0
  108. package/dist/hooks/index.d.ts +3 -0
  109. package/dist/hooks/index.d.ts.map +1 -0
  110. package/dist/hooks/index.js +4 -0
  111. package/dist/hooks/index.js.map +1 -0
  112. package/dist/hooks/useCopy.d.ts +1 -0
  113. package/dist/hooks/useCopy.d.ts.map +1 -0
  114. package/dist/hooks/useCopy.js +2 -0
  115. package/dist/hooks/useCopy.js.map +1 -0
  116. package/dist/hooks/useCopyToClipboard.d.ts +10 -0
  117. package/dist/hooks/useCopyToClipboard.d.ts.map +1 -0
  118. package/dist/hooks/useCopyToClipboard.js +16 -0
  119. package/dist/hooks/useCopyToClipboard.js.map +1 -0
  120. package/dist/hooks/useTheme.d.ts +2 -0
  121. package/dist/hooks/useTheme.d.ts.map +1 -0
  122. package/dist/hooks/useTheme.js +9 -0
  123. package/dist/hooks/useTheme.js.map +1 -0
  124. package/dist/index.d.ts +4 -0
  125. package/dist/index.d.ts.map +1 -0
  126. package/dist/index.js +5 -0
  127. package/dist/index.js.map +1 -0
  128. package/dist/state/theme.d.ts +7 -0
  129. package/dist/state/theme.d.ts.map +1 -0
  130. package/dist/state/theme.js +8 -0
  131. package/dist/state/theme.js.map +1 -0
  132. package/dist/utils/clipboard.d.ts +2 -0
  133. package/dist/utils/clipboard.d.ts.map +1 -0
  134. package/dist/utils/clipboard.js +6 -0
  135. package/dist/utils/clipboard.js.map +1 -0
  136. package/dist/utils/cn.d.ts +3 -0
  137. package/dist/utils/cn.d.ts.map +1 -0
  138. package/dist/utils/cn.js +7 -0
  139. package/dist/utils/cn.js.map +1 -0
  140. package/dist/utils/date.d.ts +16 -0
  141. package/dist/utils/date.d.ts.map +1 -0
  142. package/dist/utils/date.js +79 -0
  143. package/dist/utils/date.js.map +1 -0
  144. package/dist/utils/format/chart.d.ts +3 -0
  145. package/dist/utils/format/chart.d.ts.map +1 -0
  146. package/dist/utils/format/chart.js +14 -0
  147. package/dist/utils/format/chart.js.map +1 -0
  148. package/dist/utils/format/date.d.ts +10 -0
  149. package/dist/utils/format/date.d.ts.map +1 -0
  150. package/dist/utils/format/date.js +57 -0
  151. package/dist/utils/format/date.js.map +1 -0
  152. package/dist/utils/format/duration.d.ts +9 -0
  153. package/dist/utils/format/duration.d.ts.map +1 -0
  154. package/dist/utils/format/duration.js +71 -0
  155. package/dist/utils/format/duration.js.map +1 -0
  156. package/dist/utils/format/index.d.ts +5 -0
  157. package/dist/utils/format/index.d.ts.map +1 -0
  158. package/dist/utils/format/index.js +6 -0
  159. package/dist/utils/format/index.js.map +1 -0
  160. package/dist/utils/format/number.d.ts +7 -0
  161. package/dist/utils/format/number.d.ts.map +1 -0
  162. package/dist/utils/format/number.js +20 -0
  163. package/dist/utils/format/number.js.map +1 -0
  164. package/dist/utils/index.d.ts +5 -0
  165. package/dist/utils/index.d.ts.map +1 -0
  166. package/dist/utils/index.js +6 -0
  167. package/dist/utils/index.js.map +1 -0
  168. package/index.css +778 -0
  169. package/package.json +74 -0
  170. package/src/colors.stories.conts.ts +164 -0
  171. package/src/colors.stories.tsx +66 -0
  172. package/src/components/button.stories.tsx +126 -0
  173. package/src/components/button.tsx +63 -0
  174. package/src/components/icon/custom/badge.tsx +17 -0
  175. package/src/components/icon/custom/check-circle-solid.tsx +24 -0
  176. package/src/components/icon/custom/circle-dotted-line.tsx +17 -0
  177. package/src/components/icon/custom/component-fill.tsx +17 -0
  178. package/src/components/icon/custom/component-line.tsx +17 -0
  179. package/src/components/icon/custom/ellipse-mini-solid.tsx +17 -0
  180. package/src/components/icon/custom/index.ts +11 -0
  181. package/src/components/icon/custom/info-tooltip-fill.tsx +21 -0
  182. package/src/components/icon/custom/resize.tsx +17 -0
  183. package/src/components/icon/custom/spinner.tsx +98 -0
  184. package/src/components/icon/custom/thunder.tsx +17 -0
  185. package/src/components/icon/custom/x-circle-solid.tsx +24 -0
  186. package/src/components/icon/icon.stories.tsx +29 -0
  187. package/src/components/icon/icon.tsx +42 -0
  188. package/src/components/icon/index.ts +1 -0
  189. package/src/components/index.ts +4 -0
  190. package/src/components/renovate.json +23 -0
  191. package/src/components/theme-provider.tsx +50 -0
  192. package/src/components/typography/code.stories.tsx +36 -0
  193. package/src/components/typography/code.tsx +38 -0
  194. package/src/components/typography/header.stories.tsx +27 -0
  195. package/src/components/typography/header.tsx +41 -0
  196. package/src/components/typography/index.ts +3 -0
  197. package/src/components/typography/text.stories.tsx +67 -0
  198. package/src/components/typography/text.tsx +42 -0
  199. package/src/hooks/index.ts +2 -0
  200. package/src/hooks/useCopy.ts +0 -0
  201. package/src/hooks/useCopyToClipboard.ts +20 -0
  202. package/src/hooks/useTheme.ts +10 -0
  203. package/src/index.ts +3 -0
  204. package/src/state/theme.ts +15 -0
  205. package/src/utils/clipboard.ts +4 -0
  206. package/src/utils/cn.ts +6 -0
  207. package/src/utils/date.test.ts +119 -0
  208. package/src/utils/date.ts +99 -0
  209. package/src/utils/format/chart.ts +16 -0
  210. package/src/utils/format/date.test.ts +65 -0
  211. package/src/utils/format/date.ts +75 -0
  212. package/src/utils/format/duration.test.ts +58 -0
  213. package/src/utils/format/duration.ts +82 -0
  214. package/src/utils/format/index.ts +4 -0
  215. package/src/utils/format/number.test.ts +38 -0
  216. package/src/utils/format/number.ts +33 -0
  217. package/src/utils/index.ts +4 -0
  218. package/test/global.ts +3 -0
  219. package/test/setup.ts +9 -0
  220. package/tsconfig.build.json +13 -0
  221. package/tsconfig.json +11 -0
  222. package/tsconfig.test.json +12 -0
  223. package/vercel.json +8 -0
  224. package/vitest.config.ts +17 -0
@@ -0,0 +1,98 @@
1
+ import type {RemixiconComponentType} from '@remixicon/react';
2
+ import type {ComponentProps} from 'react';
3
+
4
+ export function SpinnerIcon(_props: ComponentProps<RemixiconComponentType>) {
5
+ return (
6
+ <svg width="23" height="24" viewBox="0 0 23 24" fill="none" xmlns="http://www.w3.org/2000/svg">
7
+ <title>Spinner</title>
8
+ <path
9
+ opacity="0.55"
10
+ d="M10.583 1.91667C10.583 1.41041 10.9934 1 11.4997 1C12.0059 1 12.4163 1.41041 12.4163 1.91667V5.58333C12.4163 6.08959 12.0059 6.5 11.4997 6.5C10.9934 6.5 10.583 6.08959 10.583 5.58333V1.91667Z"
11
+ fill="currentColor"
12
+ stroke="currentColor"
13
+ style={{fill: 'currentColor', fillOpacity: 1, stroke: 'currentColor', strokeOpacity: 1}}
14
+ strokeWidth="0.916667"
15
+ strokeLinecap="round"
16
+ strokeLinejoin="round"
17
+ />
18
+ <rect
19
+ x="10.583"
20
+ y="17.5"
21
+ width="1.83333"
22
+ height="5.5"
23
+ rx="0.916667"
24
+ fill="currentColor"
25
+ stroke="currentColor"
26
+ style={{fill: 'currentColor', fillOpacity: 1, stroke: 'currentColor', strokeOpacity: 1}}
27
+ strokeWidth="0.916667"
28
+ strokeLinecap="round"
29
+ strokeLinejoin="round"
30
+ />
31
+ <path
32
+ opacity="0.25"
33
+ d="M1.41667 12.918C0.910406 12.918 0.5 12.5076 0.5 12.0013C0.5 11.495 0.910405 11.0846 1.41667 11.0846L5.08333 11.0846C5.58959 11.0846 6 11.495 6 12.0013C6 12.5076 5.58959 12.918 5.08333 12.918L1.41667 12.918Z"
34
+ fill="currentColor"
35
+ stroke="currentColor"
36
+ style={{fill: 'currentColor', fillOpacity: 1, stroke: 'currentColor', strokeOpacity: 1}}
37
+ strokeWidth="0.916667"
38
+ strokeLinecap="round"
39
+ strokeLinejoin="round"
40
+ />
41
+ <path
42
+ opacity="0.75"
43
+ d="M17.9167 12.918C17.4104 12.918 17 12.5076 17 12.0013C17 11.495 17.4104 11.0846 17.9167 11.0846L21.5833 11.0846C22.0896 11.0846 22.5 11.495 22.5 12.0013C22.5 12.5076 22.0896 12.918 21.5833 12.918L17.9167 12.918Z"
44
+ fill="currentColor"
45
+ stroke="currentColor"
46
+ style={{fill: 'currentColor', fillOpacity: 1, stroke: 'currentColor', strokeOpacity: 1}}
47
+ strokeWidth="0.916667"
48
+ strokeLinecap="round"
49
+ strokeLinejoin="round"
50
+ />
51
+ <path
52
+ opacity="0.38"
53
+ d="M3.7224 5.52123C3.36442 5.16325 3.36442 4.58285 3.7224 4.22487C4.08038 3.86689 4.66078 3.86688 5.01876 4.22487L7.61149 6.81759C7.96947 7.17557 7.96947 7.75597 7.61149 8.11395C7.25351 8.47193 6.67311 8.47193 6.31512 8.11395L3.7224 5.52123Z"
54
+ fill="currentColor"
55
+ stroke="currentColor"
56
+ style={{fill: 'currentColor', fillOpacity: 1, stroke: 'currentColor', strokeOpacity: 1}}
57
+ strokeWidth="0.916667"
58
+ strokeLinecap="round"
59
+ strokeLinejoin="round"
60
+ />
61
+ <rect
62
+ opacity="0.88"
63
+ x="14.7412"
64
+ y="16.5391"
65
+ width="1.83333"
66
+ height="5.5"
67
+ rx="0.916667"
68
+ transform="rotate(-45 14.7412 16.5391)"
69
+ fill="currentColor"
70
+ stroke="currentColor"
71
+ style={{fill: 'currentColor', fillOpacity: 1, stroke: 'currentColor', strokeOpacity: 1}}
72
+ strokeWidth="0.916667"
73
+ strokeLinecap="round"
74
+ strokeLinejoin="round"
75
+ />
76
+ <path
77
+ opacity="0.13"
78
+ d="M5.0183 19.7796C4.66032 20.1375 4.07992 20.1375 3.72194 19.7796C3.36396 19.4216 3.36396 18.8412 3.72194 18.4832L6.31466 15.8905C6.67264 15.5325 7.25304 15.5325 7.61102 15.8905C7.969 16.2484 7.969 16.8288 7.61102 17.1868L5.0183 19.7796Z"
79
+ fill="currentColor"
80
+ stroke="currentColor"
81
+ style={{fill: 'currentColor', fillOpacity: 1, stroke: 'currentColor', strokeOpacity: 1}}
82
+ strokeWidth="0.916667"
83
+ strokeLinecap="round"
84
+ strokeLinejoin="round"
85
+ />
86
+ <path
87
+ opacity="0.63"
88
+ d="M16.6853 8.11354C16.3273 8.47152 15.7469 8.47152 15.3889 8.11354C15.0309 7.75556 15.0309 7.17516 15.3889 6.81718L17.9817 4.22445C18.3396 3.86647 18.92 3.86647 19.278 4.22445C19.636 4.58243 19.636 5.16283 19.278 5.52081L16.6853 8.11354Z"
89
+ fill="currentColor"
90
+ stroke="currentColor"
91
+ style={{fill: 'currentColor', fillOpacity: 1, stroke: 'currentColor', strokeOpacity: 1}}
92
+ strokeWidth="0.916667"
93
+ strokeLinecap="round"
94
+ strokeLinejoin="round"
95
+ />
96
+ </svg>
97
+ );
98
+ }
@@ -0,0 +1,17 @@
1
+ import type {RemixiconComponentType} from '@remixicon/react';
2
+ import type {ComponentProps} from 'react';
3
+
4
+ export function ThunderIcon(_props: ComponentProps<RemixiconComponentType>) {
5
+ return (
6
+ <svg
7
+ width="25"
8
+ height="24"
9
+ viewBox="0 0 25 24"
10
+ fill="currentColor"
11
+ xmlns="http://www.w3.org/2000/svg"
12
+ >
13
+ <title>Thunder</title>
14
+ <path d="M14.2707 10.1872H19.5832L10.729 22V13.8219H5.4165L14.2707 2V10.1872Z" />
15
+ </svg>
16
+ );
17
+ }
@@ -0,0 +1,24 @@
1
+ import type {RemixiconComponentType} from '@remixicon/react';
2
+ import type {ComponentProps} from 'react';
3
+
4
+ export function XCircleSolidIcon(_props: ComponentProps<RemixiconComponentType>) {
5
+ return (
6
+ <svg
7
+ width="19"
8
+ height="18"
9
+ viewBox="0 0 19 18"
10
+ fill="currentColor"
11
+ xmlns="http://www.w3.org/2000/svg"
12
+ >
13
+ <title>X Circle Solid</title>
14
+ <g clipPath="url(#clip0_6552_160759)">
15
+ <path d="M9.49964 0.464844C4.79458 0.464844 0.966309 4.29311 0.966309 8.99818C0.966309 13.7032 4.79458 17.5315 9.49964 17.5315C14.2047 17.5315 18.033 13.7032 18.033 8.99818C18.033 4.29311 14.2047 0.464844 9.49964 0.464844ZM12.9983 11.3662C13.3108 11.6787 13.3108 12.1854 12.9983 12.4979C12.8426 12.6536 12.6378 12.7326 12.433 12.7326C12.2282 12.7326 12.0234 12.6547 11.8676 12.4979L9.49964 10.1299L7.13164 12.4979C6.97591 12.6536 6.77111 12.7326 6.56631 12.7326C6.36151 12.7326 6.15671 12.6547 6.00097 12.4979C5.68844 12.1854 5.68844 11.6787 6.00097 11.3662L8.36897 8.99818L6.00097 6.63018C5.68844 6.31764 5.68844 5.81098 6.00097 5.49844C6.31351 5.18591 6.82018 5.18591 7.13271 5.49844L9.50071 7.86644L11.8687 5.49844C12.1812 5.18591 12.6879 5.18591 13.0004 5.49844C13.313 5.81098 13.313 6.31764 13.0004 6.63018L10.6324 8.99818L13.0004 11.3662H12.9983Z" />
16
+ </g>
17
+ <defs>
18
+ <clipPath id="clip0_6552_160759">
19
+ <rect width="18" height="18" fill="white" transform="translate(0.5)" />
20
+ </clipPath>
21
+ </defs>
22
+ </svg>
23
+ );
24
+ }
@@ -0,0 +1,29 @@
1
+ import type {Meta, StoryObj} from '@storybook/react';
2
+ import {Code} from 'components/typography';
3
+ import {Icon, iconNames} from './icon';
4
+
5
+ const meta = {
6
+ title: 'Components/Icon',
7
+ component: Icon,
8
+ } satisfies Meta<typeof Icon>;
9
+
10
+ export default meta;
11
+ type Story = StoryObj<typeof meta>;
12
+
13
+ export const Gallery: Story = {
14
+ args: {name: 'google'},
15
+ render: (args) => (
16
+ <div className="flex flex-col gap-16">
17
+ <div className="grid grid-cols-8 gap-16">
18
+ {iconNames.toSorted().map((name) => (
19
+ <div key={name} className="flex flex-col items-center gap-4">
20
+ <Icon {...args} name={name} />
21
+ <Code variant="label" className="text-foreground-neutral-subtle">
22
+ {name}
23
+ </Code>
24
+ </div>
25
+ ))}
26
+ </div>
27
+ </div>
28
+ ),
29
+ };
@@ -0,0 +1,42 @@
1
+ import {type RemixiconComponentType, RiGoogleFill, RiMicrosoftFill} from '@remixicon/react';
2
+ import type {ComponentProps} from 'react';
3
+ import {
4
+ BadgeIcon,
5
+ CheckCircleSolidIcon,
6
+ CircleDottedLineIcon,
7
+ ComponentFillIcon,
8
+ ComponentLineIcon,
9
+ EllipseMiniSolidIcon,
10
+ InfoTooltipFillIcon,
11
+ ResizeIcon,
12
+ SpinnerIcon,
13
+ ThunderIcon,
14
+ XCircleSolidIcon,
15
+ } from './custom';
16
+
17
+ const iconsMap = {
18
+ google: RiGoogleFill,
19
+ microsoft: RiMicrosoftFill,
20
+ badge: BadgeIcon,
21
+ checkCircleSolid: CheckCircleSolidIcon,
22
+ circleDottedLine: CircleDottedLineIcon,
23
+ componentFill: ComponentFillIcon,
24
+ xCircleSolid: XCircleSolidIcon,
25
+ thunder: ThunderIcon,
26
+ resize: ResizeIcon,
27
+ infoTooltipFill: InfoTooltipFillIcon,
28
+ spinner: SpinnerIcon,
29
+ ellipseMiniSolid: EllipseMiniSolidIcon,
30
+ componentLine: ComponentLineIcon,
31
+ } as const satisfies Record<string, RemixiconComponentType>;
32
+
33
+ export type IconName = keyof typeof iconsMap;
34
+ export const iconNames = Object.keys(iconsMap) as IconName[];
35
+
36
+ type BaseIconProps = ComponentProps<typeof RiGoogleFill>;
37
+ type IconProps = {name: IconName} & Omit<BaseIconProps, 'name'>;
38
+
39
+ export function Icon({name, ...props}: IconProps) {
40
+ const IconComponent = iconsMap[name];
41
+ return <IconComponent {...props} />;
42
+ }
@@ -0,0 +1 @@
1
+ export * from './icon';
@@ -0,0 +1,4 @@
1
+ export * from './button';
2
+ export * from './icon';
3
+ export * from './theme-provider';
4
+ export * from './typography';
@@ -0,0 +1,23 @@
1
+ {
2
+ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3
+ "extends": [
4
+ "config:recommended",
5
+ "group:recommended",
6
+ "monorepo:turbo",
7
+ "monorepo:vitest",
8
+ "monorepo:react",
9
+ "packages:react",
10
+ "packages:vite",
11
+ "packages:unitTest",
12
+ "helpers:pinGitHubActionDigests",
13
+ "helpers:followTypescriptRc",
14
+ "customManagers:biomeVersions",
15
+ "customManagers:dockerfileVersions",
16
+ "replacements:all",
17
+ "security:openssf-scorecard",
18
+ ":configMigration",
19
+ "abandonments:recommended",
20
+ ":gitSignOff",
21
+ "schedule:daily"
22
+ ]
23
+ }
@@ -0,0 +1,50 @@
1
+ import {type ReactNode, useEffect, useState} from 'react';
2
+ import {type Theme, ThemeProviderContext} from 'state/theme';
3
+
4
+ type ThemeProviderProps = {
5
+ children: ReactNode;
6
+ defaultTheme?: Theme;
7
+ storageKey?: string;
8
+ };
9
+
10
+ export function ThemeProvider({
11
+ children,
12
+ defaultTheme = 'system',
13
+ storageKey = 'shipfox-theme',
14
+ ...props
15
+ }: ThemeProviderProps) {
16
+ const [theme, setTheme] = useState<Theme>(
17
+ () => (localStorage.getItem(storageKey) as Theme) || defaultTheme,
18
+ );
19
+
20
+ useEffect(() => {
21
+ const root = window.document.documentElement;
22
+
23
+ root.classList.remove('light', 'dark');
24
+
25
+ if (theme === 'system') {
26
+ const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches
27
+ ? 'dark'
28
+ : 'light';
29
+
30
+ root.classList.add(systemTheme);
31
+ return;
32
+ }
33
+
34
+ root.classList.add(theme);
35
+ }, [theme]);
36
+
37
+ const value = {
38
+ theme,
39
+ setTheme: (theme: Theme) => {
40
+ localStorage.setItem(storageKey, theme);
41
+ setTheme(theme);
42
+ },
43
+ };
44
+
45
+ return (
46
+ <ThemeProviderContext.Provider {...props} value={value}>
47
+ {children}
48
+ </ThemeProviderContext.Provider>
49
+ );
50
+ }
@@ -0,0 +1,36 @@
1
+ import type {Meta, StoryObj} from '@storybook/react';
2
+ import {Code} from './code';
3
+
4
+ const meta: Meta = {
5
+ title: 'Typography/Code',
6
+ };
7
+ export default meta;
8
+
9
+ type Story = StoryObj;
10
+
11
+ const variants = ['label', 'paragraph'] as const;
12
+
13
+ export const Default: Story = {
14
+ render: () => (
15
+ <div className="flex flex-col gap-16">
16
+ {variants.map((variant) => (
17
+ <div key={variant} className="grid grid-cols-2 gap-8">
18
+ <div className="flex flex-col gap-4">
19
+ <Code variant="label" className="text-foreground-neutral-subtle">
20
+ {variant}
21
+ </Code>
22
+ <Code variant={variant}>The quick brown fox jumps over the lazy dog</Code>
23
+ </div>
24
+ <div className="flex flex-col gap-4">
25
+ <Code variant="label" className="text-foreground-neutral-subtle">
26
+ {variant} - Bold
27
+ </Code>
28
+ <Code variant={variant} bold>
29
+ The quick brown fox jumps over the lazy dog
30
+ </Code>
31
+ </div>
32
+ </div>
33
+ ))}
34
+ </div>
35
+ ),
36
+ };
@@ -0,0 +1,38 @@
1
+ import {cva, type VariantProps} from 'class-variance-authority';
2
+ import type {ElementType, HTMLAttributes, PropsWithChildren} from 'react';
3
+ import {cn} from 'utils';
4
+
5
+ export const codeVariants = cva('', {
6
+ variants: {
7
+ variant: {
8
+ label: 'text-xs',
9
+ paragraph: 'text-sm',
10
+ },
11
+ },
12
+ defaultVariants: {
13
+ variant: 'paragraph',
14
+ },
15
+ });
16
+
17
+ export type CodeProps = PropsWithChildren<HTMLAttributes<HTMLParagraphElement>> &
18
+ VariantProps<typeof codeVariants> & {
19
+ as?: ElementType;
20
+ bold?: boolean;
21
+ };
22
+
23
+ export function Code({children, className, variant, as, bold, ...props}: CodeProps) {
24
+ const Component = as ?? 'p';
25
+ return (
26
+ <Component
27
+ className={cn(
28
+ codeVariants({variant}),
29
+ 'leading-20 font-code',
30
+ {'font-bold': bold},
31
+ className,
32
+ )}
33
+ {...props}
34
+ >
35
+ {children}
36
+ </Component>
37
+ );
38
+ }
@@ -0,0 +1,27 @@
1
+ import type {Meta, StoryObj} from '@storybook/react';
2
+ import {Code} from './code';
3
+ import {Header} from './header';
4
+
5
+ const meta: Meta = {
6
+ title: 'Typography/Header',
7
+ };
8
+ export default meta;
9
+
10
+ type Story = StoryObj;
11
+
12
+ const variants = ['h1', 'h2', 'h3', 'h4'] as const;
13
+
14
+ export const Default: Story = {
15
+ render: () => (
16
+ <div className="flex flex-col gap-16">
17
+ {variants.map((variant) => (
18
+ <div key={variant} className="flex flex-col gap-4">
19
+ <Code variant="label" className="text-foreground-neutral-subtle">
20
+ {variant}
21
+ </Code>
22
+ <Header variant={variant}>The quick brown fox jumps over the lazy dog</Header>
23
+ </div>
24
+ ))}
25
+ </div>
26
+ ),
27
+ };
@@ -0,0 +1,41 @@
1
+ import {cva, type VariantProps} from 'class-variance-authority';
2
+ import type {ElementType, HTMLAttributes, PropsWithChildren} from 'react';
3
+ import {cn} from 'utils';
4
+
5
+ export const headerVariants = cva('', {
6
+ variants: {
7
+ variant: {
8
+ h1: 'text-3xl',
9
+ h2: 'text-xl',
10
+ h3: 'text-lg',
11
+ h4: 'text-md',
12
+ },
13
+ },
14
+ defaultVariants: {
15
+ variant: 'h1',
16
+ },
17
+ });
18
+
19
+ const components = {
20
+ h1: 'h1',
21
+ h2: 'h2',
22
+ h3: 'h3',
23
+ h4: 'h4',
24
+ } as const;
25
+
26
+ export type HeaderProps = PropsWithChildren<HTMLAttributes<HTMLParagraphElement>> &
27
+ VariantProps<typeof headerVariants> & {
28
+ as?: ElementType;
29
+ };
30
+
31
+ export function Header({children, className, variant, as, ...props}: HeaderProps) {
32
+ const Component = as ?? (variant ? components[variant] : 'h1');
33
+ return (
34
+ <Component
35
+ className={cn(headerVariants({variant}), 'font-display font-medium', className)}
36
+ {...props}
37
+ >
38
+ {children}
39
+ </Component>
40
+ );
41
+ }
@@ -0,0 +1,3 @@
1
+ export * from './code';
2
+ export * from './header';
3
+ export * from './text';
@@ -0,0 +1,67 @@
1
+ import type {Meta, StoryObj} from '@storybook/react';
2
+ import {Code} from './code';
3
+ import {Text} from './text';
4
+
5
+ const meta: Meta = {
6
+ title: 'Typography/Text',
7
+ };
8
+ export default meta;
9
+
10
+ type Story = StoryObj;
11
+
12
+ const sizes = ['xs', 'sm', 'md', 'lg', 'xl'] as const;
13
+
14
+ export const Default: Story = {
15
+ render: () => (
16
+ <div className="flex flex-col gap-16">
17
+ {sizes.map((size) => (
18
+ <div key={size} className="grid grid-cols-2 gap-8">
19
+ <div className="flex flex-col gap-4">
20
+ <Code variant="label" className="text-foreground-neutral-subtle">
21
+ {size}
22
+ </Code>
23
+ <Text size={size}>The quick brown fox jumps over the lazy dog</Text>
24
+ </div>
25
+ <div className="flex flex-col gap-4">
26
+ <Code variant="label" className="text-foreground-neutral-subtle">
27
+ {size} - Bold
28
+ </Code>
29
+ <Text size={size} bold>
30
+ The quick brown fox jumps over the lazy dog
31
+ </Text>
32
+ </div>
33
+ </div>
34
+ ))}
35
+ </div>
36
+ ),
37
+ };
38
+
39
+ const textParagraph =
40
+ 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';
41
+
42
+ export const Paragraph: Story = {
43
+ render: () => (
44
+ <div className="flex flex-col gap-16">
45
+ {sizes.map((size) => (
46
+ <div key={size} className="grid grid-cols-2 gap-8">
47
+ <div className="flex flex-col gap-4">
48
+ <Code variant="label" className="text-foreground-neutral-subtle">
49
+ {size} - Regular
50
+ </Code>
51
+ <Text size={size} compact={false}>
52
+ {textParagraph}
53
+ </Text>
54
+ </div>
55
+ <div className="flex flex-col gap-4">
56
+ <Code variant="label" className="text-foreground-neutral-subtle">
57
+ {size} - Compact
58
+ </Code>
59
+ <Text size={size} compact={true}>
60
+ {textParagraph}
61
+ </Text>
62
+ </div>
63
+ </div>
64
+ ))}
65
+ </div>
66
+ ),
67
+ };
@@ -0,0 +1,42 @@
1
+ import {cva, type VariantProps} from 'class-variance-authority';
2
+ import type {ElementType, HTMLAttributes, PropsWithChildren} from 'react';
3
+ import {cn} from 'utils';
4
+
5
+ export const textVariants = cva('', {
6
+ variants: {
7
+ size: {
8
+ xs: 'text-xs',
9
+ sm: 'text-sm',
10
+ md: 'text-md',
11
+ lg: 'text-lg',
12
+ xl: 'text-xl',
13
+ },
14
+ },
15
+ defaultVariants: {
16
+ size: 'md',
17
+ },
18
+ });
19
+
20
+ export type TextProps = PropsWithChildren<HTMLAttributes<HTMLParagraphElement>> &
21
+ VariantProps<typeof textVariants> & {
22
+ as?: ElementType;
23
+ compact?: boolean;
24
+ bold?: boolean;
25
+ };
26
+
27
+ export function Text({children, className, size, as, compact, bold, ...props}: TextProps) {
28
+ const Component = as ?? 'p';
29
+ return (
30
+ <Component
31
+ className={cn(
32
+ textVariants({size}),
33
+ 'font-display',
34
+ {'leading-20': compact, 'font-medium': bold},
35
+ className,
36
+ )}
37
+ {...props}
38
+ >
39
+ {children}
40
+ </Component>
41
+ );
42
+ }
@@ -0,0 +1,2 @@
1
+ export * from './useCopyToClipboard';
2
+ export * from './useTheme';
File without changes
@@ -0,0 +1,20 @@
1
+ import {useState} from 'react';
2
+ import {copyTextToClipboard} from 'utils';
3
+
4
+ interface UseCopyToClipboardParams {
5
+ text: string;
6
+ onCopy?: (text: string) => void;
7
+ }
8
+
9
+ export function useCopyToClipboard({text, onCopy}: UseCopyToClipboardParams) {
10
+ const [copied, setCopied] = useState(false);
11
+
12
+ const copy = async () => {
13
+ await copyTextToClipboard(text);
14
+
15
+ if (onCopy) onCopy(text);
16
+ setCopied(true);
17
+ };
18
+
19
+ return {copy, copied};
20
+ }
@@ -0,0 +1,10 @@
1
+ import {useContext} from 'react';
2
+ import {ThemeProviderContext} from 'state/theme';
3
+
4
+ export const useTheme = () => {
5
+ const context = useContext(ThemeProviderContext);
6
+
7
+ if (context === undefined) throw new Error('useTheme must be used within a ThemeProvider');
8
+
9
+ return context;
10
+ };
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from './components';
2
+ export * from './hooks';
3
+ export * from './utils';
@@ -0,0 +1,15 @@
1
+ import {createContext} from 'react';
2
+
3
+ export type Theme = 'dark' | 'light' | 'system';
4
+
5
+ export type ThemeProviderState = {
6
+ theme: Theme;
7
+ setTheme: (theme: Theme) => void;
8
+ };
9
+
10
+ const initialState: ThemeProviderState = {
11
+ theme: 'system',
12
+ setTheme: () => null,
13
+ };
14
+
15
+ export const ThemeProviderContext = createContext<ThemeProviderState>(initialState);
@@ -0,0 +1,4 @@
1
+ export async function copyTextToClipboard(text: string) {
2
+ if ('clipboard' in navigator) return await navigator.clipboard.writeText(text);
3
+ return document.execCommand('copy', true, text);
4
+ }
@@ -0,0 +1,6 @@
1
+ import {type ClassValue, clsx} from 'clsx';
2
+ import {twMerge} from 'tailwind-merge';
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs));
6
+ }