@smooai/smooth-operator 0.1.0 → 0.2.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.
Files changed (81) hide show
  1. package/README.md +18 -4
  2. package/dist/react/components/SmoothChat.d.ts +35 -0
  3. package/dist/react/components/SmoothChat.d.ts.map +1 -0
  4. package/dist/react/components/SmoothChat.js +26 -0
  5. package/dist/react/components/SmoothChat.js.map +1 -0
  6. package/dist/react/components/parts.d.ts +30 -0
  7. package/dist/react/components/parts.d.ts.map +1 -0
  8. package/dist/react/components/parts.js +67 -0
  9. package/dist/react/components/parts.js.map +1 -0
  10. package/dist/react/index.d.ts +27 -0
  11. package/dist/react/index.d.ts.map +1 -0
  12. package/dist/react/index.js +26 -0
  13. package/dist/react/index.js.map +1 -0
  14. package/dist/react/provider.d.ts +27 -0
  15. package/dist/react/provider.d.ts.map +1 -0
  16. package/dist/react/provider.js +25 -0
  17. package/dist/react/provider.js.map +1 -0
  18. package/dist/react/response.d.ts +19 -0
  19. package/dist/react/response.d.ts.map +1 -0
  20. package/dist/react/response.js +53 -0
  21. package/dist/react/response.js.map +1 -0
  22. package/dist/react/theme.d.ts +64 -0
  23. package/dist/react/theme.d.ts.map +1 -0
  24. package/dist/react/theme.js +38 -0
  25. package/dist/react/theme.js.map +1 -0
  26. package/dist/react/types.d.ts +24 -0
  27. package/dist/react/types.d.ts.map +1 -0
  28. package/dist/react/types.js +2 -0
  29. package/dist/react/types.js.map +1 -0
  30. package/dist/react/use-conversation.d.ts +59 -0
  31. package/dist/react/use-conversation.d.ts.map +1 -0
  32. package/dist/react/use-conversation.js +154 -0
  33. package/dist/react/use-conversation.js.map +1 -0
  34. package/dist/widget/chat-widget.iife.js +1301 -0
  35. package/dist/widget/chat-widget.iife.js.map +1 -0
  36. package/dist/widget/config.d.ts +73 -0
  37. package/dist/widget/config.d.ts.map +1 -0
  38. package/dist/widget/config.js +30 -0
  39. package/dist/widget/config.js.map +1 -0
  40. package/dist/widget/conversation.d.ts +50 -0
  41. package/dist/widget/conversation.d.ts.map +1 -0
  42. package/dist/widget/conversation.js +173 -0
  43. package/dist/widget/conversation.js.map +1 -0
  44. package/dist/widget/element.d.ts +94 -0
  45. package/dist/widget/element.d.ts.map +1 -0
  46. package/dist/widget/element.js +377 -0
  47. package/dist/widget/element.js.map +1 -0
  48. package/dist/widget/index.d.ts +25 -0
  49. package/dist/widget/index.d.ts.map +1 -0
  50. package/dist/widget/index.js +24 -0
  51. package/dist/widget/index.js.map +1 -0
  52. package/dist/widget/logo.d.ts +9 -0
  53. package/dist/widget/logo.d.ts.map +1 -0
  54. package/dist/widget/logo.js +10 -0
  55. package/dist/widget/logo.js.map +1 -0
  56. package/dist/widget/standalone.d.ts +25 -0
  57. package/dist/widget/standalone.d.ts.map +1 -0
  58. package/dist/widget/standalone.js +15 -0
  59. package/dist/widget/standalone.js.map +1 -0
  60. package/dist/widget/styles.d.ts +12 -0
  61. package/dist/widget/styles.d.ts.map +1 -0
  62. package/dist/widget/styles.js +262 -0
  63. package/dist/widget/styles.js.map +1 -0
  64. package/package.json +44 -6
  65. package/src/react/components/SmoothChat.tsx +57 -0
  66. package/src/react/components/parts.tsx +141 -0
  67. package/src/react/index.ts +30 -0
  68. package/src/react/provider.tsx +40 -0
  69. package/src/react/response.ts +57 -0
  70. package/src/react/styles.css +231 -0
  71. package/src/react/theme.ts +92 -0
  72. package/src/react/types.ts +27 -0
  73. package/src/react/use-conversation.ts +203 -0
  74. package/src/widget/config.ts +102 -0
  75. package/src/widget/conversation.ts +212 -0
  76. package/src/widget/element.ts +420 -0
  77. package/src/widget/index.ts +37 -0
  78. package/src/widget/logo.ts +9 -0
  79. package/src/widget/smooth-logo.svg +32 -0
  80. package/src/widget/standalone.ts +33 -0
  81. package/src/widget/styles.ts +265 -0
