@hanzo/ui 4.5.4 → 4.6.0

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 (156) hide show
  1. package/README-MCP.md +3 -3
  2. package/README.md +229 -0
  3. package/assets/ai-icons.tsx +207 -0
  4. package/assets/crypto.tsx +33 -0
  5. package/assets/file-type-icon.tsx +66 -0
  6. package/assets/file.tsx +45 -0
  7. package/assets/general.tsx +2318 -0
  8. package/assets/hanzo-logo.svg +9 -0
  9. package/assets/hanzo-logo.tsx +15 -0
  10. package/assets/index.ts +8 -0
  11. package/assets/index.tsx +4 -0
  12. package/assets/llm-provider.tsx +1094 -0
  13. package/bin/create-registry.js +1 -1
  14. package/bin/test-mcp.sh +1 -1
  15. package/bin/update-registry.js +2 -2
  16. package/blocks/components/content.tsx +1 -1
  17. package/blocks/components/grid-block/index.tsx +1 -1
  18. package/blocks/components/screenful-block/content.tsx +1 -1
  19. package/blocks/components/screenful-block/poster-background.tsx +1 -1
  20. package/components/index.ts +56 -0
  21. package/dist/button.d.ts +1 -0
  22. package/dist/button.js +1 -0
  23. package/dist/hooks/index.d.ts +7 -0
  24. package/dist/hooks/index.js +7 -0
  25. package/dist/hooks/use-click-away.d.ts +2 -0
  26. package/dist/hooks/use-click-away.js +23 -0
  27. package/dist/hooks/use-combined-refs.d.ts +3 -0
  28. package/dist/hooks/use-combined-refs.js +18 -0
  29. package/dist/hooks/use-copy-clipboard.d.ts +9 -0
  30. package/dist/hooks/use-copy-clipboard.js +21 -0
  31. package/dist/hooks/use-debounce.d.ts +1 -0
  32. package/dist/hooks/use-debounce.js +13 -0
  33. package/dist/hooks/use-fill-ids.d.ts +8 -0
  34. package/dist/hooks/use-fill-ids.js +20 -0
  35. package/dist/hooks/use-map.d.ts +1 -0
  36. package/dist/hooks/use-map.js +20 -0
  37. package/dist/hooks/use-measure.d.ts +8 -0
  38. package/dist/hooks/use-measure.js +25 -0
  39. package/dist/hooks/use-reverse-video-playback.d.ts +1 -0
  40. package/dist/hooks/use-reverse-video-playback.js +41 -0
  41. package/dist/hooks/use-scroll-restoration.d.ts +8 -0
  42. package/dist/hooks/use-scroll-restoration.js +36 -0
  43. package/dist/mcp/enhanced-server.js +2 -2
  44. package/dist/registry/api.d.ts +1 -1
  45. package/dist/registry/api.js +3 -3
  46. package/dist/registry/index.d.ts +48 -48
  47. package/dist/registry/index.js +3 -3
  48. package/dist/utils.d.ts +1 -0
  49. package/dist/utils.js +1 -0
  50. package/helpers/file.ts +33 -0
  51. package/helpers/memoization.ts +40 -0
  52. package/package.json +27 -6
  53. package/primitives/accordion.tsx +53 -45
  54. package/primitives/alert-dialog.tsx +185 -0
  55. package/primitives/alert.tsx +74 -0
  56. package/primitives/apply-typography.tsx +1 -1
  57. package/primitives/avatar.tsx +37 -29
  58. package/primitives/background-beams.tsx +142 -0
  59. package/primitives/badge.tsx +27 -19
  60. package/primitives/breadcrumb.tsx +77 -62
  61. package/primitives/button.tsx +69 -72
  62. package/primitives/card.tsx +73 -59
  63. package/primitives/chat/chat-input-area.tsx +87 -0
  64. package/primitives/chat/chat-input.tsx +71 -0
  65. package/primitives/chat/files-preview.tsx +330 -0
  66. package/primitives/chat/index.ts +6 -0
  67. package/primitives/chat/json-form.tsx +8 -0
  68. package/primitives/chat/message-list.tsx +307 -0
  69. package/primitives/chat/message.tsx +569 -0
  70. package/primitives/chat/sqlite-preview.tsx +215 -0
  71. package/primitives/checkbox.tsx +18 -19
  72. package/primitives/collapsible.tsx +9 -0
  73. package/primitives/command.tsx +75 -83
  74. package/primitives/context-menu.tsx +115 -109
  75. package/primitives/copy-to-clipboard-icon.tsx +60 -0
  76. package/primitives/dialog-video-controller.tsx +1 -1
  77. package/primitives/dialog.tsx +111 -145
  78. package/primitives/dot-pattern.tsx +57 -0
  79. package/primitives/dots-loader.tsx +13 -0
  80. package/primitives/drawer.tsx +59 -87
  81. package/primitives/dropdown-menu.tsx +199 -0
  82. package/primitives/error-message.tsx +19 -0
  83. package/primitives/file-uploader.tsx +200 -0
  84. package/primitives/form.tsx +92 -87
  85. package/primitives/hover-card.tsx +28 -0
  86. package/primitives/icons/github.tsx +1 -1
  87. package/primitives/icons/youtube-logo.tsx +1 -1
  88. package/primitives/index-common.ts +121 -42
  89. package/primitives/index-next.ts +3 -1
  90. package/primitives/input.tsx +115 -20
  91. package/primitives/label.tsx +15 -23
  92. package/primitives/loading-spinner.tsx +1 -1
  93. package/primitives/markdown-preview.tsx +609 -0
  94. package/primitives/mermaid.tsx +196 -0
  95. package/primitives/next/link-element.tsx +1 -1
  96. package/primitives/next/mdx-link.tsx +1 -1
  97. package/primitives/pagination.tsx +117 -0
  98. package/primitives/popover.tsx +20 -25
  99. package/primitives/pretty-json-print.tsx +28 -0
  100. package/primitives/progress.tsx +14 -15
  101. package/primitives/prompt-textarea.tsx +72 -0
  102. package/primitives/qr-code.tsx +112 -0
  103. package/primitives/radio-group.tsx +25 -39
  104. package/primitives/resizable.tsx +47 -0
  105. package/primitives/scroll-area.tsx +35 -25
  106. package/primitives/search-input.tsx +66 -0
  107. package/primitives/select.tsx +62 -109
  108. package/primitives/separator.tsx +22 -26
  109. package/primitives/sheet.tsx +78 -117
  110. package/primitives/skeleton.tsx +13 -16
  111. package/primitives/slider.tsx +50 -60
  112. package/primitives/stepper.tsx +272 -0
  113. package/primitives/switch.tsx +14 -23
  114. package/primitives/table.tsx +65 -77
  115. package/primitives/tabs.tsx +29 -39
  116. package/primitives/text-link.tsx +25 -0
  117. package/primitives/textarea.tsx +61 -0
  118. package/primitives/textfield.tsx +75 -0
  119. package/primitives/toast.tsx +30 -0
  120. package/primitives/toggle-group.tsx +33 -33
  121. package/primitives/toggle.tsx +22 -51
  122. package/primitives/tooltip.tsx +37 -38
  123. package/registry.json +1 -1
  124. package/src/button.ts +1 -0
  125. package/src/hooks/index.ts +7 -0
  126. package/src/hooks/use-click-away.ts +31 -0
  127. package/src/hooks/use-combined-refs.ts +22 -0
  128. package/src/hooks/use-copy-clipboard.ts +30 -0
  129. package/src/hooks/use-debounce.ts +17 -0
  130. package/src/hooks/use-fill-ids.ts +25 -0
  131. package/src/hooks/use-map.ts +26 -0
  132. package/src/hooks/use-measure.ts +42 -0
  133. package/src/hooks/use-reverse-video-playback.ts +43 -0
  134. package/src/hooks/use-scroll-restoration.ts +50 -0
  135. package/src/mcp/README.md +1 -1
  136. package/src/mcp/enhanced-server.ts +2 -2
  137. package/src/registry/api.ts +3 -3
  138. package/src/registry/index.ts +3 -3
  139. package/src/utils.ts +1 -0
  140. package/style/theme-provider.tsx +1 -1
  141. package/test-imports.mjs +19 -0
  142. package/types/animation-def.ts +1 -1
  143. package/types/button-def.ts +1 -1
  144. package/types/index.ts +1 -1
  145. package/util/blob.ts +28 -0
  146. package/util/copy-to-clipboard.ts +17 -0
  147. package/util/create-shadow-root.ts +22 -0
  148. package/util/date.ts +83 -0
  149. package/util/debounce.ts +11 -0
  150. package/util/file.ts +15 -0
  151. package/util/format-and-abbreviate-as-currency.ts +1 -1
  152. package/util/format-text.ts +33 -0
  153. package/util/index.ts +9 -78
  154. package/util/timing.ts +3 -0
  155. package/util/toasts.tsx +17 -0
  156. package/utils.ts +9 -0
