@djangocfg/ui-tools 2.1.407 → 2.1.409
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.
- package/README.md +9 -10
- package/dist/file-icon/index.cjs +449 -61
- package/dist/file-icon/index.cjs.map +1 -1
- package/dist/file-icon/index.d.cts +56 -18
- package/dist/file-icon/index.d.ts +56 -18
- package/dist/file-icon/index.mjs +448 -62
- package/dist/file-icon/index.mjs.map +1 -1
- package/dist/tree/index.cjs +49 -22
- package/dist/tree/index.cjs.map +1 -1
- package/dist/tree/index.d.cts +9 -3
- package/dist/tree/index.d.ts +9 -3
- package/dist/tree/index.mjs +49 -22
- package/dist/tree/index.mjs.map +1 -1
- package/dist/{types-B_zhyAqR.d.cts → types-eEu8SeiQ.d.cts} +4 -0
- package/dist/{types-B_zhyAqR.d.ts → types-eEu8SeiQ.d.ts} +4 -0
- package/package.json +8 -13
- package/src/components/FloatingToolbar/index.tsx +37 -3
- package/src/lib/page-snapshot/__tests__/capture-integration.test.ts +85 -0
- package/src/lib/page-snapshot/__tests__/engine.test.ts +36 -0
- package/src/lib/page-snapshot/__tests__/redaction-integration.test.ts +99 -0
- package/src/lib/page-snapshot/__tests__/tokens.test.ts +17 -0
- package/src/lib/page-snapshot/capture/__tests__/budget.test.ts +49 -0
- package/src/lib/page-snapshot/capture/__tests__/chrome-filter.test.ts +47 -0
- package/src/lib/page-snapshot/capture/__tests__/fold.test.ts +66 -0
- package/src/lib/page-snapshot/capture/__tests__/scope.test.ts +74 -0
- package/src/lib/page-snapshot/capture/__tests__/walk.test.ts +129 -0
- package/src/lib/page-snapshot/capture/accessible-name.ts +73 -0
- package/src/lib/page-snapshot/capture/budget.ts +95 -0
- package/src/lib/page-snapshot/capture/chrome-filter.ts +81 -0
- package/src/lib/page-snapshot/capture/classify.ts +111 -0
- package/src/lib/page-snapshot/capture/dom-utils.ts +111 -0
- package/src/lib/page-snapshot/capture/fold.ts +96 -0
- package/src/lib/page-snapshot/capture/scope.ts +169 -0
- package/src/lib/page-snapshot/capture/walk.ts +250 -0
- package/src/lib/page-snapshot/cst/__tests__/serialize.test.ts +50 -0
- package/src/lib/page-snapshot/cst/directives.ts +47 -0
- package/src/lib/page-snapshot/cst/payload.ts +50 -0
- package/src/lib/page-snapshot/cst/serialize.ts +84 -0
- package/src/lib/page-snapshot/cst/types.ts +115 -0
- package/src/lib/page-snapshot/engine.ts +176 -0
- package/src/lib/page-snapshot/index.ts +93 -0
- package/src/lib/page-snapshot/react/PageSnapshotChip.tsx +72 -0
- package/src/lib/page-snapshot/react/PageSnapshotPreview.tsx +78 -0
- package/src/lib/page-snapshot/react/__tests__/PageSnapshotChip.test.tsx +54 -0
- package/src/lib/page-snapshot/react/__tests__/provider.test.tsx +103 -0
- package/src/lib/page-snapshot/react/__tests__/use-page-snapshot-toggle.test.tsx +62 -0
- package/src/lib/page-snapshot/react/provider.tsx +162 -0
- package/src/lib/page-snapshot/react/use-page-snapshot-toggle.ts +47 -0
- package/src/lib/page-snapshot/react/use-page-snapshot.ts +67 -0
- package/src/lib/page-snapshot/redaction/__tests__/audit.test.ts +25 -0
- package/src/lib/page-snapshot/redaction/__tests__/heuristics.test.ts +73 -0
- package/src/lib/page-snapshot/redaction/__tests__/luhn.test.ts +26 -0
- package/src/lib/page-snapshot/redaction/__tests__/patterns.test.ts +60 -0
- package/src/lib/page-snapshot/redaction/audit.ts +58 -0
- package/src/lib/page-snapshot/redaction/heuristics.ts +75 -0
- package/src/lib/page-snapshot/redaction/index.ts +75 -0
- package/src/lib/page-snapshot/redaction/luhn.ts +25 -0
- package/src/lib/page-snapshot/redaction/patterns.ts +111 -0
- package/src/lib/page-snapshot/refs/__tests__/registry.test.ts +24 -0
- package/src/lib/page-snapshot/refs/registry.ts +46 -0
- package/src/lib/page-snapshot/staleness/__tests__/hash.test.ts +34 -0
- package/src/lib/page-snapshot/staleness/hash.ts +20 -0
- package/src/lib/page-snapshot/tokens.ts +15 -0
- package/src/tools/AudioPlayer/context/PlayerProvider.tsx +13 -14
- package/src/tools/AudioPlayer/hooks/useAudioElementEvents.ts +55 -6
- package/src/tools/AudioPlayer/parts/Meta/TimeDisplay.tsx +2 -5
- package/src/tools/Chat/README.md +277 -39
- package/src/tools/Chat/composer/Composer.tsx +471 -0
- package/src/tools/Chat/composer/ComposerActionBar.tsx +65 -0
- package/src/tools/Chat/composer/ComposerBanner.tsx +128 -0
- package/src/tools/Chat/composer/ComposerButton.tsx +64 -0
- package/src/tools/Chat/composer/ComposerFooter.tsx +90 -0
- package/src/tools/Chat/composer/ComposerMenuButton.tsx +62 -0
- package/src/tools/Chat/composer/ComposerModelPicker.tsx +104 -0
- package/src/tools/Chat/composer/ComposerRichTextarea.tsx +88 -0
- package/src/tools/Chat/composer/ComposerToolPill.tsx +95 -0
- package/src/tools/Chat/composer/index.ts +45 -0
- package/src/tools/Chat/composer/size-context.tsx +26 -0
- package/src/tools/Chat/composer/types.ts +143 -0
- package/src/tools/Chat/composer/useComposerActions.tsx +164 -0
- package/src/tools/Chat/context/ChatProvider.tsx +54 -3
- package/src/tools/Chat/core/__tests__/metadata.test.ts +69 -0
- package/src/tools/Chat/core/index.ts +23 -1
- package/src/tools/Chat/core/markdown.ts +1 -1
- package/src/tools/Chat/core/metadata.ts +47 -0
- package/src/tools/Chat/core/payload-dispatch.ts +1 -1
- package/src/tools/Chat/core/transport/http.ts +71 -32
- package/src/tools/Chat/core/transport/sse.ts +18 -10
- package/src/tools/Chat/highlight/HighlightOverlay.tsx +101 -0
- package/src/tools/Chat/highlight/README.md +103 -0
- package/src/tools/Chat/highlight/SpotlightCanvas.tsx +153 -0
- package/src/tools/Chat/highlight/__tests__/HighlightOverlay.test.tsx +112 -0
- package/src/tools/Chat/highlight/__tests__/resolveRef.test.ts +55 -0
- package/src/tools/Chat/highlight/index.ts +21 -0
- package/src/tools/Chat/highlight/resolveRef.ts +42 -0
- package/src/tools/Chat/highlight/types.ts +49 -0
- package/src/tools/Chat/highlight/useHighlightTargets.ts +128 -0
- package/src/tools/Chat/hooks/index.ts +0 -5
- package/src/tools/Chat/hooks/useAutoFocusOnStreamEnd.ts +28 -47
- package/src/tools/Chat/hooks/useChat.ts +47 -14
- package/src/tools/Chat/hooks/useChatComposer.ts +2 -2
- package/src/tools/Chat/hooks/useChatLayout.ts +1 -1
- package/src/tools/Chat/hooks/useStreamEndFocus.ts +54 -0
- package/src/tools/Chat/index.ts +25 -219
- package/src/tools/Chat/launcher/ChatDock.tsx +1 -1
- package/src/tools/Chat/launcher/ChatLauncher.tsx +1 -1
- package/src/tools/Chat/launcher/{ChatHeader.tsx → header/ChatHeader.tsx} +24 -11
- package/src/tools/Chat/launcher/{ChatHeaderActionButton.tsx → header/ChatHeaderActionButton.tsx} +34 -3
- package/src/tools/Chat/launcher/{ChatHeaderLanguageButton.tsx → header/ChatHeaderLanguageButton.tsx} +2 -2
- package/src/tools/Chat/launcher/{ChatHeaderModeToggle.tsx → header/ChatHeaderModeToggle.tsx} +1 -1
- package/src/tools/Chat/launcher/{ChatHeaderResetButton.tsx → header/ChatHeaderResetButton.tsx} +2 -1
- package/src/tools/Chat/launcher/{HeaderSlots.tsx → header/HeaderSlots.tsx} +3 -3
- package/src/tools/Chat/launcher/header/index.ts +26 -0
- package/src/tools/Chat/launcher/index.ts +3 -10
- package/src/tools/Chat/lazy.tsx +38 -284
- package/src/tools/Chat/{components → messages}/MessageBubble.tsx +58 -5
- package/src/tools/Chat/{components → messages}/MessageList.tsx +8 -25
- package/src/tools/Chat/messages/blocks/MessageBlocks.tsx +131 -0
- package/src/tools/Chat/messages/blocks/builtin.tsx +91 -0
- package/src/tools/Chat/messages/blocks/index.ts +12 -0
- package/src/tools/Chat/messages/blocks/registry.tsx +42 -0
- package/src/tools/Chat/messages/blocks/renderers/AudioBlock.tsx +20 -0
- package/src/tools/Chat/messages/blocks/renderers/CodeBlock.tsx +19 -0
- package/src/tools/Chat/messages/blocks/renderers/GalleryBlock.tsx +26 -0
- package/src/tools/Chat/messages/blocks/renderers/ImageBlock.tsx +27 -0
- package/src/tools/Chat/messages/blocks/renderers/JsonBlock.tsx +12 -0
- package/src/tools/Chat/messages/blocks/renderers/LottieBlock.tsx +11 -0
- package/src/tools/Chat/messages/blocks/renderers/MapBlock.tsx +36 -0
- package/src/tools/Chat/messages/blocks/renderers/MermaidBlock.tsx +11 -0
- package/src/tools/Chat/messages/blocks/renderers/VideoBlock.tsx +24 -0
- package/src/tools/Chat/messages/blocks/renderers/types.ts +8 -0
- package/src/tools/Chat/{components → messages}/index.ts +11 -5
- package/src/tools/Chat/public.ts +212 -0
- package/src/tools/Chat/shell/ChatRoot.tsx +345 -0
- package/src/tools/Chat/{components → shell}/EmptyState.tsx +4 -2
- package/src/tools/Chat/shell/index.ts +15 -0
- package/src/tools/Chat/types/block.ts +120 -0
- package/src/tools/Chat/types/config.ts +0 -5
- package/src/tools/Chat/types/index.ts +17 -0
- package/src/tools/Chat/types/message.ts +3 -0
- package/src/tools/Chat/utils/index.ts +4 -0
- package/src/tools/CodeEditor/README.md +4 -6
- package/src/tools/CodeEditor/components/DiffEditor.tsx +48 -13
- package/src/tools/CodeEditor/components/Editor.tsx +96 -44
- package/src/tools/CodeEditor/context/EditorProvider.tsx +34 -17
- package/src/tools/CodeEditor/hooks/useEditorTheme.ts +92 -99
- package/src/tools/CodeEditor/hooks/useMonaco.ts +37 -22
- package/src/tools/CodeEditor/lazy.tsx +6 -0
- package/src/tools/CodeEditor/lib/index.ts +1 -1
- package/src/tools/CodeEditor/lib/themes.ts +3 -39
- package/src/tools/CronScheduler/CronScheduler.client.tsx +230 -61
- package/src/tools/CronScheduler/components/CustomInput.tsx +21 -4
- package/src/tools/CronScheduler/components/DayChips.tsx +13 -11
- package/src/tools/CronScheduler/components/MonthDayGrid.tsx +4 -4
- package/src/tools/CronScheduler/components/SchedulePreview.tsx +7 -3
- package/src/tools/CronScheduler/components/TimeSelector.tsx +1 -1
- package/src/tools/CronScheduler/index.tsx +1 -1
- package/src/tools/CronScheduler/types/index.ts +8 -3
- package/src/tools/CronScheduler/utils/cron-humanize.ts +61 -16
- package/src/tools/CronScheduler/utils/cron-parser.ts +13 -4
- package/src/tools/FileIcon/FileIcon.tsx +24 -39
- package/src/tools/FileIcon/get-file-icon.ts +73 -0
- package/src/tools/FileIcon/icons/icon-data.ts +399 -0
- package/src/tools/FileIcon/index.ts +4 -0
- package/src/tools/FileIcon/loader.ts +17 -35
- package/src/tools/FileIcon/specialFolders.ts +18 -0
- package/src/tools/Gallery/components/lightbox/GalleryLightbox.tsx +112 -35
- package/src/tools/Gallery/components/media/GalleryVideo.tsx +21 -2
- package/src/tools/Gallery/components/preview/GalleryCarousel.tsx +11 -1
- package/src/tools/Gallery/hooks/usePreloadImages.ts +54 -7
- package/src/tools/ImageViewer/components/ImageInfo.tsx +12 -1
- package/src/tools/ImageViewer/components/ImageToolbar.tsx +51 -43
- package/src/tools/ImageViewer/components/ImageViewer.tsx +96 -24
- package/src/tools/ImageViewer/hooks/useImageLoading.ts +13 -0
- package/src/tools/ImageViewer/utils/constants.ts +3 -0
- package/src/tools/ImageViewer/utils/index.ts +1 -0
- package/src/tools/JsonForm/JsonSchemaForm.tsx +4 -1
- package/src/tools/JsonForm/templates/ArrayFieldTemplate.tsx +5 -3
- package/src/tools/JsonForm/templates/BaseInputTemplate.tsx +7 -4
- package/src/tools/JsonForm/templates/ErrorListTemplate.tsx +3 -1
- package/src/tools/JsonForm/templates/ObjectFieldTemplate.tsx +23 -3
- package/src/tools/JsonForm/widgets/ColorWidget.tsx +20 -12
- package/src/tools/JsonForm/widgets/NumberWidget.tsx +14 -9
- package/src/tools/JsonForm/widgets/RadioWidget.tsx +78 -0
- package/src/tools/JsonForm/widgets/SelectWidget.tsx +1 -0
- package/src/tools/JsonForm/widgets/SliderWidget.tsx +7 -4
- package/src/tools/JsonForm/widgets/TextWidget.tsx +41 -17
- package/src/tools/JsonForm/widgets/index.ts +1 -0
- package/src/tools/JsonTree/components/JsonContent.tsx +115 -40
- package/src/tools/LottiePlayer/LottiePlayer.client.tsx +177 -72
- package/src/tools/LottiePlayer/index.tsx +14 -4
- package/src/tools/LottiePlayer/lazy.tsx +11 -3
- package/src/tools/LottiePlayer/types.ts +31 -1
- package/src/tools/LottiePlayer/useLottie.ts +32 -9
- package/src/tools/LottiePlayer/usePrefersReducedMotion.ts +46 -0
- package/src/tools/Map/components/LayerSwitcher.tsx +54 -21
- package/src/tools/Map/components/MapCluster.tsx +28 -21
- package/src/tools/Map/components/MapContainer.tsx +11 -4
- package/src/tools/Map/components/MapLegend.tsx +46 -15
- package/src/tools/Map/components/MapMarker.tsx +31 -2
- package/src/tools/Map/hooks/useMapEvents.ts +64 -105
- package/src/tools/MarkdownEditor/MarkdownEditor.tsx +61 -6
- package/src/tools/MarkdownEditor/MentionList.tsx +37 -4
- package/src/tools/MarkdownEditor/createMentionSuggestion.ts +11 -0
- package/src/tools/MarkdownEditor/lazy.tsx +32 -7
- package/src/tools/MarkdownEditor/styles.css +13 -0
- package/src/tools/MarkdownMessage/CodeBlock.tsx +40 -17
- package/src/tools/MarkdownMessage/MarkdownMessage.tsx +26 -6
- package/src/tools/MarkdownMessage/components.tsx +22 -9
- package/src/tools/MarkdownMessage/types.ts +24 -1
- package/src/tools/Mermaid/Mermaid.client.tsx +27 -5
- package/src/tools/Mermaid/components/MermaidErrorPanel.tsx +31 -0
- package/src/tools/Mermaid/components/MermaidFullscreenModal.tsx +14 -17
- package/src/tools/Mermaid/hooks/useMermaidRenderer.ts +264 -168
- package/src/tools/Mermaid/hooks/useMermaidValidation.ts +76 -10
- package/src/tools/Mermaid/index.tsx +6 -0
- package/src/tools/Mermaid/utils/mermaid-helpers.ts +141 -18
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/SchemaFields/FieldRow.tsx +11 -1
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/SchemaFields/buildTree.ts +49 -20
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/index.tsx +7 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/grouping.ts +7 -4
- package/src/tools/OpenapiViewer/constants.ts +3 -0
- package/src/tools/OpenapiViewer/hooks/useOpenApiSchema.ts +73 -11
- package/src/tools/OpenapiViewer/utils/schemaExport.ts +26 -6
- package/src/tools/PrettyCode/PrettyCode.client.tsx +23 -16
- package/src/tools/PrettyCode/lazy.tsx +1 -1
- package/src/tools/SpeechRecognition/README.md +1 -1
- package/src/tools/SpeechRecognition/__tests__/language.test.ts +9 -3
- package/src/tools/SpeechRecognition/components/RecordingPulse.tsx +59 -0
- package/src/tools/SpeechRecognition/components/index.ts +2 -0
- package/src/tools/SpeechRecognition/core/engine/external.ts +24 -7
- package/src/tools/SpeechRecognition/core/language.ts +23 -6
- package/src/tools/SpeechRecognition/hooks/usePushToTalk.ts +36 -5
- package/src/tools/SpeechRecognition/hooks/useSpeechRecognition.ts +18 -11
- package/src/tools/SpeechRecognition/widgets/VoiceComposerSlot.tsx +94 -26
- package/src/tools/SpeechRecognition/widgets/index.ts +1 -1
- package/src/tools/Tree/README.md +4 -8
- package/src/tools/Tree/TreeRoot.tsx +22 -10
- package/src/tools/Tree/components/TreeContent.tsx +24 -4
- package/src/tools/Tree/components/TreeLabel.tsx +8 -2
- package/src/tools/Tree/components/TreeRow.tsx +16 -6
- package/src/tools/Tree/data/flatten.ts +10 -4
- package/src/tools/Tree/types.ts +4 -0
- package/src/tools/Uploader/components/UploadAddButton.tsx +29 -6
- package/src/tools/Uploader/components/UploadDropzone.tsx +63 -7
- package/src/tools/Uploader/components/UploadPageDropOverlay.tsx +19 -5
- package/src/tools/Uploader/components/UploadPreviewItem.tsx +47 -17
- package/src/tools/Uploader/components/UploadPreviewList.tsx +24 -12
- package/src/tools/Uploader/utils/formatters.ts +8 -3
- package/src/tools/VideoPlayer/canvas/hls-canvas.tsx +1 -0
- package/src/tools/VideoPlayer/canvas/{jsx.d.ts → jsx-augmentation.ts} +12 -19
- package/src/tools/VideoPlayer/canvas/vimeo-canvas.tsx +1 -0
- package/src/tools/VideoPlayer/canvas/youtube-canvas.tsx +1 -0
- package/src/tools/VideoPlayer/parts/fullscreen.tsx +1 -1
- package/src/tools/VideoPlayer/parts/pip.tsx +1 -1
- package/src/tools/VideoPlayer/parts/playback-rate.tsx +1 -1
- package/src/tools/VideoPlayer/parts/seek-bar.tsx +2 -2
- package/src/tools/VideoPlayer/parts/volume.tsx +2 -2
- package/src/tools/index.ts +2 -1
- package/src/tools/Chat/components/AudioToggle.tsx +0 -78
- package/src/tools/Chat/components/ChatRoot.tsx +0 -305
- package/src/tools/Chat/components/Composer.tsx +0 -216
- package/src/tools/Chat/hooks/useChatScroll.ts +0 -145
- package/src/tools/Chat/types.ts +0 -9
- package/src/tools/JsonTree/components/JsonToolbar.tsx +0 -95
- package/src/tools/JsonTree/hooks/useElementCorner.ts +0 -84
- package/src/tools/JsonTree/hooks/useNavbarHeight.ts +0 -83
- package/src/tools/OpenapiViewer/components/DocsLayout/schemaFields.ts +0 -121
- package/src/tools/Tour/README.md +0 -373
- package/src/tools/Tour/components/Tour.tsx +0 -12
- package/src/tools/Tour/components/TourContent.tsx +0 -171
- package/src/tools/Tour/components/TourNavigation.tsx +0 -77
- package/src/tools/Tour/components/TourProgress.tsx +0 -88
- package/src/tools/Tour/components/TourSpotlight.tsx +0 -199
- package/src/tools/Tour/components/index.ts +0 -5
- package/src/tools/Tour/context/TourContext.ts +0 -19
- package/src/tools/Tour/context/TourProvider.tsx +0 -292
- package/src/tools/Tour/context/index.ts +0 -2
- package/src/tools/Tour/hooks/index.ts +0 -3
- package/src/tools/Tour/hooks/useKeyboardNavigation.ts +0 -59
- package/src/tools/Tour/hooks/useStepTarget.ts +0 -121
- package/src/tools/Tour/hooks/useTour.ts +0 -42
- package/src/tools/Tour/index.ts +0 -38
- package/src/tools/Tour/types/index.ts +0 -224
- package/src/tools/Tour/utils/dom.ts +0 -98
- package/src/tools/Tour/utils/index.ts +0 -3
- package/src/tools/Tour/utils/logger.ts +0 -3
- package/src/tools/Tour/utils/scrollIntoView.ts +0 -24
- /package/src/tools/Chat/{config.ts → constants.ts} +0 -0
- /package/src/tools/Chat/launcher/{ChatHeaderAudioToggle.tsx → header/ChatHeaderAudioToggle.tsx} +0 -0
- /package/src/tools/Chat/{components → messages}/Attachments.tsx +0 -0
- /package/src/tools/Chat/{components → messages}/JumpToLatest.tsx +0 -0
- /package/src/tools/Chat/{components → messages}/MessageActions.tsx +0 -0
- /package/src/tools/Chat/{components → messages}/Sources.tsx +0 -0
- /package/src/tools/Chat/{components → messages}/StreamingIndicator.tsx +0 -0
- /package/src/tools/Chat/{components → messages}/ToolCalls.tsx +0 -0
- /package/src/tools/Chat/{components → shell}/ErrorBanner.tsx +0 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message blocks — typed, serializable rich-content slots.
|
|
3
|
+
*
|
|
4
|
+
* A `ChatMessage` may carry `blocks: MessageBlock[]`. Each block is a
|
|
5
|
+
* discriminated union member keyed by `kind`. Payloads are plain JSON
|
|
6
|
+
* (no Date, no Float32Array, no React nodes) so blocks survive history
|
|
7
|
+
* persistence and SSE transport. See `@docs/message-blocks.md`.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** Spaciousness hint forwarded from the bubble to renderers. */
|
|
11
|
+
export type BlockAppearance = 'compact' | 'full';
|
|
12
|
+
|
|
13
|
+
interface BlockBase {
|
|
14
|
+
/** Stable id — used as React key and for memo diffing. */
|
|
15
|
+
id: string;
|
|
16
|
+
/** Optional caption rendered above the block. */
|
|
17
|
+
caption?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface TextBlock extends BlockBase {
|
|
21
|
+
kind: 'text';
|
|
22
|
+
text: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface MarkdownBlock extends BlockBase {
|
|
26
|
+
kind: 'markdown';
|
|
27
|
+
markdown: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface AudioBlock extends BlockBase {
|
|
31
|
+
kind: 'audio';
|
|
32
|
+
src: string;
|
|
33
|
+
title?: string;
|
|
34
|
+
artist?: string;
|
|
35
|
+
cover?: string;
|
|
36
|
+
/** `compact` → AudioPlayer variant. */
|
|
37
|
+
variant?: 'default' | 'compact';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface VideoBlock extends BlockBase {
|
|
41
|
+
kind: 'video';
|
|
42
|
+
/** Raw URL string — VideoPlayer auto-classifies YouTube/Vimeo/HLS/MP4. */
|
|
43
|
+
src: string;
|
|
44
|
+
poster?: string;
|
|
45
|
+
title?: string;
|
|
46
|
+
aspectRatio?: number | 'auto' | 'fill';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface ImageBlock extends BlockBase {
|
|
50
|
+
kind: 'image';
|
|
51
|
+
src: string;
|
|
52
|
+
alt?: string;
|
|
53
|
+
/** When true → zoom/pan ImageViewer; else a plain `<img>`. */
|
|
54
|
+
interactive?: boolean;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface GalleryBlock extends BlockBase {
|
|
58
|
+
kind: 'gallery';
|
|
59
|
+
items: Array<{ id: string; src: string; thumbnail?: string; alt?: string }>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface MapBlock extends BlockBase {
|
|
63
|
+
kind: 'map';
|
|
64
|
+
center: { lat: number; lng: number };
|
|
65
|
+
zoom?: number;
|
|
66
|
+
markers?: Array<{ id: string; lat: number; lng: number; label?: string }>;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface JsonBlock extends BlockBase {
|
|
70
|
+
kind: 'json';
|
|
71
|
+
data: unknown;
|
|
72
|
+
/** JsonTree display mode. */
|
|
73
|
+
mode?: 'full' | 'compact' | 'inline';
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface MermaidBlock extends BlockBase {
|
|
77
|
+
kind: 'mermaid';
|
|
78
|
+
chart: string;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface CodeBlock extends BlockBase {
|
|
82
|
+
kind: 'code';
|
|
83
|
+
code: string;
|
|
84
|
+
language: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface LottieBlock extends BlockBase {
|
|
88
|
+
kind: 'lottie';
|
|
89
|
+
/** Animation JSON URL or inline animationData object. */
|
|
90
|
+
src: string;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Escape hatch for host-defined block types. The built-in registry
|
|
95
|
+
* renders it as the unknown-kind fallback unless the host registers a
|
|
96
|
+
* `custom` renderer that switches on `name`.
|
|
97
|
+
*/
|
|
98
|
+
export interface CustomBlock extends BlockBase {
|
|
99
|
+
kind: 'custom';
|
|
100
|
+
/** Host-defined sub-type, dispatched by the host's own renderer. */
|
|
101
|
+
name: string;
|
|
102
|
+
payload: unknown;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export type MessageBlock =
|
|
106
|
+
| TextBlock
|
|
107
|
+
| MarkdownBlock
|
|
108
|
+
| AudioBlock
|
|
109
|
+
| VideoBlock
|
|
110
|
+
| ImageBlock
|
|
111
|
+
| GalleryBlock
|
|
112
|
+
| MapBlock
|
|
113
|
+
| JsonBlock
|
|
114
|
+
| MermaidBlock
|
|
115
|
+
| CodeBlock
|
|
116
|
+
| LottieBlock
|
|
117
|
+
| CustomBlock;
|
|
118
|
+
|
|
119
|
+
/** The discriminant literal — `'audio' | 'video' | …`. */
|
|
120
|
+
export type MessageBlockKind = MessageBlock['kind'];
|
|
@@ -29,13 +29,8 @@ export interface ChatConfig {
|
|
|
29
29
|
description?: string;
|
|
30
30
|
/** Suggested prompts shown on empty conversation. */
|
|
31
31
|
suggestions?: Array<{ label: string; prompt: string }>;
|
|
32
|
-
/** Locale forwarded to the transport via stream metadata. */
|
|
33
|
-
locale?: string;
|
|
34
32
|
/** Project / chat slug forwarded to the transport. */
|
|
35
33
|
slug?: string;
|
|
36
|
-
/** UI density. Use `prefs.density` for the same effect; this stays for
|
|
37
|
-
* backwards compatibility. */
|
|
38
|
-
density?: 'comfortable' | 'compact';
|
|
39
34
|
/** Identity of the human author. Renders avatar / name on user bubbles
|
|
40
35
|
* and gets stamped on outgoing messages as `message.sender`. */
|
|
41
36
|
user?: ChatUserContext;
|
|
@@ -19,6 +19,23 @@
|
|
|
19
19
|
export type { ChatRole, ChatPersona, ChatUserContext, ChatAssistantContext } from './persona';
|
|
20
20
|
export type { ChatToolCall } from './tool-call';
|
|
21
21
|
export type { ChatAttachment, ChatSource } from './attachment';
|
|
22
|
+
export type {
|
|
23
|
+
MessageBlock,
|
|
24
|
+
MessageBlockKind,
|
|
25
|
+
BlockAppearance,
|
|
26
|
+
TextBlock,
|
|
27
|
+
MarkdownBlock,
|
|
28
|
+
AudioBlock,
|
|
29
|
+
VideoBlock,
|
|
30
|
+
ImageBlock,
|
|
31
|
+
GalleryBlock,
|
|
32
|
+
MapBlock,
|
|
33
|
+
JsonBlock,
|
|
34
|
+
MermaidBlock,
|
|
35
|
+
CodeBlock,
|
|
36
|
+
LottieBlock,
|
|
37
|
+
CustomBlock,
|
|
38
|
+
} from './block';
|
|
22
39
|
export type { ChatMessage } from './message';
|
|
23
40
|
export { DEFAULT_LABELS } from './labels';
|
|
24
41
|
export type { ChatLabels } from './labels';
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { ChatAttachment, ChatSource } from './attachment';
|
|
9
|
+
import type { MessageBlock } from './block';
|
|
9
10
|
import type { ChatPersona, ChatRole } from './persona';
|
|
10
11
|
import type { ChatToolCall } from './tool-call';
|
|
11
12
|
|
|
@@ -26,6 +27,8 @@ export interface ChatMessage {
|
|
|
26
27
|
toolActivity?: string;
|
|
27
28
|
toolCalls?: ChatToolCall[];
|
|
28
29
|
attachments?: ChatAttachment[];
|
|
30
|
+
/** Rich tool-component blocks rendered after the message body. */
|
|
31
|
+
blocks?: MessageBlock[];
|
|
29
32
|
sources?: ChatSource[];
|
|
30
33
|
tokensIn?: number;
|
|
31
34
|
tokensOut?: number;
|
|
@@ -102,14 +102,12 @@ const {
|
|
|
102
102
|
|
|
103
103
|
## Theme
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
The editor is always dark (devtool-style), regardless of the app theme. The custom `app-dark` Monaco theme is registered automatically with colors derived from CSS variables (`--background`, `--foreground`, `--card`, `--border`).
|
|
106
106
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
Override with explicit theme:
|
|
107
|
+
Override with an explicit theme:
|
|
110
108
|
|
|
111
109
|
```tsx
|
|
112
|
-
<Editor options={{ theme: 'vs-dark' }} /> {/*
|
|
110
|
+
<Editor options={{ theme: 'vs-dark' }} /> {/* built-in dark */}
|
|
113
111
|
<Editor options={{ theme: 'hc-black' }} /> {/* high contrast */}
|
|
114
112
|
```
|
|
115
113
|
|
|
@@ -120,7 +118,7 @@ Override with explicit theme:
|
|
|
120
118
|
| `useMonaco()` | `{ monaco, isLoading, error }` | Load Monaco namespace |
|
|
121
119
|
| `useEditor()` | `{ editor, isReady, setEditor }` | Editor instance management |
|
|
122
120
|
| `useLanguage(filename)` | `string` | Detect language from file extension |
|
|
123
|
-
| `useEditorTheme(monaco, override?)` | `string` | Resolved Monaco theme name (
|
|
121
|
+
| `useEditorTheme(monaco, override?)` | `string` | Resolved Monaco theme name (always dark) |
|
|
124
122
|
|
|
125
123
|
## Types
|
|
126
124
|
|
|
@@ -4,7 +4,7 @@ import { useRef, useEffect } from 'react';
|
|
|
4
4
|
import type * as monaco from 'monaco-editor';
|
|
5
5
|
|
|
6
6
|
import { useMonaco } from '../hooks/useMonaco';
|
|
7
|
-
import { useEditorTheme } from '../hooks/useEditorTheme';
|
|
7
|
+
import { useEditorTheme, EDITOR_BACKGROUND } from '../hooks/useEditorTheme';
|
|
8
8
|
import type { DiffEditorProps } from '../types';
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -31,10 +31,10 @@ export function DiffEditor({
|
|
|
31
31
|
}: DiffEditorProps) {
|
|
32
32
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
33
33
|
const editorRef = useRef<monaco.editor.IStandaloneDiffEditor | null>(null);
|
|
34
|
-
const { monaco, isLoading } = useMonaco();
|
|
34
|
+
const { monaco, isLoading, error } = useMonaco();
|
|
35
35
|
const resolvedTheme = useEditorTheme(monaco, options.theme);
|
|
36
36
|
|
|
37
|
-
// Create diff editor
|
|
37
|
+
// Create diff editor — runs once Monaco is available.
|
|
38
38
|
useEffect(() => {
|
|
39
39
|
if (!monaco || !containerRef.current || editorRef.current) return;
|
|
40
40
|
|
|
@@ -60,24 +60,26 @@ export function DiffEditor({
|
|
|
60
60
|
editorRef.current = editor;
|
|
61
61
|
|
|
62
62
|
return () => {
|
|
63
|
+
// Dispose models before the editor so Monaco releases all references.
|
|
63
64
|
originalModel.dispose();
|
|
64
65
|
modifiedModel.dispose();
|
|
65
66
|
editor.dispose();
|
|
66
67
|
editorRef.current = null;
|
|
67
68
|
};
|
|
69
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
68
70
|
}, [monaco]);
|
|
69
71
|
|
|
70
|
-
// Update models when content changes
|
|
72
|
+
// Update models when content changes — skip no-op writes to avoid
|
|
73
|
+
// resetting scroll/decorations on unrelated re-renders.
|
|
71
74
|
useEffect(() => {
|
|
72
75
|
const editor = editorRef.current;
|
|
73
|
-
if (!editor
|
|
76
|
+
if (!editor) return;
|
|
74
77
|
|
|
75
78
|
const model = editor.getModel();
|
|
76
|
-
if (model)
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}, [original, modified, monaco]);
|
|
79
|
+
if (!model) return;
|
|
80
|
+
if (model.original.getValue() !== original) model.original.setValue(original);
|
|
81
|
+
if (model.modified.getValue() !== modified) model.modified.setValue(modified);
|
|
82
|
+
}, [original, modified]);
|
|
81
83
|
|
|
82
84
|
// Update language
|
|
83
85
|
useEffect(() => {
|
|
@@ -91,21 +93,53 @@ export function DiffEditor({
|
|
|
91
93
|
}
|
|
92
94
|
}, [language, monaco]);
|
|
93
95
|
|
|
96
|
+
// Apply theme — must go through setTheme(), updateOptions ignores `theme`.
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
if (!monaco || !editorRef.current) return;
|
|
99
|
+
monaco.editor.setTheme(resolvedTheme);
|
|
100
|
+
}, [monaco, resolvedTheme]);
|
|
101
|
+
|
|
102
|
+
if (error) {
|
|
103
|
+
return (
|
|
104
|
+
<div
|
|
105
|
+
className={className}
|
|
106
|
+
role="alert"
|
|
107
|
+
style={{
|
|
108
|
+
width: '100%',
|
|
109
|
+
height,
|
|
110
|
+
display: 'flex',
|
|
111
|
+
alignItems: 'center',
|
|
112
|
+
justifyContent: 'center',
|
|
113
|
+
padding: 16,
|
|
114
|
+
textAlign: 'center',
|
|
115
|
+
backgroundColor: EDITOR_BACKGROUND,
|
|
116
|
+
color: 'hsl(var(--destructive))',
|
|
117
|
+
fontSize: 13,
|
|
118
|
+
}}
|
|
119
|
+
>
|
|
120
|
+
Failed to load diff editor: {error.message}
|
|
121
|
+
</div>
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
94
125
|
if (isLoading) {
|
|
95
126
|
return (
|
|
96
127
|
<div
|
|
97
128
|
className={className}
|
|
129
|
+
role="status"
|
|
130
|
+
aria-busy="true"
|
|
98
131
|
style={{
|
|
99
132
|
width: '100%',
|
|
100
133
|
height,
|
|
101
134
|
display: 'flex',
|
|
102
135
|
alignItems: 'center',
|
|
103
136
|
justifyContent: 'center',
|
|
104
|
-
backgroundColor:
|
|
105
|
-
color: '
|
|
137
|
+
backgroundColor: EDITOR_BACKGROUND,
|
|
138
|
+
color: 'hsl(var(--muted-foreground))',
|
|
139
|
+
fontSize: 13,
|
|
106
140
|
}}
|
|
107
141
|
>
|
|
108
|
-
Loading diff editor
|
|
142
|
+
Loading diff editor…
|
|
109
143
|
</div>
|
|
110
144
|
);
|
|
111
145
|
}
|
|
@@ -117,6 +151,7 @@ export function DiffEditor({
|
|
|
117
151
|
style={{
|
|
118
152
|
width: '100%',
|
|
119
153
|
height,
|
|
154
|
+
backgroundColor: EDITOR_BACKGROUND,
|
|
120
155
|
}}
|
|
121
156
|
/>
|
|
122
157
|
);
|
|
@@ -4,7 +4,7 @@ import { useRef, useEffect, useState, useCallback, forwardRef, useImperativeHand
|
|
|
4
4
|
import type * as monaco from 'monaco-editor';
|
|
5
5
|
|
|
6
6
|
import { useMonaco } from '../hooks/useMonaco';
|
|
7
|
-
import { useEditorTheme } from '../hooks/useEditorTheme';
|
|
7
|
+
import { useEditorTheme, EDITOR_BACKGROUND } from '../hooks/useEditorTheme';
|
|
8
8
|
import type { EditorProps } from '../types';
|
|
9
9
|
|
|
10
10
|
export interface EditorRef {
|
|
@@ -51,7 +51,7 @@ export const Editor = forwardRef<EditorRef, EditorProps>(function Editor(
|
|
|
51
51
|
) {
|
|
52
52
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
53
53
|
const editorRef = useRef<monaco.editor.IStandaloneCodeEditor | null>(null);
|
|
54
|
-
const { monaco, isLoading } = useMonaco();
|
|
54
|
+
const { monaco, isLoading, error } = useMonaco();
|
|
55
55
|
const resolvedTheme = useEditorTheme(monaco, options.theme);
|
|
56
56
|
|
|
57
57
|
// Auto-height state
|
|
@@ -63,18 +63,24 @@ export const Editor = forwardRef<EditorRef, EditorProps>(function Editor(
|
|
|
63
63
|
setContentHeight(Math.min(Math.max(h, minHeight), maxHeight));
|
|
64
64
|
}, [autoHeight, minHeight, maxHeight]);
|
|
65
65
|
|
|
66
|
-
//
|
|
67
|
-
|
|
66
|
+
// Keep latest callbacks in refs so the create-effect can stay [monaco]-only
|
|
67
|
+
// without going stale when the parent passes new function identities.
|
|
68
|
+
const onChangeRef = useRef(onChange);
|
|
69
|
+
const onMountRef = useRef(onMount);
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
onChangeRef.current = onChange;
|
|
72
|
+
onMountRef.current = onMount;
|
|
73
|
+
});
|
|
68
74
|
|
|
69
75
|
// Expose editor methods via ref
|
|
70
76
|
useImperativeHandle(ref, () => ({
|
|
71
77
|
getEditor: () => editorRef.current,
|
|
72
|
-
getValue: () => editorRef.current?.getValue()
|
|
78
|
+
getValue: () => editorRef.current?.getValue() ?? '',
|
|
73
79
|
setValue: (val: string) => editorRef.current?.setValue(val),
|
|
74
80
|
focus: () => editorRef.current?.focus(),
|
|
75
|
-
}));
|
|
81
|
+
}), []);
|
|
76
82
|
|
|
77
|
-
// Create editor
|
|
83
|
+
// Create editor — runs once Monaco is available.
|
|
78
84
|
useEffect(() => {
|
|
79
85
|
if (!monaco || !containerRef.current || editorRef.current) return;
|
|
80
86
|
|
|
@@ -91,7 +97,7 @@ export const Editor = forwardRef<EditorRef, EditorProps>(function Editor(
|
|
|
91
97
|
lineNumbers: options.lineNumbers || 'on',
|
|
92
98
|
readOnly: options.readOnly || false,
|
|
93
99
|
automaticLayout: true,
|
|
94
|
-
scrollBeyondLastLine: autoHeight
|
|
100
|
+
scrollBeyondLastLine: !autoHeight,
|
|
95
101
|
scrollbar: autoHeight ? { vertical: 'hidden', horizontal: 'auto' } : undefined,
|
|
96
102
|
overviewRulerLanes: autoHeight ? 0 : undefined,
|
|
97
103
|
padding: { top: 16, bottom: 16 },
|
|
@@ -108,57 +114,60 @@ export const Editor = forwardRef<EditorRef, EditorProps>(function Editor(
|
|
|
108
114
|
|
|
109
115
|
editorRef.current = editor;
|
|
110
116
|
|
|
111
|
-
//
|
|
112
|
-
|
|
113
|
-
editor.
|
|
114
|
-
|
|
115
|
-
isInternalChangeRef.current = true;
|
|
116
|
-
onChange(editor.getValue());
|
|
117
|
-
});
|
|
118
|
-
}
|
|
117
|
+
// Change listener — always attached; reads latest onChange via ref.
|
|
118
|
+
const changeSub = editor.onDidChangeModelContent(() => {
|
|
119
|
+
onChangeRef.current?.(editor.getValue());
|
|
120
|
+
});
|
|
119
121
|
|
|
120
122
|
// Auto-height: resize container to fit content
|
|
123
|
+
let sizeSub: monaco.IDisposable | undefined;
|
|
121
124
|
if (autoHeight) {
|
|
122
|
-
editor.onDidContentSizeChange(() => updateContentHeight(editor));
|
|
125
|
+
sizeSub = editor.onDidContentSizeChange(() => updateContentHeight(editor));
|
|
123
126
|
updateContentHeight(editor);
|
|
124
127
|
}
|
|
125
128
|
|
|
126
129
|
// Call onMount callback
|
|
127
|
-
|
|
130
|
+
onMountRef.current?.(editor);
|
|
128
131
|
|
|
129
132
|
return () => {
|
|
133
|
+
changeSub.dispose();
|
|
134
|
+
sizeSub?.dispose();
|
|
135
|
+
// Dispose the model explicitly — editor.dispose() does not always
|
|
136
|
+
// release models in older Monaco builds, and never the ones we own.
|
|
137
|
+
editor.getModel()?.dispose();
|
|
130
138
|
editor.dispose();
|
|
131
139
|
editorRef.current = null;
|
|
132
140
|
};
|
|
141
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
133
142
|
}, [monaco]);
|
|
134
143
|
|
|
135
|
-
//
|
|
144
|
+
// Sync value when the prop changes from outside (skip echoes of user typing).
|
|
136
145
|
useEffect(() => {
|
|
137
146
|
const editor = editorRef.current;
|
|
138
147
|
if (!editor) return;
|
|
139
148
|
|
|
140
|
-
// Skip if this is an internal change (user typing) - prevents cursor reset
|
|
141
|
-
if (isInternalChangeRef.current) {
|
|
142
|
-
isInternalChangeRef.current = false;
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
149
|
const currentValue = editor.getValue();
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
150
|
+
// If the prop already matches the editor, nothing to do — this also
|
|
151
|
+
// covers the common controlled case where onChange echoes value back,
|
|
152
|
+
// so we never reset the cursor on the user's own keystrokes.
|
|
153
|
+
if (value === currentValue) return;
|
|
151
154
|
|
|
152
|
-
|
|
155
|
+
const position = editor.getPosition();
|
|
156
|
+
const selections = editor.getSelections();
|
|
153
157
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
158
|
+
// executeEdits preserves undo history (unlike setValue, which wipes it).
|
|
159
|
+
const model = editor.getModel();
|
|
160
|
+
if (model) {
|
|
161
|
+
editor.executeEdits('external-sync', [
|
|
162
|
+
{ range: model.getFullModelRange(), text: value, forceMoveMarkers: true },
|
|
163
|
+
]);
|
|
164
|
+
editor.pushUndoStop();
|
|
165
|
+
} else {
|
|
166
|
+
editor.setValue(value);
|
|
161
167
|
}
|
|
168
|
+
|
|
169
|
+
if (position) editor.setPosition(position);
|
|
170
|
+
if (selections && selections.length > 0) editor.setSelections(selections);
|
|
162
171
|
}, [value]);
|
|
163
172
|
|
|
164
173
|
// Update language when prop changes
|
|
@@ -167,41 +176,83 @@ export const Editor = forwardRef<EditorRef, EditorProps>(function Editor(
|
|
|
167
176
|
if (!editor || !monaco) return;
|
|
168
177
|
|
|
169
178
|
const model = editor.getModel();
|
|
170
|
-
if (model) {
|
|
179
|
+
if (model && model.getLanguageId() !== language) {
|
|
171
180
|
monaco.editor.setModelLanguage(model, language);
|
|
172
181
|
}
|
|
173
182
|
}, [language, monaco]);
|
|
174
183
|
|
|
184
|
+
// Apply theme — Monaco ignores `theme` inside updateOptions, it must go
|
|
185
|
+
// through setTheme(). This is what makes light/dark switching actually work.
|
|
186
|
+
useEffect(() => {
|
|
187
|
+
if (!monaco || !editorRef.current) return;
|
|
188
|
+
monaco.editor.setTheme(resolvedTheme);
|
|
189
|
+
}, [monaco, resolvedTheme]);
|
|
190
|
+
|
|
175
191
|
// Update options when props change
|
|
176
192
|
useEffect(() => {
|
|
177
193
|
const editor = editorRef.current;
|
|
178
194
|
if (!editor) return;
|
|
179
195
|
|
|
180
196
|
editor.updateOptions({
|
|
181
|
-
theme: resolvedTheme,
|
|
182
197
|
fontSize: options.fontSize,
|
|
183
198
|
readOnly: options.readOnly,
|
|
184
199
|
minimap: { enabled: options.minimap !== false },
|
|
185
200
|
wordWrap: options.wordWrap,
|
|
186
201
|
lineNumbers: options.lineNumbers,
|
|
202
|
+
tabSize: options.tabSize,
|
|
203
|
+
insertSpaces: options.insertSpaces,
|
|
187
204
|
});
|
|
188
|
-
}, [
|
|
205
|
+
}, [
|
|
206
|
+
options.fontSize,
|
|
207
|
+
options.readOnly,
|
|
208
|
+
options.minimap,
|
|
209
|
+
options.wordWrap,
|
|
210
|
+
options.lineNumbers,
|
|
211
|
+
options.tabSize,
|
|
212
|
+
options.insertSpaces,
|
|
213
|
+
]);
|
|
214
|
+
|
|
215
|
+
if (error) {
|
|
216
|
+
return (
|
|
217
|
+
<div
|
|
218
|
+
className={className}
|
|
219
|
+
role="alert"
|
|
220
|
+
style={{
|
|
221
|
+
width,
|
|
222
|
+
height,
|
|
223
|
+
display: 'flex',
|
|
224
|
+
alignItems: 'center',
|
|
225
|
+
justifyContent: 'center',
|
|
226
|
+
padding: 16,
|
|
227
|
+
textAlign: 'center',
|
|
228
|
+
backgroundColor: EDITOR_BACKGROUND,
|
|
229
|
+
color: 'hsl(var(--destructive))',
|
|
230
|
+
fontSize: 13,
|
|
231
|
+
}}
|
|
232
|
+
>
|
|
233
|
+
Failed to load editor: {error.message}
|
|
234
|
+
</div>
|
|
235
|
+
);
|
|
236
|
+
}
|
|
189
237
|
|
|
190
238
|
if (isLoading) {
|
|
191
239
|
return (
|
|
192
240
|
<div
|
|
193
241
|
className={className}
|
|
242
|
+
role="status"
|
|
243
|
+
aria-busy="true"
|
|
194
244
|
style={{
|
|
195
245
|
width,
|
|
196
246
|
height,
|
|
197
247
|
display: 'flex',
|
|
198
248
|
alignItems: 'center',
|
|
199
249
|
justifyContent: 'center',
|
|
200
|
-
backgroundColor:
|
|
201
|
-
color: '
|
|
250
|
+
backgroundColor: EDITOR_BACKGROUND,
|
|
251
|
+
color: 'hsl(var(--muted-foreground))',
|
|
252
|
+
fontSize: 13,
|
|
202
253
|
}}
|
|
203
254
|
>
|
|
204
|
-
Loading editor
|
|
255
|
+
Loading editor…
|
|
205
256
|
</div>
|
|
206
257
|
);
|
|
207
258
|
}
|
|
@@ -215,7 +266,8 @@ export const Editor = forwardRef<EditorRef, EditorProps>(function Editor(
|
|
|
215
266
|
style={{
|
|
216
267
|
width,
|
|
217
268
|
height: resolvedHeight,
|
|
218
|
-
|
|
269
|
+
backgroundColor: EDITOR_BACKGROUND,
|
|
270
|
+
...(autoHeight && { minHeight, maxHeight, overflow: 'hidden' }),
|
|
219
271
|
}}
|
|
220
272
|
/>
|
|
221
273
|
);
|
|
@@ -168,23 +168,40 @@ export function EditorProvider({ children, onSave }: EditorProviderProps) {
|
|
|
168
168
|
[openFiles]
|
|
169
169
|
);
|
|
170
170
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
171
|
+
// Memoize so consumers don't re-render on unrelated parent renders.
|
|
172
|
+
const value = useMemo<EditorContextValue>(
|
|
173
|
+
() => ({
|
|
174
|
+
openFiles,
|
|
175
|
+
activeFile,
|
|
176
|
+
monaco,
|
|
177
|
+
editor,
|
|
178
|
+
isReady: monaco !== null && editor !== null,
|
|
179
|
+
|
|
180
|
+
openFile,
|
|
181
|
+
closeFile,
|
|
182
|
+
setActiveFile,
|
|
183
|
+
updateContent,
|
|
184
|
+
saveFile,
|
|
185
|
+
|
|
186
|
+
isDirty,
|
|
187
|
+
getContent,
|
|
188
|
+
getFile,
|
|
189
|
+
}),
|
|
190
|
+
[
|
|
191
|
+
openFiles,
|
|
192
|
+
activeFile,
|
|
193
|
+
monaco,
|
|
194
|
+
editor,
|
|
195
|
+
openFile,
|
|
196
|
+
closeFile,
|
|
197
|
+
setActiveFile,
|
|
198
|
+
updateContent,
|
|
199
|
+
saveFile,
|
|
200
|
+
isDirty,
|
|
201
|
+
getContent,
|
|
202
|
+
getFile,
|
|
203
|
+
],
|
|
204
|
+
);
|
|
188
205
|
|
|
189
206
|
return (
|
|
190
207
|
<EditorContext.Provider value={value}>
|