@vrixton/pixel-pet 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.
package/README.md CHANGED
@@ -62,7 +62,9 @@ The message shows right away, without hovering, and screen readers announce it.
62
62
  | Option | Type | Default | Description |
63
63
  | --- | --- | --- | --- |
64
64
  | `emotion` | `'happy' \| 'angry' \| 'curious'` | none | Plays that emotion's animation and colors the bubble to match. Without it, the bubble is neutral. |
65
- | `duration` | `number` | `5000` | How long the message stays, in milliseconds. |
65
+ | `duration` | `number` | `5000` | How long the message stays, in milliseconds. Pass `Infinity` to keep it until a new message replaces it, the user taps the pet, or the pet falls asleep. |
66
+
67
+ Call `pet.current?.hush()` to close the current message right away, for example when the user dismisses it.
66
68
 
67
69
  ## Props
68
70
 
@@ -77,7 +79,8 @@ The message shows right away, without hovering, and screen readers announce it.
77
79
  | `messages` | `PetMessages` | English messages | Replaces the text shown for each emotion. |
78
80
  | `dialogStyle` | `DialogStyleProps` | none | Styles for every bubble. |
79
81
  | `emotionDialogStyles` | `Partial<Record<PetEmotion, DialogStyleProps>>` | none | Styles for the bubble of a single emotion. |
80
- | `ref` | `Ref<PixelPetHandle>` | none | Gives you the `say()` method. |
82
+ | `onClick` | `(event) => void` | none | Called when the user clicks or taps the pet. Call `event.preventDefault()` inside it to skip the pet's own reaction. |
83
+ | `ref` | `Ref<PixelPetHandle>` | none | Gives you the `say()` and `hush()` methods. |
81
84
 
82
85
  ## Reusing a configuration
83
86
 
package/dist/index.d.mts CHANGED
@@ -18,6 +18,7 @@ interface PetSayOptions {
18
18
  }
19
19
  interface PixelPetHandle {
20
20
  say: (message: React.ReactNode, options?: PetSayOptions) => void;
21
+ hush: () => void;
21
22
  }
