@aixnn/aixautots 0.0.0-stage → 0.5.3

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.
@@ -0,0 +1,175 @@
1
+ import { toNormalizedPointClamped, classifyDrag, mapKey } from './chunk-NWFYTFMI.js';
2
+ import { useRef, useEffect, useCallback } from 'react';
3
+ import { jsx, jsxs } from 'react/jsx-runtime';
4
+
5
+ var TOUCH_MOVE_THROTTLE_MS = 30;
6
+ function MirrorView({
7
+ stream,
8
+ deviceSize,
9
+ onInput,
10
+ keyboard = true,
11
+ autoFocus = true,
12
+ onFirstFrame,
13
+ onResize,
14
+ continuousTouch = false,
15
+ className
16
+ }) {
17
+ const videoRef = useRef(null);
18
+ const downRef = useRef(null);
19
+ const gestureActiveRef = useRef(false);
20
+ const lastMoveSentRef = useRef(0);
21
+ const firstFrameRef = useRef(false);
22
+ useEffect(() => {
23
+ const v = videoRef.current;
24
+ if (v) v.srcObject = stream;
25
+ firstFrameRef.current = false;
26
+ }, [stream]);
27
+ const handleFrameReady = useCallback(() => {
28
+ if (firstFrameRef.current) return;
29
+ const v = videoRef.current;
30
+ if (!v || v.videoWidth === 0) return;
31
+ firstFrameRef.current = true;
32
+ onFirstFrame?.({ width: v.videoWidth, height: v.videoHeight });
33
+ }, [onFirstFrame]);
34
+ const handleResize = useCallback(() => {
35
+ const v = videoRef.current;
36
+ if (!v || v.videoWidth === 0) return;
37
+ onResize?.({ width: v.videoWidth, height: v.videoHeight });
38
+ }, [onResize]);
39
+ useEffect(() => {
40
+ const v = videoRef.current;
41
+ if (!v) return;
42
+ v.addEventListener("resize", handleResize);
43
+ return () => v.removeEventListener("resize", handleResize);
44
+ }, [handleResize, stream]);
45
+ useEffect(() => {
46
+ if (autoFocus) videoRef.current?.focus();
47
+ }, [autoFocus, stream]);
48
+ const clampedPoint = useCallback(
49
+ (e) => {
50
+ const r = e.currentTarget.getBoundingClientRect();
51
+ const box = { left: r.left, top: r.top, width: r.width, height: r.height };
52
+ return toNormalizedPointClamped({ clientX: e.clientX, clientY: e.clientY }, box, deviceSize);
53
+ },
54
+ [deviceSize]
55
+ );
56
+ const handlePointerDown = useCallback((e) => {
57
+ if (!onInput) return;
58
+ e.currentTarget.focus();
59
+ try {
60
+ e.currentTarget.setPointerCapture(e.pointerId);
61
+ } catch {
62
+ }
63
+ if (continuousTouch) {
64
+ gestureActiveRef.current = true;
65
+ lastMoveSentRef.current = 0;
66
+ const p = clampedPoint(e);
67
+ if (p) onInput({ t: "touch_down", x: p.x, y: p.y });
68
+ return;
69
+ }
70
+ downRef.current = { clientX: e.clientX, clientY: e.clientY, t: e.timeStamp };
71
+ }, [onInput, continuousTouch, clampedPoint]);
72
+ const handlePointerMove = useCallback((e) => {
73
+ if (!onInput || !continuousTouch || !gestureActiveRef.current) return;
74
+ const now = Date.now();
75
+ if (now - lastMoveSentRef.current < TOUCH_MOVE_THROTTLE_MS) return;
76
+ lastMoveSentRef.current = now;
77
+ const p = clampedPoint(e);
78
+ if (p) onInput({ t: "touch_move", x: p.x, y: p.y });
79
+ }, [onInput, continuousTouch, clampedPoint]);
80
+ const handlePointerUp = useCallback((e) => {
81
+ if (!onInput) return;
82
+ if (continuousTouch) {
83
+ if (!gestureActiveRef.current) return;
84
+ gestureActiveRef.current = false;
85
+ const p = clampedPoint(e);
86
+ if (p) onInput({ t: "touch_up", x: p.x, y: p.y });
87
+ return;
88
+ }
89
+ const start = downRef.current;
90
+ downRef.current = null;
91
+ if (!start) return;
92
+ const box = e.currentTarget.getBoundingClientRect();
93
+ const msg = classifyDrag(
94
+ start,
95
+ { clientX: e.clientX, clientY: e.clientY, t: e.timeStamp },
96
+ { left: box.left, top: box.top, width: box.width, height: box.height },
97
+ deviceSize
98
+ );
99
+ if (msg) onInput(msg);
100
+ }, [onInput, continuousTouch, deviceSize, clampedPoint]);
101
+ const handleKeyDown = useCallback((e) => {
102
+ if (!onInput || !keyboard) return;
103
+ const msg = mapKey(e);
104
+ if (msg) {
105
+ e.preventDefault();
106
+ onInput(msg);
107
+ }
108
+ }, [onInput, keyboard]);
109
+ return /* @__PURE__ */ jsx(
110
+ "video",
111
+ {
112
+ ref: videoRef,
113
+ autoPlay: true,
114
+ playsInline: true,
115
+ muted: true,
116
+ tabIndex: keyboard ? 0 : -1,
117
+ className,
118
+ onPointerDown: handlePointerDown,
119
+ onPointerMove: handlePointerMove,
120
+ onPointerUp: handlePointerUp,
121
+ onPointerCancel: handlePointerUp,
122
+ onKeyDown: handleKeyDown,
123
+ onLoadedData: handleFrameReady,
124
+ onPlaying: handleFrameReady,
125
+ style: {
126
+ background: "var(--aix-editor-bg, #000)",
127
+ borderRadius: "var(--aix-radius, 6px)",
128
+ width: "100%",
129
+ objectFit: "contain",
130
+ touchAction: "none",
131
+ outline: "none"
132
+ }
133
+ }
134
+ );
135
+ }
136
+ var btn = {
137
+ background: "var(--aix-accent, #2d6cdf)",
138
+ color: "#fff",
139
+ border: "none",
140
+ borderRadius: "var(--aix-radius, 6px)",
141
+ padding: "4px 12px",
142
+ cursor: "pointer",
143
+ display: "inline-flex",
144
+ alignItems: "center",
145
+ justifyContent: "center"
146
+ };
147
+ var iconProps = {
148
+ width: 18,
149
+ height: 18,
150
+ viewBox: "0 0 24 24",
151
+ fill: "none",
152
+ stroke: "currentColor",
153
+ strokeWidth: 1.8,
154
+ strokeLinecap: "round",
155
+ strokeLinejoin: "round"
156
+ };
157
+ var AndroidBack = () => /* @__PURE__ */ jsx("svg", { ...iconProps, "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M15.5 5 L7.5 12 L15.5 19 Z" }) });
158
+ var AndroidHome = () => /* @__PURE__ */ jsx("svg", { ...iconProps, "aria-hidden": true, children: /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "6.5" }) });
159
+ var AndroidMenu = () => /* @__PURE__ */ jsx("svg", { ...iconProps, "aria-hidden": true, children: /* @__PURE__ */ jsx("rect", { x: "7", y: "7", width: "10", height: "10", rx: "1.5" }) });
160
+ var IosBack = () => /* @__PURE__ */ jsx("svg", { ...iconProps, "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M14.5 5 L8.5 12 L14.5 19" }) });
161
+ var IosHome = () => /* @__PURE__ */ jsxs("svg", { ...iconProps, "aria-hidden": true, children: [
162
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "8.5" }),
163
+ /* @__PURE__ */ jsx("rect", { x: "8.5", y: "8.5", width: "7", height: "7", rx: "1.5" })
164
+ ] });
165
+ function ControlBar({ platform = "android", onHome, onBack, onMenu, onScreenshot, className }) {
166
+ const android = platform === "android";
167
+ return /* @__PURE__ */ jsxs("div", { className, style: { display: "flex", gap: 8, padding: 8, background: "var(--aix-bg, #161616)", borderRadius: "var(--aix-radius, 6px)" }, children: [
168
+ onBack && /* @__PURE__ */ jsx("button", { type: "button", onClick: onBack, style: btn, "aria-label": "Back", title: "Back", children: android ? /* @__PURE__ */ jsx(AndroidBack, {}) : /* @__PURE__ */ jsx(IosBack, {}) }),
169
+ onHome && /* @__PURE__ */ jsx("button", { type: "button", onClick: onHome, style: btn, "aria-label": "Home", title: "Home", children: android ? /* @__PURE__ */ jsx(AndroidHome, {}) : /* @__PURE__ */ jsx(IosHome, {}) }),
170
+ android && onMenu && /* @__PURE__ */ jsx("button", { type: "button", onClick: onMenu, style: btn, "aria-label": "Menu", title: "Menu", children: /* @__PURE__ */ jsx(AndroidMenu, {}) }),
171
+ onScreenshot && /* @__PURE__ */ jsx("button", { type: "button", onClick: onScreenshot, style: btn, children: "Screenshot" })
172
+ ] });
173
+ }
174
+
175
+ export { ControlBar, MirrorView };
@@ -0,0 +1,273 @@
1
+ import { clsx } from 'clsx';
2
+ import { twMerge } from 'tailwind-merge';
3
+ import * as DialogPrimitive from '@radix-ui/react-dialog';
4
+ import { X, CheckCircle2, XCircle, Info, ChevronDown } from 'lucide-react';
5
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
+ import { forwardRef, useState, useCallback, useEffect, useRef } from 'react';
7
+ import { cva } from 'class-variance-authority';
8
+
9
+ // src/ui/primitives/utils.ts
10
+ function cn(...inputs) {
11
+ return twMerge(clsx(inputs));
12
+ }
13
+ function Dialog({
14
+ open,
15
+ onClose,
16
+ title,
17
+ description,
18
+ children,
19
+ maxWidth = "max-w-md"
20
+ }) {
21
+ return /* @__PURE__ */ jsx(DialogPrimitive.Root, { open, onOpenChange: onClose, children: /* @__PURE__ */ jsxs(DialogPrimitive.Portal, { children: [
22
+ /* @__PURE__ */ jsx(DialogPrimitive.Overlay, { className: "fixed inset-0 bg-black/50 z-40" }),
23
+ /* @__PURE__ */ jsxs(
24
+ DialogPrimitive.Content,
25
+ {
26
+ className: cn(
27
+ "fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-card border border-border rounded-lg p-6 w-full z-50 shadow-xl",
28
+ maxWidth
29
+ ),
30
+ children: [
31
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between mb-4", children: [
32
+ /* @__PURE__ */ jsxs("div", { children: [
33
+ title && /* @__PURE__ */ jsx(DialogPrimitive.Title, { className: "text-sm font-semibold", children: title }),
34
+ description && /* @__PURE__ */ jsx(DialogPrimitive.Description, { className: "text-xs text-muted-foreground mt-1", children: description })
35
+ ] }),
36
+ /* @__PURE__ */ jsx(DialogPrimitive.Close, { className: "p-1 rounded hover:bg-secondary transition-colors", children: /* @__PURE__ */ jsx(X, { className: "w-4 h-4 text-muted-foreground" }) })
37
+ ] }),
38
+ children
39
+ ]
40
+ }
41
+ )
42
+ ] }) });
43
+ }
44
+ function Drawer({ open, onClose, title, children, widthClass = "max-w-lg" }) {
45
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
46
+ /* @__PURE__ */ jsx(
47
+ "div",
48
+ {
49
+ className: cn(
50
+ "fixed inset-0 z-[55] bg-black/40 transition-opacity duration-300",
51
+ open ? "opacity-100" : "pointer-events-none opacity-0"
52
+ ),
53
+ onClick: onClose
54
+ }
55
+ ),
56
+ /* @__PURE__ */ jsxs(
57
+ "div",
58
+ {
59
+ className: cn(
60
+ "fixed right-0 top-0 z-[56] flex h-full w-full flex-col border-l border-border bg-card transition-transform duration-300 ease-in-out",
61
+ widthClass,
62
+ open ? "translate-x-0" : "translate-x-full"
63
+ ),
64
+ role: "dialog",
65
+ children: [
66
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b border-border px-4 py-3 shrink-0", children: [
67
+ /* @__PURE__ */ jsx("span", { className: "truncate text-sm font-semibold text-foreground", children: title }),
68
+ /* @__PURE__ */ jsx(
69
+ "button",
70
+ {
71
+ type: "button",
72
+ onClick: onClose,
73
+ className: "rounded p-1 text-muted-foreground hover:bg-secondary hover:text-foreground",
74
+ children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
75
+ }
76
+ )
77
+ ] }),
78
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto p-4", children })
79
+ ]
80
+ }
81
+ )
82
+ ] });
83
+ }
84
+ var _seq = 0;
85
+ function useToast() {
86
+ const [toasts, setToasts] = useState([]);
87
+ const dismiss = useCallback((id) => {
88
+ setToasts((list) => list.filter((x) => x.id !== id));
89
+ }, []);
90
+ const push = useCallback((kind, message) => {
91
+ const id = ++_seq;
92
+ setToasts((list) => [...list, { id, kind, message }]);
93
+ return id;
94
+ }, []);
95
+ const toast = {
96
+ success: (m) => push("success", m),
97
+ error: (m) => push("error", m),
98
+ info: (m) => push("info", m)
99
+ };
100
+ return { toasts, toast, dismiss };
101
+ }
102
+ function ToastViewport({
103
+ toasts,
104
+ onDismiss
105
+ }) {
106
+ if (toasts.length === 0) return null;
107
+ return /* @__PURE__ */ jsx("div", { className: "pointer-events-none fixed right-4 top-4 z-[80] flex max-w-[90vw] flex-col gap-2", children: toasts.map((item) => /* @__PURE__ */ jsx(ToastCard, { item, onDismiss }, item.id)) });
108
+ }
109
+ function ToastCard({ item, onDismiss }) {
110
+ useEffect(() => {
111
+ const ms = item.kind === "error" ? 6e3 : 3500;
112
+ const tm = setTimeout(() => onDismiss(item.id), ms);
113
+ return () => clearTimeout(tm);
114
+ }, [item, onDismiss]);
115
+ const Icon = item.kind === "success" ? CheckCircle2 : item.kind === "error" ? XCircle : Info;
116
+ const color = item.kind === "success" ? "text-success" : item.kind === "error" ? "text-destructive" : "text-primary";
117
+ return /* @__PURE__ */ jsxs("div", { className: "pointer-events-auto flex w-80 max-w-[90vw] items-start gap-2 rounded-lg border border-border bg-card px-3 py-2.5 shadow-xl", children: [
118
+ /* @__PURE__ */ jsx(Icon, { className: cn("mt-0.5 h-4 w-4 shrink-0", color) }),
119
+ /* @__PURE__ */ jsx("p", { className: "flex-1 break-words text-xs text-foreground", children: item.message }),
120
+ /* @__PURE__ */ jsx(
121
+ "button",
122
+ {
123
+ type: "button",
124
+ onClick: () => onDismiss(item.id),
125
+ className: "shrink-0 rounded p-0.5 text-muted-foreground hover:bg-secondary hover:text-foreground",
126
+ children: /* @__PURE__ */ jsx(X, { className: "h-3.5 w-3.5" })
127
+ }
128
+ )
129
+ ] });
130
+ }
131
+ var buttonVariants = cva(
132
+ "inline-flex items-center justify-center gap-1.5 rounded-md text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary disabled:pointer-events-none disabled:opacity-50",
133
+ {
134
+ variants: {
135
+ variant: {
136
+ primary: "bg-primary text-primary-foreground hover:bg-primary/90",
137
+ secondary: "bg-secondary text-foreground hover:bg-secondary/80",
138
+ destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
139
+ ghost: "hover:bg-secondary text-muted-foreground hover:text-foreground"
140
+ },
141
+ size: {
142
+ xs: "px-2 py-1 text-[11px]",
143
+ sm: "px-3 py-1.5",
144
+ md: "px-4 py-2",
145
+ icon: "p-1.5"
146
+ }
147
+ },
148
+ defaultVariants: {
149
+ variant: "primary",
150
+ size: "sm"
151
+ }
152
+ }
153
+ );
154
+ var Button = forwardRef(
155
+ ({ className, variant, size, ...props }, ref) => {
156
+ return /* @__PURE__ */ jsx(
157
+ "button",
158
+ {
159
+ className: cn(buttonVariants({ variant, size, className })),
160
+ ref,
161
+ ...props
162
+ }
163
+ );
164
+ }
165
+ );
166
+ Button.displayName = "Button";
167
+ function Select({
168
+ value,
169
+ onChange,
170
+ options,
171
+ placeholder = "Select...",
172
+ className,
173
+ disabled
174
+ }) {
175
+ return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
176
+ /* @__PURE__ */ jsxs(
177
+ "select",
178
+ {
179
+ value,
180
+ onChange: (e) => onChange(e.target.value),
181
+ disabled,
182
+ className: cn(
183
+ "w-full appearance-none rounded-md bg-secondary border border-border px-3 py-2 pr-8 text-xs outline-none transition-colors focus:border-primary cursor-pointer",
184
+ disabled && "cursor-not-allowed opacity-60",
185
+ className
186
+ ),
187
+ children: [
188
+ placeholder && /* @__PURE__ */ jsx("option", { value: "", disabled: true, children: placeholder }),
189
+ options.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: opt.label }, opt.value))
190
+ ]
191
+ }
192
+ ),
193
+ /* @__PURE__ */ jsx(ChevronDown, { className: "absolute right-2 top-1/2 -translate-y-1/2 w-3.5 h-3.5 text-muted-foreground pointer-events-none" })
194
+ ] });
195
+ }
196
+ var Input = forwardRef(
197
+ ({ className, icon, error, ...props }, ref) => {
198
+ return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
199
+ icon && /* @__PURE__ */ jsx("div", { className: "absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground", children: icon }),
200
+ /* @__PURE__ */ jsx(
201
+ "input",
202
+ {
203
+ className: cn(
204
+ "w-full rounded-md bg-secondary border border-border px-3 py-2 text-xs outline-none transition-colors placeholder:text-muted-foreground focus:border-primary",
205
+ icon && "pl-9",
206
+ error && "border-destructive focus:border-destructive",
207
+ className
208
+ ),
209
+ ref,
210
+ ...props
211
+ }
212
+ ),
213
+ error && /* @__PURE__ */ jsx("p", { className: "mt-1 text-[11px] text-destructive", children: error })
214
+ ] });
215
+ }
216
+ );
217
+ Input.displayName = "Input";
218
+ var badgeVariants = cva(
219
+ "inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-[10px] font-medium uppercase",
220
+ {
221
+ variants: {
222
+ variant: {
223
+ success: "bg-green-500/10 text-green-500",
224
+ destructive: "bg-destructive/10 text-destructive",
225
+ warning: "bg-orange-500/10 text-orange-500",
226
+ info: "bg-primary/10 text-primary",
227
+ muted: "bg-secondary text-muted-foreground"
228
+ }
229
+ },
230
+ defaultVariants: {
231
+ variant: "muted"
232
+ }
233
+ }
234
+ );
235
+ function Badge({ className, variant, ...props }) {
236
+ return /* @__PURE__ */ jsx("span", { className: cn(badgeVariants({ variant, className })), ...props });
237
+ }
238
+ function Popover({
239
+ trigger,
240
+ children,
241
+ align = "end",
242
+ className
243
+ }) {
244
+ const [open, setOpen] = useState(false);
245
+ const ref = useRef(null);
246
+ useEffect(() => {
247
+ if (!open) return;
248
+ const onDown = (e) => {
249
+ if (ref.current && !ref.current.contains(e.target)) setOpen(false);
250
+ };
251
+ const onKey = (e) => {
252
+ if (e.key === "Escape") setOpen(false);
253
+ };
254
+ document.addEventListener("mousedown", onDown);
255
+ document.addEventListener("keydown", onKey);
256
+ return () => {
257
+ document.removeEventListener("mousedown", onDown);
258
+ document.removeEventListener("keydown", onKey);
259
+ };
260
+ }, [open]);
261
+ return /* @__PURE__ */ jsxs("div", { className: "relative inline-block", ref, children: [
262
+ trigger({ open, toggle: () => setOpen((o) => !o) }),
263
+ open && /* @__PURE__ */ jsx(
264
+ "div",
265
+ {
266
+ className: `absolute z-50 mt-1 min-w-[260px] rounded-md border border-border bg-background shadow-lg p-3 ${align === "end" ? "right-0" : "left-0"} ${className ?? ""}`,
267
+ children: children(() => setOpen(false))
268
+ }
269
+ )
270
+ ] });
271
+ }
272
+
273
+ export { Badge, Button, Dialog, Drawer, Input, Popover, Select, ToastViewport, cn, useToast };
@@ -0,0 +1,56 @@
1
+ import { cn } from './chunk-EVHTAXQG.js';
2
+ import { useRef, useMemo, useEffect } from 'react';
3
+ import { jsx, jsxs } from 'react/jsx-runtime';
4
+
5
+ var LEVEL_META = {
6
+ error: { tag: "E", cls: "text-destructive" },
7
+ warn: { tag: "W", cls: "text-warning" },
8
+ info: { tag: "I", cls: "text-foreground" },
9
+ debug: { tag: "D", cls: "text-muted-foreground" },
10
+ system: { tag: "\u2022", cls: "text-primary" }
11
+ };
12
+ function clock(ts) {
13
+ const m = ts.match(/T(\d{2}:\d{2}:\d{2}\.\d{3})/);
14
+ return m?.[1] ?? ts;
15
+ }
16
+ function LogConsole({ logs, levels, query, wrap, autoScroll }) {
17
+ const ref = useRef(null);
18
+ const q = query.trim().toLowerCase();
19
+ const shown = useMemo(
20
+ () => logs.filter(
21
+ (l) => levels.has(l.level) && (q === "" || l.msg.toLowerCase().includes(q) || (l.device ?? "").toLowerCase().includes(q))
22
+ ),
23
+ [logs, levels, q]
24
+ );
25
+ useEffect(() => {
26
+ if (autoScroll && ref.current) ref.current.scrollTop = ref.current.scrollHeight;
27
+ }, [shown, autoScroll]);
28
+ return /* @__PURE__ */ jsx(
29
+ "div",
30
+ {
31
+ ref,
32
+ className: cn(
33
+ "h-full overflow-auto bg-background px-2 py-1.5 text-code-sm font-mono leading-relaxed selection:bg-primary/20",
34
+ wrap ? "whitespace-pre-wrap break-all" : "whitespace-pre"
35
+ ),
36
+ children: shown.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-muted-foreground px-1 py-1", children: logs.length === 0 ? "No logs yet" : "No lines match the current filter." }) : shown.map((l, i) => {
37
+ const meta = LEVEL_META[l.level];
38
+ return /* @__PURE__ */ jsxs(
39
+ "div",
40
+ {
41
+ className: cn("flex gap-2 px-1 rounded-sm hover:bg-surface/60", meta.cls),
42
+ children: [
43
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 text-muted-foreground tabular-nums", children: clock(l.ts) }),
44
+ /* @__PURE__ */ jsx("span", { className: cn("shrink-0 w-3 text-center font-bold", meta.cls), children: meta.tag }),
45
+ l.device && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-muted-foreground", children: l.device }),
46
+ /* @__PURE__ */ jsx("span", { className: cn(meta.cls, !wrap && "shrink-0"), children: l.msg })
47
+ ]
48
+ },
49
+ i
50
+ );
51
+ })
52
+ }
53
+ );
54
+ }
55
+
56
+ export { LogConsole };