@djangocfg/ui-tools 2.1.382 → 2.1.384

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 (89) hide show
  1. package/dist/ChatRoot-JVR3M3H2.mjs +5 -0
  2. package/dist/{ChatRoot-6IZFM5HM.mjs.map → ChatRoot-JVR3M3H2.mjs.map} +1 -1
  3. package/dist/ChatRoot-LXIUBOXF.cjs +14 -0
  4. package/dist/{ChatRoot-LW4XNIKP.cjs.map → ChatRoot-LXIUBOXF.cjs.map} +1 -1
  5. package/dist/DictationField-U25MEYAL.mjs +4 -0
  6. package/dist/{DictationField-2ZLQWLYV.mjs.map → DictationField-U25MEYAL.mjs.map} +1 -1
  7. package/dist/DictationField-XWR5VOID.cjs +13 -0
  8. package/dist/{DictationField-IPPJ54CU.cjs.map → DictationField-XWR5VOID.cjs.map} +1 -1
  9. package/dist/{chunk-KMSBGNVC.cjs → chunk-4PFW7MIJ.cjs} +4 -2
  10. package/dist/chunk-4PFW7MIJ.cjs.map +1 -0
  11. package/dist/{chunk-4LXG3NBV.mjs → chunk-C2YN6WEO.mjs} +3 -3
  12. package/dist/chunk-C2YN6WEO.mjs.map +1 -0
  13. package/dist/{chunk-OZAU3QWD.cjs → chunk-HPK3EWBF.cjs} +8 -8
  14. package/dist/chunk-HPK3EWBF.cjs.map +1 -0
  15. package/dist/{chunk-UWVP6LCW.mjs → chunk-PEKBT75W.mjs} +8 -8
  16. package/dist/chunk-PEKBT75W.mjs.map +1 -0
  17. package/dist/index.cjs +192 -55
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.cts +78 -6
  20. package/dist/index.d.ts +78 -6
  21. package/dist/index.mjs +143 -8
  22. package/dist/index.mjs.map +1 -1
  23. package/package.json +6 -13
  24. package/src/tools/Chat/core/audio/defaults.ts +16 -11
  25. package/src/tools/Chat/core/audio/sounds/error.ts +3 -0
  26. package/src/tools/Chat/core/audio/sounds/mention.ts +3 -0
  27. package/src/tools/Chat/core/audio/sounds/notification.ts +3 -0
  28. package/src/tools/Chat/core/audio/sounds/received.ts +3 -0
  29. package/src/tools/Chat/core/audio/sounds/sent.ts +3 -0
  30. package/src/tools/Chat/core/audio/sounds/start.ts +3 -0
  31. package/src/tools/Chat/index.ts +15 -0
  32. package/src/tools/SpeechRecognition/core/audio/defaults.ts +4 -4
  33. package/dist/ChatRoot-6IZFM5HM.mjs +0 -5
  34. package/dist/ChatRoot-LW4XNIKP.cjs +0 -14
  35. package/dist/DictationField-2ZLQWLYV.mjs +0 -4
  36. package/dist/DictationField-IPPJ54CU.cjs +0 -13
  37. package/dist/chunk-4LXG3NBV.mjs.map +0 -1
  38. package/dist/chunk-KMSBGNVC.cjs.map +0 -1
  39. package/dist/chunk-OZAU3QWD.cjs.map +0 -1
  40. package/dist/chunk-UWVP6LCW.mjs.map +0 -1
  41. package/src/audio-assets.d.ts +0 -8
  42. package/src/components/markdown/MarkdownMessage/MarkdownMessage.story.tsx +0 -771
  43. package/src/stories/index.ts +0 -63
  44. package/src/tools/AudioPlayer/AudioPlayer.story.tsx +0 -481
  45. package/src/tools/Chat/core/audio/sounds/error.mp3 +0 -0
  46. package/src/tools/Chat/core/audio/sounds/mention.mp3 +0 -0
  47. package/src/tools/Chat/core/audio/sounds/notification.mp3 +0 -0
  48. package/src/tools/Chat/core/audio/sounds/received.mp3 +0 -0
  49. package/src/tools/Chat/core/audio/sounds/sent.mp3 +0 -0
  50. package/src/tools/Chat/core/audio/sounds/start.mp3 +0 -0
  51. package/src/tools/Chat/stories/01-basic.story.tsx +0 -64
  52. package/src/tools/Chat/stories/02-bubbles.story.tsx +0 -21
  53. package/src/tools/Chat/stories/03-tool-calls.story.tsx +0 -59
  54. package/src/tools/Chat/stories/04-personas.story.tsx +0 -78
  55. package/src/tools/Chat/stories/05-launcher.story.tsx +0 -321
  56. package/src/tools/Chat/stories/06-header.story.tsx +0 -147
  57. package/src/tools/Chat/stories/07-audio-actions.story.tsx +0 -112
  58. package/src/tools/Chat/stories/shared/Frame.tsx +0 -21
  59. package/src/tools/Chat/stories/shared/index.ts +0 -5
  60. package/src/tools/Chat/stories/shared/messages.ts +0 -39
  61. package/src/tools/Chat/stories/shared/personas.ts +0 -13
  62. package/src/tools/Chat/stories/shared/seeds.ts +0 -92
  63. package/src/tools/Chat/stories/shared/transports.ts +0 -36
  64. package/src/tools/CodeEditor/CodeEditor.story.tsx +0 -202
  65. package/src/tools/CronScheduler/CronScheduler.story.tsx +0 -300
  66. package/src/tools/Gallery/Gallery.story.tsx +0 -237
  67. package/src/tools/ImageViewer/ImageViewer.story.tsx +0 -85
  68. package/src/tools/JsonForm/JsonForm.story.tsx +0 -350
  69. package/src/tools/JsonTree/JsonTree.story.tsx +0 -141
  70. package/src/tools/LottiePlayer/LottiePlayer.story.tsx +0 -95
  71. package/src/tools/Map/Map.story.tsx +0 -458
  72. package/src/tools/MarkdownEditor/MarkdownEditor.story.tsx +0 -225
  73. package/src/tools/Mermaid/Mermaid.story.tsx +0 -251
  74. package/src/tools/OpenapiViewer/OpenapiViewer.story.tsx +0 -230
  75. package/src/tools/PrettyCode/PrettyCode.story.tsx +0 -304
  76. package/src/tools/SpeechRecognition/stories/01-basic.story.tsx +0 -32
  77. package/src/tools/SpeechRecognition/stories/02-dictation-field.story.tsx +0 -32
  78. package/src/tools/SpeechRecognition/stories/03-push-to-talk.story.tsx +0 -27
  79. package/src/tools/SpeechRecognition/stories/04-mic-meter.story.tsx +0 -35
  80. package/src/tools/SpeechRecognition/stories/05-custom-engine-http.story.tsx +0 -40
  81. package/src/tools/SpeechRecognition/stories/06-custom-engine-ws.story.tsx +0 -48
  82. package/src/tools/SpeechRecognition/stories/07-language-device.story.tsx +0 -57
  83. package/src/tools/SpeechRecognition/stories/08-errors-permissions.story.tsx +0 -25
  84. package/src/tools/SpeechRecognition/stories/09-chat-voice.story.tsx +0 -90
  85. package/src/tools/SpeechRecognition/stories/shared.tsx +0 -123
  86. package/src/tools/Tour/Tour.story.tsx +0 -279
  87. package/src/tools/Tree/Tree.story.tsx +0 -620
  88. package/src/tools/Uploader/Uploader.story.tsx +0 -415
  89. package/src/tools/VideoPlayer/VideoPlayer.story.tsx +0 -87
