@djangocfg/ui-tools 2.1.91

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 (174) hide show
  1. package/dist/LottiePlayer.client-LBEC2JKY.mjs +161 -0
  2. package/dist/LottiePlayer.client-LBEC2JKY.mjs.map +1 -0
  3. package/dist/LottiePlayer.client-WFMG2OOW.cjs +168 -0
  4. package/dist/LottiePlayer.client-WFMG2OOW.cjs.map +1 -0
  5. package/dist/Mermaid.client-4TU2TSH3.mjs +477 -0
  6. package/dist/Mermaid.client-4TU2TSH3.mjs.map +1 -0
  7. package/dist/Mermaid.client-SBYY364Q.cjs +483 -0
  8. package/dist/Mermaid.client-SBYY364Q.cjs.map +1 -0
  9. package/dist/PlaygroundLayout-3YVSAEAF.cjs +1003 -0
  10. package/dist/PlaygroundLayout-3YVSAEAF.cjs.map +1 -0
  11. package/dist/PlaygroundLayout-4DYBORAS.mjs +996 -0
  12. package/dist/PlaygroundLayout-4DYBORAS.mjs.map +1 -0
  13. package/dist/PrettyCode.client-LCBPPTIX.mjs +152 -0
  14. package/dist/PrettyCode.client-LCBPPTIX.mjs.map +1 -0
  15. package/dist/PrettyCode.client-PNPLXRH6.cjs +154 -0
  16. package/dist/PrettyCode.client-PNPLXRH6.cjs.map +1 -0
  17. package/dist/chunk-37ZI6VD4.mjs +12 -0
  18. package/dist/chunk-37ZI6VD4.mjs.map +1 -0
  19. package/dist/chunk-3HK2OE62.cjs +81 -0
  20. package/dist/chunk-3HK2OE62.cjs.map +1 -0
  21. package/dist/chunk-7DGDQVQW.cjs +591 -0
  22. package/dist/chunk-7DGDQVQW.cjs.map +1 -0
  23. package/dist/chunk-M6P2FU7L.mjs +572 -0
  24. package/dist/chunk-M6P2FU7L.mjs.map +1 -0
  25. package/dist/chunk-UQ3XI5MY.cjs +15 -0
  26. package/dist/chunk-UQ3XI5MY.cjs.map +1 -0
  27. package/dist/chunk-YFRNE2IR.mjs +79 -0
  28. package/dist/chunk-YFRNE2IR.mjs.map +1 -0
  29. package/dist/index.cjs +5042 -0
  30. package/dist/index.cjs.map +1 -0
  31. package/dist/index.d.cts +1591 -0
  32. package/dist/index.d.ts +1591 -0
  33. package/dist/index.mjs +4941 -0
  34. package/dist/index.mjs.map +1 -0
  35. package/package.json +86 -0
  36. package/src/components/markdown/MarkdownMessage.tsx +340 -0
  37. package/src/components/markdown/index.ts +5 -0
  38. package/src/index.ts +26 -0
  39. package/src/stores/index.ts +9 -0
  40. package/src/stores/mediaCache.ts +534 -0
  41. package/src/tools/AudioPlayer/README.md +206 -0
  42. package/src/tools/AudioPlayer/components/HybridAudioPlayer.tsx +216 -0
  43. package/src/tools/AudioPlayer/components/HybridSimplePlayer.tsx +280 -0
  44. package/src/tools/AudioPlayer/components/HybridWaveform.tsx +279 -0
  45. package/src/tools/AudioPlayer/components/ReactiveCover/AudioReactiveCover.tsx +149 -0
  46. package/src/tools/AudioPlayer/components/ReactiveCover/effects/GlowEffect.tsx +110 -0
  47. package/src/tools/AudioPlayer/components/ReactiveCover/effects/MeshEffect.tsx +58 -0
  48. package/src/tools/AudioPlayer/components/ReactiveCover/effects/OrbsEffect.tsx +45 -0
  49. package/src/tools/AudioPlayer/components/ReactiveCover/effects/SpotlightEffect.tsx +82 -0
  50. package/src/tools/AudioPlayer/components/ReactiveCover/effects/index.ts +8 -0
  51. package/src/tools/AudioPlayer/components/ReactiveCover/index.ts +6 -0
  52. package/src/tools/AudioPlayer/components/index.ts +22 -0
  53. package/src/tools/AudioPlayer/context/HybridAudioProvider.tsx +158 -0
  54. package/src/tools/AudioPlayer/context/index.ts +16 -0
  55. package/src/tools/AudioPlayer/effects/index.ts +412 -0
  56. package/src/tools/AudioPlayer/hooks/index.ts +35 -0
  57. package/src/tools/AudioPlayer/hooks/useHybridAudio.ts +387 -0
  58. package/src/tools/AudioPlayer/hooks/useHybridAudioAnalysis.ts +95 -0
  59. package/src/tools/AudioPlayer/hooks/useVisualization.tsx +207 -0
  60. package/src/tools/AudioPlayer/index.ts +133 -0
  61. package/src/tools/AudioPlayer/types/effects.ts +73 -0
  62. package/src/tools/AudioPlayer/types/index.ts +27 -0
  63. package/src/tools/AudioPlayer/utils/debug.ts +14 -0
  64. package/src/tools/AudioPlayer/utils/formatTime.ts +10 -0
  65. package/src/tools/AudioPlayer/utils/index.ts +6 -0
  66. package/src/tools/ImageViewer/@refactoring/00-PLAN.md +71 -0
  67. package/src/tools/ImageViewer/@refactoring/01-TYPES.md +121 -0
  68. package/src/tools/ImageViewer/@refactoring/02-UTILS.md +143 -0
  69. package/src/tools/ImageViewer/@refactoring/03-HOOKS.md +261 -0
  70. package/src/tools/ImageViewer/@refactoring/04-COMPONENTS.md +427 -0
  71. package/src/tools/ImageViewer/@refactoring/05-EXECUTION-CHECKLIST.md +126 -0
  72. package/src/tools/ImageViewer/README.md +200 -0
  73. package/src/tools/ImageViewer/components/ImageInfo.tsx +44 -0
  74. package/src/tools/ImageViewer/components/ImageToolbar.tsx +145 -0
  75. package/src/tools/ImageViewer/components/ImageViewer.tsx +241 -0
  76. package/src/tools/ImageViewer/components/index.ts +7 -0
  77. package/src/tools/ImageViewer/hooks/index.ts +9 -0
  78. package/src/tools/ImageViewer/hooks/useImageLoading.ts +204 -0
  79. package/src/tools/ImageViewer/hooks/useImageTransform.ts +101 -0
  80. package/src/tools/ImageViewer/index.ts +60 -0
  81. package/src/tools/ImageViewer/types.ts +81 -0
  82. package/src/tools/ImageViewer/utils/constants.ts +59 -0
  83. package/src/tools/ImageViewer/utils/debug.ts +14 -0
  84. package/src/tools/ImageViewer/utils/index.ts +17 -0
  85. package/src/tools/ImageViewer/utils/lqip.ts +47 -0
  86. package/src/tools/JsonForm/JsonSchemaForm.tsx +197 -0
  87. package/src/tools/JsonForm/examples/BotConfigExample.tsx +249 -0
  88. package/src/tools/JsonForm/examples/RealBotConfigExample.tsx +161 -0
  89. package/src/tools/JsonForm/index.ts +46 -0
  90. package/src/tools/JsonForm/templates/ArrayFieldItemTemplate.tsx +47 -0
  91. package/src/tools/JsonForm/templates/ArrayFieldTemplate.tsx +74 -0
  92. package/src/tools/JsonForm/templates/BaseInputTemplate.tsx +107 -0
  93. package/src/tools/JsonForm/templates/ErrorListTemplate.tsx +35 -0
  94. package/src/tools/JsonForm/templates/FieldTemplate.tsx +62 -0
  95. package/src/tools/JsonForm/templates/ObjectFieldTemplate.tsx +116 -0
  96. package/src/tools/JsonForm/templates/index.ts +12 -0
  97. package/src/tools/JsonForm/types.ts +83 -0
  98. package/src/tools/JsonForm/utils.ts +213 -0
  99. package/src/tools/JsonForm/widgets/CheckboxWidget.tsx +37 -0
  100. package/src/tools/JsonForm/widgets/ColorWidget.tsx +219 -0
  101. package/src/tools/JsonForm/widgets/NumberWidget.tsx +89 -0
  102. package/src/tools/JsonForm/widgets/SelectWidget.tsx +97 -0
  103. package/src/tools/JsonForm/widgets/SliderWidget.tsx +148 -0
  104. package/src/tools/JsonForm/widgets/SwitchWidget.tsx +35 -0
  105. package/src/tools/JsonForm/widgets/TextWidget.tsx +96 -0
  106. package/src/tools/JsonForm/widgets/index.ts +14 -0
  107. package/src/tools/JsonTree/index.tsx +243 -0
  108. package/src/tools/LottiePlayer/LottiePlayer.client.tsx +213 -0
  109. package/src/tools/LottiePlayer/index.tsx +56 -0
  110. package/src/tools/LottiePlayer/types.ts +108 -0
  111. package/src/tools/LottiePlayer/useLottie.ts +164 -0
  112. package/src/tools/Mermaid/Mermaid.client.tsx +82 -0
  113. package/src/tools/Mermaid/components/MermaidCodeViewer.tsx +95 -0
  114. package/src/tools/Mermaid/components/MermaidFullscreenModal.tsx +103 -0
  115. package/src/tools/Mermaid/hooks/index.ts +4 -0
  116. package/src/tools/Mermaid/hooks/useMermaidCleanup.ts +73 -0
  117. package/src/tools/Mermaid/hooks/useMermaidFullscreen.ts +46 -0
  118. package/src/tools/Mermaid/hooks/useMermaidRenderer.ts +226 -0
  119. package/src/tools/Mermaid/hooks/useMermaidValidation.ts +29 -0
  120. package/src/tools/Mermaid/index.tsx +44 -0
  121. package/src/tools/Mermaid/utils/mermaid-helpers.ts +33 -0
  122. package/src/tools/OpenapiViewer/components/EndpointInfo.tsx +149 -0
  123. package/src/tools/OpenapiViewer/components/EndpointsLibrary.tsx +263 -0
  124. package/src/tools/OpenapiViewer/components/PlaygroundLayout.tsx +125 -0
  125. package/src/tools/OpenapiViewer/components/PlaygroundStepper.tsx +100 -0
  126. package/src/tools/OpenapiViewer/components/RequestBuilder.tsx +157 -0
  127. package/src/tools/OpenapiViewer/components/RequestParametersForm.tsx +253 -0
  128. package/src/tools/OpenapiViewer/components/ResponseViewer.tsx +173 -0
  129. package/src/tools/OpenapiViewer/components/VersionSelector.tsx +68 -0
  130. package/src/tools/OpenapiViewer/components/index.ts +14 -0
  131. package/src/tools/OpenapiViewer/constants.ts +39 -0
  132. package/src/tools/OpenapiViewer/context/PlaygroundContext.tsx +337 -0
  133. package/src/tools/OpenapiViewer/hooks/index.ts +8 -0
  134. package/src/tools/OpenapiViewer/hooks/useMobile.ts +10 -0
  135. package/src/tools/OpenapiViewer/hooks/useOpenApiSchema.ts +199 -0
  136. package/src/tools/OpenapiViewer/index.tsx +37 -0
  137. package/src/tools/OpenapiViewer/types.ts +151 -0
  138. package/src/tools/OpenapiViewer/utils/apiKeyManager.ts +149 -0
  139. package/src/tools/OpenapiViewer/utils/formatters.ts +71 -0
  140. package/src/tools/OpenapiViewer/utils/index.ts +9 -0
  141. package/src/tools/OpenapiViewer/utils/versionManager.ts +161 -0
  142. package/src/tools/PrettyCode/PrettyCode.client.tsx +208 -0
  143. package/src/tools/PrettyCode/index.tsx +47 -0
  144. package/src/tools/VideoPlayer/@refactoring/00-PLAN.md +91 -0
  145. package/src/tools/VideoPlayer/@refactoring/01-TYPES.md +284 -0
  146. package/src/tools/VideoPlayer/@refactoring/02-UTILS.md +141 -0
  147. package/src/tools/VideoPlayer/@refactoring/03-HOOKS.md +178 -0
  148. package/src/tools/VideoPlayer/@refactoring/04-COMPONENTS.md +95 -0
  149. package/src/tools/VideoPlayer/@refactoring/05-EXECUTION-CHECKLIST.md +139 -0
  150. package/src/tools/VideoPlayer/README.md +264 -0
  151. package/src/tools/VideoPlayer/components/VideoControls.tsx +138 -0
  152. package/src/tools/VideoPlayer/components/VideoErrorFallback.tsx +172 -0
  153. package/src/tools/VideoPlayer/components/VideoPlayer.tsx +201 -0
  154. package/src/tools/VideoPlayer/components/index.ts +14 -0
  155. package/src/tools/VideoPlayer/context/VideoPlayerContext.tsx +52 -0
  156. package/src/tools/VideoPlayer/context/index.ts +8 -0
  157. package/src/tools/VideoPlayer/hooks/index.ts +12 -0
  158. package/src/tools/VideoPlayer/hooks/useVideoPlayerSettings.ts +70 -0
  159. package/src/tools/VideoPlayer/hooks/useVideoPositionCache.ts +116 -0
  160. package/src/tools/VideoPlayer/index.ts +77 -0
  161. package/src/tools/VideoPlayer/providers/NativeProvider.tsx +284 -0
  162. package/src/tools/VideoPlayer/providers/StreamProvider.tsx +505 -0
  163. package/src/tools/VideoPlayer/providers/VidstackProvider.tsx +400 -0
  164. package/src/tools/VideoPlayer/providers/index.ts +8 -0
  165. package/src/tools/VideoPlayer/types/index.ts +38 -0
  166. package/src/tools/VideoPlayer/types/player.ts +116 -0
  167. package/src/tools/VideoPlayer/types/provider.ts +93 -0
  168. package/src/tools/VideoPlayer/types/sources.ts +97 -0
  169. package/src/tools/VideoPlayer/utils/debug.ts +14 -0
  170. package/src/tools/VideoPlayer/utils/fileSource.ts +78 -0
  171. package/src/tools/VideoPlayer/utils/index.ts +12 -0
  172. package/src/tools/VideoPlayer/utils/resolvers.ts +75 -0
  173. package/src/tools/_shared.ts +29 -0
  174. package/src/tools/index.ts +172 -0
