@emmaexcel/shakecursor 0.1.5 → 0.1.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.
@@ -10,51 +10,44 @@
10
10
  <style>
11
11
  :host {
12
12
  all: initial;
13
- --ai-accent: ${e.theme.primaryColor};
14
- --ai-accent-strong: #2563eb;
15
- --ai-accent-soft: color-mix(in srgb, var(--ai-accent), white 88%);
13
+ --ai-blue: #4285F4;
14
+ --ai-red: #DB4437;
15
+ --ai-yellow: #F4B400;
16
+ --ai-green: #0F9D58;
17
+ --ai-primary: ${e.theme.primaryColor};
16
18
  --ai-panel: ${e.theme.panelBackground};
17
- --ai-panel-raised: color-mix(in srgb, var(--ai-panel), white 7%);
18
19
  --ai-text: ${e.theme.textColor};
19
- --ai-muted: color-mix(in srgb, var(--ai-text), transparent 42%);
20
- --ai-faint: color-mix(in srgb, var(--ai-text), transparent 88%);
21
- --ai-border: color-mix(in srgb, var(--ai-text), transparent 86%);
22
20
  --ai-radius: ${e.theme.borderRadius}px;
23
- --ai-shadow-lg: 0 24px 70px rgba(15, 23, 42, 0.22), 0 8px 24px rgba(15, 23, 42, 0.10);
24
- --ai-shadow-md: 0 14px 36px rgba(15, 23, 42, 0.16), 0 3px 10px rgba(15, 23, 42, 0.08);
25
- color: var(--ai-text);
26
21
  font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
27
22
  }
28
23
 
29
- * {
30
- box-sizing: border-box;
31
- }
32
-
33
24
  .custom-cursor {
34
25
  position: fixed;
35
26
  left: 0;
36
27
  top: 0;
37
- width: 34px;
38
- height: 34px;
28
+ width: 24px;
29
+ height: 24px;
39
30
  pointer-events: none;
40
31
  z-index: 2147483647;
41
32
  display: none;
42
- margin-left: -5px;
43
- margin-top: -5px;
44
- color: var(--ai-accent-strong);
45
- filter: drop-shadow(0 10px 16px rgba(37, 99, 235, 0.28));
33
+ margin-left: -2px;
34
+ margin-top: -2px;
35
+ filter: drop-shadow(0 4px 10px rgba(66, 133, 244, 0.3));
46
36
  }
47
37
 
48
38
  .custom-cursor.active {
49
39
  display: block;
50
40
  }
51
41
 
42
+ /* Rounded pointer shape */
52
43
  .cursor-shape {
53
44
  width: 100%;
54
45
  height: 100%;
55
- fill: #ffffff;
56
- stroke: currentColor;
57
- stroke-width: 2;
46
+ fill: white;
47
+ stroke: var(--ai-blue);
48
+ stroke-width: 2.5px;
49
+ /* Using a circle with high radius as base for a rounded pointer */
50
+ stroke-linejoin: round;
58
51
  }
59
52
 
60
53
  .toast {
@@ -65,18 +58,13 @@
65
58
  display: none;
66
59
  align-items: center;
67
60
  gap: 10px;
68
- min-height: 42px;
69
- border: 1px solid color-mix(in srgb, var(--ai-accent), transparent 78%);
70
- border-radius: 999px;
71
- background:
72
- linear-gradient(180deg, rgba(255, 255, 255, 0.92), rgba(255, 255, 255, 0.74)),
73
- var(--ai-panel);
61
+ border: 1px solid color-mix(in srgb, var(--ai-primary), transparent 74%);
62
+ border-radius: var(--ai-radius);
63
+ background: var(--ai-panel);
74
64
  color: var(--ai-text);
75
- padding: 8px 10px 8px 12px;
76
- font: 700 12px/1 Inter, ui-sans-serif, system-ui, sans-serif;
77
- letter-spacing: 0;
78
- box-shadow: var(--ai-shadow-md);
79
- backdrop-filter: blur(18px) saturate(1.25);
65
+ padding: 10px 12px;
66
+ font: 700 13px/1 Inter, ui-sans-serif, system-ui, sans-serif;
67
+ box-shadow: 0 16px 42px rgba(15, 23, 42, 0.18);
80
68
  }
81
69
 
82
70
  .toast.active {
@@ -84,28 +72,18 @@
84
72
  }
85
73
 
86
74
  .pulse {
87
- position: relative;
88
- width: 9px;
89
- height: 9px;
75
+ width: 8px;
76
+ height: 8px;
90
77
  border-radius: 999px;
91
- background: var(--ai-accent);
92
- box-shadow: 0 0 0 5px color-mix(in srgb, var(--ai-accent), transparent 86%);
93
- }
94
-
95
- .pulse::after {
96
- content: "";
97
- position: absolute;
98
- inset: -6px;
99
- border-radius: inherit;
100
- border: 1px solid color-mix(in srgb, var(--ai-accent), transparent 58%);
101
- animation: pulse-ring 1.45s cubic-bezier(0.2, 0.8, 0.2, 1) infinite;
78
+ background: var(--ai-primary);
79
+ box-shadow: 0 0 0 0 color-mix(in srgb, var(--ai-primary), transparent 38%);
80
+ animation: pulse-ring 1.3s infinite;
102
81
  }
103
82
 
104
83
  .count {
105
- border-left: 1px solid var(--ai-border);
106
- padding: 4px 2px 4px 10px;
107
- color: var(--ai-muted);
108
- font-weight: 650;
84
+ border-left: 1px solid rgba(15, 23, 42, 0.12);
85
+ padding-left: 10px;
86
+ opacity: 0.72;
109
87
  }
110
88
 
