@moldable-ai/ui 0.2.12 → 0.2.14
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 +0 -1
- package/dist/components/app-error-boundary.d.ts.map +1 -1
- package/dist/components/app-error-boundary.js +17 -2
- package/dist/components/chat/chat-input.d.ts +1 -1
- package/dist/components/chat/chat-input.d.ts.map +1 -1
- package/dist/components/chat/chat-input.js +3 -3
- package/dist/components/chat/chat-messages.js +1 -1
- package/dist/components/chat/chat-panel.d.ts +1 -1
- package/dist/components/chat/chat-panel.d.ts.map +1 -1
- package/dist/components/chat/chat-panel.js +4 -8
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/lib/today.d.ts +150 -0
- package/dist/lib/today.d.ts.map +1 -0
- package/dist/lib/today.js +50 -0
- package/package.json +2 -2
- package/src/styles/index.css +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-error-boundary.d.ts","sourceRoot":"","sources":["../../src/components/app-error-boundary.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAGjE,KAAK,WAAW,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"app-error-boundary.d.ts","sourceRoot":"","sources":["../../src/components/app-error-boundary.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAGjE,KAAK,WAAW,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAA;AAWjD,UAAU,qBAAqB;IAC7B,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED,UAAU,qBAAqB;IAC7B,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;IACnB,MAAM,EAAE,WAAW,CAAA;IACnB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;CAC9B;AAqDD,qBAAa,gBAAiB,SAAQ,SAAS,CAC7C,qBAAqB,EACrB,qBAAqB,CACtB;IACC,KAAK,EAAE,qBAAqB,CAI3B;IAED,MAAM,CAAC,wBAAwB,CAC7B,KAAK,EAAE,KAAK,GACX,OAAO,CAAC,qBAAqB,CAAC;IAIjC,iBAAiB,IAAI,IAAI;IAOzB,oBAAoB,IAAI,IAAI;IAU5B,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,GAAG,IAAI;IAWtD,OAAO,CAAC,iBAAiB,CAMxB;IAED,OAAO,CAAC,wBAAwB,CAK/B;IAED,OAAO,CAAC,MAAM,CAEb;IAED,OAAO,CAAC,WAAW,CAYlB;IAED,MAAM;CA8CP"}
|
|
@@ -26,6 +26,19 @@ function formatError(error, source, componentStack) {
|
|
|
26
26
|
parts.push(`Source: ${source}`);
|
|
27
27
|
return parts.join('\n\n');
|
|
28
28
|
}
|
|
29
|
+
function reportClientErrorToMoldable(appName, error, source, componentStack) {
|
|
30
|
+
if (typeof window === 'undefined' || window.parent === window)
|
|
31
|
+
return;
|
|
32
|
+
const message = {
|
|
33
|
+
type: 'moldable:app-client-error',
|
|
34
|
+
appName,
|
|
35
|
+
source,
|
|
36
|
+
message: `${error.name}: ${error.message}`,
|
|
37
|
+
stack: error.stack,
|
|
38
|
+
componentStack,
|
|
39
|
+
};
|
|
40
|
+
window.parent.postMessage(message, '*');
|
|
41
|
+
}
|
|
29
42
|
export class AppErrorBoundary extends Component {
|
|
30
43
|
state = {
|
|
31
44
|
error: null,
|
|
@@ -50,16 +63,19 @@ export class AppErrorBoundary extends Component {
|
|
|
50
63
|
componentDidCatch(error, info) {
|
|
51
64
|
console.error(`${this.props.appName} UI crashed:`, error, info);
|
|
52
65
|
this.setState({ componentStack: info.componentStack ?? null });
|
|
66
|
+
reportClientErrorToMoldable(this.props.appName, error, 'react', info.componentStack ?? null);
|
|
53
67
|
}
|
|
54
68
|
handleWindowError = (event) => {
|
|
55
69
|
const error = event.error instanceof Error ? event.error : new Error(event.message);
|
|
56
70
|
console.error(`${this.props.appName} uncaught frontend error:`, error);
|
|
57
71
|
this.setState({ error, source: 'window', componentStack: null });
|
|
72
|
+
reportClientErrorToMoldable(this.props.appName, error, 'window', null);
|
|
58
73
|
};
|
|
59
74
|
handleUnhandledRejection = (event) => {
|
|
60
75
|
const error = toError(event.reason);
|
|
61
76
|
console.error(`${this.props.appName} unhandled promise rejection:`, error);
|
|
62
77
|
this.setState({ error, source: 'promise', componentStack: null });
|
|
78
|
+
reportClientErrorToMoldable(this.props.appName, error, 'promise', null);
|
|
63
79
|
};
|
|
64
80
|
reload = () => {
|
|
65
81
|
window.location.reload();
|
|
@@ -68,10 +84,9 @@ export class AppErrorBoundary extends Component {
|
|
|
68
84
|
const { error, source, componentStack } = this.state;
|
|
69
85
|
if (!error)
|
|
70
86
|
return;
|
|
71
|
-
const surfaceLabel = this.props.surface === 'widget' ? ' widget' : ' full app';
|
|
72
87
|
const errorReport = formatError(error, source, componentStack);
|
|
73
88
|
const text = [
|
|
74
|
-
`${this.props.appName}
|
|
89
|
+
`${this.props.appName} hit an uncaught frontend error.`,
|
|
75
90
|
'Please inspect and fix the client crash.',
|
|
76
91
|
errorReport,
|
|
77
92
|
].join('\n\n');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-input.d.ts","sourceRoot":"","sources":["../../../src/components/chat/chat-input.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EAGT,SAAS,EACT,SAAS,EACV,MAAM,OAAO,CAAA;AAKd,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,OAAO,
|
|
1
|
+
{"version":3,"file":"chat-input.d.ts","sourceRoot":"","sources":["../../../src/components/chat/chat-input.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EAGT,SAAS,EACT,SAAS,EACV,MAAM,OAAO,CAAA;AAKd,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,OAAO,CAAA;AAE7C,MAAM,MAAM,sBAAsB,GAAG;IACnC,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,KAAK,cAAc,GAAG;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,aAAa,EAAE,CAAC,CAAC,EAAE,WAAW,CAAC,mBAAmB,CAAC,KAAK,IAAI,CAAA;IAC5D,QAAQ,EAAE,CACR,CAAC,EAAE,SAAS,CAAC,eAAe,CAAC,GAAG,SAAS,EACzC,IAAI,CAAC,EAAE,cAAc,KAClB,IAAI,CAAA;IACT,YAAY,EAAE,OAAO,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,SAAS,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAAA;IAChD,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IACnB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gBAAgB,CAAC,EAAE,mBAAmB,EAAE,CAAA;IACxC,uBAAuB,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9C,mBAAmB,CAAC,EAAE,SAAS,CAAA;IAC/B,cAAc,CAAC,EAAE,SAAS,CAAA;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,aAAa,CAAC,EAAE,sBAAsB,EAAE,CAAA;IACxC,oBAAoB,CAAC,EAAE,CAAC,OAAO,EAAE,sBAAsB,KAAK,IAAI,CAAA;CACjE,CAAA;AAED,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,aAAa,EACb,QAAQ,EACR,YAAY,EACZ,WAA+B,EAC/B,QAAQ,EACR,MAAM,EACN,OAAe,EACf,gBAAqB,EACrB,uBAAuB,EACvB,mBAAmB,EACnB,cAAc,EACd,cAAsB,EACtB,aAAkB,EAClB,oBAAoB,GACrB,EAAE,cAAc,2CA2KhB"}
|
|
@@ -30,8 +30,8 @@ export function ChatInput({ input, onInputChange, onSubmit, isResponding, placeh
|
|
|
30
30
|
onSubmit(undefined, isResponding ? 'queue' : 'send');
|
|
31
31
|
}
|
|
32
32
|
};
|
|
33
|
-
//
|
|
34
|
-
const showStopButton = isResponding;
|
|
33
|
+
// During a response, Enter/primary submit queues follow-up text.
|
|
34
|
+
const showStopButton = isResponding && !canSubmit;
|
|
35
35
|
const handleButtonClick = (e) => {
|
|
36
36
|
// When rendered as stop button (type="button"), always call onStop
|
|
37
37
|
// Don't re-check conditions - trust the render decision to avoid race conditions
|
|
@@ -53,6 +53,6 @@ export function ChatInput({ input, onInputChange, onSubmit, isResponding, placeh
|
|
|
53
53
|
}, children: [_jsxs("span", { className: "bg-muted text-muted-foreground rounded px-1.5 py-0.5 font-mono text-xs", children: ["/", command.name] }), _jsx("span", { className: "min-w-0 text-xs", children: command.description })] }, command.id))) })), !compact && hasAttachments && (_jsx("div", { className: "flex max-h-32 gap-2 overflow-x-auto px-3 pt-3", children: imageAttachments.map((attachment) => (_jsxs("div", { className: "bg-muted/70 border-border flex max-w-48 shrink-0 items-center gap-2 rounded-xl border p-1.5 pr-2", children: [_jsx("div", { className: "bg-background flex size-9 shrink-0 items-center justify-center overflow-hidden rounded-lg border", children: attachment.previewUrl ? (_jsx("img", { src: attachment.previewUrl, alt: "", className: "size-full object-cover", draggable: false })) : (_jsx(ImageIcon, { className: "text-muted-foreground size-4" })) }), _jsx("span", { className: "min-w-0 truncate text-xs font-medium", title: attachment.path, children: attachment.name }), onRemoveImageAttachment && (_jsx("button", { type: "button", onClick: () => onRemoveImageAttachment(attachment.id), className: "text-muted-foreground hover:bg-accent hover:text-foreground flex size-6 shrink-0 cursor-pointer items-center justify-center rounded-md transition-colors", "aria-label": `Remove ${attachment.name}`, children: _jsx(X, { className: "size-3.5" }) }))] }, attachment.id))) })), _jsx("div", { className: cn('w-full px-5', compact ? 'py-4' : 'pb-2 pt-4'), children: _jsx(Textarea, { ref: inputRef, value: input, placeholder: placeholder, onChange: onInputChange, onKeyDown: handleKeyDown, className: cn('max-h-32 min-h-[24px] resize-none rounded-none border-0 !bg-transparent p-0 text-sm shadow-none focus:outline-none focus-visible:ring-0 focus-visible:ring-offset-0 dark:!bg-transparent', compact && 'max-h-6 min-h-6') }) }), !compact && (_jsxs("div", { className: "flex min-h-11 items-center justify-between gap-3 px-3 pb-3", children: [_jsx("div", { className: "flex min-w-0 shrink-0 items-center justify-start gap-1", children: footerStartControls }), _jsx("div", { className: "min-w-0 flex-1" }), _jsx("div", { className: "flex min-w-0 shrink-0 items-center justify-end gap-0.5", children: footerControls }), _jsxs(Button, { type: showStopButton ? 'button' : 'submit', size: "icon", className: "bg-primary text-primary-foreground size-8 cursor-pointer rounded-full hover:opacity-70 disabled:opacity-30", disabled: !canSubmit && !isResponding, onClick: handleButtonClick, children: [showStopButton ? (_jsx(Square, { className: "fill-primary-foreground size-4 animate-pulse" })) : (_jsx(ArrowUp, { className: "size-4" })), _jsx("span", { className: "sr-only", children: showStopButton
|
|
54
54
|
? 'Stop generating'
|
|
55
55
|
: isResponding
|
|
56
|
-
? '
|
|
56
|
+
? 'Queue follow-up'
|
|
57
57
|
: 'Send message' })] })] }))] }) }) }) }));
|
|
58
58
|
}
|
|
@@ -36,6 +36,6 @@ function PureMessages({ messages, status, checkpoints, restoringMessageId, onRes
|
|
|
36
36
|
return (_jsxs(_Fragment, { children: [messages.map((message, index) => {
|
|
37
37
|
const checkpoint = checkpoints?.get(message.id);
|
|
38
38
|
return (_jsx(MessageRow, { message: message, isLast: index === messages.length - 1, isStreaming: isStreaming, checkpoint: checkpoint, restoringMessageId: restoringMessageId, onRestoreCheckpoint: onRestoreCheckpoint }, message.id));
|
|
39
|
-
}), isThinking && _jsx(ThinkingMessage, {}), isCompacting && _jsx(CompactingMessage, {})] }));
|
|
39
|
+
}), isThinking && !isCompacting && _jsx(ThinkingMessage, {}), isCompacting && _jsx(CompactingMessage, {})] }));
|
|
40
40
|
}
|
|
41
41
|
export const Messages = memo(PureMessages);
|
|
@@ -77,7 +77,7 @@ export interface ChatPanelProps {
|
|
|
77
77
|
isExpanded: boolean;
|
|
78
78
|
/** Toggle expanded state */
|
|
79
79
|
onExpandedChange: (expanded: boolean) => void;
|
|
80
|
-
/** Whether the panel is minimized (hidden below fold
|
|
80
|
+
/** Whether the panel is minimized (hidden below fold) */
|
|
81
81
|
isMinimized?: boolean;
|
|
82
82
|
/** Toggle minimized state */
|
|
83
83
|
onMinimizedChange?: (minimized: boolean) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-panel.d.ts","sourceRoot":"","sources":["../../../src/components/chat/chat-panel.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"chat-panel.d.ts","sourceRoot":"","sources":["../../../src/components/chat/chat-panel.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import { AlertCircle, ArrowDown, ChevronDown, ClipboardList, Code2, CornerDownRight, GripVertical, Image as ImageIcon, ListPlus,
|
|
3
|
+
import { AlertCircle, ArrowDown, ChevronDown, ClipboardList, Code2, CornerDownRight, GripVertical, Image as ImageIcon, ListPlus, Pencil, Trash2, } from 'lucide-react';
|
|
4
4
|
import { useCallback, useEffect, useMemo, useRef, useState, } from 'react';
|
|
5
5
|
import { cn } from '../../lib/utils';
|
|
6
6
|
import { Button } from '../ui/button';
|
|
@@ -153,7 +153,7 @@ export function ChatPanel({ messages, status, isTurnInFlight, input, onInputChan
|
|
|
153
153
|
}
|
|
154
154
|
if (!input.trim() && imageAttachments.length === 0)
|
|
155
155
|
return;
|
|
156
|
-
const submitMode = mode ?? (isResponding ? '
|
|
156
|
+
const submitMode = mode ?? (isResponding ? 'queue' : 'send');
|
|
157
157
|
if (!isExpanded) {
|
|
158
158
|
onExpandedChange(true);
|
|
159
159
|
}
|
|
@@ -210,10 +210,6 @@ export function ChatPanel({ messages, status, isTurnInFlight, input, onInputChan
|
|
|
210
210
|
document.addEventListener('keydown', handleKeyDown);
|
|
211
211
|
return () => document.removeEventListener('keydown', handleKeyDown);
|
|
212
212
|
}, [controlsDisabled, isExpanded, handleNewChat]);
|
|
213
|
-
// Handle clicking the minimized flap
|
|
214
|
-
const handleFlapClick = useCallback(() => {
|
|
215
|
-
onMinimizedChange?.(false);
|
|
216
|
-
}, [onMinimizedChange]);
|
|
217
213
|
// Handle minimize button - now goes to minimized state
|
|
218
214
|
const handleMinimize = useCallback(() => {
|
|
219
215
|
if (isExpanded) {
|
|
@@ -242,7 +238,7 @@ export function ChatPanel({ messages, status, isTurnInFlight, input, onInputChan
|
|
|
242
238
|
}
|
|
243
239
|
items.push({ key: message.id, kind: 'message', message });
|
|
244
240
|
}
|
|
245
|
-
if (isThinking) {
|
|
241
|
+
if (isThinking && !isCompacting) {
|
|
246
242
|
items.push({ key: 'thinking', kind: 'thinking' });
|
|
247
243
|
}
|
|
248
244
|
if (isCompacting) {
|
|
@@ -358,7 +354,7 @@ export function ChatPanel({ messages, status, isTurnInFlight, input, onInputChan
|
|
|
358
354
|
}
|
|
359
355
|
};
|
|
360
356
|
}, [isAtBottom, isExpanded, messages.length, scrollToBottom]);
|
|
361
|
-
return (_jsxs(_Fragment, { children: [_jsx(AnimatePresence, { children: isExpanded && !isMinimized && (_jsx(motion.div, { "data-moldable-chat-backdrop": true, initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, transition: { duration: 0.2 }, className: "fixed inset-0 z-40 bg-black/20", onClick: () => onExpandedChange(false) })) }), _jsx(
|
|
357
|
+
return (_jsxs(_Fragment, { children: [_jsx(AnimatePresence, { children: isExpanded && !isMinimized && (_jsx(motion.div, { "data-moldable-chat-backdrop": true, initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, transition: { duration: 0.2 }, className: "fixed inset-0 z-40 bg-black/20", onClick: () => onExpandedChange(false) })) }), _jsx(motion.div, { "data-moldable-chat-panel": true, initial: false, animate: {
|
|
362
358
|
width: isExpanded ? 'min(90vw, 640px)' : '400px',
|
|
363
359
|
y: isMinimized ? 'calc(100% + 24px)' : 0,
|
|
364
360
|
opacity: isMinimized ? 0 : 1,
|
package/dist/index.d.ts
CHANGED
|
@@ -3,11 +3,11 @@ export { ThemeProvider, useTheme, themeScript, type Theme } from './lib/theme';
|
|
|
3
3
|
export { WorkspaceProvider, useWorkspace, WORKSPACE_HEADER, } from './lib/workspace';
|
|
4
4
|
export { useMoldableCommands, useMoldableCommand, useMoldableAppCommands, useMoldableNavigationPop, useMoldableNavigationState, isInMoldable, sendToMoldable, pushMoldableNavigation, popMoldableNavigation, resetMoldableNavigation, downloadFile, type AppCommand, type CommandAction, type CommandsResponse, type CommandMessage, type MoldableNavigationEntry, type MoldableNavigationPopMessage, type MoldableNavigationStateMessage, type DownloadFileOptions, } from './lib/commands';
|
|
5
5
|
export * from './components/ui';
|
|
6
|
+
export { TODAY_KIND_RANK, TODAY_KIND_TTL_MS, makeTodayItem, type TodayItem, type TodayItemKind, type TodaySurface, type TodayAction, type TodayResponse, type ResumeState, type HydratedTodayItem, type HydratedResume, } from './lib/today';
|
|
6
7
|
export { useIsMobile } from './hooks/use-mobile';
|
|
7
8
|
export { Markdown } from './components/markdown';
|
|
8
9
|
export { RichMediaPlayer, type RichMediaPlayerProps, } from './components/rich-media-player';
|
|
9
10
|
export { CodeBlock } from './components/code-block';
|
|
10
|
-
export { WidgetLayout } from './components/widget-layout';
|
|
11
11
|
export { AppErrorBoundary } from './components/app-error-boundary';
|
|
12
12
|
export * from './components/chat';
|
|
13
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,sBAAsB,EACtB,wBAAwB,EACxB,0BAA0B,EAC1B,YAAY,EACZ,cAAc,EACd,sBAAsB,EACtB,qBAAqB,EACrB,uBAAuB,EACvB,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,uBAAuB,EAC5B,KAAK,4BAA4B,EACjC,KAAK,8BAA8B,EACnC,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,
|
|
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,wBAAwB,EACxB,0BAA0B,EAC1B,YAAY,EACZ,cAAc,EACd,sBAAsB,EACtB,qBAAqB,EACrB,uBAAuB,EACvB,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,uBAAuB,EAC5B,KAAK,4BAA4B,EACjC,KAAK,8BAA8B,EACnC,KAAK,mBAAmB,GACzB,MAAM,gBAAgB,CAAA;AAGvB,cAAc,iBAAiB,CAAA;AAG/B,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,aAAa,EACb,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,cAAc,GACpB,MAAM,aAAa,CAAA;AAGpB,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,gBAAgB,EAAE,MAAM,iCAAiC,CAAA;AAGlE,cAAc,mBAAmB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,8 @@ export { WorkspaceProvider, useWorkspace, WORKSPACE_HEADER, } from './lib/worksp
|
|
|
8
8
|
export { useMoldableCommands, useMoldableCommand, useMoldableAppCommands, useMoldableNavigationPop, useMoldableNavigationState, isInMoldable, sendToMoldable, pushMoldableNavigation, popMoldableNavigation, resetMoldableNavigation, downloadFile, } from './lib/commands';
|
|
9
9
|
// Export UI components
|
|
10
10
|
export * from './components/ui';
|
|
11
|
+
// Export Today contract
|
|
12
|
+
export { TODAY_KIND_RANK, TODAY_KIND_TTL_MS, makeTodayItem, } from './lib/today';
|
|
11
13
|
// Export hooks
|
|
12
14
|
export { useIsMobile } from './hooks/use-mobile';
|
|
13
15
|
// Export Markdown
|
|
@@ -15,8 +17,6 @@ export { Markdown } from './components/markdown';
|
|
|
15
17
|
export { RichMediaPlayer, } from './components/rich-media-player';
|
|
16
18
|
// Export CodeBlock
|
|
17
19
|
export { CodeBlock } from './components/code-block';
|
|
18
|
-
// Export WidgetLayout
|
|
19
|
-
export { WidgetLayout } from './components/widget-layout';
|
|
20
20
|
// Export app error boundary
|
|
21
21
|
export { AppErrorBoundary } from './components/app-error-boundary';
|
|
22
22
|
// Export chat components
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Today contract — the shared shape apps use to contribute to the Moldable
|
|
3
|
+
* "Today" home view, and the host uses to aggregate + triage them.
|
|
4
|
+
*
|
|
5
|
+
* See prds/today-view.prd.md. The guiding rule: silence is the default. An app
|
|
6
|
+
* contributes an item ONLY when something earns attention (a resume point, an
|
|
7
|
+
* in-flight job, a blocker, a time-sensitive nudge). It does not mirror an
|
|
8
|
+
* always-on overview.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Why a contribution earns attention. Drives ranking, styling, and default decay.
|
|
12
|
+
* (prds/today-view.prd.md §3)
|
|
13
|
+
*/
|
|
14
|
+
export type TodayItemKind = 'resume' | 'active' | 'blocked' | 'timely' | 'threshold' | 'milestone' | 'agent-activity';
|
|
15
|
+
/** How an item renders. Most items are `text`; `widget` is the rare live case. */
|
|
16
|
+
export type TodaySurface = 'text' | 'nudge' | 'metric' | 'widget';
|
|
17
|
+
/**
|
|
18
|
+
* An action a user can take directly from a Today card. Reuses the app-command
|
|
19
|
+
* vocabulary (navigate/message) plus Today-specific affordances.
|
|
20
|
+
*/
|
|
21
|
+
export type TodayAction =
|
|
22
|
+
/** Open the contributing app (optionally deep-linked to a route/entity). */
|
|
23
|
+
{
|
|
24
|
+
type: 'open-app';
|
|
25
|
+
label: string;
|
|
26
|
+
deepLink?: string;
|
|
27
|
+
}
|
|
28
|
+
/** Call one of the app's own `/api/moldable/rpc` methods in place. */
|
|
29
|
+
| {
|
|
30
|
+
type: 'rpc';
|
|
31
|
+
label: string;
|
|
32
|
+
method: string;
|
|
33
|
+
params?: unknown;
|
|
34
|
+
/** If set, confirm with the user before running (destructive actions). */
|
|
35
|
+
confirm?: string;
|
|
36
|
+
/** Optional toast/label shown on success. */
|
|
37
|
+
successLabel?: string;
|
|
38
|
+
}
|
|
39
|
+
/** Drop a prompt into the unified chat to follow up / interrogate. */
|
|
40
|
+
| {
|
|
41
|
+
type: 'message';
|
|
42
|
+
label: string;
|
|
43
|
+
prompt: string;
|
|
44
|
+
}
|
|
45
|
+
/** Navigate the app to a specific path (app-command `navigate` semantics). */
|
|
46
|
+
| {
|
|
47
|
+
type: 'navigate';
|
|
48
|
+
label: string;
|
|
49
|
+
path: string;
|
|
50
|
+
}
|
|
51
|
+
/** Dismiss the item (host-handled; honors `cadence`). */
|
|
52
|
+
| {
|
|
53
|
+
type: 'dismiss';
|
|
54
|
+
label?: string;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* A single Today contribution. Apps return zero or more of these from
|
|
58
|
+
* `GET /api/moldable/today`. `appId` is attached by the host (it knows which
|
|
59
|
+
* app it queried), so apps never set it.
|
|
60
|
+
*/
|
|
61
|
+
export interface TodayItem {
|
|
62
|
+
/**
|
|
63
|
+
* Stable id for this *logical* item (e.g. `resume:lesson:hanon` or
|
|
64
|
+
* `timer:active`). Used for dedupe + persisting dismissals across refreshes.
|
|
65
|
+
*/
|
|
66
|
+
id: string;
|
|
67
|
+
kind: TodayItemKind;
|
|
68
|
+
/** Defaults to `text`. */
|
|
69
|
+
surface?: TodaySurface;
|
|
70
|
+
/** One scannable line. ("Resume Lesson 2 of 4: Hanon Hand Agility") */
|
|
71
|
+
title: string;
|
|
72
|
+
/** Optional second line of context. */
|
|
73
|
+
subtitle?: string;
|
|
74
|
+
/** Emoji or lucide icon name; falls back to the app icon. */
|
|
75
|
+
icon?: string;
|
|
76
|
+
/** Optional accent color (CSS value) for emphasis. */
|
|
77
|
+
accentColor?: string;
|
|
78
|
+
/** Ordered actions; the first is treated as primary. */
|
|
79
|
+
actions?: TodayAction[];
|
|
80
|
+
/**
|
|
81
|
+
* For `surface: 'widget'` — a temporary, actionable embed summoned only for
|
|
82
|
+
* this item. `path` is served by the app.
|
|
83
|
+
*/
|
|
84
|
+
widget?: {
|
|
85
|
+
path: string;
|
|
86
|
+
height?: number;
|
|
87
|
+
};
|
|
88
|
+
/** App hint, 0–100. The host has final say over ordering (PRD §6). */
|
|
89
|
+
priority?: number;
|
|
90
|
+
/** ISO timestamp; defaults to now when omitted. */
|
|
91
|
+
createdAt?: string;
|
|
92
|
+
/** ISO timestamp; host applies a per-kind default when omitted. */
|
|
93
|
+
expiresAt?: string;
|
|
94
|
+
/** Defaults to true. */
|
|
95
|
+
dismissible?: boolean;
|
|
96
|
+
/** Anti-repeat policy. `once` = don't resurface same day after dismiss. */
|
|
97
|
+
cadence?: 'once' | 'daily' | 'while-true';
|
|
98
|
+
/** Optional grouping label the agent/host may use to cluster items. */
|
|
99
|
+
groupHint?: string;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The most recent "pick up where you left off" point for an app. Powers the
|
|
103
|
+
* Resume rail. Distinct from a `resume`-kind item so the host can render it as
|
|
104
|
+
* a first-class, always-available rail rather than an attention card.
|
|
105
|
+
*/
|
|
106
|
+
export interface ResumeState {
|
|
107
|
+
title: string;
|
|
108
|
+
subtitle?: string;
|
|
109
|
+
icon?: string;
|
|
110
|
+
/** Where opening the app should land. */
|
|
111
|
+
deepLink?: string;
|
|
112
|
+
/** ISO timestamp of last interaction; used to rank the rail by recency. */
|
|
113
|
+
lastTouchedAt?: string;
|
|
114
|
+
}
|
|
115
|
+
/** Response shape for `GET /api/moldable/today`. */
|
|
116
|
+
export interface TodayResponse {
|
|
117
|
+
items: TodayItem[];
|
|
118
|
+
resume?: ResumeState | null;
|
|
119
|
+
/** ISO timestamp the app generated this; host may use for caching. */
|
|
120
|
+
generatedAt?: string;
|
|
121
|
+
}
|
|
122
|
+
/** Host-side: a TodayItem enriched with which app produced it. */
|
|
123
|
+
export interface HydratedTodayItem extends TodayItem {
|
|
124
|
+
appId: string;
|
|
125
|
+
appName: string;
|
|
126
|
+
appIcon?: string;
|
|
127
|
+
appIconPath?: string;
|
|
128
|
+
}
|
|
129
|
+
/** Host-side resume entry (ResumeState + provenance). */
|
|
130
|
+
export interface HydratedResume extends ResumeState {
|
|
131
|
+
appId: string;
|
|
132
|
+
appName: string;
|
|
133
|
+
appIcon?: string;
|
|
134
|
+
appIconPath?: string;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Kind → ranking weight (higher surfaces first). The host's deterministic
|
|
138
|
+
* triage baseline; the Today agent may re-rank, but this is the floor.
|
|
139
|
+
* (prds/today-view.prd.md §6)
|
|
140
|
+
*/
|
|
141
|
+
export declare const TODAY_KIND_RANK: Record<TodayItemKind, number>;
|
|
142
|
+
/** Kind → default time-to-live (ms) when an item omits `expiresAt`. */
|
|
143
|
+
export declare const TODAY_KIND_TTL_MS: Record<TodayItemKind, number>;
|
|
144
|
+
/**
|
|
145
|
+
* Normalize a partial item into a complete TodayItem with sensible defaults.
|
|
146
|
+
* Apps building items by hand can use this, or just return literal JSON — the
|
|
147
|
+
* host applies the same defaults defensively (see `normalizeTodayItem`).
|
|
148
|
+
*/
|
|
149
|
+
export declare function makeTodayItem(item: Omit<TodayItem, 'createdAt' | 'surface' | 'dismissible'> & Partial<Pick<TodayItem, 'createdAt' | 'surface' | 'dismissible'>>): TodayItem;
|
|
150
|
+
//# sourceMappingURL=today.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"today.d.ts","sourceRoot":"","sources":["../../src/lib/today.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Today contract — the shared shape apps use to contribute to the Moldable
|
|
3
|
+
* "Today" home view, and the host uses to aggregate + triage them.
|
|
4
|
+
*
|
|
5
|
+
* See prds/today-view.prd.md. The guiding rule: silence is the default. An app
|
|
6
|
+
* contributes an item ONLY when something earns attention (a resume point, an
|
|
7
|
+
* in-flight job, a blocker, a time-sensitive nudge). It does not mirror an
|
|
8
|
+
* always-on overview.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Kind → ranking weight (higher surfaces first). The host's deterministic
|
|
12
|
+
* triage baseline; the Today agent may re-rank, but this is the floor.
|
|
13
|
+
* (prds/today-view.prd.md §6)
|
|
14
|
+
*/
|
|
15
|
+
export const TODAY_KIND_RANK = {
|
|
16
|
+
blocked: 100,
|
|
17
|
+
timely: 90,
|
|
18
|
+
active: 80,
|
|
19
|
+
resume: 70,
|
|
20
|
+
threshold: 60,
|
|
21
|
+
'agent-activity': 40,
|
|
22
|
+
milestone: 20,
|
|
23
|
+
};
|
|
24
|
+
/** Kind → default time-to-live (ms) when an item omits `expiresAt`. */
|
|
25
|
+
export const TODAY_KIND_TTL_MS = {
|
|
26
|
+
blocked: 24 * 60 * 60 * 1000,
|
|
27
|
+
timely: 6 * 60 * 60 * 1000,
|
|
28
|
+
active: 2 * 60 * 60 * 1000,
|
|
29
|
+
resume: 14 * 24 * 60 * 60 * 1000,
|
|
30
|
+
threshold: 24 * 60 * 60 * 1000,
|
|
31
|
+
'agent-activity': 48 * 60 * 60 * 1000,
|
|
32
|
+
milestone: 24 * 60 * 60 * 1000,
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Normalize a partial item into a complete TodayItem with sensible defaults.
|
|
36
|
+
* Apps building items by hand can use this, or just return literal JSON — the
|
|
37
|
+
* host applies the same defaults defensively (see `normalizeTodayItem`).
|
|
38
|
+
*/
|
|
39
|
+
export function makeTodayItem(item) {
|
|
40
|
+
const createdAt = item.createdAt ?? new Date().toISOString();
|
|
41
|
+
const expiresAt = item.expiresAt ??
|
|
42
|
+
new Date(Date.parse(createdAt) + TODAY_KIND_TTL_MS[item.kind]).toISOString();
|
|
43
|
+
return {
|
|
44
|
+
surface: 'text',
|
|
45
|
+
dismissible: true,
|
|
46
|
+
...item,
|
|
47
|
+
createdAt,
|
|
48
|
+
expiresAt,
|
|
49
|
+
};
|
|
50
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moldable-ai/ui",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.14",
|
|
4
4
|
"description": "Shared UI components for Moldable applications",
|
|
5
5
|
"author": "Desiderata LLC",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -108,7 +108,7 @@
|
|
|
108
108
|
"@types/react-dom": "^19.1.6",
|
|
109
109
|
"jsdom": "^26.1.0",
|
|
110
110
|
"typescript": "^5.8.3",
|
|
111
|
-
"vitest": "^
|
|
111
|
+
"vitest": "^4.1.8"
|
|
112
112
|
},
|
|
113
113
|
"peerDependencies": {
|
|
114
114
|
"react": "^19.0.0",
|
package/src/styles/index.css
CHANGED
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
--card-foreground: oklch(0.141 0.005 285.823);
|
|
102
102
|
--popover: oklch(1 0 0);
|
|
103
103
|
--popover-foreground: oklch(0.141 0.005 285.823);
|
|
104
|
-
--primary: oklch(0.
|
|
104
|
+
--primary: oklch(0.205 0 0);
|
|
105
105
|
--primary-foreground: oklch(0.985 0 0);
|
|
106
106
|
--secondary: oklch(0.967 0.001 286.375);
|
|
107
107
|
--secondary-foreground: oklch(0.21 0.006 285.885);
|
|
@@ -154,8 +154,8 @@
|
|
|
154
154
|
--card-foreground: oklch(0.985 0 0);
|
|
155
155
|
--popover: oklch(0.269 0.0018 286.28);
|
|
156
156
|
--popover-foreground: oklch(0.985 0 0);
|
|
157
|
-
--primary: oklch(0.
|
|
158
|
-
--primary-foreground: oklch(0.
|
|
157
|
+
--primary: oklch(0.985 0 0);
|
|
158
|
+
--primary-foreground: oklch(0.205 0 0);
|
|
159
159
|
--secondary: oklch(0.3375 0.0035 286.21);
|
|
160
160
|
--secondary-foreground: oklch(0.985 0 0);
|
|
161
161
|
--muted: oklch(0.3375 0.0035 286.21);
|