@mblinkov/whats-missing 20.0.20 → 20.0.21

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.
@@ -1,10 +1,10 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),o=require("react"),le=window.origin+"/cloud/speakid/games/whatsmissing/",D=(a,m)=>a.map(([c,s])=>({src:`${le}${m}/${s.replace(/\s/g,"%20")}.png`,name:s})),ae=[["apple","apple"],["banana","banana"],["bread","bread"],["burger","burger"],["cake","cake"],["carrot","carrot"],["cheese","cheese"],["chicken","chicken"],["chocolate","chocolate"],["corn","corn"],["donut","donut"],["fish","fish"],["fries","fries"],["grapes","grapes"],["ice_cream","ice cream"],["milk","milk"],["orange","orange"],["pear","pear"],["pizza","pizza"],["rice","rice"],["sandwich","sandwich"],["soup","soup"],["strawberry","strawberry"],["tomato","tomato"],["watermelon","watermelon"]],de=[["bear","bear"],["cat","cat"],["crocodile","crocodile"],["dolphin","dolphin"],["elephant","elephant"],["fox","fox"],["giraffe","giraffe"],["horse","horse"],["kangaroo","kangaroo"],["lion","lion"],["monkey","monkey"],["owl","owl"],["panda","panda"],["penguin","penguin"],["squirrel","squirrel"],["tiger","tiger"],["tortoise","tortoise"],["wolf","wolf"],["zebra","zebra"]],ce=[["ball","ball"],["balloon","balloon"],["blocks","blocks"],["car","car"],["doll","doll"],["drum","drum"],["guitar","guitar"],["jump_rope","jump rope"],["kite","kite"],["paints","paints"],["plane","plane"],["puzzle","puzzle"],["rocket","rocket"],["scooter","scooter"],["skateboard","skateboard"],["slide","slide"],["teddy_bear","teddy bear"],["yo-yo","yo-yo"],["crayons","crayons"]],P={food:D(ae,"food"),animals:D(de,"animals"),toys:D(ce,"toys")},me=`
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),r=require("react"),ce=window.origin+"/cloud/speakid/games/whatsmissing/",D=(a,m)=>a.map(([c,s])=>({src:`${ce}${m}/${s.replace(/\s/g,"%20")}.png`,name:s})),me=[["apple","apple"],["banana","banana"],["bread","bread"],["burger","burger"],["cake","cake"],["carrot","carrot"],["cheese","cheese"],["chicken","chicken"],["chocolate","chocolate"],["corn","corn"],["donut","donut"],["fish","fish"],["fries","fries"],["grapes","grapes"],["ice_cream","ice cream"],["milk","milk"],["orange","orange"],["pear","pear"],["pizza","pizza"],["rice","rice"],["sandwich","sandwich"],["soup","soup"],["strawberry","strawberry"],["tomato","tomato"],["watermelon","watermelon"]],ue=[["bear","bear"],["cat","cat"],["crocodile","crocodile"],["dolphin","dolphin"],["elephant","elephant"],["fox","fox"],["giraffe","giraffe"],["horse","horse"],["kangaroo","kangaroo"],["lion","lion"],["monkey","monkey"],["owl","owl"],["panda","panda"],["penguin","penguin"],["squirrel","squirrel"],["tiger","tiger"],["tortoise","tortoise"],["wolf","wolf"],["zebra","zebra"]],ge=[["ball","ball"],["balloon","balloon"],["blocks","blocks"],["car","car"],["doll","doll"],["drum","drum"],["guitar","guitar"],["jump_rope","jump rope"],["kite","kite"],["paints","paints"],["plane","plane"],["puzzle","puzzle"],["rocket","rocket"],["scooter","scooter"],["skateboard","skateboard"],["slide","slide"],["teddy_bear","teddy bear"],["yo-yo","yo-yo"],["crayons","crayons"]],P={food:D(me,"food"),animals:D(ue,"animals"),toys:D(ge,"toys")},he=`
2
2
  @keyframes spin {
3
3
  from { transform: rotate(0deg); }
4
4
  to { transform: rotate(360deg); }
5
5
  }
6
- `;if(typeof document<"u"&&!document.getElementById("spin-keyframes")){const a=document.createElement("style");a.id="spin-keyframes",a.innerHTML=me,document.head.appendChild(a)}const ue={animation:"spin 1.4s linear infinite"},n={gmCenterScreen:{position:"relative",zIndex:1,minHeight:"100vh",width:"100%",display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"center",textAlign:"center",color:"#1f2937",padding:"24px 16px",boxSizing:"border-box",transform:"translateY(20px)"},gmHeadline1:{fontWeight:700,fontSize:"clamp(28px, 4vw, 40px)",lineHeight:"110%"},gmHeadline3:{fontWeight:600,fontSize:"18px",lineHeight:"130%"},gmBodyM:{fontWeight:400,fontSize:"16px",lineHeight:"140%"},gmBodyS:{fontWeight:400,fontSize:"14px",lineHeight:"140%",color:"#6b7280"},gmButton:{fontFamily:'"Geist", system-ui, -apple-system, "Segoe UI", Roboto, Arial, "Noto Sans"',fontWeight:600,fontSize:"16px",padding:"10px 16px",borderRadius:"12px",border:"1px solid #e5e7eb",background:"#ec4c44",color:"#ffffff",cursor:"pointer",boxShadow:"0 6px 18px rgba(236, 76, 68, .18)",transition:"transform .06s ease, box-shadow .2s ease, background .2s ease, opacity .2s ease"},gmButtonActive:{background:"#333",color:"#fff"},gmGameLayout:{position:"relative",width:"100%",maxWidth:"600px",minHeight:"100vh",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",textAlign:"center",color:"#1f2937",padding:"16px 8px",margin:"0 auto"},gmGrid:{width:"100%",maxWidth:"calc(210px * 3 + 20px * 2)",margin:"0 auto",display:"grid",gridTemplateColumns:"repeat(3, 210px)",gridAutoRows:"210px",gap:"20px",justifyContent:"center"},gmCard:{border:"1px solid #e5e7eb",borderRadius:"16px",background:"#f9f9f9",aspectRatio:"1 / 1",display:"flex",alignItems:"center",justifyContent:"center",overflow:"hidden",transition:"transform .2s ease, box-shadow .2s ease, border-color .2s ease"},gmCorrect:{border:"2px solid #10b981",boxShadow:"0 0 18px rgba(16,185,129,.45)",background:"#ecfdf5"},gmWrong:{border:"2px solid #ec4c44",boxShadow:"0 0 18px rgba(236,76,68,.35)",background:"#fef2f2"},gmInput:{padding:"6px 10px",borderRadius:"6px",border:"1px solid #ccc",fontSize:"16px",fontFamily:'"Geist", system-ui',width:"160px"},gmTable:{marginTop:"20px",marginBottom:"32px",borderCollapse:"collapse",width:"100%",maxWidth:"520px",tableLayout:"fixed",textAlign:"center"},gmTableCell:{padding:"8px 12px",borderBottom:"1px solid #e5e7eb",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"},gmLogoFixed:{position:"absolute",top:"16px",left:"24px",width:"120px",zIndex:10,pointerEvents:"none",background:"transparent",transform:"none",willChange:"auto"},gmLogoImg:{height:"clamp(28px, 5vw, 40px)",width:"auto",background:"transparent",objectFit:"contain",imageRendering:"auto",transform:"translateZ(0)",backfaceVisibility:"hidden",WebkitFontSmoothing:"antialiased"},gmHourglass:{fontSize:"42px",...ue}},ge=()=>{const a=document.createElement("style");a.textContent=`
6
+ `;if(typeof document<"u"&&!document.getElementById("spin-keyframes")){const a=document.createElement("style");a.id="spin-keyframes",a.innerHTML=he,document.head.appendChild(a)}const fe={animation:"spin 1.4s linear infinite"},n={gmCenterScreen:{position:"relative",zIndex:1,minHeight:"100%",width:"100%",display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"center",textAlign:"center",color:"#1f2937",padding:"24px 16px",boxSizing:"border-box",transform:"translateY(20px)"},gmHeadline1:{fontWeight:700,fontSize:"clamp(28px, 4vw, 40px)",lineHeight:"110%"},gmHeadline3:{fontWeight:600,fontSize:"18px",lineHeight:"130%"},gmBodyM:{fontWeight:400,fontSize:"16px",lineHeight:"140%"},gmBodyS:{fontWeight:400,fontSize:"14px",lineHeight:"140%",color:"#6b7280"},gmButton:{fontFamily:'"Geist", system-ui, -apple-system, "Segoe UI", Roboto, Arial, "Noto Sans"',fontWeight:600,fontSize:"16px",padding:"10px 16px",borderRadius:"12px",border:"1px solid #e5e7eb",background:"#ec4c44",color:"#ffffff",cursor:"pointer",boxShadow:"0 6px 18px rgba(236, 76, 68, .18)",transition:"transform .06s ease, box-shadow .2s ease, background .2s ease, opacity .2s ease"},gmButtonActive:{background:"#333",color:"#fff"},gmGameLayout:{position:"relative",width:"100%",maxWidth:"600px",minHeight:"100%",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",textAlign:"center",color:"#1f2937",padding:"16px 8px",margin:"0 auto"},gmGrid:{width:"100%",maxWidth:"calc(210px * 3 + 20px * 2)",margin:"0 auto",display:"grid",gridTemplateColumns:"repeat(3, 210px)",gridAutoRows:"210px",gap:"20px",justifyContent:"center"},gmCard:{border:"1px solid #e5e7eb",borderRadius:"16px",background:"#f9f9f9",aspectRatio:"1 / 1",display:"flex",alignItems:"center",justifyContent:"center",overflow:"hidden",transition:"transform .2s ease, box-shadow .2s ease, border-color .2s ease"},gmCorrect:{border:"2px solid #10b981",boxShadow:"0 0 18px rgba(16,185,129,.45)",background:"#ecfdf5"},gmWrong:{border:"2px solid #ec4c44",boxShadow:"0 0 18px rgba(236,76,68,.35)",background:"#fef2f2"},gmInput:{padding:"6px 10px",borderRadius:"6px",border:"1px solid #ccc",fontSize:"16px",fontFamily:'"Geist", system-ui',width:"160px"},gmTable:{marginTop:"20px",marginBottom:"32px",borderCollapse:"collapse",width:"100%",maxWidth:"520px",tableLayout:"fixed",textAlign:"center"},gmTableCell:{padding:"8px 12px",borderBottom:"1px solid #e5e7eb",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"},gmLogoFixed:{position:"absolute",top:"16px",left:"24px",width:"120px",zIndex:10,pointerEvents:"none",background:"transparent",transform:"none",willChange:"auto"},gmLogoImg:{height:"clamp(28px, 5vw, 40px)",width:"auto",background:"transparent",objectFit:"contain",imageRendering:"auto",transform:"translateZ(0)",backfaceVisibility:"hidden",WebkitFontSmoothing:"antialiased"},gmHourglass:{fontSize:"42px",...fe}},pe=()=>{const a=document.createElement("style");a.textContent=`
7
7
  /* scope only inside game root */