111
89
  .hover {
@@ -113,182 +91,113 @@
113
91
  z-index: 2147483644;
114
92
  pointer-events: none;
115
93
  display: none;
94
+ /* Thinner, professional 2px border */
116
95
  border: 2px solid transparent;
117
- border-radius: calc(var(--ai-radius) + 3px);
118
- background:
119
- linear-gradient(transparent, transparent) padding-box,
120
- linear-gradient(135deg, #60a5fa, #8b5cf6 48%, #22c55e) border-box;
121
- box-shadow:
122
- 0 0 0 4px rgba(37, 99, 235, 0.10),
123
- 0 18px 46px rgba(37, 99, 235, 0.18);
124
- transition:
125
- left 120ms ease,
126
- top 120ms ease,
127
- width 120ms ease,
128
- height 120ms ease;
96
+ border-radius: var(--ai-radius);
97
+ /* Pure transparent center, no fill at all */
98
+ background: none !important;
99
+ /* Conic gradient on border using border-image for absolute transparency in middle */
100
+ border-image: conic-gradient(var(--ai-blue), var(--ai-red), var(--ai-yellow), var(--ai-green), var(--ai-blue)) 1;
101
+ box-shadow: 0 0 15px rgba(66, 133, 244, 0.15);
102
+ transition: all 0.08s ease-out;
129
103
  }
130
104
 
131
105
  .panel {
132
106
  position: fixed;
133
107
  z-index: 2147483646;
134
- width: min(392px, calc(100vw - 32px));
108
+ width: 380px;
135
109
  display: none;
136
- border: 1px solid rgba(15, 23, 42, 0.12);
137
- border-radius: calc(var(--ai-radius) + 6px);
138
- background:
139
- radial-gradient(circle at 18% 0%, color-mix(in srgb, var(--ai-accent), transparent 88%), transparent 36%),
140
- linear-gradient(180deg, rgba(255, 255, 255, 0.96), rgba(255, 255, 255, 0.86)),
141
- var(--ai-panel);
110
+ border: 1px solid rgba(17, 24, 39, 0.14);
111
+ border-radius: var(--ai-radius);
112
+ background: var(--ai-panel);
142
113
  color: var(--ai-text);
143
114
  text-align: left;
144
- box-shadow: var(--ai-shadow-lg);
115
+ box-shadow: 0 26px 70px rgba(15, 23, 42, 0.22);
145
116
  overflow: hidden;
146
- backdrop-filter: blur(22px) saturate(1.18);
147
117
  }
148
118
 
149
119
  .panel.visible {
150
120
  display: block;
151
- animation: panel-in 140ms ease-out;
152
121
  }
153
122
 
154
123
  .head {
155
- display: grid;
156
- grid-template-columns: minmax(0, 1fr) 34px;
157
- align-items: start;
124
+ display: flex;
125
+ align-items: center;
126
+ justify-content: space-between;
158
127
  gap: 14px;
159
- border-bottom: 1px solid rgba(15, 23, 42, 0.08);
160
- padding: 16px 16px 13px;
128
+ border-bottom: 1px solid rgba(17, 24, 39, 0.08);
129
+ padding: 14px 14px 12px;
161
130
  }
162
131
 
163
132
  .kind {
164
- display: inline-flex;
165
- align-items: center;
166
- width: fit-content;
167
- max-width: 100%;
168
- min-height: 22px;
169
- margin-bottom: 7px;
170
- border: 1px solid color-mix(in srgb, var(--ai-accent), transparent 72%);
171
- border-radius: 999px;
172
- background: var(--ai-accent-soft);
173
- color: var(--ai-accent-strong);
174
- padding: 0 8px;
175
- font: 800 10px/1 Inter, ui-sans-serif, system-ui, sans-serif;
176
- letter-spacing: 0.04em;
133
+ display: block;
134
+ margin-bottom: 4px;
135
+ color: var(--ai-blue);
136
+ font: 800 11px/1 Inter, ui-sans-serif, system-ui, sans-serif;
177
137
  text-transform: uppercase;
178
138
  }
179
139
 
180
140
  .label {
181
- display: -webkit-box;
141
+ display: block;
182
142
  color: var(--ai-text);
183
- font: 760 15px/1.35 Inter, ui-sans-serif, system-ui, sans-serif;
184
- letter-spacing: 0;
185
- overflow: hidden;
186
- -webkit-box-orient: vertical;
187
- -webkit-line-clamp: 2;
143
+ font: 700 14px/1.25 Inter, ui-sans-serif, system-ui, sans-serif;
188
144
  }
189
145
 
190
146
  button {
191
- appearance: none;
192
- border: 1px solid rgba(15, 23, 42, 0.12);
193
- border-radius: calc(var(--ai-radius) - 2px);
194
- min-height: 42px;
195
- background: #0f172a;
147
+ border: 1px solid rgba(17, 24, 39, 0.12);
148
+ border-radius: var(--ai-radius);
149
+ min-height: 40px;
150
+ background: #111827;
196
151
  color: #ffffff;
197
- font: 760 14px/1 Inter, ui-sans-serif, system-ui, sans-serif;
198
- letter-spacing: 0;
152
+ font: 700 14px/1 Inter, ui-sans-serif, system-ui, sans-serif;
199
153
  cursor: pointer;
200
- transition:
201
- transform 120ms ease,
202
- box-shadow 120ms ease,
203
- background 120ms ease,
204
- border-color 120ms ease,
205
- opacity 120ms ease;
206
- }
207
-
208
- button:hover:not(:disabled) {
209
- transform: translateY(-1px);
210
- box-shadow: 0 10px 20px rgba(15, 23, 42, 0.16);
211
- }
212
-
213
- button:active:not(:disabled) {
214
- transform: translateY(0);
215
- }
216
-
217
- button:focus-visible,
218
- textarea:focus-visible {
219
- outline: 3px solid color-mix(in srgb, var(--ai-accent), transparent 78%);
220
- outline-offset: 2px;
221
154
  }
222
155
 
223
156
  button:disabled {
224
157
  cursor: not-allowed;
225
- opacity: 0.58;
226
- transform: none;
227
- box-shadow: none;
158
+ opacity: 0.56;
228
159
  }
229
160
 
230
161
  .close {
231
162
  min-width: 34px;
232
163
  min-height: 34px;
233
- border-radius: 999px;
234
164
  padding: 0;
235
- background: rgba(255, 255, 255, 0.72);
236
- color: var(--ai-muted);
237
- font-size: 18px;
238
- line-height: 1;
239
- }
240
-
241
- .close:hover:not(:disabled) {
242
- background: #ffffff;
243
- color: var(--ai-text);
165
+ background: #f3f4f6;
166
+ color: #111827;
244
167
  }
245
168
 
246
169
  form {
247
170
  display: grid;
248
- gap: 12px;
249
- padding: 14px 16px 16px;
171
+ gap: 10px;
172
+ padding: 14px;
250
173
  }
251
174
 
252
175
  textarea {
176
+ box-sizing: border-box;
253
177
  width: 100%;
254
178
  resize: vertical;
255
- min-height: 96px;
256
- max-height: 190px;
257
- border: 1px solid rgba(15, 23, 42, 0.14);
258
- border-radius: calc(var(--ai-radius) + 1px);
259
- padding: 12px 13px;
179
+ min-height: 86px;
180
+ max-height: 180px;
181
+ border: 1px solid rgba(17, 24, 39, 0.16);
182
+ border-radius: var(--ai-radius);
183
+ padding: 12px;
260
184
  color: #111827;
261
- background: rgba(255, 255, 255, 0.88);
262
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.7);
263
- font: 450 14px/1.5 Inter, ui-sans-serif, system-ui, sans-serif;
264
- letter-spacing: 0;
265
- }
266
-
267
- textarea::placeholder {
268
- color: rgba(75, 85, 99, 0.72);
269
- }
270
-
271
- textarea:focus {
272
- border-color: color-mix(in srgb, var(--ai-accent), transparent 22%);
273
185
  background: #ffffff;
274
- outline: none;
186
+ font: 15px/1.45 Inter, ui-sans-serif, system-ui, sans-serif;
275
187
  }
