@hanzo/ui 4.7.0 → 4.8.2

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 (272) hide show
  1. package/assets/ai-icons.tsx +207 -0
  2. package/assets/crypto.tsx +33 -0
  3. package/assets/file-type-icon.tsx +66 -0
  4. package/assets/file.tsx +45 -0
  5. package/assets/general.tsx +2318 -0
  6. package/assets/hanzo-logo.svg +9 -0
  7. package/assets/hanzo-logo.tsx +17 -0
  8. package/assets/index.ts +122 -0
  9. package/assets/index.tsx +4 -0
  10. package/assets/llm-provider.tsx +1094 -0
  11. package/blocks/auth/index.ts +6 -0
  12. package/blocks/auth/login-2fa.tsx +165 -0
  13. package/blocks/auth/login-basic.tsx +94 -0
  14. package/blocks/auth/login-social.tsx +148 -0
  15. package/blocks/auth/magic-link.tsx +129 -0
  16. package/blocks/auth/password-reset.tsx +97 -0
  17. package/blocks/auth/signup.tsx +157 -0
  18. package/blocks/components/accordian-block.tsx +48 -0
  19. package/blocks/components/block-component-props.ts +11 -0
  20. package/blocks/components/bullet-cards-block.tsx +46 -0
  21. package/blocks/components/card-block/index.tsx +171 -0
  22. package/blocks/components/card-block/link-out-button.tsx +20 -0
  23. package/blocks/components/card-block/util.ts +28 -0
  24. package/blocks/components/carte-blanche-block/index.tsx +127 -0
  25. package/blocks/components/carte-blanche-block/variant-content-left.tsx +49 -0
  26. package/blocks/components/content.tsx +70 -0
  27. package/blocks/components/cta-block.tsx +115 -0
  28. package/blocks/components/enh-heading-block.tsx +204 -0
  29. package/blocks/components/grid-block/grid-block-mutator.ts +12 -0
  30. package/blocks/components/grid-block/index.tsx +83 -0
  31. package/blocks/components/grid-block/mutator-registry.ts +10 -0
  32. package/blocks/components/grid-block/table-borders.mutator.ts +47 -0
  33. package/blocks/components/group-block.tsx +83 -0
  34. package/blocks/components/heading-block.tsx +88 -0
  35. package/blocks/components/image-block.tsx +111 -0
  36. package/blocks/components/index.ts +30 -0
  37. package/blocks/components/screenful-block/content.tsx +123 -0
  38. package/blocks/components/screenful-block/index.tsx +107 -0
  39. package/blocks/components/screenful-block/poster-background.tsx +34 -0
  40. package/blocks/components/screenful-block/video-background.tsx +45 -0
  41. package/blocks/components/space-block.tsx +66 -0
  42. package/blocks/components/video-block.tsx +138 -0
  43. package/blocks/data-display/activity-feed.tsx +242 -0
  44. package/blocks/data-display/data-table.tsx +235 -0
  45. package/blocks/data-display/stats-grid.tsx +194 -0
  46. package/blocks/def/accordian-block.ts +14 -0
  47. package/blocks/def/block.ts +7 -0
  48. package/blocks/def/bullet-cards-block.ts +22 -0
  49. package/blocks/def/card-block.ts +22 -0
  50. package/blocks/def/carte-blanche-block.ts +21 -0
  51. package/blocks/def/cta-block.ts +19 -0
  52. package/blocks/def/element-block.ts +11 -0
  53. package/blocks/def/enh-heading-block.ts +44 -0
  54. package/blocks/def/grid-block.ts +16 -0
  55. package/blocks/def/group-block.ts +11 -0
  56. package/blocks/def/heading-block.ts +15 -0
  57. package/blocks/def/image-block.ts +31 -0
  58. package/blocks/def/index.ts +35 -0
  59. package/blocks/def/screenful-block.ts +54 -0
  60. package/blocks/def/space-block.ts +64 -0
  61. package/blocks/def/video-block.ts +9 -0
  62. package/blocks/ecommerce/checkout.tsx +242 -0
  63. package/blocks/ecommerce/index.ts +7 -0
  64. package/blocks/ecommerce/product-detail.tsx +257 -0
  65. package/blocks/ecommerce/product-grid.tsx +148 -0
  66. package/blocks/ecommerce/shopping-cart.tsx +181 -0
  67. package/blocks/index.ts +2 -0
  68. package/blocks/marketing/cta-section.tsx +207 -0
  69. package/blocks/marketing/faq.tsx +159 -0
  70. package/blocks/marketing/features-grid.tsx +156 -0
  71. package/blocks/marketing/hero-section.tsx +192 -0
  72. package/blocks/marketing/index.ts +6 -0
  73. package/blocks/marketing/pricing-table.tsx +121 -0
  74. package/blocks/marketing/testimonials.tsx +196 -0
  75. package/components/index.ts +9 -0
  76. package/dist/index.js +1407 -1514
  77. package/dist/index.mjs +1363 -1472
  78. package/dist/tailwind/index.js +3 -1
  79. package/dist/tailwind/index.mjs +3 -1
  80. package/dist/util/format-text.js +51 -0
  81. package/dist/util/format-text.mjs +32 -0
  82. package/dist/util/index.js +384 -0
  83. package/dist/util/index.mjs +363 -0
  84. package/frameworks/core/index.ts +6 -0
  85. package/frameworks/core/utils/index.ts +64 -0
  86. package/frameworks/react/components/button.tsx +26 -0
  87. package/frameworks/react/components/index.ts +5 -0
  88. package/frameworks/react/hooks/index.ts +5 -0
  89. package/frameworks/react/index.ts +9 -0
  90. package/frameworks/react/package.json +8 -0
  91. package/frameworks/react/utils/index.ts +2 -0
  92. package/frameworks/react-native/index.ts +9 -0
  93. package/frameworks/react-native/package.json +8 -0
  94. package/frameworks/registry.json +371 -0
  95. package/frameworks/setup.sh +69 -0
  96. package/frameworks/svelte/index.ts +9 -0
  97. package/frameworks/svelte/package.json +8 -0
  98. package/frameworks/tracker.json +1854 -0
  99. package/frameworks/vue/index.ts +9 -0
  100. package/frameworks/vue/package.json +8 -0
  101. package/helpers/file.ts +33 -0
  102. package/helpers/memoization.ts +40 -0
  103. package/package.json +49 -11
  104. package/primitives/accordion.tsx +74 -0
  105. package/primitives/action-button.tsx +42 -0
  106. package/primitives/alert-dialog.tsx +185 -0
  107. package/primitives/alert.tsx +74 -0
  108. package/primitives/apply-typography.tsx +55 -0
  109. package/primitives/aspect-ratio.tsx +5 -0
  110. package/primitives/avatar.tsx +57 -0
  111. package/primitives/background-beams.tsx +142 -0
  112. package/primitives/badge.tsx +45 -0
  113. package/primitives/breadcrumb.tsx +130 -0
  114. package/primitives/breakpoint-indicator.tsx +19 -0
  115. package/primitives/button.tsx +72 -0
  116. package/primitives/calendar.tsx +72 -0
  117. package/primitives/card.tsx +97 -0
  118. package/primitives/carousel.tsx +238 -0
  119. package/primitives/chat/chat-input-area.tsx +88 -0
  120. package/primitives/chat/chat-input.tsx +71 -0
  121. package/primitives/chat/files-preview.tsx +331 -0
  122. package/primitives/chat/index.ts +6 -0
  123. package/primitives/chat/json-form.tsx +8 -0
  124. package/primitives/chat/message-list.tsx +308 -0
  125. package/primitives/chat/message.tsx +569 -0
  126. package/primitives/chat/sqlite-preview.tsx +215 -0
  127. package/primitives/checkbox.tsx +32 -0
  128. package/primitives/collapsible.tsx +9 -0
  129. package/primitives/combobox.tsx +239 -0
  130. package/primitives/command.tsx +151 -0
  131. package/primitives/context-menu.tsx +206 -0
  132. package/primitives/copy-to-clipboard-icon.tsx +60 -0
  133. package/primitives/dialog-video-controller.tsx +38 -0
  134. package/primitives/dialog.tsx +128 -0
  135. package/primitives/dot-pattern.tsx +57 -0
  136. package/primitives/dots-loader.tsx +13 -0
  137. package/primitives/drawer.tsx +113 -0
  138. package/primitives/dropdown-menu.tsx +199 -0
  139. package/primitives/error-message.tsx +19 -0
  140. package/primitives/file-uploader.tsx +202 -0
  141. package/primitives/form.tsx +183 -0
  142. package/primitives/hover-card.tsx +28 -0
  143. package/primitives/icons/github.tsx +14 -0
  144. package/primitives/icons/index.ts +18 -0
  145. package/primitives/icons/youtube-logo.tsx +59 -0
  146. package/primitives/index-common.ts +304 -0
  147. package/primitives/index-next.ts +4 -0
  148. package/primitives/input-otp.tsx +65 -0
  149. package/primitives/input.tsx +126 -0
  150. package/primitives/label.tsx +21 -0
  151. package/primitives/list-adaptor.ts +12 -0
  152. package/primitives/list-box.tsx +74 -0
  153. package/primitives/loading-spinner.tsx +33 -0
  154. package/primitives/markdown-preview.tsx +612 -0
  155. package/primitives/mermaid.tsx +191 -0
  156. package/primitives/navigation-menu.tsx +147 -0
  157. package/primitives/next/image.tsx +91 -0
  158. package/primitives/next/index.ts +7 -0
  159. package/primitives/next/inline-icon.tsx +36 -0
  160. package/primitives/next/link-element.tsx +109 -0
  161. package/primitives/next/mdx-link.tsx +22 -0
  162. package/primitives/next/media-stack.tsx +52 -0
  163. package/primitives/next/nav-items.tsx +45 -0
  164. package/primitives/next/youtube-embed.tsx +83 -0
  165. package/primitives/pagination.tsx +117 -0
  166. package/primitives/popover.tsx +34 -0
  167. package/primitives/pretty-json-print.tsx +28 -0
  168. package/primitives/progress.tsx +27 -0
  169. package/primitives/prompt-textarea.tsx +72 -0
  170. package/primitives/qr-code.tsx +112 -0
  171. package/primitives/radio-group.tsx +42 -0
  172. package/primitives/resizable.tsx +47 -0
  173. package/primitives/scroll-area.tsx +57 -0
  174. package/primitives/search-input.tsx +66 -0
  175. package/primitives/select.tsx +122 -0
  176. package/primitives/separator.tsx +26 -0
  177. package/primitives/sheet.tsx +139 -0
  178. package/primitives/skeleton.tsx +18 -0
  179. package/primitives/slider.tsx +63 -0
  180. package/primitives/sonner.tsx +35 -0
  181. package/primitives/step-indicator.tsx +69 -0
  182. package/primitives/stepper.tsx +272 -0
  183. package/primitives/switch.tsx +27 -0
  184. package/primitives/table.tsx +105 -0
  185. package/primitives/tabs.tsx +50 -0
  186. package/primitives/text-area.tsx +26 -0
  187. package/primitives/text-link.tsx +25 -0
  188. package/primitives/textarea.tsx +62 -0
  189. package/primitives/textfield.tsx +76 -0
  190. package/primitives/toast.tsx +30 -0
  191. package/primitives/toggle-group.tsx +63 -0
  192. package/primitives/toggle.tsx +44 -0
  193. package/primitives/tooltip.tsx +47 -0
  194. package/primitives/video-player.tsx +23 -0
  195. package/src/button.ts +1 -0
  196. package/src/hooks/index.ts +7 -0
  197. package/src/hooks/use-click-away.ts +31 -0
  198. package/src/hooks/use-combined-refs.ts +22 -0
  199. package/src/hooks/use-copy-clipboard.ts +30 -0
  200. package/src/hooks/use-debounce.ts +17 -0
  201. package/src/hooks/use-fill-ids.ts +25 -0
  202. package/src/hooks/use-map.ts +26 -0
  203. package/src/hooks/use-measure.ts +42 -0
  204. package/src/hooks/use-reverse-video-playback.ts +43 -0
  205. package/src/hooks/use-scroll-restoration.ts +50 -0
  206. package/src/index-lean.ts +87 -0
  207. package/src/index.ts +54 -0
  208. package/src/mcp/README.md +141 -0
  209. package/src/mcp/enhanced-server.ts +1208 -0
  210. package/src/mcp/index.ts +518 -0
  211. package/src/mcp/package.json +10 -0
  212. package/src/registry/api.ts +164 -0
  213. package/src/registry/index.ts +60 -0
  214. package/src/registry/package.json +10 -0
  215. package/src/utils.ts +19 -0
  216. package/tailwind/colors.tailwind.js +53 -0
  217. package/tailwind/fontFamily.tailwind.ts +7 -0
  218. package/tailwind/fontSize.tailwind.ts +13 -0
  219. package/tailwind/index.ts +7 -0
  220. package/tailwind/safelist.tailwind.js +26 -0
  221. package/tailwind/screens.tailwind.js +8 -0
  222. package/tailwind/spacing.tailwind.js +65 -0
  223. package/tailwind/tailwind.config.hanzo-preset.d.ts +5 -0
  224. package/tailwind/tailwind.config.hanzo-preset.js +915 -0
  225. package/tailwind/tw-font-desc.ts +15 -0
  226. package/tailwind/typo-plugin/get-plugin-styles.js +679 -0
  227. package/tailwind/typo-plugin/index.d.ts +9 -0
  228. package/tailwind/typo-plugin/index.js +141 -0
  229. package/tailwind/typo-plugin/utils.js +60 -0
  230. package/tailwind/typography-test.mdx +35 -0
  231. package/tailwind/z-index.tailwind.js +71 -0
  232. package/types/animation-def.ts +3 -0
  233. package/types/breakpoints.ts +11 -0
  234. package/types/bullet-item.ts +10 -0
  235. package/types/button-def.ts +39 -0
  236. package/types/dimensions.ts +8 -0
  237. package/types/grid-def.ts +56 -0
  238. package/types/image-def.ts +32 -0
  239. package/types/index.ts +30 -0
  240. package/types/link-def.ts +56 -0
  241. package/types/media-stack-def.ts +31 -0
  242. package/types/t-shirt-size.ts +5 -0
  243. package/types/tshirt-dimensions.ts +20 -0
  244. package/types/video-def.ts +25 -0
  245. package/util/blob.ts +33 -0
  246. package/util/copy-to-clipboard.ts +17 -0
  247. package/util/create-shadow-root.ts +22 -0
  248. package/util/date.ts +84 -0
  249. package/util/debounce.ts +11 -0
  250. package/util/file.ts +15 -0
  251. package/util/format-and-abbreviate-as-currency.ts +125 -0
  252. package/util/format-text.ts +34 -0
  253. package/util/format-to-max-char.ts +68 -0
  254. package/util/index-client.ts +3 -0
  255. package/util/index.ts +112 -0
  256. package/util/number-abbreviate.ts +49 -0
  257. package/util/specifier.ts +43 -0
  258. package/util/spread-to-transform.ts +25 -0
  259. package/util/step-animation.ts +90 -0
  260. package/util/timing.ts +3 -0
  261. package/util/toasts.tsx +17 -0
  262. package/util/two-way-map.ts +19 -0
  263. package/dist/index.d.mts +0 -16
  264. package/dist/index.d.ts +0 -16
  265. package/dist/lib/utils.d.mts +0 -2
  266. package/dist/lib/utils.d.ts +0 -2
  267. package/dist/src/utils.d.mts +0 -7
  268. package/dist/src/utils.d.ts +0 -7
  269. package/dist/tailwind/index.d.mts +0 -2
  270. package/dist/tailwind/index.d.ts +0 -2
  271. package/dist/types/index.d.mts +0 -12
  272. package/dist/types/index.d.ts +0 -12