@@ -0,0 +1,265 @@
1
+ import type { ChatWidgetMode, ChatWidgetTheme } from './config.js';
2
+
3
+ /**
4
+ * Render the widget's scoped stylesheet. All theme values are injected as CSS
5
+ * custom properties on `:host` so they can be overridden per-instance and so the
6
+ * styles below stay static. Kept deliberately framework-light — no Tailwind, no
7
+ * runtime CSS-in-JS; just a string the web component drops into its shadow root.
8
+ *
9
+ * `mode` switches the host positioning + panel sizing between the floating
10
+ * popover (default) and the full-page layout (fills its container/viewport).
11
+ */
12
+ export function buildStyles(theme: Required<ChatWidgetTheme>, mode: ChatWidgetMode = 'popover'): string {
13
+ return `
14
+ :host {
15
+ --sac-text: ${theme.text};
16
+ --sac-bg: ${theme.background};
17
+ --sac-primary: ${theme.primary};
18
+ --sac-primary-text: ${theme.primaryText};
19
+ --sac-assistant-bubble: ${theme.assistantBubble};
20
+ --sac-assistant-bubble-text: ${theme.assistantBubbleText};
21
+ --sac-user-bubble: ${theme.userBubble};
22
+ --sac-user-bubble-text: ${theme.userBubbleText};
23
+ --sac-border: ${theme.border};
24
+
25
+ ${
26
+ mode === 'fullpage'
27
+ ? `/* Full-page: fill the host's box (the element should be sized by its
28
+ container, or it falls back to filling the viewport). */
29
+ display: block;
30
+ position: relative;
31
+ width: 100%;
32
+ height: 100%;
33
+ min-height: 100vh;`
34
+ : `/* Popover: float in the bottom-right corner. */
35
+ position: fixed;
36
+ bottom: 20px;
37
+ right: 20px;
38
+ z-index: 2147483000;`
39
+ }
40
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
41
+ }
42
+
43
+ * { box-sizing: border-box; }
44
+
45
+ .launcher {
46
+ width: 56px;
47
+ height: 56px;
48
+ border-radius: 50%;
49
+ border: none;
50
+ cursor: pointer;
51
+ background: var(--sac-primary);
52
+ color: var(--sac-primary-text);
53
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
54
+ display: flex;
55
+ align-items: center;
56
+ justify-content: center;
57
+ font-size: 24px;
58
+ transition: transform 0.15s ease;
59
+ }
60
+ .launcher:hover { transform: scale(1.05); }
61
+
62
+ .panel {
63
+ width: 360px;
64
+ max-width: calc(100vw - 40px);
65
+ height: 520px;
66
+ max-height: calc(100vh - 40px);
67
+ display: flex;
68
+ flex-direction: column;
69
+ background: var(--sac-bg);
70
+ color: var(--sac-text);
71
+ border: 1px solid var(--sac-border);
72
+ border-radius: 14px;
73
+ overflow: hidden;
74
+ box-shadow: 0 12px 40px rgba(0, 0, 0, 0.35);
75
+ }
76
+
77
+ /* Full-page: the panel becomes the whole surface — no floating box, no shadow,
78
+ no rounded corners; it fills the host. */
79
+ .panel.fullpage {
80
+ width: 100%;
81
+ height: 100%;
82
+ min-height: 100vh;
83
+ max-width: none;
84
+ max-height: none;
85
+ border: none;
86
+ border-radius: 0;
87
+ box-shadow: none;
88
+ }
89
+
90
+ .header {
91
+ display: flex;
92
+ align-items: center;
93
+ justify-content: space-between;
94
+ padding: 12px 14px;
95
+ background: var(--sac-primary);
96
+ color: var(--sac-primary-text);
97
+ }
98
+ .header .brand { display: flex; align-items: center; gap: 10px; min-width: 0; }
99
+ .header .logo { height: 24px; width: auto; display: block; }
100
+ .header .title { font-weight: 600; font-size: 15px; }
101
+ .header .status { font-size: 11px; opacity: 0.85; }
102
+ .header .powered {
103
+ font-size: 10px;
104
+ opacity: 0.7;
105
+ letter-spacing: 0.02em;
106
+ }
107
+ .header .close {
108
+ background: transparent;
109
+ border: none;
110
+ color: inherit;
111
+ cursor: pointer;
112
+ font-size: 18px;
113
+ line-height: 1;
114
+ padding: 4px;
115
+ }
116
+
117
+ /* Full-page header: taller, logo-led, centered max-width content row. */
118
+ .panel.fullpage .header { padding: 14px 20px; }
119
+ .panel.fullpage .logo { height: 30px; }
120
+
121
+ .messages {
122
+ flex: 1;
123
+ overflow-y: auto;
124
+ padding: 14px;
125
+ display: flex;
126
+ flex-direction: column;
127
+ gap: 10px;
128
+ }
129
+
130
+ .bubble {
131
+ max-width: 80%;
132
+ padding: 9px 12px;
133
+ border-radius: 12px;
134
+ font-size: 14px;
135
+ line-height: 1.4;
136
+ white-space: pre-wrap;
137
+ word-break: break-word;
138
+ }
139
+ .bubble.assistant {
140
+ align-self: flex-start;
141
+ background: var(--sac-assistant-bubble);
142
+ color: var(--sac-assistant-bubble-text);
143
+ border-bottom-left-radius: 4px;
144
+ }
145
+ .bubble.user {
146
+ align-self: flex-end;
147
+ background: var(--sac-user-bubble);
148
+ color: var(--sac-user-bubble-text);
149
+ border-bottom-right-radius: 4px;
150
+ }
151
+ .bubble.greeting { opacity: 0.85; font-style: italic; }
152
+
153
+ /* Full-page: center the conversation in a readable column and let bubbles
154
+ breathe a little wider. */
155
+ .panel.fullpage .messages {
156
+ padding: 24px 20px;
157
+ align-items: stretch;
158
+ }
159
+ .panel.fullpage .messages > * {
160
+ width: 100%;
161
+ max-width: 760px;
162
+ margin-left: auto;
163
+ margin-right: auto;
164
+ }
165
+ .panel.fullpage .bubble { max-width: 100%; }
166
+ .panel.fullpage .bubble.user { align-self: flex-end; max-width: 80%; margin-right: auto; }
167
+ .panel.fullpage .bubble.assistant { align-self: flex-start; max-width: 100%; }
168
+
169
+ /* Sources panel — rendered under an assistant bubble whose terminal
170
+ eventual_response carried citations. */
171
+ .sources {
172
+ align-self: flex-start;
173
+ max-width: 80%;
174
+ margin-top: -4px;
175
+ font-size: 12.5px;
176
+ color: var(--sac-text);
177
+ }
178
+ .panel.fullpage .sources { max-width: 100%; }
179
+ .sources details { background: transparent; }
180
+ .sources summary {
181
+ cursor: pointer;
182
+ font-weight: 600;
183
+ opacity: 0.85;
184
+ list-style: none;
185
+ user-select: none;
186
+ padding: 2px 0;
187
+ }
188
+ .sources summary::-webkit-details-marker { display: none; }
189
+ .sources summary::before {
190
+ content: '▸';
191
+ display: inline-block;
192
+ margin-right: 6px;
193
+ transition: transform 0.15s ease;
194
+ }
195
+ .sources details[open] summary::before { transform: rotate(90deg); }
196
+ .sources ol {
197
+ margin: 6px 0 0;
198
+ padding-left: 0;
199
+ list-style: none;
200
+ display: flex;
201
+ flex-direction: column;
202
+ gap: 8px;
203
+ }
204
+ .sources li {
205
+ border-left: 2px solid var(--sac-primary);
206
+ padding-left: 10px;
207
+ }
208
+ .sources .src-title {
209
+ color: var(--sac-primary);
210
+ text-decoration: none;
211
+ font-weight: 600;
212
+ word-break: break-word;
213
+ }
214
+ .sources a.src-title:hover { text-decoration: underline; }
215
+ .sources span.src-title { color: var(--sac-text); opacity: 0.95; }
216
+ .sources .src-snippet {
217
+ display: block;
218
+ margin-top: 2px;
219
+ opacity: 0.7;
220
+ line-height: 1.4;
221
+ white-space: normal;
222
+ }
223
+
224
+ .cursor::after {
225
+ content: '▋';
226
+ margin-left: 1px;
227
+ animation: sac-blink 1s steps(2, start) infinite;
228
+ }
229
+ @keyframes sac-blink { to { visibility: hidden; } }
230
+
231
+ .composer {
232
+ display: flex;
233
+ gap: 8px;
234
+ padding: 10px;
235
+ border-top: 1px solid var(--sac-border);
236
+ }
237
+ .composer textarea {
238
+ flex: 1;
239
+ resize: none;
240
+ border: 1px solid var(--sac-border);
241
+ border-radius: 8px;
242
+ padding: 8px 10px;
243
+ font-family: inherit;
244
+ font-size: 14px;
245
+ background: transparent;
246
+ color: var(--sac-text);
247
+ max-height: 96px;
248
+ line-height: 1.4;
249
+ }
250
+ .composer textarea:focus { outline: 1px solid var(--sac-primary); }
251
+ .composer button {
252
+ border: none;
253
+ border-radius: 8px;
254
+ padding: 0 14px;
255
+ cursor: pointer;
256
+ background: var(--sac-primary);
257
+ color: var(--sac-primary-text);
258
+ font-weight: 600;
259
+ font-size: 14px;
260
+ }
261
+ .composer button:disabled { opacity: 0.5; cursor: default; }
262
+
263
+ .hidden { display: none !important; }
264
+ `;
265
+ }