@hanzo/ui 5.3.26 → 5.3.29

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 (100) hide show
  1. package/content/index.ts +26 -0
  2. package/dist/util/index.js +6 -0
  3. package/dist/util/index.mjs +6 -1
  4. package/docs/_registry/index.ts +426 -0
  5. package/docs/_registry/layout/docs-min.tsx +197 -0
  6. package/docs/_registry/layout/page-min.tsx +128 -0
  7. package/docs/components/accordion.tsx +118 -0
  8. package/docs/components/banner.tsx +144 -0
  9. package/docs/components/callout.tsx +112 -0
  10. package/docs/components/card.tsx +52 -0
  11. package/docs/components/codeblock.tsx +258 -0
  12. package/docs/components/dialog/search-algolia.tsx +132 -0
  13. package/docs/components/dialog/search-default.tsx +131 -0
  14. package/docs/components/dialog/search-orama.tsx +143 -0
  15. package/docs/components/dialog/search.tsx +529 -0
  16. package/docs/components/dynamic-codeblock.tsx +129 -0
  17. package/docs/components/files.tsx +81 -0
  18. package/docs/components/github-info.tsx +107 -0
  19. package/docs/components/heading.tsx +33 -0
  20. package/docs/components/image-zoom.css +77 -0
  21. package/docs/components/image-zoom.tsx +58 -0
  22. package/docs/components/index.ts +7 -0
  23. package/docs/components/inline-toc.tsx +48 -0
  24. package/docs/components/sidebar/base.tsx +451 -0
  25. package/docs/components/sidebar/link-item.tsx +65 -0
  26. package/docs/components/sidebar/page-tree.tsx +113 -0
  27. package/docs/components/sidebar/tabs/dropdown.tsx +109 -0
  28. package/docs/components/sidebar/tabs/index.tsx +89 -0
  29. package/docs/components/steps.tsx +9 -0
  30. package/docs/components/tabs.tsx +203 -0
  31. package/docs/components/toc/clerk.tsx +173 -0
  32. package/docs/components/toc/default.tsx +57 -0
  33. package/docs/components/toc/index.tsx +136 -0
  34. package/docs/components/type-table.tsx +174 -0
  35. package/docs/components/ui/accordion.tsx +88 -0
  36. package/docs/components/ui/button.tsx +28 -0
  37. package/docs/components/ui/collapsible.tsx +42 -0
  38. package/docs/components/ui/navigation-menu.tsx +83 -0
  39. package/docs/components/ui/popover.tsx +32 -0
  40. package/docs/components/ui/scroll-area.tsx +59 -0
  41. package/docs/components/ui/tabs.tsx +145 -0
  42. package/docs/contexts/i18n.tsx +56 -0
  43. package/docs/contexts/search.tsx +165 -0
  44. package/docs/contexts/tree.tsx +65 -0
  45. package/docs/css/black.css +39 -0
  46. package/docs/css/catppuccin.css +49 -0
  47. package/docs/css/colors/index.css +51 -0
  48. package/docs/css/dusk.css +47 -0
  49. package/docs/css/layouts/docs.css +1 -0
  50. package/docs/css/layouts/home.css +1 -0
  51. package/docs/css/layouts/notebook.css +1 -0
  52. package/docs/css/neutral.css +7 -0
  53. package/docs/css/ocean.css +48 -0
  54. package/docs/css/preset.css +305 -0
  55. package/docs/css/purple.css +39 -0
  56. package/docs/css/shadcn.css +36 -0
  57. package/docs/css/shiki.css +90 -0
  58. package/docs/css/solar.css +75 -0
  59. package/docs/css/style.css +9 -0
  60. package/docs/css/vitepress.css +77 -0
  61. package/docs/i18n.tsx +30 -0
  62. package/docs/icons.tsx +354 -0
  63. package/docs/layouts/docs/client.tsx +129 -0
  64. package/docs/layouts/docs/index.tsx +321 -0
  65. package/docs/layouts/docs/page/client.tsx +376 -0
  66. package/docs/layouts/docs/page/index.tsx +251 -0
  67. package/docs/layouts/docs/sidebar.tsx +265 -0
  68. package/docs/layouts/home/client.tsx +375 -0
  69. package/docs/layouts/home/index.tsx +51 -0
  70. package/docs/layouts/home/navbar.tsx +55 -0
  71. package/docs/layouts/notebook/client.tsx +281 -0
  72. package/docs/layouts/notebook/index.tsx +461 -0
  73. package/docs/layouts/notebook/page/client.tsx +375 -0
  74. package/docs/layouts/notebook/page/index.tsx +251 -0
  75. package/docs/layouts/notebook/sidebar.tsx +248 -0
  76. package/docs/layouts/shared/index.tsx +89 -0
  77. package/docs/layouts/shared/language-toggle.tsx +66 -0
  78. package/docs/layouts/shared/link-item.tsx +119 -0
  79. package/docs/layouts/shared/search-toggle.tsx +78 -0
  80. package/docs/layouts/shared/theme-toggle.tsx +86 -0
  81. package/docs/mdx.server.tsx +37 -0
  82. package/docs/mdx.tsx +97 -0
  83. package/docs/og.tsx +101 -0
  84. package/docs/page.tsx +85 -0
  85. package/docs/provider/base.tsx +173 -0
  86. package/docs/provider/next.tsx +23 -0
  87. package/docs/provider/react-router.tsx +23 -0
  88. package/docs/provider/tanstack.tsx +23 -0
  89. package/docs/provider/waku.tsx +23 -0
  90. package/docs/source.ts +3 -0
  91. package/docs/theme/typography/LICENSE +21 -0
  92. package/docs/theme/typography/index.ts +201 -0
  93. package/docs/theme/typography/styles.ts +449 -0
  94. package/docs/utils/cn.ts +1 -0
  95. package/docs/utils/is-active.ts +23 -0
  96. package/docs/utils/merge-refs.ts +15 -0
  97. package/docs/utils/use-copy-button.ts +39 -0
  98. package/docs/utils/use-footer-items.ts +27 -0
  99. package/docs/utils/use-is-scroll-top.ts +21 -0
  100. package/package.json +4 -2
