@vrixton/pixel-pet 0.1.0 → 0.2.1
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 +15 -14
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
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
|
-
| `
|
|
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
|
|
|
@@ -98,25 +101,23 @@ const danko: PixelPetProps = {
|
|
|
98
101
|
|
|
99
102
|
## Translating the messages
|
|
100
103
|
|
|
101
|
-
|
|
104
|
+
Messages can be plain strings with two markers, so they fit in translation files as they are:
|
|
102
105
|
|
|
103
106
|
```tsx
|
|
104
107
|
<PixelPet
|
|
105
108
|
petName="Danko"
|
|
109
|
+
label="{name}, the pet"
|
|
106
110
|
messages={{
|
|
107
|
-
happy:
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
<span className="pixel-pet-highlight-happy">feliz</span>.
|
|
111
|
-
</>
|
|
112
|
-
),
|
|
113
|
-
angry: 'Danko está abrumado.',
|
|
114
|
-
curious: 'Danko tiene mucha curiosidad.',
|
|
111
|
+
happy: '{name} está **feliz**.',
|
|
112
|
+
angry: '{name} está **abrumado**.',
|
|
113
|
+
curious: '{name} tiene mucha **curiosidad**.',
|
|
115
114
|
}}
|
|
116
115
|
/>
|
|
117
116
|
```
|
|
118
117
|
|
|
119
|
-
The
|
|
118
|
+
`{name}` becomes the pet's name in its color, and `**word**` shows that word in the color of the emotion. The markers also work in `say()`: there, `**word**` takes the color of the requested emotion, or the pet's color when there is none. In `label`, which screen readers read aloud, only `{name}` is replaced. Any emotion you leave out keeps its English message.
|
|
119
|
+
|
|
120
|
+
Messages can also be any React node when you need more control. The highlight classes are `pixel-pet-highlight-pet`, `pixel-pet-highlight-happy`, `pixel-pet-highlight-angry`, and `pixel-pet-highlight-curious`.
|
|
120
121
|
|
|
121
122
|
## Styling the bubble
|
|
122
123
|
|
|
@@ -128,7 +129,7 @@ The highlight classes are `pixel-pet-highlight-pet`, `pixel-pet-highlight-happy`
|
|
|
128
129
|
| `textColor` | `'#ffffff'` |
|
|
129
130
|
| `borderColor` | Depends on the emotion |
|
|
130
131
|
| `borderWidth` | `'1px'` |
|
|
131
|
-
| `borderRadius` | `'
|
|
132
|
+
| `borderRadius` | `'0'` |
|
|
132
133
|
| `fontFamily` | `'monospace'` |
|
|
133
134
|
|
|
134
135
|
A field set in `emotionDialogStyles` wins over the same field in `dialogStyle`, which wins over the default. Messages from `say()` without an emotion use `dialogStyle`.
|
|
@@ -141,7 +142,7 @@ A sheet passed through `spriteSrc` has to follow the same layout as the bundled
|
|
|
141
142
|
|
|
142
143
|
## How it behaves
|
|
143
144
|
|
|
144
|
-
The pet wanders on its own, sometimes walking and sometimes standing, and turns around at the edges of the container. Every 30 seconds it may switch to a random mood for 5 seconds; hovering over it or focusing it with the keyboard shows what it's feeling. Clicking it shows its last mood, and clicking it more than five times in ten seconds makes it angry. After two minutes without mouse, touch, keyboard, or scroll wheel activity on the page, it falls asleep, and any activity wakes it up.
|
|
145
|
+
The pet wanders on its own, sometimes walking and sometimes standing, and turns around at the edges of the container. Every 30 seconds it may switch to a random mood for 5 seconds; hovering over it or focusing it with the keyboard shows what it's feeling. Clicking it shows its last mood for three seconds, and clicking it more than five times in ten seconds makes it angry. After a click, the bubble stays hidden while the pointer rests on the pet; moving the pointer away and back shows it again. After two minutes without mouse, touch, keyboard, or scroll wheel activity on the page, it falls asleep, and any activity wakes it up.
|
|
145
146
|
|
|
146
147
|
The pet is a real button, so it can be reached with the keyboard, has a visible focus outline, and is announced with its name. When the user prefers reduced motion, it stays still, its animation pauses, and the bubble appears without its pop-in effect.
|
|
147
148
|
|
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
|
|
2
|
+
"use strict";var Y=Object.defineProperty;var De=Object.getOwnPropertyDescriptor;var Ae=Object.getOwnPropertyNames;var Ie=Object.prototype.hasOwnProperty;var Le=(i,s)=>{for(var u in s)Y(i,u,{get:s[u],enumerable:!0})},_e=(i,s,u,b)=>{if(s&&typeof s=="object"||typeof s=="function")for(let d of Ae(s))!Ie.call(i,d)&&d!==u&&Y(i,d,{get:()=>s[d],enumerable:!(b=De(s,d))||b.enumerable});return i};var Fe=i=>_e(Y({},"__esModule",{value:!0}),i);var Ye={};Le(Ye,{PixelPet:()=>Ve});module.exports=Fe(Ye);var t=require("react");var c=require("react/jsx-runtime"),re=["pointermove","pointerdown","keydown","wheel"],le="(prefers-reduced-motion: reduce)",K=4,Ne=240,ie=5e3,We=3e3,He=/(\{name\}|\*\*[^*]+\*\*)/,q={happy:"{name} is feeling **happy**!",angry:"{name} is feeling **overwhelmed**!",curious:"{name} is very **curious**"},se=65,ae=100,Oe=.04,Be=100,Ue=i=>{if(typeof window.matchMedia!="function")return()=>{};let s=window.matchMedia(le);return s.addEventListener("change",i),()=>s.removeEventListener("change",i)},$e=()=>typeof window.matchMedia=="function"&&window.matchMedia(le).matches,Xe=()=>(0,t.useSyncExternalStore)(Ue,$e,()=>!1),Ge={happy:{backgroundColor:"#1e1c06eb",borderColor:"#ffeb3b"},angry:{backgroundColor:"#210908eb",borderColor:"#F04037"},curious:{backgroundColor:"#1f341deb",borderColor:"#8BE383"}},ze={backgroundColor:"#05080ceb",borderColor:"var(--pixel-pet-color, #FDDBA0)"},Ve=({petName:i="Static",variant:s="cat",spriteSrc:u,color:b,label:d,walk:ce=!0,messages:F,dialogStyle:x={},emotionDialogStyles:pe={},onClick:ue,ref:de})=>{let[a,p]=(0,t.useState)("idle"),fe=Xe(),y=ce&&!fe,N=(0,t.useRef)(null),C=(0,t.useRef)(null),Q=(0,t.useRef)(null),[W,me]=(0,t.useState)(null),[E,S]=(0,t.useState)(null),[ge,j]=(0,t.useState)(!1),[xe,J]=(0,t.useState)(!1),[he,Z]=(0,t.useState)(!1),[be,ee]=(0,t.useState)(!1),[f,ye]=(0,t.useState)(null),R=(0,t.useRef)(ae),[H,Ee]=(0,t.useState)(0),[O,Re]=(0,t.useState)("right"),D=(e,n)=>typeof e!="string"?e:e.split(He).map((o,r)=>r%2===0?o:o==="{name}"?(0,c.jsx)("span",{className:"pixel-pet-highlight-pet",children:i},r):(0,c.jsx)("span",{className:`pixel-pet-highlight-${n??"pet"}`,children:o.slice(2,-2)},r)),Te={happy:D(F?.happy??q.happy,"happy"),angry:D(F?.angry??q.angry,"angry"),curious:D(F?.curious??q.curious,"curious")},te=(0,t.useRef)(a),A=(0,t.useRef)(null),T=(0,t.useRef)(!1),I=(0,t.useRef)(!1),l=(0,t.useRef)(null),oe=(0,t.useRef)("happy"),B=(0,t.useRef)([]),k=(0,t.useRef)(null),P=(0,t.useRef)(!1),v=(0,t.useRef)(null),U=(0,t.useRef)(ie),$=(e,n=!1)=>{a==="sleep"&&p("idle"),oe.current=e,S(e),Z(n),l.current&&clearTimeout(l.current),l.current=setTimeout(()=>{I.current||S(null)},5e3)},M=e=>{P.current=e!==null,ye(e)},L=()=>{v.current&&clearTimeout(v.current)},ne=e=>{L(),e!==1/0&&(v.current=setTimeout(()=>M(null),e))};(0,t.useImperativeHandle)(de,()=>({say:(e,n={})=>{p(o=>o==="sleep"?"idle":o),M({message:e,emotion:n.emotion??null}),U.current=n.duration??ie,ne(U.current)},hush:()=>{L(),M(null)}}),[]),(0,t.useEffect)(()=>{let e,n=()=>{p(o=>o==="sleep"?"idle":o),clearTimeout(e),e=setTimeout(()=>{S(null),M(null),p("sleep")},12e4)};return re.forEach(o=>{window.addEventListener(o,n,{passive:!0})}),n(),()=>{clearTimeout(e),re.forEach(o=>{window.removeEventListener(o,n)})}},[]),(0,t.useEffect)(()=>{te.current=a},[a]),(0,t.useEffect)(()=>{let e=setInterval(()=>{if(te.current==="sleep"||P.current)return;let n=["happy","angry","curious"],o=n[Math.floor(Math.random()*n.length)];$(o)},3e4);return()=>{clearInterval(e)}},[]),(0,t.useEffect)(()=>()=>{l.current&&clearTimeout(l.current),v.current&&clearTimeout(v.current),k.current&&clearTimeout(k.current)},[]),(0,t.useEffect)(()=>{if(!(a==="sleep"||!y)){if(a==="walk"){let e=Math.floor(Math.random()*175001)+5e3;A.current=setTimeout(()=>{p("idle"),T.current=!0,setTimeout(()=>{T.current=!1},3e4)},e)}else{let e=()=>{if(!T.current&&Math.random()>.4){p("walk");return}A.current=setTimeout(e,5e3)};e()}return()=>{A.current&&clearTimeout(A.current)}}},[a,y]);let X=e=>{R.current=e,C.current&&(C.current.style.transform=`translateX(${e}px)`)};(0,t.useEffect)(()=>{if(a!=="walk"||E!==null||f!==null||!y)return;let e=0,n=H-se;if(n<=e)return;let o=0,r=null,g=w=>{let z=r===null?0:Math.min(w-r,Be);r=w;let h=R.current+(O==="right"?1:-1)*Oe*z;if(h<=e||h>=n){if(Math.random()>.5){p("idle"),T.current=!0,setTimeout(()=>{T.current=!1},3e4);return}X(h<=e?e+2:n-2),Re(V=>V==="right"?"left":"right");return}X(h),o=requestAnimationFrame(g)};return o=requestAnimationFrame(g),()=>cancelAnimationFrame(o)},[a,E,f,O,y,H]),(0,t.useEffect)(()=>{let e=N.current;if(!e)return;let n=r=>{Ee(r),X(Math.max(Math.min(R.current,r-se),0))};if(n(e.clientWidth),typeof ResizeObserver>"u")return;let o=new ResizeObserver(([r])=>{r&&n(r.contentRect.width)});return o.observe(e),()=>o.disconnect()},[]);let ke=e=>{if(ue?.(e),e.defaultPrevented)return;let n=Date.now();a==="sleep"&&p("idle"),P.current&&(L(),M(null)),I.current=!1,ee(!0),k.current&&clearTimeout(k.current),k.current=setTimeout(()=>Z(!1),We);let o=[...B.current,n].filter(r=>n-r<=1e4);B.current=o,o.length>5?(B.current=[],$("angry",!0)):$(oe.current,!0)},Pe=()=>{j(!0),P.current&&L(),E&&(I.current=!0,l.current&&clearTimeout(l.current))},ve=()=>{j(!1),ee(!1),P.current&&ne(U.current),E&&(I.current=!1,l.current&&clearTimeout(l.current),l.current=setTimeout(()=>{S(null)},5e3))},_=f!==null&&a!=="sleep",m=a==="sleep"?null:_?f.emotion:E,G=_||m!==null&&(ge&&!be||xe||he);(0,t.useLayoutEffect)(()=>{let e=N.current,n=C.current,o=Q.current;if(!G||!e||!n||!o)return;let r=e.clientWidth,g=Math.max(Math.min(Ne,r-K*2),0),w=Math.min(o.offsetWidth,g),z=R.current+n.offsetWidth/2,h=K,V=r-K-w,Ce=z-w/2,Se=Math.max(Math.min(Ce,V),h);me({left:Se-R.current,maxWidth:g})},[G,m,f,H]);let Me=()=>m?`pixel-pet-state-${m}`:(!y||_)&&a==="walk"?"pixel-pet-state-idle":`pixel-pet-state-${a}`,we=e=>{let n=e?Ge[e]:ze,o=e&&pe[e]||{},r=o.backgroundColor||x.backgroundColor||n.backgroundColor,g=o.borderColor||x.borderColor||n.borderColor;return{backgroundColor:r,color:o.textColor||x.textColor||"#ffffff",border:`${o.borderWidth||x.borderWidth||"1px"} solid ${g}`,borderRadius:o.borderRadius||x.borderRadius||"0",fontFamily:o.fontFamily||x.fontFamily||"monospace"}};return(0,c.jsx)("div",{className:"pixel-pet",ref:N,style:b?{"--pixel-pet-color":b}:void 0,children:(0,c.jsxs)("div",{ref:C,className:"pixel-pet-container",style:{transform:`translateX(${ae}px)`},onMouseEnter:Pe,onMouseLeave:ve,children:[(0,c.jsx)("div",{className:"pixel-pet-status",role:"status",children:G&&(0,c.jsx)("div",{ref:Q,className:"pixel-pet-dialog",style:{...we(m),...W&&{left:W.left,maxWidth:W.maxWidth}},children:_?D(f.message,f.emotion):m&&Te[m]})}),(0,c.jsx)("button",{type:"button","aria-label":(d??i).split("{name}").join(i),className:`pixel-pet-sprite pixel-pet-${s} ${Me()} ${O==="left"?"pixel-pet-flip-x":""}`,style:u?{backgroundImage:`url("${u}")`}:void 0,onClick:ke,onFocus:e=>J(e.currentTarget.matches(":focus-visible")),onBlur:()=>J(!1)})]})})};0&&(module.exports={PixelPet});
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import{useState as
|
|
2
|
+
import{useState as a,useEffect as d,useImperativeHandle as Ae,useLayoutEffect as Ie,useRef as r,useSyncExternalStore as Le}from"react";import{jsx as x,jsxs as Ge}from"react/jsx-runtime";var re=["pointermove","pointerdown","keydown","wheel"],le="(prefers-reduced-motion: reduce)",V=4,_e=240,ie=5e3,Fe=3e3,Ne=/(\{name\}|\*\*[^*]+\*\*)/,Y={happy:"{name} is feeling **happy**!",angry:"{name} is feeling **overwhelmed**!",curious:"{name} is very **curious**"},se=65,ae=100,We=.04,He=100,Oe=f=>{if(typeof window.matchMedia!="function")return()=>{};let M=window.matchMedia(le);return M.addEventListener("change",f),()=>M.removeEventListener("change",f)},Be=()=>typeof window.matchMedia=="function"&&window.matchMedia(le).matches,Ue=()=>Le(Oe,Be,()=>!1),$e={happy:{backgroundColor:"#1e1c06eb",borderColor:"#ffeb3b"},angry:{backgroundColor:"#210908eb",borderColor:"#F04037"},curious:{backgroundColor:"#1f341deb",borderColor:"#8BE383"}},Xe={backgroundColor:"#05080ceb",borderColor:"var(--pixel-pet-color, #FDDBA0)"},je=({petName:f="Static",variant:M="cat",spriteSrc:K,color:q,label:ce,walk:pe=!0,messages:_,dialogStyle:m={},emotionDialogStyles:ue={},onClick:de,ref:fe})=>{let[i,l]=a("idle"),me=Ue(),h=pe&&!me,F=r(null),w=r(null),Q=r(null),[N,ge]=a(null),[b,C]=a(null),[xe,j]=a(!1),[he,J]=a(!1),[be,Z]=a(!1),[ye,ee]=a(!1),[c,Ee]=a(null),y=r(ae),[W,Re]=a(0),[H,Te]=a("right"),S=(e,o)=>typeof e!="string"?e:e.split(Ne).map((t,n)=>n%2===0?t:t==="{name}"?x("span",{className:"pixel-pet-highlight-pet",children:f},n):x("span",{className:`pixel-pet-highlight-${o??"pet"}`,children:t.slice(2,-2)},n)),ke={happy:S(_?.happy??Y.happy,"happy"),angry:S(_?.angry??Y.angry,"angry"),curious:S(_?.curious??Y.curious,"curious")},te=r(i),D=r(null),E=r(!1),A=r(!1),s=r(null),oe=r("happy"),O=r([]),R=r(null),T=r(!1),k=r(null),B=r(ie),U=(e,o=!1)=>{i==="sleep"&&l("idle"),oe.current=e,C(e),Z(o),s.current&&clearTimeout(s.current),s.current=setTimeout(()=>{A.current||C(null)},5e3)},P=e=>{T.current=e!==null,Ee(e)},I=()=>{k.current&&clearTimeout(k.current)},ne=e=>{I(),e!==1/0&&(k.current=setTimeout(()=>P(null),e))};Ae(fe,()=>({say:(e,o={})=>{l(t=>t==="sleep"?"idle":t),P({message:e,emotion:o.emotion??null}),B.current=o.duration??ie,ne(B.current)},hush:()=>{I(),P(null)}}),[]),d(()=>{let e,o=()=>{l(t=>t==="sleep"?"idle":t),clearTimeout(e),e=setTimeout(()=>{C(null),P(null),l("sleep")},12e4)};return re.forEach(t=>{window.addEventListener(t,o,{passive:!0})}),o(),()=>{clearTimeout(e),re.forEach(t=>{window.removeEventListener(t,o)})}},[]),d(()=>{te.current=i},[i]),d(()=>{let e=setInterval(()=>{if(te.current==="sleep"||T.current)return;let o=["happy","angry","curious"],t=o[Math.floor(Math.random()*o.length)];U(t)},3e4);return()=>{clearInterval(e)}},[]),d(()=>()=>{s.current&&clearTimeout(s.current),k.current&&clearTimeout(k.current),R.current&&clearTimeout(R.current)},[]),d(()=>{if(!(i==="sleep"||!h)){if(i==="walk"){let e=Math.floor(Math.random()*175001)+5e3;D.current=setTimeout(()=>{l("idle"),E.current=!0,setTimeout(()=>{E.current=!1},3e4)},e)}else{let e=()=>{if(!E.current&&Math.random()>.4){l("walk");return}D.current=setTimeout(e,5e3)};e()}return()=>{D.current&&clearTimeout(D.current)}}},[i,h]);let $=e=>{y.current=e,w.current&&(w.current.style.transform=`translateX(${e}px)`)};d(()=>{if(i!=="walk"||b!==null||c!==null||!h)return;let e=0,o=W-se;if(o<=e)return;let t=0,n=null,u=v=>{let G=n===null?0:Math.min(v-n,He);n=v;let g=y.current+(H==="right"?1:-1)*We*G;if(g<=e||g>=o){if(Math.random()>.5){l("idle"),E.current=!0,setTimeout(()=>{E.current=!1},3e4);return}$(g<=e?e+2:o-2),Te(z=>z==="right"?"left":"right");return}$(g),t=requestAnimationFrame(u)};return t=requestAnimationFrame(u),()=>cancelAnimationFrame(t)},[i,b,c,H,h,W]),d(()=>{let e=F.current;if(!e)return;let o=n=>{Re(n),$(Math.max(Math.min(y.current,n-se),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 Pe=e=>{if(de?.(e),e.defaultPrevented)return;let o=Date.now();i==="sleep"&&l("idle"),T.current&&(I(),P(null)),A.current=!1,ee(!0),R.current&&clearTimeout(R.current),R.current=setTimeout(()=>Z(!1),Fe);let t=[...O.current,o].filter(n=>o-n<=1e4);O.current=t,t.length>5?(O.current=[],U("angry",!0)):U(oe.current,!0)},ve=()=>{j(!0),T.current&&I(),b&&(A.current=!0,s.current&&clearTimeout(s.current))},Me=()=>{j(!1),ee(!1),T.current&&ne(B.current),b&&(A.current=!1,s.current&&clearTimeout(s.current),s.current=setTimeout(()=>{C(null)},5e3))},L=c!==null&&i!=="sleep",p=i==="sleep"?null:L?c.emotion:b,X=L||p!==null&&(xe&&!ye||he||be);Ie(()=>{let e=F.current,o=w.current,t=Q.current;if(!X||!e||!o||!t)return;let n=e.clientWidth,u=Math.max(Math.min(_e,n-V*2),0),v=Math.min(t.offsetWidth,u),G=y.current+o.offsetWidth/2,g=V,z=n-V-v,Se=G-v/2,De=Math.max(Math.min(Se,z),g);ge({left:De-y.current,maxWidth:u})},[X,p,c,W]);let we=()=>p?`pixel-pet-state-${p}`:(!h||L)&&i==="walk"?"pixel-pet-state-idle":`pixel-pet-state-${i}`,Ce=e=>{let o=e?$e[e]:Xe,t=e&&ue[e]||{},n=t.backgroundColor||m.backgroundColor||o.backgroundColor,u=t.borderColor||m.borderColor||o.borderColor;return{backgroundColor:n,color:t.textColor||m.textColor||"#ffffff",border:`${t.borderWidth||m.borderWidth||"1px"} solid ${u}`,borderRadius:t.borderRadius||m.borderRadius||"0",fontFamily:t.fontFamily||m.fontFamily||"monospace"}};return x("div",{className:"pixel-pet",ref:F,style:q?{"--pixel-pet-color":q}:void 0,children:Ge("div",{ref:w,className:"pixel-pet-container",style:{transform:`translateX(${ae}px)`},onMouseEnter:ve,onMouseLeave:Me,children:[x("div",{className:"pixel-pet-status",role:"status",children:X&&x("div",{ref:Q,className:"pixel-pet-dialog",style:{...Ce(p),...N&&{left:N.left,maxWidth:N.maxWidth}},children:L?S(c.message,c.emotion):p&&ke[p]})}),x("button",{type:"button","aria-label":(ce??f).split("{name}").join(f),className:`pixel-pet-sprite pixel-pet-${M} ${we()} ${H==="left"?"pixel-pet-flip-x":""}`,style:K?{backgroundImage:`url("${K}")`}:void 0,onClick:Pe,onFocus:e=>J(e.currentTarget.matches(":focus-visible")),onBlur:()=>J(!1)})]})})};export{je as PixelPet};
|
package/package.json
CHANGED