@agentforge-io/chat-sdk 2.4.0-dev.5 → 2.4.0-dev.6
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/ChatDrawer.d.ts +81 -28
- package/dist/ChatDrawer.js +212 -59
- package/package.json +1 -2
package/dist/ChatDrawer.d.ts
CHANGED
|
@@ -1,24 +1,61 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `<ChatDrawer>` —
|
|
2
|
+
* `<ChatDrawer>` — standard bottom-sheet wrapper around `<ChatWidget>`.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* The host gives us:
|
|
5
|
+
* - `open` / `onOpenChange`: controlled visibility (host owns the route /
|
|
6
|
+
* URL sync, the SDK doesn't touch the URL).
|
|
7
|
+
* - All the `<ChatWidget>` props (token, apiBaseUrl, etc.): forwarded
|
|
8
|
+
* verbatim. The widget mounts INSIDE the drawer.
|
|
9
9
|
*
|
|
10
|
-
* What
|
|
11
|
-
* -
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* -
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
10
|
+
* What the drawer adds on top:
|
|
11
|
+
* - Mounts via React portal (`document.body`) so it overlays the page
|
|
12
|
+
* regardless of the host's stacking context. Lazy-mounted: the portal
|
|
13
|
+
* target is computed at first open so SSR stays clean.
|
|
14
|
+
* - Visually pinned to the bottom of the *visual viewport* (not the
|
|
15
|
+
* layout viewport). On iOS Safari and Android Chrome the on-screen
|
|
16
|
+
* keyboard shrinks `window.visualViewport.height`; we listen to
|
|
17
|
+
* `resize` / `scroll` on visualViewport and reflow the drawer's
|
|
18
|
+
* `height` + `bottom` so the composer never gets clipped by the
|
|
19
|
+
* keyboard.
|
|
20
|
+
* - Opens at a configurable snap fraction (default 0.98 = 98% of the
|
|
21
|
+
* visible viewport). The visitor sees a thin sliver of the page
|
|
22
|
+
* underneath, which keeps context and lets a tap-outside dismiss.
|
|
23
|
+
* - Drag-to-dismiss with vanilla touch events: drag the handle down
|
|
24
|
+
* past 30% of the panel height and the drawer closes. No external
|
|
25
|
+
* deps — the SDK stays portable.
|
|
26
|
+
* - Survives close+reopen: the widget inside is rendered once and kept
|
|
27
|
+
* alive (CSS `display:none` toggle when closed, NOT unmounted), so
|
|
28
|
+
* the chat session, transcript, and any in-flight tool calls stay
|
|
29
|
+
* intact when the visitor closes and reopens the drawer.
|
|
30
|
+
*
|
|
31
|
+
* What the drawer does NOT do (deliberately):
|
|
32
|
+
* - It doesn't sync with the URL. The host decides whether `?view=chat`,
|
|
33
|
+
* `/chat`, or any other route shape opens it.
|
|
34
|
+
* - It doesn't manage the chat session lifecycle. That's `<ChatWidget>`'s
|
|
35
|
+
* job. We just provide presentation.
|
|
36
|
+
* - It doesn't render a "fake composer" to trigger opening. The host
|
|
37
|
+
* decides what trigger UX makes sense (button, input pill, FAB, etc.)
|
|
38
|
+
* and calls `onOpenChange(true)`.
|
|
19
39
|
*/
|
|
20
40
|
import { type CSSProperties, type ReactNode } from 'react';
|
|
21
41
|
import { type ChatWidgetProps } from './react';
|
|
42
|
+
/**
|
|
43
|
+
* Drawer accepts the chat surface in two shapes:
|
|
44
|
+
*
|
|
45
|
+
* - `widgetProps`: pass the ChatWidget configuration and the drawer
|
|
46
|
+
* creates the widget internally. The standard / forward-looking
|
|
47
|
+
* API — most consumers should use this.
|
|
48
|
+
*
|
|
49
|
+
* - `chatSlot`: pass a pre-rendered React node (typically a
|
|
50
|
+
* `<ChatWidget>` instance the host wired up itself). Useful when
|
|
51
|
+
* the host already orchestrates the widget (multiple chat slots,
|
|
52
|
+
* custom decorators, legacy code) and just wants the drawer's
|
|
53
|
+
* positioning + drag UX on top.
|
|
54
|
+
*
|
|
55
|
+
* Exactly one of the two MUST be passed. Mutual exclusivity isn't
|
|
56
|
+
* encoded at the type level (TS unions with optional props get noisy)
|
|
57
|
+
* — the runtime asserts gracefully if neither is present.
|
|
58
|
+
*/
|
|
22
59
|
type ChatSurface = {
|
|
23
60
|
widgetProps: ChatWidgetProps;
|
|
24
61
|
chatSlot?: never;
|
|
@@ -27,23 +64,39 @@ type ChatSurface = {
|
|
|
27
64
|
widgetProps?: never;
|
|
28
65
|
};
|
|
29
66
|
export type ChatDrawerProps = ChatSurface & {
|
|
30
|
-
/**
|
|
67
|
+
/** Whether the drawer is visible. Controlled. */
|
|
31
68
|
open: boolean;
|
|
32
|
-
/** Fired when the drawer wants to close
|
|
33
|
-
*
|
|
34
|
-
* shape so the host doesn't have to change call sites. */
|
|
69
|
+
/** Fired when the drawer wants to close (drag-to-dismiss, tap on the
|
|
70
|
+
* backdrop, close button). Host is responsible for setting `open=false`. */
|
|
35
71
|
onOpenChange: (open: boolean) => void;
|
|
36
|
-
/**
|
|
72
|
+
/** Snap fraction of the visible viewport, 0–1. Defaults to 0.98 (98% =
|
|
73
|
+
* the standard "near-fullscreen drawer that still hints at the page
|
|
74
|
+
* below" pattern). Lower numbers leave more of the page visible. */
|
|
75
|
+
snap?: number;
|
|
76
|
+
/** Display in the drawer header above the chat. Templates pass the
|
|
77
|
+
* agent / team identity here. When omitted, the drawer renders a
|
|
78
|
+
* bare drag handle only — useful for hosts that want a borderless
|
|
79
|
+
* panel. */
|
|
37
80
|
header?: ReactNode;
|
|
38
|
-
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
|
|
42
|
-
/** Extra class on the drawer surface.
|
|
81
|
+
/** Backdrop click closes the drawer. Default true — set false if the
|
|
82
|
+
* host wants a "modal" feel where the only escape is the close button
|
|
83
|
+
* or the drag-down gesture. */
|
|
84
|
+
closeOnBackdropClick?: boolean;
|
|
85
|
+
/** Extra class on the drawer's root surface (the white card). Use it to
|
|
86
|
+
* add a custom shadow / border colour. The CSS vars on `--af-*` already
|
|
87
|
+
* let you re-theme the chat widget itself; this is for the SURROUND. */
|
|
43
88
|
drawerClassName?: string;
|
|
44
|
-
/**
|
|
45
|
-
*
|
|
46
|
-
*
|
|
89
|
+
/** Inline style applied to the drawer surface — typically the host's
|
|
90
|
+
* bundle of `--af-bg`, `--af-fg`, `--af-bubble-*`, etc. CSS vars.
|
|
91
|
+
* Because the drawer renders into a portal (`document.body`), any
|
|
92
|
+
* vars declared on the host's page wrapper DON'T cascade in. The
|
|
93
|
+
* host re-declares them here so the chat surface inside the portal
|
|
94
|
+
* picks up the same theme.
|
|
95
|
+
*
|
|
96
|
+
* We default the SURFACE BG to `var(--af-bg, …)` so passing
|
|
97
|
+
* `--af-bg` in `surfaceStyle` themes the drawer's background.
|
|
98
|
+
* When omitted the drawer falls back to white in light mode and
|
|
99
|
+
* the system default elsewhere — passable but not theme-perfect. */
|
|
47
100
|
surfaceStyle?: CSSProperties & Record<string, string>;
|
|
48
101
|
};
|
|
49
102
|
export declare function ChatDrawer(props: ChatDrawerProps): JSX.Element | null;
|
package/dist/ChatDrawer.js
CHANGED
|
@@ -3,36 +3,136 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ChatDrawer = ChatDrawer;
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
5
|
/**
|
|
6
|
-
* `<ChatDrawer>` —
|
|
6
|
+
* `<ChatDrawer>` — standard bottom-sheet wrapper around `<ChatWidget>`.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
8
|
+
* The host gives us:
|
|
9
|
+
* - `open` / `onOpenChange`: controlled visibility (host owns the route /
|
|
10
|
+
* URL sync, the SDK doesn't touch the URL).
|
|
11
|
+
* - All the `<ChatWidget>` props (token, apiBaseUrl, etc.): forwarded
|
|
12
|
+
* verbatim. The widget mounts INSIDE the drawer.
|
|
13
13
|
*
|
|
14
|
-
* What
|
|
15
|
-
* -
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* -
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
14
|
+
* What the drawer adds on top:
|
|
15
|
+
* - Mounts via React portal (`document.body`) so it overlays the page
|
|
16
|
+
* regardless of the host's stacking context. Lazy-mounted: the portal
|
|
17
|
+
* target is computed at first open so SSR stays clean.
|
|
18
|
+
* - Visually pinned to the bottom of the *visual viewport* (not the
|
|
19
|
+
* layout viewport). On iOS Safari and Android Chrome the on-screen
|
|
20
|
+
* keyboard shrinks `window.visualViewport.height`; we listen to
|
|
21
|
+
* `resize` / `scroll` on visualViewport and reflow the drawer's
|
|
22
|
+
* `height` + `bottom` so the composer never gets clipped by the
|
|
23
|
+
* keyboard.
|
|
24
|
+
* - Opens at a configurable snap fraction (default 0.98 = 98% of the
|
|
25
|
+
* visible viewport). The visitor sees a thin sliver of the page
|
|
26
|
+
* underneath, which keeps context and lets a tap-outside dismiss.
|
|
27
|
+
* - Drag-to-dismiss with vanilla touch events: drag the handle down
|
|
28
|
+
* past 30% of the panel height and the drawer closes. No external
|
|
29
|
+
* deps — the SDK stays portable.
|
|
30
|
+
* - Survives close+reopen: the widget inside is rendered once and kept
|
|
31
|
+
* alive (CSS `display:none` toggle when closed, NOT unmounted), so
|
|
32
|
+
* the chat session, transcript, and any in-flight tool calls stay
|
|
33
|
+
* intact when the visitor closes and reopens the drawer.
|
|
34
|
+
*
|
|
35
|
+
* What the drawer does NOT do (deliberately):
|
|
36
|
+
* - It doesn't sync with the URL. The host decides whether `?view=chat`,
|
|
37
|
+
* `/chat`, or any other route shape opens it.
|
|
38
|
+
* - It doesn't manage the chat session lifecycle. That's `<ChatWidget>`'s
|
|
39
|
+
* job. We just provide presentation.
|
|
40
|
+
* - It doesn't render a "fake composer" to trigger opening. The host
|
|
41
|
+
* decides what trigger UX makes sense (button, input pill, FAB, etc.)
|
|
42
|
+
* and calls `onOpenChange(true)`.
|
|
23
43
|
*/
|
|
24
44
|
const react_1 = require("react");
|
|
45
|
+
const react_dom_1 = require("react-dom");
|
|
25
46
|
const react_2 = require("./react");
|
|
26
47
|
function ChatDrawer(props) {
|
|
27
|
-
const { open, onOpenChange, header,
|
|
28
|
-
//
|
|
29
|
-
//
|
|
30
|
-
|
|
48
|
+
const { open, onOpenChange, snap = 0.98, header, closeOnBackdropClick = true, drawerClassName, surfaceStyle: surfaceStyleProp, widgetProps, chatSlot, } = props;
|
|
49
|
+
// We mount once and keep alive across close→reopen so the chat session
|
|
50
|
+
// doesn't get destroyed. After the FIRST open the panel stays in the
|
|
51
|
+
// DOM forever (toggled by `display:none`) — `hasOpened` gates the
|
|
52
|
+
// initial mount so SSR doesn't render an empty portal.
|
|
53
|
+
const [hasOpened, setHasOpened] = (0, react_1.useState)(open);
|
|
54
|
+
(0, react_1.useEffect)(() => {
|
|
55
|
+
if (open)
|
|
56
|
+
setHasOpened(true);
|
|
57
|
+
}, [open]);
|
|
58
|
+
// Visible viewport tracking. iOS Safari + Android Chrome shrink
|
|
59
|
+
// `visualViewport.height` when the on-screen keyboard pops up; the
|
|
60
|
+
// layout viewport stays the same. We pin the drawer's height + bottom
|
|
61
|
+
// to the visual viewport so the composer is always above the keyboard.
|
|
62
|
+
const [vv, setVv] = (0, react_1.useState)(() => ({
|
|
63
|
+
h: typeof window === 'undefined' ? 0 : window.innerHeight,
|
|
64
|
+
offsetTop: 0,
|
|
65
|
+
}));
|
|
31
66
|
(0, react_1.useEffect)(() => {
|
|
32
|
-
|
|
67
|
+
if (typeof window === 'undefined')
|
|
68
|
+
return;
|
|
69
|
+
const view = window.visualViewport;
|
|
70
|
+
if (!view)
|
|
71
|
+
return;
|
|
72
|
+
const update = () => setVv({ h: view.height, offsetTop: view.offsetTop });
|
|
73
|
+
update();
|
|
74
|
+
view.addEventListener('resize', update);
|
|
75
|
+
view.addEventListener('scroll', update);
|
|
76
|
+
return () => {
|
|
77
|
+
view.removeEventListener('resize', update);
|
|
78
|
+
view.removeEventListener('scroll', update);
|
|
79
|
+
};
|
|
80
|
+
}, []);
|
|
81
|
+
// Snap-point height: % of the visible viewport. Recomputed when vv
|
|
82
|
+
// changes so a keyboard popup keeps the drawer aligned.
|
|
83
|
+
const drawerHeight = Math.max(0, Math.round(vv.h * Math.min(Math.max(snap, 0.1), 1)));
|
|
84
|
+
// Drag-to-dismiss. Vanilla touch handlers — no library. We track
|
|
85
|
+
// pointerdown on the handle, follow movement on pointermove, and
|
|
86
|
+
// decide on pointerup whether the drag crossed the "dismiss" threshold
|
|
87
|
+
// (30% of the panel height).
|
|
88
|
+
const surfaceRef = (0, react_1.useRef)(null);
|
|
89
|
+
const dragStateRef = (0, react_1.useRef)(null);
|
|
90
|
+
const [dragOffset, setDragOffset] = (0, react_1.useState)(0);
|
|
91
|
+
const onHandlePointerDown = (0, react_1.useCallback)((e) => {
|
|
92
|
+
if (e.button !== 0 && e.pointerType !== 'touch')
|
|
93
|
+
return;
|
|
94
|
+
e.currentTarget.setPointerCapture?.(e.pointerId);
|
|
95
|
+
dragStateRef.current = {
|
|
96
|
+
startY: e.clientY,
|
|
97
|
+
startTime: Date.now(),
|
|
98
|
+
dragging: true,
|
|
99
|
+
};
|
|
100
|
+
}, []);
|
|
101
|
+
const onHandlePointerMove = (0, react_1.useCallback)((e) => {
|
|
102
|
+
const s = dragStateRef.current;
|
|
103
|
+
if (!s?.dragging)
|
|
104
|
+
return;
|
|
105
|
+
const delta = Math.max(0, e.clientY - s.startY);
|
|
106
|
+
setDragOffset(delta);
|
|
33
107
|
}, []);
|
|
34
|
-
|
|
35
|
-
|
|
108
|
+
const onHandlePointerUp = (0, react_1.useCallback)((e) => {
|
|
109
|
+
const s = dragStateRef.current;
|
|
110
|
+
if (!s?.dragging)
|
|
111
|
+
return;
|
|
112
|
+
dragStateRef.current = null;
|
|
113
|
+
try {
|
|
114
|
+
e.currentTarget.releasePointerCapture?.(e.pointerId);
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// Pointer was already released by some other code path; nothing
|
|
118
|
+
// to do here. Releasing a non-captured pointer throws — swallow.
|
|
119
|
+
}
|
|
120
|
+
const delta = Math.max(0, e.clientY - s.startY);
|
|
121
|
+
const dismissThreshold = drawerHeight * 0.3;
|
|
122
|
+
const elapsed = Date.now() - s.startTime;
|
|
123
|
+
// Dismiss on EITHER a long-drag (past the threshold) or a quick
|
|
124
|
+
// flick (small distance but high velocity). Velocity unit is
|
|
125
|
+
// px/ms; >0.5 is roughly the threshold iOS sheets use.
|
|
126
|
+
const velocity = elapsed > 0 ? delta / elapsed : 0;
|
|
127
|
+
if (delta > dismissThreshold || velocity > 0.5) {
|
|
128
|
+
onOpenChange(false);
|
|
129
|
+
}
|
|
130
|
+
setDragOffset(0);
|
|
131
|
+
}, [drawerHeight, onOpenChange]);
|
|
132
|
+
// Lock body scroll while the drawer is open so the page underneath
|
|
133
|
+
// doesn't move when the visitor scrolls inside the chat. Restored on
|
|
134
|
+
// close. Necessary on iOS Safari where the rubber-band scroll bleeds
|
|
135
|
+
// through to the body even with overflow:hidden on a child.
|
|
36
136
|
(0, react_1.useEffect)(() => {
|
|
37
137
|
if (typeof document === 'undefined')
|
|
38
138
|
return;
|
|
@@ -44,48 +144,101 @@ function ChatDrawer(props) {
|
|
|
44
144
|
document.body.style.overflow = prev;
|
|
45
145
|
};
|
|
46
146
|
}, [open]);
|
|
47
|
-
|
|
147
|
+
// Escape closes the drawer. Keyboard-friendly even when focus is in
|
|
148
|
+
// the textarea — preventDefault on the input itself swallows Escape
|
|
149
|
+
// before it bubbles, so we use capture phase.
|
|
150
|
+
(0, react_1.useEffect)(() => {
|
|
151
|
+
if (!open)
|
|
152
|
+
return;
|
|
153
|
+
if (typeof window === 'undefined')
|
|
154
|
+
return;
|
|
155
|
+
const onKey = (e) => {
|
|
156
|
+
if (e.key === 'Escape')
|
|
157
|
+
onOpenChange(false);
|
|
158
|
+
};
|
|
159
|
+
window.addEventListener('keydown', onKey, true);
|
|
160
|
+
return () => window.removeEventListener('keydown', onKey, true);
|
|
161
|
+
}, [open, onOpenChange]);
|
|
162
|
+
// Lazy portal target. We render to `document.body` so the drawer
|
|
163
|
+
// overlays everything regardless of the consumer's stacking context.
|
|
164
|
+
const [portalEl, setPortalEl] = (0, react_1.useState)(null);
|
|
165
|
+
(0, react_1.useLayoutEffect)(() => {
|
|
166
|
+
if (typeof document === 'undefined')
|
|
167
|
+
return;
|
|
168
|
+
setPortalEl(document.body);
|
|
169
|
+
}, []);
|
|
170
|
+
// Stable id so the drag handle's `aria-controls` can point at the
|
|
171
|
+
// panel. Required for screen readers to announce the relationship.
|
|
172
|
+
const panelId = (0, react_1.useId)();
|
|
173
|
+
if (!portalEl)
|
|
48
174
|
return null;
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
175
|
+
if (!hasOpened)
|
|
176
|
+
return null;
|
|
177
|
+
// The translate3d ensures the drawer animates from below on first
|
|
178
|
+
// open (initial transform = 100%, becomes 0% after the open prop
|
|
179
|
+
// flips). When dragging we add the manual drag offset on top.
|
|
180
|
+
const translateY = open ? `${dragOffset}px` : `${drawerHeight}px`;
|
|
181
|
+
// Transition disabled WHILE dragging so the surface follows the
|
|
182
|
+
// finger 1:1. Re-enabled at the end of the drag (delta back to 0
|
|
183
|
+
// smoothly when below threshold).
|
|
184
|
+
const isDragging = dragStateRef.current?.dragging === true;
|
|
185
|
+
// Motion / sizing portion of the surface style, kept separate from
|
|
186
|
+
// the host-supplied theming so a re-render driven by drag offset
|
|
187
|
+
// doesn't smash the host's CSS vars.
|
|
188
|
+
const surfaceMotionStyle = {
|
|
189
|
+
height: `${drawerHeight}px`,
|
|
190
|
+
transform: `translate3d(0, ${translateY}, 0)`,
|
|
191
|
+
bottom: `${vv.offsetTop}px`,
|
|
192
|
+
transition: isDragging ? 'none' : 'transform 240ms cubic-bezier(.32,.72,0,1)',
|
|
193
|
+
willChange: 'transform',
|
|
194
|
+
};
|
|
195
|
+
return (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsxs)("div", { className: "af-drawer-root", "data-state": open ? 'open' : 'closed', style: {
|
|
53
196
|
position: 'fixed',
|
|
54
197
|
inset: 0,
|
|
55
|
-
height: '100dvh',
|
|
56
198
|
zIndex: 2147483600,
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
199
|
+
pointerEvents: open ? 'auto' : 'none',
|
|
200
|
+
}, children: [(0, jsx_runtime_1.jsx)("div", { className: "af-drawer-backdrop", onClick: closeOnBackdropClick ? () => onOpenChange(false) : undefined, style: {
|
|
201
|
+
position: 'absolute',
|
|
202
|
+
inset: 0,
|
|
203
|
+
backgroundColor: 'rgba(0, 0, 0, 0.4)',
|
|
204
|
+
opacity: open ? 1 : 0,
|
|
205
|
+
transition: 'opacity 200ms ease-out',
|
|
206
|
+
}, "aria-hidden": true }), (0, jsx_runtime_1.jsxs)("div", { ref: surfaceRef, id: panelId, role: "dialog", "aria-modal": "true", className: `af-drawer-surface ${drawerClassName ?? ''}`, style: {
|
|
207
|
+
position: 'absolute',
|
|
208
|
+
left: 0,
|
|
209
|
+
right: 0,
|
|
210
|
+
width: '100%',
|
|
211
|
+
// Host supplies the CSS vars via `surfaceStyle`; the
|
|
212
|
+
// backgroundColor resolves from `--af-bg` (which the host
|
|
213
|
+
// declares in that same prop). When `surfaceStyle` is
|
|
214
|
+
// omitted we fall back to white — passable for an unthemed
|
|
215
|
+
// demo, wrong for a themed embed; passing surfaceStyle is
|
|
216
|
+
// the correct path.
|
|
64
217
|
backgroundColor: 'var(--af-bg, #ffffff)',
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
218
|
+
color: 'var(--af-fg, inherit)',
|
|
219
|
+
borderTopLeftRadius: '16px',
|
|
220
|
+
borderTopRightRadius: '16px',
|
|
221
|
+
boxShadow: '0 -8px 24px rgba(15, 23, 42, 0.25)',
|
|
69
222
|
display: 'flex',
|
|
70
223
|
flexDirection: 'column',
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
224
|
+
overflow: 'hidden',
|
|
225
|
+
// Host-supplied theme vars come FIRST so the motion
|
|
226
|
+
// properties below override any conflicting `transform` /
|
|
227
|
+
// `height` declarations a careless host might pass.
|
|
228
|
+
...surfaceStyleProp,
|
|
229
|
+
...surfaceMotionStyle,
|
|
230
|
+
}, children: [(0, jsx_runtime_1.jsx)("div", { onPointerDown: onHandlePointerDown, onPointerMove: onHandlePointerMove, onPointerUp: onHandlePointerUp, onPointerCancel: onHandlePointerUp, style: {
|
|
231
|
+
padding: '10px 0',
|
|
232
|
+
cursor: 'grab',
|
|
233
|
+
touchAction: 'none',
|
|
234
|
+
display: 'flex',
|
|
235
|
+
justifyContent: 'center',
|
|
236
|
+
flexShrink: 0,
|
|
237
|
+
}, "aria-label": "Drag to close", children: (0, jsx_runtime_1.jsx)("span", { style: {
|
|
238
|
+
width: '40px',
|
|
239
|
+
height: '4px',
|
|
240
|
+
borderRadius: '999px',
|
|
241
|
+
backgroundColor: 'var(--af-muted, rgba(100, 116, 139, 0.45))',
|
|
242
|
+
display: 'block',
|
|
243
|
+
} }) }), header, (0, jsx_runtime_1.jsx)("div", { style: { flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column' }, children: chatSlot ?? (widgetProps ? ((0, jsx_runtime_1.jsx)(react_2.ChatWidget, { ...widgetProps, inline: true, variant: widgetProps.variant ?? 'bare' })) : null) })] })] }), portalEl);
|
|
91
244
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentforge-io/chat-sdk",
|
|
3
|
-
"version": "2.4.0-dev.
|
|
3
|
+
"version": "2.4.0-dev.6",
|
|
4
4
|
"description": "Framework-free chat session SDK for AgentForge public chat tokens. Headless — no DOM. Drop into any frontend (React, Vue, Svelte, vanilla) and listen for events.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -35,7 +35,6 @@
|
|
|
35
35
|
"@types/node": "^20.0.0",
|
|
36
36
|
"@types/react": "^18.3.28",
|
|
37
37
|
"react": "^18.3.1",
|
|
38
|
-
"react-dom": "^18.3.1",
|
|
39
38
|
"typescript": "^5.0.0"
|
|
40
39
|
}
|
|
41
40
|
}
|