@@ -0,0 +1,81 @@
1
+ 'use client';
2
+
3
+ import { cva } from 'class-variance-authority';
4
+ import { File as FileIcon, Folder as FolderIcon, FolderOpen } from '@icons';
5
+ import { type HTMLAttributes, type ReactNode, useState } from 'react';
6
+ import { cn } from '@/utils/cn';
7
+ import {
8
+ Collapsible,
9
+ CollapsibleContent,
10
+ CollapsibleTrigger,
11
+ } from './ui/collapsible';
12
+
13
+ const itemVariants = cva(
14
+ 'flex flex-row items-center gap-2 rounded-md px-2 py-1.5 text-sm hover:bg-fd-accent hover:text-fd-accent-foreground [&_svg]:size-4',
15
+ );
16
+
17
+ export function Files({
18
+ className,
19
+ ...props
20
+ }: HTMLAttributes<HTMLDivElement>): React.ReactElement {
21
+ return (
22
+ <div
23
+ className={cn('not-prose rounded-md border bg-fd-card p-2', className)}
24
+ {...props}
25
+ >
26
+ {props.children}
27
+ </div>
28
+ );
29
+ }
30
+
31
+ export interface FileProps extends HTMLAttributes<HTMLDivElement> {
32
+ name: string;
33
+ icon?: ReactNode;
34
+ }
35
+
36
+ export interface FolderProps extends HTMLAttributes<HTMLDivElement> {
37
+ name: string;
38
+
39
+ disabled?: boolean;
40
+
41
+ /**
42
+ * Open folder by default
43
+ *
44
+ * @defaultValue false
45
+ */
46
+ defaultOpen?: boolean;
47
+ }
48
+
49
+ export function File({
50
+ name,
51
+ icon = <FileIcon />,
52
+ className,
53
+ ...rest
54
+ }: FileProps): React.ReactElement {
55
+ return (
56
+ <div className={cn(itemVariants({ className }))} {...rest}>
57
+ {icon}
58
+ {name}
59
+ </div>
60
+ );
61
+ }
62
+
63
+ export function Folder({
64
+ name,
65
+ defaultOpen = false,
66
+ ...props
67
+ }: FolderProps): React.ReactElement {
68
+ const [open, setOpen] = useState(defaultOpen);
69
+
70
+ return (
71
+ <Collapsible open={open} onOpenChange={setOpen} {...props}>
72
+ <CollapsibleTrigger className={cn(itemVariants({ className: 'w-full' }))}>
73
+ {open ? <FolderOpen /> : <FolderIcon />}
74
+ {name}
75
+ </CollapsibleTrigger>
76
+ <CollapsibleContent>
77
+ <div className="ms-2 flex flex-col border-l ps-2">{props.children}</div>
78
+ </CollapsibleContent>
79
+ </Collapsible>
80
+ );
81
+ }
@@ -0,0 +1,107 @@
1
+ import { cn } from '@/utils/cn';
2
+ import { Star } from '@icons';
3
+ import { type AnchorHTMLAttributes } from 'react';
4
+
5
+ async function getRepoStarsAndForks(
6
+ owner: string,
7
+ repo: string,
8
+ token?: string,
9
+ baseUrl: string = 'https://api.github.com',
10
+ ): Promise<{
11
+ stars: number;
12
+ forks: number;
13
+ }> {
14
+ const endpoint = `${baseUrl}/repos/${owner}/${repo}`;
15
+ const headers = new Headers({
16
+ 'Content-Type': 'application/json',
17
+ });
18
+
19
+ if (token) headers.set('Authorization', `Bearer ${token}`);
20
+
21
+ const response = await fetch(endpoint, {
22
+ headers,
23
+ next: {
24
+ revalidate: 60,
25
+ },
26
+ } as RequestInit);
27
+
28
+ if (!response.ok) {
29
+ const message = await response.text();
30
+
31
+ throw new Error(`Failed to fetch repository data: ${message}`);
32
+ }
33
+
34
+ const data = await response.json();
35
+ return {
36
+ stars: data.stargazers_count,
37
+ forks: data.forks_count,
38
+ };
39
+ }
40
+
41
+ export async function GithubInfo({
42
+ repo,
43
+ owner,
44
+ token,
45
+ baseUrl,
46
+ ...props
47
+ }: AnchorHTMLAttributes<HTMLAnchorElement> & {
48
+ owner: string;
49
+ repo: string;
50
+ token?: string;
51
+ baseUrl?: string;
52
+ }) {
53
+ const { stars } = await getRepoStarsAndForks(owner, repo, token, baseUrl);
54
+ const humanizedStars = humanizeNumber(stars);
55
+
56
+ return (
57
+ <a
58
+ href={`https://github.com/${owner}/${repo}`}
59
+ rel="noreferrer noopener"
60
+ target="_blank"
61
+ {...props}
62
+ className={cn(
63
+ 'flex flex-col gap-1.5 p-2 rounded-lg text-sm text-fd-foreground/80 transition-colors lg:flex-row lg:items-center hover:text-fd-accent-foreground hover:bg-fd-accent',
64
+ props.className,
65
+ )}
66
+ >
67
+ <p className="flex items-center gap-2 truncate">
68
+ <svg fill="currentColor" viewBox="0 0 24 24" className="size-3.5">
69
+ <title>GitHub</title>
70
+ <path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" />
71
+ </svg>
72
+ {owner}/{repo}
73
+ </p>
74
+ <p className="flex text-xs items-center gap-1 text-fd-muted-foreground">
75
+ <Star className="size-3" />
76
+ {humanizedStars}
77
+ </p>
78
+ </a>
79
+ );
80
+ }
81
+
82
+ /**
83
+ * Converts a number to a human-readable string with K suffix for thousands
84
+ * @example 1500 -> "1.5K", 1000000 -> "1000000"
85
+ */
86
+ function humanizeNumber(num: number): string {
87
+ if (num < 1000) {
88
+ return num.toString();
89
+ }
90
+
91
+ if (num < 100000) {
92
+ // For numbers between 1,000 and 99,999, show with one decimal (e.g., 1.5K)
93
+ const value = (num / 1000).toFixed(1);
94
+ // Remove trailing .0 if present
95
+ const formattedValue = value.endsWith('.0') ? value.slice(0, -2) : value;
96
+
97
+ return `${formattedValue}K`;
98
+ }
99
+
100
+ if (num < 1000000) {
101
+ // For numbers between 10,000 and 999,999, show as whole K (e.g., 10K, 999K)
102
+ return `${Math.floor(num / 1000)}K`;
103
+ }
104
+
105
+ // For 1,000,000 and above, just return the number
106
+ return num.toString();
107
+ }
@@ -0,0 +1,33 @@
1
+ import { Link } from '@icons';
2
+ import type { ComponentPropsWithoutRef } from 'react';
3
+ import { cn } from '@/utils/cn';
4
+
5
+ type Types = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
6
+ type HeadingProps<T extends Types> = Omit<ComponentPropsWithoutRef<T>, 'as'> & {
7
+ as?: T;
8
+ };
9
+
10
+ export function Heading<T extends Types = 'h1'>({
11
+ as,
12
+ className,
13
+ ...props
14
+ }: HeadingProps<T>): React.ReactElement {
15
+ const As = as ?? 'h1';
16
+
17
+ if (!props.id) return <As className={className} {...props} />;
18
+
19
+ return (
20
+ <As
21
+ className={cn('flex scroll-m-28 flex-row items-center gap-2', className)}
22
+ {...props}
23
+ >
24
+ <a data-card="" href={`#${props.id}`} className="peer">
25
+ {props.children}
26
+ </a>
27
+ <Link
28
+ aria-hidden
29
+ className="size-3.5 shrink-0 text-fd-muted-foreground opacity-0 transition-opacity peer-hover:opacity-100"
30
+ />
31
+ </As>
32
+ );
33
+ }
@@ -0,0 +1,77 @@
1
+ [data-rmiz] {
2
+ display: block;
3
+ position: relative;
4
+ }
5
+
6
+ [data-rmiz-ghost] {
7
+ pointer-events: none;
8
+ position: absolute;
9
+ }
10
+
11
+ [data-rmiz-btn-zoom],
12
+ [data-rmiz-btn-unzoom] {
13
+ display: none;
14
+ }
15
+
16
+ [data-rmiz-content='found'] img {
17
+ cursor: zoom-in;
18
+ }
19
+
20
+ [data-rmiz-modal][open] {
21
+ width: 100vw /* fallback */;
22
+ width: 100dvw;
23
+
24
+ height: 100vh /* fallback */;
25
+ height: 100dvh;
26
+
27
+ background-color: transparent;
28
+ max-width: none;
29
+ max-height: none;
30
+ margin: 0;
31
+ padding: 0;
32
+ position: fixed;
33
+ overflow: hidden;
34
+ }
35
+
36
+ [data-rmiz-modal]:focus-visible {
37
+ outline: none;
38
+ }
39
+
40
+ [data-rmiz-modal-overlay] {
41
+ transition: background-color 0.3s;
42
+ position: absolute;
43
+ inset: 0;
44
+ }
45
+
46
+ [data-rmiz-modal-overlay='visible'] {
47
+ background-color: var(--color-fd-background);
48
+ }
49
+
50
+ [data-rmiz-modal-overlay='hidden'] {
51
+ background-color: transparent;
52
+ }
53
+
54
+ [data-rmiz-modal-content] {
55
+ width: 100%;
56
+ height: 100%;
57
+ position: relative;
58
+ }
59
+
60
+ [data-rmiz-modal]::backdrop {
61
+ display: none;
62
+ }
63
+
64
+ [data-rmiz-modal-img] {
65
+ cursor: zoom-out;
66
+ image-rendering: high-quality;
67
+ transform-origin: 0 0;
68
+ transition: transform 0.3s;
69
+ position: absolute;
70
+ }
71
+
72
+ @media (prefers-reduced-motion: reduce) {
73
+ [data-rmiz-modal-overlay],
74
+ [data-rmiz-modal-img] {
75
+ transition-duration: 0.01ms !important;
76
+ }
77
+ }
@@ -0,0 +1,58 @@
1
+ 'use client';
2
+
3
+ import { Image, type ImageProps } from '@hanzo/docs-core/framework';
4
+ import type { ComponentProps } from 'react';
5
+ import Zoom, { type UncontrolledProps } from 'react-medium-image-zoom';
6
+ import './image-zoom.css';
7
+
8
+ export type ImageZoomProps = ImageProps & {
9
+ /**
10
+ * Image props when zoom in
11
+ */
12
+ zoomInProps?: ComponentProps<'img'>;
13
+
14
+ /**
15
+ * Props for `react-medium-image-zoom`
16
+ */
17
+ rmiz?: UncontrolledProps;
18
+ };
19
+
20
+ function getImageSrc(src: ImageProps['src']): string {
21
+ if (typeof src === 'string') return src;
22
+
23
+ if (typeof src === 'object') {
24
+ // Next.js
25
+ if ('default' in src)
26
+ return (src as { default: { src: string } }).default.src;
27
+ return src.src;
28
+ }
29
+
30
+ return '';
31
+ }
32
+
33
+ export function ImageZoom({
34
+ zoomInProps,
35
+ children,
36
+ rmiz,
37
+ ...props
38
+ }: ImageZoomProps) {
39
+ return (
40
+ <Zoom
41
+ zoomMargin={20}
42
+ wrapElement="span"
43
+ {...rmiz}
44
+ zoomImg={{
45
+ src: getImageSrc(props.src),
46
+ sizes: undefined,
47
+ ...zoomInProps,
48
+ }}
49
+ >
50
+ {children ?? (
51
+ <Image
52
+ sizes="(max-width: 768px) 100vw, (max-width: 1200px) 70vw, 900px"
53
+ {...props}
54
+ />
55
+ )}
56
+ </Zoom>
57
+ );
58
+ }
@@ -0,0 +1,7 @@
1
+ // Documentation-specific components
2
+ // For general content components (Card, Tabs, Steps, Callout, Accordion),
3
+ // use @hanzo/ui/content instead
4
+
5
+ // TypeTable is truly docs-specific (API reference tables)
6
+ export { TypeTable } from './type-table'
7
+ export type { TypeNode, ParameterNode } from './type-table'
@@ -0,0 +1,48 @@
1
+ 'use client';
2
+
3
+ import { ChevronDown } from '@icons';
4
+ import type { TOCItemType } from '@hanzo/docs-core/toc';
5
+ import {
6
+ Collapsible,
7
+ CollapsibleContent,
8
+ CollapsibleTrigger,
9
+ } from './ui/collapsible';
10
+ import type { ComponentProps } from 'react';
11
+ import { cn } from '@/utils/cn';
12
+
13
+ export interface InlineTocProps extends ComponentProps<typeof Collapsible> {
14
+ items: TOCItemType[];
15
+ }
16
+
17
+ export function InlineTOC({ items, ...props }: InlineTocProps) {
18
+ return (
19
+ <Collapsible
20
+ {...props}
21
+ className={cn(
22
+ 'not-prose rounded-lg border bg-fd-card text-fd-card-foreground',
23
+ props.className,
24
+ )}
25
+ >
26
+ <CollapsibleTrigger className="group inline-flex w-full items-center justify-between px-4 py-2.5 font-medium">
27
+ {props.children ?? 'Table of Contents'}
28
+ <ChevronDown className="size-4 transition-transform duration-200 group-data-[state=open]:rotate-180" />
29
+ </CollapsibleTrigger>
30
+ <CollapsibleContent>
31
+ <div className="flex flex-col p-4 pt-0 text-sm text-fd-muted-foreground">
32
+ {items.map((item) => (
33
+ <a
34
+ key={item.url}
35
+ href={item.url}
36
+ className="border-s py-1.5 hover:text-fd-accent-foreground"
37
+ style={{
38
+ paddingInlineStart: 12 * Math.max(item.depth - 1, 0),
39
+ }}
40
+ >
41
+ {item.title}
42
+ </a>
43
+ ))}
44
+ </div>
45
+ </CollapsibleContent>
46
+ </Collapsible>
47
+ );
48
+ }