ghostykit 0.9.0 → 0.9.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/README.md +1 -0
- package/dist/split/index.d.ts +15 -0
- package/dist/split/index.js +48 -5
- package/dist/split.css +22 -1
- package/dist/styles.css +6 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -276,6 +276,7 @@ const split = usePilotoSplit({ widthKey: "app:agent-width", onOpenChange: setSid
|
|
|
276
276
|
```
|
|
277
277
|
|
|
278
278
|
`useStickyPanelHeight(variant === "panel")` keeps the panel's composer in view while the page scrolls.
|
|
279
|
+
`<PilotoLauncher split={split} label="Talk to Ghosty" avatarSrc=… className="fixed bottom-6 right-6" />` is the open button (spring in/out, hidden while open).
|
|
279
280
|
Colors: `--gk-split-handle`, `--gk-split-accent`, `--gk-split-sheet-bg`, `--gk-split-overlay`.
|
|
280
281
|
|
|
281
282
|
## Accessibility
|
package/dist/split/index.d.ts
CHANGED
|
@@ -19,6 +19,8 @@ export declare function usePilotoSplit(options: PilotoSplitOptions | string): {
|
|
|
19
19
|
setSheetOpen: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|
|
20
20
|
mounted: boolean;
|
|
21
21
|
widthKey: string;
|
|
22
|
+
animating: boolean;
|
|
23
|
+
targetWidth: number;
|
|
22
24
|
/** Abierto en la forma que toca (panel o hoja). */
|
|
23
25
|
isOpen: boolean;
|
|
24
26
|
open: () => void;
|
|
@@ -56,3 +58,16 @@ export declare function useStickyPanelHeight(enabled?: boolean): {
|
|
|
56
58
|
};
|
|
57
59
|
/** Panel lateral desde `minWidth` px (default 1024, el `lg` de Tailwind), hoja debajo. En el servidor, escritorio. */
|
|
58
60
|
export declare function useIsDesktop(minWidth?: number): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* El botón para abrir el piloto: una pastilla con el avatar y «Hablar con …» que entra y sale con
|
|
63
|
+
* resorte (como el tablero de Ventas de gs). Se muestra sólo con el piloto cerrado.
|
|
64
|
+
*/
|
|
65
|
+
export declare function PilotoLauncher({ split, label, avatarSrc, className, style, }: {
|
|
66
|
+
split: PilotoSplitState;
|
|
67
|
+
/** Texto de la pastilla, p. ej. «Hablar con Ghosty». Sin texto, sólo el avatar. */
|
|
68
|
+
label?: string;
|
|
69
|
+
avatarSrc: string;
|
|
70
|
+
/** Posición y colores (`fixed bottom-6 right-6 …`). */
|
|
71
|
+
className?: string;
|
|
72
|
+
style?: CSSProperties;
|
|
73
|
+
}): import("react").JSX.Element;
|
package/dist/split/index.js
CHANGED
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
3
3
|
import { Group, Panel, Separator, usePanelRef } from "react-resizable-panels";
|
|
4
4
|
import { Drawer } from "vaul";
|
|
5
|
+
import { AnimatePresence, motion } from "motion/react";
|
|
5
6
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
7
|
var SHEET_SNAPS = [0.6, 0.94];
|
|
8
|
+
var OPEN_MS = 320;
|
|
7
9
|
function usePilotoSplit(options) {
|
|
8
10
|
const { widthKey, defaultWidth = 420, desktopMinWidth = 1024, onOpenChange } = typeof options === "string" ? { widthKey: options } : options;
|
|
9
11
|
const isDesktop = useIsDesktop(desktopMinWidth);
|
|
@@ -11,6 +13,13 @@ function usePilotoSplit(options) {
|
|
|
11
13
|
const [panelOpen, setPanelOpen] = useState(false);
|
|
12
14
|
const [sheetOpen, setSheetOpen] = useState(false);
|
|
13
15
|
const [mounted, setMounted] = useState(false);
|
|
16
|
+
const [animating, setAnimating] = useState(false);
|
|
17
|
+
const animTimer = useRef(void 0);
|
|
18
|
+
const animate = useCallback(() => {
|
|
19
|
+
setAnimating(true);
|
|
20
|
+
clearTimeout(animTimer.current);
|
|
21
|
+
animTimer.current = setTimeout(() => setAnimating(false), OPEN_MS + 40);
|
|
22
|
+
}, []);
|
|
14
23
|
useEffect(() => {
|
|
15
24
|
const panel = panelRef.current;
|
|
16
25
|
if (isDesktop || !panel || panel.isCollapsed()) return;
|
|
@@ -22,13 +31,16 @@ function usePilotoSplit(options) {
|
|
|
22
31
|
if (!isDesktop) return setSheetOpen(true);
|
|
23
32
|
const panel = panelRef.current;
|
|
24
33
|
if (!panel || !panel.isCollapsed()) return;
|
|
34
|
+
animate();
|
|
25
35
|
panel.expand();
|
|
26
36
|
panel.resize(`${readWidth(widthKey, defaultWidth)}px`);
|
|
27
|
-
}, [isDesktop, panelRef, widthKey, defaultWidth]);
|
|
37
|
+
}, [isDesktop, panelRef, widthKey, defaultWidth, animate]);
|
|
28
38
|
const close = useCallback(() => {
|
|
29
|
-
panelRef.current
|
|
39
|
+
const panel = panelRef.current;
|
|
40
|
+
if (panel && !panel.isCollapsed()) animate();
|
|
41
|
+
panel?.collapse();
|
|
30
42
|
setSheetOpen(false);
|
|
31
|
-
}, [panelRef]);
|
|
43
|
+
}, [panelRef, animate]);
|
|
32
44
|
const isOpen = isDesktop ? panelOpen : sheetOpen;
|
|
33
45
|
const notify = useRef(onOpenChange);
|
|
34
46
|
notify.current = onOpenChange;
|
|
@@ -44,6 +56,8 @@ function usePilotoSplit(options) {
|
|
|
44
56
|
setSheetOpen,
|
|
45
57
|
mounted,
|
|
46
58
|
widthKey,
|
|
59
|
+
animating,
|
|
60
|
+
targetWidth: readWidth(widthKey, defaultWidth),
|
|
47
61
|
/** Abierto en la forma que toca (panel o hoja). */
|
|
48
62
|
isOpen,
|
|
49
63
|
open,
|
|
@@ -62,7 +76,7 @@ function PilotoSplit({
|
|
|
62
76
|
sheetClassName = "",
|
|
63
77
|
style
|
|
64
78
|
}) {
|
|
65
|
-
const { isDesktop, panelRef, panelOpen, setPanelOpen, sheetOpen, setSheetOpen, mounted, widthKey } = split;
|
|
79
|
+
const { isDesktop, panelRef, panelOpen, setPanelOpen, sheetOpen, setSheetOpen, mounted, widthKey, animating, targetWidth } = split;
|
|
66
80
|
const [sheetSnap, setSheetSnap] = useState(SHEET_SNAPS[0]);
|
|
67
81
|
const sheetChat = useRef(null);
|
|
68
82
|
const [sheetChatH, setSheetChatH] = useState(null);
|
|
@@ -105,7 +119,7 @@ function PilotoSplit({
|
|
|
105
119
|
maxSize: "60%",
|
|
106
120
|
style: { overflow: "clip", minWidth: 0 },
|
|
107
121
|
onResize: (size) => setPanelOpen(size.inPixels > 0),
|
|
108
|
-
children: mounted && isDesktop && /* @__PURE__ */ jsx("div", { style: { height: "100%" }, inert: !panelOpen, children: piloto("panel") })
|
|
122
|
+
children: mounted && isDesktop && /* @__PURE__ */ jsx("div", { style: { height: "100%", width: animating ? `${targetWidth}px` : "100%" }, inert: !panelOpen, children: piloto("panel") })
|
|
109
123
|
}
|
|
110
124
|
)
|
|
111
125
|
] }) }),
|
|
@@ -188,7 +202,36 @@ function useIsDesktop(minWidth = 1024) {
|
|
|
188
202
|
}, [minWidth]);
|
|
189
203
|
return desktop;
|
|
190
204
|
}
|
|
205
|
+
function PilotoLauncher({
|
|
206
|
+
split,
|
|
207
|
+
label,
|
|
208
|
+
avatarSrc,
|
|
209
|
+
className = "",
|
|
210
|
+
style
|
|
211
|
+
}) {
|
|
212
|
+
return /* @__PURE__ */ jsx(AnimatePresence, { children: !split.isOpen && /* @__PURE__ */ jsxs(
|
|
213
|
+
motion.button,
|
|
214
|
+
{
|
|
215
|
+
type: "button",
|
|
216
|
+
onClick: split.open,
|
|
217
|
+
"aria-label": label ?? "Abrir el piloto",
|
|
218
|
+
title: label,
|
|
219
|
+
initial: { opacity: 0, scale: 0.6, y: 20 },
|
|
220
|
+
animate: { opacity: 1, scale: 1, y: 0 },
|
|
221
|
+
exit: { opacity: 0, scale: 0.6, y: 20 },
|
|
222
|
+
transition: { type: "spring", stiffness: 400, damping: 24 },
|
|
223
|
+
className: `gk-launcher ${label ? "" : "gk-launcher-icon"} ${className}`,
|
|
224
|
+
style,
|
|
225
|
+
children: [
|
|
226
|
+
/* @__PURE__ */ jsx("img", { src: avatarSrc, alt: "" }),
|
|
227
|
+
label && /* @__PURE__ */ jsx("span", { children: label })
|
|
228
|
+
]
|
|
229
|
+
},
|
|
230
|
+
"gk-launcher"
|
|
231
|
+
) });
|
|
232
|
+
}
|
|
191
233
|
export {
|
|
234
|
+
PilotoLauncher,
|
|
192
235
|
PilotoSplit,
|
|
193
236
|
useIsDesktop,
|
|
194
237
|
usePilotoSplit,
|
package/dist/split.css
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
/* Abrir y cerrar se animan; arrastrar, no. */
|
|
6
6
|
.gk-split:not(:has([data-separator="active"])) > [data-panel] {
|
|
7
|
-
transition: flex-grow
|
|
7
|
+
transition: flex-grow 320ms cubic-bezier(0.22, 1, 0.36, 1);
|
|
8
8
|
}
|
|
9
9
|
@media (prefers-reduced-motion: reduce) {
|
|
10
10
|
.gk-split > [data-panel] { transition: none; }
|
|
@@ -48,3 +48,24 @@
|
|
|
48
48
|
}
|
|
49
49
|
.gk-split-handle { margin: 8px auto !important; height: 6px !important; width: 48px !important; flex-shrink: 0; background: #d1d5db !important; }
|
|
50
50
|
.gk-split-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
|
|
51
|
+
|
|
52
|
+
/* Pastilla para abrir el piloto. Colores: --gk-launcher-bg, --gk-launcher-fg. */
|
|
53
|
+
.gk-launcher {
|
|
54
|
+
display: inline-flex;
|
|
55
|
+
align-items: center;
|
|
56
|
+
gap: 8px;
|
|
57
|
+
padding: 8px 16px 8px 8px;
|
|
58
|
+
border: 0;
|
|
59
|
+
border-radius: 9999px;
|
|
60
|
+
background: var(--gk-launcher-bg, #191a20);
|
|
61
|
+
color: var(--gk-launcher-fg, #fff);
|
|
62
|
+
font-family: inherit;
|
|
63
|
+
font-size: 14px;
|
|
64
|
+
font-weight: 600;
|
|
65
|
+
line-height: 1;
|
|
66
|
+
cursor: pointer;
|
|
67
|
+
box-shadow: 0 12px 30px -10px rgb(25 26 32 / 0.6);
|
|
68
|
+
z-index: 40;
|
|
69
|
+
}
|
|
70
|
+
.gk-launcher img { width: 32px; height: 32px; object-fit: contain; }
|
|
71
|
+
.gk-launcher-icon { padding: 8px; }
|
package/dist/styles.css
CHANGED
|
@@ -155,12 +155,18 @@
|
|
|
155
155
|
.piloto .right-4:not([data-piloto-isolate] *) {
|
|
156
156
|
right: calc(var(--spacing) * 4);
|
|
157
157
|
}
|
|
158
|
+
.piloto .right-6:not([data-piloto-isolate] *) {
|
|
159
|
+
right: calc(var(--spacing) * 6);
|
|
160
|
+
}
|
|
158
161
|
.piloto .bottom-2:not([data-piloto-isolate] *) {
|
|
159
162
|
bottom: calc(var(--spacing) * 2);
|
|
160
163
|
}
|
|
161
164
|
.piloto .bottom-4:not([data-piloto-isolate] *) {
|
|
162
165
|
bottom: calc(var(--spacing) * 4);
|
|
163
166
|
}
|
|
167
|
+
.piloto .bottom-6:not([data-piloto-isolate] *) {
|
|
168
|
+
bottom: calc(var(--spacing) * 6);
|
|
169
|
+
}
|
|
164
170
|
.piloto .bottom-full:not([data-piloto-isolate] *) {
|
|
165
171
|
bottom: 100%;
|
|
166
172
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ghostykit",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "Ghosty Autopilot — the autopilot chat for your React app, on AG-UI: works with LangGraph, Mastra, CrewAI or any AG-UI agent. Streaming text, agent steps, human approval cards (interrupt/resume), attachments and voice.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/core/index.js",
|