package/package.json ADDED
@@ -0,0 +1,86 @@
1
+ {
2
+ "name": "@djangocfg/ui-tools",
3
+ "version": "2.1.91",
4
+ "description": "Heavy React tools with lazy loading - for Electron, Vite, CRA, Next.js apps",
5
+ "keywords": [
6
+ "ui-tools",
7
+ "react",
8
+ "lazy-loading",
9
+ "video-player",
10
+ "audio-player",
11
+ "json-form",
12
+ "mermaid",
13
+ "code-highlight"
14
+ ],
15
+ "author": {
16
+ "name": "DjangoCFG",
17
+ "url": "https://djangocfg.com"
18
+ },
19
+ "homepage": "https://djangocfg.com",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://github.com/markolofsen/django-cfg.git",
23
+ "directory": "packages/ui-tools"
24
+ },
25
+ "license": "MIT",
26
+ "type": "module",
27
+ "main": "./dist/index.cjs",
28
+ "module": "./dist/index.mjs",
29
+ "types": "./dist/index.d.ts",
30
+ "exports": {
31
+ ".": {
32
+ "types": "./dist/index.d.ts",
33
+ "import": "./dist/index.mjs",
34
+ "require": "./dist/index.cjs"
35
+ }
36
+ },
37
+ "files": [
38
+ "dist",
39
+ "src",
40
+ "README.md",
41
+ "LICENSE"
42
+ ],
43
+ "scripts": {
44
+ "build": "tsup",
45
+ "clean": "rm -rf dist",
46
+ "dev": "tsup --watch",
47
+ "check": "tsc --noEmit"
48
+ },
49
+ "peerDependencies": {
50
+ "lucide-react": "^0.545.0",
51
+ "react": "^18.0.0 || ^19.0.0",
52
+ "react-dom": "^18.0.0 || ^19.0.0",
53
+ "tailwindcss": "^4.0.0",
54
+ "zustand": "^5.0.0",
55
+ "consola": "^3.4.2"
56
+ },
57
+ "dependencies": {
58
+ "@djangocfg/ui-core": "^2.1.91",
59
+ "@rjsf/core": "^6.1.2",
60
+ "@rjsf/utils": "^6.1.2",
61
+ "@rjsf/validator-ajv8": "^6.1.2",
62
+ "@vidstack/react": "next",
63
+ "@wavesurfer/react": "^1.0.12",
64
+ "media-icons": "next",
65
+ "mermaid": "^11.12.0",
66
+ "prism-react-renderer": "^2.4.1",
67
+ "react-json-tree": "^0.20.0",
68
+ "react-lottie-player": "^2.1.0",
69
+ "react-markdown": "10.1.0",
70
+ "react-zoom-pan-pinch": "^3.7.0",
71
+ "remark-gfm": "4.0.1",
72
+ "vidstack": "next",
73
+ "wavesurfer.js": "^7.12.1"
74
+ },
75
+ "devDependencies": {
76
+ "@djangocfg/typescript-config": "^2.1.91",
77
+ "@types/node": "^24.7.2",
78
+ "@types/react": "^19.1.0",
79
+ "@types/react-dom": "^19.1.0",
80
+ "tsup": "^8.5.0",
81
+ "typescript": "^5.9.3"
82
+ },
83
+ "publishConfig": {
84
+ "access": "public"
85
+ }
86
+ }
@@ -0,0 +1,340 @@
1
+ 'use client';
2
+
3
+ import React from 'react';
4
+ import ReactMarkdown from 'react-markdown';
5
+ import remarkGfm from 'remark-gfm';
6
+
7
+ import { CopyButton } from '@djangocfg/ui-core/components';
8
+ import { useResolvedTheme } from '@djangocfg/ui-core/hooks';
9
+
10
+ import Mermaid from '../../tools/Mermaid';
11
+ import PrettyCode from '../../tools/PrettyCode';
12
+
13
+ import type { Components } from 'react-markdown';
14
+
15
+ // Helper function to extract text content from React children
16
+ const extractTextFromChildren = (children: React.ReactNode): string => {
17
+ if (typeof children === 'string') {
18
+ return children;
19
+ }
20
+
21
+ if (typeof children === 'number') {
22
+ return String(children);
23
+ }
24
+
25
+ if (React.isValidElement(children)) {
26
+ const props = children.props as { children?: React.ReactNode };
27
+ return extractTextFromChildren(props.children);
28
+ }
29
+
30
+ if (Array.isArray(children)) {
31
+ return children.map(extractTextFromChildren).join('');
32
+ }
33
+
34
+ return '';
35
+ };
36
+
37
+ export interface MarkdownMessageProps {
38
+ /** Markdown content to render */
39
+ content: string;
40
+ /** Additional CSS classes */
41
+ className?: string;
42
+ /** Whether the message is from the user (affects styling) */
43
+ isUser?: boolean;
44
+ /** Use compact size (text-xs instead of text-sm) */
45
+ isCompact?: boolean;
46
+ }
47
+
48
+ // Code block component with copy functionality
49
+ interface CodeBlockProps {
50
+ code: string;
51
+ language: string;
52
+ isUser: boolean;
53
+ isCompact?: boolean;
54
+ }
55
+
56
+ const CodeBlock: React.FC<CodeBlockProps> = ({ code, language, isUser, isCompact = false }) => {
57
+ const theme = useResolvedTheme();
58
+
59
+ return (
60
+ <div className="relative group my-3">
61
+ {/* Copy button */}
62
+ <CopyButton
63
+ value={code}
64
+ variant="ghost"
65
+ className={`
66
+ absolute top-2 right-2 z-10 opacity-0 group-hover:opacity-100 transition-opacity
67
+ h-8 w-8
68
+ ${isUser
69
+ ? 'hover:bg-white/20 text-white'
70
+ : 'hover:bg-muted-foreground/20 text-muted-foreground hover:text-foreground'
71
+ }
72
+ `}
73
+ title="Copy code"
74
+ />
75
+
76
+ {/* Code content */}
77
+ <PrettyCode
78
+ data={code}
79
+ language={language}
80
+ className={isCompact ? 'text-xs' : 'text-sm'}
81
+ customBg={isUser ? "bg-white/10" : "bg-muted dark:bg-muted"}
82
+ mode={theme}
83
+ isCompact={isCompact}
84
+ />
85
+ </div>
86
+ );
87
+ };
88
+
89
+ // Custom components for markdown in chat
90
+ // Base size: text-sm (14px) for normal, text-xs (12px) for compact
91
+ const createMarkdownComponents = (isUser: boolean = false, isCompact: boolean = false): Components => {
92
+ // Text size classes based on compact mode
93
+ const textSize = isCompact ? 'text-xs' : 'text-sm';
94
+ const headingBase = isCompact ? 'text-sm' : 'text-base';
95
+ const headingSm = isCompact ? 'text-xs' : 'text-sm';
96
+
97
+ return {
98
+ // Headings - scaled for chat context
99
+ h1: ({ children }) => (
100
+ <h1 className={`${headingBase} font-bold mb-2 mt-3 first:mt-0`}>{children}</h1>
101
+ ),
102
+ h2: ({ children }) => (
103
+ <h2 className={`${headingSm} font-bold mb-2 mt-3 first:mt-0`}>{children}</h2>
104
+ ),
105
+ h3: ({ children }) => (
106
+ <h3 className={`${headingSm} font-semibold mb-1 mt-2 first:mt-0`}>{children}</h3>
107
+ ),
108
+ h4: ({ children }) => (
109
+ <h4 className={`${headingSm} font-semibold mb-1 mt-2 first:mt-0`}>{children}</h4>
110
+ ),
111
+ h5: ({ children }) => (
112
+ <h5 className={`${headingSm} font-medium mb-1 mt-2 first:mt-0`}>{children}</h5>
113
+ ),
114
+ h6: ({ children }) => (
115
+ <h6 className={`${headingSm} font-medium mb-1 mt-2 first:mt-0`}>{children}</h6>
116
+ ),
117
+
118
+ // Paragraphs - compact spacing for chat
119
+ p: ({ children }) => (
120
+ <p className={`${textSize} mb-2 last:mb-0 leading-relaxed break-words`}>{children}</p>
121
+ ),
122
+
123
+ // Lists - compact
124
+ ul: ({ children }) => (
125
+ <ul className={`list-disc list-inside mb-2 space-y-1 ${textSize}`}>{children}</ul>
126
+ ),
127
+ ol: ({ children }) => (
128
+ <ol className={`list-decimal list-inside mb-2 space-y-1 ${textSize}`}>{children}</ol>
129
+ ),
130
+ li: ({ children }) => (
131
+ <li className="break-words">{children}</li>
132
+ ),
133
+
134
+ // Links - appropriate for chat context
135
+ a: ({ href, children }) => (
136
+ <a
137
+ href={href}
138
+ className={`${textSize} text-primary underline hover:text-primary/80 transition-colors break-all`}
139
+ target={href?.startsWith('http') ? '_blank' : undefined}
140
+ rel={href?.startsWith('http') ? 'noopener noreferrer' : undefined}
141
+ >
142
+ {children}
143
+ </a>
144
+ ),
145
+
146
+ // Code blocks - using CodeBlock component with copy functionality
147
+ pre: ({ children }) => {
148
+ // Extract code content and language
149
+ let codeContent = '';
150
+ let language = 'plaintext';
151
+
152
+ if (React.isValidElement(children)) {
153
+ const child = children;
154
+
155
+ if (child.type === 'code' || (typeof child.type === 'function' && child.type.name === 'code')) {
156
+ const codeProps = child.props as { className?: string; children?: React.ReactNode };
157
+ const rawClassName = codeProps.className;
158
+ language = rawClassName?.replace(/language-/, '').trim() || 'plaintext';
159
+ codeContent = extractTextFromChildren(codeProps.children).trim();
160
+ } else {
161
+ codeContent = extractTextFromChildren(children).trim();
162
+ }
163
+ } else {
164
+ codeContent = extractTextFromChildren(children).trim();
165
+ }
166
+
167
+ // If still no content, show placeholder
168
+ if (!codeContent) {
169
+ return (
170
+ <div className="my-3 p-3 bg-muted rounded text-sm text-muted-foreground">
171
+ No content available
172
+ </div>
173
+ );
174
+ }
175
+
176
+ // Handle Mermaid diagrams separately
177
+ if (language === 'mermaid') {
178
+ return (
179
+ <div className="my-3 max-w-full overflow-x-auto">
180
+ <Mermaid chart={codeContent} className="max-w-[600px] mx-auto" isCompact={isCompact} />
181
+ </div>
182
+ );
183
+ }
184
+
185
+ // Try to use CodeBlock component, fallback to simple pre if it fails
186
+ try {
187
+ return <CodeBlock code={codeContent} language={language} isUser={isUser} isCompact={isCompact} />;
188
+ } catch (error) {
189
+ // Fallback to simple pre element with copy button
190
+ console.warn('CodeBlock failed, using fallback:', error);
191
+ return (
192
+ <div className="relative group my-3">
193
+ <CopyButton
194
+ value={codeContent}
195
+ variant="ghost"
196
+ className={`
197
+ absolute top-2 right-2 z-10 opacity-0 group-hover:opacity-100 transition-opacity
198
+ h-8 w-8
199
+ ${isUser
200
+ ? 'hover:bg-white/20 text-white'
201
+ : 'hover:bg-muted-foreground/20 text-muted-foreground hover:text-foreground'
202
+ }
203
+ `}
204
+ title="Copy code"
205
+ />
206
+ <pre className={`
207
+ p-3 rounded text-xs font-mono overflow-x-auto
208
+ ${isUser
209
+ ? 'bg-white/10 text-white'
210
+ : 'bg-muted text-foreground'
211
+ }
212
+ `}>
213
+ <code>{codeContent}</code>
214
+ </pre>
215
+ </div>
216
+ );
217
+ }
218
+ },
219
+
220
+ // Inline code
221
+ code: ({ children, className }) => {
222
+ // If it's inside a pre tag, let pre handle it
223
+ if (className?.includes('language-')) {
224
+ return <code className={className}>{children}</code>;
225
+ }
226
+
227
+ // Extract text content safely
228
+ const codeContent = extractTextFromChildren(children);
229
+
230
+ // Inline code styling
231
+ return (
232
+ <code className="px-1.5 py-0.5 rounded text-xs font-mono bg-muted text-foreground break-all">
233
+ {codeContent}
234
+ </code>
235
+ );
236
+ },
237
+
238
+ // Blockquotes
239
+ blockquote: ({ children }) => (
240
+ <blockquote className={`${textSize} border-l-2 border-border pl-3 my-2 italic text-muted-foreground break-words`}>
241
+ {children}
242
+ </blockquote>
243
+ ),
244
+
245
+ // Tables - compact for chat
246
+ table: ({ children }) => (
247
+ <div className="overflow-x-auto my-3">
248
+ <table className={`min-w-full ${textSize} border-collapse`}>
249
+ {children}
250
+ </table>
251
+ </div>
252
+ ),
253
+ thead: ({ children }) => (
254
+ <thead className="bg-muted/50">
255
+ {children}
256
+ </thead>
257
+ ),
258
+ tbody: ({ children }) => (
259
+ <tbody>{children}</tbody>
260
+ ),
261
+ tr: ({ children }) => (
262
+ <tr className="border-b border-border/50">{children}</tr>
263
+ ),
264
+ th: ({ children }) => (
265
+ <th className="px-2 py-1 text-left font-medium break-words">{children}</th>
266
+ ),
267
+ td: ({ children }) => (
268
+ <td className="px-2 py-1 break-words">{children}</td>
269
+ ),
270
+
271
+ // Horizontal rule
272
+ hr: () => (
273
+ <hr className="my-3 border-0 h-px bg-border" />
274
+ ),
275
+
276
+ // Strong and emphasis
277
+ strong: ({ children }) => (
278
+ <strong className="font-semibold">{children}</strong>
279
+ ),
280
+ em: ({ children }) => (
281
+ <em className="italic">{children}</em>
282
+ ),
283
+ };};
284
+
285
+ /**
286
+ * MarkdownMessage - Renders markdown content with syntax highlighting and GFM support
287
+ *
288
+ * Features:
289
+ * - GitHub Flavored Markdown (GFM) support
290
+ * - Syntax highlighted code blocks with copy button
291
+ * - Mermaid diagram rendering
292
+ * - Tables, lists, blockquotes
293
+ * - User/assistant styling modes
294
+ *
295
+ * @example
296
+ * ```tsx
297
+ * <MarkdownMessage content="# Hello\n\nThis is **bold** text." />
298
+ *
299
+ * // User message styling
300
+ * <MarkdownMessage content="Some content" isUser />
301
+ * ```
302
+ */
303
+ export const MarkdownMessage: React.FC<MarkdownMessageProps> = ({
304
+ content,
305
+ className = "",
306
+ isUser = false,
307
+ isCompact = false,
308
+ }) => {
309
+ const components = React.useMemo(() => createMarkdownComponents(isUser, isCompact), [isUser, isCompact]);
310
+
311
+ const textSizeClass = isCompact ? 'text-xs' : 'text-sm';
312
+ const proseClass = isCompact ? 'prose-xs' : 'prose-sm';
313
+
314
+ return (
315
+ <div
316
+ className={`
317
+ prose ${proseClass} max-w-none break-words overflow-hidden ${textSizeClass}
318
+ ${isUser ? 'prose-invert' : 'dark:prose-invert'}
319
+ ${className}
320
+ `}
321
+ style={{
322
+ // Inherit colors from parent - fixes issues with external CSS variables
323
+ '--tw-prose-body': 'inherit',
324
+ '--tw-prose-headings': 'inherit',
325
+ '--tw-prose-bold': 'inherit',
326
+ '--tw-prose-links': 'inherit',
327
+ color: 'inherit',
328
+ } as React.CSSProperties}
329
+ >
330
+ <ReactMarkdown
331
+ remarkPlugins={[remarkGfm]}
332
+ components={components}
333
+ >
334
+ {content}
335
+ </ReactMarkdown>
336
+ </div>
337
+ );
338
+ };
339
+
340
+ export default MarkdownMessage;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Markdown Components
3
+ */
4
+
5
+ export { MarkdownMessage, type MarkdownMessageProps } from './MarkdownMessage';
package/src/index.ts ADDED
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @djangocfg/ui-tools
3
+ *
4
+ * Heavy React tools with lazy loading (React.lazy + Suspense)
5
+ * Works in any React environment: Next.js, Vite, Wails, CRA
6
+ *
7
+ * Bundle sizes:
8
+ * - Mermaid: ~800KB (diagram rendering)
9
+ * - PrettyCode: ~500KB (code syntax highlighting)
10
+ * - JsonTree: ~100KB (JSON visualization)
11
+ * - LottiePlayer: ~200KB (Lottie animation player)
12
+ * - JsonForm: ~300KB (JSON Schema form generator)
13
+ * - OpenapiViewer: ~400KB (OpenAPI schema viewer & playground)
14
+ * - VideoPlayer: ~150KB (Professional video player with Vidstack)
15
+ * - AudioPlayer: ~200KB (Audio player with WaveSurfer.js)
16
+ * - ImageViewer: ~50KB (Image viewer with zoom/pan/rotate)
17
+ */
18
+
19
+ // Re-export everything from tools
20
+ export * from './tools';
21
+
22
+ // Re-export components (markdown, etc.)
23
+ export * from './components/markdown';
24
+
25
+ // Re-export stores
26
+ export * from './stores/mediaCache';
@@ -0,0 +1,9 @@
1
+ export {
2
+ useMediaCacheStore,
3
+ useImageCache,
4
+ useAudioCache,
5
+ useVideoCache,
6
+ useVideoPlayerSettings,
7
+ useBlobUrlCleanup,
8
+ generateContentKey,
9
+ } from './mediaCache';