@courseecho/ai-widget-react 1.0.24 → 1.0.26
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/ShadowWrapper.d.ts +3 -7
- package/dist/ShadowWrapper.js +6 -177
- package/dist/components.js +4 -3
- package/package.json +1 -1
- package/dist/core/src/auto-suggestion-generator.d.ts +0 -118
- package/dist/core/src/auto-suggestion-generator.js +0 -538
- package/dist/core/src/communication-service.d.ts +0 -47
- package/dist/core/src/communication-service.js +0 -124
- package/dist/core/src/index.d.ts +0 -11
- package/dist/core/src/index.js +0 -15
- package/dist/core/src/models.d.ts +0 -137
- package/dist/core/src/models.js +0 -5
- package/dist/core/src/sdk.d.ts +0 -166
- package/dist/core/src/sdk.js +0 -387
- package/dist/core/src/state-manager.d.ts +0 -200
- package/dist/core/src/state-manager.js +0 -368
- package/dist/core/src/widget-css.d.ts +0 -14
- package/dist/core/src/widget-css.js +0 -389
- package/dist/react/src/ShadowWrapper.d.ts +0 -12
- package/dist/react/src/ShadowWrapper.js +0 -44
- package/dist/react/src/components.d.ts +0 -25
- package/dist/react/src/components.js +0 -226
- package/dist/react/src/hooks.d.ts +0 -64
- package/dist/react/src/hooks.js +0 -181
- package/dist/react/src/index.d.ts +0 -7
- package/dist/react/src/index.js +0 -5
package/dist/ShadowWrapper.d.ts
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* ShadowWrapper — renders children inside a Shadow DOM
|
|
3
|
-
* is completely isolated from the host application's styles.
|
|
2
|
+
* ShadowWrapper — renders children inside a Shadow DOM.
|
|
4
3
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* 2. Full element reset inside the shadow — counters any UA-sheet or inherited font changes
|
|
8
|
-
* 3. Google Fonts injected into document <head> (fonts are shared across shadow trees)
|
|
9
|
-
* 4. React portal into a container that lives inside the shadow root
|
|
4
|
+
* CSS lives in ONE place: packages/core/src/widget-css.ts
|
|
5
|
+
* Resolved via the npm workspace symlink → no install needed.
|
|
10
6
|
*/
|
|
11
7
|
import React from 'react';
|
|
12
8
|
export declare const ShadowWrapper: React.FC<{
|
package/dist/ShadowWrapper.js
CHANGED
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
/**
|
|
3
|
-
* ShadowWrapper — renders children inside a Shadow DOM
|
|
4
|
-
* is completely isolated from the host application's styles.
|
|
3
|
+
* ShadowWrapper — renders children inside a Shadow DOM.
|
|
5
4
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* 2. Full element reset inside the shadow — counters any UA-sheet or inherited font changes
|
|
9
|
-
* 3. Google Fonts injected into document <head> (fonts are shared across shadow trees)
|
|
10
|
-
* 4. React portal into a container that lives inside the shadow root
|
|
5
|
+
* CSS lives in ONE place: packages/core/src/widget-css.ts
|
|
6
|
+
* Resolved via the npm workspace symlink → no install needed.
|
|
11
7
|
*/
|
|
12
8
|
import { useRef, useEffect, useState } from 'react';
|
|
13
9
|
import { createPortal } from 'react-dom';
|
|
14
|
-
|
|
10
|
+
import { WIDGET_CSS } from '@courseecho/ai-core-sdk';
|
|
11
|
+
// Inter font must be in document <head> — fonts are shared across shadow DOM boundaries
|
|
15
12
|
function ensureFont() {
|
|
16
13
|
if (typeof document === 'undefined')
|
|
17
14
|
return;
|
|
@@ -23,186 +20,18 @@ function ensureFont() {
|
|
|
23
20
|
link.href = 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap';
|
|
24
21
|
document.head.appendChild(link);
|
|
25
22
|
}
|
|
26
|
-
const WIDGET_CSS = `
|
|
27
|
-
/* ── Total isolation from host app ───────────────────────────────────────── */
|
|
28
|
-
:host {
|
|
29
|
-
all: initial !important;
|
|
30
|
-
display: block !important;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/* Guarantee every element inside the shadow starts from a known baseline */
|
|
34
|
-
*, *::before, *::after {
|
|
35
|
-
box-sizing: border-box !important;
|
|
36
|
-
margin: 0 !important;
|
|
37
|
-
padding: 0 !important;
|
|
38
|
-
border: 0 !important;
|
|
39
|
-
font-size: 100% !important;
|
|
40
|
-
font: inherit !important;
|
|
41
|
-
vertical-align: baseline !important;
|
|
42
|
-
line-height: inherit !important;
|
|
43
|
-
color: inherit !important;
|
|
44
|
-
background: transparent !important;
|
|
45
|
-
text-decoration: none !important;
|
|
46
|
-
list-style: none !important;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/* Restore sensible block/inline defaults that the above stripped */
|
|
50
|
-
div, section, article, header, footer, main, nav, aside { display: block !important; }
|
|
51
|
-
span, em, strong, small, code, kbd { display: inline !important; }
|
|
52
|
-
button { display: inline-flex !important; cursor: pointer !important; }
|
|
53
|
-
textarea, input { display: block !important; }
|
|
54
|
-
ul, ol { display: flex !important; flex-direction: column !important; }
|
|
55
|
-
a { cursor: pointer !important; }
|
|
56
|
-
|
|
57
|
-
/* ── Widget component styles ─────────────────────────────────────────────── */
|
|
58
|
-
.aiwg-root *, .aiwg-root *::before, .aiwg-root *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
59
|
-
|
|
60
|
-
.aiwg-root {
|
|
61
|
-
--aiwg-primary: #6366f1;
|
|
62
|
-
--aiwg-primary-dark: #8b5cf6;
|
|
63
|
-
--aiwg-fg-color: #ffffff;
|
|
64
|
-
--aiwg-bg-color: #ffffff;
|
|
65
|
-
--aiwg-chat-bg: #f1f5f9;
|
|
66
|
-
|
|
67
|
-
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
68
|
-
font-size: 14px; line-height: 1.5; color: #1a1a2e;
|
|
69
|
-
display: flex; flex-direction: column; overflow: hidden;
|
|
70
|
-
border-radius: 16px; background: var(--aiwg-bg-color);
|
|
71
|
-
position: fixed; bottom: 24px; right: 24px;
|
|
72
|
-
width: 380px !important; max-width: calc(100vw - 48px) !important;
|
|
73
|
-
z-index: 99999;
|
|
74
|
-
transition: height 0.25s ease;
|
|
75
|
-
box-shadow: 0 24px 64px rgba(0,0,0,0.18);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
.aiwg-header { background: linear-gradient(135deg,#6366f1 0%,#8b5cf6 100%); padding: 16px 20px; display: flex; align-items: center; gap: 12px; flex-shrink: 0; position: relative; overflow: hidden; }
|
|
79
|
-
.aiwg-header::before { content:''; position:absolute; width:140px; height:140px; background:rgba(255,255,255,.08); border-radius:50%; top:-50px; right:-30px; }
|
|
80
|
-
.aiwg-avatar { width:40px; height:40px; background:rgba(255,255,255,.25); border-radius:50%; display:flex; align-items:center; justify-content:center; font-size:18px; flex-shrink:0; border:2px solid rgba(255,255,255,.4); }
|
|
81
|
-
.aiwg-header-info { flex:1; }
|
|
82
|
-
.aiwg-title { color:#fff; font-weight:600; font-size:15px; }
|
|
83
|
-
.aiwg-subtitle { color:rgba(255,255,255,.75); font-size:12px; display:flex; align-items:center; gap:5px; }
|
|
84
|
-
.aiwg-online-dot { width:7px; height:7px; background:#4ade80; border-radius:50%; display:inline-block; animation:aiwg-pulse 2s ease-in-out infinite; }
|
|
85
|
-
@keyframes aiwg-pulse { 0%,100%{opacity:1;transform:scale(1)} 50%{opacity:.6;transform:scale(.85)} }
|
|
86
|
-
.aiwg-minimize-btn { width:36px; height:36px; background:rgba(255,255,255,.18); border:1.5px solid rgba(255,255,255,.3); border-radius:50%; color:#fff; cursor:pointer !important; display:flex; align-items:center; justify-content:center; font-size:18px; line-height:1; transition:background .15s,transform .15s; flex-shrink:0; position:relative; z-index:2; }
|
|
87
|
-
.aiwg-minimize-btn * { pointer-events:none; }
|
|
88
|
-
.aiwg-minimize-btn:hover { background:rgba(255,255,255,.32); transform:scale(1.08); }
|
|
89
|
-
|
|
90
|
-
.aiwg-messages { flex:1; overflow-y:auto; padding:20px 16px 8px; scroll-behavior:smooth; display:flex; flex-direction:column; gap:12px; }
|
|
91
|
-
.aiwg-messages::-webkit-scrollbar { width:4px; }
|
|
92
|
-
.aiwg-messages::-webkit-scrollbar-thumb { background:#e2e8f0; border-radius:99px; }
|
|
93
|
-
|
|
94
|
-
.aiwg-welcome { text-align:center; padding:24px 16px; display:flex; flex-direction:column; align-items:center; gap:8px; }
|
|
95
|
-
.aiwg-welcome-icon { font-size:36px; margin-bottom:4px; }
|
|
96
|
-
.aiwg-welcome h4 { font-size:15px; font-weight:600; color:#1a1a2e; }
|
|
97
|
-
.aiwg-welcome p { font-size:13px; color:#64748b; }
|
|
98
|
-
|
|
99
|
-
.aiwg-msg { display:flex; gap:8px; align-items:flex-end; animation:aiwg-fade-up .2s ease both; }
|
|
100
|
-
@keyframes aiwg-fade-up { from{opacity:0;transform:translateY(8px)} to{opacity:1;transform:translateY(0)} }
|
|
101
|
-
.aiwg-msg--user { flex-direction:row-reverse; }
|
|
102
|
-
.aiwg-msg-avatar { width:28px; height:28px; border-radius:50%; display:flex; align-items:center; justify-content:center; font-size:13px; flex-shrink:0; margin-bottom:2px; }
|
|
103
|
-
.aiwg-msg--bot .aiwg-msg-avatar { background:linear-gradient(135deg,#6366f1,#8b5cf6); color:#fff; }
|
|
104
|
-
.aiwg-msg--user .aiwg-msg-avatar { background:#e2e8f0; color:#64748b; }
|
|
105
|
-
.aiwg-msg-body { max-width:78%; }
|
|
106
|
-
.aiwg-msg-bubble { padding:10px 14px; border-radius:18px; font-size:14px; line-height:1.55; word-break:break-word; }
|
|
107
|
-
.aiwg-msg--bot .aiwg-msg-bubble { background:#f1f5f9; color:#1a1a2e; border-bottom-left-radius:4px; }
|
|
108
|
-
.aiwg-msg--user .aiwg-msg-bubble { background:linear-gradient(135deg,#6366f1,#8b5cf6); color:#fff; border-bottom-right-radius:4px; }
|
|
109
|
-
.aiwg-msg-time { font-size:10px; color:#94a3b8; margin-top:4px; text-align:right; padding:0 4px; }
|
|
110
|
-
.aiwg-msg--bot .aiwg-msg-time { text-align:left; }
|
|
111
|
-
|
|
112
|
-
.aiwg-msg-bubble strong { font-weight:600; }
|
|
113
|
-
.aiwg-msg-bubble em { font-style:italic; }
|
|
114
|
-
.aiwg-msg-bubble code { background:rgba(0,0,0,.08); padding:1px 5px; border-radius:4px; font-family:'Fira Code','Consolas',monospace; font-size:.9em; }
|
|
115
|
-
.aiwg-msg--user .aiwg-msg-bubble code { background:rgba(255,255,255,.2); }
|
|
116
|
-
.aiwg-msg-bubble ol, .aiwg-msg-bubble ul { padding-left:18px; margin:6px 0; display:flex; flex-direction:column; gap:3px; }
|
|
117
|
-
.aiwg-msg-bubble ol { list-style:decimal; }
|
|
118
|
-
.aiwg-msg-bubble ul { list-style:disc; }
|
|
119
|
-
.aiwg-msg-bubble li { line-height:1.5; }
|
|
120
|
-
.aiwg-msg-bubble h3,.aiwg-msg-bubble h4 { font-weight:600; margin:8px 0 4px; }
|
|
121
|
-
.aiwg-msg-bubble p { margin:2px 0; }
|
|
122
|
-
|
|
123
|
-
.aiwg-typing { padding:10px 14px; }
|
|
124
|
-
.aiwg-typing-dots { display:flex; gap:4px; align-items:center; }
|
|
125
|
-
.aiwg-typing-dots span { width:7px; height:7px; background:#94a3b8; border-radius:50%; animation:aiwg-bounce 1.2s ease-in-out infinite; }
|
|
126
|
-
.aiwg-typing-dots span:nth-child(2) { animation-delay:.2s; }
|
|
127
|
-
.aiwg-typing-dots span:nth-child(3) { animation-delay:.4s; }
|
|
128
|
-
@keyframes aiwg-bounce { 0%,80%,100%{transform:translateY(0)} 40%{transform:translateY(-6px)} }
|
|
129
|
-
|
|
130
|
-
.aiwg-chip-row { padding:6px 16px 2px; display:flex; flex-wrap:wrap; gap:6px; flex-shrink:0; }
|
|
131
|
-
.aiwg-chip { background:#f1f5f9; border:1px solid #e2e8f0; border-radius:99px; padding:4px 12px; font-size:12px; color:#4f46e5; cursor:pointer; transition:all .15s; white-space:nowrap; font-weight:500; }
|
|
132
|
-
.aiwg-chip:hover { background:#ede9fe; border-color:#a5b4fc; }
|
|
133
|
-
|
|
134
|
-
.aiwg-input-area { padding:12px 16px 16px; flex-shrink:0; background:#fff; border-top:1px solid #f1f5f9; position:relative; }
|
|
135
|
-
|
|
136
|
-
.aiwg-suggestions { position:absolute; bottom:calc(100% + 4px); left:16px; right:16px; background:#fff; border:1px solid #e2e8f0; border-radius:12px; box-shadow:0 8px 24px rgba(0,0,0,.12); overflow:hidden; z-index:100; animation:aiwg-fade-up .15s ease both; }
|
|
137
|
-
.aiwg-suggestions-header { padding:8px 14px 4px; font-size:11px; font-weight:600; color:#94a3b8; text-transform:uppercase; letter-spacing:.06em; border-bottom:1px solid #f1f5f9; }
|
|
138
|
-
.aiwg-suggestion-item { display:flex; align-items:center; gap:10px; padding:10px 14px; cursor:pointer; transition:background .1s; border-bottom:1px solid #f8fafc; }
|
|
139
|
-
.aiwg-suggestion-item:last-child { border-bottom:none; }
|
|
140
|
-
.aiwg-suggestion-item:hover,.aiwg-suggestion-item.aiwg-active { background:#f5f3ff; }
|
|
141
|
-
.aiwg-suggestion-icon { font-size:16px; flex-shrink:0; }
|
|
142
|
-
.aiwg-suggestion-main { flex:1; min-width:0; }
|
|
143
|
-
.aiwg-suggestion-text { font-size:13px; font-weight:500; color:#1a1a2e; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
|
|
144
|
-
.aiwg-suggestion-text mark { background:none; color:#6366f1; font-weight:600; }
|
|
145
|
-
.aiwg-suggestion-desc { font-size:11px; color:#94a3b8; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
|
|
146
|
-
.aiwg-suggestion-badge { font-size:10px; font-weight:600; padding:2px 8px; border-radius:99px; background:#ede9fe; color:#6366f1; flex-shrink:0; }
|
|
147
|
-
.aiwg-kbd-hint { padding:6px 14px; font-size:11px; color:#cbd5e1; background:#f8fafc; display:flex; justify-content:flex-end; gap:10px; }
|
|
148
|
-
.aiwg-kbd-hint kbd { font-family:inherit; background:#e2e8f0; border-radius:4px; padding:1px 5px; font-size:10px; color:#64748b; }
|
|
149
|
-
|
|
150
|
-
.aiwg-input-row { display:flex; gap:8px; align-items:flex-end; }
|
|
151
|
-
.aiwg-input { flex:1; border:1.5px solid #e2e8f0; border-radius:12px; padding:10px 14px; font-size:14px; font-family:inherit; outline:none; resize:none; background:#f8fafc; color:#1a1a2e; transition:border-color .15s,box-shadow .15s,background .15s; line-height:1.4; max-height:120px; overflow-y:auto; scrollbar-width:none; -ms-overflow-style:none; }
|
|
152
|
-
.aiwg-input::-webkit-scrollbar { display:none; }
|
|
153
|
-
.aiwg-input::placeholder { color:#94a3b8; }
|
|
154
|
-
.aiwg-input:focus { border-color:#8b5cf6; background:#fff; box-shadow:0 0 0 3px rgba(139,92,246,.1); }
|
|
155
|
-
.aiwg-send-btn { width:42px; height:42px; background:linear-gradient(135deg,#6366f1,#8b5cf6); border:none; border-radius:12px; color:#fff; cursor:pointer; display:flex; align-items:center; justify-content:center; flex-shrink:0; transition:transform .15s,box-shadow .15s,opacity .15s; box-shadow:0 4px 12px rgba(99,102,241,.35); }
|
|
156
|
-
.aiwg-send-btn svg { width:18px; height:18px; }
|
|
157
|
-
.aiwg-send-btn:hover { transform:translateY(-1px); box-shadow:0 6px 16px rgba(99,102,241,.4); }
|
|
158
|
-
.aiwg-send-btn:active { transform:translateY(0); }
|
|
159
|
-
.aiwg-send-btn:disabled { opacity:.5; cursor:not-allowed; transform:none; }
|
|
160
|
-
|
|
161
|
-
.aiwg-error { margin:0 16px 8px; padding:8px 12px; background:#fef2f2; border:1px solid #fecaca; border-radius:8px; font-size:12px; color:#dc2626; }
|
|
162
|
-
|
|
163
|
-
.aiwg-root.aiwg-minimized .aiwg-messages,
|
|
164
|
-
.aiwg-root.aiwg-minimized .aiwg-chip-row,
|
|
165
|
-
.aiwg-root.aiwg-minimized .aiwg-error,
|
|
166
|
-
.aiwg-root.aiwg-minimized .aiwg-input-area,
|
|
167
|
-
.aiwg-root.aiwg-minimized .aiwg-powered { display:none !important; }
|
|
168
|
-
.aiwg-root.aiwg-minimized .aiwg-minimize-btn { display:none !important; }
|
|
169
|
-
.aiwg-root.aiwg-minimized { cursor:pointer; }
|
|
170
|
-
.aiwg-root.aiwg-minimized .aiwg-header { cursor:pointer !important; }
|
|
171
|
-
|
|
172
|
-
.aiwg-powered { text-align:center; padding:6px 16px 10px; font-size:11px; color:#94a3b8; flex-shrink:0; border-top:1px solid #f1f5f9; background:#fff; }
|
|
173
|
-
.aiwg-powered a { color:#6366f1; text-decoration:none; font-weight:500; }
|
|
174
|
-
.aiwg-powered a:hover { text-decoration:underline; }
|
|
175
|
-
|
|
176
|
-
.aiwg-dark { background:#0f172a; color:#e2e8f0; }
|
|
177
|
-
.aiwg-dark .aiwg-msg--bot .aiwg-msg-bubble { background:#1e293b; color:#e2e8f0; }
|
|
178
|
-
.aiwg-dark .aiwg-input-area { background:#0f172a; border-top-color:#1e293b; }
|
|
179
|
-
.aiwg-dark .aiwg-input { background:#1e293b; border-color:#334155; color:#e2e8f0; }
|
|
180
|
-
.aiwg-dark .aiwg-input:focus { border-color:#8b5cf6; background:#1e293b; }
|
|
181
|
-
.aiwg-dark .aiwg-suggestions { background:#1e293b; border-color:#334155; }
|
|
182
|
-
.aiwg-dark .aiwg-suggestions-header { color:#64748b; border-bottom-color:#334155; }
|
|
183
|
-
.aiwg-dark .aiwg-suggestion-item { border-bottom-color:#0f172a; }
|
|
184
|
-
.aiwg-dark .aiwg-suggestion-item:hover,.aiwg-dark .aiwg-suggestion-item.aiwg-active { background:#2d1b69; }
|
|
185
|
-
.aiwg-dark .aiwg-suggestion-text { color:#e2e8f0; }
|
|
186
|
-
.aiwg-dark .aiwg-chip { background:#1e293b; border-color:#334155; }
|
|
187
|
-
.aiwg-dark .aiwg-chip:hover { background:#2d1b69; }
|
|
188
|
-
.aiwg-dark .aiwg-kbd-hint { background:#1e293b; }
|
|
189
|
-
.aiwg-dark .aiwg-welcome h4 { color:#e2e8f0; }
|
|
190
|
-
.aiwg-dark .aiwg-powered { background:#0f172a; border-top-color:#1e293b; }
|
|
191
|
-
`;
|
|
192
23
|
export const ShadowWrapper = ({ children }) => {
|
|
193
24
|
const hostRef = useRef(null);
|
|
194
25
|
const [portalTarget, setPortalTarget] = useState(null);
|
|
195
26
|
useEffect(() => {
|
|
196
|
-
ensureFont();
|
|
27
|
+
ensureFont();
|
|
197
28
|
const host = hostRef.current;
|
|
198
29
|
if (!host || host.shadowRoot)
|
|
199
30
|
return;
|
|
200
31
|
const shadow = host.attachShadow({ mode: 'open' });
|
|
201
|
-
// Inject all widget CSS into the shadow root
|
|
202
32
|
const style = document.createElement('style');
|
|
203
33
|
style.textContent = WIDGET_CSS;
|
|
204
34
|
shadow.appendChild(style);
|
|
205
|
-
// The container where React will portal the widget tree
|
|
206
35
|
const container = document.createElement('div');
|
|
207
36
|
shadow.appendChild(container);
|
|
208
37
|
setPortalTarget(container);
|
package/dist/components.js
CHANGED
|
@@ -4,6 +4,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
4
4
|
* Usage: <AiChatWidget config={...} apiKey="..." />
|
|
5
5
|
*/
|
|
6
6
|
import { useRef, useEffect, useState, useCallback } from 'react';
|
|
7
|
+
import { ICONS } from '@courseecho/ai-core-sdk';
|
|
7
8
|
import { useAiWidget } from './hooks';
|
|
8
9
|
import { ShadowWrapper } from './ShadowWrapper';
|
|
9
10
|
// Chat sound — Web Audio API (no external files)
|
|
@@ -217,10 +218,10 @@ export const AiChatWidget = ({ config, apiKey, jwtToken, title = 'AI Assistant',
|
|
|
217
218
|
const themeClass = mergedConfig.theme === 'dark' ? 'aiwg-dark' : '';
|
|
218
219
|
const minimizedClass = isMinimized ? 'aiwg-minimized' : '';
|
|
219
220
|
const poweredByLabel = poweredBy || 'CourseEcho.com';
|
|
220
|
-
return (_jsx(ShadowWrapper, { children: _jsxs("div", { className: `aiwg-root ${themeClass} ${minimizedClass} ${className || ''}`, style: { height: isMinimized ? '72px' : expandedHeight }, children: [_jsxs("div", { className: "aiwg-header", onClick: () => isMinimized && setIsMinimized(false), children: [_jsx("div", { className: "aiwg-avatar" }), _jsxs("div", { className: "aiwg-header-info", children: [_jsx("div", { className: "aiwg-title", children: title }), _jsxs("div", { className: "aiwg-subtitle", children: [_jsx("span", { className: "aiwg-online-dot" }), subtitle] })] }), _jsx("button", { className: "aiwg-minimize-btn", "aria-label": "Minimize", onClick: (e) => { e.stopPropagation(); setIsMinimized(true); },
|
|
221
|
+
return (_jsx(ShadowWrapper, { children: _jsxs("div", { className: `aiwg-root ${themeClass} ${minimizedClass} ${className || ''}`, style: { height: isMinimized ? '72px' : expandedHeight }, children: [_jsxs("div", { className: "aiwg-header", onClick: () => isMinimized && setIsMinimized(false), children: [_jsx("div", { className: "aiwg-avatar", dangerouslySetInnerHTML: { __html: ICONS.BOT } }), _jsxs("div", { className: "aiwg-header-info", children: [_jsx("div", { className: "aiwg-title", children: title }), _jsxs("div", { className: "aiwg-subtitle", children: [_jsx("span", { className: "aiwg-online-dot" }), subtitle] })] }), _jsx("button", { className: "aiwg-minimize-btn", "aria-label": "Minimize", onClick: (e) => { e.stopPropagation(); setIsMinimized(true); }, dangerouslySetInnerHTML: { __html: ICONS.CLOSE } })] }), _jsxs("div", { className: "aiwg-messages", children: [messages.length === 0 && (_jsxs("div", { className: "aiwg-welcome", children: [_jsx("div", { className: "aiwg-welcome-icon", dangerouslySetInnerHTML: { __html: ICONS.WAVE } }), _jsx("h4", { children: "Hi there! I'm your AI assistant." }), _jsx("p", { children: "Ask me anything or pick a suggestion below." })] })), messages.map((msg) => {
|
|
221
222
|
const isUser = msg.role === 'user';
|
|
222
223
|
const time = new Date(msg.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
223
|
-
return (_jsxs("div", { className: `aiwg-msg ${isUser ? 'aiwg-msg--user' : 'aiwg-msg--bot'}`, children: [_jsx("div", { className: "aiwg-msg-avatar",
|
|
224
|
-
}), isLoading && (_jsxs("div", { className: "aiwg-msg aiwg-msg--bot", children: [_jsx("div", { className: "aiwg-msg-avatar" }), _jsx("div", { className: "aiwg-msg-body", children: _jsx("div", { className: "aiwg-msg-bubble aiwg-typing", children: _jsxs("div", { className: "aiwg-typing-dots", children: [_jsx("span", {}), _jsx("span", {}), _jsx("span", {})] }) }) })] })), error && _jsxs("div", { className: "aiwg-error", style: { display: 'block' }, children: [" ", error] }), _jsx("div", { ref: messagesEndRef })] }), chipsVisible && messages.length === 0 && (_jsx("div", { className: "aiwg-chip-row", children: allSugs.slice(0, 4).map(s => (_jsxs("button", { className: "aiwg-chip", onClick: () => selectSuggestion(s.text), children: [s.icon, " ", s.text] }, s.id))) })), _jsxs("div", { className: "aiwg-input-area", children: [showSuggestions && filteredSugs.length > 0 && (_jsxs("div", { className: "aiwg-suggestions", children: [_jsx("div", { className: "aiwg-suggestions-header", children: "Suggestions" }), _jsx("div", { className: "aiwg-suggestions-list", children: filteredSugs.map((s, i) => (_jsxs("div", { className: `aiwg-suggestion-item${i === activeIdx ? ' aiwg-active' : ''}`, onMouseEnter: () => setActiveIdx(i), onClick: () => selectSuggestion(s.text), children: [s.icon && _jsx("span", { className: "aiwg-suggestion-icon", children: s.icon }), _jsxs("div", { className: "aiwg-suggestion-main", children: [_jsx("div", { className: "aiwg-suggestion-text", children: s.text }), s.description && _jsx("div", { className: "aiwg-suggestion-desc", children: s.description })] }), s.category && _jsx("span", { className: "aiwg-suggestion-badge", children: s.category })] }, s.id))) }), _jsxs("div", { className: "aiwg-kbd-hint", children: [_jsxs("span", { children: [_jsx("kbd", {}), " navigate"] }), _jsxs("span", { children: [_jsx("kbd", {}), " select"] }), _jsxs("span", { children: [_jsx("kbd", { children: "Esc" }), " close"] })] })] })), _jsxs("div", { className: "aiwg-input-row", children: [_jsx("textarea", { ref: inputRef, className: "aiwg-input", placeholder: placeholder, value: userInput, rows: 1, onChange: handleInputChange, onFocus: () => filterSugs(userInput), onKeyDown: handleKeyDown, disabled: isLoading, "aria-label": "Chat message input" }), _jsx("button", { className: "aiwg-send-btn", type: "button", disabled: isLoading || !userInput.trim(), onClick: () => doSend(userInput), "aria-label": "Send", children: _jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("line", { x1: "22", y1: "2", x2: "11", y2: "13" }), _jsx("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })] }) })] })] }), _jsxs("div", { className: "aiwg-powered", children: ["Powered by", ' ', _jsx("a", { href: poweredByUrl, target: "_blank", rel: "noopener noreferrer", children: poweredByLabel })] })] }) }));
|
|
224
|
+
return (_jsxs("div", { className: `aiwg-msg ${isUser ? 'aiwg-msg--user' : 'aiwg-msg--bot'}`, children: [_jsx("div", { className: "aiwg-msg-avatar", dangerouslySetInnerHTML: { __html: isUser ? ICONS.USER : ICONS.BOT } }), _jsxs("div", { className: "aiwg-msg-body", children: [_jsx("div", { className: "aiwg-msg-bubble", children: isUser ? msg.content : renderMarkdown(msg.content) }), _jsx("div", { className: "aiwg-msg-time", children: time })] })] }, msg.id));
|
|
225
|
+
}), isLoading && (_jsxs("div", { className: "aiwg-msg aiwg-msg--bot", children: [_jsx("div", { className: "aiwg-msg-avatar", dangerouslySetInnerHTML: { __html: ICONS.BOT } }), _jsx("div", { className: "aiwg-msg-body", children: _jsx("div", { className: "aiwg-msg-bubble aiwg-typing", children: _jsxs("div", { className: "aiwg-typing-dots", children: [_jsx("span", {}), _jsx("span", {}), _jsx("span", {})] }) }) })] })), error && _jsxs("div", { className: "aiwg-error", style: { display: 'block' }, children: [" ", error] }), _jsx("div", { ref: messagesEndRef })] }), chipsVisible && messages.length === 0 && (_jsx("div", { className: "aiwg-chip-row", children: allSugs.slice(0, 4).map(s => (_jsxs("button", { className: "aiwg-chip", onClick: () => selectSuggestion(s.text), children: [s.icon, " ", s.text] }, s.id))) })), _jsxs("div", { className: "aiwg-input-area", children: [showSuggestions && filteredSugs.length > 0 && (_jsxs("div", { className: "aiwg-suggestions", children: [_jsx("div", { className: "aiwg-suggestions-header", children: "Suggestions" }), _jsx("div", { className: "aiwg-suggestions-list", children: filteredSugs.map((s, i) => (_jsxs("div", { className: `aiwg-suggestion-item${i === activeIdx ? ' aiwg-active' : ''}`, onMouseEnter: () => setActiveIdx(i), onClick: () => selectSuggestion(s.text), children: [s.icon && _jsx("span", { className: "aiwg-suggestion-icon", children: s.icon }), _jsxs("div", { className: "aiwg-suggestion-main", children: [_jsx("div", { className: "aiwg-suggestion-text", children: s.text }), s.description && _jsx("div", { className: "aiwg-suggestion-desc", children: s.description })] }), s.category && _jsx("span", { className: "aiwg-suggestion-badge", children: s.category })] }, s.id))) }), _jsxs("div", { className: "aiwg-kbd-hint", children: [_jsxs("span", { children: [_jsx("kbd", {}), " navigate"] }), _jsxs("span", { children: [_jsx("kbd", {}), " select"] }), _jsxs("span", { children: [_jsx("kbd", { children: "Esc" }), " close"] })] })] })), _jsxs("div", { className: "aiwg-input-row", children: [_jsx("textarea", { ref: inputRef, className: "aiwg-input", placeholder: placeholder, value: userInput, rows: 1, onChange: handleInputChange, onFocus: () => filterSugs(userInput), onKeyDown: handleKeyDown, disabled: isLoading, "aria-label": "Chat message input" }), _jsx("button", { className: "aiwg-send-btn", type: "button", disabled: isLoading || !userInput.trim(), onClick: () => doSend(userInput), "aria-label": "Send", children: _jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("line", { x1: "22", y1: "2", x2: "11", y2: "13" }), _jsx("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })] }) })] })] }), _jsxs("div", { className: "aiwg-powered", children: ["Powered by", ' ', _jsx("a", { href: poweredByUrl, target: "_blank", rel: "noopener noreferrer", children: poweredByLabel })] })] }) }));
|
|
225
226
|
};
|
|
226
227
|
export default AiChatWidget;
|
package/package.json
CHANGED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Page Content Scanner and AI Suggestion Generator
|
|
3
|
-
* Automatically extracts page content and generates AI-powered suggestions
|
|
4
|
-
*/
|
|
5
|
-
import { AiSuggestion, PageScanConfig, AiSuggestionGeneratorConfig } from './models';
|
|
6
|
-
export interface PageContent {
|
|
7
|
-
url: string;
|
|
8
|
-
title: string;
|
|
9
|
-
description: string;
|
|
10
|
-
headings: string[];
|
|
11
|
-
keywords: string[];
|
|
12
|
-
pageType: string;
|
|
13
|
-
rawText: string;
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Scans page content and extracts relevant information
|
|
17
|
-
*/
|
|
18
|
-
export declare class PageContentScanner {
|
|
19
|
-
private config;
|
|
20
|
-
private cachedContent;
|
|
21
|
-
constructor(config?: PageScanConfig);
|
|
22
|
-
/**
|
|
23
|
-
* Scan page content
|
|
24
|
-
*/
|
|
25
|
-
scanPage(): PageContent;
|
|
26
|
-
/**
|
|
27
|
-
* Get cached content if still valid
|
|
28
|
-
*/
|
|
29
|
-
private getCachedContent;
|
|
30
|
-
/**
|
|
31
|
-
* Cache content
|
|
32
|
-
*/
|
|
33
|
-
private cacheContent;
|
|
34
|
-
/**
|
|
35
|
-
* Extract page title
|
|
36
|
-
*/
|
|
37
|
-
private extractTitle;
|
|
38
|
-
/**
|
|
39
|
-
* Extract meta description
|
|
40
|
-
*/
|
|
41
|
-
private extractDescription;
|
|
42
|
-
/**
|
|
43
|
-
* Extract all headings
|
|
44
|
-
*/
|
|
45
|
-
private extractHeadings;
|
|
46
|
-
/**
|
|
47
|
-
* Extract keywords from meta tags
|
|
48
|
-
*/
|
|
49
|
-
private extractKeywords;
|
|
50
|
-
/**
|
|
51
|
-
* Detect page type (course, product, blog, etc.)
|
|
52
|
-
*/
|
|
53
|
-
private detectPageType;
|
|
54
|
-
/**
|
|
55
|
-
* Extract main text content
|
|
56
|
-
*/
|
|
57
|
-
private extractMainContent;
|
|
58
|
-
/**
|
|
59
|
-
* Clear cache
|
|
60
|
-
*/
|
|
61
|
-
clearCache(): void;
|
|
62
|
-
/**
|
|
63
|
-
* Update config
|
|
64
|
-
*/
|
|
65
|
-
updateConfig(config: Partial<PageScanConfig>): void;
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Generates AI-powered suggestions based on page content
|
|
69
|
-
*/
|
|
70
|
-
export declare class AiSuggestionGenerator {
|
|
71
|
-
private config;
|
|
72
|
-
private pageScanner;
|
|
73
|
-
constructor(config?: AiSuggestionGeneratorConfig, pageScanner?: PageContentScanner);
|
|
74
|
-
/**
|
|
75
|
-
* Generate suggestions based on page content
|
|
76
|
-
*/
|
|
77
|
-
generateSuggestions(): Promise<AiSuggestion[]>;
|
|
78
|
-
/**
|
|
79
|
-
* Free tier: Generate suggestions locally based on heuristics
|
|
80
|
-
*/
|
|
81
|
-
private generateFreeSuggestions;
|
|
82
|
-
/**
|
|
83
|
-
* Premium tier: Use backend AI for smart suggestions
|
|
84
|
-
*/
|
|
85
|
-
private generatePremiumSuggestions;
|
|
86
|
-
/**
|
|
87
|
-
* Course page suggestions
|
|
88
|
-
*/
|
|
89
|
-
private generateCourseSuggestions;
|
|
90
|
-
/**
|
|
91
|
-
* Product page suggestions
|
|
92
|
-
*/
|
|
93
|
-
private generateProductSuggestions;
|
|
94
|
-
/**
|
|
95
|
-
* Blog page suggestions
|
|
96
|
-
*/
|
|
97
|
-
private generateBlogSuggestions;
|
|
98
|
-
/**
|
|
99
|
-
* Support page suggestions
|
|
100
|
-
*/
|
|
101
|
-
private generateSupportSuggestions;
|
|
102
|
-
/**
|
|
103
|
-
* Documentation page suggestions
|
|
104
|
-
*/
|
|
105
|
-
private generateDocsSuggestions;
|
|
106
|
-
/**
|
|
107
|
-
* Generic page suggestions
|
|
108
|
-
*/
|
|
109
|
-
private generateGenericSuggestions;
|
|
110
|
-
/**
|
|
111
|
-
* Update config
|
|
112
|
-
*/
|
|
113
|
-
updateConfig(config: Partial<AiSuggestionGeneratorConfig>): void;
|
|
114
|
-
/**
|
|
115
|
-
* Get current tier
|
|
116
|
-
*/
|
|
117
|
-
getTier(): string;
|
|
118
|
-
}
|