@mks2508/mks-ui 0.4.0 → 0.5.1
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/index.css +129 -0
- package/dist/react-ui/blocks/Terminal/TerminalDisplay.d.ts +46 -0
- package/dist/react-ui/blocks/Terminal/TerminalDisplay.d.ts.map +1 -0
- package/dist/react-ui/blocks/Terminal/TerminalDisplay.js +175 -0
- package/dist/react-ui/blocks/Terminal/TerminalDisplay.styles.d.ts +21 -0
- package/dist/react-ui/blocks/Terminal/TerminalDisplay.styles.d.ts.map +1 -0
- package/dist/react-ui/blocks/Terminal/TerminalDisplay.styles.js +31 -0
- package/dist/react-ui/blocks/Terminal/TerminalDisplay.types.d.ts +56 -0
- package/dist/react-ui/blocks/Terminal/TerminalDisplay.types.d.ts.map +1 -0
- package/dist/react-ui/blocks/Terminal/chrome.d.ts +14 -0
- package/dist/react-ui/blocks/Terminal/chrome.d.ts.map +1 -0
- package/dist/react-ui/blocks/Terminal/chrome.js +6 -0
- package/dist/react-ui/blocks/Terminal/components/LogLineBadges.d.ts +5 -5
- package/dist/react-ui/blocks/Terminal/components/LogLineBadges.d.ts.map +1 -1
- package/dist/react-ui/blocks/Terminal/display.d.ts +20 -0
- package/dist/react-ui/blocks/Terminal/display.d.ts.map +1 -0
- package/dist/react-ui/blocks/Terminal/display.js +9 -0
- package/dist/react-ui/blocks/Terminal/index.d.ts +4 -0
- package/dist/react-ui/blocks/Terminal/index.d.ts.map +1 -1
- package/dist/react-ui/blocks/Terminal/index.js +4 -1
- package/dist/react-ui/blocks/Terminal/panel/TerminalPanelChrome.d.ts +7 -6
- package/dist/react-ui/blocks/Terminal/panel/TerminalPanelChrome.d.ts.map +1 -1
- package/dist/react-ui/blocks/Terminal/panel/TerminalPanelChrome.js +51 -30
- package/dist/react-ui/blocks/Terminal/panel/TerminalPanelChrome.styles.d.ts +35 -0
- package/dist/react-ui/blocks/Terminal/panel/TerminalPanelChrome.styles.d.ts.map +1 -0
- package/dist/react-ui/blocks/Terminal/panel/TerminalPanelChrome.styles.js +57 -0
- package/dist/react-ui/blocks/Terminal/panel/TerminalPanelChrome.types.d.ts +7 -2
- package/dist/react-ui/blocks/Terminal/panel/TerminalPanelChrome.types.d.ts.map +1 -1
- package/dist/react-ui/primitives/AutoHeight/index.d.ts +1 -1
- package/dist/react-ui/primitives/CountingNumber/index.d.ts +1 -1
- package/dist/react-ui/primitives/waapi/Morph/techniques/useCSSGridMorph.d.ts.map +1 -1
- package/dist/react-ui/primitives/waapi/Morph/techniques/useCSSGridMorph.js +2 -0
- package/dist/react-ui/primitives/waapi/Morph/techniques/useFLIPClipPath.d.ts.map +1 -1
- package/dist/react-ui/primitives/waapi/Morph/techniques/useFLIPClipPath.js +2 -0
- package/dist/react-ui/primitives/waapi/Morph/techniques/useViewTransitions.d.ts.map +1 -1
- package/dist/react-ui/primitives/waapi/Morph/techniques/useViewTransitions.js +2 -0
- package/dist/react-ui/primitives/waapi/Morph/useMorph.d.ts.map +1 -1
- package/dist/react-ui/primitives/waapi/Morph/useMorph.js +2 -0
- package/dist/react-ui/primitives/waapi/Reorder/useReorder.d.ts.map +1 -1
- package/dist/react-ui/primitives/waapi/Reorder/useReorder.js +2 -0
- package/dist/react-ui/primitives/waapi/Reorder/useReorderPresence.d.ts.map +1 -1
- package/dist/react-ui/primitives/waapi/Reorder/useReorderPresence.js +2 -0
- package/dist/react-ui/primitives/waapi/SlidingNumber/SlidingNumber.styles.d.ts +1 -1
- package/dist/react-ui/primitives/waapi/SlidingText/SlidingText.styles.d.ts +1 -1
- package/dist/react-ui/primitives/waapi/core/useAnimationOrchestrator.d.ts.map +1 -1
- package/dist/react-ui/primitives/waapi/core/useAnimationOrchestrator.js +2 -0
- package/dist/react-ui/primitives/waapi/core/useElementRegistry.d.ts.map +1 -1
- package/dist/react-ui/primitives/waapi/core/useElementRegistry.js +2 -0
- package/dist/react-ui/primitives/waapi/core/useFLIPAnimation.d.ts.map +1 -1
- package/dist/react-ui/primitives/waapi/core/useFLIPAnimation.js +2 -0
- package/dist/react-ui/primitives/waapi/core/usePositionCapture.d.ts.map +1 -1
- package/dist/react-ui/primitives/waapi/core/usePositionCapture.js +2 -0
- package/dist/react-ui/ui/Accordion/Accordion.styles.d.ts +1 -1
- package/dist/react-ui/ui/Accordion/Accordion.types.d.ts +1 -1
- package/dist/react-ui/ui/AlertDialog/AlertDialog.styles.d.ts +1 -1
- package/dist/react-ui/ui/AlertDialog/AlertDialog.types.d.ts +1 -1
- package/dist/react-ui/ui/Badge/Badge.styles.d.ts +1 -1
- package/dist/react-ui/ui/Badge/Badge.types.d.ts +1 -1
- package/dist/react-ui/ui/Button/Button.styles.d.ts +1 -1
- package/dist/react-ui/ui/Button/Button.types.d.ts +1 -1
- package/dist/react-ui/ui/Card/Card.styles.d.ts +1 -1
- package/dist/react-ui/ui/Card/Card.types.d.ts +1 -1
- package/dist/react-ui/ui/Checkbox/Checkbox.styles.d.ts +1 -1
- package/dist/react-ui/ui/Checkbox/Checkbox.types.d.ts +1 -1
- package/dist/react-ui/ui/Combobox/Combobox.styles.d.ts +1 -1
- package/dist/react-ui/ui/Combobox/Combobox.types.d.ts +1 -1
- package/dist/react-ui/ui/CornerBracket/CornerBracket.styles.d.ts +1 -1
- package/dist/react-ui/ui/CornerBracket/CornerBracket.types.d.ts +1 -1
- package/dist/react-ui/ui/DataCard/DataCard.styles.d.ts +1 -1
- package/dist/react-ui/ui/DataCard/DataCard.types.d.ts +1 -1
- package/dist/react-ui/ui/DataCard/index.d.ts +1 -1
- package/dist/react-ui/ui/Dialog/Dialog.styles.d.ts +1 -1
- package/dist/react-ui/ui/Dialog/Dialog.types.d.ts +1 -1
- package/dist/react-ui/ui/DropdownMenu/DropdownMenu.styles.d.ts +1 -1
- package/dist/react-ui/ui/DropdownMenu/DropdownMenu.types.d.ts +1 -1
- package/dist/react-ui/ui/Field/Field.styles.d.ts +1 -1
- package/dist/react-ui/ui/Field/Field.types.d.ts +1 -1
- package/dist/react-ui/ui/Input/Input.styles.d.ts +1 -1
- package/dist/react-ui/ui/Input/Input.types.d.ts +1 -1
- package/dist/react-ui/ui/InputGroup/InputGroup.styles.d.ts +1 -1
- package/dist/react-ui/ui/InputGroup/InputGroup.types.d.ts +1 -1
- package/dist/react-ui/ui/InputGroup/index.d.ts.map +1 -1
- package/dist/react-ui/ui/InputGroup/index.js +2 -0
- package/dist/react-ui/ui/Label/Label.styles.d.ts +1 -1
- package/dist/react-ui/ui/Label/Label.types.d.ts +1 -1
- package/dist/react-ui/ui/Menu/Menu.styles.d.ts +1 -1
- package/dist/react-ui/ui/Menu/Menu.types.d.ts +2 -2
- package/dist/react-ui/ui/Popover/Popover.styles.d.ts +1 -1
- package/dist/react-ui/ui/Popover/Popover.types.d.ts +1 -1
- package/dist/react-ui/ui/Progress/Progress.styles.d.ts +1 -1
- package/dist/react-ui/ui/Progress/Progress.types.d.ts +2 -2
- package/dist/react-ui/ui/Select/Select.styles.d.ts +1 -1
- package/dist/react-ui/ui/Select/Select.types.d.ts +1 -1
- package/dist/react-ui/ui/Separator/Separator.styles.d.ts +1 -1
- package/dist/react-ui/ui/Separator/Separator.types.d.ts +1 -1
- package/dist/react-ui/ui/Switch/Switch.styles.d.ts +1 -1
- package/dist/react-ui/ui/Switch/Switch.types.d.ts +1 -1
- package/dist/react-ui/ui/Tabs/Tabs.styles.d.ts +1 -1
- package/dist/react-ui/ui/Tabs/Tabs.types.d.ts +3 -3
- package/dist/react-ui/ui/TextFlow/TextFlow.styles.d.ts +1 -1
- package/dist/react-ui/ui/Textarea/Textarea.styles.d.ts +1 -1
- package/dist/react-ui/ui/Textarea/Textarea.types.d.ts +1 -1
- package/dist/react-ui/ui/Tooltip/Tooltip.styles.d.ts +1 -1
- package/dist/react-ui/ui/Tooltip/Tooltip.types.d.ts +1 -1
- package/package.json +41 -34
- package/src/css.d.ts +6 -0
- package/src/react-ui/blocks/Terminal/TerminalDisplay.styles.ts +38 -0
- package/src/react-ui/blocks/Terminal/TerminalDisplay.tsx +254 -0
- package/src/react-ui/blocks/Terminal/TerminalDisplay.types.ts +73 -0
- package/src/react-ui/blocks/Terminal/chrome.ts +25 -0
- package/src/react-ui/blocks/Terminal/display.ts +46 -0
- package/src/react-ui/blocks/Terminal/index.ts +8 -0
- package/src/react-ui/blocks/Terminal/panel/TerminalPanelChrome.styles.ts +75 -0
- package/src/react-ui/blocks/Terminal/panel/TerminalPanelChrome.tsx +69 -40
- package/src/react-ui/blocks/Terminal/panel/TerminalPanelChrome.types.ts +8 -2
- package/src/react-ui/primitives/waapi/Morph/techniques/useCSSGridMorph.ts +1 -0
- package/src/react-ui/primitives/waapi/Morph/techniques/useFLIPClipPath.ts +1 -0
- package/src/react-ui/primitives/waapi/Morph/techniques/useViewTransitions.ts +1 -0
- package/src/react-ui/primitives/waapi/Morph/useMorph.ts +1 -0
- package/src/react-ui/primitives/waapi/Reorder/useReorder.ts +1 -0
- package/src/react-ui/primitives/waapi/Reorder/useReorderPresence.ts +1 -0
- package/src/react-ui/primitives/waapi/core/useAnimationOrchestrator.ts +1 -0
- package/src/react-ui/primitives/waapi/core/useElementRegistry.ts +1 -0
- package/src/react-ui/primitives/waapi/core/useFLIPAnimation.ts +1 -0
- package/src/react-ui/primitives/waapi/core/usePositionCapture.ts +1 -0
- package/src/react-ui/ui/Accordion/index.tsx +3 -3
- package/src/react-ui/ui/InputGroup/index.tsx +2 -0
- /package/dist/react-ui/blocks/Terminal/panel/{terminal-filter-dropdown.module-Bovc57nm.css → terminal-filter-dropdown.module-CNVWCefU.css} +0 -0
- /package/dist/react-ui/blocks/Terminal/panel/{terminal-session-tabs.module-QyxHO7cN.css → terminal-session-tabs.module-cmyJ11jP.css} +0 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TerminalDisplay — Readonly GPU-rendered terminal for ANSI content.
|
|
3
|
+
*
|
|
4
|
+
* Uses restty directly (not xterm) for GPU-accelerated rendering of
|
|
5
|
+
* ANSI-formatted text without PTY connection. Content is written via
|
|
6
|
+
* `restty.sendInput(data, "pty")` which feeds text to the WASM terminal
|
|
7
|
+
* engine for parsing and rendering.
|
|
8
|
+
*
|
|
9
|
+
* Optionally wrapped in TerminalPanelChrome glassmorphism shell.
|
|
10
|
+
*
|
|
11
|
+
* @module components/devenv/terminal/TerminalDisplay
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
'use client';
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
useRef,
|
|
18
|
+
useEffect,
|
|
19
|
+
useCallback,
|
|
20
|
+
forwardRef,
|
|
21
|
+
useImperativeHandle,
|
|
22
|
+
useState,
|
|
23
|
+
} from 'react';
|
|
24
|
+
import type { Restty } from 'restty';
|
|
25
|
+
import type { ITerminalDisplayProps, ITerminalDisplayRef } from './TerminalDisplay.types';
|
|
26
|
+
import { terminalDisplayStyles, terminalDisplayVariants } from './TerminalDisplay.styles';
|
|
27
|
+
import { TerminalPanelChrome } from './panel/TerminalPanelChrome';
|
|
28
|
+
import { getSynthwaveGhosttyTheme, xtermThemeToGhostty } from './Terminal.theme.restty';
|
|
29
|
+
import { cn } from '@/react-ui/lib/utils';
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* TerminalDisplay — Readonly restty terminal for displaying ANSI content.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```tsx
|
|
36
|
+
* <TerminalDisplay
|
|
37
|
+
* content={"\x1b[31mError:\x1b[0m Something failed"}
|
|
38
|
+
* title="Error Output"
|
|
39
|
+
* variant="error"
|
|
40
|
+
* fontSize={12}
|
|
41
|
+
* />
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```tsx
|
|
46
|
+
* // Without chrome shell
|
|
47
|
+
* <TerminalDisplay
|
|
48
|
+
* content={ansiOutput}
|
|
49
|
+
* chrome={false}
|
|
50
|
+
* minHeight={100}
|
|
51
|
+
* />
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```tsx
|
|
56
|
+
* // With imperative handle
|
|
57
|
+
* const ref = useRef<ITerminalDisplayRef>(null);
|
|
58
|
+
* ref.current?.write("Additional output\r\n");
|
|
59
|
+
* ref.current?.clear();
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export const TerminalDisplay = forwardRef<ITerminalDisplayRef, ITerminalDisplayProps>(
|
|
63
|
+
(
|
|
64
|
+
{
|
|
65
|
+
content,
|
|
66
|
+
title = 'Output',
|
|
67
|
+
variant = 'default',
|
|
68
|
+
chrome = true,
|
|
69
|
+
fontSize = 13,
|
|
70
|
+
minHeight = 200,
|
|
71
|
+
theme,
|
|
72
|
+
resttyThemeName,
|
|
73
|
+
gpuRenderer = 'auto',
|
|
74
|
+
slots,
|
|
75
|
+
className,
|
|
76
|
+
emptyText,
|
|
77
|
+
onReady,
|
|
78
|
+
},
|
|
79
|
+
ref,
|
|
80
|
+
) => {
|
|
81
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
82
|
+
const resttyRef = useRef<Restty | null>(null);
|
|
83
|
+
const [isReady, setIsReady] = useState(false);
|
|
84
|
+
|
|
85
|
+
// Store callbacks in refs
|
|
86
|
+
const callbacksRef = useRef({ onReady });
|
|
87
|
+
callbacksRef.current = { onReady };
|
|
88
|
+
|
|
89
|
+
// Store content in ref to avoid re-creating restty on content change
|
|
90
|
+
const contentRef = useRef(content);
|
|
91
|
+
contentRef.current = content;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Initialize restty on mount.
|
|
95
|
+
* Dynamic import for SSR safety and code-splitting.
|
|
96
|
+
*/
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
if (!containerRef.current) return;
|
|
99
|
+
let destroyed = false;
|
|
100
|
+
|
|
101
|
+
const init = async () => {
|
|
102
|
+
const { Restty: ResttyClass, getBuiltinTheme } = await import('restty');
|
|
103
|
+
if (destroyed || !containerRef.current) return;
|
|
104
|
+
|
|
105
|
+
const restty = new ResttyClass({
|
|
106
|
+
root: containerRef.current,
|
|
107
|
+
appOptions: {
|
|
108
|
+
renderer: gpuRenderer,
|
|
109
|
+
fontSize,
|
|
110
|
+
autoResize: true,
|
|
111
|
+
},
|
|
112
|
+
fontSources: [
|
|
113
|
+
{
|
|
114
|
+
type: 'local',
|
|
115
|
+
matchers: [
|
|
116
|
+
'jetbrains mono',
|
|
117
|
+
'fira code',
|
|
118
|
+
'sf mono',
|
|
119
|
+
'cascadia code',
|
|
120
|
+
'meslo',
|
|
121
|
+
],
|
|
122
|
+
},
|
|
123
|
+
],
|
|
124
|
+
createInitialPane: true,
|
|
125
|
+
shortcuts: false,
|
|
126
|
+
defaultContextMenu: false,
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
resttyRef.current = restty;
|
|
130
|
+
|
|
131
|
+
// Apply theme
|
|
132
|
+
if (resttyThemeName) {
|
|
133
|
+
const builtinTheme = getBuiltinTheme(resttyThemeName);
|
|
134
|
+
if (builtinTheme) restty.applyTheme(builtinTheme);
|
|
135
|
+
} else if (theme) {
|
|
136
|
+
restty.applyTheme(xtermThemeToGhostty(theme));
|
|
137
|
+
} else {
|
|
138
|
+
restty.applyTheme(getSynthwaveGhosttyTheme());
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Wait for WASM to be ready before writing content.
|
|
142
|
+
// Restty loads WASM async internally — panes() returns empty until ready.
|
|
143
|
+
const waitForWasm = () => {
|
|
144
|
+
if (destroyed) return;
|
|
145
|
+
const panes = restty.panes();
|
|
146
|
+
if (panes && panes.length > 0) {
|
|
147
|
+
// WASM loaded, pane created — safe to write
|
|
148
|
+
if (contentRef.current) {
|
|
149
|
+
restty.sendInput(contentRef.current, 'pty');
|
|
150
|
+
}
|
|
151
|
+
setIsReady(true);
|
|
152
|
+
callbacksRef.current.onReady?.(restty);
|
|
153
|
+
} else {
|
|
154
|
+
// Not ready yet, retry
|
|
155
|
+
requestAnimationFrame(waitForWasm);
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
requestAnimationFrame(waitForWasm);
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
init().catch(() => {
|
|
162
|
+
// Silently fail — container will show empty
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
return () => {
|
|
166
|
+
destroyed = true;
|
|
167
|
+
resttyRef.current?.destroy();
|
|
168
|
+
resttyRef.current = null;
|
|
169
|
+
setIsReady(false);
|
|
170
|
+
};
|
|
171
|
+
}, []); // Mount once
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Re-write content when it changes after initialization.
|
|
175
|
+
*/
|
|
176
|
+
useEffect(() => {
|
|
177
|
+
if (!isReady || !resttyRef.current) return;
|
|
178
|
+
resttyRef.current.clearScreen();
|
|
179
|
+
if (content) {
|
|
180
|
+
resttyRef.current.sendInput(content, 'pty');
|
|
181
|
+
}
|
|
182
|
+
}, [content, isReady]);
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Handle fontSize changes after initialization.
|
|
186
|
+
*/
|
|
187
|
+
useEffect(() => {
|
|
188
|
+
if (!isReady || !resttyRef.current) return;
|
|
189
|
+
resttyRef.current.setFontSize(fontSize);
|
|
190
|
+
}, [fontSize, isReady]);
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Expose imperative handle.
|
|
194
|
+
*/
|
|
195
|
+
useImperativeHandle(ref, () => ({
|
|
196
|
+
getRestty: () => resttyRef.current,
|
|
197
|
+
clear: () => resttyRef.current?.clearScreen(),
|
|
198
|
+
write: (data: string) => resttyRef.current?.sendInput(data, 'pty'),
|
|
199
|
+
}));
|
|
200
|
+
|
|
201
|
+
/** Map variant to chrome variant */
|
|
202
|
+
const chromeVariant = variant === 'error' ? 'error' : 'default';
|
|
203
|
+
const chromeSize = variant === 'compact' ? 'compact' : 'default';
|
|
204
|
+
|
|
205
|
+
/** The terminal content area */
|
|
206
|
+
const terminalElement = (
|
|
207
|
+
<div
|
|
208
|
+
className={cn(
|
|
209
|
+
terminalDisplayVariants({ variant }),
|
|
210
|
+
slots?.root,
|
|
211
|
+
className,
|
|
212
|
+
)}
|
|
213
|
+
style={{ minHeight: `${minHeight}px` }}
|
|
214
|
+
>
|
|
215
|
+
{/* Empty state */}
|
|
216
|
+
{!content && emptyText && (
|
|
217
|
+
<div
|
|
218
|
+
className={cn(terminalDisplayStyles.emptyState, slots?.emptyState)}
|
|
219
|
+
style={{ minHeight: `${minHeight}px` }}
|
|
220
|
+
>
|
|
221
|
+
{emptyText}
|
|
222
|
+
</div>
|
|
223
|
+
)}
|
|
224
|
+
|
|
225
|
+
{/* Restty container */}
|
|
226
|
+
<div
|
|
227
|
+
ref={containerRef}
|
|
228
|
+
className={cn(terminalDisplayStyles.terminal, slots?.terminal)}
|
|
229
|
+
style={{
|
|
230
|
+
minHeight: `${minHeight}px`,
|
|
231
|
+
display: !content && emptyText ? 'none' : undefined,
|
|
232
|
+
}}
|
|
233
|
+
/>
|
|
234
|
+
</div>
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
if (!chrome) return terminalElement;
|
|
238
|
+
|
|
239
|
+
return (
|
|
240
|
+
<TerminalPanelChrome
|
|
241
|
+
containerName={title}
|
|
242
|
+
isConnected={isReady}
|
|
243
|
+
variant={chromeVariant}
|
|
244
|
+
size={chromeSize}
|
|
245
|
+
slots={{ root: slots?.chrome }}
|
|
246
|
+
className={className}
|
|
247
|
+
>
|
|
248
|
+
{terminalElement}
|
|
249
|
+
</TerminalPanelChrome>
|
|
250
|
+
);
|
|
251
|
+
},
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
TerminalDisplay.displayName = 'TerminalDisplay';
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TerminalDisplay component types.
|
|
3
|
+
*
|
|
4
|
+
* Readonly GPU-rendered terminal for displaying ANSI-formatted text
|
|
5
|
+
* without PTY connection, using restty.
|
|
6
|
+
*
|
|
7
|
+
* @module components/devenv/terminal/TerminalDisplay.types
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { SlotOverrides } from '@/core/types';
|
|
11
|
+
import type { Restty } from 'restty';
|
|
12
|
+
import type { ITerminalTheme } from './Terminal.types';
|
|
13
|
+
|
|
14
|
+
/** Slot names for TerminalDisplay sub-regions */
|
|
15
|
+
export type TerminalDisplaySlot = 'root' | 'chrome' | 'terminal' | 'emptyState';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Props for TerminalDisplay component.
|
|
19
|
+
*/
|
|
20
|
+
export interface ITerminalDisplayProps {
|
|
21
|
+
/** ANSI-formatted string content to display */
|
|
22
|
+
content: string;
|
|
23
|
+
|
|
24
|
+
/** Title shown in the chrome header */
|
|
25
|
+
title?: string;
|
|
26
|
+
|
|
27
|
+
/** Visual variant — 'error' uses red accent line */
|
|
28
|
+
variant?: 'default' | 'compact' | 'error';
|
|
29
|
+
|
|
30
|
+
/** Whether to show the glassmorphism chrome shell (default: true) */
|
|
31
|
+
chrome?: boolean;
|
|
32
|
+
|
|
33
|
+
/** Font size in CSS pixels (default: 13) */
|
|
34
|
+
fontSize?: number;
|
|
35
|
+
|
|
36
|
+
/** Minimum height in CSS pixels (default: 200) */
|
|
37
|
+
minHeight?: number;
|
|
38
|
+
|
|
39
|
+
/** Terminal theme in xterm.js format (auto-converted to Ghostty) */
|
|
40
|
+
theme?: ITerminalTheme;
|
|
41
|
+
|
|
42
|
+
/** Restty built-in theme name from the 458-theme catalog */
|
|
43
|
+
resttyThemeName?: string;
|
|
44
|
+
|
|
45
|
+
/** GPU renderer preference (default: 'auto') */
|
|
46
|
+
gpuRenderer?: 'auto' | 'webgpu' | 'webgl2';
|
|
47
|
+
|
|
48
|
+
/** Slot class overrides for each visual region */
|
|
49
|
+
slots?: SlotOverrides<TerminalDisplaySlot>;
|
|
50
|
+
|
|
51
|
+
/** Custom class name on root element */
|
|
52
|
+
className?: string;
|
|
53
|
+
|
|
54
|
+
/** Placeholder text when content is empty */
|
|
55
|
+
emptyText?: string;
|
|
56
|
+
|
|
57
|
+
/** Callback when restty instance is ready */
|
|
58
|
+
onReady?: (restty: Restty) => void;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Imperative handle for TerminalDisplay.
|
|
63
|
+
*/
|
|
64
|
+
export interface ITerminalDisplayRef {
|
|
65
|
+
/** Get the underlying Restty instance */
|
|
66
|
+
getRestty: () => Restty | null;
|
|
67
|
+
|
|
68
|
+
/** Clear the terminal display */
|
|
69
|
+
clear: () => void;
|
|
70
|
+
|
|
71
|
+
/** Write additional ANSI content (appends) */
|
|
72
|
+
write: (data: string) => void;
|
|
73
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal Chrome — lightweight barrel export.
|
|
3
|
+
*
|
|
4
|
+
* Exports only the glassmorphism shell components (no restty, no xterm).
|
|
5
|
+
* Use `@mks2508/mks-ui/react/blocks/Terminal/chrome` for zero terminal deps.
|
|
6
|
+
*
|
|
7
|
+
* @module @mks2508/mks-ui/react/blocks/Terminal/chrome
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// Chrome shell
|
|
11
|
+
export { TerminalPanelChrome, NOISE_TEXTURE_SVG, terminalScrollStyles } from './panel/TerminalPanelChrome';
|
|
12
|
+
export { TerminalPanelHeader } from './panel/TerminalPanelHeader';
|
|
13
|
+
export { TerminalPanelFooter } from './panel/TerminalPanelFooter';
|
|
14
|
+
|
|
15
|
+
// Chrome styles + variants
|
|
16
|
+
export {
|
|
17
|
+
terminalChromeStyles,
|
|
18
|
+
terminalChromeVariants,
|
|
19
|
+
ACCENT_GRADIENTS,
|
|
20
|
+
type TerminalChromeSlot,
|
|
21
|
+
type TerminalChromeVariantProps,
|
|
22
|
+
} from './panel/TerminalPanelChrome.styles';
|
|
23
|
+
|
|
24
|
+
// Chrome types
|
|
25
|
+
export type { ITerminalPanelChromeProps } from './panel/TerminalPanelChrome.types';
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal Display — lightweight barrel export.
|
|
3
|
+
*
|
|
4
|
+
* Exports the readonly TerminalDisplay component + restty wrapper + chrome.
|
|
5
|
+
* Depends on restty only (not xterm, not shiki, not xterm addons).
|
|
6
|
+
* Use `@mks2508/mks-ui/react/blocks/Terminal/display` for minimal deps.
|
|
7
|
+
*
|
|
8
|
+
* @module @mks2508/mks-ui/react/blocks/Terminal/display
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// TerminalDisplay (readonly restty terminal)
|
|
12
|
+
export { TerminalDisplay } from './TerminalDisplay';
|
|
13
|
+
export {
|
|
14
|
+
terminalDisplayStyles,
|
|
15
|
+
terminalDisplayVariants,
|
|
16
|
+
type TerminalDisplayVariantProps,
|
|
17
|
+
} from './TerminalDisplay.styles';
|
|
18
|
+
export type {
|
|
19
|
+
ITerminalDisplayProps,
|
|
20
|
+
ITerminalDisplayRef,
|
|
21
|
+
TerminalDisplaySlot,
|
|
22
|
+
} from './TerminalDisplay.types';
|
|
23
|
+
|
|
24
|
+
// Restty React wrapper (for advanced use)
|
|
25
|
+
export { TerminalRestty } from './TerminalRestty';
|
|
26
|
+
export type { ITerminalResttyProps, ITerminalResttyRef } from './TerminalRestty';
|
|
27
|
+
|
|
28
|
+
// Chrome (re-exported for convenience)
|
|
29
|
+
export { TerminalPanelChrome, NOISE_TEXTURE_SVG, terminalScrollStyles } from './panel/TerminalPanelChrome';
|
|
30
|
+
export type { ITerminalPanelChromeProps } from './panel/TerminalPanelChrome.types';
|
|
31
|
+
export {
|
|
32
|
+
terminalChromeStyles,
|
|
33
|
+
terminalChromeVariants,
|
|
34
|
+
ACCENT_GRADIENTS,
|
|
35
|
+
type TerminalChromeSlot,
|
|
36
|
+
} from './panel/TerminalPanelChrome.styles';
|
|
37
|
+
|
|
38
|
+
// Theme utilities (needed for display customization)
|
|
39
|
+
export { SYNTHWAVE_TERMINAL_THEME, getTerminalTheme } from './Terminal.theme';
|
|
40
|
+
export {
|
|
41
|
+
hexToResttyColor,
|
|
42
|
+
xtermThemeToGhostty,
|
|
43
|
+
getSynthwaveGhosttyTheme,
|
|
44
|
+
type IResttyThemeColor,
|
|
45
|
+
type IResttyGhosttyTheme,
|
|
46
|
+
} from './Terminal.theme.restty';
|
|
@@ -101,3 +101,11 @@ export type {
|
|
|
101
101
|
} from './panel/TerminalLogsPanel.types';
|
|
102
102
|
export type { ILogLinesViewerProps } from './panel/LogLinesViewer';
|
|
103
103
|
export type { TLogLevelFilter } from './parsing/LogParser.types';
|
|
104
|
+
|
|
105
|
+
// TerminalDisplay (lightweight readonly restty terminal)
|
|
106
|
+
export { TerminalDisplay } from './TerminalDisplay';
|
|
107
|
+
export type { ITerminalDisplayProps, ITerminalDisplayRef, TerminalDisplaySlot } from './TerminalDisplay.types';
|
|
108
|
+
export { terminalDisplayStyles, terminalDisplayVariants, type TerminalDisplayVariantProps } from './TerminalDisplay.styles';
|
|
109
|
+
|
|
110
|
+
// Chrome StyleSlots + CVA variants
|
|
111
|
+
export { terminalChromeStyles, terminalChromeVariants, ACCENT_GRADIENTS, type TerminalChromeSlot, type TerminalChromeVariantProps } from './panel/TerminalPanelChrome.styles';
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TerminalPanelChrome style definitions.
|
|
3
|
+
*
|
|
4
|
+
* StyleSlots + CVA variants for the Ghostty-inspired glassmorphism shell.
|
|
5
|
+
* Follows the mks-ui composable pattern: base styles via StyleSlots,
|
|
6
|
+
* visual variants via CVA, consumer overrides via SlotOverrides.
|
|
7
|
+
*
|
|
8
|
+
* @module components/devenv/terminal/panel/chrome/styles
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
12
|
+
import type { StyleSlots } from '@/core/types';
|
|
13
|
+
|
|
14
|
+
/** Slot names for TerminalPanelChrome sub-regions */
|
|
15
|
+
export type TerminalChromeSlot =
|
|
16
|
+
| 'root'
|
|
17
|
+
| 'accentLine'
|
|
18
|
+
| 'accentGradient'
|
|
19
|
+
| 'accentShimmer'
|
|
20
|
+
| 'header'
|
|
21
|
+
| 'sessionTabs'
|
|
22
|
+
| 'actionBar'
|
|
23
|
+
| 'content'
|
|
24
|
+
| 'footer';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Default style slots for each chrome sub-region.
|
|
28
|
+
*/
|
|
29
|
+
export const terminalChromeStyles: StyleSlots<TerminalChromeSlot> = {
|
|
30
|
+
root: 'glass-heavy glass-noise rounded-2xl overflow-hidden relative',
|
|
31
|
+
accentLine: 'absolute top-0 left-0 right-0 h-px z-10 pointer-events-none overflow-hidden',
|
|
32
|
+
accentGradient: 'h-full w-full',
|
|
33
|
+
accentShimmer: 'absolute inset-0 bg-gradient-to-r from-transparent via-white/40 to-transparent',
|
|
34
|
+
header: '',
|
|
35
|
+
sessionTabs: '',
|
|
36
|
+
actionBar: '',
|
|
37
|
+
content: '',
|
|
38
|
+
footer: '',
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Accent line gradient classes per variant.
|
|
43
|
+
*/
|
|
44
|
+
export const ACCENT_GRADIENTS = {
|
|
45
|
+
default: 'bg-gradient-to-r from-transparent via-primary/70 to-transparent shadow-[0_0_12px_hsla(330,85%,43%,0.5)]',
|
|
46
|
+
error: 'bg-gradient-to-r from-transparent via-destructive/70 to-transparent shadow-[0_0_12px_hsla(0,72%,51%,0.5)]',
|
|
47
|
+
minimal: '',
|
|
48
|
+
} as const;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* CVA variants for the chrome root element.
|
|
52
|
+
*/
|
|
53
|
+
export const terminalChromeVariants = cva(terminalChromeStyles.root, {
|
|
54
|
+
variants: {
|
|
55
|
+
variant: {
|
|
56
|
+
/** Default: magenta accent line, full glassmorphism */
|
|
57
|
+
default: '',
|
|
58
|
+
/** Minimal: no accent line, no noise texture, simpler rounding */
|
|
59
|
+
minimal: 'rounded-lg',
|
|
60
|
+
/** Error: red/destructive accent line instead of magenta */
|
|
61
|
+
error: '',
|
|
62
|
+
},
|
|
63
|
+
size: {
|
|
64
|
+
default: '',
|
|
65
|
+
compact: 'rounded-xl',
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
defaultVariants: {
|
|
69
|
+
variant: 'default',
|
|
70
|
+
size: 'default',
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
/** Extracted variant props type for consumer use */
|
|
75
|
+
export type TerminalChromeVariantProps = VariantProps<typeof terminalChromeVariants>;
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* - macOS-style header (TerminalPanelHeader)
|
|
13
13
|
* - Slots for action bar, children (terminal content), and footer
|
|
14
14
|
* - Neon magenta scrollbar styles
|
|
15
|
+
* - StyleSlots + CVA variants for customization
|
|
15
16
|
*
|
|
16
17
|
* @module components/devenv/terminal/panel/chrome
|
|
17
18
|
*/
|
|
@@ -19,6 +20,11 @@
|
|
|
19
20
|
'use client';
|
|
20
21
|
|
|
21
22
|
import type { ITerminalPanelChromeProps } from './TerminalPanelChrome.types';
|
|
23
|
+
import {
|
|
24
|
+
terminalChromeStyles,
|
|
25
|
+
terminalChromeVariants,
|
|
26
|
+
ACCENT_GRADIENTS,
|
|
27
|
+
} from './TerminalPanelChrome.styles';
|
|
22
28
|
import { TerminalPanelHeader } from './TerminalPanelHeader';
|
|
23
29
|
import { TerminalSessionTabs } from './TerminalSessionTabs';
|
|
24
30
|
import { cn } from '@/react-ui/lib/utils';
|
|
@@ -129,16 +135,16 @@ export const terminalScrollStyles = `
|
|
|
129
135
|
* consistent visual chrome. Used by both TerminalLogsPanel (readonly)
|
|
130
136
|
* and TerminalInteractivePanel (interactive).
|
|
131
137
|
*
|
|
138
|
+
* Supports StyleSlots for class overrides and CVA variants
|
|
139
|
+
* for visual presets (default, minimal, error).
|
|
140
|
+
*
|
|
132
141
|
* @example
|
|
133
142
|
* ```tsx
|
|
134
143
|
* <TerminalPanelChrome
|
|
135
144
|
* containerName="devenv-agent-backend"
|
|
136
145
|
* isConnected={true}
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
* onSessionTabClick={(id) => setActiveSession(id)}
|
|
140
|
-
* onSessionClose={(id) => closeSession(id)}
|
|
141
|
-
* onNewSession={() => createSession()}
|
|
146
|
+
* variant="error"
|
|
147
|
+
* slots={{ root: 'max-h-[400px]', content: 'p-2' }}
|
|
142
148
|
* actionBar={<TerminalFilterTabs ... />}
|
|
143
149
|
* footer={<TerminalPanelFooter ... />}
|
|
144
150
|
* >
|
|
@@ -149,6 +155,8 @@ export const terminalScrollStyles = `
|
|
|
149
155
|
export function TerminalPanelChrome({
|
|
150
156
|
containerName,
|
|
151
157
|
isConnected,
|
|
158
|
+
variant = 'default',
|
|
159
|
+
size = 'default',
|
|
152
160
|
viewMode = 'terminal',
|
|
153
161
|
onViewModeChange,
|
|
154
162
|
sessions,
|
|
@@ -165,6 +173,7 @@ export function TerminalPanelChrome({
|
|
|
165
173
|
onMinimize,
|
|
166
174
|
onMaximize,
|
|
167
175
|
crtEffect,
|
|
176
|
+
slots,
|
|
168
177
|
className,
|
|
169
178
|
}: ITerminalPanelChromeProps) {
|
|
170
179
|
/** Whether to render session tabs (multi-session mode) */
|
|
@@ -172,63 +181,83 @@ export function TerminalPanelChrome({
|
|
|
172
181
|
(sessions && sessions.length > 0) ||
|
|
173
182
|
(availableContainers && availableContainers.length > 0);
|
|
174
183
|
|
|
184
|
+
/** Whether to show the accent line (hidden in minimal variant) */
|
|
185
|
+
const showAccentLine = variant !== 'minimal';
|
|
186
|
+
|
|
187
|
+
/** Accent gradient based on variant */
|
|
188
|
+
const accentGradient = ACCENT_GRADIENTS[variant ?? 'default'] ?? ACCENT_GRADIENTS.default;
|
|
189
|
+
|
|
175
190
|
return (
|
|
176
191
|
<div
|
|
177
192
|
className={cn(
|
|
178
|
-
|
|
179
|
-
|
|
193
|
+
terminalChromeVariants({ variant, size }),
|
|
194
|
+
slots?.root,
|
|
195
|
+
className,
|
|
180
196
|
)}
|
|
181
197
|
>
|
|
182
198
|
{/* Animated top accent line with shimmer */}
|
|
183
|
-
|
|
184
|
-
<div
|
|
185
|
-
className=
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
199
|
+
{showAccentLine && (
|
|
200
|
+
<div className={cn(terminalChromeStyles.accentLine, slots?.accentLine)}>
|
|
201
|
+
<div className={cn(accentGradient, slots?.accentGradient)} />
|
|
202
|
+
<div
|
|
203
|
+
className={cn(terminalChromeStyles.accentShimmer, slots?.accentShimmer)}
|
|
204
|
+
style={{
|
|
205
|
+
backgroundSize: '200% 100%',
|
|
206
|
+
animation: 'shimmer-line 4s ease-in-out infinite',
|
|
207
|
+
}}
|
|
208
|
+
/>
|
|
209
|
+
</div>
|
|
210
|
+
)}
|
|
195
211
|
|
|
196
212
|
{/* Session Tabs */}
|
|
197
213
|
{showSessionTabs && (
|
|
198
|
-
<
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
214
|
+
<div className={cn(slots?.sessionTabs)}>
|
|
215
|
+
<TerminalSessionTabs
|
|
216
|
+
sessions={sessions || []}
|
|
217
|
+
activeSessionId={activeSessionId || null}
|
|
218
|
+
onTabClick={(sessionId) => onSessionTabClick?.(sessionId)}
|
|
219
|
+
onClose={(sessionId) => onSessionClose?.(sessionId)}
|
|
220
|
+
onNewSession={onNewSession}
|
|
221
|
+
availableContainers={availableContainers}
|
|
222
|
+
onAddContainer={onAddContainer}
|
|
223
|
+
/>
|
|
224
|
+
</div>
|
|
207
225
|
)}
|
|
208
226
|
|
|
209
227
|
{/* Header */}
|
|
210
|
-
<
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
228
|
+
<div className={cn(slots?.header)}>
|
|
229
|
+
<TerminalPanelHeader
|
|
230
|
+
containerName={containerName}
|
|
231
|
+
isConnected={isConnected}
|
|
232
|
+
viewMode={viewMode}
|
|
233
|
+
onViewModeChange={onViewModeChange}
|
|
234
|
+
onClose={onClose}
|
|
235
|
+
onMinimize={onMinimize}
|
|
236
|
+
onMaximize={onMaximize}
|
|
237
|
+
/>
|
|
238
|
+
</div>
|
|
219
239
|
|
|
220
240
|
{/* Action Bar Slot */}
|
|
221
|
-
{actionBar
|
|
241
|
+
{actionBar && (
|
|
242
|
+
<div className={cn(slots?.actionBar)}>
|
|
243
|
+
{actionBar}
|
|
244
|
+
</div>
|
|
245
|
+
)}
|
|
222
246
|
|
|
223
247
|
{/* Terminal Content - with optional CRT effects */}
|
|
224
248
|
<div className={cn(
|
|
225
|
-
crtEffect && 'terminal-crt terminal-bloom'
|
|
249
|
+
crtEffect && 'terminal-crt terminal-bloom',
|
|
250
|
+
slots?.content,
|
|
226
251
|
)}>
|
|
227
252
|
{children}
|
|
228
253
|
</div>
|
|
229
254
|
|
|
230
255
|
{/* Footer Slot */}
|
|
231
|
-
{footer
|
|
256
|
+
{footer && (
|
|
257
|
+
<div className={cn(slots?.footer)}>
|
|
258
|
+
{footer}
|
|
259
|
+
</div>
|
|
260
|
+
)}
|
|
232
261
|
|
|
233
262
|
{/* Terminal scroll styles */}
|
|
234
263
|
<style>{terminalScrollStyles}</style>
|