276
188
 
277
- .submit {
278
- border-color: color-mix(in srgb, var(--ai-accent-strong), black 14%);
279
- background:
280
- linear-gradient(180deg, color-mix(in srgb, var(--ai-accent), white 8%), var(--ai-accent-strong));
281
- box-shadow: 0 12px 22px color-mix(in srgb, var(--ai-accent), transparent 78%);
189
+ textarea:focus {
190
+ border-color: var(--ai-blue);
191
+ outline: 3px solid color-mix(in srgb, var(--ai-blue), transparent 86%);
282
192
  }
283
193
 
284
194
  .error,
285
195
  .answer {
286
196
  display: none;
287
- margin: 0 16px 16px;
288
- border-radius: calc(var(--ai-radius) + 1px);
289
- padding: 12px 13px;
290
- font: 440 14px/1.5 Inter, ui-sans-serif, system-ui, sans-serif;
291
- letter-spacing: 0;
197
+ margin: 0 14px 14px;
198
+ border-radius: var(--ai-radius);
199
+ padding: 12px;
200
+ font: 14px/1.45 Inter, ui-sans-serif, system-ui, sans-serif;
292
201
  white-space: pre-wrap;
293
202
  }
294
203
 
@@ -298,25 +207,18 @@
298
207
  }
299
208
 
300
209
  .error {
301
- border: 1px solid rgba(220, 38, 38, 0.18);
302
- background: #fff1f2;
303
- color: #9f1239;
210
+ background: #fef2f2;
211
+ color: #991b1b;
304
212
  }
305
213
 
306
214
  .answer {
307
- max-height: 230px;
215
+ max-height: 220px;
308
216
  overflow: auto;
309
- border: 1px solid rgba(15, 23, 42, 0.08);
310
- background: rgba(248, 250, 252, 0.82);
217
+ background: #f8fafc;
311
218
  color: #111827;
312
219
  }
313
220
 
314
221
  @media (max-width: 760px) {
315
- .toast {
316
- right: 12px;
317
- bottom: 12px;
318
- }
319
-
320
222
  .panel {
321
223
  left: 12px !important;
322
224
  right: 12px;
@@ -326,41 +228,15 @@
326
228
  }
327
229
  }
328
230
 
329
- @media (prefers-reduced-motion: reduce) {
330
- *,
331
- *::before,
332
- *::after {
333
- animation-duration: 0.001ms !important;
334
- animation-iteration-count: 1 !important;
335
- transition-duration: 0.001ms !important;
336
- }
337
- }
338
-
339
231
  @keyframes pulse-ring {
340
- 0% {
341
- opacity: 0.75;
342
- transform: scale(0.74);
343
- }
344
- 100% {
345
- opacity: 0;
346
- transform: scale(1.55);
347
- }
348
- }
349
-
350
- @keyframes panel-in {
351
- from {
352
- opacity: 0;
353
- transform: translateY(6px) scale(0.985);
354
- }
355
- to {
356
- opacity: 1;
357
- transform: translateY(0) scale(1);
358
- }
232
+ 70% { box-shadow: 0 0 0 8px transparent; }
233
+ 100% { box-shadow: 0 0 0 0 transparent; }
359
234
  }
360
235
  </style>
361
236
  <div class="custom-cursor">
362
- <svg viewBox="0 0 28 32" class="cursor-shape" aria-hidden="true">
363
- <path d="M2,2 L2,28 L8,22 L14,32 L18,29 L12,19 L22,19 Z" stroke-linejoin="round" stroke-linecap="round" />
237
+ <svg viewBox="0 0 28 32" class="cursor-shape">
238
+ <!-- Rounded, professional pointer -->
239
+ <path d="M4,2 L4,26 L10,20 L15,30 L19,27 L14,18 L24,18 Z" stroke-linejoin="round" stroke-linecap="round" />
364
240
  </svg>
365
241
  </div>
366
242
  <div class="toast" role="status">
@@ -384,4 +260,4 @@
384
260
  <p class="error"></p>
385
261
  <div class="answer"></div>
386
262
  </section>