@@ -1,415 +0,0 @@
1
- import { useState } from 'react';
2
- import { defineStory, useBoolean, useNumber } from '@djangocfg/playground';
3
- import { Card, CardContent, CardHeader, CardTitle } from '@djangocfg/ui-core/components';
4
- import { ImageIcon, ClipboardPaste } from 'lucide-react';
5
- import { Uploader } from './components/Uploader';
6
- import { logger } from './utils';
7
- import { UploadProvider } from './context';
8
- import { UploadDropzone } from './components/UploadDropzone';
9
- import { UploadPreviewList } from './components/UploadPreviewList';
10
- import { UploadAddButton } from './components/UploadAddButton';
11
- import { useUploadEvents } from './hooks/useUploadEvents';
12
- import { useClipboardPaste } from './hooks/useClipboardPaste';
13
- import { useUploadProvider } from './hooks/useUploadProvider';
14
- import type { UploadedAsset, AssetType } from './types';
15
-
16
- export default defineStory({
17
- title: 'Tools/Uploader',
18
- component: Uploader,
19
- description: 'Drag-drop file uploader with progress tracking and preview.',
20
- });
21
-
22
- // Mock upload endpoint that simulates server response
23
- const MOCK_DESTINATION = 'https://httpbin.org/post';
24
-
25
- export const Interactive = () => {
26
- const [compact] = useBoolean('compact', {
27
- defaultValue: false,
28
- label: 'Compact Mode',
29
- });
30
-
31
- const [showPreview] = useBoolean('showPreview', {
32
- defaultValue: true,
33
- label: 'Show Preview',
34
- });
35
-
36
- const [multiple] = useBoolean('multiple', {
37
- defaultValue: true,
38
- label: 'Multiple Files',
39
- });
40
-
41
- const [maxSizeMB] = useNumber('maxSizeMB', {
42
- defaultValue: 10,
43
- min: 1,
44
- max: 100,
45
- label: 'Max Size (MB)',
46
- });
47
-
48
- const [concurrent] = useNumber('concurrent', {
49
- defaultValue: 3,
50
- min: 1,
51
- max: 10,
52
- label: 'Concurrent Uploads',
53
- });
54
-
55
- const [uploadedFiles, setUploadedFiles] = useState<string[]>([]);
56
-
57
- return (
58
- <div className="max-w-2xl space-y-4">
59
- <Uploader
60
- destination={MOCK_DESTINATION}
61
- compact={compact}
62
- showPreview={showPreview}
63
- multiple={multiple}
64
- maxSizeMB={maxSizeMB}
65
- concurrent={concurrent}
66
- accept={['image', 'document']}
67
- onUploadComplete={(asset) => {
68
- setUploadedFiles((prev) => [...prev, asset.name]);
69
- }}
70
- />
71
-
72
- {uploadedFiles.length > 0 && (
73
- <Card>
74
- <CardHeader>
75
- <CardTitle className="text-sm">Uploaded Files</CardTitle>
76
- </CardHeader>
77
- <CardContent>
78
- <ul className="text-sm space-y-1">
79
- {uploadedFiles.map((name, i) => (
80
- <li key={i} className="text-muted-foreground">
81
- {name}
82
- </li>
83
- ))}
84
- </ul>
85
- </CardContent>
86
- </Card>
87
- )}
88
- </div>
89
- );
90
- };
91
-
92
- export const Default = () => (
93
- <div className="max-w-2xl">
94
- <Uploader
95
- destination={MOCK_DESTINATION}
96
- accept={['image', 'video', 'document']}
97
- />
98
- </div>
99
- );
100
-
101
- export const ImagesOnly = () => (
102
- <div className="max-w-2xl">
103
- <Uploader
104
- destination={MOCK_DESTINATION}
105
- accept={['image']}
106
- maxSizeMB={5}
107
- />
108
- </div>
109
- );
110
-
111
- export const Compact = () => (
112
- <div className="max-w-md">
113
- <Uploader
114
- destination={MOCK_DESTINATION}
115
- compact
116
- accept={['image', 'document']}
117
- />
118
- </div>
119
- );
120
-
121
- export const NoPreview = () => (
122
- <div className="max-w-2xl">
123
- <Uploader
124
- destination={MOCK_DESTINATION}
125
- showPreview={false}
126
- accept={['image', 'document']}
127
- />
128
- </div>
129
- );
130
-
131
- export const SingleFile = () => (
132
- <div className="max-w-2xl">
133
- <Uploader
134
- destination={MOCK_DESTINATION}
135
- multiple={false}
136
- accept={['image']}
137
- />
138
- </div>
139
- );
140
-
141
- // Custom composition example
142
- function CustomUploaderContent() {
143
- const [assets, setAssets] = useState<UploadedAsset[]>([]);
144
-
145
- useUploadEvents({
146
- onFileComplete: (asset) => {
147
- setAssets((prev) => [...prev, asset]);
148
- },
149
- onError: (error, fileName) => {
150
- logger.error(`Error uploading ${fileName}: ${error}`);
151
- },
152
- });
153
-
154
- return (
155
- <div className="grid grid-cols-2 gap-4">
156
- <div>
157
- <h3 className="text-sm font-medium mb-2">Drop Zone</h3>
158
- <UploadDropzone accept={['image']} />
159
- </div>
160
- <div>
161
- <h3 className="text-sm font-medium mb-2">Upload Queue</h3>
162
- <UploadPreviewList />
163
- </div>
164
- </div>
165
- );
166
- }
167
-
168
- export const CustomComposition = () => (
169
- <div className="max-w-3xl">
170
- <UploadProvider destination={{ url: MOCK_DESTINATION }}>
171
- <CustomUploaderContent />
172
- </UploadProvider>
173
- </div>
174
- );
175
-
176
- // With add button
177
- function WithAddButtonContent() {
178
- return (
179
- <div className="space-y-4">
180
- <div className="flex items-center gap-2">
181
- <UploadAddButton accept={['image', 'document']} />
182
- <span className="text-sm text-muted-foreground">
183
- Click to add files
184
- </span>
185
- </div>
186
- <UploadPreviewList />
187
- </div>
188
- );
189
- }
190
-
191
- export const WithAddButton = () => (
192
- <div className="max-w-2xl">
193
- <UploadProvider destination={{ url: MOCK_DESTINATION }}>
194
- <WithAddButtonContent />
195
- </UploadProvider>
196
- </div>
197
- );
198
-
199
- export const DocumentsOnly = () => (
200
- <div className="max-w-2xl">
201
- <Uploader
202
- destination={MOCK_DESTINATION}
203
- accept={['document']}
204
- maxSizeMB={20}
205
- >
206
- <div className="text-center">
207
- <p className="text-muted-foreground">Drop PDF, DOC, or XLS files</p>
208
- <p className="text-xs text-muted-foreground/60 mt-1">
209
- Max 20MB per file
210
- </p>
211
- </div>
212
- </Uploader>
213
- </div>
214
- );
215
-
216
- export const CustomContent = () => (
217
- <div className="max-w-2xl">
218
- <Uploader
219
- destination={MOCK_DESTINATION}
220
- accept={['image']}
221
- compact
222
- >
223
- <div className="flex items-center gap-2">
224
- <span className="text-2xl">+</span>
225
- <span className="text-sm">Add images</span>
226
- </div>
227
- </Uploader>
228
- </div>
229
- );
230
-
231
- // Paste to upload
232
- export const PasteToUpload = () => {
233
- const [pasteEnabled] = useBoolean('pasteEnabled', {
234
- defaultValue: true,
235
- label: 'Paste Enabled (Ctrl+V)',
236
- });
237
-
238
- return (
239
- <div className="max-w-2xl space-y-4">
240
- <Card>
241
- <CardContent className="pt-4">
242
- <p className="text-sm text-muted-foreground flex items-center gap-2">
243
- <ClipboardPaste className="h-4 w-4" />
244
- Copy an image anywhere, then press <kbd className="px-1 py-0.5 rounded bg-muted text-xs font-mono">Ctrl+V</kbd> to upload it.
245
- Supports: files, screenshots, copied images, base64 URLs, remote image URLs.
246
- </p>
247
- </CardContent>
248
- </Card>
249
- <Uploader
250
- destination={MOCK_DESTINATION}
251
- accept={['image']}
252
- pasteEnabled={pasteEnabled}
253
- onPasteNoMatch={() => logger.info('Paste: no uploadable content found')}
254
- />
255
- </div>
256
- );
257
- };
258
-
259
- // useClipboardPaste hook standalone
260
- function ClipboardPasteHookContent() {
261
- const { upload } = useUploadProvider();
262
- const [lastPaste, setLastPaste] = useState<string | null>(null);
263
-
264
- useClipboardPaste({
265
- enabled: true,
266
- acceptTypes: ['image'],
267
- onFiles: (files) => {
268
- setLastPaste(`Pasted ${files.length} file(s): ${files.map((f) => f.name).join(', ')}`);
269
- upload(files);
270
- },
271
- onNoMatch: () => setLastPaste('Paste detected but no image found in clipboard'),
272
- });
273
-
274
- return (
275
- <div className="space-y-4">
276
- <Card>
277
- <CardContent className="pt-4 space-y-2">
278
- <p className="text-sm text-muted-foreground flex items-center gap-2">
279
- <ClipboardPaste className="h-4 w-4" />
280
- Using <code className="text-xs bg-muted px-1 rounded">useClipboardPaste</code> hook directly — paste anywhere on the page.
281
- </p>
282
- {lastPaste && (
283
- <p className="text-xs font-mono bg-muted rounded p-2">{lastPaste}</p>
284
- )}
285
- </CardContent>
286
- </Card>
287
- <UploadPreviewList />
288
- </div>
289
- );
290
- }
291
-
292
- export const ClipboardPasteHook = () => (
293
- <div className="max-w-2xl">
294
- <UploadProvider destination={{ url: MOCK_DESTINATION }}>
295
- <ClipboardPasteHookContent />
296
- </UploadProvider>
297
- </div>
298
- );
299
-
300
- // Page-level drop zone
301
- function PageDropContent() {
302
- return (
303
- <div className="space-y-4">
304
- <Card>
305
- <CardHeader>
306
- <CardTitle className="text-sm">Page Drop Enabled</CardTitle>
307
- </CardHeader>
308
- <CardContent>
309
- <p className="text-sm text-muted-foreground mb-4">
310
- Drag files anywhere on the page to upload. An overlay will appear when dragging.
311
- </p>
312
- <UploadPreviewList />
313
- </CardContent>
314
- </Card>
315
- </div>
316
- );
317
- }
318
-
319
- export const PageDrop = () => (
320
- <div className="max-w-2xl">
321
- <UploadProvider
322
- destination={{ url: MOCK_DESTINATION }}
323
- pageDropEnabled
324
- pageDropProps={{
325
- accept: ['image', 'document'],
326
- maxSizeMB: 10,
327
- }}
328
- >
329
- <PageDropContent />
330
- </UploadProvider>
331
- </div>
332
- );
333
-
334
- // Page drop with custom overlay
335
- function PageDropCustomOverlayContent() {
336
- return (
337
- <div className="space-y-4">
338
- <Card>
339
- <CardHeader>
340
- <CardTitle className="text-sm">Custom Page Drop Overlay</CardTitle>
341
- </CardHeader>
342
- <CardContent>
343
- <p className="text-sm text-muted-foreground mb-4">
344
- This example uses a custom overlay design.
345
- </p>
346
- <UploadPreviewList />
347
- </CardContent>
348
- </Card>
349
- </div>
350
- );
351
- }
352
-
353
- export const PageDropCustomOverlay = () => (
354
- <div className="max-w-2xl">
355
- <UploadProvider
356
- destination={{ url: MOCK_DESTINATION }}
357
- pageDropEnabled
358
- pageDropProps={{
359
- accept: ['image'],
360
- }}
361
- pageDropOverlay={
362
- <div className="text-center p-12 bg-primary/10 rounded-2xl border-4 border-dashed border-primary">
363
- <ImageIcon className="h-16 w-16 text-primary mx-auto mb-4" />
364
- <p className="text-xl font-bold text-primary">Drop your images here!</p>
365
- </div>
366
- }
367
- >
368
- <PageDropCustomOverlayContent />
369
- </UploadProvider>
370
- </div>
371
- );
372
-
373
- // Standalone — uploadFn instead of UploadProvider (custom API hooks, no rpldy)
374
- export const StandaloneWithUploadFn = () => {
375
- const [files, setFiles] = useState<string[]>([]);
376
-
377
- return (
378
- <div className="max-w-2xl space-y-4">
379
- <Card>
380
- <CardContent className="pt-4">
381
- <p className="text-sm text-muted-foreground flex items-center gap-2">
382
- <ClipboardPaste className="h-4 w-4" />
383
- No <code className="text-xs bg-muted px-1 rounded">UploadProvider</code> needed.
384
- Pass <code className="text-xs bg-muted px-1 rounded">uploadFn</code> to handle files yourself.
385
- Drag, click, or paste (Ctrl+V).
386
- </p>
387
- </CardContent>
388
- </Card>
389
- <UploadDropzone
390
- accept={['image', 'document']}
391
- maxSizeMB={10}
392
- pasteEnabled
393
- uploadFn={(selected) => {
394
- setFiles((prev) => [...prev, ...selected.map((f) => f.name)]);
395
- logger.info('Custom uploadFn received: ' + selected.map((f) => f.name).join(', '));
396
- }}
397
- onPasteNoMatch={() => logger.info('Paste: no uploadable content found')}
398
- />
399
- {files.length > 0 && (
400
- <Card>
401
- <CardHeader>
402
- <CardTitle className="text-sm">Received by uploadFn</CardTitle>
403
- </CardHeader>
404
- <CardContent>
405
- <ul className="text-sm space-y-1">
406
- {files.map((name, i) => (
407
- <li key={i} className="text-muted-foreground">{name}</li>
408
- ))}
409
- </ul>
410
- </CardContent>
411
- </Card>
412
- )}
413
- </div>
414
- );
415
- };
@@ -1,87 +0,0 @@
1
- import { defineStory, useBoolean, useSelect } from '@djangocfg/playground';
2
- import { VideoPlayer } from './index';
3
- import type { VideoSourceUnion } from './types';
4
-
5
- export default defineStory({
6
- title: 'Tools/Video Player',
7
- component: VideoPlayer,
8
- description: 'Video player with HLS support, quality selection, and custom controls.',
9
- });
10
-
11
- const VIDEO_SOURCES: Record<string, VideoSourceUnion> = {
12
- mp4: {
13
- type: 'url',
14
- url: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4',
15
- poster: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/images/BigBuckBunny.jpg',
16
- title: 'Big Buck Bunny',
17
- },
18
- hls: {
19
- type: 'hls',
20
- url: 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8',
21
- title: 'HLS Stream',
22
- },
23
- elephants: {
24
- type: 'url',
25
- url: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4',
26
- poster: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/images/ElephantsDream.jpg',
27
- title: "Elephant's Dream",
28
- },
29
- };
30
-
31
- export const Interactive = () => {
32
- const [sourceKey] = useSelect('source', {
33
- options: ['mp4', 'hls', 'elephants'] as const,
34
- defaultValue: 'mp4',
35
- label: 'Video Source',
36
- description: 'Select video source type',
37
- });
38
-
39
- const [autoplay] = useBoolean('autoplay', {
40
- defaultValue: false,
41
- label: 'Autoplay',
42
- description: 'Auto-start video playback',
43
- });
44
-
45
- const [muted] = useBoolean('muted', {
46
- defaultValue: false,
47
- label: 'Muted',
48
- description: 'Mute video audio',
49
- });
50
-
51
- const [loop] = useBoolean('loop', {
52
- defaultValue: false,
53
- label: 'Loop',
54
- description: 'Loop video playback',
55
- });
56
-
57
- const source = VIDEO_SOURCES[sourceKey];
58
-
59
- return (
60
- <div className="max-w-3xl" key={sourceKey}>
61
- <VideoPlayer
62
- source={source}
63
- autoPlay={autoplay}
64
- muted={muted}
65
- loop={loop}
66
- />
67
- </div>
68
- );
69
- };
70
-
71
- export const MP4 = () => (
72
- <div className="max-w-3xl">
73
- <VideoPlayer source={VIDEO_SOURCES.mp4} />
74
- </div>
75
- );
76
-
77
- export const HLS = () => (
78
- <div className="max-w-3xl">
79
- <VideoPlayer source={VIDEO_SOURCES.hls} />
80
- </div>
81
- );
82
-
83
- export const WithPoster = () => (
84
- <div className="max-w-3xl">
85
- <VideoPlayer source={VIDEO_SOURCES.elephants} />
86
- </div>
87
- );