@infonomic/uikit 2.0.0 → 2.1.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 (314) hide show
  1. package/dist/components/button/index.js +1 -17
  2. package/dist/components/card/card.d.ts.map +1 -1
  3. package/dist/tsconfig.build.tsbuildinfo +1 -1
  4. package/package.json +35 -31
  5. package/src/astro.d.ts +43 -0
  6. package/src/astro.js +2 -2
  7. package/src/components/@types/shared.ts +24 -0
  8. package/src/components/accordion/accordion.module.css +60 -0
  9. package/src/components/accordion/accordion.stories.tsx +117 -0
  10. package/src/components/accordion/accordion.tsx +105 -0
  11. package/src/components/animation/fade-in-lift.stories.tsx +81 -0
  12. package/src/components/animation/fade-in-lift.tsx +42 -0
  13. package/src/components/avatar/avatar.module.css +54 -0
  14. package/src/components/avatar/avatar.stories.tsx +28 -0
  15. package/src/components/avatar/avatar.tsx +19 -0
  16. package/src/components/button/@types/button.ts +17 -0
  17. package/src/components/button/button-group.module.css +17 -0
  18. package/src/components/button/button-group.stories.tsx +45 -0
  19. package/src/components/button/button-group.tsx +132 -0
  20. package/src/components/button/button-icon.stories.tsx +145 -0
  21. package/src/components/button/button-intents.stories.tsx +50 -0
  22. package/src/components/button/button-variants.stories.tsx +60 -0
  23. package/src/components/button/button.astro +86 -0
  24. package/src/components/button/button.module.css +533 -0
  25. package/src/components/button/button.tsx +81 -0
  26. package/src/components/button/control-buttons.module.css +144 -0
  27. package/src/components/button/control-buttons.stories.tsx +60 -0
  28. package/src/components/button/control-buttons.tsx +137 -0
  29. package/src/components/button/copy-button.module.css +31 -0
  30. package/src/components/button/copy-button.stories.tsx +50 -0
  31. package/src/components/button/copy-button.tsx +92 -0
  32. package/src/components/button/icon-button.astro +47 -0
  33. package/src/components/button/icon-button.tsx +44 -0
  34. package/src/components/button/index.ts +5 -0
  35. package/src/components/calendar/calendar.module.css +315 -0
  36. package/src/components/calendar/calendar.stories.tsx +139 -0
  37. package/src/components/calendar/calendar.tsx +173 -0
  38. package/src/components/card/card-content.astro +14 -0
  39. package/src/components/card/card-description.astro +14 -0
  40. package/src/components/card/card-footer.astro +14 -0
  41. package/src/components/card/card-header.astro +14 -0
  42. package/src/components/card/card-title.astro +14 -0
  43. package/src/components/card/card.astro +41 -0
  44. package/src/components/card/card.module.css +67 -0
  45. package/src/components/card/card.stories.tsx +61 -0
  46. package/src/components/card/card.tsx +86 -0
  47. package/src/components/container/container.astro +13 -0
  48. package/src/components/container/container.module.css +28 -0
  49. package/src/components/container/container.stories.tsx +42 -0
  50. package/src/components/container/container.tsx +23 -0
  51. package/src/components/dropdown/dropdown.module.css +131 -0
  52. package/src/components/dropdown/dropdown.stories.tsx +103 -0
  53. package/src/components/dropdown/dropdown.tsx +193 -0
  54. package/src/components/hamburger/hamburger.astro +30 -0
  55. package/src/components/hamburger/hamburger.tsx +66 -0
  56. package/src/components/input/@types/checkbox.ts +20 -0
  57. package/src/components/input/@types/input.ts +20 -0
  58. package/src/components/input/checkbox-group.tsx +78 -0
  59. package/src/components/input/checkbox.module.css +267 -0
  60. package/src/components/input/checkbox.stories.tsx +240 -0
  61. package/src/components/input/checkbox.tsx +95 -0
  62. package/src/components/input/error-text.astro +14 -0
  63. package/src/components/input/error-text.module.css +19 -0
  64. package/src/components/input/error-text.tsx +18 -0
  65. package/src/components/input/errors.tsx +37 -0
  66. package/src/components/input/help-text.astro +13 -0
  67. package/src/components/input/help-text.module.css +19 -0
  68. package/src/components/input/help-text.tsx +13 -0
  69. package/src/components/input/index.tsx +8 -0
  70. package/src/components/input/input-adornment.astro +26 -0
  71. package/src/components/input/input-adornment.module.css +18 -0
  72. package/src/components/input/input-adornment.tsx +36 -0
  73. package/src/components/input/input.astro +99 -0
  74. package/src/components/input/input.module.css +310 -0
  75. package/src/components/input/input.stories.tsx +174 -0
  76. package/src/components/input/input.tsx +103 -0
  77. package/src/components/input/label.astro +24 -0
  78. package/src/components/input/label.module.css +28 -0
  79. package/src/components/input/label.tsx +25 -0
  80. package/src/components/input/radio-group.module.css +219 -0
  81. package/src/components/input/radio-group.stories.tsx +73 -0
  82. package/src/components/input/radio-group.tsx +67 -0
  83. package/src/components/input/select.module.css +75 -0
  84. package/src/components/input/select.stories.tsx +34 -0
  85. package/src/components/input/select.tsx +115 -0
  86. package/src/components/input/text-area.module.css +9 -0
  87. package/src/components/input/text-area.stories.tsx +51 -0
  88. package/src/components/input/text-area.tsx +81 -0
  89. package/src/components/input/utils.ts +21 -0
  90. package/src/components/notifications/@types/alert.ts +12 -0
  91. package/src/components/notifications/@types/toast.ts +12 -0
  92. package/src/components/notifications/alert.module.css +114 -0
  93. package/src/components/notifications/alert.stories.tsx +39 -0
  94. package/src/components/notifications/alert.tsx +117 -0
  95. package/src/components/notifications/index.ts +2 -0
  96. package/src/components/notifications/toast.module.css +237 -0
  97. package/src/components/notifications/toast.stories.tsx +42 -0
  98. package/src/components/notifications/toast.tsx +124 -0
  99. package/src/components/overlay/index.stories.tsx +29 -0
  100. package/src/components/overlay/index.ts +2 -0
  101. package/src/components/overlay/overlay.module.css +41 -0
  102. package/src/components/overlay/overlay.tsx +61 -0
  103. package/src/components/pager/@types/index.ts +2 -0
  104. package/src/components/pager/ellipses.tsx +18 -0
  105. package/src/components/pager/event-pager.tsx +18 -0
  106. package/src/components/pager/first-button.tsx +53 -0
  107. package/src/components/pager/hooks/types/usePagination.ts +80 -0
  108. package/src/components/pager/hooks/usePagination.ts +140 -0
  109. package/src/components/pager/icons/first.tsx +33 -0
  110. package/src/components/pager/icons/index.tsx +4 -0
  111. package/src/components/pager/icons/last.tsx +33 -0
  112. package/src/components/pager/icons/next.tsx +20 -0
  113. package/src/components/pager/icons/previous.tsx +20 -0
  114. package/src/components/pager/index.ts +4 -0
  115. package/src/components/pager/last-button.tsx +57 -0
  116. package/src/components/pager/next-button.tsx +55 -0
  117. package/src/components/pager/number-button.tsx +83 -0
  118. package/src/components/pager/pagination.module.css +165 -0
  119. package/src/components/pager/pagination.stories.tsx +190 -0
  120. package/src/components/pager/pagination.tsx +266 -0
  121. package/src/components/pager/previous-button.tsx +51 -0
  122. package/src/components/scroll-area/scroll-area.module.css +80 -0
  123. package/src/components/scroll-area/scroll-area.stories.tsx +33 -0
  124. package/src/components/scroll-area/scroll-area.tsx +22 -0
  125. package/src/components/scroll-to-top/scroll-to-top.tsx +59 -0
  126. package/src/components/section/section.astro +13 -0
  127. package/src/components/section/section.module.css +7 -0
  128. package/src/components/section/section.tsx +23 -0
  129. package/src/components/shimmer/shimmer.module.css +53 -0
  130. package/src/components/shimmer/shimmer.stories.tsx +24 -0
  131. package/src/components/shimmer/shimmer.tsx +70 -0
  132. package/src/components/table/table.module.css +100 -0
  133. package/src/components/table/table.stories.tsx +95 -0
  134. package/src/components/table/table.tsx +165 -0
  135. package/src/components/tabs/tabs.module.css +64 -0
  136. package/src/components/tabs/tabs.stories.tsx +47 -0
  137. package/src/components/tabs/tabs.tsx +75 -0
  138. package/src/components/timeline/timeline.module.css +87 -0
  139. package/src/components/timeline/timeline.stories.tsx +50 -0
  140. package/src/components/timeline/timeline.tsx +177 -0
  141. package/src/components/tooltip/tooltip.module.css +55 -0
  142. package/src/components/tooltip/tooltip.stories.tsx +59 -0
  143. package/src/components/tooltip/tooltip.tsx +51 -0
  144. package/src/declarations.d.ts +4 -0
  145. package/src/hooks/use-media-query.ts +20 -0
  146. package/src/icons/activity-icon.tsx +40 -0
  147. package/src/icons/calendar-icon.tsx +39 -0
  148. package/src/icons/check-icon.tsx +33 -0
  149. package/src/icons/chevron-down-icon.tsx +39 -0
  150. package/src/icons/chevron-left-double-icon.tsx +58 -0
  151. package/src/icons/chevron-left-icon.tsx +58 -0
  152. package/src/icons/chevron-right-double-icon.tsx +58 -0
  153. package/src/icons/chevron-right-icon.tsx +58 -0
  154. package/src/icons/chevrons-up-down.tsx +37 -0
  155. package/src/icons/close-icon.astro +38 -0
  156. package/src/icons/close-icon.tsx +30 -0
  157. package/src/icons/copy-icon.tsx +35 -0
  158. package/src/icons/danger-icon.tsx +18 -0
  159. package/src/icons/dashboard-icon.tsx +41 -0
  160. package/src/icons/delete-icon.tsx +34 -0
  161. package/src/icons/document-icon.tsx +38 -0
  162. package/src/icons/download-icon.tsx +39 -0
  163. package/src/icons/edit-icon.tsx +35 -0
  164. package/src/icons/ellipsis-icon.tsx +38 -0
  165. package/src/icons/email-icon.tsx +33 -0
  166. package/src/icons/external-link-icon.tsx +39 -0
  167. package/src/icons/github-icon.tsx +27 -0
  168. package/src/icons/globe-icon.tsx +50 -0
  169. package/src/icons/google-icon.tsx +44 -0
  170. package/src/icons/gripper-vertical-icon.tsx +43 -0
  171. package/src/icons/history-icon.tsx +32 -0
  172. package/src/icons/home-icon.tsx +34 -0
  173. package/src/icons/icon-element.astro +27 -0
  174. package/src/icons/icon-element.tsx +32 -0
  175. package/src/icons/icon-sprite.tsx +18 -0
  176. package/src/icons/icons.module.css +147 -0
  177. package/src/icons/index.stories.tsx +25 -0
  178. package/src/icons/index.ts +39 -0
  179. package/src/icons/info-icon.tsx +18 -0
  180. package/src/icons/infonomic-icon.tsx +173 -0
  181. package/src/icons/light-icon.astro +36 -0
  182. package/src/icons/light-icon.tsx +29 -0
  183. package/src/icons/location-pin-icon.tsx +36 -0
  184. package/src/icons/moon-icon.astro +38 -0
  185. package/src/icons/moon-icon.tsx +42 -0
  186. package/src/icons/plus-icon.tsx +34 -0
  187. package/src/icons/primary-icon.tsx +22 -0
  188. package/src/icons/refresh-icon.tsx +33 -0
  189. package/src/icons/return-icon.tsx +36 -0
  190. package/src/icons/roles-icon.tsx +34 -0
  191. package/src/icons/search-icon.astro +40 -0
  192. package/src/icons/search-icon.tsx +29 -0
  193. package/src/icons/search-menu-icon.tsx +42 -0
  194. package/src/icons/settings-gear-icon.tsx +36 -0
  195. package/src/icons/settings-sliders-icon.tsx +43 -0
  196. package/src/icons/sign-out-icon.tsx +35 -0
  197. package/src/icons/source/icon-calendar.svg +1 -0
  198. package/src/icons/source/icon-check.svg +4 -0
  199. package/src/icons/source/icon-close.svg +3 -0
  200. package/src/icons/source/icon-coinbase.svg +9 -0
  201. package/src/icons/source/icon-copy.svg +4 -0
  202. package/src/icons/source/icon-document.svg +5 -0
  203. package/src/icons/source/icon-download.svg +4 -0
  204. package/src/icons/source/icon-edit.svg +6 -0
  205. package/src/icons/source/icon-eth-purple.svg +15 -0
  206. package/src/icons/source/icon-etherscan.svg +5 -0
  207. package/src/icons/source/icon-external-link.svg +4 -0
  208. package/src/icons/source/icon-globe.svg +7 -0
  209. package/src/icons/source/icon-gripper-vertical.svg +9 -0
  210. package/src/icons/source/icon-info.svg +4 -0
  211. package/src/icons/source/icon-infonomic.svg +43 -0
  212. package/src/icons/source/icon-ledger.svg +4 -0
  213. package/src/icons/source/icon-light.svg +3 -0
  214. package/src/icons/source/icon-location-pin.svg +8 -0
  215. package/src/icons/source/icon-logout.svg +6 -0
  216. package/src/icons/source/icon-metamask.svg +32 -0
  217. package/src/icons/source/icon-moon.svg +3 -0
  218. package/src/icons/source/icon-plus.svg +4 -0
  219. package/src/icons/source/icon-refresh.svg +4 -0
  220. package/src/icons/source/icon-return.svg +4 -0
  221. package/src/icons/source/icon-search-menu.svg +13 -0
  222. package/src/icons/source/icon-search.svg +3 -0
  223. package/src/icons/source/icon-settings-gear.svg +5 -0
  224. package/src/icons/source/icon-settings.svg +12 -0
  225. package/src/icons/source/icon-wallet.svg +3 -0
  226. package/src/icons/source/icon-walletconnect.svg +4 -0
  227. package/src/icons/source/icon-x.svg +4 -0
  228. package/src/icons/stopwatch-icon.tsx +39 -0
  229. package/src/icons/success-icon.tsx +18 -0
  230. package/src/icons/types/icon.ts +8 -0
  231. package/src/icons/user-icon.tsx +33 -0
  232. package/src/icons/users-icon.tsx +35 -0
  233. package/src/icons/wallet-icon.tsx +29 -0
  234. package/src/icons/warning-icon.tsx +18 -0
  235. package/src/icons/x-icon.tsx +33 -0
  236. package/src/loaders/ellipses.tsx +36 -0
  237. package/src/loaders/loaders.stories.tsx +46 -0
  238. package/src/loaders/ring.tsx +33 -0
  239. package/src/loaders/spinner.tsx +28 -0
  240. package/src/loaders/types/index.ts +6 -0
  241. package/src/react.ts +99 -0
  242. package/src/styles/base/animations.css +143 -0
  243. package/src/styles/base/base.css +5 -0
  244. package/src/styles/base/colors.css +163 -0
  245. package/src/styles/base/colors.stories.tsx +671 -0
  246. package/src/styles/base/reset.css +464 -0
  247. package/src/styles/base/typography.css +25 -0
  248. package/src/styles/base/vars.css +188 -0
  249. package/src/styles/components/card.css +20 -0
  250. package/src/styles/components/checkbox.css +55 -0
  251. package/src/styles/components/components.css +11 -0
  252. package/src/styles/components/directional-button.css +92 -0
  253. package/src/styles/components/dropdown.css +19 -0
  254. package/src/styles/components/fade-in-lift.css +13 -0
  255. package/src/styles/components/hamburger.css +107 -0
  256. package/src/styles/components/icon-element.css +4 -0
  257. package/src/styles/components/list-checkbox.css +60 -0
  258. package/src/styles/components/loaders.css +196 -0
  259. package/src/styles/components/popover.css +15 -0
  260. package/src/styles/components/scroll-to-top.css +89 -0
  261. package/src/styles/components/toast.css +18 -0
  262. package/src/styles/styles.css +6 -0
  263. package/src/styles/theme/autofill.css +58 -0
  264. package/src/styles/theme/scrollers.css +52 -0
  265. package/src/styles/theme/theme.css +130 -0
  266. package/src/styles/theme/theme.stories.tsx +33 -0
  267. package/src/styles/typography/code.stories.tsx +76 -0
  268. package/src/styles/typography/default.stories.tsx +51 -0
  269. package/src/styles/typography/fonts.css +30 -0
  270. package/src/styles/typography/lists.stories.tsx +50 -0
  271. package/src/styles/typography/prose.css +404 -0
  272. package/src/styles/typography/quote.stories.tsx +37 -0
  273. package/src/styles/typography.css +24 -0
  274. package/src/styles/utils/scroll-layout-shift.css +9 -0
  275. package/src/styles/utils/utility-classes.css +1278 -0
  276. package/src/styles/utils/utils.css +2 -0
  277. package/src/theme/theme-provider/index.ts +1 -0
  278. package/src/theme/theme-provider/provider.tsx +44 -0
  279. package/src/utils/capitalize.ts +6 -0
  280. package/src/utils/externalLinkProps.ts +6 -0
  281. package/src/utils/findMatch.ts +7 -0
  282. package/src/utils/getPortalRoot.ts +3 -0
  283. package/src/utils/isTouchDevice.ts +11 -0
  284. package/src/utils/objectsToArray.ts +15 -0
  285. package/src/utils/objectsToString.ts +5 -0
  286. package/src/utils/polymorphic.ts +16 -0
  287. package/src/utils/to-kebab-case.ts +5 -0
  288. package/src/widgets/datepicker/datepicker.module.css +189 -0
  289. package/src/widgets/datepicker/datepicker.stories.tsx +25 -0
  290. package/src/widgets/datepicker/datepicker.tsx +310 -0
  291. package/src/widgets/drawer/drawer-container.tsx +26 -0
  292. package/src/widgets/drawer/drawer-content.tsx +26 -0
  293. package/src/widgets/drawer/drawer-context.tsx +49 -0
  294. package/src/widgets/drawer/drawer-header.tsx +27 -0
  295. package/src/widgets/drawer/drawer-top-actions.tsx +27 -0
  296. package/src/widgets/drawer/drawer-wrapper.tsx +54 -0
  297. package/src/widgets/drawer/drawer.module.css +116 -0
  298. package/src/widgets/drawer/drawer.stories.tsx +224 -0
  299. package/src/widgets/drawer/drawer.tsx +115 -0
  300. package/src/widgets/drawer/motionDomAnimation.ts +4 -0
  301. package/src/widgets/drawer/motionDomMax.ts +4 -0
  302. package/src/widgets/modal/modal-actions.tsx +26 -0
  303. package/src/widgets/modal/modal-container.tsx +26 -0
  304. package/src/widgets/modal/modal-content.tsx +26 -0
  305. package/src/widgets/modal/modal-header.tsx +27 -0
  306. package/src/widgets/modal/modal-wrapper.tsx +50 -0
  307. package/src/widgets/modal/modal.module.css +85 -0
  308. package/src/widgets/modal/modal.stories.tsx +71 -0
  309. package/src/widgets/modal/modal.tsx +110 -0
  310. package/src/widgets/modal/motionDomAnimation.ts +4 -0
  311. package/src/widgets/modal/motionDomMax.ts +4 -0
  312. package/src/widgets/search/index.ts +1 -0
  313. package/src/widgets/search/search.stories.tsx +18 -0
  314. package/src/widgets/search/search.tsx +186 -0