8
8
  #whats-missing-root, #whats-missing-root * { box-sizing: border-box; }
9
9
  #whats-missing-root img { max-width:100%; height:auto; display:block; user-select:none; }
10
- `,document.head.appendChild(a)},he=(a,m)=>{const c=Array.from({length:a.length+1},()=>Array(m.length+1).fill(0));for(let s=0;s<=a.length;s++)c[s][0]=s;for(let s=0;s<=m.length;s++)c[0][s]=s;for(let s=1;s<=a.length;s++)for(let u=1;u<=m.length;u++)c[s][u]=a[s-1]===m[u-1]?c[s-1][u-1]:Math.min(c[s-1][u-1],c[s][u-1],c[s-1][u])+1;return c[a.length][m.length]};function fe(a,m={minDesktopWidth:1200,forceResize:!1}){const c=o.useRef(null),s=m.minDesktopWidth??1200,u=!!m.forceResize;o.useLayoutEffect(()=>{if(typeof window>"u"||!a||!a.current)return;const i=a.current,L=()=>{try{const r=document.body,d=getComputedStyle(r),p=parseFloat(r.style&&r.style.zoom||"");if(p&&!isNaN(p)&&p>0)return p;const j=parseFloat(d.zoom||"");if(j&&!isNaN(j)&&j>0)return j;const k=d.transform||d.webkitTransform||d.mozTransform;if(k&&k!=="none"){const C=k.match(/matrix\(([^)]+)\)/);if(C){const v=C[1].split(",").map(B=>parseFloat(B))[0];if(v&&!isNaN(v))return v}}}catch{}return 1},b=()=>{if(s&&window.innerWidth<s){S();return}const r=L();if(!r||r===1){S();return}c.current||(c.current={transform:i.style.transform||null,transformOrigin:i.style.transformOrigin||null,width:i.style.width||null,height:i.style.height||null,willChange:i.style.willChange||null});const d=1/r;u&&(i.style.width=`${r*100}%`,i.style.height=`${r*100}%`),i.style.transform=`scale(${d})`,i.style.transformOrigin="top left",i.style.willChange="transform",typeof process<"u"&&process.env&&process.env.NODE_ENV==="development"&&console.debug("[useNeutralizeBodyZoom] applied scale:",{scale:r,inv:d,forceResize:u})},S=()=>{if(!c.current)return;const r=c.current;r.transform===null?i.style.removeProperty("transform"):i.style.transform=r.transform,r.transformOrigin===null?i.style.removeProperty("transform-origin"):i.style.transformOrigin=r.transformOrigin,r.width===null?i.style.removeProperty("width"):i.style.width=r.width,r.height===null?i.style.removeProperty("height"):i.style.height=r.height,r.willChange===null?i.style.removeProperty("will-change"):i.style.willChange=r.willChange,c.current=null,process.env.NODE_ENV==="development"&&console.debug("[useNeutralizeBodyZoom] restored original styles")};let x=0;const w=()=>{cancelAnimationFrame(x),x=requestAnimationFrame(b)},f=new MutationObserver(r=>{for(const d of r)if(d.type==="attributes"&&(d.attributeName==="style"||d.attributeName==="class")){w();break}});return f.observe(document.body,{attributes:!0,attributeFilter:["style","class"]}),window.addEventListener("resize",w),w(),()=>{cancelAnimationFrame(x),f.disconnect(),window.removeEventListener("resize",w),S()}},[a,s,u])}function pe(){const a=o.useRef(null);fe(a,{minDesktopWidth:1200,forceResize:!1}),o.useEffect(()=>(ge(),()=>{document.body.style.overflow=""}),[]);const[m,c]=o.useState(null),[s,u]=o.useState([]),[i,L]=o.useState(4),[b,S]=o.useState(!1),[x,w]=o.useState(1),[f,r]=o.useState(null),[d,p]=o.useState("ready"),[j,k]=o.useState(3),[C,M]=o.useState(10),[v,B]=o.useState(20),[Q,F]=o.useState(0),[A,W]=o.useState(!1),[H,q]=o.useState(""),[z,N]=o.useState(!1),[G,Y]=o.useState(!1),[$,R]=o.useState(null),[ee,O]=o.useState([]),[te,V]=o.useState([]),[y,ne]=o.useState(!1),[ye,Z]=o.useState(1),[_,U]=o.useState(null);o.useEffect(()=>{const t=()=>{const l=window.innerWidth<768;if(ne(l),l)U(null),Z(1);else{const T=Math.min(window.innerWidth,window.innerHeight),I=Math.max(360,Math.round(T*.97)),E=Math.min(I,1e3);U(E),Z(1)}};return t(),window.addEventListener("resize",t),()=>window.removeEventListener("resize",t)},[]);const K=t=>[...t].sort(()=>Math.random()-.5).slice(0,6),X=()=>{if(!m)return;const t=K(P[m]);u(t),S(!0),W(!1),w(1),F(0),O([]),V([]),J(t,[],!0)},J=(t=s,l=te,h=!1)=>{const g=K(t.length?t:P[m]);let T=Math.floor(Math.random()*g.length),I=g[T].name,E=0;for(;l.includes(I)&&E<20;)T=Math.floor(Math.random()*g.length),I=g[T].name,E++;u(g),r(T),V([...l,I]),N(!1),q(""),B(20),R(null),h?(p("ready"),k(3),M(10)):(p("memorize"),M(10))};o.useEffect(()=>{if(!(!b||A||z)){if(d==="ready")if(j<=0)p("memorize");else{const t=setTimeout(()=>k(l=>l-1),1e3);return()=>clearTimeout(t)}if(d==="memorize")if(C<=0)p("guess");else{const t=setTimeout(()=>M(l=>l-1),1e3);return()=>clearTimeout(t)}if(d==="guess"){if(v<=0){N(!0),R("wrong");const l=s[f].name;O(h=>[...h,{round:x,answer:H,correct:l,result:"wrong"}]);return}const t=setTimeout(()=>B(l=>l-1),1e3);return()=>clearTimeout(t)}}},[d,j,C,v,b,A,z,s,f,x,H]);const se=()=>{if(f===null||G)return;const t=s[f].name,l=H.toLowerCase().trim();let h="wrong";l===t?(F(g=>g+1),R("correct"),h="correct"):he(l,t)===1?(F(g=>g+.5),R("almost"),h="almost"):(R("wrong"),h="wrong"),O(g=>[...g,{round:x,answer:l,correct:t,result:h}]),Y(!0),setTimeout(()=>{Y(!1),N(!0)},600)},oe=()=>x<i?(w(t=>t+1),J()):W(!0),re=()=>{S(!1),W(!1),c(null)},ie=o.useMemo(()=>e.jsx("div",{style:{...n.gmLogoFixed,position:"absolute",top:16,left:16,zIndex:30},children:e.jsxs("picture",{children:[e.jsx("source",{srcSet:window.origin+"/cloud/speakid/games/whatsmissing/logo.svg",type:"image/svg+xml"}),e.jsx("img",{src:window.origin+"/cloud/speakid/games/whatsmissing/logo.png",alt:"SPEAKID Logo",style:n.gmLogoImg,loading:"lazy"})]})}),[]);return e.jsx("div",{ref:a,style:{width:"100%",height:"100vh",display:"flex",justifyContent:"center",alignItems:"center",background:"linear-gradient(to bottom, #fff8f8 0%, #f9fafb 100%)",transition:"background 0.3s ease",overflowX:"clip"},children:e.jsx("div",{style:{width:y?"100%":_||1e3,height:y?"100%":_||1e3,display:"flex",justifyContent:"center",alignItems:"center",overflow:"hidden",borderRadius:y?0:"20px",background:"linear-gradient(to bottom, #fff8f8 0%, #f9fafb 100%)",boxShadow:y?"none":"0 0 40px rgba(0,0,0,0.1)",margin:y?"0 auto":"unset",position:"relative"},children:e.jsx("div",{style:{transform:"none",width:"100%",height:"100%",display:"flex",justifyContent:"center",alignItems:"center"},children:e.jsxs("div",{id:"whats-missing-root",children:[!y&&ie,!m&&!b&&e.jsxs("div",{style:n.gmCenterScreen,children:[e.jsx("h1",{style:n.gmHeadline1,children:"WHAT'S MISSING?"}),e.jsx("p",{style:n.gmBodyM,children:"Select a theme:"}),e.jsx("div",{style:{display:"flex",gap:16},children:["animals","food","toys"].map(t=>e.jsx("button",{style:n.gmButton,onClick:()=>c(t),children:t==="animals"?"🐶 Animals":t==="food"?"🍎 Food":"🧸 Toys"},t))}),e.jsxs("div",{style:{marginTop:24},children:[e.jsx("p",{style:n.gmBodyS,children:"Choose number of rounds:"}),e.jsx("div",{style:{display:"flex",gap:12,marginTop:8},children:[3,4,5].map(t=>e.jsx("button",{style:{...n.gmButton,...i===t?n.gmButtonActive:{}},onClick:()=>L(t),children:t},t))})]})]}),m&&!b&&e.jsxs("div",{style:n.gmCenterScreen,children:[e.jsxs("h1",{style:n.gmHeadline1,children:["Theme selected: ",m]}),e.jsxs("p",{style:n.gmBodyM,children:["Rounds: ",i]}),e.jsx("button",{style:n.gmButton,onClick:X,children:"▶ Start game"})]}),A&&e.jsxs("div",{style:n.gmCenterScreen,children:[e.jsx("h1",{style:n.gmHeadline1,children:"Results"}),e.jsxs("h2",{style:n.gmHeadline3,children:["Your score: ",Q," / ",i]}),e.jsx("p",{style:{...n.gmBodyM,color:"#10b981",marginTop:12},children:"Yahoo! You did it! 🍬✨"}),e.jsxs("table",{style:n.gmTable,children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Round"}),e.jsx("th",{children:"Your Answer"}),e.jsx("th",{children:"Correct"}),e.jsx("th",{children:"Result"})]})}),e.jsx("tbody",{children:ee.map((t,l)=>e.jsxs("tr",{children:[e.jsx("td",{style:n.gmTableCell,children:t.round}),e.jsx("td",{style:n.gmTableCell,children:t.answer||"—"}),e.jsx("td",{style:n.gmTableCell,children:t.correct}),e.jsx("td",{style:n.gmTableCell,children:t.result==="correct"?"✔ Correct":t.result==="almost"?"◐ Almost (0.5)":"✘ Wrong"})]},l))})]}),e.jsxs("div",{style:{display:"flex",gap:12,marginTop:24},children:[e.jsx("button",{style:n.gmButton,onClick:X,children:"🔁 Play again"}),e.jsx("button",{style:n.gmButton,onClick:re,children:"⬅️ Choose theme"})]})]}),b&&!A&&e.jsxs("div",{style:n.gmGameLayout,children:[e.jsxs("div",{style:{minHeight:160,display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"center"},children:[d==="ready"&&e.jsxs(e.Fragment,{children:[e.jsx("h1",{style:{...n.gmHeadline1,color:"#ec4c44"},children:"GET READY"}),e.jsx("div",{style:n.gmHourglass,children:"⏳"})]}),d==="memorize"&&e.jsxs("p",{style:{...n.gmBodyM,color:"#10b981"},children:["MEMORIZE (",C,")"]}),d==="guess"&&!z&&e.jsxs("p",{style:n.gmBodyM,children:["⏳ Time left: ",v,"s"]})]}),d!=="ready"&&e.jsx("div",{style:{...n.gmGrid,gridTemplateColumns:y?"repeat(2, 1fr)":"repeat(3, 210px)",gridAutoRows:y?"150px":"210px",gap:y?"12px":"20px",justifyItems:"center"},children:s.map((t,l)=>{const h=f===l&&d==="guess"&&!z;return e.jsx("div",{style:{...n.gmCard,...$==="correct"&&f===l?n.gmCorrect:{},...$==="wrong"&&f===l?n.gmWrong:{}},children:!h&&e.jsx("img",{src:t.src,alt:t.name,style:{width:"100%",height:"100%",objectFit:"cover"}})},l)})}),e.jsxs("div",{style:{marginTop:16,height:80},children:[d==="guess"&&!z&&e.jsxs("div",{children:[e.jsx("input",{type:"text",placeholder:"Type the missing word",value:H,onChange:t=>q(t.target.value),style:n.gmInput}),e.jsx("button",{style:{...n.gmButton,marginLeft:8},onClick:se,disabled:G,children:G?"...":"Check"})]}),z&&e.jsx("button",{type:"button",style:n.gmButton,onClick:oe,children:"Next round"})]})]})]})})})})}exports.Game=pe;exports.themes=P;
10
+ `,document.head.appendChild(a)},ye=(a,m)=>{const c=Array.from({length:a.length+1},()=>Array(m.length+1).fill(0));for(let s=0;s<=a.length;s++)c[s][0]=s;for(let s=0;s<=m.length;s++)c[0][s]=s;for(let s=1;s<=a.length;s++)for(let u=1;u<=m.length;u++)c[s][u]=a[s-1]===m[u-1]?c[s-1][u-1]:Math.min(c[s-1][u-1],c[s][u-1],c[s-1][u])+1;return c[a.length][m.length]};function xe(a,m={minDesktopWidth:1200,forceResize:!1}){const c=r.useRef(null),s=m.minDesktopWidth??1200,u=!!m.forceResize;r.useLayoutEffect(()=>{if(typeof window>"u"||!a||!a.current)return;const l=a.current,A=()=>{try{const i=document.body,d=getComputedStyle(i),p=parseFloat(i.style&&i.style.zoom||"");if(p&&!isNaN(p)&&p>0)return p;const v=parseFloat(d.zoom||"");if(v&&!isNaN(v)&&v>0)return v;const k=d.transform||d.webkitTransform||d.mozTransform;if(k&&k!=="none"){const z=k.match(/matrix\(([^)]+)\)/);if(z){const j=z[1].split(",").map(E=>parseFloat(E))[0];if(j&&!isNaN(j))return j}}}catch{}return 1},b=()=>{if(s&&window.innerWidth<s){S();return}const i=A();if(!i||i===1){S();return}c.current||(c.current={transform:l.style.transform||null,transformOrigin:l.style.transformOrigin||null,width:l.style.width||null,height:l.style.height||null,willChange:l.style.willChange||null});const d=1/i;u&&(l.style.width=`${i*100}%`,l.style.height=`${i*100}%`),l.style.transform=`scale(${d})`,l.style.transformOrigin="top left",l.style.willChange="transform",typeof process<"u"&&process.env&&process.env.NODE_ENV==="development"&&console.debug("[useNeutralizeBodyZoom] applied scale:",{scale:i,inv:d,forceResize:u})},S=()=>{if(!c.current)return;const i=c.current;i.transform===null?l.style.removeProperty("transform"):l.style.transform=i.transform,i.transformOrigin===null?l.style.removeProperty("transform-origin"):l.style.transformOrigin=i.transformOrigin,i.width===null?l.style.removeProperty("width"):l.style.width=i.width,i.height===null?l.style.removeProperty("height"):l.style.height=i.height,i.willChange===null?l.style.removeProperty("will-change"):l.style.willChange=i.willChange,c.current=null,process.env.NODE_ENV==="development"&&console.debug("[useNeutralizeBodyZoom] restored original styles")};let x=0;const w=()=>{cancelAnimationFrame(x),x=requestAnimationFrame(b)},f=new MutationObserver(i=>{for(const d of i)if(d.type==="attributes"&&(d.attributeName==="style"||d.attributeName==="class")){w();break}});return f.observe(document.body,{attributes:!0,attributeFilter:["style","class"]}),window.addEventListener("resize",w),w(),()=>{cancelAnimationFrame(x),f.disconnect(),window.removeEventListener("resize",w),S()}},[a,s,u])}function be(){const a=r.useRef(null);xe(a,{minDesktopWidth:1200,forceResize:!1}),r.useEffect(()=>(pe(),()=>{document.body.style.overflow=""}),[]);const[m,c]=r.useState(null),[s,u]=r.useState([]),[l,A]=r.useState(4),[b,S]=r.useState(!1),[x,w]=r.useState(1),[f,i]=r.useState(null),[d,p]=r.useState("ready"),[v,k]=r.useState(3),[z,M]=r.useState(10),[j,E]=r.useState(20),[Q,H]=r.useState(0),[L,F]=r.useState(!1),[B,q]=r.useState(""),[C,W]=r.useState(!1),[N,V]=r.useState(!1),[Y,I]=r.useState(null),[ee,G]=r.useState([]),[te,$]=r.useState([]),[y,ne]=r.useState(!1),[we,Z]=r.useState(1),[_,U]=r.useState(null);r.useEffect(()=>{const t=()=>{const g=window.visualViewport,h=g?Math.round(g.width):window.innerWidth,T=g?Math.round(g.height):window.innerHeight,R=h<768;if(ne(R),R)U(null),Z(1);else{const le=Math.min(h,T),ae=Math.max(360,Math.round(le*.97)),de=Math.min(ae,1e3);U(de),Z(1)}};t(),window.addEventListener("resize",t);const o=window.visualViewport;return o&&typeof o.addEventListener=="function"&&(o.addEventListener("resize",t),o.addEventListener("scroll",t)),()=>{window.removeEventListener("resize",t),o&&typeof o.removeEventListener=="function"&&(o.removeEventListener("resize",t),o.removeEventListener("scroll",t))}},[]);const K=t=>[...t].sort(()=>Math.random()-.5).slice(0,6),X=()=>{if(!m)return;const t=K(P[m]);u(t),S(!0),F(!1),w(1),H(0),G([]),$([]),J(t,[],!0)},J=(t=s,o=te,g=!1)=>{const h=K(t.length?t:P[m]);let T=Math.floor(Math.random()*h.length),R=h[T].name,O=0;for(;o.includes(R)&&O<20;)T=Math.floor(Math.random()*h.length),R=h[T].name,O++;u(h),i(T),$([...o,R]),W(!1),q(""),E(20),I(null),g?(p("ready"),k(3),M(10)):(p("memorize"),M(10))};r.useEffect(()=>{if(!(!b||L||C)){if(d==="ready")if(v<=0)p("memorize");else{const t=setTimeout(()=>k(o=>o-1),1e3);return()=>clearTimeout(t)}if(d==="memorize")if(z<=0)p("guess");else{const t=setTimeout(()=>M(o=>o-1),1e3);return()=>clearTimeout(t)}if(d==="guess"){if(j<=0){W(!0),I("wrong");const o=s[f].name;G(g=>[...g,{round:x,answer:B,correct:o,result:"wrong"}]);return}const t=setTimeout(()=>E(o=>o-1),1e3);return()=>clearTimeout(t)}}},[d,v,z,j,b,L,C,s,f,x,B]);const se=()=>{if(f===null||N)return;const t=s[f].name,o=B.toLowerCase().trim();let g="wrong";o===t?(H(h=>h+1),I("correct"),g="correct"):ye(o,t)===1?(H(h=>h+.5),I("almost"),g="almost"):(I("wrong"),g="wrong"),G(h=>[...h,{round:x,answer:o,correct:t,result:g}]),V(!0),setTimeout(()=>{V(!1),W(!0)},600)},oe=()=>x<l?(w(t=>t+1),J()):F(!0),re=()=>{S(!1),F(!1),c(null)},ie=r.useMemo(()=>e.jsx("div",{style:{...n.gmLogoFixed,position:"absolute",top:16,left:16,zIndex:30},children:e.jsxs("picture",{children:[e.jsx("source",{srcSet:window.origin+"/cloud/speakid/games/whatsmissing/logo.svg",type:"image/svg+xml"}),e.jsx("img",{src:window.origin+"/cloud/speakid/games/whatsmissing/logo.png",alt:"SPEAKID Logo",style:n.gmLogoImg,loading:"lazy"})]})}),[]);return e.jsx("div",{ref:a,style:{width:"100%",height:"100vh",display:"flex",justifyContent:"center",alignItems:"center",background:"linear-gradient(to bottom, #fff8f8 0%, #f9fafb 100%)",transition:"background 0.3s ease",overflowX:"clip"},children:e.jsx("div",{style:{width:y?"100%":_||1e3,height:y?"100%":_||1e3,display:"flex",justifyContent:"center",alignItems:"center",overflow:"hidden",borderRadius:y?0:"20px",background:"linear-gradient(to bottom, #fff8f8 0%, #f9fafb 100%)",boxShadow:y?"none":"0 0 40px rgba(0,0,0,0.1)",margin:y?"0 auto":"unset",position:"relative"},children:e.jsx("div",{style:{transform:"none",width:"100%",height:"100%",display:"flex",justifyContent:"center",alignItems:"center"},children:e.jsxs("div",{id:"whats-missing-root",children:[!y&&ie,!m&&!b&&e.jsxs("div",{style:n.gmCenterScreen,children:[e.jsx("h1",{style:n.gmHeadline1,children:"WHAT'S MISSING?"}),e.jsx("p",{style:n.gmBodyM,children:"Select a theme:"}),e.jsx("div",{style:{display:"flex",gap:16},children:["animals","food","toys"].map(t=>e.jsx("button",{style:n.gmButton,onClick:()=>c(t),children:t==="animals"?"🐶 Animals":t==="food"?"🍎 Food":"🧸 Toys"},t))}),e.jsxs("div",{style:{marginTop:24},children:[e.jsx("p",{style:n.gmBodyS,children:"Choose number of rounds:"}),e.jsx("div",{style:{display:"flex",gap:12,marginTop:8},children:[3,4,5].map(t=>e.jsx("button",{style:{...n.gmButton,...l===t?n.gmButtonActive:{}},onClick:()=>A(t),children:t},t))})]})]}),m&&!b&&e.jsxs("div",{style:n.gmCenterScreen,children:[e.jsxs("h1",{style:n.gmHeadline1,children:["Theme selected: ",m]}),e.jsxs("p",{style:n.gmBodyM,children:["Rounds: ",l]}),e.jsx("button",{style:n.gmButton,onClick:X,children:"▶ Start game"})]}),L&&e.jsxs("div",{style:n.gmCenterScreen,children:[e.jsx("h1",{style:n.gmHeadline1,children:"Results"}),e.jsxs("h2",{style:n.gmHeadline3,children:["Your score: ",Q," / ",l]}),e.jsx("p",{style:{...n.gmBodyM,color:"#10b981",marginTop:12},children:"Yahoo! You did it! 🍬✨"}),e.jsxs("table",{style:n.gmTable,children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Round"}),e.jsx("th",{children:"Your Answer"}),e.jsx("th",{children:"Correct"}),e.jsx("th",{children:"Result"})]})}),e.jsx("tbody",{children:ee.map((t,o)=>e.jsxs("tr",{children:[e.jsx("td",{style:n.gmTableCell,children:t.round}),e.jsx("td",{style:n.gmTableCell,children:t.answer||"—"}),e.jsx("td",{style:n.gmTableCell,children:t.correct}),e.jsx("td",{style:n.gmTableCell,children:t.result==="correct"?"✔ Correct":t.result==="almost"?"◐ Almost (0.5)":"✘ Wrong"})]},o))})]}),e.jsxs("div",{style:{display:"flex",gap:12,marginTop:24},children:[e.jsx("button",{style:n.gmButton,onClick:X,children:"🔁 Play again"}),e.jsx("button",{style:n.gmButton,onClick:re,children:"⬅️ Choose theme"})]})]}),b&&!L&&e.jsxs("div",{style:n.gmGameLayout,children:[e.jsxs("div",{style:{minHeight:160,display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"center"},children:[d==="ready"&&e.jsxs(e.Fragment,{children:[e.jsx("h1",{style:{...n.gmHeadline1,color:"#ec4c44"},children:"GET READY"}),e.jsx("div",{style:n.gmHourglass,children:"⏳"})]}),d==="memorize"&&e.jsxs("p",{style:{...n.gmBodyM,color:"#10b981"},children:["MEMORIZE (",z,")"]}),d==="guess"&&!C&&e.jsxs("p",{style:n.gmBodyM,children:["⏳ Time left: ",j,"s"]})]}),d!=="ready"&&e.jsx("div",{style:{...n.gmGrid,gridTemplateColumns:y?"repeat(2, 1fr)":"repeat(3, 210px)",gridAutoRows:y?"150px":"210px",gap:y?"12px":"20px",justifyItems:"center"},children:s.map((t,o)=>{const g=f===o&&d==="guess"&&!C;return e.jsx("div",{style:{...n.gmCard,...Y==="correct"&&f===o?n.gmCorrect:{},...Y==="wrong"&&f===o?n.gmWrong:{}},children:!g&&e.jsx("img",{src:t.src,alt:t.name,style:{width:"100%",height:"100%",objectFit:"cover"}})},o)})}),e.jsxs("div",{style:{marginTop:16,height:80},children:[d==="guess"&&!C&&e.jsxs("div",{children:[e.jsx("input",{type:"text",placeholder:"Type the missing word",value:B,onChange:t=>q(t.target.value),style:n.gmInput}),e.jsx("button",{style:{...n.gmButton,marginLeft:8},onClick:se,disabled:N,children:N?"...":"Check"})]}),C&&e.jsx("button",{type:"button",style:n.gmButton,onClick:oe,children:"Next round"})]})]})]})})})})}exports.Game=be;exports.themes=P;
@@ -1,9 +1,9 @@
1
- import { jsx as t, jsxs as c, Fragment as ce } from "react/jsx-runtime";
2
- import { useRef as te, useEffect as P, useState as d, useMemo as me, useLayoutEffect as ge } from "react";
3
- const ue = window.origin + "/cloud/speakid/games/whatsmissing/", Y = (l, g) => l.map(([m, o]) => ({
4
- src: `${ue}${g}/${o.replace(/\s/g, "%20")}.png`,
1
+ import { jsx as t, jsxs as c, Fragment as ue } from "react/jsx-runtime";
2
+ import { useRef as te, useEffect as P, useState as d, useMemo as he, useLayoutEffect as fe } from "react";
3
+ const pe = window.origin + "/cloud/speakid/games/whatsmissing/", V = (l, g) => l.map(([m, o]) => ({
4
+ src: `${pe}${g}/${o.replace(/\s/g, "%20")}.png`,
5
5
  name: o
6
- })), he = [
6
+ })), ye = [
7
7
  ["apple", "apple"],
8
8
  ["banana", "banana"],
9
9
  ["bread", "bread"],
@@ -29,7 +29,7 @@ const ue = window.origin + "/cloud/speakid/games/whatsmissing/", Y = (l, g) => l
29
29
  ["strawberry", "strawberry"],
30
30
  ["tomato", "tomato"],
31
31
  ["watermelon", "watermelon"]
32
- ], pe = [
32
+ ], be = [
33
33
  ["bear", "bear"],
34
34
  ["cat", "cat"],
35
35
  ["crocodile", "crocodile"],
@@ -49,7 +49,7 @@ const ue = window.origin + "/cloud/speakid/games/whatsmissing/", Y = (l, g) => l
49
49
  ["tortoise", "tortoise"],
50
50
  ["wolf", "wolf"],
51
51
  ["zebra", "zebra"]
52
- ], fe = [
52
+ ], we = [
53
53
  ["ball", "ball"],
54
54
  ["balloon", "balloon"],
55
55
  ["blocks", "blocks"],
@@ -70,10 +70,10 @@ const ue = window.origin + "/cloud/speakid/games/whatsmissing/", Y = (l, g) => l
70
70
  ["yo-yo", "yo-yo"],
71
71
  ["crayons", "crayons"]
72
72
  ], ee = {
73
- food: Y(he, "food"),
74
- animals: Y(pe, "animals"),
75
- toys: Y(fe, "toys")
76
- }, ye = `
73
+ food: V(ye, "food"),
74
+ animals: V(be, "animals"),
75
+ toys: V(we, "toys")
76
+ }, xe = `
77
77
  @keyframes spin {
78
78
  from { transform: rotate(0deg); }
79
79
  to { transform: rotate(360deg); }
@@ -81,15 +81,17 @@ const ue = window.origin + "/cloud/speakid/games/whatsmissing/", Y = (l, g) => l
81
81
  `;
82
82
  if (typeof document < "u" && !document.getElementById("spin-keyframes")) {
83
83
  const l = document.createElement("style");
84
- l.id = "spin-keyframes", l.innerHTML = ye, document.head.appendChild(l);
84
+ l.id = "spin-keyframes", l.innerHTML = xe, document.head.appendChild(l);
85
85
  }
86
- const be = {
86
+ const ve = {
87
87
  animation: "spin 1.4s linear infinite"
88
88
  }, n = {
89
89
  gmCenterScreen: {
90
90
  position: "relative",
91
91
  zIndex: 1,
92
- minHeight: "100vh",
92
+ // use percent so the component fits inside the centered square container
93
+ // (100vh caused overflow on tablets because it measured the viewport, not the container)
94
+ minHeight: "100%",
93
95
  width: "100%",
94
96
  display: "flex",
95
97
  flexDirection: "column",
@@ -144,7 +146,8 @@ const be = {
144
146
  position: "relative",
145
147
  width: "100%",
146
148
  maxWidth: "600px",
147
- minHeight: "100vh",
149
+ // should fill the parent square, not the full viewport
150
+ minHeight: "100%",
148
151
  display: "flex",
149
152
  flexDirection: "column",
150
153
  alignItems: "center",
@@ -233,16 +236,16 @@ const be = {
233
236
  },
234
237
  gmHourglass: {
235
238
  fontSize: "42px",
236
- ...be
239
+ ...ve
237
240
  }
238
- }, xe = () => {
241
+ }, ke = () => {
239
242
  const l = document.createElement("style");
240
243
  l.textContent = `
241
244
  /* scope only inside game root */
242
245
  #whats-missing-root, #whats-missing-root * { box-sizing: border-box; }
243
246
  #whats-missing-root img { max-width:100%; height:auto; display:block; user-select:none; }
244
247
  `, document.head.appendChild(l);
245
- }, we = (l, g) => {
248
+ }, ze = (l, g) => {
246
249
  const m = Array.from({ length: l.length + 1 }, () => Array(g.length + 1).fill(0));
247
250
  for (let o = 0; o <= l.length; o++) m[o][0] = o;
248
251
  for (let o = 0; o <= g.length; o++) m[0][o] = o;
@@ -251,13 +254,13 @@ const be = {
251
254
  m[o][u] = l[o - 1] === g[u - 1] ? m[o - 1][u - 1] : Math.min(m[o - 1][u - 1], m[o][u - 1], m[o - 1][u]) + 1;
252
255
  return m[l.length][g.length];
253
256
  };
254
- function ve(l, g = { minDesktopWidth: 1200, forceResize: !1 }) {
257
+ function Ce(l, g = { minDesktopWidth: 1200, forceResize: !1 }) {
255
258
  const m = te(null), o = g.minDesktopWidth ?? 1200, u = !!g.forceResize;
256
- ge(() => {
259
+ fe(() => {
257
260
  if (typeof window > "u" || !l || !l.current) return;
258
- const i = l.current, E = () => {
261
+ const s = l.current, F = () => {
259
262
  try {
260
- const r = document.body, a = getComputedStyle(r), y = parseFloat(r.style && r.style.zoom || "");
263
+ const i = document.body, a = getComputedStyle(i), y = parseFloat(i.style && i.style.zoom || "");
261
264
  if (y && !isNaN(y) && y > 0) return y;
262
265
  const k = parseFloat(a.zoom || "");
263
266
  if (k && !isNaN(k) && k > 0) return k;
@@ -265,120 +268,124 @@ function ve(l, g = { minDesktopWidth: 1200, forceResize: !1 }) {
265
268
  if (S && S !== "none") {
266
269
  const T = S.match(/matrix\(([^)]+)\)/);
267
270
  if (T) {
268
- const C = T[1].split(",").map((H) => parseFloat(H))[0];
269
- if (C && !isNaN(C)) return C;
271
+ const z = T[1].split(",").map((E) => parseFloat(E))[0];
272
+ if (z && !isNaN(z)) return z;
270
273
  }
271
274
  }
272
275
  } catch {
273
276
  }
274
277
  return 1;
275
- }, w = () => {
278
+ }, x = () => {
276
279
  if (o && window.innerWidth < o) {
277
- z();
280
+ C();
278
281
  return;
279
282
  }
280
- const r = E();
281
- if (!r || r === 1) {
282
- z();
283
+ const i = F();
284
+ if (!i || i === 1) {
285
+ C();
283
286
  return;
284
287
  }
285
288
  m.current || (m.current = {
286
- transform: i.style.transform || null,
287
- transformOrigin: i.style.transformOrigin || null,
288
- width: i.style.width || null,
289
- height: i.style.height || null,
290
- willChange: i.style.willChange || null
289
+ transform: s.style.transform || null,
290
+ transformOrigin: s.style.transformOrigin || null,
291
+ width: s.style.width || null,
292
+ height: s.style.height || null,
293
+ willChange: s.style.willChange || null
291
294
  });
292
- const a = 1 / r;
293
- u && (i.style.width = `${r * 100}%`, i.style.height = `${r * 100}%`), i.style.transform = `scale(${a})`, i.style.transformOrigin = "top left", i.style.willChange = "transform", typeof process < "u" && process.env && process.env.NODE_ENV === "development" && console.debug("[useNeutralizeBodyZoom] applied scale:", { scale: r, inv: a, forceResize: u });
294
- }, z = () => {
295
+ const a = 1 / i;
296
+ u && (s.style.width = `${i * 100}%`, s.style.height = `${i * 100}%`), s.style.transform = `scale(${a})`, s.style.transformOrigin = "top left", s.style.willChange = "transform", typeof process < "u" && process.env && process.env.NODE_ENV === "development" && console.debug("[useNeutralizeBodyZoom] applied scale:", { scale: i, inv: a, forceResize: u });
297
+ }, C = () => {
295
298
  if (!m.current) return;
296
- const r = m.current;
297
- r.transform === null ? i.style.removeProperty("transform") : i.style.transform = r.transform, r.transformOrigin === null ? i.style.removeProperty("transform-origin") : i.style.transformOrigin = r.transformOrigin, r.width === null ? i.style.removeProperty("width") : i.style.width = r.width, r.height === null ? i.style.removeProperty("height") : i.style.height = r.height, r.willChange === null ? i.style.removeProperty("will-change") : i.style.willChange = r.willChange, m.current = null, process.env.NODE_ENV === "development" && console.debug("[useNeutralizeBodyZoom] restored original styles");
299
+ const i = m.current;
300
+ i.transform === null ? s.style.removeProperty("transform") : s.style.transform = i.transform, i.transformOrigin === null ? s.style.removeProperty("transform-origin") : s.style.transformOrigin = i.transformOrigin, i.width === null ? s.style.removeProperty("width") : s.style.width = i.width, i.height === null ? s.style.removeProperty("height") : s.style.height = i.height, i.willChange === null ? s.style.removeProperty("will-change") : s.style.willChange = i.willChange, m.current = null, process.env.NODE_ENV === "development" && console.debug("[useNeutralizeBodyZoom] restored original styles");
298
301
  };
299
- let x = 0;
302
+ let w = 0;
300
303
  const v = () => {
301
- cancelAnimationFrame(x), x = requestAnimationFrame(w);
302
- }, f = new MutationObserver((r) => {
303
- for (const a of r)
304
+ cancelAnimationFrame(w), w = requestAnimationFrame(x);
305
+ }, p = new MutationObserver((i) => {
306
+ for (const a of i)
304
307
  if (a.type === "attributes" && (a.attributeName === "style" || a.attributeName === "class")) {
305
308
  v();
306
309
  break;
307
310
  }
308
311
  });
309
- return f.observe(document.body, { attributes: !0, attributeFilter: ["style", "class"] }), window.addEventListener("resize", v), v(), () => {
310
- cancelAnimationFrame(x), f.disconnect(), window.removeEventListener("resize", v), z();
312
+ return p.observe(document.body, { attributes: !0, attributeFilter: ["style", "class"] }), window.addEventListener("resize", v), v(), () => {
313
+ cancelAnimationFrame(w), p.disconnect(), window.removeEventListener("resize", v), C();
311
314
  };
312
315
  }, [l, o, u]);
313
316
  }
314
- function Se() {
317
+ function Me() {
315
318
  const l = te(null);
316
- ve(l, { minDesktopWidth: 1200, forceResize: !1 }), P(() => (xe(), () => {
319
+ Ce(l, { minDesktopWidth: 1200, forceResize: !1 }), P(() => (ke(), () => {
317
320
  document.body.style.overflow = "";
318
321
  }), []);
319
- const [g, m] = d(null), [o, u] = d([]), [i, E] = d(4), [w, z] = d(!1), [x, v] = d(1), [f, r] = d(null), [a, y] = d("ready"), [k, S] = d(3), [T, A] = d(10), [C, H] = d(20), [ne, N] = d(0), [L, j] = d(!1), [F, $] = d(""), [R, D] = d(!1), [G, q] = d(!1), [V, M] = d(null), [oe, O] = d([]), [re, Z] = d([]), [b, ie] = d(!1), [ke, _] = d(1), [U, K] = d(null);
322
+ const [g, m] = d(null), [o, u] = d([]), [s, F] = d(4), [x, C] = d(!1), [w, v] = d(1), [p, i] = d(null), [a, y] = d("ready"), [k, S] = d(3), [T, B] = d(10), [z, E] = d(20), [ne, W] = d(0), [A, N] = d(!1), [H, Y] = d(""), [R, j] = d(!1), [D, $] = d(!1), [q, L] = d(null), [oe, G] = d([]), [re, Z] = d([]), [b, ie] = d(!1), [Se, _] = d(1), [U, K] = d(null);
320
323
  P(() => {
321
324
  const e = () => {
322
- const s = window.innerWidth < 768;
323
- if (ie(s), s)
325
+ const h = window.visualViewport, f = h ? Math.round(h.width) : window.innerWidth, I = h ? Math.round(h.height) : window.innerHeight, M = f < 768;
326
+ if (ie(M), M)
324
327
  K(null), _(1);
325
328
  else {
326
- const I = Math.min(window.innerWidth, window.innerHeight), B = Math.max(360, Math.round(I * 0.97)), W = Math.min(B, 1e3);
327
- K(W), _(1);
329
+ const ce = Math.min(f, I), me = Math.max(360, Math.round(ce * 0.97)), ge = Math.min(me, 1e3);
330
+ K(ge), _(1);
328
331
  }
329
332
  };
330
- return e(), window.addEventListener("resize", e), () => window.removeEventListener("resize", e);
333
+ e(), window.addEventListener("resize", e);
334
+ const r = window.visualViewport;
335
+ return r && typeof r.addEventListener == "function" && (r.addEventListener("resize", e), r.addEventListener("scroll", e)), () => {
336
+ window.removeEventListener("resize", e), r && typeof r.removeEventListener == "function" && (r.removeEventListener("resize", e), r.removeEventListener("scroll", e));
337
+ };
331
338
  }, []);
332
339
  const X = (e) => [...e].sort(() => Math.random() - 0.5).slice(0, 6), J = () => {
333
340
  if (!g) return;
334
341
  const e = X(ee[g]);
335
- u(e), z(!0), j(!1), v(1), N(0), O([]), Z([]), Q(e, [], !0);
336
- }, Q = (e = o, s = re, p = !1) => {
337
- const h = X(e.length ? e : ee[g]);
338
- let I = Math.floor(Math.random() * h.length), B = h[I].name, W = 0;
339
- for (; s.includes(B) && W < 20; )
340
- I = Math.floor(Math.random() * h.length), B = h[I].name, W++;
341
- u(h), r(I), Z([...s, B]), D(!1), $(""), H(20), M(null), p ? (y("ready"), S(3), A(10)) : (y("memorize"), A(10));
342
+ u(e), C(!0), N(!1), v(1), W(0), G([]), Z([]), Q(e, [], !0);
343
+ }, Q = (e = o, r = re, h = !1) => {
344
+ const f = X(e.length ? e : ee[g]);
345
+ let I = Math.floor(Math.random() * f.length), M = f[I].name, O = 0;
346
+ for (; r.includes(M) && O < 20; )
347
+ I = Math.floor(Math.random() * f.length), M = f[I].name, O++;
348
+ u(f), i(I), Z([...r, M]), j(!1), Y(""), E(20), L(null), h ? (y("ready"), S(3), B(10)) : (y("memorize"), B(10));
342
349
  };
343
350
  P(() => {
344
- if (!(!w || L || R)) {
351
+ if (!(!x || A || R)) {
345
352
  if (a === "ready")
346
353
  if (k <= 0) y("memorize");
347
354
  else {
348
- const e = setTimeout(() => S((s) => s - 1), 1e3);
355
+ const e = setTimeout(() => S((r) => r - 1), 1e3);
349
356
  return () => clearTimeout(e);
350
357
  }
351
358
  if (a === "memorize")
352
359
  if (T <= 0) y("guess");
353
360
  else {
354
- const e = setTimeout(() => A((s) => s - 1), 1e3);
361
+ const e = setTimeout(() => B((r) => r - 1), 1e3);
355
362
  return () => clearTimeout(e);
356
363
  }
357
364
  if (a === "guess") {
358
- if (C <= 0) {
359
- D(!0), M("wrong");
360
- const s = o[f].name;
361
- O((p) => [
362
- ...p,
363
- { round: x, answer: F, correct: s, result: "wrong" }
365
+ if (z <= 0) {
366
+ j(!0), L("wrong");
367
+ const r = o[p].name;
368
+ G((h) => [
369
+ ...h,
370
+ { round: w, answer: H, correct: r, result: "wrong" }
364
371
  ]);
365
372
  return;
366
373
  }
367
- const e = setTimeout(() => H((s) => s - 1), 1e3);
374
+ const e = setTimeout(() => E((r) => r - 1), 1e3);
368
375
  return () => clearTimeout(e);
369
376
  }
370
377
  }
371
- }, [a, k, T, C, w, L, R, o, f, x, F]);
378
+ }, [a, k, T, z, x, A, R, o, p, w, H]);
372
379
  const se = () => {
373
- if (f === null || G) return;
374
- const e = o[f].name, s = F.toLowerCase().trim();
375
- let p = "wrong";
376
- s === e ? (N((h) => h + 1), M("correct"), p = "correct") : we(s, e) === 1 ? (N((h) => h + 0.5), M("almost"), p = "almost") : (M("wrong"), p = "wrong"), O((h) => [...h, { round: x, answer: s, correct: e, result: p }]), q(!0), setTimeout(() => {
377
- q(!1), D(!0);
380
+ if (p === null || D) return;
381
+ const e = o[p].name, r = H.toLowerCase().trim();
382
+ let h = "wrong";
383
+ r === e ? (W((f) => f + 1), L("correct"), h = "correct") : ze(r, e) === 1 ? (W((f) => f + 0.5), L("almost"), h = "almost") : (L("wrong"), h = "wrong"), G((f) => [...f, { round: w, answer: r, correct: e, result: h }]), $(!0), setTimeout(() => {
384
+ $(!1), j(!0);
378
385
  }, 600);
379
- }, le = () => x < i ? (v((e) => e + 1), Q()) : j(!0), ae = () => {
380
- z(!1), j(!1), m(null);
381
- }, de = me(
386
+ }, le = () => w < s ? (v((e) => e + 1), Q()) : N(!0), ae = () => {
387
+ C(!1), N(!1), m(null);
388
+ }, de = he(
382
389
  () => (
383
390
  // ensure logo is positioned inside the square container
384
391
  /* @__PURE__ */ t("div", { style: { ...n.gmLogoFixed, position: "absolute", top: 16, left: 16, zIndex: 30 }, children: /* @__PURE__ */ c("picture", { children: [
@@ -432,7 +439,7 @@ function Se() {
432
439
  },
433
440
  children: /* @__PURE__ */ c("div", { id: "whats-missing-root", children: [
434
441
  !b && de,
435
- !g && !w && /* @__PURE__ */ c("div", { style: n.gmCenterScreen, children: [
442
+ !g && !x && /* @__PURE__ */ c("div", { style: n.gmCenterScreen, children: [
436
443
  /* @__PURE__ */ t("h1", { style: n.gmHeadline1, children: "WHAT'S MISSING?" }),
437
444
  /* @__PURE__ */ t("p", { style: n.gmBodyM, children: "Select a theme:" }),
438
445
  /* @__PURE__ */ t("div", { style: { display: "flex", gap: 16 }, children: ["animals", "food", "toys"].map((e) => /* @__PURE__ */ t("button", { style: n.gmButton, onClick: () => m(e), children: e === "animals" ? "🐶 Animals" : e === "food" ? "🍎 Food" : "🧸 Toys" }, e)) }),
@@ -443,33 +450,33 @@ function Se() {
443
450
  {
444
451
  style: {
445
452
  ...n.gmButton,
446
- ...i === e ? n.gmButtonActive : {}
453
+ ...s === e ? n.gmButtonActive : {}
447
454
  },
448
- onClick: () => E(e),
455
+ onClick: () => F(e),
449
456
  children: e
450
457
  },
451
458
  e
452
459
  )) })
453
460
  ] })
454
461
  ] }),
455
- g && !w && /* @__PURE__ */ c("div", { style: n.gmCenterScreen, children: [
462
+ g && !x && /* @__PURE__ */ c("div", { style: n.gmCenterScreen, children: [
456
463
  /* @__PURE__ */ c("h1", { style: n.gmHeadline1, children: [
457
464
  "Theme selected: ",
458
465
  g
459
466
  ] }),
460
467
  /* @__PURE__ */ c("p", { style: n.gmBodyM, children: [
461
468
  "Rounds: ",
462
- i
469
+ s
463
470
  ] }),
464
471
  /* @__PURE__ */ t("button", { style: n.gmButton, onClick: J, children: "▶ Start game" })
465
472
  ] }),
466
- L && /* @__PURE__ */ c("div", { style: n.gmCenterScreen, children: [
473
+ A && /* @__PURE__ */ c("div", { style: n.gmCenterScreen, children: [
467
474
  /* @__PURE__ */ t("h1", { style: n.gmHeadline1, children: "Results" }),
468
475
  /* @__PURE__ */ c("h2", { style: n.gmHeadline3, children: [
469
476
  "Your score: ",
470
477
  ne,
471
478
  " / ",
472
- i
479
+ s
473
480
  ] }),
474
481
  /* @__PURE__ */ t("p", { style: { ...n.gmBodyM, color: "#10b981", marginTop: 12 }, children: "Yahoo! You did it! 🍬✨" }),
475
482
  /* @__PURE__ */ c("table", { style: n.gmTable, children: [
@@ -479,19 +486,19 @@ function Se() {
479
486
  /* @__PURE__ */ t("th", { children: "Correct" }),
480
487
  /* @__PURE__ */ t("th", { children: "Result" })
481
488
  ] }) }),
482
- /* @__PURE__ */ t("tbody", { children: oe.map((e, s) => /* @__PURE__ */ c("tr", { children: [
489
+ /* @__PURE__ */ t("tbody", { children: oe.map((e, r) => /* @__PURE__ */ c("tr", { children: [
483
490
  /* @__PURE__ */ t("td", { style: n.gmTableCell, children: e.round }),
484
491
  /* @__PURE__ */ t("td", { style: n.gmTableCell, children: e.answer || "—" }),
485
492
  /* @__PURE__ */ t("td", { style: n.gmTableCell, children: e.correct }),
486
493
  /* @__PURE__ */ t("td", { style: n.gmTableCell, children: e.result === "correct" ? "✔ Correct" : e.result === "almost" ? "◐ Almost (0.5)" : "✘ Wrong" })
487
- ] }, s)) })
494
+ ] }, r)) })
488
495
  ] }),
489
496
  /* @__PURE__ */ c("div", { style: { display: "flex", gap: 12, marginTop: 24 }, children: [
490
497
  /* @__PURE__ */ t("button", { style: n.gmButton, onClick: J, children: "🔁 Play again" }),
491
498
  /* @__PURE__ */ t("button", { style: n.gmButton, onClick: ae, children: "⬅️ Choose theme" })
492
499
  ] })
493
500
  ] }),
494
- w && !L && /* @__PURE__ */ c("div", { style: n.gmGameLayout, children: [
501
+ x && !A && /* @__PURE__ */ c("div", { style: n.gmGameLayout, children: [
495
502
  /* @__PURE__ */ c(
496
503
  "div",
497
504
  {
@@ -503,7 +510,7 @@ function Se() {
503
510
  alignItems: "center"
504
511
  },
505
512
  children: [
506
- a === "ready" && /* @__PURE__ */ c(ce, { children: [
513
+ a === "ready" && /* @__PURE__ */ c(ue, { children: [
507
514
  /* @__PURE__ */ t("h1", { style: { ...n.gmHeadline1, color: "#ec4c44" }, children: "GET READY" }),
508
515
  /* @__PURE__ */ t("div", { style: n.gmHourglass, children: "⏳" })
509
516
  ] }),
@@ -514,7 +521,7 @@ function Se() {
514
521
  ] }),
515
522
  a === "guess" && !R && /* @__PURE__ */ c("p", { style: n.gmBodyM, children: [
516
523
  "⏳ Time left: ",
517
- C,
524
+ z,
518
525
  "s"
519
526
  ] })
520
527
  ]
@@ -530,17 +537,17 @@ function Se() {
530
537
  gap: b ? "12px" : "20px",
531
538
  justifyItems: "center"
532
539
  },
533
- children: o.map((e, s) => {
534
- const p = f === s && a === "guess" && !R;
540
+ children: o.map((e, r) => {
541
+ const h = p === r && a === "guess" && !R;
535
542
  return /* @__PURE__ */ t(
536
543
  "div",
537
544
  {
538
545
  style: {
539
546
  ...n.gmCard,
540
- ...V === "correct" && f === s ? n.gmCorrect : {},
541
- ...V === "wrong" && f === s ? n.gmWrong : {}
547
+ ...q === "correct" && p === r ? n.gmCorrect : {},
548
+ ...q === "wrong" && p === r ? n.gmWrong : {}
542
549
  },
543
- children: !p && /* @__PURE__ */ t(
550
+ children: !h && /* @__PURE__ */ t(
544
551
  "img",
545
552
  {
546
553
  src: e.src,
@@ -553,7 +560,7 @@ function Se() {
553
560
  }
554
561
  )
555
562
  },
556
- s
563
+ r
557
564
  );
558
565
  })
559
566
  }
@@ -565,8 +572,8 @@ function Se() {
565
572
  {
566
573
  type: "text",
567
574
  placeholder: "Type the missing word",
568
- value: F,
569
- onChange: (e) => $(e.target.value),
575
+ value: H,
576
+ onChange: (e) => Y(e.target.value),
570
577
  style: n.gmInput
571
578
  }
572
579
  ),
@@ -575,8 +582,8 @@ function Se() {
575
582
  {
576
583
  style: { ...n.gmButton, marginLeft: 8 },
577
584
  onClick: se,
578
- disabled: G,
579
- children: G ? "..." : "Check"
585
+ disabled: D,
586
+ children: D ? "..." : "Check"
580
587
  }
581
588
  )
582
589
  ] }),
@@ -592,6 +599,6 @@ function Se() {
592
599
  );
593
600
  }
594
601
  export {
595
- Se as Game,
602
+ Me as Game,
596
603
  ee as themes
597
604
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mblinkov/whats-missing",
3
- "version": "20.0.20",
3
+ "version": "20.0.21",
4
4
  "main": "dist/whats-missing.umd.js",
5
5
  "module": "dist/whats-missing.es.js",
6
6
  "types": "dist/index.d.ts",
@@ -25,7 +25,9 @@ export const styles: Record<string, CSSProperties> = {
25
25
  gmCenterScreen: {
26
26
  position: "relative",
27
27
  zIndex: 1,
28
- minHeight: "100vh",
28
+ // use percent so the component fits inside the centered square container
29
+ // (100vh caused overflow on tablets because it measured the viewport, not the container)
30
+ minHeight: "100%",
29
31
  width: "100%",
30
32
  display: "flex",
31
33
  flexDirection: "column",
@@ -100,7 +102,8 @@ export const styles: Record<string, CSSProperties> = {
100
102
  position: "relative",
101
103
  width: "100%",
102
104
  maxWidth: "600px",
103
- minHeight: "100vh",
105
+ // should fill the parent square, not the full viewport
106
+ minHeight: "100%",
104
107
  display: "flex",
105
108
  flexDirection: "column",
106
109
  alignItems: "center",
@@ -203,7 +206,8 @@ export const styles: Record<string, CSSProperties> = {
203
206
  flexDirection: "column",
204
207
  alignItems: "center",
205
208
  justifyContent: "center",
206
- height: "60vh",
209
+ // use percent so the wrapper scales with the container square
210
+ height: "60%",
207
211
  gap: "16px",
208
212
  },
209
213
 
package/src/Game.tsx CHANGED
@@ -213,34 +213,54 @@ export default function Game() {
213
213
 
214
214
  // ✅ адаптив под мобилки, планшеты и десктоп
215
215
  useEffect(() => {
216
- const resize = () => {
217
- const mobile = window.innerWidth < 768;
218
- const tablet = window.innerWidth >= 768 && window.innerWidth < 1200;
219
-
220
-
221
- // treat only phones as "mobile" so tablets use the desktop (square/centered) layout
222
- setIsMobile(mobile);
223
-
224
-
225
- if (mobile) {
226
- // mobile: fluid full-width layout
227
- setContainerSize(null);
228
- setScale(1);
229
- } else {
230
- // tablets and desktops: fit into a centered square (max 1000)
231
- const safeFactor = 0.97;
232
- const maxSquare = 1000;
233
- const available = Math.min(window.innerWidth, window.innerHeight);
234
- const sizePx = Math.max(360, Math.round(available * safeFactor)); // don't go too small
235
- const finalSize = Math.min(sizePx, maxSquare);
236
- setContainerSize(finalSize);
237
- setScale(1);
238
- }
239
- };
240
- resize();
241
- window.addEventListener("resize", resize);
242
- return () => window.removeEventListener("resize", resize);
243
- }, []);
216
+ const resize = () => {
217
+ // Prefer visualViewport when available — it's more accurate under page zoom
218
+ const vv = (window as any).visualViewport;
219
+ const vw = vv ? Math.round(vv.width) : window.innerWidth;
220
+ const vh = vv ? Math.round(vv.height) : window.innerHeight;
221
+
222
+ const mobile = vw < 768;
223
+ // tablet flag kept for possible future use
224
+ const tablet = vw >= 768 && vw < 1200;
225
+
226
+ // treat only phones as "mobile" so tablets use the desktop (square/centered) layout
227
+ setIsMobile(mobile);
228
+
229
+ if (mobile) {
230
+ // mobile: fluid full-width layout
231
+ setContainerSize(null);
232
+ setScale(1);
233
+ } else {
234
+ // tablets and desktops: fit into a centered square (max 1000)
235
+ const safeFactor = 0.97;
236
+ const maxSquare = 1000;
237
+ const available = Math.min(vw, vh);
238
+ const sizePx = Math.max(360, Math.round(available * safeFactor)); // don't go too small
239
+ const finalSize = Math.min(sizePx, maxSquare);
240
+ setContainerSize(finalSize);
241
+ setScale(1);
242
+ }
243
+ };
244
+
245
+ // run once
246
+ resize();
247
+
248
+ // listen to both window and visualViewport (if available) since some browsers update only visualViewport on zoom
249
+ window.addEventListener("resize", resize);
250
+ const vv = (window as any).visualViewport;
251
+ if (vv && typeof vv.addEventListener === "function") {
252
+ vv.addEventListener("resize", resize);
253
+ vv.addEventListener("scroll", resize);
254
+ }
255
+
256
+ return () => {
257
+ window.removeEventListener("resize", resize);
258
+ if (vv && typeof vv.removeEventListener === "function") {
259
+ vv.removeEventListener("resize", resize);
260
+ vv.removeEventListener("scroll", resize);
261
+ }
262
+ };
263
+ }, []);
244
264
 
245
265
 
246
266
  const getRandomSix = (arr: ImageItem[]) =>