@@ -0,0 +1,83 @@
1
+ 'use client'
2
+
3
+ import { useState } from 'react'
4
+ import Image from 'next/image'
5
+
6
+ import * as Icons from '../icons'
7
+
8
+ // Concept based on https://www.youtube.com/watch?v=lLqRchtjN00
9
+ // (https://github.com/a-trost/fableton)
10
+
11
+ const YouTubeEmbed: React.FC<{
12
+ youtubeID: string
13
+ width: number
14
+ height: number
15
+ buttonSize?: number
16
+ timeAt?: string // '5s'
17
+ title?: string
18
+ caption?: string
19
+ className?: string
20
+ }> = ({
21
+ youtubeID,
22
+ width,
23
+ height,
24
+ buttonSize=100,
25
+ timeAt,
26
+ title,
27
+ caption,
28
+ className=''
29
+ }) => {
30
+
31
+ const [showVideo, setShowVideo] = useState(false)
32
+
33
+ // re autoplay: https://stackoverflow.com/a/45610557/11645689
34
+ return (
35
+ <div className={className}>
36
+ {showVideo ? (
37
+ <iframe
38
+ width={width}
39
+ height={height}
40
+ src={`https://www.youtube-nocookie.com/embed/${youtubeID + ((timeAt) ? `?t=${timeAt}&` : '?')}rel=0&autoplay=1`}
41
+ allow='accelerometer ; autoplay *; clipboard-write *; encrypted-media *; gyroscope *; picture-in-picture *;'
42
+ allowFullScreen
43
+ title={title || 'Youtube video'}
44
+ className='aspect-[16/9] h-full w-full p-0 border-0 '
45
+ />
46
+ ) : (
47
+ <button
48
+ type='button'
49
+ onClick={() => setShowVideo(true)}
50
+ className='relative aspect-[16/9] w-full'
51
+ aria-label={`Play video ${title}`}
52
+ >
53
+ <Image
54
+ src={`https://img.youtube.com/vi/${youtubeID}/maxresdefault.jpg`}
55
+ alt=''
56
+ className='h-full w-full'
57
+ width={width}
58
+ height={height}
59
+ loading='lazy'
60
+ />
61
+ <div
62
+ className={ //https://stackoverflow.com/a/23384995/11645689
63
+ 'absolute z-above-content-2 left-[50%] top-[50%] -translate-y-2/4 -translate-x-2/4 ' +
64
+ 'grid place-items-center ' +
65
+ 'text-xl text-white opacity-90'
66
+ }
67
+ >
68
+ <Icons.youtube
69
+ width={buttonSize}
70
+ height={buttonSize}
71
+ role='img'
72
+ className='transform transition hover:scale-110'
73
+ {...{'aria-hidden': true}}
74
+ />
75
+ </div>
76
+ {caption && <p className='hidden md:block whitespace-nowrap typography absolute z-above-content left-[50%] top-[20px] -translate-x-2/4 '>{caption}</p>}
77
+ </button>
78
+ )}
79
+ </div>
80
+ )
81
+ }
82
+
83
+ export default YouTubeEmbed
@@ -0,0 +1,117 @@
1
+ import { MoreHorizontal, RedoIcon, UndoIcon } from 'lucide-react';
2
+ import React from 'react';
3
+
4
+ import { cn } from '../src/utils';
5
+ import { ButtonProps, buttonVariants } from './button';
6
+
7
+ const Pagination = ({ className, ...props }: React.ComponentProps<'nav'>) => (
8
+ <nav
9
+ aria-label="pagination"
10
+ className={cn('mx-auto flex w-full justify-center', className)}
11
+ role="navigation"
12
+ {...props}
13
+ />
14
+ );
15
+ Pagination.displayName = 'Pagination';
16
+
17
+ const PaginationContent = ({
18
+ className,
19
+ ...props
20
+ }: React.ComponentProps<'ul'>) => (
21
+ <ul
22
+ className={cn('flex flex-row items-center gap-1', className)}
23
+ {...props}
24
+ />
25
+ );
26
+ PaginationContent.displayName = 'PaginationContent';
27
+
28
+ const PaginationItem = ({
29
+ className,
30
+ ...props
31
+ }: React.ComponentProps<'li'>) => (
32
+ <li className={cn('', className)} {...props} />
33
+ );
34
+ PaginationItem.displayName = 'PaginationItem';
35
+
36
+ type PaginationLinkProps = {
37
+ isActive?: boolean;
38
+ } & Pick<ButtonProps, 'size'> &
39
+ React.ComponentProps<'a'>;
40
+
41
+ const PaginationLink = ({
42
+ className,
43
+ isActive,
44
+ size = 'icon',
45
+ ...props
46
+ }: PaginationLinkProps) => (
47
+ <a
48
+ aria-current={isActive ? 'page' : undefined}
49
+ className={cn(
50
+ buttonVariants({
51
+ variant: isActive ? 'outline' : 'tertiary',
52
+ size,
53
+ }),
54
+ 'size-[30px] rounded-lg p-0.5',
55
+ className,
56
+ )}
57
+ {...props}
58
+ />
59
+ );
60
+ PaginationLink.displayName = 'PaginationLink';
61
+
62
+ const PaginationPrevious = ({
63
+ className,
64
+ ...props
65
+ }: React.ComponentProps<typeof PaginationLink>) => (
66
+ <PaginationLink
67
+ aria-label="Go to previous page"
68
+ className={cn('gap-1', className)}
69
+ size="sm"
70
+ {...props}
71
+ >
72
+ <UndoIcon className="h-4 w-4" />
73
+ <span className="sr-only">Previous</span>
74
+ </PaginationLink>
75
+ );
76
+ PaginationPrevious.displayName = 'PaginationPrevious';
77
+
78
+ const PaginationNext = ({
79
+ className,
80
+ ...props
81
+ }: React.ComponentProps<typeof PaginationLink>) => (
82
+ <PaginationLink
83
+ aria-label="Go to next page"
84
+ className={cn('gap-1', className)}
85
+ size="sm"
86
+ {...props}
87
+ >
88
+ <span className="sr-only">Next</span>
89
+ <RedoIcon className="h-4 w-4" />
90
+ </PaginationLink>
91
+ );
92
+ PaginationNext.displayName = 'PaginationNext';
93
+
94
+ const PaginationEllipsis = ({
95
+ className,
96
+ ...props
97
+ }: React.ComponentProps<'span'>) => (
98
+ <span
99
+ aria-hidden
100
+ className={cn('flex h-9 w-9 items-center justify-center', className)}
101
+ {...props}
102
+ >
103
+ <MoreHorizontal className="h-4 w-4" />
104
+ <span className="sr-only">More pages</span>
105
+ </span>
106
+ );
107
+ PaginationEllipsis.displayName = 'PaginationEllipsis';
108
+
109
+ export {
110
+ Pagination,
111
+ PaginationContent,
112
+ PaginationLink,
113
+ PaginationItem,
114
+ PaginationPrevious,
115
+ PaginationNext,
116
+ PaginationEllipsis,
117
+ };
@@ -0,0 +1,34 @@
1
+ import * as PopoverPrimitive from '@radix-ui/react-popover';
2
+ import React from 'react';
3
+
4
+ import { cn } from '../src/utils';
5
+
6
+ const Popover = PopoverPrimitive.Root;
7
+
8
+ const PopoverTrigger = PopoverPrimitive.Trigger;
9
+ const PopoverAnchor = PopoverPrimitive.Anchor;
10
+ const PopoverArrow = PopoverPrimitive.Arrow;
11
+ const PopoverClose = PopoverPrimitive.Close;
12
+
13
+ const PopoverContent = ({
14
+ className,
15
+ align = 'center',
16
+ sideOffset = 4,
17
+ ...props
18
+ }: React.ComponentProps<typeof PopoverPrimitive.Content>) => (
19
+ <PopoverPrimitive.Portal>
20
+ <PopoverPrimitive.Content
21
+ align={align}
22
+ className={cn(
23
+ 'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
24
+ 'bg-bg-dark border-divider z-50 w-72 rounded-md border p-4 text-gray-50 shadow-lg shadow-md outline-hidden',
25
+ className,
26
+ )}
27
+ sideOffset={sideOffset}
28
+ {...props}
29
+ />
30
+ </PopoverPrimitive.Portal>
31
+ );
32
+ PopoverContent.displayName = PopoverPrimitive.Content.displayName;
33
+
34
+ export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor, PopoverArrow, PopoverClose };
@@ -0,0 +1,28 @@
1
+ import { useMemo } from 'react';
2
+ import { cn } from '../src/utils';
3
+
4
+ export const PrettyJsonPrint = ({
5
+ json,
6
+ className,
7
+ }: {
8
+ json: string | object;
9
+ className?: string;
10
+ }) => {
11
+ const formattedJson = useMemo(() => {
12
+ let formattedValue = `Unparseable JSON: String(${json})`;
13
+ if (typeof json === 'object') {
14
+ formattedValue = JSON.stringify(json, null, 2);
15
+ } else if (typeof json === 'string') {
16
+ try {
17
+ const parsedJson = JSON.parse(json);
18
+ formattedValue = JSON.stringify(parsedJson, null, 2);
19
+ } catch (error) {
20
+ console.error('error parsing json', error);
21
+ }
22
+ }
23
+ return formattedValue;
24
+ }, [json]);
25
+ return (
26
+ <pre className={cn('overflow-x-scroll', className)}>{formattedJson}</pre>
27
+ );
28
+ };
@@ -0,0 +1,27 @@
1
+ import * as ProgressPrimitive from '@radix-ui/react-progress';
2
+ import React from 'react';
3
+
4
+ import { cn } from '../src/utils';
5
+
6
+ const Progress = ({
7
+ className,
8
+ value,
9
+ ...props
10
+ }: React.ComponentProps<typeof ProgressPrimitive.Root>) => (
11
+ <ProgressPrimitive.Root
12
+ className={cn(
13
+ 'bg-bg-quaternary relative h-4 w-full overflow-hidden',
14
+ className,
15
+ )}
16
+ {...props}
17
+ >
18
+ <ProgressPrimitive.Indicator
19
+ className="h-full w-full flex-1 bg-green-500 transition-all"
20
+ style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
21
+ />
22
+ </ProgressPrimitive.Root>
23
+ );
24
+ Progress.displayName = ProgressPrimitive.Root.displayName;
25
+
26
+ export { Progress };
27
+ export default Progress;
@@ -0,0 +1,72 @@
1
+ import React from 'react';
2
+
3
+ import { cn } from '../src/utils';
4
+ import { DotsLoader } from './dots-loader';
5
+ import { FormLabel } from './form';
6
+
7
+ const MIN_TEXTAREA_HEIGHT = 32;
8
+ export interface PromptTextareaProps
9
+ extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
10
+ isLoading?: boolean;
11
+ label?: string;
12
+ field: {
13
+ onChange: (...event: any[]) => void;
14
+ onBlur: () => void;
15
+ value: any;
16
+ disabled?: boolean;
17
+ name: string;
18
+ placeholder?: string;
19
+ };
20
+ }
21
+
22
+ const PromptTextarea = ({ className, ...props }: PromptTextareaProps) => {
23
+ const textareaRef = React.useRef<HTMLTextAreaElement>(null);
24
+
25
+ React.useLayoutEffect(() => {
26
+ // Reset height - important to shrink on delete
27
+
28
+ if (!textareaRef.current) return;
29
+
30
+ textareaRef.current.style.height = '60px';
31
+ // Set height
32
+ textareaRef.current.style.height = `${Math.max(
33
+ textareaRef.current.scrollHeight + 2,
34
+ MIN_TEXTAREA_HEIGHT,
35
+ )}px`;
36
+
37
+ if (props.autoFocus !== undefined && props.autoFocus) {
38
+ textareaRef.current.focus();
39
+ }
40
+ // eslint-disable-next-line react-hooks/exhaustive-deps
41
+ }, [props.value]);
42
+
43
+ return (
44
+ <>
45
+ <textarea
46
+ className={cn(
47
+ 'flex w-full rounded-md border border-gray-200 bg-gray-400 px-4 py-2 pt-4 text-sm break-words placeholder-gray-100 placeholder:text-base focus-visible:ring-1 focus-visible:ring-gray-100 focus-visible:outline-hidden focus-visible:ring-inset disabled:cursor-not-allowed disabled:opacity-50',
48
+ className,
49
+ )}
50
+ style={{
51
+ minHeight: MIN_TEXTAREA_HEIGHT,
52
+ resize: 'none',
53
+ maxHeight: '300px',
54
+ }}
55
+ {...props.field}
56
+ onKeyDown={props.onKeyDown}
57
+ ref={textareaRef}
58
+ {...(!props.isLoading && {
59
+ placeholder: props.label,
60
+ })}
61
+ />
62
+
63
+ {props.isLoading ? (
64
+ <DotsLoader className="absolute top-6 left-4" />
65
+ ) : null}
66
+ <FormLabel className="sr-only">{props.label}</FormLabel>
67
+ </>
68
+ );
69
+ };
70
+ PromptTextarea.displayName = 'PromptTextarea';
71
+
72
+ export { PromptTextarea };
@@ -0,0 +1,112 @@
1
+ import { DownloadIcon } from '@radix-ui/react-icons';
2
+ import { Check } from 'lucide-react';
3
+ import React, { useState } from 'react';
4
+ import { IProps, QRCode as ReactQRCode } from 'react-qrcode-logo';
5
+
6
+ import hanzoLogo from '../assets/images/app-icon.png';
7
+ import { Button } from './button';
8
+ import { Dialog, DialogContent } from './dialog';
9
+
10
+ export function QRCode({
11
+ value,
12
+ size,
13
+ id,
14
+ ...props
15
+ }: {
16
+ value: IProps['value'];
17
+ size: IProps['size'];
18
+ id?: IProps['id'];
19
+ } & React.HTMLAttributes<HTMLDivElement>): React.ReactElement {
20
+ return (
21
+ <div {...props}>
22
+ <ReactQRCode
23
+ ecLevel={'M'}
24
+ eyeColor="black"
25
+ eyeRadius={10}
26
+ fgColor="black"
27
+ id={id}
28
+ logoHeight={size ? size * 0.2 : undefined}
29
+ logoImage={hanzoLogo}
30
+ logoPaddingStyle="circle"
31
+ logoWidth={size ? size * 0.2 : undefined}
32
+ qrStyle="dots"
33
+ removeQrCodeBehindLogo
34
+ size={size ?? 300}
35
+ value={value}
36
+ />
37
+ </div>
38
+ );
39
+ }
40
+
41
+ export function QrCodeModal({
42
+ open,
43
+ onOpenChange,
44
+ value,
45
+ onSave,
46
+ title,
47
+ description,
48
+ modalClassName,
49
+ }: {
50
+ open: boolean;
51
+ onOpenChange: (open: boolean) => void;
52
+ value: IProps['value'];
53
+ onSave: (key: string) => void;
54
+ title: React.ReactNode;
55
+ description: React.ReactNode;
56
+ modalClassName?: string;
57
+ }) {
58
+ const [saved, setSaved] = useState(false);
59
+ const downloadCode = async () => {
60
+ const canvas = document.querySelector('#registration-code-qr');
61
+ if (canvas instanceof HTMLCanvasElement) {
62
+ try {
63
+ const pngUrl = canvas.toDataURL();
64
+ onSave(pngUrl);
65
+ setSaved(true);
66
+ } catch (error) {
67
+ console.error(error);
68
+ } finally {
69
+ setTimeout(() => {
70
+ setSaved(false);
71
+ }, 3000);
72
+ }
73
+ }
74
+ };
75
+
76
+ return (
77
+ <Dialog onOpenChange={onOpenChange} open={open}>
78
+ <DialogContent className={modalClassName}>
79
+ <div className="flex flex-col items-center py-4">
80
+ <h2 className="mb-1 text-lg font-semibold">{title}</h2>
81
+ <p className="text-text-secondary mb-5 text-center text-xs">
82
+ {description}
83
+ </p>
84
+ <div className="mb-7 overflow-hidden rounded-lg shadow-2xl">
85
+ <QRCode size={190} value={value} />
86
+ <QRCode
87
+ className="hidden"
88
+ id="registration-code-qr"
89
+ size={1024}
90
+ value={value}
91
+ />
92
+ </div>
93
+ <div className="flex flex-col gap-4">
94
+ <Button className="flex gap-1" onClick={downloadCode}>
95
+ {saved ? <Check /> : <DownloadIcon className="h-4 w-4" />}
96
+ {saved ? 'Saved' : 'Download'}
97
+ </Button>
98
+ <Button
99
+ className="flex gap-1"
100
+ onClick={() => {
101
+ onOpenChange(false);
102
+ }}
103
+ variant="tertiary"
104
+ >
105
+ I saved it, close
106
+ </Button>
107
+ </div>
108
+ </div>
109
+ </DialogContent>
110
+ </Dialog>
111
+ );
112
+ }
@@ -0,0 +1,42 @@
1
+ 'use client';
2
+
3
+ import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
4
+ import { Circle } from 'lucide-react';
5
+ import React from 'react';
6
+
7
+ import { cn } from '../src/utils';
8
+
9
+ const RadioGroup = ({
10
+ className,
11
+ ...props
12
+ }: React.ComponentProps<typeof RadioGroupPrimitive.Root>) => {
13
+ return (
14
+ <RadioGroupPrimitive.Root
15
+ className={cn('grid gap-2', className)}
16
+ {...props}
17
+ />
18
+ );
19
+ };
20
+ RadioGroup.displayName = RadioGroupPrimitive.Root.displayName;
21
+
22
+ const RadioGroupItem = ({
23
+ className,
24
+ ...props
25
+ }: React.ComponentProps<typeof RadioGroupPrimitive.Item>) => {
26
+ return (
27
+ <RadioGroupPrimitive.Item
28
+ className={cn(
29
+ 'border-brand text-brand ring-offset-background focus-visible:ring-ring aspect-square h-4 w-4 rounded-full border focus:outline-hidden focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
30
+ className,
31
+ )}
32
+ {...props}
33
+ >
34
+ <RadioGroupPrimitive.Indicator className="flex items-center justify-center">
35
+ <Circle className="h-2.5 w-2.5 fill-current text-current" />
36
+ </RadioGroupPrimitive.Indicator>
37
+ </RadioGroupPrimitive.Item>
38
+ );
39
+ };
40
+ RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;
41
+
42
+ export { RadioGroup, RadioGroupItem };
@@ -0,0 +1,47 @@
1
+ import { GripVertical } from 'lucide-react';
2
+ import * as ResizablePrimitive from 'react-resizable-panels';
3
+
4
+ import { cn } from '../src/utils';
5
+
6
+ const ResizablePanelGroup = ({
7
+ className,
8
+ ...props
9
+ }: React.ComponentProps<typeof ResizablePrimitive.PanelGroup>) => (
10
+ <ResizablePrimitive.PanelGroup
11
+ className={cn(
12
+ 'flex h-full w-full data-[panel-group-direction=vertical]:flex-col',
13
+ className,
14
+ )}
15
+ {...props}
16
+ />
17
+ );
18
+
19
+ const ResizablePanel = ResizablePrimitive.Panel;
20
+
21
+ const ResizableHandle = ({
22
+ withHandle,
23
+ className,
24
+ ...props
25
+ }: React.ComponentProps<typeof ResizablePrimitive.PanelResizeHandle> & {
26
+ withHandle?: boolean;
27
+ }) => (
28
+ <ResizablePrimitive.PanelResizeHandle
29
+ className={cn(
30
+ 'focus-visible:ring-ring relative flex w-px items-center justify-center bg-gray-100 after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:ring-1 focus-visible:ring-offset-1 focus-visible:outline-hidden',
31
+ 'data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:translate-x-0 data-[panel-group-direction=vertical]:after:-translate-y-1/2 [&[data-panel-group-direction=vertical]>div]:rotate-90',
32
+ 'data-[resize-handle-state=drag]:after:bg-bg-secondary',
33
+ 'data-[resize-handle-state=hover]:after:bg-bg-secondary',
34
+ 'after:w-[1px] data-[panel-group-direction=vertical]:after:h-[1px]',
35
+ className,
36
+ )}
37
+ {...props}
38
+ >
39
+ {withHandle && (
40
+ <div className="z-10 flex h-4 w-3 items-center justify-center rounded-xs border bg-gray-200">
41
+ <GripVertical className="h-2.5 w-2.5" />
42
+ </div>
43
+ )}
44
+ </ResizablePrimitive.PanelResizeHandle>
45
+ );
46
+
47
+ export { ResizablePanelGroup, ResizablePanel, ResizableHandle };
@@ -0,0 +1,57 @@
1
+ import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
2
+ import React from 'react';
3
+
4
+ import { cn } from '../src/utils';
5
+
6
+ const ScrollArea = ({
7
+ className,
8
+ children,
9
+ ref,
10
+ ...props
11
+ }: React.ComponentProps<typeof ScrollAreaPrimitive.Root> & {
12
+ ref?: React.RefObject<HTMLDivElement | null>;
13
+ }) => (
14
+ <ScrollAreaPrimitive.Root
15
+ className={cn('relative overflow-hidden', className)}
16
+ {...props}
17
+ >
18
+ <ScrollAreaPrimitive.Viewport
19
+ className="h-full w-full rounded-[inherit]"
20
+ ref={ref}
21
+ >
22
+ {children}
23
+ </ScrollAreaPrimitive.Viewport>
24
+ <ScrollBar />
25
+ <ScrollAreaPrimitive.Corner />
26
+ </ScrollAreaPrimitive.Root>
27
+ );
28
+ ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
29
+
30
+ const ScrollBar = ({
31
+ className,
32
+ orientation = 'vertical',
33
+ ...props
34
+ }: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>) => (
35
+ <ScrollAreaPrimitive.ScrollAreaScrollbar
36
+ className={cn(
37
+ 'flex touch-none transition-colors select-none',
38
+ orientation === 'vertical' &&
39
+ 'h-full w-2.5 border-l border-l-transparent p-[1px]',
40
+ orientation === 'horizontal' &&
41
+ 'h-2.5 border-t border-t-transparent p-[1px]',
42
+ className,
43
+ )}
44
+ orientation={orientation}
45
+ {...props}
46
+ >
47
+ <ScrollAreaPrimitive.ScrollAreaThumb
48
+ className={cn(
49
+ 'relative rounded-full bg-gray-300',
50
+ orientation === 'vertical' && 'flex-1',
51
+ )}
52
+ />
53
+ </ScrollAreaPrimitive.ScrollAreaScrollbar>
54
+ );
55
+ ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
56
+
57
+ export { ScrollArea, ScrollBar };
@@ -0,0 +1,66 @@
1
+ import { SearchIcon, XIcon } from 'lucide-react';
2
+ import React from 'react';
3
+
4
+ import { cn } from '../src/utils';
5
+ import { Button } from './button';
6
+ import { Input } from './input';
7
+
8
+ export type SearchInputProps = React.InputHTMLAttributes<HTMLInputElement> & {
9
+ classNames?: {
10
+ container?: string;
11
+ input?: string;
12
+ button?: string;
13
+ };
14
+ };
15
+
16
+ const SearchInput = ({
17
+ className,
18
+ value,
19
+ onChange,
20
+ classNames,
21
+ ...props
22
+ }: SearchInputProps) => {
23
+ return (
24
+ <div
25
+ className={cn(
26
+ 'shadow-border-input focus-within:shadow-border-input-focus relative flex h-10 flex-1 items-center overflow-hidden rounded-full shadow-[0_0_0_1px_currentColor] transition-shadow',
27
+ classNames?.container,
28
+ )}
29
+ >
30
+ <Input
31
+ className={cn(
32
+ 'placeholder:!text-text-placeholder !h-full border-none bg-transparent py-2 pl-10',
33
+ classNames?.input,
34
+ )}
35
+ onChange={(e) => {
36
+ onChange?.(e);
37
+ }}
38
+ placeholder="Search..."
39
+ spellCheck={false}
40
+ value={value}
41
+ {...props}
42
+ />
43
+ <SearchIcon className="text-text-tertiary absolute top-1/2 left-4 -z-[1px] h-4 w-4 -translate-y-1/2" />
44
+ {value && (
45
+ <Button
46
+ className={cn('absolute right-1 h-8 w-8 p-2', classNames?.button)}
47
+ onClick={() => {
48
+ onChange?.({
49
+ target: { value: '' },
50
+ } as React.ChangeEvent<HTMLInputElement>);
51
+ }}
52
+ size="auto"
53
+ type="button"
54
+ variant="tertiary"
55
+ >
56
+ <XIcon />
57
+ <span className="sr-only">Clear</span>
58
+ </Button>
59
+ )}
60
+ </div>
61
+ );
62
+ };
63
+
64
+ SearchInput.displayName = 'SearchInput';
65
+
66
+ export { SearchInput };