@@ -0,0 +1,2 @@
1
+ @import "./utility-classes.css";
2
+ @import "./scroll-layout-shift.css";
@@ -0,0 +1 @@
1
+ export * from './provider'
@@ -0,0 +1,44 @@
1
+ /**
2
+ * NOTE: Not used in production. This is only here for
3
+ * uikit development with the provider placed in
4
+ * .storybook/preview.tsx
5
+ */
6
+
7
+ import { createContext, useContext, useMemo } from 'react'
8
+ import type { ReactNode } from 'react'
9
+
10
+ enum Theme {
11
+ DARK = 'dark',
12
+ LIGHT = 'light'
13
+ }
14
+
15
+ // ThemeContext
16
+ interface ThemeContextType {
17
+ theme: Theme | null
18
+ }
19
+ const ThemeContext = createContext<ThemeContextType | undefined>(undefined)
20
+
21
+ interface ThemeProviderProps {
22
+ children: ReactNode
23
+ theme: Theme
24
+ }
25
+
26
+ // ThemeProvider
27
+ function ThemeProvider({ children, theme }: ThemeProviderProps): React.JSX.Element {
28
+ const contextValue = useMemo(() => {
29
+ return { theme }
30
+ }, [theme])
31
+
32
+ return <ThemeContext value={contextValue}>{children}</ThemeContext>
33
+ }
34
+
35
+ // Hook helper useTheme
36
+ function useTheme(): ThemeContextType {
37
+ const context = useContext(ThemeContext)
38
+ if (context === undefined) {
39
+ throw new Error('useTheme must be used within a ThemeProvider')
40
+ }
41
+ return context
42
+ }
43
+
44
+ export { Theme, ThemeProvider, useTheme }
@@ -0,0 +1,6 @@
1
+ export function capitalize(str: string): string {
2
+ if (typeof str !== 'string' || str.length === 0) {
3
+ return ''
4
+ }
5
+ return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase()
6
+ }
@@ -0,0 +1,6 @@
1
+ const EXTERNAL_LINK_PROPS: { target: string; rel: string } = {
2
+ target: '_blank',
3
+ rel: 'noreferrer noopener'
4
+ }
5
+
6
+ export default EXTERNAL_LINK_PROPS
@@ -0,0 +1,7 @@
1
+ function findMatch(data: any, find: any, defaultValue: any): any {
2
+ const founded = data.findIndex((el: any) => el === find)
3
+
4
+ return founded >= 0 ? find : defaultValue
5
+ }
6
+
7
+ export default findMatch
@@ -0,0 +1,3 @@
1
+ export function getPortalRoot(): false | HTMLElement {
2
+ return typeof window !== 'undefined' && (document.getElementById('portal-root') ?? document.body)
3
+ }
@@ -0,0 +1,11 @@
1
+ const isTouchDevice = (): boolean => {
2
+ return (
3
+ typeof window !== 'undefined' &&
4
+ ('ontouchstart' in window ||
5
+ navigator.maxTouchPoints > 0 ||
6
+ // @ts-expect-error: error
7
+ navigator.msMaxTouchPoints > 0)
8
+ )
9
+ }
10
+
11
+ export default isTouchDevice
@@ -0,0 +1,15 @@
1
+ export default function objectsToArray(object: any): any[] {
2
+ let result: any[] = []
3
+
4
+ Object.values(object).forEach((value) => {
5
+ if (typeof value === 'string') {
6
+ result = [...result, value]
7
+ } else if (typeof value === 'object' && !Array.isArray(value) && value !== null) {
8
+ result = [...result, ...objectsToArray(value)]
9
+ }
10
+
11
+ return undefined
12
+ })
13
+
14
+ return result
15
+ }
@@ -0,0 +1,5 @@
1
+ import objectsToArray from './objectsToArray.js'
2
+
3
+ export default function objectsToString(object: any): string {
4
+ return objectsToArray(object).join(' ')
5
+ }
@@ -0,0 +1,16 @@
1
+ import { type ComponentProps, type ElementType, type ReactElement } from 'react'
2
+
3
+ /**
4
+ * @see https://www.benmvp.com/blog/polymorphic-react-components-typescript/
5
+ */
6
+ export interface AsProps<E extends ElementType = ElementType> {
7
+ as?: E
8
+ }
9
+
10
+ export type MergeProps<E extends ElementType> = AsProps<E> & Omit<ComponentProps<E>, keyof AsProps>
11
+
12
+ export type PolymorphicComponentProps<E extends ElementType, P> = P & MergeProps<E>
13
+
14
+ export type PolymorphicComponent<P, D extends ElementType = 'button'> = <E extends ElementType = D>(
15
+ props: PolymorphicComponentProps<E, P>
16
+ ) => ReactElement | null
@@ -0,0 +1,5 @@
1
+ export const toKebabCase = (string?: string): string =>
2
+ (string ?? '')
3
+ ?.replace(/([a-z])([A-Z])/g, '$1-$2')
4
+ .replace(/\s+/g, '-')
5
+ .toLowerCase()
@@ -0,0 +1,189 @@
1
+ @layer infonomic-base, infonomic-utilities, infonomic-theme, infonomic-components;
2
+
3
+ @layer infonomic-components {
4
+ .container {
5
+ position: relative;
6
+ }
7
+
8
+ .input,
9
+ .input-wrapper {
10
+ width: 100%;
11
+ }
12
+
13
+ .content {
14
+ width: 100%;
15
+ border-radius: 4px;
16
+ padding-top: var(--spacing-4);
17
+ padding-bottom: var(--spacing-2);
18
+ padding-left: var(--spacing-2);
19
+ padding-right: var(--spacing-1);
20
+ background-color: var(--background);
21
+ border: 1px solid var(--border-color);
22
+ box-shadow: var(--shadow-md);
23
+ animation-duration: 400ms;
24
+ animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
25
+ will-change: transform, opacity;
26
+
27
+ &:focus {
28
+ box-shadow: var(--shadow-md)
29
+ }
30
+
31
+ &[data-state="open"][data-side="top"] {
32
+ animation-name: slideDownAndFade;
33
+ }
34
+
35
+ &[data-state="open"][data-side="right"] {
36
+ animation-name: slideLeftAndFade;
37
+ }
38
+
39
+ &[data-state="open"][data-side="bottom"] {
40
+ animation-name: slideUpAndFade;
41
+ }
42
+
43
+ &[data-state="open"][data-side="left"] {
44
+ animation-name: slideRightAndFade;
45
+ }
46
+ }
47
+
48
+ .content:is(:global(.dark) *) {
49
+ background: var(--canvas-800);
50
+ }
51
+
52
+ .content-components {
53
+ display: flex;
54
+ width: 100%;
55
+ gap: var(--spacing-2);
56
+ }
57
+
58
+
59
+ .status-and-actions {
60
+ display: flex;
61
+ flex-direction: column;
62
+ justify-content: space-between;
63
+ align-items: center;
64
+ width: 100%;
65
+ }
66
+
67
+ .content-status {
68
+ display: flex;
69
+ align-items: center;
70
+ padding-left: var(--spacing-4);
71
+ padding-right: var(--spacing-2);
72
+ font-size: var(--font-size-sm);
73
+ color: var(--foreground);
74
+ width: 100%;
75
+ }
76
+
77
+ .content-actions {
78
+ display: flex;
79
+ flex-direction: row;
80
+ justify-content: space-between;
81
+ margin-top: var(--spacing-3);
82
+ padding-left: var(--spacing-4);
83
+ padding-right: var(--spacing-6);
84
+ gap: var(--spacing-2);
85
+ width: 100%;
86
+ }
87
+
88
+ .content-actions-button {
89
+ /* min-width: 100px; */
90
+ --ring-color: var(--violet-7);
91
+ }
92
+
93
+ .arrow {
94
+ fill: var(--gray-50);
95
+ }
96
+
97
+ .close {
98
+ all: unset;
99
+ font-family: inherit;
100
+ border-radius: 100%;
101
+ height: 25px;
102
+ width: 25px;
103
+ display: inline-flex;
104
+ align-items: center;
105
+ justify-content: center;
106
+ color: var(--violet-11);
107
+ position: absolute;
108
+ top: 5px;
109
+ right: 5px;
110
+
111
+ &:hover {
112
+ background-color: var(--violet-4);
113
+ }
114
+
115
+ &:focus {
116
+ box-shadow: 0 0 0 2px var(--violet-7);
117
+ }
118
+ }
119
+
120
+ .time-picker-container {
121
+ width: 80px;
122
+ margin: 0.6rem 0.5rem 1rem 0;
123
+ }
124
+
125
+ .time-picker-scroll-area {
126
+ height: 280px;
127
+ padding-right: var(--spacing-4)
128
+ }
129
+
130
+ .time-picker {
131
+ display: flex;
132
+ padding-left: var(--spacing-1);
133
+ padding-right: var(--spacing-1);
134
+ flex-direction: column;
135
+ gap: 0.5rem;
136
+ }
137
+
138
+ .time-picker-button {
139
+ width: 100%;
140
+ }
141
+
142
+ @keyframes slideUpAndFade {
143
+ from {
144
+ opacity: 0;
145
+ transform: translateY(2px);
146
+ }
147
+
148
+ to {
149
+ opacity: 1;
150
+ transform: translateY(0);
151
+ }
152
+ }
153
+
154
+ @keyframes slideRightAndFade {
155
+ from {
156
+ opacity: 0;
157
+ transform: translateX(-2px);
158
+ }
159
+
160
+ to {
161
+ opacity: 1;
162
+ transform: translateX(0);
163
+ }
164
+ }
165
+
166
+ @keyframes slideDownAndFade {
167
+ from {
168
+ opacity: 0;
169
+ transform: translateY(-2px);
170
+ }
171
+
172
+ to {
173
+ opacity: 1;
174
+ transform: translateY(0);
175
+ }
176
+ }
177
+
178
+ @keyframes slideLeftAndFade {
179
+ from {
180
+ opacity: 0;
181
+ transform: translateX(2px);
182
+ }
183
+
184
+ to {
185
+ opacity: 1;
186
+ transform: translateX(0);
187
+ }
188
+ }
189
+ }
@@ -0,0 +1,25 @@
1
+ import { DatePicker } from './datepicker.js'
2
+
3
+ export default {
4
+ title: 'Widgets/DatePicker',
5
+ component: DatePicker,
6
+ argTypes: {},
7
+ }
8
+
9
+ export const Default = (): React.JSX.Element => {
10
+ const handleDateChange = (value: Date | null): void => {
11
+ console.log('Selected date:', value)
12
+ }
13
+
14
+ return (
15
+ <div style={{ maxWidth: '270px', margin: '0 auto' }}>
16
+ <DatePicker
17
+ onDateChange={handleDateChange}
18
+ id="published_on"
19
+ name="published_on"
20
+ variant="outlined"
21
+ helpText="Select published on date."
22
+ />
23
+ </div>
24
+ )
25
+ }
@@ -0,0 +1,310 @@
1
+ 'use client'
2
+ /**
3
+ * @file DatePicker component using react-day-picker and radix-ui
4
+ * Portions copyright (c) 2023 Maliksidk19 licensed under the MIT
5
+ * license found in the LICENSE file in the root directory of this source tree.
6
+ * of https://github.com/Maliksidk19/shadcn-datetime-picker/
7
+ */
8
+
9
+ import cx from 'classnames'
10
+ import { format } from 'date-fns'
11
+ import { Popover } from 'radix-ui'
12
+ import type React from 'react'
13
+ import { useEffect, useRef, useState } from 'react'
14
+ import { Button } from '../../components/button/button.js'
15
+ import { IconButton } from '../../components/button/icon-button.js'
16
+ import { Calendar } from '../../components/calendar/calendar.js'
17
+ import { Input, InputAdornment } from '../../components/input'
18
+ import type { Intent, Size, Variant } from '../../components/input/@types/input.js'
19
+ import { ScrollArea } from '../../components/scroll-area/scroll-area.js'
20
+ import { CalendarIcon } from '../../icons/calendar-icon.js'
21
+ import { CloseIcon } from '../../icons/close-icon.js'
22
+ import styles from './datepicker.module.css'
23
+
24
+ export interface DatePickerProps extends React.InputHTMLAttributes<HTMLInputElement> {
25
+ id: string
26
+ name: string
27
+ label?: string
28
+ required?: boolean
29
+ initialValue?: Date | null
30
+ mode?: 'date' | 'datetime'
31
+ yearsInFuture?: number
32
+ yearsInPast?: number
33
+ variant?: Variant
34
+ inputSize?: Size
35
+ inputWrapperClassName?: string
36
+ inputClassName?: string
37
+ intent?: Intent
38
+ containerClassName?: string
39
+ helpText?: string
40
+ errorText?: string
41
+ ariaLabelForSearch?: string
42
+ ariaLabelForClear?: string
43
+ onClear?: () => void
44
+ onDateChange?: (value: Date | null) => void
45
+ validatorFn?: (value: Date) => {
46
+ valid: boolean
47
+ value: Date
48
+ }
49
+ placeHolderText?: string
50
+ }
51
+
52
+ export function DatePicker({
53
+ id,
54
+ name,
55
+ label,
56
+ required,
57
+ initialValue,
58
+ mode = 'datetime',
59
+ yearsInFuture = 1,
60
+ yearsInPast = 10,
61
+ variant,
62
+ intent,
63
+ inputSize,
64
+ inputClassName,
65
+ inputWrapperClassName,
66
+ containerClassName,
67
+ onClear = () => {},
68
+ onDateChange = () => {},
69
+ validatorFn,
70
+ helpText,
71
+ errorText,
72
+ placeHolderText = '',
73
+ ariaLabelForSearch = 'date',
74
+ ariaLabelForClear = 'clear',
75
+ ...rest
76
+ }: DatePickerProps): React.JSX.Element {
77
+ const [isOpen, setIsOpen] = useState(false)
78
+ const [time, setTime] = useState<string>('08:00')
79
+ const [date, setDate] = useState<Date | null>(() => {
80
+ if (initialValue) {
81
+ return initialValue
82
+ }
83
+ if (initialValue == null && required === true) {
84
+ return new Date()
85
+ }
86
+ return null
87
+ })
88
+ const [month, setMonth] = useState<Date | null>(date)
89
+ const calendarRef = useRef<HTMLDivElement | null>(null)
90
+ const inputRef = useRef<HTMLInputElement>(null)
91
+ const hasInitialized = useRef(false)
92
+
93
+ const handleClear = (): void => {
94
+ if (inputRef?.current != null) {
95
+ inputRef.current.value = ''
96
+ }
97
+ setDate(null)
98
+ onDateChange(null)
99
+ onClear()
100
+ }
101
+
102
+ const handleOnDateChange = (value: Date | null): void => {
103
+ if (onDateChange != null && typeof onDateChange === 'function') {
104
+ onDateChange(value)
105
+ }
106
+ }
107
+
108
+ const handleOnKeyDown = (e: React.KeyboardEvent<HTMLInputElement>): void => {
109
+ if (e.key === 'ArrowDown') {
110
+ e.preventDefault()
111
+ setIsOpen(true)
112
+ }
113
+ }
114
+
115
+ // This is to handle cases where the date picker is used in a form and the initial
116
+ // value is not set, but the field is required. In such cases, we want
117
+ // to trigger the onDateChange callback with the current date to ensure that
118
+ // the form is valid and the date picker is initialized with a value.
119
+ // Runs only once on mount
120
+ useEffect(() => {
121
+ if (
122
+ initialValue == null &&
123
+ date != null &&
124
+ required === true &&
125
+ hasInitialized.current === false
126
+ ) {
127
+ hasInitialized.current = true
128
+ onDateChange(date)
129
+ }
130
+ })
131
+
132
+ return (
133
+ <div className={cx(styles.container, containerClassName)}>
134
+ <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--spacing-2)' }}>
135
+ <Input
136
+ id={id}
137
+ label={label}
138
+ readOnly
139
+ required={required}
140
+ name={name}
141
+ variant={variant}
142
+ intent={intent}
143
+ inputSize={inputSize}
144
+ ref={inputRef}
145
+ className={cx(styles.input, inputClassName)}
146
+ inputWrapperClassName={cx(styles['input-wrapper'], inputWrapperClassName)}
147
+ onKeyDown={handleOnKeyDown}
148
+ onClick={(e) => {
149
+ e.preventDefault()
150
+ e.stopPropagation()
151
+ setIsOpen(true)
152
+ }}
153
+ value={date ? `${format(date, 'PP HH:mm')}` : ''}
154
+ placeHolder={placeHolderText}
155
+ helpText={helpText}
156
+ disabled={false}
157
+ error={false}
158
+ endAdornment={
159
+ <InputAdornment position="end">
160
+ <IconButton
161
+ role="button"
162
+ intent="noeffect"
163
+ variant="text"
164
+ arial-label={ariaLabelForClear}
165
+ size="xs"
166
+ onClick={() => {
167
+ handleClear()
168
+ }}
169
+ >
170
+ <CloseIcon width="14px" height="14px" />
171
+ </IconButton>
172
+ <IconButton
173
+ role="button"
174
+ intent="noeffect"
175
+ variant="text"
176
+ arial-label={ariaLabelForClear}
177
+ size="xs"
178
+ onClick={() => {
179
+ setIsOpen(true)
180
+ }}
181
+ >
182
+ <CalendarIcon width="18px" height="18px" />
183
+ </IconButton>
184
+ </InputAdornment>
185
+ }
186
+ {...rest}
187
+ />
188
+ </div>
189
+
190
+ <Popover.Root open={isOpen} onOpenChange={setIsOpen}>
191
+ <Popover.Trigger asChild>
192
+ <div style={{ position: 'relative', height: '1px' }}>
193
+ <span className="sr-only">Select date</span>
194
+ </div>
195
+ </Popover.Trigger>
196
+ <Popover.Portal>
197
+ <Popover.Content sideOffset={5} className={styles.content}>
198
+ <div className={styles['content-components']}>
199
+ <div ref={calendarRef}>
200
+ <Calendar
201
+ mode="single"
202
+ required
203
+ captionLayout="dropdown"
204
+ selected={date ?? undefined}
205
+ month={month ?? undefined}
206
+ onMonthChange={setMonth}
207
+ onSelect={(selectedDate: Date) => {
208
+ if (selectedDate) {
209
+ const [hours, minutes] = time.split(':')
210
+ selectedDate.setHours(Number.parseInt(hours), Number.parseInt(minutes))
211
+ setDate(selectedDate)
212
+ setMonth(selectedDate)
213
+ handleOnDateChange(selectedDate)
214
+ }
215
+ }}
216
+ startMonth={new Date(new Date().getFullYear() - yearsInPast, 0)}
217
+ endMonth={new Date(new Date().getFullYear() + yearsInFuture, 0)}
218
+ // TODO: add props
219
+ // disabled={(date) =>
220
+ // Number(date) < Date.now() - 1000 * 60 * 60 * 24 ||
221
+ // Number(date) > Date.now() + 1000 * 60 * 60 * 24 * 30
222
+ // }
223
+ />
224
+ </div>
225
+ {mode === 'datetime' && (
226
+ <div className={styles['time-picker-container']}>
227
+ <ScrollArea className={styles['time-picker-scroll-area']}>
228
+ <div className={styles['time-picker']}>
229
+ {Array.from({ length: 96 }).map((_, i) => {
230
+ const hour = Math.floor(i / 4)
231
+ .toString()
232
+ .padStart(2, '0')
233
+ const minute = ((i % 4) * 15).toString().padStart(2, '0')
234
+ const timeValue = `${hour}:${minute}`
235
+ return (
236
+ <Button
237
+ key={i}
238
+ size="sm"
239
+ className={styles['time-picker-button']}
240
+ variant="outlined"
241
+ onClick={() => {
242
+ setTime(timeValue)
243
+ if (date) {
244
+ const newDate = new Date(date.getTime())
245
+ newDate.setHours(Number.parseInt(hour), Number.parseInt(minute), 0)
246
+ setDate(newDate)
247
+ handleOnDateChange(newDate)
248
+ }
249
+ }}
250
+ >
251
+ {timeValue}
252
+ </Button>
253
+ )
254
+ })}
255
+ </div>
256
+ </ScrollArea>
257
+ </div>
258
+ )}
259
+ </div>
260
+ <div className={styles['status-and-actions']}>
261
+ <div className={styles['content-status']}>
262
+ {date ? `${format(date, 'PPPp')}` : 'No date selected'}
263
+ </div>
264
+ <div className={styles['content-actions']}>
265
+ <div>
266
+ <Button
267
+ variant="outlined"
268
+ size="sm"
269
+ className={styles['content-actions-button']}
270
+ onClick={() => {
271
+ const today = new Date()
272
+ setDate(today)
273
+ setMonth(today)
274
+ handleOnDateChange(today)
275
+ }}
276
+ >
277
+ Today
278
+ </Button>
279
+ </div>
280
+ <div style={{ display: 'flex', gap: 'var(--spacing-3)' }}>
281
+ <Button
282
+ size="sm"
283
+ intent="noeffect"
284
+ className={styles['content-actions-button']}
285
+ onClick={() => {
286
+ setIsOpen(false)
287
+ }}
288
+ >
289
+ Cancel
290
+ </Button>
291
+ <Button
292
+ variant="outlined"
293
+ size="sm"
294
+ className={styles['content-actions-button']}
295
+ onClick={() => {
296
+ setIsOpen(false)
297
+ handleOnDateChange(date)
298
+ }}
299
+ >
300
+ Select
301
+ </Button>
302
+ </div>
303
+ </div>
304
+ </div>
305
+ </Popover.Content>
306
+ </Popover.Portal>
307
+ </Popover.Root>
308
+ </div>
309
+ )
310
+ }
@@ -0,0 +1,26 @@
1
+ 'use client'
2
+ import type * as React from 'react'
3
+
4
+ import cx from 'classnames'
5
+
6
+ import styles from './drawer.module.css'
7
+
8
+ type DrawerContainerIntrinsicProps = React.JSX.IntrinsicElements['div']
9
+ export interface DrawerContainerProps extends DrawerContainerIntrinsicProps {
10
+ className?: string
11
+ }
12
+
13
+ export function DrawerContainer({
14
+ ref,
15
+ children,
16
+ className,
17
+ ...rest
18
+ }: DrawerContainerProps & {
19
+ ref?: React.RefObject<HTMLDivElement>
20
+ }) {
21
+ return (
22
+ <div ref={ref} role="dialog" className={cx(styles['drawer-container'], className)} {...rest}>
23
+ {children}
24
+ </div>
25
+ )
26
+ }