22
23
  interface PixelPetProps {
23
24
  petName?: string;
@@ -29,6 +30,7 @@ interface PixelPetProps {
29
30
  messages?: PetMessages;
30
31
  dialogStyle?: DialogStyleProps;
31
32
  emotionDialogStyles?: Partial<Record<PetEmotion, DialogStyleProps>>;
33
+ onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
32
34
  ref?: React.Ref<PixelPetHandle>;
33
35
  }
34
36
  declare const PixelPet: React.FC<PixelPetProps>;
package/dist/index.d.ts CHANGED
@@ -18,6 +18,7 @@ interface PetSayOptions {
18
18
  }
19
19
  interface PixelPetHandle {
20
20
  say: (message: React.ReactNode, options?: PetSayOptions) => void;
21
+ hush: () => void;
21
22
  }
22
23
  interface PixelPetProps {
23
24
  petName?: string;
@@ -29,6 +30,7 @@ interface PixelPetProps {
29
30
  messages?: PetMessages;
30
31
  dialogStyle?: DialogStyleProps;
31
32
  emotionDialogStyles?: Partial<Record<PetEmotion, DialogStyleProps>>;
33
+ onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
32
34
  ref?: React.Ref<PixelPetHandle>;
33
35
  }
34
36
  declare const PixelPet: React.FC<PixelPetProps>;
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  'use client';
2
- "use strict";var G=Object.defineProperty;var Re=Object.getOwnPropertyDescriptor;var we=Object.getOwnPropertyNames;var ve=Object.prototype.hasOwnProperty;var Ce=(i,s)=>{for(var u in s)G(i,u,{get:s[u],enumerable:!0})},Me=(i,s,u,b)=>{if(s&&typeof s=="object"||typeof s=="function")for(let d of we(s))!ve.call(i,d)&&d!==u&&G(i,d,{get:()=>s[d],enumerable:!(b=Re(s,d))||b.enumerable});return i};var Se=i=>Me(G({},"__esModule",{value:!0}),i);var He={};Ce(He,{PixelPet:()=>Oe});module.exports=Se(He);var t=require("react");var r=require("react/jsx-runtime"),Z=["pointermove","pointerdown","keydown","wheel"],ne="(prefers-reduced-motion: reduce)",V=4,De=240,ee=5e3,te=65,oe=100,Ie=.04,Ae=100,Le=i=>{if(typeof window.matchMedia!="function")return()=>{};let s=window.matchMedia(ne);return s.addEventListener("change",i),()=>s.removeEventListener("change",i)},Ne=()=>typeof window.matchMedia=="function"&&window.matchMedia(ne).matches,Fe=()=>(0,t.useSyncExternalStore)(Le,Ne,()=>!1),We={happy:{backgroundColor:"#1e1c063d",borderColor:"#ffeb3b"},angry:{backgroundColor:"#21090833",borderColor:"#F04037"},curious:{backgroundColor:"#1f341d3a",borderColor:"#8BE383"}},_e={backgroundColor:"#05080cd9",borderColor:"var(--pixel-pet-color, #FDDBA0)"},Oe=({petName:i="Static",variant:s="cat",spriteSrc:u,color:b,label:d,walk:re=!0,messages:I,dialogStyle:g={},emotionDialogStyles:ie={},ref:se})=>{let[a,c]=(0,t.useState)("idle"),ae=Fe(),y=re&&!ae,A=(0,t.useRef)(null),v=(0,t.useRef)(null),Y=(0,t.useRef)(null),[L,le]=(0,t.useState)(null),[k,C]=(0,t.useState)(null),[pe,q]=(0,t.useState)(!1),[ce,Q]=(0,t.useState)(!1),[ue,de]=(0,t.useState)(!1),[x,fe]=(0,t.useState)(null),E=(0,t.useRef)(oe),[N,me]=(0,t.useState)(0),[F,ge]=(0,t.useState)("right"),xe={happy:I?.happy??(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("span",{className:"pixel-pet-highlight-pet",children:i})," is feeling"," ",(0,r.jsx)("span",{className:"pixel-pet-highlight-happy",children:"happy"}),"!"]}),angry:I?.angry??(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("span",{className:"pixel-pet-highlight-pet",children:i})," is feeling"," ",(0,r.jsx)("span",{className:"pixel-pet-highlight-angry",children:"overwhelmed"}),"!"]}),curious:I?.curious??(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("span",{className:"pixel-pet-highlight-pet",children:i})," is very"," ",(0,r.jsx)("span",{className:"pixel-pet-highlight-curious",children:"curious"})]})},K=(0,t.useRef)(a),M=(0,t.useRef)(null),P=(0,t.useRef)(!1),W=(0,t.useRef)(!1),p=(0,t.useRef)(null),j=(0,t.useRef)("happy"),_=(0,t.useRef)([]),T=(0,t.useRef)(!1),R=(0,t.useRef)(null),O=(0,t.useRef)(ee),H=(e,n=!1)=>{a==="sleep"&&c("idle"),j.current=e,C(e),de(n),p.current&&clearTimeout(p.current),p.current=setTimeout(()=>{W.current||C(null)},5e3)},S=e=>{T.current=e!==null,fe(e)},$=()=>{R.current&&clearTimeout(R.current)},J=e=>{$(),R.current=setTimeout(()=>S(null),e)};(0,t.useImperativeHandle)(se,()=>({say:(e,n={})=>{c(o=>o==="sleep"?"idle":o),S({message:e,emotion:n.emotion??null}),O.current=n.duration??ee,J(O.current)}}),[]),(0,t.useEffect)(()=>{let e,n=()=>{c(o=>o==="sleep"?"idle":o),clearTimeout(e),e=setTimeout(()=>{C(null),S(null),c("sleep")},12e4)};return Z.forEach(o=>{window.addEventListener(o,n,{passive:!0})}),n(),()=>{clearTimeout(e),Z.forEach(o=>{window.removeEventListener(o,n)})}},[]),(0,t.useEffect)(()=>{K.current=a},[a]),(0,t.useEffect)(()=>{let e=setInterval(()=>{if(K.current==="sleep"||T.current)return;let n=["happy","angry","curious"],o=n[Math.floor(Math.random()*n.length)];H(o)},3e4);return()=>{clearInterval(e)}},[]),(0,t.useEffect)(()=>()=>{p.current&&clearTimeout(p.current),R.current&&clearTimeout(R.current)},[]),(0,t.useEffect)(()=>{if(!(a==="sleep"||!y)){if(a==="walk"){let e=Math.floor(Math.random()*175001)+5e3;M.current=setTimeout(()=>{c("idle"),P.current=!0,setTimeout(()=>{P.current=!1},3e4)},e)}else{let e=()=>{if(!P.current&&Math.random()>.4){c("walk");return}M.current=setTimeout(e,5e3)};e()}return()=>{M.current&&clearTimeout(M.current)}}},[a,y]);let U=e=>{E.current=e,v.current&&(v.current.style.transform=`translateX(${e}px)`)};(0,t.useEffect)(()=>{if(a!=="walk"||k!==null||x!==null||!y)return;let e=0,n=N-te;if(n<=e)return;let o=0,l=null,m=w=>{let B=l===null?0:Math.min(w-l,Ae);l=w;let h=E.current+(F==="right"?1:-1)*Ie*B;if(h<=e||h>=n){if(Math.random()>.5){c("idle"),P.current=!0,setTimeout(()=>{P.current=!1},3e4);return}U(h<=e?e+2:n-2),ge(z=>z==="right"?"left":"right");return}U(h),o=requestAnimationFrame(m)};return o=requestAnimationFrame(m),()=>cancelAnimationFrame(o)},[a,k,x,F,y,N]),(0,t.useEffect)(()=>{let e=A.current;if(!e)return;let n=l=>{me(l),U(Math.max(Math.min(E.current,l-te),0))};if(n(e.clientWidth),typeof ResizeObserver>"u")return;let o=new ResizeObserver(([l])=>{l&&n(l.contentRect.width)});return o.observe(e),()=>o.disconnect()},[]);let he=()=>{let e=Date.now();a==="sleep"&&c("idle"),T.current&&($(),S(null));let n=[..._.current,e].filter(o=>e-o<=1e4);_.current=n,n.length>5?(_.current=[],H("angry",!0)):H(j.current,!0)},be=()=>{q(!0),T.current&&$(),k&&(W.current=!0,p.current&&clearTimeout(p.current))},ye=()=>{q(!1),T.current&&J(O.current),k&&(W.current=!1,p.current&&clearTimeout(p.current),p.current=setTimeout(()=>{C(null)},5e3))},D=x!==null&&a!=="sleep",f=a==="sleep"?null:D?x.emotion:k,X=D||f!==null&&(pe||ce||ue);(0,t.useLayoutEffect)(()=>{let e=A.current,n=v.current,o=Y.current;if(!X||!e||!n||!o)return;let l=e.clientWidth,m=Math.max(Math.min(De,l-V*2),0),w=Math.min(o.offsetWidth,m),B=E.current+n.offsetWidth/2,h=V,z=l-V-w,Pe=B-w/2,Te=Math.max(Math.min(Pe,z),h);le({left:Te-E.current,maxWidth:m})},[X,f,x,N]);let ke=()=>f?`pixel-pet-state-${f}`:(!y||D)&&a==="walk"?"pixel-pet-state-idle":`pixel-pet-state-${a}`,Ee=e=>{let n=e?We[e]:_e,o=e&&ie[e]||{},l=o.backgroundColor||g.backgroundColor||n.backgroundColor,m=o.borderColor||g.borderColor||n.borderColor;return{backgroundColor:l,color:o.textColor||g.textColor||"#ffffff",border:`${o.borderWidth||g.borderWidth||"1px"} solid ${m}`,borderRadius:o.borderRadius||g.borderRadius||"5px",fontFamily:o.fontFamily||g.fontFamily||"monospace"}};return(0,r.jsx)("div",{className:"pixel-pet",ref:A,style:b?{"--pixel-pet-color":b}:void 0,children:(0,r.jsxs)("div",{ref:v,className:"pixel-pet-container",style:{transform:`translateX(${oe}px)`},onMouseEnter:be,onMouseLeave:ye,children:[(0,r.jsx)("div",{className:"pixel-pet-status",role:"status",children:X&&(0,r.jsx)("div",{ref:Y,className:"pixel-pet-dialog",style:{...Ee(f),...L&&{left:L.left,maxWidth:L.maxWidth}},children:D?x.message:f&&xe[f]})}),(0,r.jsx)("button",{type:"button","aria-label":d??i,className:`pixel-pet-sprite pixel-pet-${s} ${ke()} ${F==="left"?"pixel-pet-flip-x":""}`,style:u?{backgroundImage:`url("${u}")`}:void 0,onClick:he,onFocus:()=>Q(!0),onBlur:()=>Q(!1)})]})})};0&&(module.exports={PixelPet});
2
+ "use strict";var G=Object.defineProperty;var ve=Object.getOwnPropertyDescriptor;var we=Object.getOwnPropertyNames;var Me=Object.prototype.hasOwnProperty;var Ce=(s,a)=>{for(var u in a)G(s,u,{get:a[u],enumerable:!0})},Se=(s,a,u,b)=>{if(a&&typeof a=="object"||typeof a=="function")for(let d of we(a))!Me.call(s,d)&&d!==u&&G(s,d,{get:()=>a[d],enumerable:!(b=ve(a,d))||b.enumerable});return s};var De=s=>Se(G({},"__esModule",{value:!0}),s);var $e={};Ce($e,{PixelPet:()=>Oe});module.exports=De($e);var t=require("react");var r=require("react/jsx-runtime"),Z=["pointermove","pointerdown","keydown","wheel"],ne="(prefers-reduced-motion: reduce)",V=4,Ie=240,ee=5e3,te=65,oe=100,Ae=.04,Le=100,Ne=s=>{if(typeof window.matchMedia!="function")return()=>{};let a=window.matchMedia(ne);return a.addEventListener("change",s),()=>a.removeEventListener("change",s)},Fe=()=>typeof window.matchMedia=="function"&&window.matchMedia(ne).matches,We=()=>(0,t.useSyncExternalStore)(Ne,Fe,()=>!1),_e={happy:{backgroundColor:"#1e1c063d",borderColor:"#ffeb3b"},angry:{backgroundColor:"#21090833",borderColor:"#F04037"},curious:{backgroundColor:"#1f341d3a",borderColor:"#8BE383"}},He={backgroundColor:"#05080cd9",borderColor:"var(--pixel-pet-color, #FDDBA0)"},Oe=({petName:s="Static",variant:a="cat",spriteSrc:u,color:b,label:d,walk:re=!0,messages:A,dialogStyle:g={},emotionDialogStyles:ie={},onClick:se,ref:ae})=>{let[l,c]=(0,t.useState)("idle"),le=We(),y=re&&!le,L=(0,t.useRef)(null),M=(0,t.useRef)(null),Y=(0,t.useRef)(null),[N,pe]=(0,t.useState)(null),[E,C]=(0,t.useState)(null),[ce,q]=(0,t.useState)(!1),[ue,Q]=(0,t.useState)(!1),[de,fe]=(0,t.useState)(!1),[x,me]=(0,t.useState)(null),k=(0,t.useRef)(oe),[F,ge]=(0,t.useState)(0),[W,xe]=(0,t.useState)("right"),he={happy:A?.happy??(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("span",{className:"pixel-pet-highlight-pet",children:s})," is feeling"," ",(0,r.jsx)("span",{className:"pixel-pet-highlight-happy",children:"happy"}),"!"]}),angry:A?.angry??(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("span",{className:"pixel-pet-highlight-pet",children:s})," is feeling"," ",(0,r.jsx)("span",{className:"pixel-pet-highlight-angry",children:"overwhelmed"}),"!"]}),curious:A?.curious??(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)("span",{className:"pixel-pet-highlight-pet",children:s})," is very"," ",(0,r.jsx)("span",{className:"pixel-pet-highlight-curious",children:"curious"})]})},K=(0,t.useRef)(l),S=(0,t.useRef)(null),P=(0,t.useRef)(!1),_=(0,t.useRef)(!1),p=(0,t.useRef)(null),j=(0,t.useRef)("happy"),H=(0,t.useRef)([]),T=(0,t.useRef)(!1),R=(0,t.useRef)(null),O=(0,t.useRef)(ee),$=(e,n=!1)=>{l==="sleep"&&c("idle"),j.current=e,C(e),fe(n),p.current&&clearTimeout(p.current),p.current=setTimeout(()=>{_.current||C(null)},5e3)},v=e=>{T.current=e!==null,me(e)},D=()=>{R.current&&clearTimeout(R.current)},J=e=>{D(),e!==1/0&&(R.current=setTimeout(()=>v(null),e))};(0,t.useImperativeHandle)(ae,()=>({say:(e,n={})=>{c(o=>o==="sleep"?"idle":o),v({message:e,emotion:n.emotion??null}),O.current=n.duration??ee,J(O.current)},hush:()=>{D(),v(null)}}),[]),(0,t.useEffect)(()=>{let e,n=()=>{c(o=>o==="sleep"?"idle":o),clearTimeout(e),e=setTimeout(()=>{C(null),v(null),c("sleep")},12e4)};return Z.forEach(o=>{window.addEventListener(o,n,{passive:!0})}),n(),()=>{clearTimeout(e),Z.forEach(o=>{window.removeEventListener(o,n)})}},[]),(0,t.useEffect)(()=>{K.current=l},[l]),(0,t.useEffect)(()=>{let e=setInterval(()=>{if(K.current==="sleep"||T.current)return;let n=["happy","angry","curious"],o=n[Math.floor(Math.random()*n.length)];$(o)},3e4);return()=>{clearInterval(e)}},[]),(0,t.useEffect)(()=>()=>{p.current&&clearTimeout(p.current),R.current&&clearTimeout(R.current)},[]),(0,t.useEffect)(()=>{if(!(l==="sleep"||!y)){if(l==="walk"){let e=Math.floor(Math.random()*175001)+5e3;S.current=setTimeout(()=>{c("idle"),P.current=!0,setTimeout(()=>{P.current=!1},3e4)},e)}else{let e=()=>{if(!P.current&&Math.random()>.4){c("walk");return}S.current=setTimeout(e,5e3)};e()}return()=>{S.current&&clearTimeout(S.current)}}},[l,y]);let B=e=>{k.current=e,M.current&&(M.current.style.transform=`translateX(${e}px)`)};(0,t.useEffect)(()=>{if(l!=="walk"||E!==null||x!==null||!y)return;let e=0,n=F-te;if(n<=e)return;let o=0,i=null,m=w=>{let X=i===null?0:Math.min(w-i,Le);i=w;let h=k.current+(W==="right"?1:-1)*Ae*X;if(h<=e||h>=n){if(Math.random()>.5){c("idle"),P.current=!0,setTimeout(()=>{P.current=!1},3e4);return}B(h<=e?e+2:n-2),xe(z=>z==="right"?"left":"right");return}B(h),o=requestAnimationFrame(m)};return o=requestAnimationFrame(m),()=>cancelAnimationFrame(o)},[l,E,x,W,y,F]),(0,t.useEffect)(()=>{let e=L.current;if(!e)return;let n=i=>{ge(i),B(Math.max(Math.min(k.current,i-te),0))};if(n(e.clientWidth),typeof ResizeObserver>"u")return;let o=new ResizeObserver(([i])=>{i&&n(i.contentRect.width)});return o.observe(e),()=>o.disconnect()},[]);let be=e=>{if(se?.(e),e.defaultPrevented)return;let n=Date.now();l==="sleep"&&c("idle"),T.current&&(D(),v(null));let o=[...H.current,n].filter(i=>n-i<=1e4);H.current=o,o.length>5?(H.current=[],$("angry",!0)):$(j.current,!0)},ye=()=>{q(!0),T.current&&D(),E&&(_.current=!0,p.current&&clearTimeout(p.current))},Ee=()=>{q(!1),T.current&&J(O.current),E&&(_.current=!1,p.current&&clearTimeout(p.current),p.current=setTimeout(()=>{C(null)},5e3))},I=x!==null&&l!=="sleep",f=l==="sleep"?null:I?x.emotion:E,U=I||f!==null&&(ce||ue||de);(0,t.useLayoutEffect)(()=>{let e=L.current,n=M.current,o=Y.current;if(!U||!e||!n||!o)return;let i=e.clientWidth,m=Math.max(Math.min(Ie,i-V*2),0),w=Math.min(o.offsetWidth,m),X=k.current+n.offsetWidth/2,h=V,z=i-V-w,Te=X-w/2,Re=Math.max(Math.min(Te,z),h);pe({left:Re-k.current,maxWidth:m})},[U,f,x,F]);let ke=()=>f?`pixel-pet-state-${f}`:(!y||I)&&l==="walk"?"pixel-pet-state-idle":`pixel-pet-state-${l}`,Pe=e=>{let n=e?_e[e]:He,o=e&&ie[e]||{},i=o.backgroundColor||g.backgroundColor||n.backgroundColor,m=o.borderColor||g.borderColor||n.borderColor;return{backgroundColor:i,color:o.textColor||g.textColor||"#ffffff",border:`${o.borderWidth||g.borderWidth||"1px"} solid ${m}`,borderRadius:o.borderRadius||g.borderRadius||"5px",fontFamily:o.fontFamily||g.fontFamily||"monospace"}};return(0,r.jsx)("div",{className:"pixel-pet",ref:L,style:b?{"--pixel-pet-color":b}:void 0,children:(0,r.jsxs)("div",{ref:M,className:"pixel-pet-container",style:{transform:`translateX(${oe}px)`},onMouseEnter:ye,onMouseLeave:Ee,children:[(0,r.jsx)("div",{className:"pixel-pet-status",role:"status",children:U&&(0,r.jsx)("div",{ref:Y,className:"pixel-pet-dialog",style:{...Pe(f),...N&&{left:N.left,maxWidth:N.maxWidth}},children:I?x.message:f&&he[f]})}),(0,r.jsx)("button",{type:"button","aria-label":d??s,className:`pixel-pet-sprite pixel-pet-${a} ${ke()} ${W==="left"?"pixel-pet-flip-x":""}`,style:u?{backgroundImage:`url("${u}")`}:void 0,onClick:be,onFocus:()=>Q(!0),onBlur:()=>Q(!1)})]})})};0&&(module.exports={PixelPet});
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
1
  'use client';
