@moldable-ai/ui 0.2.7 → 0.2.9
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/dist/components/app-error-boundary.d.ts +26 -0
- package/dist/components/app-error-boundary.d.ts.map +1 -0
- package/dist/components/app-error-boundary.js +87 -0
- package/dist/components/chat/chat-input.d.ts +9 -1
- package/dist/components/chat/chat-input.d.ts.map +1 -1
- package/dist/components/chat/chat-input.js +13 -4
- package/dist/components/chat/chat-message.d.ts +6 -0
- package/dist/components/chat/chat-message.d.ts.map +1 -1
- package/dist/components/chat/chat-message.js +576 -157
- package/dist/components/chat/chat-messages.d.ts +2 -1
- package/dist/components/chat/chat-messages.d.ts.map +1 -1
- package/dist/components/chat/chat-messages.js +3 -3
- package/dist/components/chat/chat-panel.d.ts +25 -3
- package/dist/components/chat/chat-panel.d.ts.map +1 -1
- package/dist/components/chat/chat-panel.js +173 -49
- package/dist/components/chat/index.d.ts +3 -3
- package/dist/components/chat/index.d.ts.map +1 -1
- package/dist/components/chat/index.js +1 -1
- package/dist/components/chat/model-selector.d.ts.map +1 -1
- package/dist/components/chat/model-selector.js +1 -1
- package/dist/components/chat/tool-handlers.d.ts.map +1 -1
- package/dist/components/chat/tool-handlers.js +89 -1
- package/dist/components/markdown.d.ts.map +1 -1
- package/dist/components/markdown.js +18 -4
- package/dist/components/rich-media-player.d.ts +8 -0
- package/dist/components/rich-media-player.d.ts.map +1 -0
- package/dist/components/rich-media-player.js +99 -0
- package/dist/components/ui/command.d.ts +2 -1
- package/dist/components/ui/command.d.ts.map +1 -1
- package/dist/components/ui/command.js +2 -2
- package/dist/components/ui/resizable.d.ts +4 -1
- package/dist/components/ui/resizable.d.ts.map +1 -1
- package/dist/components/ui/resizable.js +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/lib/commands.d.ts +8 -0
- package/dist/lib/commands.d.ts.map +1 -1
- package/dist/lib/commands.js +18 -0
- package/package.json +17 -14
- package/src/styles/index.css +25 -0
- package/dist/lib/commands.test.d.ts +0 -2
- package/dist/lib/commands.test.d.ts.map +0 -1
- package/dist/lib/commands.test.js +0 -111
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { AlertTriangle, BookOpen, Check, CheckCheck, Copy, Database, Download, FileCode, FileText, FolderOpen, Globe, Info, Package, Plus, Search, Sparkles, Terminal, Trash2, X, } from 'lucide-react';
|
|
3
|
+
import { AlertTriangle, BookOpen, Camera, Check, CheckCheck, Copy, Database, Download, FileCode, FileText, FolderOpen, Globe, Info, Package, Plus, Search, Sparkles, Terminal, Trash2, X, } from 'lucide-react';
|
|
4
4
|
import { useState } from 'react';
|
|
5
5
|
import { cn } from '../../lib/utils';
|
|
6
6
|
import { ThinkingTimelineMarker } from './thinking-timeline';
|
|
@@ -108,6 +108,94 @@ function appApiItemCount(result) {
|
|
|
108
108
|
* Default tool handlers for Moldable tools
|
|
109
109
|
*/
|
|
110
110
|
export const DEFAULT_TOOL_HANDLERS = {
|
|
111
|
+
viewImage: {
|
|
112
|
+
loadingLabel: 'Viewing image...',
|
|
113
|
+
marker: ThinkingTimelineMarker.Default,
|
|
114
|
+
inline: false,
|
|
115
|
+
renderLoading: (args) => {
|
|
116
|
+
const { imagePath } = (args ?? {});
|
|
117
|
+
return (_jsx(LoadingIndicator, { icon: Sparkles, children: imagePath
|
|
118
|
+
? `Viewing ${getFileName(imagePath)}...`
|
|
119
|
+
: 'Viewing image...' }));
|
|
120
|
+
},
|
|
121
|
+
renderOutput: (output, toolCallId) => {
|
|
122
|
+
const result = output;
|
|
123
|
+
if (!result) {
|
|
124
|
+
return (_jsx(LoadingIndicator, { icon: Sparkles, children: "Viewing image..." }, toolCallId));
|
|
125
|
+
}
|
|
126
|
+
return (_jsxs("div", { className: "bg-muted text-muted-foreground my-1 inline-flex max-w-full items-center gap-2 rounded-md px-2 py-1 text-xs", children: [_jsx(Sparkles, { className: "size-3.5 shrink-0" }), _jsx("span", { className: "min-w-0 truncate", children: result.imagePath
|
|
127
|
+
? `Viewed ${getFileName(result.imagePath)}`
|
|
128
|
+
: 'Viewed image' })] }, toolCallId));
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
generateImage: {
|
|
132
|
+
loadingLabel: 'Generating image...',
|
|
133
|
+
marker: ThinkingTimelineMarker.Default,
|
|
134
|
+
inline: true,
|
|
135
|
+
renderLoading: (args) => {
|
|
136
|
+
const { prompt, aspectRatio } = (args ?? {});
|
|
137
|
+
const ratioClass = aspectRatio === 'portrait'
|
|
138
|
+
? 'aspect-[3/4]'
|
|
139
|
+
: aspectRatio === 'story'
|
|
140
|
+
? 'aspect-[9/16]'
|
|
141
|
+
: aspectRatio === 'landscape'
|
|
142
|
+
? 'aspect-[4/3]'
|
|
143
|
+
: aspectRatio === 'widescreen'
|
|
144
|
+
? 'aspect-video'
|
|
145
|
+
: 'aspect-square';
|
|
146
|
+
return (_jsx("figure", { className: "my-2 min-w-0 max-w-2xl", children: _jsxs("div", { className: cn('border-border bg-muted relative w-full overflow-hidden rounded-lg border', ratioClass), children: [_jsx("div", { className: "from-muted via-background/45 to-muted absolute inset-0 animate-pulse bg-gradient-to-br" }), _jsx("div", { className: "bg-foreground/5 absolute inset-0" }), _jsxs("div", { className: "text-muted-foreground absolute inset-0 flex flex-col items-center justify-center gap-2 px-6 text-center", children: [_jsx(Sparkles, { className: "size-5 animate-pulse" }), _jsx("span", { className: "max-w-full truncate text-xs font-medium", children: prompt
|
|
147
|
+
? `Generating "${prompt.slice(0, 54)}${prompt.length > 54 ? '...' : ''}"`
|
|
148
|
+
: 'Generating image...' })] })] }) }));
|
|
149
|
+
},
|
|
150
|
+
renderOutput: (output, toolCallId) => {
|
|
151
|
+
const result = output;
|
|
152
|
+
if (!result) {
|
|
153
|
+
return (_jsx(LoadingIndicator, { icon: Sparkles, children: "Generating image..." }, toolCallId));
|
|
154
|
+
}
|
|
155
|
+
const parts = Array.isArray(result.value) ? result.value : [];
|
|
156
|
+
const image = parts.find((part) => (part.type === 'image-data' || part.type === 'media') &&
|
|
157
|
+
part.data &&
|
|
158
|
+
part.mediaType?.startsWith('image/'));
|
|
159
|
+
const imageSrc = result.imageUrl ??
|
|
160
|
+
(image?.data && image.mediaType
|
|
161
|
+
? `data:${image.mediaType};base64,${image.data}`
|
|
162
|
+
: undefined);
|
|
163
|
+
if (!imageSrc) {
|
|
164
|
+
return (_jsxs("div", { className: "bg-muted text-muted-foreground my-1 flex max-w-full items-start gap-2 rounded-md px-2 py-1.5 text-xs", children: [_jsx(Sparkles, { className: "mt-0.5 size-3.5 shrink-0" }), _jsx("span", { className: "min-w-0 whitespace-normal break-words leading-relaxed", children: result.imagePath
|
|
165
|
+
? `Generated image saved at ${result.imagePath}.`
|
|
166
|
+
: 'Generated image saved.' })] }, toolCallId));
|
|
167
|
+
}
|
|
168
|
+
return (_jsxs("figure", { className: "my-2 min-w-0 max-w-2xl", children: [_jsx("div", { className: "border-border bg-muted overflow-hidden rounded-lg border", children: _jsx("img", { src: imageSrc, alt: result.prompt || 'Generated image', className: "block max-h-[420px] w-full object-contain" }) }), _jsxs("figcaption", { className: "text-muted-foreground mt-1 flex min-w-0 items-center gap-1 text-xs", children: [_jsx(Sparkles, { className: "size-3 shrink-0" }), _jsx("span", { className: "truncate", children: result.imagePath
|
|
169
|
+
? `${getFileName(result.imagePath)}${result.size ? ` - ${result.size}` : ''}`
|
|
170
|
+
: result.size || 'Generated image' })] })] }, toolCallId));
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
take_screenshot: {
|
|
174
|
+
loadingLabel: 'Taking screenshot...',
|
|
175
|
+
marker: ThinkingTimelineMarker.Default,
|
|
176
|
+
inline: true,
|
|
177
|
+
renderLoading: () => (_jsx(LoadingIndicator, { icon: Camera, children: "Taking screenshot..." })),
|
|
178
|
+
renderOutput: (output, toolCallId) => {
|
|
179
|
+
const result = output;
|
|
180
|
+
if (!result) {
|
|
181
|
+
return (_jsx(LoadingIndicator, { icon: Camera, children: "Taking screenshot..." }, toolCallId));
|
|
182
|
+
}
|
|
183
|
+
if (result.type === 'error-text') {
|
|
184
|
+
return (_jsxs("div", { className: "bg-destructive/10 text-destructive my-1 flex max-w-full items-start gap-2 rounded-md px-2 py-1.5 text-xs", children: [_jsx(Camera, { className: "mt-0.5 size-3.5 shrink-0" }), _jsx("span", { className: "min-w-0 whitespace-normal break-words leading-relaxed", children: typeof result.value === 'string'
|
|
185
|
+
? result.value
|
|
186
|
+
: 'Screenshot failed' })] }, toolCallId));
|
|
187
|
+
}
|
|
188
|
+
const parts = Array.isArray(result.value) ? result.value : [];
|
|
189
|
+
const image = parts.find((part) => (part.type === 'image-data' || part.type === 'media') &&
|
|
190
|
+
part.data &&
|
|
191
|
+
part.mediaType?.startsWith('image/'));
|
|
192
|
+
const text = parts.find((part) => part.type === 'text')?.text;
|
|
193
|
+
if (!image?.data || !image.mediaType) {
|
|
194
|
+
return (_jsxs("div", { className: "bg-muted text-muted-foreground my-1 inline-flex max-w-full items-center gap-2 rounded-md px-2 py-1 text-xs", children: [_jsx(Camera, { className: "size-3.5 shrink-0" }), _jsx("span", { className: "truncate", children: text || 'Screenshot captured' }), _jsx(Check, { className: "size-3 shrink-0 text-green-600" })] }, toolCallId));
|
|
195
|
+
}
|
|
196
|
+
return (_jsxs("figure", { className: "my-2 min-w-0 max-w-2xl", children: [_jsx("div", { className: "border-border bg-muted overflow-hidden rounded-lg border", children: _jsx("img", { src: `data:${image.mediaType};base64,${image.data}`, alt: "Current app screenshot", className: "block max-h-[420px] w-full object-contain" }) }), text && (_jsxs("figcaption", { className: "text-muted-foreground mt-1 flex items-center gap-1 text-xs", children: [_jsx(Camera, { className: "size-3" }), _jsx("span", { className: "truncate", children: text })] }))] }, toolCallId));
|
|
197
|
+
},
|
|
198
|
+
},
|
|
111
199
|
listMoldableAppApi: {
|
|
112
200
|
loadingLabel: 'Listing app APIs...',
|
|
113
201
|
marker: ThinkingTimelineMarker.Default,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/components/markdown.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAyB,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/components/markdown.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAyB,MAAM,OAAO,CAAA;AAiF7C,KAAK,mBAAmB,GAAG;IACzB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAAA;IACvC,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B,CAAA;AA8TD,eAAO,MAAM,QAAQ,uFA5DlB,mBAAmB,6CAmErB,CAAA"}
|
|
@@ -4,6 +4,7 @@ import React, { memo, useState } from 'react';
|
|
|
4
4
|
import ReactMarkdown from 'react-markdown';
|
|
5
5
|
import { cn } from '../lib/utils';
|
|
6
6
|
import { CodeBlock } from './code-block';
|
|
7
|
+
import { RichMediaPlayer } from './rich-media-player';
|
|
7
8
|
import { Button } from './ui/button';
|
|
8
9
|
import { Checkbox } from './ui/checkbox';
|
|
9
10
|
import rehypeRaw from 'rehype-raw';
|
|
@@ -62,10 +63,23 @@ function processMentions(text) {
|
|
|
62
63
|
return parts.length > 0 ? parts : [text];
|
|
63
64
|
}
|
|
64
65
|
const components = {
|
|
65
|
-
img({ src, alt }) {
|
|
66
|
+
img({ src, alt, className, style, width }) {
|
|
66
67
|
if (!src || typeof src !== 'string')
|
|
67
68
|
return null;
|
|
68
|
-
|
|
69
|
+
const imageWidth = typeof width === 'number' || typeof width === 'string'
|
|
70
|
+
? width
|
|
71
|
+
: undefined;
|
|
72
|
+
return (_jsx("span", { className: "flex justify-center", children: _jsx("img", { src: src, alt: alt ?? '', className: cn('h-auto max-w-full rounded-lg', className), style: style, width: imageWidth }) }));
|
|
73
|
+
},
|
|
74
|
+
audio({ src, title }) {
|
|
75
|
+
if (!src || typeof src !== 'string')
|
|
76
|
+
return null;
|
|
77
|
+
return (_jsx(RichMediaPlayer, { kind: "audio", src: src, title: typeof title === 'string' ? title : undefined }));
|
|
78
|
+
},
|
|
79
|
+
video({ src, title }) {
|
|
80
|
+
if (!src || typeof src !== 'string')
|
|
81
|
+
return null;
|
|
82
|
+
return (_jsx(RichMediaPlayer, { kind: "video", src: src, title: typeof title === 'string' ? title : undefined }));
|
|
69
83
|
},
|
|
70
84
|
table({ children }) {
|
|
71
85
|
return (_jsx("table", { className: "border-collapse border px-3 py-1", children: children }));
|
|
@@ -142,9 +156,9 @@ const components = {
|
|
|
142
156
|
return _jsx(CodeBlock, { code: codeContent, language: language });
|
|
143
157
|
}
|
|
144
158
|
// Inline code - style nicely, remove prose backticks via before:/after:content-none
|
|
145
|
-
return (_jsx("code", { className: "bg-muted text-foreground rounded
|
|
159
|
+
return (_jsx("code", { className: "bg-muted/70 text-foreground rounded px-1 py-0.5 font-mono text-[0.92em] before:content-none after:content-none", ...props, children: children }));
|
|
146
160
|
},
|
|
147
|
-
a: ({ children, href, ...props }) => (_jsx("a", { className: "text-primary break-all font-
|
|
161
|
+
a: ({ children, href, ...props }) => (_jsx("a", { className: "text-primary break-all font-medium hover:underline", href: href ?? '#', target: "_blank", rel: "noreferrer", ...props, children: children })),
|
|
148
162
|
// Process @mentions in text and paragraph nodes
|
|
149
163
|
p: ({ children, ...props }) => {
|
|
150
164
|
const processedChildren = React.Children.map(children, (child) => {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type RichMediaPlayerProps = {
|
|
2
|
+
className?: string;
|
|
3
|
+
kind: 'audio' | 'video';
|
|
4
|
+
src: string;
|
|
5
|
+
title?: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function RichMediaPlayer({ className, kind, src, title, }: RichMediaPlayerProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
//# sourceMappingURL=rich-media-player.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rich-media-player.d.ts","sourceRoot":"","sources":["../../src/components/rich-media-player.tsx"],"names":[],"mappings":"AAaA,MAAM,MAAM,oBAAoB,GAAG;IACjC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,OAAO,GAAG,OAAO,CAAA;IACvB,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAuBD,wBAAgB,eAAe,CAAC,EAC9B,SAAS,EACT,IAAI,EACJ,GAAG,EACH,KAAK,GACN,EAAE,oBAAoB,2CAmNtB"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useCallback, useMemo, useRef, useState } from 'react';
|
|
4
|
+
import { FastForward, Pause, Play, Rewind, Volume2, VolumeX, } from 'lucide-react';
|
|
5
|
+
import { cn } from '../lib/utils';
|
|
6
|
+
const PLAYBACK_RATES = [0.75, 1, 1.25, 1.5, 2];
|
|
7
|
+
function formatTime(value) {
|
|
8
|
+
if (!Number.isFinite(value) || value < 0)
|
|
9
|
+
return '0:00';
|
|
10
|
+
const totalSeconds = Math.floor(value);
|
|
11
|
+
const hours = Math.floor(totalSeconds / 3600);
|
|
12
|
+
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
13
|
+
const seconds = totalSeconds % 60;
|
|
14
|
+
if (hours > 0) {
|
|
15
|
+
return `${hours}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
|
|
16
|
+
}
|
|
17
|
+
return `${minutes}:${String(seconds).padStart(2, '0')}`;
|
|
18
|
+
}
|
|
19
|
+
function safeDuration(duration) {
|
|
20
|
+
return Number.isFinite(duration) && duration > 0 ? duration : 0;
|
|
21
|
+
}
|
|
22
|
+
export function RichMediaPlayer({ className, kind, src, title, }) {
|
|
23
|
+
const mediaRef = useRef(null);
|
|
24
|
+
const containerRef = useRef(null);
|
|
25
|
+
const [currentTime, setCurrentTime] = useState(0);
|
|
26
|
+
const [duration, setDuration] = useState(0);
|
|
27
|
+
const [isPlaying, setIsPlaying] = useState(false);
|
|
28
|
+
const [isMuted, setIsMuted] = useState(false);
|
|
29
|
+
const [volume, setVolume] = useState(1);
|
|
30
|
+
const [playbackRate, setPlaybackRate] = useState(1);
|
|
31
|
+
const durationValue = safeDuration(duration);
|
|
32
|
+
const canSeek = durationValue > 0;
|
|
33
|
+
const isAudio = kind === 'audio';
|
|
34
|
+
const mediaTitle = useMemo(() => {
|
|
35
|
+
if (title)
|
|
36
|
+
return title;
|
|
37
|
+
try {
|
|
38
|
+
return decodeURIComponent(src.split('/').pop()?.split('?')[0] ?? src);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return src;
|
|
42
|
+
}
|
|
43
|
+
}, [src, title]);
|
|
44
|
+
const setMediaElement = useCallback((element) => {
|
|
45
|
+
mediaRef.current = element;
|
|
46
|
+
}, []);
|
|
47
|
+
const togglePlayback = () => {
|
|
48
|
+
const media = mediaRef.current;
|
|
49
|
+
if (!media)
|
|
50
|
+
return;
|
|
51
|
+
if (media.paused) {
|
|
52
|
+
void media.play();
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
media.pause();
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const seekBy = (offset) => {
|
|
59
|
+
const media = mediaRef.current;
|
|
60
|
+
if (!media)
|
|
61
|
+
return;
|
|
62
|
+
media.currentTime = Math.max(0, Math.min(durationValue, media.currentTime + offset));
|
|
63
|
+
};
|
|
64
|
+
const seekTo = (value) => {
|
|
65
|
+
const media = mediaRef.current;
|
|
66
|
+
if (!media)
|
|
67
|
+
return;
|
|
68
|
+
media.currentTime = value;
|
|
69
|
+
setCurrentTime(value);
|
|
70
|
+
};
|
|
71
|
+
const changeVolume = (value) => {
|
|
72
|
+
const media = mediaRef.current;
|
|
73
|
+
if (!media)
|
|
74
|
+
return;
|
|
75
|
+
media.volume = value;
|
|
76
|
+
media.muted = value === 0;
|
|
77
|
+
setVolume(value);
|
|
78
|
+
setIsMuted(value === 0);
|
|
79
|
+
};
|
|
80
|
+
const toggleMuted = () => {
|
|
81
|
+
const media = mediaRef.current;
|
|
82
|
+
if (!media)
|
|
83
|
+
return;
|
|
84
|
+
const nextMuted = !media.muted;
|
|
85
|
+
media.muted = nextMuted;
|
|
86
|
+
setIsMuted(nextMuted);
|
|
87
|
+
};
|
|
88
|
+
const cyclePlaybackRate = () => {
|
|
89
|
+
const media = mediaRef.current;
|
|
90
|
+
if (!media)
|
|
91
|
+
return;
|
|
92
|
+
const currentIndex = PLAYBACK_RATES.findIndex((rate) => rate === playbackRate);
|
|
93
|
+
const nextRate = PLAYBACK_RATES[(currentIndex + 1) % PLAYBACK_RATES.length] ?? 1;
|
|
94
|
+
media.playbackRate = nextRate;
|
|
95
|
+
setPlaybackRate(nextRate);
|
|
96
|
+
};
|
|
97
|
+
const controls = (_jsxs("div", { className: cn('flex flex-col gap-2 text-white', isAudio ? 'p-3' : 'bg-gradient-to-b from-transparent via-black/65 to-neutral-950 px-3 pt-10 pb-3'), children: [_jsx("input", { "aria-label": "Seek", className: "h-2 w-full cursor-pointer accent-white disabled:cursor-default disabled:opacity-50", disabled: !canSeek, max: durationValue, min: 0, onChange: (event) => seekTo(Number(event.currentTarget.value)), step: 0.1, type: "range", value: Math.min(currentTime, durationValue) }), _jsxs("div", { className: "flex h-10 items-center gap-3 px-1", children: [_jsx("button", { "aria-label": isPlaying ? 'Pause' : 'Play', className: "cursor-pointer rounded-full p-1 text-white transition-colors hover:text-primary focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white", onClick: togglePlayback, type: "button", children: isPlaying ? _jsx(Pause, { className: "size-6" }) : _jsx(Play, { className: "size-6" }) }), _jsx("button", { "aria-label": "Rewind 10 seconds", className: "cursor-pointer rounded-full p-1 text-white/85 transition-colors hover:text-white focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white", onClick: () => seekBy(-10), type: "button", children: _jsx(Rewind, { className: "size-5" }) }), _jsx("button", { "aria-label": "Forward 10 seconds", className: "cursor-pointer rounded-full p-1 text-white/85 transition-colors hover:text-white focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white", onClick: () => seekBy(10), type: "button", children: _jsx(FastForward, { className: "size-5" }) }), _jsxs("div", { className: "group/volume flex items-center gap-2", children: [_jsx("button", { "aria-label": isMuted ? 'Unmute' : 'Mute', className: "cursor-pointer rounded-full p-1 text-white/85 transition-colors hover:text-white focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white", onClick: toggleMuted, type: "button", children: isMuted || volume === 0 ? (_jsx(VolumeX, { className: "size-5" })) : (_jsx(Volume2, { className: "size-5" })) }), _jsx("input", { "aria-label": "Volume", className: "h-2 w-0 cursor-pointer accent-white opacity-0 transition-all group-hover/volume:w-20 group-hover/volume:opacity-100 focus:w-20 focus:opacity-100", max: 1, min: 0, onChange: (event) => changeVolume(Number(event.currentTarget.value)), step: 0.05, type: "range", value: isMuted ? 0 : volume })] }), _jsxs("span", { className: "ml-auto min-w-28 text-right font-mono text-xs text-white/80", children: [formatTime(currentTime), " / ", formatTime(durationValue)] }), _jsxs("button", { "aria-label": "Change playback speed", className: "cursor-pointer rounded px-2 py-1 font-mono text-xs text-white/85 transition-colors hover:text-white focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white", onClick: cyclePlaybackRate, type: "button", children: [playbackRate, "x"] })] })] }));
|
|
98
|
+
return (_jsx("div", { className: cn('not-prose overflow-hidden rounded-lg border border-black/5 bg-neutral-950 text-white shadow-sm dark:border-white/10', className), ref: containerRef, children: _jsxs("div", { className: cn('group/mediaplayer relative w-full overflow-hidden', !isAudio && 'bg-black'), children: [isAudio ? (_jsx("audio", { "aria-label": mediaTitle, onDurationChange: (event) => setDuration(event.currentTarget.duration), onEnded: () => setIsPlaying(false), onLoadedMetadata: (event) => setDuration(event.currentTarget.duration), onPause: () => setIsPlaying(false), onPlay: () => setIsPlaying(true), onTimeUpdate: (event) => setCurrentTime(event.currentTarget.currentTime), preload: "metadata", ref: setMediaElement, src: src })) : (_jsx("video", { className: "h-auto max-h-[600px] min-h-[225px] w-full bg-black object-contain", onClick: togglePlayback, onDurationChange: (event) => setDuration(event.currentTarget.duration), onEnded: () => setIsPlaying(false), onLoadedMetadata: (event) => setDuration(event.currentTarget.duration), onPause: () => setIsPlaying(false), onPlay: () => setIsPlaying(true), onTimeUpdate: (event) => setCurrentTime(event.currentTarget.currentTime), playsInline: true, preload: "metadata", ref: setMediaElement, src: src })), _jsx("div", { className: cn(isAudio ? 'bg-neutral-950' : 'absolute right-0 bottom-0 left-0 transition-transform duration-300', !isAudio && isPlaying && 'translate-y-[calc(100%-36px)] group-hover/mediaplayer:translate-y-0'), children: controls })] }) }));
|
|
99
|
+
}
|
|
@@ -2,11 +2,12 @@ import * as React from 'react';
|
|
|
2
2
|
import { Dialog } from './dialog';
|
|
3
3
|
import { Command as CommandPrimitive } from 'cmdk';
|
|
4
4
|
declare function Command({ className, ...props }: React.ComponentProps<typeof CommandPrimitive>): import("react/jsx-runtime").JSX.Element;
|
|
5
|
-
declare function CommandDialog({ title, description, children, className, showCloseButton, ...props }: React.ComponentProps<typeof Dialog> & {
|
|
5
|
+
declare function CommandDialog({ title, description, children, className, showCloseButton, filter, ...props }: React.ComponentProps<typeof Dialog> & {
|
|
6
6
|
title?: string;
|
|
7
7
|
description?: string;
|
|
8
8
|
className?: string;
|
|
9
9
|
showCloseButton?: boolean;
|
|
10
|
+
filter?: React.ComponentProps<typeof CommandPrimitive>['filter'];
|
|
10
11
|
}): import("react/jsx-runtime").JSX.Element;
|
|
11
12
|
declare function CommandInput({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Input>): import("react/jsx-runtime").JSX.Element;
|
|
12
13
|
declare function CommandList({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.List>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../../src/components/ui/command.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EACL,MAAM,EAKP,MAAM,UAAU,CAAA;AACjB,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,MAAM,CAAA;AAElD,iBAAS,OAAO,CAAC,EACf,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,gBAAgB,CAAC,2CAW/C;AAED,iBAAS,aAAa,CAAC,EACrB,KAAyB,EACzB,WAA8C,EAC9C,QAAQ,EACR,SAAS,EACT,eAAsB,EACtB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,MAAM,CAAC,GAAG;IACvC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,eAAe,CAAC,EAAE,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../../src/components/ui/command.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EACL,MAAM,EAKP,MAAM,UAAU,CAAA;AACjB,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,MAAM,CAAA;AAElD,iBAAS,OAAO,CAAC,EACf,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,gBAAgB,CAAC,2CAW/C;AAED,iBAAS,aAAa,CAAC,EACrB,KAAyB,EACzB,WAA8C,EAC9C,QAAQ,EACR,SAAS,EACT,eAAsB,EACtB,MAAM,EACN,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,MAAM,CAAC,GAAG;IACvC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,MAAM,CAAC,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,gBAAgB,CAAC,CAAC,QAAQ,CAAC,CAAA;CACjE,2CAoBA;AAED,iBAAS,YAAY,CAAC,EACpB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,gBAAgB,CAAC,KAAK,CAAC,2CAiBrD;AAED,iBAAS,WAAW,CAAC,EACnB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,gBAAgB,CAAC,IAAI,CAAC,2CAWpD;AAED,iBAAS,YAAY,CAAC,EACpB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,gBAAgB,CAAC,KAAK,CAAC,2CAQrD;AAED,iBAAS,YAAY,CAAC,EACpB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,gBAAgB,CAAC,KAAK,CAAC,2CAWrD;AAED,iBAAS,gBAAgB,CAAC,EACxB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,gBAAgB,CAAC,SAAS,CAAC,2CAQzD;AAED,iBAAS,WAAW,CAAC,EACnB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,gBAAgB,CAAC,IAAI,CAAC,2CAWpD;AAED,iBAAS,eAAe,CAAC,EACvB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,2CAW9B;AAED,OAAO,EACL,OAAO,EACP,aAAa,EACb,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,eAAe,EACf,gBAAgB,GACjB,CAAA"}
|
|
@@ -7,8 +7,8 @@ import { Command as CommandPrimitive } from 'cmdk';
|
|
|
7
7
|
function Command({ className, ...props }) {
|
|
8
8
|
return (_jsx(CommandPrimitive, { "data-slot": "command", className: cn('bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md', className), ...props }));
|
|
9
9
|
}
|
|
10
|
-
function CommandDialog({ title = 'Command Palette', description = 'Search for a command to run...', children, className, showCloseButton = true, ...props }) {
|
|
11
|
-
return (_jsxs(Dialog, { ...props, children: [_jsxs(DialogHeader, { className: "sr-only", children: [_jsx(DialogTitle, { children: title }), _jsx(DialogDescription, { children: description })] }), _jsx(DialogContent, { className: cn('overflow-hidden p-0', className), showCloseButton: showCloseButton, children: _jsx(Command, { className: "[&_[cmdk-group-heading]]:text-muted-foreground **:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5", children: children }) })] }));
|
|
10
|
+
function CommandDialog({ title = 'Command Palette', description = 'Search for a command to run...', children, className, showCloseButton = true, filter, ...props }) {
|
|
11
|
+
return (_jsxs(Dialog, { ...props, children: [_jsxs(DialogHeader, { className: "sr-only", children: [_jsx(DialogTitle, { children: title }), _jsx(DialogDescription, { children: description })] }), _jsx(DialogContent, { className: cn('overflow-hidden p-0', className), showCloseButton: showCloseButton, children: _jsx(Command, { filter: filter, className: "[&_[cmdk-group-heading]]:text-muted-foreground **:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5", children: children }) })] }));
|
|
12
12
|
}
|
|
13
13
|
function CommandInput({ className, ...props }) {
|
|
14
14
|
return (_jsxs("div", { "data-slot": "command-input-wrapper", className: "flex h-9 items-center gap-2 border-b px-3", children: [_jsx(SearchIcon, { className: "size-4 shrink-0 opacity-50" }), _jsx(CommandPrimitive.Input, { "data-slot": "command-input", className: cn('placeholder:text-muted-foreground outline-hidden flex h-10 w-full rounded-md bg-transparent py-3 text-sm disabled:cursor-not-allowed disabled:opacity-50', className), ...props })] }));
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { type GroupProps, type PanelProps, type SeparatorProps } from 'react-resizable-panels';
|
|
2
2
|
declare function ResizablePanelGroup({ className, ...props }: GroupProps): import("react/jsx-runtime").JSX.Element;
|
|
3
|
-
|
|
3
|
+
type ResizablePanelProps = PanelProps & {
|
|
4
|
+
groupResizeBehavior?: string;
|
|
5
|
+
};
|
|
6
|
+
declare function ResizablePanel({ groupResizeBehavior: _groupResizeBehavior, ...props }: ResizablePanelProps): import("react/jsx-runtime").JSX.Element;
|
|
4
7
|
declare function ResizableHandle({ withHandle, className, ...props }: SeparatorProps & {
|
|
5
8
|
withHandle?: boolean;
|
|
6
9
|
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resizable.d.ts","sourceRoot":"","sources":["../../../src/components/ui/resizable.tsx"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,UAAU,EAEf,KAAK,UAAU,EAEf,KAAK,cAAc,EACpB,MAAM,wBAAwB,CAAA;AAG/B,iBAAS,mBAAmB,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,UAAU,2CAW/D;AAED,iBAAS,cAAc,CAAC,EAAE,GAAG,KAAK,
|
|
1
|
+
{"version":3,"file":"resizable.d.ts","sourceRoot":"","sources":["../../../src/components/ui/resizable.tsx"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,UAAU,EAEf,KAAK,UAAU,EAEf,KAAK,cAAc,EACpB,MAAM,wBAAwB,CAAA;AAG/B,iBAAS,mBAAmB,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,UAAU,2CAW/D;AAED,KAAK,mBAAmB,GAAG,UAAU,GAAG;IACtC,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B,CAAA;AAED,iBAAS,cAAc,CAAC,EACtB,mBAAmB,EAAE,oBAAoB,EACzC,GAAG,KAAK,EACT,EAAE,mBAAmB,2CAErB;AAED,iBAAS,eAAe,CAAC,EACvB,UAAU,EACV,SAAS,EACT,GAAG,KAAK,EACT,EAAE,cAAc,GAAG;IAClB,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB,2CAiBA;AAED,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,eAAe,EAAE,CAAA"}
|
|
@@ -6,7 +6,7 @@ import { cn } from '../../lib/utils';
|
|
|
6
6
|
function ResizablePanelGroup({ className, ...props }) {
|
|
7
7
|
return (_jsx(Group, { "data-slot": "resizable-panel-group", className: cn('flex h-full w-full data-[panel-group-direction=vertical]:flex-col', className), ...props }));
|
|
8
8
|
}
|
|
9
|
-
function ResizablePanel({ ...props }) {
|
|
9
|
+
function ResizablePanel({ groupResizeBehavior: _groupResizeBehavior, ...props }) {
|
|
10
10
|
return _jsx(Panel, { "data-slot": "resizable-panel", ...props });
|
|
11
11
|
}
|
|
12
12
|
function ResizableHandle({ withHandle, className, ...props }) {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
export { cn } from './lib/utils';
|
|
2
2
|
export { ThemeProvider, useTheme, themeScript, type Theme } from './lib/theme';
|
|
3
3
|
export { WorkspaceProvider, useWorkspace, WORKSPACE_HEADER, } from './lib/workspace';
|
|
4
|
-
export { useMoldableCommands, useMoldableCommand, isInMoldable, sendToMoldable, downloadFile, type AppCommand, type CommandAction, type CommandsResponse, type CommandMessage, type DownloadFileOptions, } from './lib/commands';
|
|
4
|
+
export { useMoldableCommands, useMoldableCommand, useMoldableAppCommands, isInMoldable, sendToMoldable, downloadFile, type AppCommand, type CommandAction, type CommandsResponse, type CommandMessage, type DownloadFileOptions, } from './lib/commands';
|
|
5
5
|
export * from './components/ui';
|
|
6
6
|
export { useIsMobile } from './hooks/use-mobile';
|
|
7
7
|
export { Markdown } from './components/markdown';
|
|
8
|
+
export { RichMediaPlayer, type RichMediaPlayerProps, } from './components/rich-media-player';
|
|
8
9
|
export { CodeBlock } from './components/code-block';
|
|
9
10
|
export { WidgetLayout } from './components/widget-layout';
|
|
11
|
+
export { AppErrorBoundary } from './components/app-error-boundary';
|
|
10
12
|
export * from './components/chat';
|
|
11
13
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAA;AAGhC,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,KAAK,EAAE,MAAM,aAAa,CAAA;AAG9E,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,gBAAgB,GACjB,MAAM,iBAAiB,CAAA;AAGxB,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,mBAAmB,GACzB,MAAM,gBAAgB,CAAA;AAGvB,cAAc,iBAAiB,CAAA;AAG/B,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAGhD,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAA;AAGhC,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,KAAK,EAAE,MAAM,aAAa,CAAA;AAG9E,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,gBAAgB,GACjB,MAAM,iBAAiB,CAAA;AAGxB,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,sBAAsB,EACtB,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,mBAAmB,GACzB,MAAM,gBAAgB,CAAA;AAGvB,cAAc,iBAAiB,CAAA;AAG/B,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAGhD,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAChD,OAAO,EACL,eAAe,EACf,KAAK,oBAAoB,GAC1B,MAAM,gCAAgC,CAAA;AAGvC,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAGnD,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAGzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAA;AAGlE,cAAc,mBAAmB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -5,16 +5,19 @@ export { ThemeProvider, useTheme, themeScript } from './lib/theme';
|
|
|
5
5
|
// Export workspace
|
|
6
6
|
export { WorkspaceProvider, useWorkspace, WORKSPACE_HEADER, } from './lib/workspace';
|
|
7
7
|
// Export commands
|
|
8
|
-
export { useMoldableCommands, useMoldableCommand, isInMoldable, sendToMoldable, downloadFile, } from './lib/commands';
|
|
8
|
+
export { useMoldableCommands, useMoldableCommand, useMoldableAppCommands, isInMoldable, sendToMoldable, downloadFile, } from './lib/commands';
|
|
9
9
|
// Export UI components
|
|
10
10
|
export * from './components/ui';
|
|
11
11
|
// Export hooks
|
|
12
12
|
export { useIsMobile } from './hooks/use-mobile';
|
|
13
13
|
// Export Markdown
|
|
14
14
|
export { Markdown } from './components/markdown';
|
|
15
|
+
export { RichMediaPlayer, } from './components/rich-media-player';
|
|
15
16
|
// Export CodeBlock
|
|
16
17
|
export { CodeBlock } from './components/code-block';
|
|
17
18
|
// Export WidgetLayout
|
|
18
19
|
export { WidgetLayout } from './components/widget-layout';
|
|
20
|
+
// Export app error boundary
|
|
21
|
+
export { AppErrorBoundary } from './components/app-error-boundary';
|
|
19
22
|
// Export chat components
|
|
20
23
|
export * from './components/chat';
|
package/dist/lib/commands.d.ts
CHANGED
|
@@ -70,6 +70,14 @@ export interface CommandMessage {
|
|
|
70
70
|
* ```
|
|
71
71
|
*/
|
|
72
72
|
export declare function useMoldableCommands(handlers: Record<string, (payload?: unknown) => void>): void;
|
|
73
|
+
/**
|
|
74
|
+
* Publish the commands that make sense for the app's current view.
|
|
75
|
+
*
|
|
76
|
+
* Apps should call this with a stable, memoized command list. The desktop
|
|
77
|
+
* command menu will prefer these commands over the app's static
|
|
78
|
+
* /api/moldable/commands response while the app is running.
|
|
79
|
+
*/
|
|
80
|
+
export declare function useMoldableAppCommands(appId: string, commands: AppCommand[]): void;
|
|
73
81
|
/**
|
|
74
82
|
* Hook to register a single command handler
|
|
75
83
|
* Useful when you want to register handlers in different components
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/lib/commands.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/lib/commands.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/commands.js
CHANGED
|
@@ -33,6 +33,24 @@ export function useMoldableCommands(handlers) {
|
|
|
33
33
|
return () => window.removeEventListener('message', handleMessage);
|
|
34
34
|
}, []);
|
|
35
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Publish the commands that make sense for the app's current view.
|
|
38
|
+
*
|
|
39
|
+
* Apps should call this with a stable, memoized command list. The desktop
|
|
40
|
+
* command menu will prefer these commands over the app's static
|
|
41
|
+
* /api/moldable/commands response while the app is running.
|
|
42
|
+
*/
|
|
43
|
+
export function useMoldableAppCommands(appId, commands) {
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (!isInMoldable())
|
|
46
|
+
return;
|
|
47
|
+
window.parent.postMessage({
|
|
48
|
+
type: 'moldable:set-app-commands',
|
|
49
|
+
appId,
|
|
50
|
+
commands,
|
|
51
|
+
}, '*');
|
|
52
|
+
}, [appId, commands]);
|
|
53
|
+
}
|
|
36
54
|
/**
|
|
37
55
|
* Hook to register a single command handler
|
|
38
56
|
* Useful when you want to register handlers in different components
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moldable-ai/ui",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9",
|
|
4
4
|
"description": "Shared UI components for Moldable applications",
|
|
5
5
|
"author": "Desiderata LLC",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -33,8 +33,19 @@
|
|
|
33
33
|
"src/styles",
|
|
34
34
|
"LICENSE"
|
|
35
35
|
],
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsc",
|
|
38
|
+
"dev": "tsc --watch",
|
|
39
|
+
"lint": "eslint . --ext .ts,.tsx --max-warnings 0",
|
|
40
|
+
"format": "prettier --write . --ignore-path ../../.prettierignore",
|
|
41
|
+
"check-types": "tsc --noEmit",
|
|
42
|
+
"test": "vitest run"
|
|
43
|
+
},
|
|
36
44
|
"dependencies": {
|
|
37
45
|
"@base-ui/react": "^1.1.0",
|
|
46
|
+
"@dnd-kit/core": "^6.3.1",
|
|
47
|
+
"@dnd-kit/sortable": "^10.0.0",
|
|
48
|
+
"@dnd-kit/utilities": "^3.2.2",
|
|
38
49
|
"@hookform/resolvers": "^5.2.2",
|
|
39
50
|
"@radix-ui/react-accordion": "^1.2.12",
|
|
40
51
|
"@radix-ui/react-alert-dialog": "^1.1.15",
|
|
@@ -89,26 +100,18 @@
|
|
|
89
100
|
"zod": "^4.3.5"
|
|
90
101
|
},
|
|
91
102
|
"devDependencies": {
|
|
103
|
+
"@moldable-ai/eslint-config": "workspace:*",
|
|
104
|
+
"@moldable-ai/prettier-config": "workspace:*",
|
|
105
|
+
"@moldable-ai/typescript-config": "workspace:*",
|
|
92
106
|
"@types/node": "^24.0.3",
|
|
93
107
|
"@types/react": "^19.1.6",
|
|
94
108
|
"@types/react-dom": "^19.1.6",
|
|
95
109
|
"jsdom": "^26.1.0",
|
|
96
110
|
"typescript": "^5.8.3",
|
|
97
|
-
"vitest": "^3.2.4"
|
|
98
|
-
"@moldable-ai/typescript-config": "0.1.3",
|
|
99
|
-
"@moldable-ai/eslint-config": "0.1.4",
|
|
100
|
-
"@moldable-ai/prettier-config": "0.1.3"
|
|
111
|
+
"vitest": "^3.2.4"
|
|
101
112
|
},
|
|
102
113
|
"peerDependencies": {
|
|
103
114
|
"react": "^19.0.0",
|
|
104
115
|
"react-dom": "^19.0.0"
|
|
105
|
-
},
|
|
106
|
-
"scripts": {
|
|
107
|
-
"build": "tsc",
|
|
108
|
-
"dev": "tsc --watch",
|
|
109
|
-
"lint": "eslint . --ext .ts,.tsx --max-warnings 0",
|
|
110
|
-
"format": "prettier --write . --ignore-path ../../.prettierignore",
|
|
111
|
-
"check-types": "tsc --noEmit",
|
|
112
|
-
"test": "vitest run"
|
|
113
116
|
}
|
|
114
|
-
}
|
|
117
|
+
}
|
package/src/styles/index.css
CHANGED
|
@@ -68,6 +68,31 @@
|
|
|
68
68
|
--chat-safe-padding: var(--chat-safe-padding);
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
@keyframes moldable-chat-shimmer {
|
|
72
|
+
0% {
|
|
73
|
+
background-position: 140% 50%;
|
|
74
|
+
}
|
|
75
|
+
100% {
|
|
76
|
+
background-position: -40% 50%;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.moldable-chat-shimmer {
|
|
81
|
+
color: transparent;
|
|
82
|
+
background: linear-gradient(
|
|
83
|
+
90deg,
|
|
84
|
+
color-mix(in oklch, var(--muted-foreground) 72%, transparent) 0%,
|
|
85
|
+
color-mix(in oklch, var(--foreground) 92%, white 8%) 42%,
|
|
86
|
+
color-mix(in oklch, var(--foreground) 100%, white 16%) 50%,
|
|
87
|
+
color-mix(in oklch, var(--foreground) 92%, white 8%) 58%,
|
|
88
|
+
color-mix(in oklch, var(--muted-foreground) 72%, transparent) 100%
|
|
89
|
+
);
|
|
90
|
+
background-size: 240% 100%;
|
|
91
|
+
-webkit-background-clip: text;
|
|
92
|
+
background-clip: text;
|
|
93
|
+
animation: moldable-chat-shimmer 1.8s ease-in-out infinite;
|
|
94
|
+
}
|
|
95
|
+
|
|
71
96
|
:root {
|
|
72
97
|
--radius: 0.65rem;
|
|
73
98
|
--background: oklch(1 0 0);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"commands.test.d.ts","sourceRoot":"","sources":["../../src/lib/commands.test.ts"],"names":[],"mappings":""}
|