387
- `;let a=i.querySelector(`.custom-cursor`),o=i.querySelector(`.toast`),s=i.querySelector(`.count`),c=i.querySelector(`.hover`),l=i.querySelector(`.panel`),u=i.querySelector(`.kind`),d=i.querySelector(`.label`),f=i.querySelector(`form`),p=i.querySelector(`textarea`),m=i.querySelector(`.submit`),h=i.querySelector(`.close`),g=i.querySelector(`.error`),_=i.querySelector(`.answer`);if(!a||!o||!s||!c||!l||!u||!d||!f||!p||!m||!h||!g||!_)throw Error(`AIOverlay UI failed to initialize`);let v=e=>{a.style.left=`${e.clientX}px`,a.style.top=`${e.clientY}px`};return f.addEventListener(`submit`,t=>{t.preventDefault();let n=p.value.trim();n&&e.onSubmit(n)}),h.addEventListener(`click`,()=>{e.onCancel()}),{root:n,contains:e=>e===n||n.contains(e),setActive:(e,t)=>{o.classList.toggle(`active`,e),a.classList.toggle(`active`,e),s.textContent=`shakes ${t}`,e?window.addEventListener(`mousemove`,v):window.removeEventListener(`mousemove`,v)},setHoverRect:e=>{if(!e){c.style.display=`none`;return}c.style.display=`block`,c.style.left=`${e.left}px`,c.style.top=`${e.top}px`,c.style.width=`${e.width}px`,c.style.height=`${e.height}px`},showPrompt:e=>{let n=t(e.rect.left+e.rect.width/2-196,16,window.innerWidth-408),r=t(e.rect.bottom+14,16,window.innerHeight-396);u.textContent=e.kind,d.textContent=e.label,p.value=``,m.disabled=!1,m.textContent=`Ask AI`,g.classList.remove(`visible`),_.classList.remove(`visible`),l.style.left=`${n}px`,l.style.top=`${r}px`,l.classList.add(`visible`),p.focus()},setThinking:e=>{m.disabled=e,m.textContent=e?`Thinking...`:`Ask AI`},setAnswer:e=>{_.textContent=e,_.classList.toggle(`visible`,!!e)},setError:e=>{g.textContent=e,g.classList.toggle(`visible`,!!e)},clearSelection:()=>{l.classList.remove(`visible`),g.classList.remove(`visible`),_.classList.remove(`visible`),p.value=``},destroy:()=>{r.remove(),n.remove(),window.removeEventListener(`mousemove`,v)}}}var v={primaryColor:`#14b8a6`,panelBackground:`rgba(255, 255, 255, 0.96)`,textColor:`#111827`,borderRadius:8},y={shake:!0,keyboardShortcut:`mod+k`},b={text:!0,images:!0,elements:!0,blockedSelectors:[`input[type="password"]`,`[data-ai-private]`,`[data-ai-overlay-ignore]`],allowedSelectors:[]},x=class{active=!1;shakeCount=0;selection=null;disposers=[];ui;config;trigger;constructor(e){this.config=e,this.trigger={...y,...e.trigger};let t={...b,...e.selection};this.ui=_({theme:{...v,...e.theme},onSubmit:e=>{this.ask(e)},onCancel:()=>{this.clearSelection()}}),this.trigger.shake&&this.disposers.push(d({onShake:()=>{this.shakeCount+=1,this.activate()}})),this.disposers.push(u({config:t,isActive:()=>this.active,isOverlayElement:e=>this.ui.contains(e),onHover:e=>{this.ui.setHoverRect(this.selection?null:e)},onSelection:e=>{this.selection=e,this.ui.setHoverRect(null),this.ui.showPrompt(e),this.config.onSelection?.(e)}})),this.disposers.push(this.bindKeyboardShortcut())}activate(){if(this.active){this.ui.setActive(!0,this.shakeCount);return}this.active=!0,document.body.classList.add(`ai-overlay-active`),this.ui.setActive(!0,this.shakeCount),this.config.onActivate?.()}deactivate(){this.active&&(this.active=!1,this.clearSelection(),this.ui.setHoverRect(null),this.ui.setActive(!1,this.shakeCount),document.body.classList.remove(`ai-overlay-active`),this.config.onDeactivate?.())}destroy(){for(let e of this.disposers)e();this.disposers=[],this.deactivate(),this.ui.destroy()}isActive(){return this.active}clearSelection(){this.selection=null,this.ui.clearSelection(),window.getSelection()?.removeAllRanges()}async ask(e){if(!this.selection)return;let t={question:e,selection:this.selection};this.config.onAsk?.(t),this.ui.setThinking(!0),this.ui.setAnswer(``),this.ui.setError(``);try{let e=this.config.siteKey?await g({apiBaseUrl:this.config.apiBaseUrl,siteKey:this.config.siteKey,payload:t}):await h(this.config.model??{},t);this.ui.setAnswer(e),this.config.onResponse?.(e,t)}catch(e){let t=e instanceof Error?e:Error(`Unknown AIOverlay error`);this.ui.setError(t.message),this.config.onError?.(t)}finally{this.ui.setThinking(!1)}}bindKeyboardShortcut(){let e=this.trigger.keyboardShortcut.toLowerCase(),t=t=>{let n=e.includes(`mod+`),r=e.split(`+`).at(-1),a=i()?t.metaKey:t.ctrlKey;n&&!a||r&&t.key.toLowerCase()===r&&(t.preventDefault(),this.active?this.deactivate():this.activate())};return document.addEventListener(`keydown`,t),()=>{document.removeEventListener(`keydown`,t)}}},S={init(e={}){return new x(e)}};typeof window<`u`&&(window.AIOverlay=S),e.AIOverlay=S})(this.AIOverlayBundle=this.AIOverlayBundle||{});
263
+ `;let a=i.querySelector(`.custom-cursor`),o=i.querySelector(`.toast`),s=i.querySelector(`.count`),c=i.querySelector(`.hover`),l=i.querySelector(`.panel`),u=i.querySelector(`.kind`),d=i.querySelector(`.label`),f=i.querySelector(`form`),p=i.querySelector(`textarea`),m=i.querySelector(`.submit`),h=i.querySelector(`.close`),g=i.querySelector(`.error`),_=i.querySelector(`.answer`);if(!a||!o||!s||!c||!l||!u||!d||!f||!p||!m||!h||!g||!_)throw Error(`AIOverlay UI failed to initialize`);let v=e=>{a.style.left=`${e.clientX}px`,a.style.top=`${e.clientY}px`};return f.addEventListener(`submit`,t=>{t.preventDefault();let n=p.value.trim();n&&e.onSubmit(n)}),h.addEventListener(`click`,()=>{e.onCancel()}),{root:n,contains:e=>e===n||n.contains(e),setActive:(e,t)=>{o.classList.toggle(`active`,e),a.classList.toggle(`active`,e),s.textContent=`shakes ${t}`,e?window.addEventListener(`mousemove`,v):window.removeEventListener(`mousemove`,v)},setHoverRect:e=>{if(!e){c.style.display=`none`;return}c.style.display=`block`,c.style.left=`${e.left}px`,c.style.top=`${e.top}px`,c.style.width=`${e.width}px`,c.style.height=`${e.height}px`},showPrompt:e=>{let n=t(e.rect.left+e.rect.width/2-190,16,window.innerWidth-396),r=t(e.rect.bottom+14,16,window.innerHeight-380);u.textContent=e.kind,d.textContent=e.label,p.value=``,m.disabled=!1,m.textContent=`Ask AI`,g.classList.remove(`visible`),_.classList.remove(`visible`),l.style.left=`${n}px`,l.style.top=`${r}px`,l.classList.add(`visible`),p.focus()},setThinking:e=>{m.disabled=e,m.textContent=e?`Thinking...`:`Ask AI`},setAnswer:e=>{_.textContent=e,_.classList.toggle(`visible`,!!e)},setError:e=>{g.textContent=e,g.classList.toggle(`visible`,!!e)},clearSelection:()=>{l.classList.remove(`visible`),g.classList.remove(`visible`),_.classList.remove(`visible`),p.value=``},destroy:()=>{r.remove(),n.remove(),window.removeEventListener(`mousemove`,v)}}}var v={primaryColor:`#14b8a6`,panelBackground:`rgba(255, 255, 255, 0.96)`,textColor:`#111827`,borderRadius:8},y={shake:!0,keyboardShortcut:`mod+k`},b={text:!0,images:!0,elements:!0,blockedSelectors:[`input[type="password"]`,`[data-ai-private]`,`[data-ai-overlay-ignore]`],allowedSelectors:[]},x=class{active=!1;shakeCount=0;selection=null;disposers=[];ui;config;trigger;constructor(e){this.config=e,this.trigger={...y,...e.trigger};let t={...b,...e.selection};this.ui=_({theme:{...v,...e.theme},onSubmit:e=>{this.ask(e)},onCancel:()=>{this.clearSelection()}}),this.trigger.shake&&this.disposers.push(d({onShake:()=>{this.shakeCount+=1,this.activate()}})),this.disposers.push(u({config:t,isActive:()=>this.active,isOverlayElement:e=>this.ui.contains(e),onHover:e=>{this.ui.setHoverRect(this.selection?null:e)},onSelection:e=>{this.selection=e,this.ui.setHoverRect(null),this.ui.showPrompt(e),this.config.onSelection?.(e)}})),this.disposers.push(this.bindKeyboardShortcut())}activate(){if(this.active){this.ui.setActive(!0,this.shakeCount);return}this.active=!0,document.body.classList.add(`ai-overlay-active`),this.ui.setActive(!0,this.shakeCount),this.config.onActivate?.()}deactivate(){this.active&&(this.active=!1,this.clearSelection(),this.ui.setHoverRect(null),this.ui.setActive(!1,this.shakeCount),document.body.classList.remove(`ai-overlay-active`),this.config.onDeactivate?.())}destroy(){for(let e of this.disposers)e();this.disposers=[],this.deactivate(),this.ui.destroy()}isActive(){return this.active}clearSelection(){this.selection=null,this.ui.clearSelection(),window.getSelection()?.removeAllRanges()}async ask(e){if(!this.selection)return;let t={question:e,selection:this.selection};this.config.onAsk?.(t),this.ui.setThinking(!0),this.ui.setAnswer(``),this.ui.setError(``);try{let e=this.config.siteKey?await g({apiBaseUrl:this.config.apiBaseUrl,siteKey:this.config.siteKey,payload:t}):await h(this.config.model??{},t);this.ui.setAnswer(e),this.config.onResponse?.(e,t)}catch(e){let t=e instanceof Error?e:Error(`Unknown AIOverlay error`);this.ui.setError(t.message),this.config.onError?.(t)}finally{this.ui.setThinking(!1)}}bindKeyboardShortcut(){let e=this.trigger.keyboardShortcut.toLowerCase(),t=t=>{let n=e.includes(`mod+`),r=e.split(`+`).at(-1),a=i()?t.metaKey:t.ctrlKey;n&&!a||r&&t.key.toLowerCase()===r&&(t.preventDefault(),this.active?this.deactivate():this.activate())};return document.addEventListener(`keydown`,t),()=>{document.removeEventListener(`keydown`,t)}}},S={init(e={}){return new x(e)}};typeof window<`u`&&(window.AIOverlay=S),e.AIOverlay=S})(this.AIOverlayBundle=this.AIOverlayBundle||{});
package/dist/overlay.js CHANGED
@@ -224,51 +224,44 @@ function g(t) {
224
224
  <style>
225
225
  :host {
226
226
  all: initial;
227
- --ai-accent: ${t.theme.primaryColor};
228
- --ai-accent-strong: #2563eb;
229
- --ai-accent-soft: color-mix(in srgb, var(--ai-accent), white 88%);
227
+ --ai-blue: #4285F4;
228
+ --ai-red: #DB4437;
229
+ --ai-yellow: #F4B400;
230
+ --ai-green: #0F9D58;
231
+ --ai-primary: ${t.theme.primaryColor};
230
232
  --ai-panel: ${t.theme.panelBackground};
231
- --ai-panel-raised: color-mix(in srgb, var(--ai-panel), white 7%);
232
233
  --ai-text: ${t.theme.textColor};
233
- --ai-muted: color-mix(in srgb, var(--ai-text), transparent 42%);
234
- --ai-faint: color-mix(in srgb, var(--ai-text), transparent 88%);
235
- --ai-border: color-mix(in srgb, var(--ai-text), transparent 86%);
236
234
  --ai-radius: ${t.theme.borderRadius}px;
237
- --ai-shadow-lg: 0 24px 70px rgba(15, 23, 42, 0.22), 0 8px 24px rgba(15, 23, 42, 0.10);
238
- --ai-shadow-md: 0 14px 36px rgba(15, 23, 42, 0.16), 0 3px 10px rgba(15, 23, 42, 0.08);
239
- color: var(--ai-text);
240
235
  font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
241
236
  }
242
237
 
243
- * {
244
- box-sizing: border-box;
245
- }
246
-
247
238
  .custom-cursor {
248
239
  position: fixed;
249
240
  left: 0;
250
241
  top: 0;
251
- width: 34px;
252
- height: 34px;
242
+ width: 24px;
243
+ height: 24px;
253
244
  pointer-events: none;
254
245
  z-index: 2147483647;
255
246
  display: none;
256
- margin-left: -5px;
257
- margin-top: -5px;
258
- color: var(--ai-accent-strong);
259
- filter: drop-shadow(0 10px 16px rgba(37, 99, 235, 0.28));
247
+ margin-left: -2px;
248
+ margin-top: -2px;
249
+ filter: drop-shadow(0 4px 10px rgba(66, 133, 244, 0.3));
260
250
  }
261
251
 
262
252
  .custom-cursor.active {
263
253
  display: block;
264
254
  }
265
255
 
256
+ /* Rounded pointer shape */
266
257
  .cursor-shape {
267
258
  width: 100%;
268
259
  height: 100%;
269
- fill: #ffffff;
270
- stroke: currentColor;
271
- stroke-width: 2;
260
+ fill: white;
261
+ stroke: var(--ai-blue);
262
+ stroke-width: 2.5px;
263
+ /* Using a circle with high radius as base for a rounded pointer */
264
+ stroke-linejoin: round;
272
265
  }
273
266
 
274
267
  .toast {
@@ -279,18 +272,13 @@ function g(t) {
279
272
  display: none;
280
273
  align-items: center;
281
274
  gap: 10px;
282
- min-height: 42px;
283
- border: 1px solid color-mix(in srgb, var(--ai-accent), transparent 78%);
284
- border-radius: 999px;
285
- background:
286
- linear-gradient(180deg, rgba(255, 255, 255, 0.92), rgba(255, 255, 255, 0.74)),
287
- var(--ai-panel);
275
+ border: 1px solid color-mix(in srgb, var(--ai-primary), transparent 74%);
276
+ border-radius: var(--ai-radius);
277
+ background: var(--ai-panel);
288
278
  color: var(--ai-text);
289
- padding: 8px 10px 8px 12px;
290
- font: 700 12px/1 Inter, ui-sans-serif, system-ui, sans-serif;
291
- letter-spacing: 0;
292
- box-shadow: var(--ai-shadow-md);
293
- backdrop-filter: blur(18px) saturate(1.25);
279
+ padding: 10px 12px;
280
+ font: 700 13px/1 Inter, ui-sans-serif, system-ui, sans-serif;
281
+ box-shadow: 0 16px 42px rgba(15, 23, 42, 0.18);
294
282
  }
295
283
 
296
284
  .toast.active {
@@ -298,28 +286,18 @@ function g(t) {
298
286
  }
299
287
 
300
288
  .pulse {
301
- position: relative;
302
- width: 9px;
303
- height: 9px;
289
+ width: 8px;
290
+ height: 8px;
304
291
  border-radius: 999px;
305
- background: var(--ai-accent);
306
- box-shadow: 0 0 0 5px color-mix(in srgb, var(--ai-accent), transparent 86%);
307
- }
308
-
309
- .pulse::after {
310
- content: "";
311
- position: absolute;
312
- inset: -6px;
313
- border-radius: inherit;
314
- border: 1px solid color-mix(in srgb, var(--ai-accent), transparent 58%);
315
- animation: pulse-ring 1.45s cubic-bezier(0.2, 0.8, 0.2, 1) infinite;
292
+ background: var(--ai-primary);
293
+ box-shadow: 0 0 0 0 color-mix(in srgb, var(--ai-primary), transparent 38%);
294
+ animation: pulse-ring 1.3s infinite;
316
295
  }
317
296
 
318
297
  .count {
319
- border-left: 1px solid var(--ai-border);
320
- padding: 4px 2px 4px 10px;
321
- color: var(--ai-muted);
322
- font-weight: 650;
298
+ border-left: 1px solid rgba(15, 23, 42, 0.12);
299
+ padding-left: 10px;
300
+ opacity: 0.72;
323
301
  }
324
302
 
325
303
  .hover {
@@ -327,182 +305,113 @@ function g(t) {
327
305
  z-index: 2147483644;
328
306
  pointer-events: none;
329
307
  display: none;
308
+ /* Thinner, professional 2px border */
330
309
  border: 2px solid transparent;
331
- border-radius: calc(var(--ai-radius) + 3px);
332
- background:
333
- linear-gradient(transparent, transparent) padding-box,
334
- linear-gradient(135deg, #60a5fa, #8b5cf6 48%, #22c55e) border-box;
335
- box-shadow:
336
- 0 0 0 4px rgba(37, 99, 235, 0.10),
337
- 0 18px 46px rgba(37, 99, 235, 0.18);
338
- transition:
339
- left 120ms ease,
340
- top 120ms ease,
341
- width 120ms ease,
342
- height 120ms ease;
310
+ border-radius: var(--ai-radius);
311
+ /* Pure transparent center, no fill at all */
312
+ background: none !important;
313
+ /* Conic gradient on border using border-image for absolute transparency in middle */
314
+ border-image: conic-gradient(var(--ai-blue), var(--ai-red), var(--ai-yellow), var(--ai-green), var(--ai-blue)) 1;
315
+ box-shadow: 0 0 15px rgba(66, 133, 244, 0.15);
316
+ transition: all 0.08s ease-out;
343
317
  }
344
318
 
345
319
  .panel {
346
320
  position: fixed;
347
321
  z-index: 2147483646;
348
- width: min(392px, calc(100vw - 32px));
322
+ width: 380px;
349
323
  display: none;
350
- border: 1px solid rgba(15, 23, 42, 0.12);
351
- border-radius: calc(var(--ai-radius) + 6px);
352
- background:
353
- radial-gradient(circle at 18% 0%, color-mix(in srgb, var(--ai-accent), transparent 88%), transparent 36%),
354
- linear-gradient(180deg, rgba(255, 255, 255, 0.96), rgba(255, 255, 255, 0.86)),
355
- var(--ai-panel);
324
+ border: 1px solid rgba(17, 24, 39, 0.14);
325
+ border-radius: var(--ai-radius);
326
+ background: var(--ai-panel);
356
327
  color: var(--ai-text);
357
328
  text-align: left;
358
- box-shadow: var(--ai-shadow-lg);
329
+ box-shadow: 0 26px 70px rgba(15, 23, 42, 0.22);
359
330
  overflow: hidden;
360
- backdrop-filter: blur(22px) saturate(1.18);
361
331
  }
362
332
 
363
333
  .panel.visible {
364
334
  display: block;
365
- animation: panel-in 140ms ease-out;
366
335
  }
367
336
 
368
337
  .head {
369
- display: grid;
370
- grid-template-columns: minmax(0, 1fr) 34px;
371
- align-items: start;
338
+ display: flex;
339
+ align-items: center;
340
+ justify-content: space-between;
372
341
  gap: 14px;
373
- border-bottom: 1px solid rgba(15, 23, 42, 0.08);
374
- padding: 16px 16px 13px;
342
+ border-bottom: 1px solid rgba(17, 24, 39, 0.08);
343
+ padding: 14px 14px 12px;
375
344
  }
376
345
 
377
346
  .kind {
378
- display: inline-flex;
379
- align-items: center;
380
- width: fit-content;
381
- max-width: 100%;
382
- min-height: 22px;
383
- margin-bottom: 7px;
384
- border: 1px solid color-mix(in srgb, var(--ai-accent), transparent 72%);
385
- border-radius: 999px;
386
- background: var(--ai-accent-soft);
387
- color: var(--ai-accent-strong);
388
- padding: 0 8px;
389
- font: 800 10px/1 Inter, ui-sans-serif, system-ui, sans-serif;
390
- letter-spacing: 0.04em;
347
+ display: block;
348
+ margin-bottom: 4px;
349
+ color: var(--ai-blue);
350
+ font: 800 11px/1 Inter, ui-sans-serif, system-ui, sans-serif;
391
351
  text-transform: uppercase;
392
352
  }
393
353
 
394
354
  .label {
395
- display: -webkit-box;
355
+ display: block;
396
356
  color: var(--ai-text);
397
- font: 760 15px/1.35 Inter, ui-sans-serif, system-ui, sans-serif;
398
- letter-spacing: 0;
399
- overflow: hidden;
400
- -webkit-box-orient: vertical;
401
- -webkit-line-clamp: 2;
357
+ font: 700 14px/1.25 Inter, ui-sans-serif, system-ui, sans-serif;
402
358
  }
403
359
 
404
360
  button {
405
- appearance: none;
406
- border: 1px solid rgba(15, 23, 42, 0.12);
407
- border-radius: calc(var(--ai-radius) - 2px);
408
- min-height: 42px;
409
- background: #0f172a;
361
+ border: 1px solid rgba(17, 24, 39, 0.12);
362
+ border-radius: var(--ai-radius);
363
+ min-height: 40px;
364
+ background: #111827;
410
365
  color: #ffffff;
411
- font: 760 14px/1 Inter, ui-sans-serif, system-ui, sans-serif;
412
- letter-spacing: 0;
366
+ font: 700 14px/1 Inter, ui-sans-serif, system-ui, sans-serif;
413
367
  cursor: pointer;
414
- transition:
415
- transform 120ms ease,
416
- box-shadow 120ms ease,
417
- background 120ms ease,
418
- border-color 120ms ease,
419
- opacity 120ms ease;
420
- }
421
-
422
- button:hover:not(:disabled) {
423
- transform: translateY(-1px);
424
- box-shadow: 0 10px 20px rgba(15, 23, 42, 0.16);
425
- }
426
-
427
- button:active:not(:disabled) {
428
- transform: translateY(0);
429
- }
430
-
431
- button:focus-visible,
432
- textarea:focus-visible {
433
- outline: 3px solid color-mix(in srgb, var(--ai-accent), transparent 78%);
434
- outline-offset: 2px;
435
368
  }
436
369
 
437
370
  button:disabled {
438
371
  cursor: not-allowed;
439
- opacity: 0.58;
440
- transform: none;
441
- box-shadow: none;
372
+ opacity: 0.56;
442
373
  }
443
374
 
444
375
  .close {
445
376
  min-width: 34px;
446
377
  min-height: 34px;
447
- border-radius: 999px;
448
378
  padding: 0;
449
- background: rgba(255, 255, 255, 0.72);
450
- color: var(--ai-muted);
451
- font-size: 18px;
452
- line-height: 1;
453
- }
454
-
455
- .close:hover:not(:disabled) {
456
- background: #ffffff;
457
- color: var(--ai-text);
379
+ background: #f3f4f6;
380
+ color: #111827;
458
381
  }
459
382
 
460
383
  form {
461
384
  display: grid;
462
- gap: 12px;
463
- padding: 14px 16px 16px;
385
+ gap: 10px;
386
+ padding: 14px;
464
387
  }
465
388
 
466
389
  textarea {
390
+ box-sizing: border-box;
467
391
  width: 100%;
468
392
  resize: vertical;
469
- min-height: 96px;
470
- max-height: 190px;
471
- border: 1px solid rgba(15, 23, 42, 0.14);
472
- border-radius: calc(var(--ai-radius) + 1px);
473
- padding: 12px 13px;
393
+ min-height: 86px;
394
+ max-height: 180px;
395
+ border: 1px solid rgba(17, 24, 39, 0.16);
396
+ border-radius: var(--ai-radius);
397
+ padding: 12px;
474
398
  color: #111827;
475
- background: rgba(255, 255, 255, 0.88);
476
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.7);
477
- font: 450 14px/1.5 Inter, ui-sans-serif, system-ui, sans-serif;
478
- letter-spacing: 0;
479
- }
480
-
481
- textarea::placeholder {
482
- color: rgba(75, 85, 99, 0.72);
483
- }
484
-
485
- textarea:focus {
486
- border-color: color-mix(in srgb, var(--ai-accent), transparent 22%);
487
399
  background: #ffffff;
488
- outline: none;
400
+ font: 15px/1.45 Inter, ui-sans-serif, system-ui, sans-serif;
489
401
  }
490
402
 
491
- .submit {
492
- border-color: color-mix(in srgb, var(--ai-accent-strong), black 14%);
493
- background:
494
- linear-gradient(180deg, color-mix(in srgb, var(--ai-accent), white 8%), var(--ai-accent-strong));
495
- box-shadow: 0 12px 22px color-mix(in srgb, var(--ai-accent), transparent 78%);
403
+ textarea:focus {
404
+ border-color: var(--ai-blue);
405
+ outline: 3px solid color-mix(in srgb, var(--ai-blue), transparent 86%);
496
406
  }
497
407
 
498
408
  .error,
499
409
  .answer {
500
410
  display: none;
501
- margin: 0 16px 16px;
502
- border-radius: calc(var(--ai-radius) + 1px);
503
- padding: 12px 13px;
504
- font: 440 14px/1.5 Inter, ui-sans-serif, system-ui, sans-serif;
505
- letter-spacing: 0;
411
+ margin: 0 14px 14px;
412
+ border-radius: var(--ai-radius);
413
+ padding: 12px;
414
+ font: 14px/1.45 Inter, ui-sans-serif, system-ui, sans-serif;
506
415
  white-space: pre-wrap;
507
416
  }
508
417
 
@@ -512,25 +421,18 @@ function g(t) {
512
421
  }
513
422
 
514
423
  .error {
515
- border: 1px solid rgba(220, 38, 38, 0.18);
516
- background: #fff1f2;
517
- color: #9f1239;
424
+ background: #fef2f2;
425
+ color: #991b1b;
518
426
  }
519
427
 
520
428
  .answer {
521
- max-height: 230px;
429
+ max-height: 220px;
522
430
  overflow: auto;
523
- border: 1px solid rgba(15, 23, 42, 0.08);
524
- background: rgba(248, 250, 252, 0.82);
431
+ background: #f8fafc;
525
432
  color: #111827;
526
433
  }
527
434
 
528
435
  @media (max-width: 760px) {
529
- .toast {
530
- right: 12px;
531
- bottom: 12px;
532
- }
533
-
534
436
  .panel {
535
437
  left: 12px !important;
536
438
  right: 12px;
@@ -540,41 +442,15 @@ function g(t) {
540
442
  }
541
443
  }
542
444
 
543
- @media (prefers-reduced-motion: reduce) {
544
- *,
545
- *::before,
546
- *::after {
547
- animation-duration: 0.001ms !important;
548
- animation-iteration-count: 1 !important;
549
- transition-duration: 0.001ms !important;
550
- }
551
- }
552
-
553
445
  @keyframes pulse-ring {
554
- 0% {
555
- opacity: 0.75;
556
- transform: scale(0.74);
557
- }
558
- 100% {
559
- opacity: 0;
560
- transform: scale(1.55);
561
- }
562
- }
563
-
564
- @keyframes panel-in {
565
- from {
566
- opacity: 0;
567
- transform: translateY(6px) scale(0.985);
568
- }
569
- to {
570
- opacity: 1;
571
- transform: translateY(0) scale(1);
572
- }
446
+ 70% { box-shadow: 0 0 0 8px transparent; }
447
+ 100% { box-shadow: 0 0 0 0 transparent; }
573
448
  }
574
449
  </style>
575
450
  <div class="custom-cursor">
576
- <svg viewBox="0 0 28 32" class="cursor-shape" aria-hidden="true">
577
- <path d="M2,2 L2,28 L8,22 L14,32 L18,29 L12,19 L22,19 Z" stroke-linejoin="round" stroke-linecap="round" />
451
+ <svg viewBox="0 0 28 32" class="cursor-shape">
452
+ <!-- Rounded, professional pointer -->
453
+ <path d="M4,2 L4,26 L10,20 L15,30 L19,27 L14,18 L24,18 Z" stroke-linejoin="round" stroke-linecap="round" />
578
454
  </svg>
579
455
  </div>
580
456
  <div class="toast" role="status">
@@ -624,7 +500,7 @@ function g(t) {
624
500
  c.style.display = "block", c.style.left = `${e.left}px`, c.style.top = `${e.top}px`, c.style.width = `${e.width}px`, c.style.height = `${e.height}px`;
625
501
  },
626
502
  showPrompt: (t) => {
627
- let n = e(t.rect.left + t.rect.width / 2 - 196, 16, window.innerWidth - 408), r = e(t.rect.bottom + 14, 16, window.innerHeight - 396);
503
+ let n = e(t.rect.left + t.rect.width / 2 - 190, 16, window.innerWidth - 396), r = e(t.rect.bottom + 14, 16, window.innerHeight - 380);
628
504
  u.textContent = t.kind, d.textContent = t.label, p.value = "", m.disabled = !1, m.textContent = "Ask AI", g.classList.remove("visible"), _.classList.remove("visible"), l.style.left = `${n}px`, l.style.top = `${r}px`, l.classList.add("visible"), p.focus();
629
505
  },
630
506
  setThinking: (e) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@emmaexcel/shakecursor",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Framework-agnostic browser SDK for contextual AI selection overlays.",
5
5
  "type": "module",
6
6
  "main": "./dist/overlay.global.js",