@@ -0,0 +1,17 @@
1
+ export async function copyToClipboard(text: string) {
2
+ try {
3
+ await navigator.clipboard.writeText(text);
4
+ } catch {
5
+ // Fallback for browsers where the Clipboard API is not supported
6
+ const textarea = document.createElement('textarea');
7
+ textarea.style.position = 'fixed';
8
+ textarea.style.top = '-9999px';
9
+ textarea.style.left = '-9999px';
10
+ textarea.innerText = text;
11
+ document.body.appendChild(textarea);
12
+ textarea.focus();
13
+ textarea.select();
14
+ document.execCommand('copy');
15
+ textarea.remove();
16
+ }
17
+ }
@@ -0,0 +1,22 @@
1
+ import { createRoot } from 'react-dom/client';
2
+
3
+ /**
4
+ * Creates a shadow root with the specified styles and returns a React root in it.
5
+ * @param {string} tagName - Node name to be applied to the shadow root.
6
+ * @param {string} styles - CSS styles to be applied to the shadow root.
7
+ * @returns {ReactRoot} - React root rendered inside the shadow root.
8
+ */
9
+
10
+ export function createShadowRoot(tagName: string, styles: string) {
11
+ const container = document.createElement(tagName);
12
+ const shadow = container.attachShadow({ mode: 'open' });
13
+
14
+ // Create a new CSS style sheet and apply the specified styles and apply the style sheet to the shadow root
15
+ const globalStyleSheet = new CSSStyleSheet();
16
+ globalStyleSheet.replaceSync(styles);
17
+ shadow.adoptedStyleSheets = [globalStyleSheet];
18
+
19
+ const html = document.querySelector('html') as HTMLHtmlElement;
20
+ html.prepend(container);
21
+ return createRoot(shadow);
22
+ }
package/util/date.ts ADDED
@@ -0,0 +1,83 @@
1
+ import { FormattedMessage } from '@hanzo_network/hanzo-node-state/v2/queries/getChatConversation/types';
2
+
3
+ export type ChatConversationMessage = {
4
+ hash: string;
5
+ parentHash: string;
6
+ inboxId: string;
7
+ scheduledTime: string | undefined;
8
+ content: string;
9
+ isLocal: boolean;
10
+ sender: {
11
+ avatar: string;
12
+ };
13
+ fileInbox?: {
14
+ id: string;
15
+ files: {
16
+ name: string;
17
+ preview?: string;
18
+ }[];
19
+ };
20
+ };
21
+ export type GetChatConversationOutput = ChatConversationMessage[];
22
+
23
+ export const formatDateToUSLocaleString = (date: Date | undefined) => {
24
+ if (!date) return '-';
25
+ return new Date(date).toLocaleDateString('en-US', {
26
+ year: 'numeric',
27
+ month: 'numeric',
28
+ day: 'numeric',
29
+ });
30
+ };
31
+ export const formatDateToLocaleStringWithTime = (date: Date | undefined) => {
32
+ if (!date) return '-';
33
+ return new Date(date).toLocaleDateString('en-US', {
34
+ year: 'numeric',
35
+ month: 'numeric',
36
+ day: 'numeric',
37
+ hour: 'numeric',
38
+ minute: 'numeric',
39
+ });
40
+ };
41
+
42
+ export const getRelativeDateLabel = (date: Date): string => {
43
+ const today = new Date();
44
+ const yesterday = new Date();
45
+ yesterday.setDate(today.getDate() - 1);
46
+ if (date.toDateString() === today.toDateString()) {
47
+ return 'today';
48
+ } else if (date.toDateString() === yesterday.toDateString()) {
49
+ return 'yesterday';
50
+ } else {
51
+ return date.toDateString();
52
+ }
53
+ };
54
+
55
+ export const groupMessagesByDate = (messages: FormattedMessage[]) => {
56
+ const groupedMessages: Record<string, FormattedMessage[]> = {};
57
+ for (const message of messages) {
58
+ const date = new Date(message.createdAt ?? '').toDateString();
59
+ if (!groupedMessages[date]) {
60
+ groupedMessages[date] = [];
61
+ }
62
+ groupedMessages[date].push(message);
63
+ }
64
+ return groupedMessages;
65
+ };
66
+
67
+ export const formatDateToMonthAndDay = (date: Date): string => {
68
+ const today = new Date();
69
+ if (
70
+ date.getDate() === today.getDate() &&
71
+ date.getMonth() === today.getMonth() &&
72
+ date.getFullYear() === today.getFullYear()
73
+ ) {
74
+ return date.toLocaleTimeString('en-US', {
75
+ hour: 'numeric',
76
+ minute: 'numeric',
77
+ hour12: true,
78
+ });
79
+ }
80
+ const month = date.getMonth() + 1;
81
+ const day = date.getDate();
82
+ return `${month}/${day}`;
83
+ };
@@ -0,0 +1,11 @@
1
+ export const debounce = (func: Function, delay: number) => {
2
+ let timeoutId: NodeJS.Timeout | null = null;
3
+ return (...args: any[]) => {
4
+ if (timeoutId) {
5
+ clearTimeout(timeoutId);
6
+ }
7
+ timeoutId = setTimeout(() => {
8
+ func(...args);
9
+ }, delay);
10
+ };
11
+ };
package/util/file.ts ADDED
@@ -0,0 +1,15 @@
1
+ export const getFileName = (fileName: string): string => {
2
+ const nameParts = fileName.split('.');
3
+ return nameParts.slice(0, -1).join('.');
4
+ };
5
+ export const getFileExt = (fileName: string): string => {
6
+ const nameParts = fileName.split('.');
7
+ return nameParts.pop() || '';
8
+ };
9
+
10
+ export const isFileTypeImageOrPdf = (file: File): boolean => {
11
+ if (!file) return false;
12
+ return (
13
+ file?.type.startsWith('image/') || file?.type.startsWith('application/pdf')
14
+ );
15
+ };
@@ -1,4 +1,4 @@
1
- import Abbr, { type QuantityAbbrSymbol, ABBR_SYMBOLS_ARRAY } from './number-abbreviate'
1
+ import Abbr, { QuantityAbbrSymbol, ABBR_SYMBOLS_ARRAY } from './number-abbreviate'
2
2
 
