@emmaexcel/shakecursor 0.1.0 → 0.1.3
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/README.md +1 -1
- package/dist/overlay.global.js +58 -11
- package/dist/overlay.js +83 -22
- package/dist/types.d.ts +2 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ Framework-agnostic browser SDK for contextual AI selection overlays.
|
|
|
5
5
|
## NPM-style usage
|
|
6
6
|
|
|
7
7
|
```ts
|
|
8
|
-
import { AIOverlay } from '@shakecursor
|
|
8
|
+
import { AIOverlay } from '@emmaexcel/shakecursor'
|
|
9
9
|
|
|
10
10
|
const overlay = AIOverlay.init({
|
|
11
11
|
siteKey: 'pk_demo_shakecursor',
|
package/dist/overlay.global.js
CHANGED
|
@@ -1,10 +1,21 @@
|
|
|
1
|
-
(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});function t(e,t,n){return Math.min(Math.max(e,t),n)}function n(e){return e.replace(/\s+/g,` `).trim()}function r(e,t=[]){return t.some(t=>{try{return e.matches(t)||!!e.closest(t)}catch{return!1}})}function i(){return/Mac|iPhone|iPad|iPod/i.test(window.navigator.platform)}function a(e){if(e.rangeCount===0)return null;let t=e.getRangeAt(0),n=t.getBoundingClientRect();return n.width>0||n.height>0?n:t.getClientRects()[0]??null}function o(e){return{rect:e,url:window.location.href,title:document.title}}function s(e){let t=n(e.innerText??``),r=e.tagName.toLowerCase(),i=e.getAttribute(`aria-label`),a=e.getAttribute(`title`),o=[i,a,t].find(Boolean);return{label:o?`${r}: ${o.slice(0,64)}`:r,content:[`Selected element: <${r}>`,i?`ARIA label: ${i}`:``,a?`Title: ${a}`:``,t?`Visible text: ${t.slice(0,5e3)}`:``].filter(Boolean).join(`
|
|
2
|
-
`)}}function c(e){let t=e.currentSrc||e.src,n=e.alt||`No alt text
|
|
3
|
-
`)}}function l(e,t){return!(r(e,t.blockedSelectors)||t.allowedSelectors.length>0&&!r(e,t.allowedSelectors))}function u(e){let t=t=>{if(!e.isActive())return;let n=t.target;if(!(n instanceof HTMLElement)||e.isOverlayElement(n)){e.onHover(null);return}if(!l(n,e.config)){e.onHover(null);return}e.onHover(n.getBoundingClientRect())},r=()=>{!e.isActive()||!e.config.text||window.setTimeout(()=>{let t=window.getSelection(),r=n(t?.toString()??``);if(!t||!r)return;let i=a(t),s=t.anchorNode?.parentElement;!i||!s||!l(s,e.config)||e.onSelection({kind:`text`,label:`highlighted text`,content:r,...o(i)})},0)},i=t=>{if(!e.isActive())return;let r=t.target;if(!(r instanceof HTMLElement)||e.isOverlayElement(r)||!l(r,e.config)||n(window.getSelection()?.toString()??``))return;let i=r instanceof HTMLImageElement?r:r.querySelector(`img`),a=!!i;if(a&&!e.config.images||!a&&!e.config.elements)return;t.preventDefault(),t.stopPropagation();let u=i?c(i):s(r),d=i?i.getBoundingClientRect():r.getBoundingClientRect();e.onSelection({kind:i?`image`:`element`,label:u.label,content:u.content,...o(d)})};return document.addEventListener(`pointerover`,t),document.addEventListener(`mouseup`,r),document.addEventListener(`click`,i,!0),()=>{document.removeEventListener(`pointerover`,t),document.removeEventListener(`mouseup`,r),document.removeEventListener(`click`,i,!0)}}function d(e){let t=e.windowMs??650,n=e.cooldownMs??1e3,r=e.minSamples??7,i=e.minReversals??5,a=e.minDistance??340,o=e.minDeltaX??16,s=[],c=0,l=l=>{let u=performance.now();if(s.push({x:l.clientX,y:l.clientY,time:u}),s=s.filter(e=>u-e.time<t),s.length<r||u-c<n)return;let d=0,f=0,p=0;for(let e=1;e<s.length;e+=1){let t=s[e].x-s[e-1].x,n=s[e].y-s[e-1].y;if(f+=Math.hypot(t,n),Math.abs(t)<o)continue;let r=Math.sign(t);p!==0&&r!==p&&(d+=1),p=r}d>=i&&f>a&&(c=u,s=[],e.onShake())};return document.addEventListener(`pointermove`,l),()=>{document.removeEventListener(`pointermove`,l)}}var f=`http://localhost:11434/api/chat`,p=`qwen3-coder:480b-cloud`,m=`https://shakeai.onrender.com`;async function h(e,t){let n=e.provider??`ollama`,r=e.endpoint??f,i=e.model??p;if(n===`custom`){let n=await fetch(r,{method:`POST`,headers:{"Content-Type":`application/json`,...e.headers},body:JSON.stringify(t)});if(!n.ok)throw Error(`Custom endpoint returned ${n.status}`);let i=await n.json();return typeof i==`string`?i:i&&typeof i==`object`&&`answer`in i&&typeof i.answer==`string`?i.answer:i&&typeof i==`object`&&`content`in i&&typeof i.content==`string`?i.content:JSON.stringify(i,null,2)}let a=await fetch(r,{method:`POST`,headers:{"Content-Type":`application/json`,...e.headers},body:JSON.stringify({model:i,stream:!1,messages:[{role:`system`,content:`You are an in-page AI assistant. Use the selected website context to answer or transform content. Be direct and practical.`},{role:`user`,content:[`Page title: ${t.selection.title}`,`Page URL: ${t.selection.url}`,`Selection type: ${t.selection.kind}`,`Selection label: ${t.selection.label}`,`Selected context:`,t.selection.content,``,`User request: ${t.question}`].join(`
|
|
4
|
-
`)}]})});if(!a.ok)throw Error(`Ollama returned ${a.status}`);let o=await a.json();if(o.error)throw Error(o.error);return o.message?.content?.trim()||`No response returned.`}async function g(e){let t=await fetch(`${e.apiBaseUrl??m}/v1/ask`,{method:`POST`,headers:{"Content-Type":`application/json`,"x-site-key":e.siteKey},body:JSON.stringify(e.payload)}),n=await t.json();if(!t.ok||n.error)throw Error(n.error??`Hosted API returned ${t.status}`);return n.answer??`No response returned.`}function _(e){let n=document.createElement(`div`);n.dataset.aiOverlayRoot=`true`;let r=document.createElement(`style`);r.dataset.aiOverlayStyle=`true`,r.textContent=`
|
|
1
|
+
(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});function t(e,t,n){return Math.min(Math.max(e,t),n)}function n(e){return e.replace(/\s+/g,` `).trim()}function r(e,t=[]){return t.some(t=>{try{return e.matches(t)||!!e.closest(t)}catch{return!1}})}function i(){return/Mac|iPhone|iPad|iPod/i.test(window.navigator.platform)}function a(e){if(e.rangeCount===0)return null;let t=e.getRangeAt(0),n=t.getBoundingClientRect();return n.width>0||n.height>0?n:t.getClientRects()[0]??null}function o(e){return{rect:e,url:window.location.href,title:document.title}}function s(e){let t=n(e.innerText??``),r=e.tagName.toLowerCase(),i=e.getAttribute(`aria-label`),a=e.getAttribute(`title`),o=[i,a,t].find(Boolean);return{label:o?`${r}: ${o.slice(0,64)}`:r,data:void 0,mimeType:void 0,content:[`Selected element: <${r}>`,i?`ARIA label: ${i}`:``,a?`Title: ${a}`:``,t?`Visible text: ${t.slice(0,5e3)}`:``].filter(Boolean).join(`
|
|
2
|
+
`)}}function c(e){let t=e.currentSrc||e.src,n=e.alt||`No alt text`,r,i;try{let t=document.createElement(`canvas`);t.width=e.naturalWidth,t.height=e.naturalHeight;let n=t.getContext(`2d`);if(n){n.drawImage(e,0,0);let[a,o]=t.toDataURL(`image/jpeg`,.8).split(`,`);r=o,i=a.split(`:`)[1].split(`;`)[0]}}catch(e){console.warn(`Failed to capture image data (likely CORS):`,e)}return{label:`image: ${n.slice(0,64)}`,data:r,mimeType:i,content:[`Selected image`,`Alt text: ${n}`,`Source: ${t}`,`Rendered size: ${Math.round(e.width)}x${Math.round(e.height)}`,`Natural size: ${e.naturalWidth}x${e.naturalHeight}`].join(`
|
|
3
|
+
`)}}function l(e,t){return!(r(e,t.blockedSelectors)||t.allowedSelectors.length>0&&!r(e,t.allowedSelectors))}function u(e){let t=t=>{if(!e.isActive())return;let n=t.target;if(!(n instanceof HTMLElement)||e.isOverlayElement(n)){e.onHover(null);return}if(!l(n,e.config)){e.onHover(null);return}e.onHover(n.getBoundingClientRect())},r=()=>{!e.isActive()||!e.config.text||window.setTimeout(()=>{let t=window.getSelection(),r=n(t?.toString()??``);if(!t||!r)return;let i=a(t),s=t.anchorNode?.parentElement;!i||!s||!l(s,e.config)||e.onSelection({kind:`text`,label:`highlighted text`,content:r,...o(i)})},0)},i=t=>{if(!e.isActive())return;let r=t.target;if(!(r instanceof HTMLElement)||e.isOverlayElement(r)||!l(r,e.config)||n(window.getSelection()?.toString()??``))return;let i=r instanceof HTMLImageElement?r:r.querySelector(`img`),a=!!i;if(a&&!e.config.images||!a&&!e.config.elements)return;t.preventDefault(),t.stopPropagation();let u=i?c(i):s(r),d=i?i.getBoundingClientRect():r.getBoundingClientRect();e.onSelection({kind:i?`image`:`element`,label:u.label,content:u.content,data:u.data,mimeType:u.mimeType,...o(d)})};return document.addEventListener(`pointerover`,t),document.addEventListener(`mouseup`,r),document.addEventListener(`click`,i,!0),()=>{document.removeEventListener(`pointerover`,t),document.removeEventListener(`mouseup`,r),document.removeEventListener(`click`,i,!0)}}function d(e){let t=e.windowMs??650,n=e.cooldownMs??1e3,r=e.minSamples??7,i=e.minReversals??5,a=e.minDistance??340,o=e.minDeltaX??16,s=[],c=0,l=l=>{let u=performance.now();if(s.push({x:l.clientX,y:l.clientY,time:u}),s=s.filter(e=>u-e.time<t),s.length<r||u-c<n)return;let d=0,f=0,p=0;for(let e=1;e<s.length;e+=1){let t=s[e].x-s[e-1].x,n=s[e].y-s[e-1].y;if(f+=Math.hypot(t,n),Math.abs(t)<o)continue;let r=Math.sign(t);p!==0&&r!==p&&(d+=1),p=r}d>=i&&f>a&&(c=u,s=[],e.onShake())};return document.addEventListener(`pointermove`,l),()=>{document.removeEventListener(`pointermove`,l)}}var f=`http://localhost:11434/api/chat`,p=`qwen3-coder:480b-cloud`,m=`https://shakeai.onrender.com`;async function h(e,t){let n=e.provider??`ollama`,r=e.endpoint??f,i=e.model??p;if(n===`custom`){let n=await fetch(r,{method:`POST`,headers:{"Content-Type":`application/json`,...e.headers},body:JSON.stringify(t)});if(!n.ok)throw Error(`Custom endpoint returned ${n.status}`);let i=await n.json();return typeof i==`string`?i:i&&typeof i==`object`&&`answer`in i&&typeof i.answer==`string`?i.answer:i&&typeof i==`object`&&`content`in i&&typeof i.content==`string`?i.content:JSON.stringify(i,null,2)}let a=await fetch(r,{method:`POST`,headers:{"Content-Type":`application/json`,...e.headers},body:JSON.stringify({model:i,stream:!1,messages:[{role:`system`,content:`You are an in-page AI assistant. Use the selected website context to answer or transform content. Be direct and practical.`},{role:`user`,content:[`Page title: ${t.selection.title}`,`Page URL: ${t.selection.url}`,`Selection type: ${t.selection.kind}`,`Selection label: ${t.selection.label}`,`Selected context:`,t.selection.content,``,`User request: ${t.question}`].join(`
|
|
4
|
+
`)}]})});if(!a.ok)throw Error(`Ollama returned ${a.status}`);let o=await a.json();if(o.error)throw Error(o.error);return o.message?.content?.trim()||`No response returned.`}async function g(e){let t=await fetch(`${e.apiBaseUrl??m}/v1/ask`,{method:`POST`,headers:{"Content-Type":`application/json`,"x-site-key":e.siteKey},body:JSON.stringify(e.payload)}),n=await t.json();if(!t.ok||n.error)throw Error(n.error??`Hosted API returned ${t.status}`);return n.answer??`No response returned.`}function _(e){let n=document.createElement(`div`);n.dataset.aiOverlayRoot=`true`;let r=document.createElement(`style`);r.dataset.aiOverlayStyle=`true`,r.textContent=`
|
|
5
|
+
body.ai-overlay-active {
|
|
6
|
+
cursor: none !important;
|
|
7
|
+
}
|
|
8
|
+
body.ai-overlay-active * {
|
|
9
|
+
cursor: none !important;
|
|
10
|
+
}
|
|
11
|
+
`;let i=n.attachShadow({mode:`open`});document.head.append(r),document.body.append(n),i.innerHTML=`
|
|
5
12
|
<style>
|
|
6
13
|
:host {
|
|
7
14
|
all: initial;
|
|
15
|
+
--ai-blue: #4285F4;
|
|
16
|
+
--ai-red: #DB4437;
|
|
17
|
+
--ai-yellow: #F4B400;
|
|
18
|
+
--ai-green: #0F9D58;
|
|
8
19
|
--ai-primary: ${e.theme.primaryColor};
|
|
9
20
|
--ai-panel: ${e.theme.panelBackground};
|
|
10
21
|
--ai-text: ${e.theme.textColor};
|
|
@@ -12,6 +23,33 @@
|
|
|
12
23
|
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
13
24
|
}
|
|
14
25
|
|
|
26
|
+
.custom-cursor {
|
|
27
|
+
position: fixed;
|
|
28
|
+
left: 0;
|
|
29
|
+
top: 0;
|
|
30
|
+
width: 32px;
|
|
31
|
+
height: 32px;
|
|
32
|
+
pointer-events: none;
|
|
33
|
+
z-index: 2147483647;
|
|
34
|
+
display: none;
|
|
35
|
+
/* Offset to center the "tip" of the pointer */
|
|
36
|
+
margin-left: -4px;
|
|
37
|
+
margin-top: -4px;
|
|
38
|
+
filter: drop-shadow(0 0 8px rgba(66, 133, 244, 0.6));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.custom-cursor.active {
|
|
42
|
+
display: block;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.cursor-shape {
|
|
46
|
+
width: 100%;
|
|
47
|
+
height: 100%;
|
|
48
|
+
fill: white;
|
|
49
|
+
stroke: var(--ai-blue);
|
|
50
|
+
stroke-width: 2px;
|
|
51
|
+
}
|
|
52
|
+
|
|
15
53
|
.toast {
|
|
16
54
|
position: fixed;
|
|
17
55
|
right: 18px;
|
|
@@ -53,11 +91,15 @@
|
|
|
53
91
|
z-index: 2147483644;
|
|
54
92
|
pointer-events: none;
|
|
55
93
|
display: none;
|
|
56
|
-
|
|
94
|
+
/* Thicker, more professional border */
|
|
95
|
+
border: 4px solid transparent;
|
|
57
96
|
border-radius: var(--ai-radius);
|
|
97
|
+
/*Conic gradient on border only, no gray background fill */
|
|
98
|
+
background: linear-gradient(transparent, transparent) padding-box,
|
|
99
|
+
conic-gradient(var(--ai-blue), var(--ai-red), var(--ai-yellow), var(--ai-green), var(--ai-blue)) border-box;
|
|
58
100
|
box-shadow:
|
|
59
|
-
0 0
|
|
60
|
-
|
|
101
|
+
0 0 30px color-mix(in srgb, var(--ai-blue), transparent 85%);
|
|
102
|
+
transition: all 0.12s ease-out;
|
|
61
103
|
}
|
|
62
104
|
|
|
63
105
|
.panel {
|
|
@@ -90,7 +132,7 @@
|
|
|
90
132
|
.kind {
|
|
91
133
|
display: block;
|
|
92
134
|
margin-bottom: 4px;
|
|
93
|
-
color: var(--ai-
|
|
135
|
+
color: var(--ai-blue);
|
|
94
136
|
font: 800 11px/1 Inter, ui-sans-serif, system-ui, sans-serif;
|
|
95
137
|
text-transform: uppercase;
|
|
96
138
|
}
|
|
@@ -145,8 +187,8 @@
|
|
|
145
187
|
}
|
|
146
188
|
|
|
147
189
|
textarea:focus {
|
|
148
|
-
border-color: var(--ai-
|
|
149
|
-
outline: 3px solid color-mix(in srgb, var(--ai-
|
|
190
|
+
border-color: var(--ai-blue);
|
|
191
|
+
outline: 3px solid color-mix(in srgb, var(--ai-blue), transparent 86%);
|
|
150
192
|
}
|
|
151
193
|
|
|
152
194
|
.error,
|
|
@@ -191,6 +233,11 @@
|
|
|
191
233
|
100% { box-shadow: 0 0 0 0 transparent; }
|
|
192
234
|
}
|
|
193
235
|
</style>
|
|
236
|
+
<div class="custom-cursor">
|
|
237
|
+
<svg viewBox="0 0 28 32" class="cursor-shape">
|
|
238
|
+
<path d="M2,2 L2,28 L8,22 L14,32 L18,29 L12,19 L22,19 Z" stroke-linejoin="round" stroke-linecap="round" />
|
|
239
|
+
</svg>
|
|
240
|
+
</div>
|
|
194
241
|
<div class="toast" role="status">
|
|
195
242
|
<span class="pulse"></span>
|
|
196
243
|
<span>AI mode active</span>
|
|
@@ -212,4 +259,4 @@
|
|
|
212
259
|
<p class="error"></p>
|
|
213
260
|
<div class="answer"></div>
|
|
214
261
|
</section>
|
|
215
|
-
`;let a=i.querySelector(`.
|
|
262
|
+
`;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
|
@@ -39,6 +39,8 @@ function o(e) {
|
|
|
39
39
|
].find(Boolean);
|
|
40
40
|
return {
|
|
41
41
|
label: o ? `${r}: ${o.slice(0, 64)}` : r,
|
|
42
|
+
data: void 0,
|
|
43
|
+
mimeType: void 0,
|
|
42
44
|
content: [
|
|
43
45
|
`Selected element: <${r}>`,
|
|
44
46
|
i ? `ARIA label: ${i}` : "",
|
|
@@ -48,9 +50,23 @@ function o(e) {
|
|
|
48
50
|
};
|
|
49
51
|
}
|
|
50
52
|
function s(e) {
|
|
51
|
-
let t = e.currentSrc || e.src, n = e.alt || "No alt text";
|
|
53
|
+
let t = e.currentSrc || e.src, n = e.alt || "No alt text", r, i;
|
|
54
|
+
try {
|
|
55
|
+
let t = document.createElement("canvas");
|
|
56
|
+
t.width = e.naturalWidth, t.height = e.naturalHeight;
|
|
57
|
+
let n = t.getContext("2d");
|
|
58
|
+
if (n) {
|
|
59
|
+
n.drawImage(e, 0, 0);
|
|
60
|
+
let [a, o] = t.toDataURL("image/jpeg", .8).split(",");
|
|
61
|
+
r = o, i = a.split(":")[1].split(";")[0];
|
|
62
|
+
}
|
|
63
|
+
} catch (e) {
|
|
64
|
+
console.warn("Failed to capture image data (likely CORS):", e);
|
|
65
|
+
}
|
|
52
66
|
return {
|
|
53
67
|
label: `image: ${n.slice(0, 64)}`,
|
|
68
|
+
data: r,
|
|
69
|
+
mimeType: i,
|
|
54
70
|
content: [
|
|
55
71
|
"Selected image",
|
|
56
72
|
`Alt text: ${n}`,
|
|
@@ -100,6 +116,8 @@ function l(e) {
|
|
|
100
116
|
kind: i ? "image" : "element",
|
|
101
117
|
label: u.label,
|
|
102
118
|
content: u.content,
|
|
119
|
+
data: u.data,
|
|
120
|
+
mimeType: u.mimeType,
|
|
103
121
|
...a(d)
|
|
104
122
|
});
|
|
105
123
|
};
|
|
@@ -198,12 +216,16 @@ function g(t) {
|
|
|
198
216
|
let n = document.createElement("div");
|
|
199
217
|
n.dataset.aiOverlayRoot = "true";
|
|
200
218
|
let r = document.createElement("style");
|
|
201
|
-
r.dataset.aiOverlayStyle = "true", r.textContent = "body.ai-overlay-active { cursor:
|
|
219
|
+
r.dataset.aiOverlayStyle = "true", r.textContent = "\n body.ai-overlay-active { \n cursor: none !important; \n }\n body.ai-overlay-active * { \n cursor: none !important; \n }\n ";
|
|
202
220
|
let i = n.attachShadow({ mode: "open" });
|
|
203
221
|
document.head.append(r), document.body.append(n), i.innerHTML = `
|
|
204
222
|
<style>
|
|
205
223
|
:host {
|
|
206
224
|
all: initial;
|
|
225
|
+
--ai-blue: #4285F4;
|
|
226
|
+
--ai-red: #DB4437;
|
|
227
|
+
--ai-yellow: #F4B400;
|
|
228
|
+
--ai-green: #0F9D58;
|
|
207
229
|
--ai-primary: ${t.theme.primaryColor};
|
|
208
230
|
--ai-panel: ${t.theme.panelBackground};
|
|
209
231
|
--ai-text: ${t.theme.textColor};
|
|
@@ -211,6 +233,33 @@ function g(t) {
|
|
|
211
233
|
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
212
234
|
}
|
|
213
235
|
|
|
236
|
+
.custom-cursor {
|
|
237
|
+
position: fixed;
|
|
238
|
+
left: 0;
|
|
239
|
+
top: 0;
|
|
240
|
+
width: 32px;
|
|
241
|
+
height: 32px;
|
|
242
|
+
pointer-events: none;
|
|
243
|
+
z-index: 2147483647;
|
|
244
|
+
display: none;
|
|
245
|
+
/* Offset to center the "tip" of the pointer */
|
|
246
|
+
margin-left: -4px;
|
|
247
|
+
margin-top: -4px;
|
|
248
|
+
filter: drop-shadow(0 0 8px rgba(66, 133, 244, 0.6));
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.custom-cursor.active {
|
|
252
|
+
display: block;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.cursor-shape {
|
|
256
|
+
width: 100%;
|
|
257
|
+
height: 100%;
|
|
258
|
+
fill: white;
|
|
259
|
+
stroke: var(--ai-blue);
|
|
260
|
+
stroke-width: 2px;
|
|
261
|
+
}
|
|
262
|
+
|
|
214
263
|
.toast {
|
|
215
264
|
position: fixed;
|
|
216
265
|
right: 18px;
|
|
@@ -252,11 +301,15 @@ function g(t) {
|
|
|
252
301
|
z-index: 2147483644;
|
|
253
302
|
pointer-events: none;
|
|
254
303
|
display: none;
|
|
255
|
-
|
|
304
|
+
/* Thicker, more professional border */
|
|
305
|
+
border: 4px solid transparent;
|
|
256
306
|
border-radius: var(--ai-radius);
|
|
307
|
+
/*Conic gradient on border only, no gray background fill */
|
|
308
|
+
background: linear-gradient(transparent, transparent) padding-box,
|
|
309
|
+
conic-gradient(var(--ai-blue), var(--ai-red), var(--ai-yellow), var(--ai-green), var(--ai-blue)) border-box;
|
|
257
310
|
box-shadow:
|
|
258
|
-
0 0
|
|
259
|
-
|
|
311
|
+
0 0 30px color-mix(in srgb, var(--ai-blue), transparent 85%);
|
|
312
|
+
transition: all 0.12s ease-out;
|
|
260
313
|
}
|
|
261
314
|
|
|
262
315
|
.panel {
|
|
@@ -289,7 +342,7 @@ function g(t) {
|
|
|
289
342
|
.kind {
|
|
290
343
|
display: block;
|
|
291
344
|
margin-bottom: 4px;
|
|
292
|
-
color: var(--ai-
|
|
345
|
+
color: var(--ai-blue);
|
|
293
346
|
font: 800 11px/1 Inter, ui-sans-serif, system-ui, sans-serif;
|
|
294
347
|
text-transform: uppercase;
|
|
295
348
|
}
|
|
@@ -344,8 +397,8 @@ function g(t) {
|
|
|
344
397
|
}
|
|
345
398
|
|
|
346
399
|
textarea:focus {
|
|
347
|
-
border-color: var(--ai-
|
|
348
|
-
outline: 3px solid color-mix(in srgb, var(--ai-
|
|
400
|
+
border-color: var(--ai-blue);
|
|
401
|
+
outline: 3px solid color-mix(in srgb, var(--ai-blue), transparent 86%);
|
|
349
402
|
}
|
|
350
403
|
|
|
351
404
|
.error,
|
|
@@ -390,6 +443,11 @@ function g(t) {
|
|
|
390
443
|
100% { box-shadow: 0 0 0 0 transparent; }
|
|
391
444
|
}
|
|
392
445
|
</style>
|
|
446
|
+
<div class="custom-cursor">
|
|
447
|
+
<svg viewBox="0 0 28 32" class="cursor-shape">
|
|
448
|
+
<path d="M2,2 L2,28 L8,22 L14,32 L18,29 L12,19 L22,19 Z" stroke-linejoin="round" stroke-linecap="round" />
|
|
449
|
+
</svg>
|
|
450
|
+
</div>
|
|
393
451
|
<div class="toast" role="status">
|
|
394
452
|
<span class="pulse"></span>
|
|
395
453
|
<span>AI mode active</span>
|
|
@@ -412,45 +470,48 @@ function g(t) {
|
|
|
412
470
|
<div class="answer"></div>
|
|
413
471
|
</section>
|
|
414
472
|
`;
|
|
415
|
-
let a = i.querySelector(".
|
|
416
|
-
if (!a || !o || !s || !c || !l || !u || !d || !f || !p || !m || !h || !g) throw Error("AIOverlay UI failed to initialize");
|
|
417
|
-
|
|
473
|
+
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");
|
|
474
|
+
if (!a || !o || !s || !c || !l || !u || !d || !f || !p || !m || !h || !g || !_) throw Error("AIOverlay UI failed to initialize");
|
|
475
|
+
let v = (e) => {
|
|
476
|
+
a.style.left = `${e.clientX}px`, a.style.top = `${e.clientY}px`;
|
|
477
|
+
};
|
|
478
|
+
return f.addEventListener("submit", (e) => {
|
|
418
479
|
e.preventDefault();
|
|
419
|
-
let n =
|
|
480
|
+
let n = p.value.trim();
|
|
420
481
|
n && t.onSubmit(n);
|
|
421
|
-
}),
|
|
482
|
+
}), h.addEventListener("click", () => {
|
|
422
483
|
t.onCancel();
|
|
423
484
|
}), {
|
|
424
485
|
root: n,
|
|
425
486
|
contains: (e) => e === n || n.contains(e),
|
|
426
487
|
setActive: (e, t) => {
|
|
427
|
-
a.classList.toggle("active", e),
|
|
488
|
+
o.classList.toggle("active", e), a.classList.toggle("active", e), s.textContent = `shakes ${t}`, e ? window.addEventListener("mousemove", v) : window.removeEventListener("mousemove", v);
|
|
428
489
|
},
|
|
429
490
|
setHoverRect: (e) => {
|
|
430
491
|
if (!e) {
|
|
431
|
-
|
|
492
|
+
c.style.display = "none";
|
|
432
493
|
return;
|
|
433
494
|
}
|
|
434
|
-
|
|
495
|
+
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`;
|
|
435
496
|
},
|
|
436
497
|
showPrompt: (t) => {
|
|
437
498
|
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);
|
|
438
|
-
|
|
499
|
+
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();
|
|
439
500
|
},
|
|
440
501
|
setThinking: (e) => {
|
|
441
|
-
|
|
502
|
+
m.disabled = e, m.textContent = e ? "Thinking..." : "Ask AI";
|
|
442
503
|
},
|
|
443
504
|
setAnswer: (e) => {
|
|
444
|
-
|
|
505
|
+
_.textContent = e, _.classList.toggle("visible", !!e);
|
|
445
506
|
},
|
|
446
507
|
setError: (e) => {
|
|
447
|
-
|
|
508
|
+
g.textContent = e, g.classList.toggle("visible", !!e);
|
|
448
509
|
},
|
|
449
510
|
clearSelection: () => {
|
|
450
|
-
|
|
511
|
+
l.classList.remove("visible"), g.classList.remove("visible"), _.classList.remove("visible"), p.value = "";
|
|
451
512
|
},
|
|
452
513
|
destroy: () => {
|
|
453
|
-
r.remove(), n.remove();
|
|
514
|
+
r.remove(), n.remove(), window.removeEventListener("mousemove", v);
|
|
454
515
|
}
|
|
455
516
|
};
|
|
456
517
|
}
|
package/dist/types.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@emmaexcel/shakecursor",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Framework-agnostic browser SDK for contextual AI selection overlays.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/overlay.global.js",
|
|
@@ -37,4 +37,4 @@
|
|
|
37
37
|
],
|
|
38
38
|
"author": "EmmaExcel",
|
|
39
39
|
"license": "MIT"
|
|
40
|
-
}
|
|
40
|
+
}
|