@mordn/chat-widget 0.2.0 → 0.3.0

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.d.mts CHANGED
@@ -120,11 +120,34 @@ interface FeatureConfig {
120
120
  * - full: 100% - fills entire screen
121
121
  */
122
122
  type ChatWidgetSize = 'compact' | 'default' | 'large' | 'full';
123
+ /**
124
+ * Layout shape the widget renders in.
125
+ *
126
+ * - `popup` : floating side panel, opened by a toggle button (default).
127
+ * Best for ambient assistance available across pages.
128
+ * - `inline` : renders in place inside the parent element. No toggle button,
129
+ * no fixed positioning, fills its container. Best for dashboard
130
+ * cards or dedicated chat sections of a page.
131
+ * - `page` : full-viewport layout with a conversation list sidebar on the
132
+ * left and the active chat on the right. Best for a dedicated
133
+ * chat route (e.g. `/chat`).
134
+ *
135
+ * The `popup` value is the historical default and remains backward compatible.
136
+ */
137
+ type ChatWidgetLayout = 'popup' | 'inline' | 'page';
123
138
  interface DisplayConfig {
139
+ /**
140
+ * How the widget renders.
141
+ * Default: `'popup'` (backward compatible).
142
+ */
143
+ layout?: ChatWidgetLayout;
124
144
  /**
125
145
  * Preset size for the widget (recommended)
126
146
  * Uses clamp() for responsive sizing with min/max bounds
127
147
  * Default: 'default'
148
+ *
149
+ * Note: `size` only applies in `popup` layout. `inline` and `page` layouts
150
+ * fill their container regardless.
128
151
  */
129
152
  size?: ChatWidgetSize;
130
153
  /**
package/dist/index.d.ts CHANGED
@@ -120,11 +120,34 @@ interface FeatureConfig {
120
120
  * - full: 100% - fills entire screen
121
121
  */
122
122
  type ChatWidgetSize = 'compact' | 'default' | 'large' | 'full';
123
+ /**
124
+ * Layout shape the widget renders in.
125
+ *
126
+ * - `popup` : floating side panel, opened by a toggle button (default).
127
+ * Best for ambient assistance available across pages.
128
+ * - `inline` : renders in place inside the parent element. No toggle button,
129
+ * no fixed positioning, fills its container. Best for dashboard
130
+ * cards or dedicated chat sections of a page.
131
+ * - `page` : full-viewport layout with a conversation list sidebar on the
132
+ * left and the active chat on the right. Best for a dedicated
133
+ * chat route (e.g. `/chat`).
134
+ *
135
+ * The `popup` value is the historical default and remains backward compatible.
136
+ */
137
+ type ChatWidgetLayout = 'popup' | 'inline' | 'page';
123
138
  interface DisplayConfig {
139
+ /**
140
+ * How the widget renders.
141
+ * Default: `'popup'` (backward compatible).
142
+ */
143
+ layout?: ChatWidgetLayout;
124
144
  /**
125
145
  * Preset size for the widget (recommended)
126
146
  * Uses clamp() for responsive sizing with min/max bounds
127
147
  * Default: 'default'
148
+ *
149
+ * Note: `size` only applies in `popup` layout. `inline` and `page` layouts
150
+ * fill their container regardless.
128
151
  */
129
152
  size?: ChatWidgetSize;
130
153
  /**
package/dist/index.js CHANGED
@@ -2027,26 +2027,21 @@ function ChatInterface({ id, initialMessages, config, onClose } = {}) {
2027
2027
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "p-2.5 border-b", style: {
2028
2028
  borderColor: "var(--chat-border-soft)",
2029
2029
  backgroundColor: "var(--chat-overlay)"
2030
- }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "relative", children: [
2031
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react10.SearchIcon, { className: "absolute left-2.5 top-1/2 -translate-y-1/2 h-3.5 w-3.5", style: {
2032
- color: "hsl(var(--chat-text-muted))"
2033
- }, strokeWidth: 2 }),
2034
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2035
- "input",
2036
- {
2037
- type: "text",
2038
- placeholder: "Search",
2039
- value: searchQuery,
2040
- onChange: (e) => setSearchQuery(e.target.value),
2041
- className: "w-full h-7 pl-8 pr-2.5 text-[13px] rounded-lg focus:outline-none transition-all",
2042
- style: {
2043
- backgroundColor: "hsl(var(--chat-surface-deep))",
2044
- border: `1px solid ${"var(--chat-border-medium)"}`,
2045
- color: "hsl(var(--chat-text))"
2046
- }
2030
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "relative", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2031
+ "input",
2032
+ {
2033
+ type: "text",
2034
+ placeholder: "Search",
2035
+ value: searchQuery,
2036
+ onChange: (e) => setSearchQuery(e.target.value),
2037
+ className: "w-full h-7 px-2.5 text-[13px] rounded-lg focus:outline-none transition-all",
2038
+ style: {
2039
+ backgroundColor: "hsl(var(--chat-surface-deep))",
2040
+ border: `1px solid ${"var(--chat-border-medium)"}`,
2041
+ color: "hsl(var(--chat-text))"
2047
2042
  }
2048
- )
2049
- ] }) }),
2043
+ }
2044
+ ) }) }),
2050
2045
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "max-h-[300px] overflow-y-auto ai-assistant-scrollbar", children: loadingHistory ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex items-center justify-center py-12", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "text-[13px]", style: { color: "hsl(var(--chat-text-muted))" }, children: "Loading..." }) }) : conversations.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-col items-center justify-center py-12 px-4 text-center", children: [
2051
2046
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "w-12 h-12 rounded-full flex items-center justify-center mb-3", style: {
2052
2047
  backgroundColor: "hsl(var(--chat-surface))"
@@ -2222,10 +2217,13 @@ function ChatWidget({
2222
2217
  display,
2223
2218
  starterPrompts
2224
2219
  }) {
2220
+ const layout = display?.layout || "popup";
2225
2221
  const showToggleButton = display?.showToggleButton !== false;
2226
- const resizable = display?.resizable !== false;
2222
+ const resizable = layout === "popup" && display?.resizable !== false;
2227
2223
  const size = display?.size || "default";
2228
- const [isOpen, setIsOpen] = (0, import_react12.useState)(display?.defaultOpen || false);
2224
+ const [isOpen, setIsOpen] = (0, import_react12.useState)(
2225
+ layout !== "popup" ? true : display?.defaultOpen || false
2226
+ );
2229
2227
  const [isResizing, setIsResizing] = (0, import_react12.useState)(false);
2230
2228
  const containerRef = (0, import_react12.useRef)(null);
2231
2229
  const customStyles = (0, import_react12.useMemo)(() => {
@@ -2286,6 +2284,43 @@ function ChatWidget({
2286
2284
  starterPrompts
2287
2285
  }), [userId, model, systemPrompt, temperature, theme, features, starterPrompts]);
2288
2286
  const togglePosition = display?.toggleButtonPosition || { bottom: "24px", right: "24px" };
2287
+ const themeClass = theme?.mode === "dark" ? "dark" : "";
2288
+ if (layout === "inline") {
2289
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ChatStorageProvider, { userId, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2290
+ "div",
2291
+ {
2292
+ ref: containerRef,
2293
+ className: `chat-widget-container chat-widget-inline chat-widget-content ${themeClass} ${className || ""}`,
2294
+ style: customStyles,
2295
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2296
+ ChatInterface,
2297
+ {
2298
+ id: conversationId,
2299
+ initialMessages,
2300
+ config
2301
+ }
2302
+ )
2303
+ }
2304
+ ) });
2305
+ }
2306
+ if (layout === "page") {
2307
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ChatStorageProvider, { userId, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2308
+ "div",
2309
+ {
2310
+ ref: containerRef,
2311
+ className: `chat-widget-container chat-widget-page chat-widget-content ${themeClass} ${className || ""}`,
2312
+ style: customStyles,
2313
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2314
+ ChatInterface,
2315
+ {
2316
+ id: conversationId,
2317
+ initialMessages,
2318
+ config
2319
+ }
2320
+ )
2321
+ }
2322
+ ) });
2323
+ }
2289
2324
  return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(ChatStorageProvider, { userId, children: [
2290
2325
  showToggleButton && !isOpen && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2291
2326
  "button",
@@ -2301,7 +2336,7 @@ function ChatWidget({
2301
2336
  "div",
2302
2337
  {
2303
2338
  ref: containerRef,
2304
- className: `chat-widget-container chat-widget-popup chat-widget-content ${theme?.mode === "dark" ? "dark" : ""} ${className || ""}`,
2339
+ className: `chat-widget-container chat-widget-popup chat-widget-content ${themeClass} ${className || ""}`,
2305
2340
  "data-size": size,
2306
2341
  "data-resizing": isResizing,
2307
2342
  style: customStyles,