@courseecho/ai-core-sdk 1.0.20 → 1.0.21

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.ts CHANGED
@@ -8,3 +8,4 @@ export { ChatStateManager, ContextStateManager, ChartManager, SuggestionManager,
8
8
  export { PageContentScanner, AiSuggestionGenerator, type PageContent, } from './auto-suggestion-generator';
9
9
  export { AiWidgetSDK } from './sdk';
10
10
  export type { StateListener } from './state-manager';
11
+ export { WIDGET_CSS } from './widget-css';
package/dist/index.js CHANGED
@@ -11,3 +11,5 @@ export { ChatStateManager, ContextStateManager, ChartManager, SuggestionManager,
11
11
  export { PageContentScanner, AiSuggestionGenerator, } from './auto-suggestion-generator';
12
12
  // Main SDK
13
13
  export { AiWidgetSDK } from './sdk';
14
+ // Canonical widget CSS (used by all framework packages)
15
+ export { WIDGET_CSS } from './widget-css';
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Canonical widget CSS — single source of truth for all framework packages.
3
+ *
4
+ * Isolation strategy:
5
+ * - React : injected into a Shadow DOM via ShadowWrapper (createPortal).
6
+ * :host { all: initial } resets inherited properties at the boundary.
7
+ * - jQuery : injected into attachShadow() root. Same :host reset applies.
8
+ * - Angular: ViewEncapsulation.ShadowDom — Angular handles the shadow root.
9
+ *
10
+ * NOTE: `@import` for Google Fonts does NOT work inside shadow-DOM <style> tags.
11
+ * Each package is responsible for loading the Inter font into document <head>
12
+ * separately (React: ensureFont(), jQuery: injectFontLink()).
13
+ */
14
+ export declare const WIDGET_CSS = "\n/* \u2500\u2500 Shadow-DOM host isolation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n:host {\n all: initial !important;\n display: block !important;\n}\n\n/* Scoped box-model reset \u2014 only touches widget elements, not all of shadow DOM */\n.aiwg-root *, .aiwg-root *::before, .aiwg-root *::after {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n}\n\n/* \u2500\u2500 Container \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-root {\n --aiwg-primary: #6366f1;\n --aiwg-primary-dark: #8b5cf6;\n --aiwg-fg-color: #ffffff;\n --aiwg-bg-color: #ffffff;\n --aiwg-chat-bg: #f1f5f9;\n\n font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n font-size: 14px;\n line-height: 1.5;\n color: #1a1a2e;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n border-radius: 16px;\n background: var(--aiwg-bg-color);\n position: fixed !important;\n bottom: 24px;\n right: 24px;\n width: 380px !important;\n max-width: calc(100vw - 48px) !important;\n z-index: 99999;\n transition: height 0.25s ease;\n box-shadow: 0 24px 64px rgba(0,0,0,0.18);\n}\n\n/* \u2500\u2500 Header \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-header {\n background: linear-gradient(135deg, var(--aiwg-primary) 0%, var(--aiwg-primary-dark) 100%);\n padding: 16px 20px;\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n position: relative;\n overflow: hidden;\n}\n.aiwg-header::before {\n content: '';\n position: absolute;\n width: 140px; height: 140px;\n background: rgba(255,255,255,0.08);\n border-radius: 50%;\n top: -50px; right: -30px;\n}\n.aiwg-avatar {\n width: 40px; height: 40px;\n background: rgba(255,255,255,0.25);\n border-radius: 50%;\n display: flex; align-items: center; justify-content: center;\n font-size: 18px;\n flex-shrink: 0;\n border: 2px solid rgba(255,255,255,0.4);\n}\n.aiwg-header-info { flex: 1; }\n.aiwg-title { color: #fff; font-weight: 600; font-size: 15px; }\n.aiwg-subtitle {\n color: rgba(255,255,255,0.75);\n font-size: 12px;\n display: flex; align-items: center; gap: 5px;\n}\n.aiwg-online-dot {\n width: 7px; height: 7px;\n background: #4ade80;\n border-radius: 50%;\n display: inline-block;\n animation: aiwg-pulse 2s ease-in-out infinite;\n}\n@keyframes aiwg-pulse {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.6; transform: scale(0.85); }\n}\n.aiwg-minimize-btn {\n width: 36px; height: 36px;\n background: rgba(255,255,255,0.18);\n border: 1.5px solid rgba(255,255,255,0.3);\n border-radius: 50%;\n color: #fff; cursor: pointer;\n display: flex; align-items: center; justify-content: center;\n font-size: 18px; line-height: 1;\n transition: background 0.15s, transform 0.15s;\n flex-shrink: 0;\n position: relative; z-index: 2;\n}\n.aiwg-minimize-btn * { cursor: pointer !important; pointer-events: none; }\n.aiwg-minimize-btn:hover { background: rgba(255,255,255,0.32); transform: scale(1.08); }\n\n/* \u2500\u2500 Messages area \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-messages {\n flex: 1;\n overflow-y: auto;\n padding: 20px 16px 8px;\n scroll-behavior: smooth;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.aiwg-messages::-webkit-scrollbar { width: 4px; }\n.aiwg-messages::-webkit-scrollbar-thumb { background: #e2e8f0; border-radius: 99px; }\n\n/* \u2500\u2500 Welcome card \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-welcome {\n text-align: center;\n padding: 24px 16px;\n display: flex; flex-direction: column; align-items: center; gap: 8px;\n}\n.aiwg-welcome-icon { font-size: 36px; margin-bottom: 4px; }\n.aiwg-welcome h4 { font-size: 15px; font-weight: 600; color: #1a1a2e; }\n.aiwg-welcome p { font-size: 13px; color: #64748b; }\n\n/* \u2500\u2500 Message bubbles \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-msg {\n display: flex;\n gap: 8px;\n align-items: flex-end;\n animation: aiwg-fade-up 0.2s ease both;\n}\n@keyframes aiwg-fade-up {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n}\n.aiwg-msg--user { flex-direction: row-reverse; }\n.aiwg-msg-avatar {\n width: 28px; height: 28px; border-radius: 50%;\n display: flex; align-items: center; justify-content: center;\n font-size: 13px; flex-shrink: 0;\n margin-bottom: 2px;\n}\n.aiwg-msg--bot .aiwg-msg-avatar { background: linear-gradient(135deg, var(--aiwg-primary), var(--aiwg-primary-dark)); color: var(--aiwg-fg-color); }\n.aiwg-msg--user .aiwg-msg-avatar { background: #e2e8f0; color: #64748b; }\n.aiwg-msg-body { max-width: 78%; }\n.aiwg-msg-bubble {\n padding: 10px 14px;\n border-radius: 18px;\n font-size: 14px;\n line-height: 1.55;\n word-break: break-word;\n}\n.aiwg-msg--bot .aiwg-msg-bubble { background: var(--aiwg-chat-bg); color: #1a1a2e; border-bottom-left-radius: 4px; }\n.aiwg-msg--user .aiwg-msg-bubble { background: linear-gradient(135deg, var(--aiwg-primary), var(--aiwg-primary-dark)); color: var(--aiwg-fg-color); border-bottom-right-radius: 4px; }\n.aiwg-msg-time { font-size: 10px; color: #94a3b8; margin-top: 4px; text-align: right; padding: 0 4px; }\n.aiwg-msg--bot .aiwg-msg-time { text-align: left; }\n\n/* \u2500\u2500 Typing indicator \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-typing { padding: 10px 14px; }\n.aiwg-typing-dots { display: flex; gap: 4px; align-items: center; }\n.aiwg-typing-dots span {\n width: 7px; height: 7px;\n background: #94a3b8; border-radius: 50%;\n animation: aiwg-bounce 1.2s ease-in-out infinite;\n}\n.aiwg-typing-dots span:nth-child(2) { animation-delay: 0.2s; }\n.aiwg-typing-dots span:nth-child(3) { animation-delay: 0.4s; }\n@keyframes aiwg-bounce {\n 0%, 80%, 100% { transform: translateY(0); }\n 40% { transform: translateY(-6px); }\n}\n\n/* \u2500\u2500 Quick-reply chips \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-chip-row {\n padding: 6px 16px 2px;\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n flex-shrink: 0;\n}\n.aiwg-chip {\n background: #f1f5f9;\n border: 1px solid #e2e8f0;\n border-radius: 99px;\n padding: 4px 12px;\n font-size: 12px;\n color: #4f46e5;\n cursor: pointer;\n transition: all 0.15s;\n white-space: nowrap;\n font-weight: 500;\n}\n.aiwg-chip:hover { background: #ede9fe; border-color: #a5b4fc; }\n.aiwg-chip-shimmer {\n background: linear-gradient(90deg, #e2e8f0 25%, #f1f5f9 50%, #e2e8f0 75%);\n background-size: 200% 100%;\n border: 1px solid transparent;\n border-radius: 99px;\n padding: 4px 34px;\n animation: aiwg-shimmer 1.4s ease-in-out infinite;\n cursor: default;\n pointer-events: none;\n}\n.aiwg-chip-ai-badge {\n display: inline-block;\n font-size: 9px; font-weight: 700;\n background: linear-gradient(135deg, var(--aiwg-primary), var(--aiwg-primary-dark));\n color: #fff;\n padding: 1px 5px;\n border-radius: 99px;\n margin-left: 5px;\n vertical-align: middle;\n letter-spacing: 0.04em;\n}\n@keyframes aiwg-shimmer {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n\n/* \u2500\u2500 Input area \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-input-area {\n padding: 12px 16px 16px;\n flex-shrink: 0;\n background: #fff;\n border-top: 1px solid #f1f5f9;\n position: relative;\n}\n.aiwg-input-row { display: flex; gap: 8px; align-items: flex-end; }\n.aiwg-input {\n flex: 1;\n border: 1.5px solid #e2e8f0;\n border-radius: 12px;\n padding: 10px 14px;\n font-size: 14px;\n font-family: inherit;\n outline: none;\n resize: none;\n background: #f8fafc;\n color: #1a1a2e;\n transition: border-color 0.15s, box-shadow 0.15s, background 0.15s;\n line-height: 1.4;\n max-height: 120px;\n overflow-y: auto;\n scrollbar-width: none;\n -ms-overflow-style: none;\n}\n.aiwg-input::-webkit-scrollbar { display: none; }\n.aiwg-input::placeholder { color: #94a3b8; }\n.aiwg-input:focus {\n border-color: var(--aiwg-primary-dark);\n background: #fff;\n box-shadow: 0 0 0 3px rgba(139,92,246,0.1);\n}\n.aiwg-send-btn {\n width: 42px; height: 42px;\n background: linear-gradient(135deg, var(--aiwg-primary), var(--aiwg-primary-dark));\n border: none; border-radius: 12px;\n color: var(--aiwg-fg-color); cursor: pointer;\n display: flex; align-items: center; justify-content: center;\n flex-shrink: 0;\n transition: transform 0.15s, box-shadow 0.15s, opacity 0.15s;\n box-shadow: 0 4px 12px rgba(99,102,241,0.35);\n}\n.aiwg-send-btn svg { width: 18px; height: 18px; }\n.aiwg-send-btn:hover { transform: translateY(-1px); box-shadow: 0 6px 16px rgba(99,102,241,0.4); }\n.aiwg-send-btn:active { transform: translateY(0); }\n.aiwg-send-btn:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }\n\n/* \u2500\u2500 Autocomplete suggestions dropdown \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-suggestions {\n position: absolute;\n bottom: calc(100% + 4px);\n left: 16px; right: 16px;\n background: #fff;\n border: 1px solid #e2e8f0;\n border-radius: 12px;\n box-shadow: 0 8px 24px rgba(0,0,0,0.12);\n overflow: hidden;\n z-index: 100;\n animation: aiwg-fade-up 0.15s ease both;\n}\n.aiwg-suggestions-header {\n padding: 8px 14px 4px;\n font-size: 11px; font-weight: 600;\n color: #94a3b8;\n text-transform: uppercase; letter-spacing: 0.06em;\n border-bottom: 1px solid #f1f5f9;\n}\n.aiwg-suggestion-item {\n display: flex; align-items: center; gap: 10px;\n padding: 10px 14px;\n cursor: pointer;\n transition: background 0.1s;\n border-bottom: 1px solid #f8fafc;\n}\n.aiwg-suggestion-item:last-child { border-bottom: none; }\n.aiwg-suggestion-item:hover,\n.aiwg-suggestion-item.aiwg-active { background: #f5f3ff; }\n.aiwg-suggestion-icon { font-size: 16px; flex-shrink: 0; }\n.aiwg-suggestion-main { flex: 1; min-width: 0; }\n.aiwg-suggestion-text { font-size: 13px; font-weight: 500; color: #1a1a2e; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.aiwg-suggestion-text mark { background: none; color: #6366f1; font-weight: 600; }\n.aiwg-suggestion-desc { font-size: 11px; color: #94a3b8; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.aiwg-suggestion-badge { font-size: 10px; font-weight: 600; padding: 2px 8px; border-radius: 99px; background: #ede9fe; color: #6366f1; flex-shrink: 0; }\n.aiwg-kbd-hint {\n padding: 6px 14px;\n font-size: 11px; color: #cbd5e1; background: #f8fafc;\n display: flex; justify-content: flex-end; gap: 10px;\n}\n.aiwg-kbd-hint kbd { font-family: inherit; background: #e2e8f0; border-radius: 4px; padding: 1px 5px; font-size: 10px; color: #64748b; }\n\n/* \u2500\u2500 Error toast \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-error {\n margin: 0 16px 8px;\n padding: 8px 12px;\n background: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 8px;\n font-size: 12px;\n color: #dc2626;\n}\n\n/* \u2500\u2500 Minimized state \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-root.aiwg-minimized .aiwg-messages,\n.aiwg-root.aiwg-minimized .aiwg-chip-row,\n.aiwg-root.aiwg-minimized .aiwg-error,\n.aiwg-root.aiwg-minimized .aiwg-input-area,\n.aiwg-root.aiwg-minimized .aiwg-powered { display: none !important; }\n.aiwg-root.aiwg-minimized .aiwg-minimize-btn { display: none !important; }\n.aiwg-root.aiwg-minimized { cursor: pointer; box-shadow: 0 8px 32px rgba(0,0,0,0.28); }\n.aiwg-root.aiwg-minimized .aiwg-header { cursor: pointer !important; }\n\n/* \u2500\u2500 Powered-by footer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-powered {\n text-align: center;\n padding: 6px 16px 10px;\n font-size: 11px; color: #94a3b8;\n flex-shrink: 0;\n border-top: 1px solid #f1f5f9;\n background: #fff;\n}\n.aiwg-powered a { color: #6366f1; text-decoration: none; font-weight: 500; }\n.aiwg-powered a:hover { text-decoration: underline; }\n\n/* \u2500\u2500 Markdown rendering \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-msg-bubble strong { font-weight: 600; }\n.aiwg-msg-bubble em { font-style: italic; }\n.aiwg-msg-bubble code { background: rgba(0,0,0,0.08); padding: 1px 5px; border-radius: 4px; font-family: 'Fira Code','Consolas',monospace; font-size: 0.9em; }\n.aiwg-msg--user .aiwg-msg-bubble code { background: rgba(255,255,255,0.2); }\n.aiwg-msg-bubble ol, .aiwg-msg-bubble ul { padding-left: 18px; margin: 6px 0; display: flex; flex-direction: column; gap: 3px; }\n.aiwg-msg-bubble ol { list-style: decimal; }\n.aiwg-msg-bubble ul { list-style: disc; }\n.aiwg-msg-bubble li { line-height: 1.5; }\n.aiwg-msg-bubble h3, .aiwg-msg-bubble h4 { font-weight: 600; margin: 8px 0 4px; }\n.aiwg-msg-bubble p { margin: 2px 0; }\n\n/* \u2500\u2500 Dark theme \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.aiwg-root.aiwg-dark { background: #0f172a; color: #e2e8f0; }\n.aiwg-dark .aiwg-msg--bot .aiwg-msg-bubble { background: #1e293b; color: #e2e8f0; }\n.aiwg-dark .aiwg-input-area { background: #0f172a; border-top-color: #1e293b; }\n.aiwg-dark .aiwg-input { background: #1e293b; border-color: #334155; color: #e2e8f0; }\n.aiwg-dark .aiwg-input:focus { border-color: #8b5cf6; background: #1e293b; box-shadow: 0 0 0 3px rgba(139,92,246,0.2); }\n.aiwg-dark .aiwg-suggestions { background: #1e293b; border-color: #334155; }\n.aiwg-dark .aiwg-suggestions-header { color: #64748b; border-bottom-color: #334155; }\n.aiwg-dark .aiwg-suggestion-item { border-bottom-color: #0f172a; }\n.aiwg-dark .aiwg-suggestion-item:hover,\n.aiwg-dark .aiwg-suggestion-item.aiwg-active { background: #2d1b69; }\n.aiwg-dark .aiwg-suggestion-text { color: #e2e8f0; }\n.aiwg-dark .aiwg-chip { background: #1e293b; border-color: #334155; }\n.aiwg-dark .aiwg-chip:hover { background: #2d1b69; }\n.aiwg-dark .aiwg-chip-shimmer { background: linear-gradient(90deg, #1e293b 25%, #334155 50%, #1e293b 75%); background-size: 200% 100%; }\n.aiwg-dark .aiwg-kbd-hint { background: #1e293b; }\n.aiwg-dark .aiwg-welcome h4 { color: #e2e8f0; }\n.aiwg-dark .aiwg-powered { background: #0f172a; border-top-color: #1e293b; }\n";
@@ -0,0 +1,389 @@
1
+ /**
2
+ * Canonical widget CSS — single source of truth for all framework packages.
3
+ *
4
+ * Isolation strategy:
5
+ * - React : injected into a Shadow DOM via ShadowWrapper (createPortal).
6
+ * :host { all: initial } resets inherited properties at the boundary.
7
+ * - jQuery : injected into attachShadow() root. Same :host reset applies.
8
+ * - Angular: ViewEncapsulation.ShadowDom — Angular handles the shadow root.
9
+ *
10
+ * NOTE: `@import` for Google Fonts does NOT work inside shadow-DOM <style> tags.
11
+ * Each package is responsible for loading the Inter font into document <head>
12
+ * separately (React: ensureFont(), jQuery: injectFontLink()).
13
+ */
14
+ export const WIDGET_CSS = `
15
+ /* ── Shadow-DOM host isolation ────────────────────────────────────────────── */
16
+ :host {
17
+ all: initial !important;
18
+ display: block !important;
19
+ }
20
+
21
+ /* Scoped box-model reset — only touches widget elements, not all of shadow DOM */
22
+ .aiwg-root *, .aiwg-root *::before, .aiwg-root *::after {
23
+ box-sizing: border-box;
24
+ margin: 0;
25
+ padding: 0;
26
+ }
27
+
28
+ /* ── Container ────────────────────────────────────────────────────────────── */
29
+ .aiwg-root {
30
+ --aiwg-primary: #6366f1;
31
+ --aiwg-primary-dark: #8b5cf6;
32
+ --aiwg-fg-color: #ffffff;
33
+ --aiwg-bg-color: #ffffff;
34
+ --aiwg-chat-bg: #f1f5f9;
35
+
36
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
37
+ font-size: 14px;
38
+ line-height: 1.5;
39
+ color: #1a1a2e;
40
+ display: flex;
41
+ flex-direction: column;
42
+ overflow: hidden;
43
+ border-radius: 16px;
44
+ background: var(--aiwg-bg-color);
45
+ position: fixed !important;
46
+ bottom: 24px;
47
+ right: 24px;
48
+ width: 380px !important;
49
+ max-width: calc(100vw - 48px) !important;
50
+ z-index: 99999;
51
+ transition: height 0.25s ease;
52
+ box-shadow: 0 24px 64px rgba(0,0,0,0.18);
53
+ }
54
+
55
+ /* ── Header ───────────────────────────────────────────────────────────────── */
56
+ .aiwg-header {
57
+ background: linear-gradient(135deg, var(--aiwg-primary) 0%, var(--aiwg-primary-dark) 100%);
58
+ padding: 16px 20px;
59
+ display: flex;
60
+ align-items: center;
61
+ gap: 12px;
62
+ flex-shrink: 0;
63
+ position: relative;
64
+ overflow: hidden;
65
+ }
66
+ .aiwg-header::before {
67
+ content: '';
68
+ position: absolute;
69
+ width: 140px; height: 140px;
70
+ background: rgba(255,255,255,0.08);
71
+ border-radius: 50%;
72
+ top: -50px; right: -30px;
73
+ }
74
+ .aiwg-avatar {
75
+ width: 40px; height: 40px;
76
+ background: rgba(255,255,255,0.25);
77
+ border-radius: 50%;
78
+ display: flex; align-items: center; justify-content: center;
79
+ font-size: 18px;
80
+ flex-shrink: 0;
81
+ border: 2px solid rgba(255,255,255,0.4);
82
+ }
83
+ .aiwg-header-info { flex: 1; }
84
+ .aiwg-title { color: #fff; font-weight: 600; font-size: 15px; }
85
+ .aiwg-subtitle {
86
+ color: rgba(255,255,255,0.75);
87
+ font-size: 12px;
88
+ display: flex; align-items: center; gap: 5px;
89
+ }
90
+ .aiwg-online-dot {
91
+ width: 7px; height: 7px;
92
+ background: #4ade80;
93
+ border-radius: 50%;
94
+ display: inline-block;
95
+ animation: aiwg-pulse 2s ease-in-out infinite;
96
+ }
97
+ @keyframes aiwg-pulse {
98
+ 0%, 100% { opacity: 1; transform: scale(1); }
99
+ 50% { opacity: 0.6; transform: scale(0.85); }
100
+ }
101
+ .aiwg-minimize-btn {
102
+ width: 36px; height: 36px;
103
+ background: rgba(255,255,255,0.18);
104
+ border: 1.5px solid rgba(255,255,255,0.3);
105
+ border-radius: 50%;
106
+ color: #fff; cursor: pointer;
107
+ display: flex; align-items: center; justify-content: center;
108
+ font-size: 18px; line-height: 1;
109
+ transition: background 0.15s, transform 0.15s;
110
+ flex-shrink: 0;
111
+ position: relative; z-index: 2;
112
+ }
113
+ .aiwg-minimize-btn * { cursor: pointer !important; pointer-events: none; }
114
+ .aiwg-minimize-btn:hover { background: rgba(255,255,255,0.32); transform: scale(1.08); }
115
+
116
+ /* ── Messages area ────────────────────────────────────────────────────────── */
117
+ .aiwg-messages {
118
+ flex: 1;
119
+ overflow-y: auto;
120
+ padding: 20px 16px 8px;
121
+ scroll-behavior: smooth;
122
+ display: flex;
123
+ flex-direction: column;
124
+ gap: 12px;
125
+ }
126
+ .aiwg-messages::-webkit-scrollbar { width: 4px; }
127
+ .aiwg-messages::-webkit-scrollbar-thumb { background: #e2e8f0; border-radius: 99px; }
128
+
129
+ /* ── Welcome card ─────────────────────────────────────────────────────────── */
130
+ .aiwg-welcome {
131
+ text-align: center;
132
+ padding: 24px 16px;
133
+ display: flex; flex-direction: column; align-items: center; gap: 8px;
134
+ }
135
+ .aiwg-welcome-icon { font-size: 36px; margin-bottom: 4px; }
136
+ .aiwg-welcome h4 { font-size: 15px; font-weight: 600; color: #1a1a2e; }
137
+ .aiwg-welcome p { font-size: 13px; color: #64748b; }
138
+
139
+ /* ── Message bubbles ──────────────────────────────────────────────────────── */
140
+ .aiwg-msg {
141
+ display: flex;
142
+ gap: 8px;
143
+ align-items: flex-end;
144
+ animation: aiwg-fade-up 0.2s ease both;
145
+ }
146
+ @keyframes aiwg-fade-up {
147
+ from { opacity: 0; transform: translateY(8px); }
148
+ to { opacity: 1; transform: translateY(0); }
149
+ }
150
+ .aiwg-msg--user { flex-direction: row-reverse; }
151
+ .aiwg-msg-avatar {
152
+ width: 28px; height: 28px; border-radius: 50%;
153
+ display: flex; align-items: center; justify-content: center;
154
+ font-size: 13px; flex-shrink: 0;
155
+ margin-bottom: 2px;
156
+ }
157
+ .aiwg-msg--bot .aiwg-msg-avatar { background: linear-gradient(135deg, var(--aiwg-primary), var(--aiwg-primary-dark)); color: var(--aiwg-fg-color); }
158
+ .aiwg-msg--user .aiwg-msg-avatar { background: #e2e8f0; color: #64748b; }
159
+ .aiwg-msg-body { max-width: 78%; }
160
+ .aiwg-msg-bubble {
161
+ padding: 10px 14px;
162
+ border-radius: 18px;
163
+ font-size: 14px;
164
+ line-height: 1.55;
165
+ word-break: break-word;
166
+ }
167
+ .aiwg-msg--bot .aiwg-msg-bubble { background: var(--aiwg-chat-bg); color: #1a1a2e; border-bottom-left-radius: 4px; }
168
+ .aiwg-msg--user .aiwg-msg-bubble { background: linear-gradient(135deg, var(--aiwg-primary), var(--aiwg-primary-dark)); color: var(--aiwg-fg-color); border-bottom-right-radius: 4px; }
169
+ .aiwg-msg-time { font-size: 10px; color: #94a3b8; margin-top: 4px; text-align: right; padding: 0 4px; }
170
+ .aiwg-msg--bot .aiwg-msg-time { text-align: left; }
171
+
172
+ /* ── Typing indicator ─────────────────────────────────────────────────────── */
173
+ .aiwg-typing { padding: 10px 14px; }
174
+ .aiwg-typing-dots { display: flex; gap: 4px; align-items: center; }
175
+ .aiwg-typing-dots span {
176
+ width: 7px; height: 7px;
177
+ background: #94a3b8; border-radius: 50%;
178
+ animation: aiwg-bounce 1.2s ease-in-out infinite;
179
+ }
180
+ .aiwg-typing-dots span:nth-child(2) { animation-delay: 0.2s; }
181
+ .aiwg-typing-dots span:nth-child(3) { animation-delay: 0.4s; }
182
+ @keyframes aiwg-bounce {
183
+ 0%, 80%, 100% { transform: translateY(0); }
184
+ 40% { transform: translateY(-6px); }
185
+ }
186
+
187
+ /* ── Quick-reply chips ────────────────────────────────────────────────────── */
188
+ .aiwg-chip-row {
189
+ padding: 6px 16px 2px;
190
+ display: flex;
191
+ flex-wrap: wrap;
192
+ gap: 6px;
193
+ flex-shrink: 0;
194
+ }
195
+ .aiwg-chip {
196
+ background: #f1f5f9;
197
+ border: 1px solid #e2e8f0;
198
+ border-radius: 99px;
199
+ padding: 4px 12px;
200
+ font-size: 12px;
201
+ color: #4f46e5;
202
+ cursor: pointer;
203
+ transition: all 0.15s;
204
+ white-space: nowrap;
205
+ font-weight: 500;
206
+ }
207
+ .aiwg-chip:hover { background: #ede9fe; border-color: #a5b4fc; }
208
+ .aiwg-chip-shimmer {
209
+ background: linear-gradient(90deg, #e2e8f0 25%, #f1f5f9 50%, #e2e8f0 75%);
210
+ background-size: 200% 100%;
211
+ border: 1px solid transparent;
212
+ border-radius: 99px;
213
+ padding: 4px 34px;
214
+ animation: aiwg-shimmer 1.4s ease-in-out infinite;
215
+ cursor: default;
216
+ pointer-events: none;
217
+ }
218
+ .aiwg-chip-ai-badge {
219
+ display: inline-block;
220
+ font-size: 9px; font-weight: 700;
221
+ background: linear-gradient(135deg, var(--aiwg-primary), var(--aiwg-primary-dark));
222
+ color: #fff;
223
+ padding: 1px 5px;
224
+ border-radius: 99px;
225
+ margin-left: 5px;
226
+ vertical-align: middle;
227
+ letter-spacing: 0.04em;
228
+ }
229
+ @keyframes aiwg-shimmer {
230
+ 0% { background-position: 200% 0; }
231
+ 100% { background-position: -200% 0; }
232
+ }
233
+
234
+ /* ── Input area ───────────────────────────────────────────────────────────── */
235
+ .aiwg-input-area {
236
+ padding: 12px 16px 16px;
237
+ flex-shrink: 0;
238
+ background: #fff;
239
+ border-top: 1px solid #f1f5f9;
240
+ position: relative;
241
+ }
242
+ .aiwg-input-row { display: flex; gap: 8px; align-items: flex-end; }
243
+ .aiwg-input {
244
+ flex: 1;
245
+ border: 1.5px solid #e2e8f0;
246
+ border-radius: 12px;
247
+ padding: 10px 14px;
248
+ font-size: 14px;
249
+ font-family: inherit;
250
+ outline: none;
251
+ resize: none;
252
+ background: #f8fafc;
253
+ color: #1a1a2e;
254
+ transition: border-color 0.15s, box-shadow 0.15s, background 0.15s;
255
+ line-height: 1.4;
256
+ max-height: 120px;
257
+ overflow-y: auto;
258
+ scrollbar-width: none;
259
+ -ms-overflow-style: none;
260
+ }
261
+ .aiwg-input::-webkit-scrollbar { display: none; }
262
+ .aiwg-input::placeholder { color: #94a3b8; }
263
+ .aiwg-input:focus {
264
+ border-color: var(--aiwg-primary-dark);
265
+ background: #fff;
266
+ box-shadow: 0 0 0 3px rgba(139,92,246,0.1);
267
+ }
268
+ .aiwg-send-btn {
269
+ width: 42px; height: 42px;
270
+ background: linear-gradient(135deg, var(--aiwg-primary), var(--aiwg-primary-dark));
271
+ border: none; border-radius: 12px;
272
+ color: var(--aiwg-fg-color); cursor: pointer;
273
+ display: flex; align-items: center; justify-content: center;
274
+ flex-shrink: 0;
275
+ transition: transform 0.15s, box-shadow 0.15s, opacity 0.15s;
276
+ box-shadow: 0 4px 12px rgba(99,102,241,0.35);
277
+ }
278
+ .aiwg-send-btn svg { width: 18px; height: 18px; }
279
+ .aiwg-send-btn:hover { transform: translateY(-1px); box-shadow: 0 6px 16px rgba(99,102,241,0.4); }
280
+ .aiwg-send-btn:active { transform: translateY(0); }
281
+ .aiwg-send-btn:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }
282
+
283
+ /* ── Autocomplete suggestions dropdown ────────────────────────────────────── */
284
+ .aiwg-suggestions {
285
+ position: absolute;
286
+ bottom: calc(100% + 4px);
287
+ left: 16px; right: 16px;
288
+ background: #fff;
289
+ border: 1px solid #e2e8f0;
290
+ border-radius: 12px;
291
+ box-shadow: 0 8px 24px rgba(0,0,0,0.12);
292
+ overflow: hidden;
293
+ z-index: 100;
294
+ animation: aiwg-fade-up 0.15s ease both;
295
+ }
296
+ .aiwg-suggestions-header {
297
+ padding: 8px 14px 4px;
298
+ font-size: 11px; font-weight: 600;
299
+ color: #94a3b8;
300
+ text-transform: uppercase; letter-spacing: 0.06em;
301
+ border-bottom: 1px solid #f1f5f9;
302
+ }
303
+ .aiwg-suggestion-item {
304
+ display: flex; align-items: center; gap: 10px;
305
+ padding: 10px 14px;
306
+ cursor: pointer;
307
+ transition: background 0.1s;
308
+ border-bottom: 1px solid #f8fafc;
309
+ }
310
+ .aiwg-suggestion-item:last-child { border-bottom: none; }
311
+ .aiwg-suggestion-item:hover,
312
+ .aiwg-suggestion-item.aiwg-active { background: #f5f3ff; }
313
+ .aiwg-suggestion-icon { font-size: 16px; flex-shrink: 0; }
314
+ .aiwg-suggestion-main { flex: 1; min-width: 0; }
315
+ .aiwg-suggestion-text { font-size: 13px; font-weight: 500; color: #1a1a2e; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
316
+ .aiwg-suggestion-text mark { background: none; color: #6366f1; font-weight: 600; }
317
+ .aiwg-suggestion-desc { font-size: 11px; color: #94a3b8; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
318
+ .aiwg-suggestion-badge { font-size: 10px; font-weight: 600; padding: 2px 8px; border-radius: 99px; background: #ede9fe; color: #6366f1; flex-shrink: 0; }
319
+ .aiwg-kbd-hint {
320
+ padding: 6px 14px;
321
+ font-size: 11px; color: #cbd5e1; background: #f8fafc;
322
+ display: flex; justify-content: flex-end; gap: 10px;
323
+ }
324
+ .aiwg-kbd-hint kbd { font-family: inherit; background: #e2e8f0; border-radius: 4px; padding: 1px 5px; font-size: 10px; color: #64748b; }
325
+
326
+ /* ── Error toast ──────────────────────────────────────────────────────────── */
327
+ .aiwg-error {
328
+ margin: 0 16px 8px;
329
+ padding: 8px 12px;
330
+ background: #fef2f2;
331
+ border: 1px solid #fecaca;
332
+ border-radius: 8px;
333
+ font-size: 12px;
334
+ color: #dc2626;
335
+ }
336
+
337
+ /* ── Minimized state ──────────────────────────────────────────────────────── */
338
+ .aiwg-root.aiwg-minimized .aiwg-messages,
339
+ .aiwg-root.aiwg-minimized .aiwg-chip-row,
340
+ .aiwg-root.aiwg-minimized .aiwg-error,
341
+ .aiwg-root.aiwg-minimized .aiwg-input-area,
342
+ .aiwg-root.aiwg-minimized .aiwg-powered { display: none !important; }
343
+ .aiwg-root.aiwg-minimized .aiwg-minimize-btn { display: none !important; }
344
+ .aiwg-root.aiwg-minimized { cursor: pointer; box-shadow: 0 8px 32px rgba(0,0,0,0.28); }
345
+ .aiwg-root.aiwg-minimized .aiwg-header { cursor: pointer !important; }
346
+
347
+ /* ── Powered-by footer ────────────────────────────────────────────────────── */
348
+ .aiwg-powered {
349
+ text-align: center;
350
+ padding: 6px 16px 10px;
351
+ font-size: 11px; color: #94a3b8;
352
+ flex-shrink: 0;
353
+ border-top: 1px solid #f1f5f9;
354
+ background: #fff;
355
+ }
356
+ .aiwg-powered a { color: #6366f1; text-decoration: none; font-weight: 500; }
357
+ .aiwg-powered a:hover { text-decoration: underline; }
358
+
359
+ /* ── Markdown rendering ───────────────────────────────────────────────────── */
360
+ .aiwg-msg-bubble strong { font-weight: 600; }
361
+ .aiwg-msg-bubble em { font-style: italic; }
362
+ .aiwg-msg-bubble code { background: rgba(0,0,0,0.08); padding: 1px 5px; border-radius: 4px; font-family: 'Fira Code','Consolas',monospace; font-size: 0.9em; }
363
+ .aiwg-msg--user .aiwg-msg-bubble code { background: rgba(255,255,255,0.2); }
364
+ .aiwg-msg-bubble ol, .aiwg-msg-bubble ul { padding-left: 18px; margin: 6px 0; display: flex; flex-direction: column; gap: 3px; }
365
+ .aiwg-msg-bubble ol { list-style: decimal; }
366
+ .aiwg-msg-bubble ul { list-style: disc; }
367
+ .aiwg-msg-bubble li { line-height: 1.5; }
368
+ .aiwg-msg-bubble h3, .aiwg-msg-bubble h4 { font-weight: 600; margin: 8px 0 4px; }
369
+ .aiwg-msg-bubble p { margin: 2px 0; }
370
+
371
+ /* ── Dark theme ───────────────────────────────────────────────────────────── */
372
+ .aiwg-root.aiwg-dark { background: #0f172a; color: #e2e8f0; }
373
+ .aiwg-dark .aiwg-msg--bot .aiwg-msg-bubble { background: #1e293b; color: #e2e8f0; }
374
+ .aiwg-dark .aiwg-input-area { background: #0f172a; border-top-color: #1e293b; }
375
+ .aiwg-dark .aiwg-input { background: #1e293b; border-color: #334155; color: #e2e8f0; }
376
+ .aiwg-dark .aiwg-input:focus { border-color: #8b5cf6; background: #1e293b; box-shadow: 0 0 0 3px rgba(139,92,246,0.2); }
377
+ .aiwg-dark .aiwg-suggestions { background: #1e293b; border-color: #334155; }
378
+ .aiwg-dark .aiwg-suggestions-header { color: #64748b; border-bottom-color: #334155; }
379
+ .aiwg-dark .aiwg-suggestion-item { border-bottom-color: #0f172a; }
380
+ .aiwg-dark .aiwg-suggestion-item:hover,
381
+ .aiwg-dark .aiwg-suggestion-item.aiwg-active { background: #2d1b69; }
382
+ .aiwg-dark .aiwg-suggestion-text { color: #e2e8f0; }
383
+ .aiwg-dark .aiwg-chip { background: #1e293b; border-color: #334155; }
384
+ .aiwg-dark .aiwg-chip:hover { background: #2d1b69; }
385
+ .aiwg-dark .aiwg-chip-shimmer { background: linear-gradient(90deg, #1e293b 25%, #334155 50%, #1e293b 75%); background-size: 200% 100%; }
386
+ .aiwg-dark .aiwg-kbd-hint { background: #1e293b; }
387
+ .aiwg-dark .aiwg-welcome h4 { color: #e2e8f0; }
388
+ .aiwg-dark .aiwg-powered { background: #0f172a; border-top-color: #1e293b; }
389
+ `;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@courseecho/ai-core-sdk",
3
- "version": "1.0.20",
3
+ "version": "1.0.21",
4
4
  "description": "Framework-agnostic core AI chat SDK. Shared logic for all framework wrappers.",
5
5
  "license": "MIT",
6
6
  "author": "CourseEcho",
@@ -14,7 +14,9 @@
14
14
  "types": "./dist/index.d.ts"
15
15
  }
16
16
  },
17
- "files": ["dist"],
17
+ "files": [
18
+ "dist"
19
+ ],
18
20
  "scripts": {
19
21
  "build": "tsc",
20
22
  "dev": "tsc --watch"
@@ -22,9 +24,16 @@
22
24
  "dependencies": {
23
25
  "rxjs": "^7.8.0"
24
26
  },
25
- "keywords": ["ai", "courseecho", "chatbot", "sdk", "widget", "chat"],
27
+ "keywords": [
28
+ "ai",
29
+ "courseecho",
30
+ "chatbot",
31
+ "sdk",
32
+ "widget",
33
+ "chat"
34
+ ],
26
35
  "devDependencies": {
27
36
  "typescript": "^5.3.0",
28
37
  "@types/node": "^20.0.0"
29
38
  }
30
- }
39
+ }