2
- import{useState as l,useEffect as f,useImperativeHandle as Ce,useLayoutEffect as Me,useRef as i,useSyncExternalStore as Se}from"react";import{Fragment as V,jsx as a,jsxs as D}from"react/jsx-runtime";var te=["pointermove","pointerdown","keydown","wheel"],ie="(prefers-reduced-motion: reduce)",G=4,De=240,oe=5e3,ne=65,re=100,Ie=.04,Ae=100,Le=c=>{if(typeof window.matchMedia!="function")return()=>{};let R=window.matchMedia(ie);return R.addEventListener("change",c),()=>R.removeEventListener("change",c)},Ne=()=>typeof window.matchMedia=="function"&&window.matchMedia(ie).matches,Fe=()=>Se(Le,Ne,()=>!1),We={happy:{backgroundColor:"#1e1c063d",borderColor:"#ffeb3b"},angry:{backgroundColor:"#21090833",borderColor:"#F04037"},curious:{backgroundColor:"#1f341d3a",borderColor:"#8BE383"}},_e={backgroundColor:"#05080cd9",borderColor:"var(--pixel-pet-color, #FDDBA0)"},ze=({petName:c="Static",variant:R="cat",spriteSrc:Y,color:q,label:se,walk:ae=!0,messages:I,dialogStyle:m={},emotionDialogStyles:le={},ref:pe})=>{let[n,p]=l("idle"),ce=Fe(),h=ae&&!ce,A=i(null),w=i(null),Q=i(null),[L,ue]=l(null),[b,v]=l(null),[de,K]=l(!1),[fe,j]=l(!1),[me,ge]=l(!1),[g,xe]=l(null),y=i(re),[N,he]=l(0),[F,be]=l("right"),ye={happy:I?.happy??D(V,{children:[a("span",{className:"pixel-pet-highlight-pet",children:c})," is feeling"," ",a("span",{className:"pixel-pet-highlight-happy",children:"happy"}),"!"]}),angry:I?.angry??D(V,{children:[a("span",{className:"pixel-pet-highlight-pet",children:c})," is feeling"," ",a("span",{className:"pixel-pet-highlight-angry",children:"overwhelmed"}),"!"]}),curious:I?.curious??D(V,{children:[a("span",{className:"pixel-pet-highlight-pet",children:c})," is very"," ",a("span",{className:"pixel-pet-highlight-curious",children:"curious"})]})},J=i(n),C=i(null),k=i(!1),W=i(!1),s=i(null),Z=i("happy"),_=i([]),E=i(!1),P=i(null),O=i(oe),H=(e,o=!1)=>{n==="sleep"&&p("idle"),Z.current=e,v(e),ge(o),s.current&&clearTimeout(s.current),s.current=setTimeout(()=>{W.current||v(null)},5e3)},M=e=>{E.current=e!==null,xe(e)},$=()=>{P.current&&clearTimeout(P.current)},ee=e=>{$(),P.current=setTimeout(()=>M(null),e)};Ce(pe,()=>({say:(e,o={})=>{p(t=>t==="sleep"?"idle":t),M({message:e,emotion:o.emotion??null}),O.current=o.duration??oe,ee(O.current)}}),[]),f(()=>{let e,o=()=>{p(t=>t==="sleep"?"idle":t),clearTimeout(e),e=setTimeout(()=>{v(null),M(null),p("sleep")},12e4)};return te.forEach(t=>{window.addEventListener(t,o,{passive:!0})}),o(),()=>{clearTimeout(e),te.forEach(t=>{window.removeEventListener(t,o)})}},[]),f(()=>{J.current=n},[n]),f(()=>{let e=setInterval(()=>{if(J.current==="sleep"||E.current)return;let o=["happy","angry","curious"],t=o[Math.floor(Math.random()*o.length)];H(t)},3e4);return()=>{clearInterval(e)}},[]),f(()=>()=>{s.current&&clearTimeout(s.current),P.current&&clearTimeout(P.current)},[]),f(()=>{if(!(n==="sleep"||!h)){if(n==="walk"){let e=Math.floor(Math.random()*175001)+5e3;C.current=setTimeout(()=>{p("idle"),k.current=!0,setTimeout(()=>{k.current=!1},3e4)},e)}else{let e=()=>{if(!k.current&&Math.random()>.4){p("walk");return}C.current=setTimeout(e,5e3)};e()}return()=>{C.current&&clearTimeout(C.current)}}},[n,h]);let U=e=>{y.current=e,w.current&&(w.current.style.transform=`translateX(${e}px)`)};f(()=>{if(n!=="walk"||b!==null||g!==null||!h)return;let e=0,o=N-ne;if(o<=e)return;let t=0,r=null,d=T=>{let B=r===null?0:Math.min(T-r,Ae);r=T;let x=y.current+(F==="right"?1:-1)*Ie*B;if(x<=e||x>=o){if(Math.random()>.5){p("idle"),k.current=!0,setTimeout(()=>{k.current=!1},3e4);return}U(x<=e?e+2:o-2),be(z=>z==="right"?"left":"right");return}U(x),t=requestAnimationFrame(d)};return t=requestAnimationFrame(d),()=>cancelAnimationFrame(t)},[n,b,g,F,h,N]),f(()=>{let e=A.current;if(!e)return;let o=r=>{he(r),U(Math.max(Math.min(y.current,r-ne),0))};if(o(e.clientWidth),typeof ResizeObserver>"u")return;let t=new ResizeObserver(([r])=>{r&&o(r.contentRect.width)});return t.observe(e),()=>t.disconnect()},[]);let ke=()=>{let e=Date.now();n==="sleep"&&p("idle"),E.current&&($(),M(null));let o=[..._.current,e].filter(t=>e-t<=1e4);_.current=o,o.length>5?(_.current=[],H("angry",!0)):H(Z.current,!0)},Ee=()=>{K(!0),E.current&&$(),b&&(W.current=!0,s.current&&clearTimeout(s.current))},Pe=()=>{K(!1),E.current&&ee(O.current),b&&(W.current=!1,s.current&&clearTimeout(s.current),s.current=setTimeout(()=>{v(null)},5e3))},S=g!==null&&n!=="sleep",u=n==="sleep"?null:S?g.emotion:b,X=S||u!==null&&(de||fe||me);Me(()=>{let e=A.current,o=w.current,t=Q.current;if(!X||!e||!o||!t)return;let r=e.clientWidth,d=Math.max(Math.min(De,r-G*2),0),T=Math.min(t.offsetWidth,d),B=y.current+o.offsetWidth/2,x=G,z=r-G-T,we=B-T/2,ve=Math.max(Math.min(we,z),x);ue({left:ve-y.current,maxWidth:d})},[X,u,g,N]);let Te=()=>u?`pixel-pet-state-${u}`:(!h||S)&&n==="walk"?"pixel-pet-state-idle":`pixel-pet-state-${n}`,Re=e=>{let o=e?We[e]:_e,t=e&&le[e]||{},r=t.backgroundColor||m.backgroundColor||o.backgroundColor,d=t.borderColor||m.borderColor||o.borderColor;return{backgroundColor:r,color:t.textColor||m.textColor||"#ffffff",border:`${t.borderWidth||m.borderWidth||"1px"} solid ${d}`,borderRadius:t.borderRadius||m.borderRadius||"5px",fontFamily:t.fontFamily||m.fontFamily||"monospace"}};return a("div",{className:"pixel-pet",ref:A,style:q?{"--pixel-pet-color":q}:void 0,children:D("div",{ref:w,className:"pixel-pet-container",style:{transform:`translateX(${re}px)`},onMouseEnter:Ee,onMouseLeave:Pe,children:[a("div",{className:"pixel-pet-status",role:"status",children:X&&a("div",{ref:Q,className:"pixel-pet-dialog",style:{...Re(u),...L&&{left:L.left,maxWidth:L.maxWidth}},children:S?g.message:u&&ye[u]})}),a("button",{type:"button","aria-label":se??c,className:`pixel-pet-sprite pixel-pet-${R} ${Te()} ${F==="left"?"pixel-pet-flip-x":""}`,style:Y?{backgroundImage:`url("${Y}")`}:void 0,onClick:ke,onFocus:()=>j(!0),onBlur:()=>j(!1)})]})})};export{ze as PixelPet};
2
+ import{useState as l,useEffect as f,useImperativeHandle as Ce,useLayoutEffect as Se,useRef as i,useSyncExternalStore as De}from"react";import{Fragment as V,jsx as a,jsxs as I}from"react/jsx-runtime";var te=["pointermove","pointerdown","keydown","wheel"],ie="(prefers-reduced-motion: reduce)",G=4,Ie=240,oe=5e3,ne=65,re=100,Ae=.04,Le=100,Ne=c=>{if(typeof window.matchMedia!="function")return()=>{};let v=window.matchMedia(ie);return v.addEventListener("change",c),()=>v.removeEventListener("change",c)},Fe=()=>typeof window.matchMedia=="function"&&window.matchMedia(ie).matches,We=()=>De(Ne,Fe,()=>!1),_e={happy:{backgroundColor:"#1e1c063d",borderColor:"#ffeb3b"},angry:{backgroundColor:"#21090833",borderColor:"#F04037"},curious:{backgroundColor:"#1f341d3a",borderColor:"#8BE383"}},He={backgroundColor:"#05080cd9",borderColor:"var(--pixel-pet-color, #FDDBA0)"},Ge=({petName:c="Static",variant:v="cat",spriteSrc:Y,color:q,label:se,walk:ae=!0,messages:A,dialogStyle:m={},emotionDialogStyles:le={},onClick:pe,ref:ce})=>{let[r,p]=l("idle"),ue=We(),h=ae&&!ue,L=i(null),w=i(null),Q=i(null),[N,de]=l(null),[b,M]=l(null),[fe,K]=l(!1),[me,j]=l(!1),[ge,xe]=l(!1),[g,he]=l(null),y=i(re),[F,be]=l(0),[W,ye]=l("right"),Ee={happy:A?.happy??I(V,{children:[a("span",{className:"pixel-pet-highlight-pet",children:c})," is feeling"," ",a("span",{className:"pixel-pet-highlight-happy",children:"happy"}),"!"]}),angry:A?.angry??I(V,{children:[a("span",{className:"pixel-pet-highlight-pet",children:c})," is feeling"," ",a("span",{className:"pixel-pet-highlight-angry",children:"overwhelmed"}),"!"]}),curious:A?.curious??I(V,{children:[a("span",{className:"pixel-pet-highlight-pet",children:c})," is very"," ",a("span",{className:"pixel-pet-highlight-curious",children:"curious"})]})},J=i(r),C=i(null),E=i(!1),_=i(!1),s=i(null),Z=i("happy"),H=i([]),k=i(!1),P=i(null),O=i(oe),$=(e,o=!1)=>{r==="sleep"&&p("idle"),Z.current=e,M(e),xe(o),s.current&&clearTimeout(s.current),s.current=setTimeout(()=>{_.current||M(null)},5e3)},T=e=>{k.current=e!==null,he(e)},S=()=>{P.current&&clearTimeout(P.current)},ee=e=>{S(),e!==1/0&&(P.current=setTimeout(()=>T(null),e))};Ce(ce,()=>({say:(e,o={})=>{p(t=>t==="sleep"?"idle":t),T({message:e,emotion:o.emotion??null}),O.current=o.duration??oe,ee(O.current)},hush:()=>{S(),T(null)}}),[]),f(()=>{let e,o=()=>{p(t=>t==="sleep"?"idle":t),clearTimeout(e),e=setTimeout(()=>{M(null),T(null),p("sleep")},12e4)};return te.forEach(t=>{window.addEventListener(t,o,{passive:!0})}),o(),()=>{clearTimeout(e),te.forEach(t=>{window.removeEventListener(t,o)})}},[]),f(()=>{J.current=r},[r]),f(()=>{let e=setInterval(()=>{if(J.current==="sleep"||k.current)return;let o=["happy","angry","curious"],t=o[Math.floor(Math.random()*o.length)];$(t)},3e4);return()=>{clearInterval(e)}},[]),f(()=>()=>{s.current&&clearTimeout(s.current),P.current&&clearTimeout(P.current)},[]),f(()=>{if(!(r==="sleep"||!h)){if(r==="walk"){let e=Math.floor(Math.random()*175001)+5e3;C.current=setTimeout(()=>{p("idle"),E.current=!0,setTimeout(()=>{E.current=!1},3e4)},e)}else{let e=()=>{if(!E.current&&Math.random()>.4){p("walk");return}C.current=setTimeout(e,5e3)};e()}return()=>{C.current&&clearTimeout(C.current)}}},[r,h]);let B=e=>{y.current=e,w.current&&(w.current.style.transform=`translateX(${e}px)`)};f(()=>{if(r!=="walk"||b!==null||g!==null||!h)return;let e=0,o=F-ne;if(o<=e)return;let t=0,n=null,d=R=>{let X=n===null?0:Math.min(R-n,Le);n=R;let x=y.current+(W==="right"?1:-1)*Ae*X;if(x<=e||x>=o){if(Math.random()>.5){p("idle"),E.current=!0,setTimeout(()=>{E.current=!1},3e4);return}B(x<=e?e+2:o-2),ye(z=>z==="right"?"left":"right");return}B(x),t=requestAnimationFrame(d)};return t=requestAnimationFrame(d),()=>cancelAnimationFrame(t)},[r,b,g,W,h,F]),f(()=>{let e=L.current;if(!e)return;let o=n=>{be(n),B(Math.max(Math.min(y.current,n-ne),0))};if(o(e.clientWidth),typeof ResizeObserver>"u")return;let t=new ResizeObserver(([n])=>{n&&o(n.contentRect.width)});return t.observe(e),()=>t.disconnect()},[]);let ke=e=>{if(pe?.(e),e.defaultPrevented)return;let o=Date.now();r==="sleep"&&p("idle"),k.current&&(S(),T(null));let t=[...H.current,o].filter(n=>o-n<=1e4);H.current=t,t.length>5?(H.current=[],$("angry",!0)):$(Z.current,!0)},Pe=()=>{K(!0),k.current&&S(),b&&(_.current=!0,s.current&&clearTimeout(s.current))},Te=()=>{K(!1),k.current&&ee(O.current),b&&(_.current=!1,s.current&&clearTimeout(s.current),s.current=setTimeout(()=>{M(null)},5e3))},D=g!==null&&r!=="sleep",u=r==="sleep"?null:D?g.emotion:b,U=D||u!==null&&(fe||me||ge);Se(()=>{let e=L.current,o=w.current,t=Q.current;if(!U||!e||!o||!t)return;let n=e.clientWidth,d=Math.max(Math.min(Ie,n-G*2),0),R=Math.min(t.offsetWidth,d),X=y.current+o.offsetWidth/2,x=G,z=n-G-R,we=X-R/2,Me=Math.max(Math.min(we,z),x);de({left:Me-y.current,maxWidth:d})},[U,u,g,F]);let Re=()=>u?`pixel-pet-state-${u}`:(!h||D)&&r==="walk"?"pixel-pet-state-idle":`pixel-pet-state-${r}`,ve=e=>{let o=e?_e[e]:He,t=e&&le[e]||{},n=t.backgroundColor||m.backgroundColor||o.backgroundColor,d=t.borderColor||m.borderColor||o.borderColor;return{backgroundColor:n,color:t.textColor||m.textColor||"#ffffff",border:`${t.borderWidth||m.borderWidth||"1px"} solid ${d}`,borderRadius:t.borderRadius||m.borderRadius||"5px",fontFamily:t.fontFamily||m.fontFamily||"monospace"}};return a("div",{className:"pixel-pet",ref:L,style:q?{"--pixel-pet-color":q}:void 0,children:I("div",{ref:w,className:"pixel-pet-container",style:{transform:`translateX(${re}px)`},onMouseEnter:Pe,onMouseLeave:Te,children:[a("div",{className:"pixel-pet-status",role:"status",children:U&&a("div",{ref:Q,className:"pixel-pet-dialog",style:{...ve(u),...N&&{left:N.left,maxWidth:N.maxWidth}},children:D?g.message:u&&Ee[u]})}),a("button",{type:"button","aria-label":se??c,className:`pixel-pet-sprite pixel-pet-${v} ${Re()} ${W==="left"?"pixel-pet-flip-x":""}`,style:Y?{backgroundImage:`url("${Y}")`}:void 0,onClick:ke,onFocus:()=>j(!0),onBlur:()=>j(!1)})]})})};export{Ge as PixelPet};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vrixton/pixel-pet",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "A pixel art pet for React that walks, sleeps, reacts to clicks, and speaks on demand.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",