@djangocfg/ui-tools 2.1.382 → 2.1.383

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 (62) hide show
  1. package/dist/DictationField-U25MEYAL.mjs +4 -0
  2. package/dist/{DictationField-2ZLQWLYV.mjs.map → DictationField-U25MEYAL.mjs.map} +1 -1
  3. package/dist/DictationField-XWR5VOID.cjs +13 -0
  4. package/dist/{DictationField-IPPJ54CU.cjs.map → DictationField-XWR5VOID.cjs.map} +1 -1
  5. package/dist/{chunk-KMSBGNVC.cjs → chunk-4PFW7MIJ.cjs} +4 -2
  6. package/dist/chunk-4PFW7MIJ.cjs.map +1 -0
  7. package/dist/{chunk-4LXG3NBV.mjs → chunk-C2YN6WEO.mjs} +3 -3
  8. package/dist/chunk-C2YN6WEO.mjs.map +1 -0
  9. package/dist/index.cjs +139 -2
  10. package/dist/index.cjs.map +1 -1
  11. package/dist/index.d.cts +68 -1
  12. package/dist/index.d.ts +68 -1
  13. package/dist/index.mjs +141 -6
  14. package/dist/index.mjs.map +1 -1
  15. package/package.json +6 -13
  16. package/src/tools/Chat/index.ts +15 -0
  17. package/dist/DictationField-2ZLQWLYV.mjs +0 -4
  18. package/dist/DictationField-IPPJ54CU.cjs +0 -13
  19. package/dist/chunk-4LXG3NBV.mjs.map +0 -1
  20. package/dist/chunk-KMSBGNVC.cjs.map +0 -1
  21. package/src/components/markdown/MarkdownMessage/MarkdownMessage.story.tsx +0 -771
  22. package/src/stories/index.ts +0 -63
  23. package/src/tools/AudioPlayer/AudioPlayer.story.tsx +0 -481
  24. package/src/tools/Chat/stories/01-basic.story.tsx +0 -64
  25. package/src/tools/Chat/stories/02-bubbles.story.tsx +0 -21
  26. package/src/tools/Chat/stories/03-tool-calls.story.tsx +0 -59
  27. package/src/tools/Chat/stories/04-personas.story.tsx +0 -78
  28. package/src/tools/Chat/stories/05-launcher.story.tsx +0 -321
  29. package/src/tools/Chat/stories/06-header.story.tsx +0 -147
  30. package/src/tools/Chat/stories/07-audio-actions.story.tsx +0 -112
  31. package/src/tools/Chat/stories/shared/Frame.tsx +0 -21
  32. package/src/tools/Chat/stories/shared/index.ts +0 -5
  33. package/src/tools/Chat/stories/shared/messages.ts +0 -39
  34. package/src/tools/Chat/stories/shared/personas.ts +0 -13
  35. package/src/tools/Chat/stories/shared/seeds.ts +0 -92
  36. package/src/tools/Chat/stories/shared/transports.ts +0 -36
  37. package/src/tools/CodeEditor/CodeEditor.story.tsx +0 -202
  38. package/src/tools/CronScheduler/CronScheduler.story.tsx +0 -300
  39. package/src/tools/Gallery/Gallery.story.tsx +0 -237
  40. package/src/tools/ImageViewer/ImageViewer.story.tsx +0 -85
  41. package/src/tools/JsonForm/JsonForm.story.tsx +0 -350
  42. package/src/tools/JsonTree/JsonTree.story.tsx +0 -141
  43. package/src/tools/LottiePlayer/LottiePlayer.story.tsx +0 -95
  44. package/src/tools/Map/Map.story.tsx +0 -458
  45. package/src/tools/MarkdownEditor/MarkdownEditor.story.tsx +0 -225
  46. package/src/tools/Mermaid/Mermaid.story.tsx +0 -251
  47. package/src/tools/OpenapiViewer/OpenapiViewer.story.tsx +0 -230
  48. package/src/tools/PrettyCode/PrettyCode.story.tsx +0 -304
  49. package/src/tools/SpeechRecognition/stories/01-basic.story.tsx +0 -32
  50. package/src/tools/SpeechRecognition/stories/02-dictation-field.story.tsx +0 -32
  51. package/src/tools/SpeechRecognition/stories/03-push-to-talk.story.tsx +0 -27
  52. package/src/tools/SpeechRecognition/stories/04-mic-meter.story.tsx +0 -35
  53. package/src/tools/SpeechRecognition/stories/05-custom-engine-http.story.tsx +0 -40
  54. package/src/tools/SpeechRecognition/stories/06-custom-engine-ws.story.tsx +0 -48
  55. package/src/tools/SpeechRecognition/stories/07-language-device.story.tsx +0 -57
  56. package/src/tools/SpeechRecognition/stories/08-errors-permissions.story.tsx +0 -25
  57. package/src/tools/SpeechRecognition/stories/09-chat-voice.story.tsx +0 -90
  58. package/src/tools/SpeechRecognition/stories/shared.tsx +0 -123
  59. package/src/tools/Tour/Tour.story.tsx +0 -279
  60. package/src/tools/Tree/Tree.story.tsx +0 -620
  61. package/src/tools/Uploader/Uploader.story.tsx +0 -415
  62. 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
- );