3
3
  interface FormatThreshold {
4
4
  from: number
@@ -0,0 +1,33 @@
1
+ import { HanzoToolHeader } from '@hanzo_network/hanzo-message-ts/api/tools/types';
2
+
3
+ export const formatText = (text: string) => {
4
+ const camelToSpaces = text.replace(/([a-z])([A-Z])/g, '$1 $2');
5
+ const snakeToSpaces = camelToSpaces.replace(/_/g, ' ');
6
+ return snakeToSpaces
7
+ .split(' ')
8
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
9
+ .join(' ');
10
+ };
11
+
12
+ export const formatCamelCaseText = (text: string) => {
13
+ const words = text.split(/(?=[A-Z])/);
14
+
15
+ const formattedWords = words.map((word) => {
16
+ return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
17
+ });
18
+
19
+ const result = formattedWords.join(' ');
20
+
21
+ return result.charAt(0).toUpperCase() + result.slice(1);
22
+ };
23
+
24
+ export const getVersionFromTool = (toolRouterKey: HanzoToolHeader) => {
25
+ if (toolRouterKey.version) {
26
+ return toolRouterKey.version;
27
+ }
28
+ const parts = toolRouterKey.name.split(':::');
29
+ if (parts.length === 4) {
30
+ return parts[3];
31
+ }
32
+ return 'latest';
33
+ };
package/util/index.ts CHANGED
@@ -1,78 +1,9 @@
1
- import { compiler as mdCompiler } from 'markdown-to-jsx'
2
-
3
- import { clsx, type ClassValue } from 'clsx'
4
- import { twMerge } from 'tailwind-merge'
5
- export { cva, type VariantProps } from 'class-variance-authority'
6
-
7
- import type { Dimensions } from '../types'
8
-
9
- import { default as _merge } from 'lodash.merge'
10
-
11
- export const cn = (...inputs: ClassValue[]) => (
12
- twMerge(clsx(inputs))
13
- )
14
-
15
- export const markdown = (s: string, options?: any): JSX.Element => (
16
- mdCompiler(s, {
17
- wrapper: null,
18
- ...options
19
- })
20
- )
21
-
22
- export const round = (num: number): string => (
23
- num
24
- .toFixed(7)
25
- .replace(/(\.[0-9]+?)0+$/, '$1')
26
- .replace(/\.0$/, '')
27
- )
28
-
29
- export const pxToRem = (px: number, base: number): string => (`${round(px / base)}rem`)
30
-
31
- export const pxToEm = (px: number, base: number): string => (`${round(px / base)}em`)
32
-
33
- export const hexToRgb = (hex: string): string => {
34
- hex = hex.replace('#', '')
35
- hex = hex.length === 3 ? hex.replace(/./g, '$&$&') : hex
36
- const r = parseInt(hex.substring(0, 2), 16)
37
- const g = parseInt(hex.substring(2, 4), 16)
38
- const b = parseInt(hex.substring(4, 6), 16)
39
- return `${r} ${g} ${b}`
40
- }
41
-
42
-
43
- export const asNum = (n: number | `${number}`): number => (
44
- (typeof n === 'number') ? n : parseInt(n, 10)
45
- )
46
-
47
- // https://stackoverflow.com/questions/3971841/how-to-resize-images-proportionally-keeping-the-aspect-ratio
48
- export const constrain = (d: Dimensions, c: Dimensions): Dimensions => {
49
-
50
- const ratio = Math.min(c.w / d.w, c.h / d.h)
51
- return {
52
- w: Math.round(d.w * ratio),
53
- h: Math.round(d.h * ratio)
54
- }
55
- }
56
-
57
- export const containsToken = (s: string | undefined, toFind: string): boolean => (s ? s.split(' ').includes(toFind) : false)
58
-
59
- export const ldMerge = (
60
- result: any,
61
- ...sources: any[]
62
- ): any => (_merge(result, ...sources))
63
-
64
- export const capitalize = (str: string): string => (
65
- str.charAt(0).toUpperCase() + str.slice(1)
66
- )
67
-
68
- export { default as spreadToTransform } from './spread-to-transform'
69
- export { default as formatToMaxChar } from './format-to-max-char'
70
- export {
71
- default as formatAndAbbreviateAsCurrency,
72
- type FormatThreshold,
73
- type QuantityAbbrSymbol
74
- } from './format-and-abbreviate-as-currency'
75
-
76
- // Must be imported from 'use client', so can't include this...
77
- // export * from './step-animation'
78
-
1
+ export * from './date';
2
+ export * from './file';
3
+ export * from './create-shadow-root';
4
+ export * from './timing';
5
+ export * from './blob';
6
+ export * from './copy-to-clipboard';
7
+ export * from './format-text';
8
+ export * from './toasts';
9
+ export * from './debounce';
package/util/timing.ts ADDED
@@ -0,0 +1,3 @@
1
+ export function delay(e = 1e3) {
2
+ return new Promise((t) => setTimeout(t, e));
3
+ }
@@ -0,0 +1,17 @@
1
+ import { toast } from 'sonner';
2
+
3
+ export const submitRegistrationNoCodeNonPristineError = () => {
4
+ return toast.error(
5
+ <div>
6
+ Your Hanzo Node is currently locked by existing keys, please restore your
7
+ connection or reset your Hanzo Node Storage
8
+ </div>,
9
+ { position: 'bottom-center' },
10
+ );
11
+ };
12
+
13
+ export const submitRegistrationNoCodeError = () => {
14
+ return toast.error(<div>Error connecting to your Hanzo Node</div>, {
15
+ position: 'bottom-center',
16
+ });
17
+ };
package/utils.ts ADDED
@@ -0,0 +1,9 @@
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
+ }
7
+
8
+ // Re-export from src/utils for backward compatibility
9
+ export * from './src/utils';