@limrun/ui 0.17.0-rc.1 → 0.17.0-rc.2

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.
Files changed (83) hide show
  1. package/README.md +18 -3
  2. package/dist/{GLTFLoader-DW6wpvyR.mjs → GLTFLoader-Cami_vza.mjs} +1 -1
  3. package/dist/{GLTFLoader-BKnsBFsj.js → GLTFLoader-DeCLxW_q.js} +1 -1
  4. package/dist/components/duo-fold-motion.d.ts +1 -1
  5. package/dist/components/duo-loading.d.ts +8 -0
  6. package/dist/components/duo-view.d.ts +6 -1
  7. package/dist/{duo-frame-BzyYljix.mjs → duo-frame-Cmw4p2uN.mjs} +414 -414
  8. package/dist/{duo-frame-DjfA4gG-.js → duo-frame-iMtrvx_a.js} +18 -18
  9. package/dist/duo-view-BAh-w2Kz.js +1 -0
  10. package/dist/duo-view-D9Ae00rj.mjs +512 -0
  11. package/dist/index.cjs +1 -1
  12. package/dist/index.css +1 -1
  13. package/dist/index.js +2 -2
  14. package/dist/lite.cjs +1 -1
  15. package/dist/lite.js +1 -1
  16. package/dist/remote-control-B2jZpf3c.js +1 -0
  17. package/dist/remote-control-DiddxS8l.mjs +2883 -0
  18. package/package.json +5 -1
  19. package/dist/demo.d.ts +0 -1
  20. package/dist/duo-view-COZg8ieG.js +0 -1
  21. package/dist/duo-view-o1yxIzxu.mjs +0 -654
  22. package/dist/remote-control-CQjSEVDF.mjs +0 -2673
  23. package/dist/remote-control-DVRXfCR2.js +0 -1
  24. package/index.html +0 -199
  25. package/src/assets/Apple_logo_white.svg +0 -4
  26. package/src/assets/android_boot.gif +0 -0
  27. package/src/assets/android_boot.webp +0 -0
  28. package/src/assets/iphone16pro_black.webp +0 -0
  29. package/src/assets/iphone16pro_black_bg.webp +0 -0
  30. package/src/assets/iphone16pro_black_landscape.webp +0 -0
  31. package/src/assets/iphone16pro_black_landscape_bg.webp +0 -0
  32. package/src/assets/pixel9_black.webp +0 -0
  33. package/src/assets/pixel9_black_landscape.webp +0 -0
  34. package/src/assets/pixel_tablet_landscape.webp +0 -0
  35. package/src/assets/pixel_tablet_portrait.webp +0 -0
  36. package/src/components/device-install/index.ts +0 -1
  37. package/src/components/duo-button-hinge.test.tsx +0 -138
  38. package/src/components/duo-button-hinge.ts +0 -75
  39. package/src/components/duo-controls.tsx +0 -142
  40. package/src/components/duo-flat-frame.tsx +0 -145
  41. package/src/components/duo-flat-geometry.test.ts +0 -63
  42. package/src/components/duo-flat-geometry.ts +0 -97
  43. package/src/components/duo-fold-motion.test.tsx +0 -245
  44. package/src/components/duo-fold-motion.tsx +0 -192
  45. package/src/components/duo-fold-renderer.test.ts +0 -29
  46. package/src/components/duo-fold-renderer.ts +0 -397
  47. package/src/components/duo-fold-timing.test.ts +0 -44
  48. package/src/components/duo-fold-timing.ts +0 -9
  49. package/src/components/duo-frame.tsx +0 -579
  50. package/src/components/duo-hardware.test.ts +0 -61
  51. package/src/components/duo-hardware.ts +0 -61
  52. package/src/components/duo-model.test.ts +0 -243
  53. package/src/components/duo-model.ts +0 -607
  54. package/src/components/duo-screen-handoff.ts +0 -52
  55. package/src/components/duo-view.test.tsx +0 -104
  56. package/src/components/duo-view.tsx +0 -315
  57. package/src/components/inspect-overlay.css +0 -223
  58. package/src/components/inspect-overlay.tsx +0 -437
  59. package/src/components/remote-control-framed.tsx +0 -14
  60. package/src/components/remote-control.css +0 -441
  61. package/src/components/remote-control.test.ts +0 -34
  62. package/src/components/remote-control.tsx +0 -3989
  63. package/src/core/ax-fetcher.test.ts +0 -418
  64. package/src/core/ax-fetcher.ts +0 -387
  65. package/src/core/ax-tree.test.ts +0 -491
  66. package/src/core/ax-tree.ts +0 -416
  67. package/src/core/camera.test.ts +0 -155
  68. package/src/core/camera.ts +0 -133
  69. package/src/core/constants.ts +0 -344
  70. package/src/core/duo.test.ts +0 -142
  71. package/src/core/duo.ts +0 -156
  72. package/src/core/webrtc-messages.ts +0 -148
  73. package/src/demo.tsx +0 -283
  74. package/src/frame-assets.ts +0 -22
  75. package/src/hooks/index.ts +0 -1
  76. package/src/index.ts +0 -29
  77. package/src/lite.test.ts +0 -30
  78. package/src/lite.ts +0 -30
  79. package/src/vite-env.d.ts +0 -1
  80. package/tsconfig.json +0 -26
  81. package/tsconfig.node.json +0 -26
  82. package/vite.config.ts +0 -35
  83. package/vitest.config.ts +0 -24
@@ -0,0 +1 @@
1
+ "use strict";const n=require("react/jsx-runtime"),s=require("react"),j=require("./remote-control-B2jZpf3c.js");function K(e,o,r){const[c,d]=s.useState(e),u=s.useRef({nativeAngle:e,send:o,failed:r});u.current={nativeAngle:e,send:o,failed:r};const l=s.useRef(void 0),m=s.useRef(!1),h=s.useRef(null);return s.useEffect(()=>(h.current=new j.HingeSender(async f=>{await u.current.send(f),l.current===f&&(l.current=void 0)},f=>{l.current=void 0,u.current.failed(String(f)),d(u.current.nativeAngle)}),()=>h.current?.stop()),[]),s.useEffect(()=>{!m.current&&l.current===void 0&&d(e)},[e]),{angle:c,changeAngle:f=>{u.current.failed(void 0),l.current=f,d(f),h.current?.set(f)},interacting:m}}function $({angle:e,changeAngle:o,interacting:r,rotate:c,onFold:d,foldTarget:u,onHingeDrag:l,children:m}){const h=s.useId();return n.jsxs("div",{className:"rc-duo-controls",onPointerDown:a=>a.stopPropagation(),children:[n.jsxs("div",{className:"rc-duo-hinge",children:[n.jsx("button",{className:"rc-duo-fold",onClick:d??(()=>o(e<90?180:0)),children:(u??e)<90?"Unfold":"Fold"}),n.jsx("label",{htmlFor:h,children:"Hinge"}),n.jsx("input",{id:h,type:"range",min:0,max:180,step:1,value:e,onPointerDown:a=>{l?.(),r.current=!0,a.currentTarget.setPointerCapture(a.pointerId)},onPointerUp:()=>{r.current=!1},onPointerCancel:()=>{r.current=!1},onLostPointerCapture:()=>{r.current=!1},onChange:a=>o(Number(a.target.value))}),n.jsxs("output",{children:[Math.round(e),"°"]}),n.jsx("button",{className:"rc-duo-rotate","aria-label":"Rotate device",title:"Rotate device",onClick:c,children:n.jsxs("svg",{viewBox:"0 0 24 24",width:"18",height:"18",fill:"none",stroke:"currentColor",strokeWidth:"1.6","aria-hidden":"true",children:[n.jsx("rect",{x:"7",y:"3",width:"10",height:"18",rx:"2"}),n.jsx("path",{d:"M3 9a9 9 0 0 1 3-5M3 4v5h5M21 15a9 9 0 0 1-3 5m3 0v-5h-5"})]})})]}),m&&n.jsx("div",{className:"rc-duo-views","aria-label":"Device view",children:m})]})}function X({button:e}){return n.jsx("svg",{viewBox:"0 0 24 24",width:"24",height:"24",fill:"none",stroke:"currentColor",strokeWidth:"1.7",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:e==="side"?n.jsxs(n.Fragment,{children:[n.jsx("rect",{x:"6",y:"10",width:"12",height:"11",rx:"2"}),n.jsx("path",{d:"M8 10V7a4 4 0 0 1 8 0v3"})]}):n.jsxs(n.Fragment,{children:[n.jsx("path",{d:"M3 9h4l5-5v16l-5-5H3zM17 12h5"}),e==="volumeUp"&&n.jsx("path",{d:"M19.5 9.5v5"})]})})}function B(e){if(!e||e.readyState<2||!e.videoWidth||!e.videoHeight)return;const o=Math.min(1,1024/Math.max(e.videoWidth,e.videoHeight)),r=document.createElement("canvas");try{const c=r.getContext("2d");return c?(r.width=Math.round(e.videoWidth*o),r.height=Math.round(e.videoHeight*o),c.drawImage(e,0,0,r.width,r.height),r):void 0}catch{return}}function Q(e,o){let r=!1,c;const d=a=>{r||(h(),o(a))},u=()=>{if(r)return;const a=B(e);a&&d(a)},l=()=>{c=void 0,u(),r||(c=e?.requestVideoFrameCallback?.(l))},m=setTimeout(()=>d(void 0),2500);c=e?.requestVideoFrameCallback?.(l),e?.addEventListener("loadeddata",u),!e?.requestVideoFrameCallback&&e&&e.readyState>=2&&u();function h(){r=!0,clearTimeout(m),c!==void 0&&e?.cancelVideoFrameCallback(c),e?.removeEventListener("loadeddata",u)}return h}function Z(e,o,r,c,d=!0){const u=s.useRef(void 0),l=s.useRef(c),m=s.useRef({inner:o,frame:r});m.current={inner:o,frame:r};const[h,a]=s.useState(),f=s.useRef(void 0),S=s.useRef(void 0),P=s.useCallback(()=>{clearTimeout(S.current),f.current=void 0,a(void 0)},[]),H=g=>{if(!d||g===o){P();return}if(window.matchMedia?.("(prefers-reduced-motion: reduce)").matches||f.current)return;const b=B(e.current);if(!b)return;const p=m.current;f.current={from:p,to:p,before:b,ready:!1},a(f.current),S.current=setTimeout(P,5e3)};return s.useEffect(()=>()=>clearTimeout(S.current),[]),s.useLayoutEffect(()=>{const g=u.current,b={inner:o,frame:r};u.current=b;const p=l.current!==c;if(l.current=c,!g)return;const y=Math.abs(g.frame.rect.min.x+g.frame.rect.max.x-r.rect.min.x-r.rect.max.x)>.5||Math.abs(g.frame.rect.min.y+g.frame.rect.max.y-r.rect.min.y-r.rect.max.y)>.5;if(!d||y||p){P();return}if(g.inner===o||(a(void 0),!g.frame.scale||!r.scale)||window.matchMedia?.("(prefers-reduced-motion: reduce)").matches)return;const D=f.current?.before??B(e.current),x=f.current?.from??g;clearTimeout(S.current),f.current=void 0,D&&(b.frame=j.flatFrameGeometry(o,(x.frame.turns+(o?1:0))%4,r.rect.min.x+r.rect.max.x,r.rect.min.y+r.rect.max.y),a({from:x,to:b,before:D,ready:!1}))},[o,r.scale,r.turns,r.rect.min.x,r.rect.min.y,c,d]),s.useEffect(()=>{if(!h||h.from.inner===o)return;const g=Q(e.current,y=>{y?a(D=>D&&{...D,after:y,ready:!0}):P()}),b=window.matchMedia?.("(prefers-reduced-motion: reduce)"),p=()=>{b?.matches&&a(void 0)};return b?.addEventListener("change",p),()=>{g(),b?.removeEventListener("change",p)}},[h?.from,o]),{motion:h,finish:P,prepare:H}}function ee({pose:e,image:o,scale:r}){const{bodyWidth:c,bodyHeight:d,screenWidth:u,screenHeight:l}=e.frame,m=u*r,h=l*r;return n.jsxs("div",{className:"rc-duo-fold-still",style:{width:c*r,height:d*r},children:[n.jsx(j.DuoFlatFrame,{inner:e.inner,width:c,height:d}),n.jsx("div",{className:"rc-duo-flat-screen",style:{width:m,height:h,left:(c-u)*r/2,top:(d-l)*r/2,borderRadius:e.inner?5.3*r:[.8,6.6,6.6,.8].map(a=>a*r+"px").join(" ")},children:o&&n.jsx("canvas",{ref:a=>{a&&(a.width=o.width,a.height=o.height,a.getContext("2d")?.drawImage(o,0,0))},style:{width:e.inner?h:m,height:e.inner?m:h,transform:`translate(-50%, -50%) rotate(${e.inner?90:0}deg)`}})})]})}function te({motion:e,onFinish:o}){const r=s.useRef(null),[c,d]=s.useState(!1);return s.useEffect(()=>{if(d(!1),!e.ready)return;let u=!1,l;return Promise.resolve().then(()=>require("./duo-fold-renderer-DdltAnF7.js")).then(({renderFold:m})=>{u||!r.current||(l=m(r.current,e,o),d(!0))}).catch(()=>{u||o()}),()=>{u=!0,l?.()}},[e.ready,e.from,o]),n.jsxs(n.Fragment,{children:[!c&&n.jsx("div",{className:"rc-duo-fold-hold","aria-hidden":"true",style:{width:e.from.frame.bodyWidth*e.from.frame.scale,height:e.from.frame.bodyHeight*e.from.frame.scale,transform:`translate(-50%, -50%) rotate(${e.from.frame.turns*90}deg)`},children:n.jsx(ee,{pose:e.from,image:e.before,scale:e.from.frame.scale})}),n.jsx("canvas",{ref:r,className:"rc-duo-fold-canvas","aria-hidden":"true",style:{visibility:c?"visible":"hidden"}})]})}const re=s.lazy(()=>Promise.resolve().then(()=>require("./duo-frame-iMtrvx_a.js")).then(e=>e.duoFrame));function ne(e){const[o,r]=s.useState("2d");return n.jsxs("div",{className:"rc-duo-view",children:[e.showFrame!==!1&&o==="3d"?n.jsx(s.Suspense,{fallback:n.jsx(_,{...e}),children:n.jsx(re,{...e})}):n.jsx(_,{...e}),e.showFrame!==!1&&n.jsxs("div",{className:"rc-duo-mode",role:"group","aria-label":"Device rendering",children:[n.jsx("button",{type:"button","aria-pressed":o==="2d",onClick:()=>r("2d"),children:"2D"}),n.jsx("button",{type:"button","aria-pressed":o==="3d",onClick:()=>r("3d"),children:"3D"})]})]})}function _(e){const o=e.showFrame!==!1,r=s.useRef(null),c=s.useRef(null),d=s.useRef(e);d.current=e;const[u,l]=s.useState({width:0,height:0}),[m,h]=s.useState(!1),[a,f]=s.useState(),[S,P]=s.useState(),[H,g]=s.useState(),[b,p]=s.useState(),y=s.useRef(void 0),D=s.useRef(null),x=e.state.displays.find(t=>t.id===(e.state.angleDegrees<90?"outer":"inner")),C=x?.id==="inner"?e.inner:e.outer,I=x?.orientation===2?2:x?.orientation===3?1:x?.orientation===4?3:0,M=x?.id==="inner",w=j.flatFrameGeometry(M,I,u.width,u.height),O=o?w.screenWidth:(M?x?.height:x?.width)??1,L=o?w.screenHeight:(M?x?.width:x?.height)??1,F=o?w.bodyWidth:O,E=o?w.bodyHeight:L,v=o?w.scale:Math.max(0,Math.min(u.width/(w.turns%2?E:F),u.height/(w.turns%2?F:E))),U=O*v,W=L*v;s.useEffect(()=>{const t=new ResizeObserver(([i])=>{i&&l({width:i.contentRect.width,height:i.contentRect.height})});return r.current&&t.observe(r.current),()=>t.disconnect()},[]),s.useEffect(()=>{const t=c.current;if(!t||!C)return;const i=()=>{t.srcObject!==C.srcObject&&(t.srcObject=C.srcObject),t.play().catch(()=>{}),e.outer?.pause(),e.inner?.pause()};return i(),C.addEventListener("loadedmetadata",i),()=>{C.removeEventListener("loadedmetadata",i),t.pause(),t.srcObject=null;for(const k of[e.outer,e.inner])k?.play().catch(()=>{})}},[C,e.outer,e.inner]);const{motion:R,finish:z,prepare:Y}=Z(c,M,w,e.state.orientation,o),{angle:G,changeAngle:A,interacting:J}=K(e.state.angleDegrees,async t=>{Y(t>=90);try{await e.setAngle(t)}catch(i){throw z(),i}},f),N=()=>{if(!y.current)return;const{screenId:t,x:i,y:k}=y.current;d.current.touch(1,t,i,k),y.current=void 0};s.useEffect(()=>{D.current=new j.DuoButtonSender((i,k)=>d.current.button(i,k),i=>f(String(i)));const t=()=>{N(),D.current?.release(),p(void 0)};return window.addEventListener("blur",t),()=>{t(),window.removeEventListener("blur",t)}},[]),s.useEffect(()=>{N()},[x?.screenId,I]);const T=()=>{D.current?.release(),p(void 0)},V=t=>({onPointerDown:i=>{R||i.button!==0||(i.currentTarget.setPointerCapture(i.pointerId),D.current?.press(t),p(t))},onPointerUp:T,onPointerCancel:T,onLostPointerCapture:T,onBlur:T,onPointerEnter:()=>g(t),onPointerLeave:()=>g(void 0),onFocus:()=>P(w.guides.find(i=>i.button===t)?.edge),onKeyDown:i=>{R||(i.key==="Enter"||i.key===" ")&&(i.preventDefault(),i.repeat||(D.current?.press(t),p(t)))},onKeyUp:i=>{(i.key==="Enter"||i.key===" ")&&(i.preventDefault(),T())}}),q=t=>{const i=t.currentTarget.getBoundingClientRect();return j.flatDisplayTouch((t.clientX-i.left)/i.width,(t.clientY-i.top)/i.height,I)};return n.jsxs("div",{className:o?"rc-duo":"rc-duo rc-duo-frameless",children:[n.jsxs("div",{ref:r,className:"rc-duo-flat-stage","data-folding":!!R,"aria-busy":!!R,onPointerMove:t=>{if(!o)return;const i=t.currentTarget.getBoundingClientRect();P(j.flatHoverEdge(t.clientX-i.left,t.clientY-i.top,w.rect))},onPointerLeave:()=>{P(void 0),g(void 0)},children:[n.jsxs("div",{className:"rc-duo-flat-device","data-display":M?"inner":"outer",style:{width:F*v,height:E*v,transform:"translate(-50%, -50%) rotate("+w.turns*90+"deg)"},children:[o&&n.jsx(j.DuoFlatFrame,{inner:M,width:F,height:E}),n.jsxs("div",{className:"rc-duo-flat-screen",role:"application","aria-label":"iPhone Duo 2D simulator",tabIndex:0,style:{width:U,height:W,left:(F-O)/2*v,top:(E-L)/2*v,borderRadius:o?M?5.3*v:[.8,6.6,6.6,.8].map(t=>t*v+"px").join(" "):0},onKeyDown:R?void 0:e.onKeyDown,onKeyUp:e.onKeyUp,onPointerDown:t=>{if(R||y.current||t.button!==0||!x)return;t.currentTarget.focus({preventScroll:!0}),t.currentTarget.setPointerCapture(t.pointerId);const i=q(t);y.current={pointer:t.pointerId,screenId:x.screenId,...i},e.touch(0,x.screenId,i.x,i.y)},onPointerMove:t=>{if(y.current?.pointer!==t.pointerId)return;const i=q(t);Object.assign(y.current,i),e.touch(2,y.current.screenId,i.x,i.y)},onPointerUp:t=>{y.current?.pointer===t.pointerId&&N()},onPointerCancel:N,onLostPointerCapture:N,children:[n.jsx("video",{ref:c,onPlaying:()=>h(!0),autoPlay:!0,muted:!0,playsInline:!0,style:{width:M?W:U,height:M?U:W,transform:"translate(-50%, -50%) rotate("+(M?90:0)+"deg)"}}),!m&&n.jsx(j.DuoLoadingScreen,{logo:e.loadingLogo})]}),o&&w.buttons.map(t=>n.jsx("button",{type:"button",className:"rc-duo-physical","data-duo-button":t.button,"data-edge":t.edge,"data-highlighted":H===t.button,"data-pressed":b===t.button,"aria-label":j.DUO_BUTTONS[t.button]+" physical button",title:j.DUO_BUTTONS[t.button],style:{left:t.x*v,top:t.y*v,width:t.edge==="top"?Math.max(28,t.width*v):28,height:t.edge==="top"?28:Math.max(28,t.height*v)},...V(t.button),children:n.jsx("span",{style:{width:Math.max(2,t.width*v),height:Math.max(2,t.height*v)}})},t.button))]}),o&&w.guides.map(t=>n.jsx("button",{type:"button",className:"rc-duo-hardware","data-duo-button":t.button,"data-visible":S===t.edge,"data-pressed":b===t.button,"aria-label":j.DUO_BUTTONS[t.button],title:j.DUO_BUTTONS[t.button],style:{left:t.targetX,top:t.targetY,"--duo-hardware-icon-size":`${w.iconSize}px`,"--duo-hardware-icon-x":`${t.x-t.targetX}px`,"--duo-hardware-icon-y":`${t.y-t.targetY}px`},...V(t.button),children:n.jsx(X,{button:t.button})},t.button)),R&&n.jsx(te,{motion:R,onFinish:z})]}),o&&n.jsx($,{angle:G,changeAngle:A,interacting:J,rotate:()=>{e.setOrientation(e.state.orientation==="portrait"?"landscape-left":"portrait").catch(t=>f(String(t)))},children:n.jsx("span",{className:"rc-duo-view-label",children:"Front view"})}),a&&n.jsx("div",{role:"alert",className:"rc-duo-error",children:a})]})}const oe=Object.freeze(Object.defineProperty({__proto__:null,default:ne},Symbol.toStringTag,{value:"Module"}));exports.DuoControls=$;exports.DuoHardwareIcon=X;exports.duoView=oe;exports.useDuoHinge=K;
@@ -0,0 +1,512 @@
1
+ import { jsx as i, jsxs as p, Fragment as K } from "react/jsx-runtime";
2
+ import { useId as te, useState as C, useRef as y, useEffect as F, useCallback as re, useLayoutEffect as ne, Suspense as oe, lazy as ie } from "react";
3
+ import { H as ae, h as A, D as G, i as ce, j as se, k as O, l as de, m as ue } from "./remote-control-DiddxS8l.mjs";
4
+ function le(e, n, r) {
5
+ const [c, d] = C(e), s = y({ nativeAngle: e, send: n, failed: r });
6
+ s.current = { nativeAngle: e, send: n, failed: r };
7
+ const u = y(void 0), f = y(!1), l = y(null);
8
+ return F(() => (l.current = new ae(
9
+ async (h) => {
10
+ await s.current.send(h), u.current === h && (u.current = void 0);
11
+ },
12
+ (h) => {
13
+ u.current = void 0, s.current.failed(String(h)), d(s.current.nativeAngle);
14
+ }
15
+ ), () => l.current?.stop()), []), F(() => {
16
+ !f.current && u.current === void 0 && d(e);
17
+ }, [e]), { angle: c, changeAngle: (h) => {
18
+ s.current.failed(void 0), u.current = h, d(h), l.current?.set(h);
19
+ }, interacting: f };
20
+ }
21
+ function he({
22
+ angle: e,
23
+ changeAngle: n,
24
+ interacting: r,
25
+ rotate: c,
26
+ onFold: d,
27
+ foldTarget: s,
28
+ onHingeDrag: u,
29
+ children: f
30
+ }) {
31
+ const l = te();
32
+ return /* @__PURE__ */ p("div", { className: "rc-duo-controls", onPointerDown: (a) => a.stopPropagation(), children: [
33
+ /* @__PURE__ */ p("div", { className: "rc-duo-hinge", children: [
34
+ /* @__PURE__ */ i("button", { className: "rc-duo-fold", onClick: d ?? (() => n(e < 90 ? 180 : 0)), children: (s ?? e) < 90 ? "Unfold" : "Fold" }),
35
+ /* @__PURE__ */ i("label", { htmlFor: l, children: "Hinge" }),
36
+ /* @__PURE__ */ i(
37
+ "input",
38
+ {
39
+ id: l,
40
+ type: "range",
41
+ min: 0,
42
+ max: 180,
43
+ step: 1,
44
+ value: e,
45
+ onPointerDown: (a) => {
46
+ u?.(), r.current = !0, a.currentTarget.setPointerCapture(a.pointerId);
47
+ },
48
+ onPointerUp: () => {
49
+ r.current = !1;
50
+ },
51
+ onPointerCancel: () => {
52
+ r.current = !1;
53
+ },
54
+ onLostPointerCapture: () => {
55
+ r.current = !1;
56
+ },
57
+ onChange: (a) => n(Number(a.target.value))
58
+ }
59
+ ),
60
+ /* @__PURE__ */ p("output", { children: [
61
+ Math.round(e),
62
+ "°"
63
+ ] }),
64
+ /* @__PURE__ */ i("button", { className: "rc-duo-rotate", "aria-label": "Rotate device", title: "Rotate device", onClick: c, children: /* @__PURE__ */ p(
65
+ "svg",
66
+ {
67
+ viewBox: "0 0 24 24",
68
+ width: "18",
69
+ height: "18",
70
+ fill: "none",
71
+ stroke: "currentColor",
72
+ strokeWidth: "1.6",
73
+ "aria-hidden": "true",
74
+ children: [
75
+ /* @__PURE__ */ i("rect", { x: "7", y: "3", width: "10", height: "18", rx: "2" }),
76
+ /* @__PURE__ */ i("path", { d: "M3 9a9 9 0 0 1 3-5M3 4v5h5M21 15a9 9 0 0 1-3 5m3 0v-5h-5" })
77
+ ]
78
+ }
79
+ ) })
80
+ ] }),
81
+ f && /* @__PURE__ */ i("div", { className: "rc-duo-views", "aria-label": "Device view", children: f })
82
+ ] });
83
+ }
84
+ function fe({ button: e }) {
85
+ return /* @__PURE__ */ i(
86
+ "svg",
87
+ {
88
+ viewBox: "0 0 24 24",
89
+ width: "24",
90
+ height: "24",
91
+ fill: "none",
92
+ stroke: "currentColor",
93
+ strokeWidth: "1.7",
94
+ strokeLinecap: "round",
95
+ strokeLinejoin: "round",
96
+ "aria-hidden": "true",
97
+ children: e === "side" ? /* @__PURE__ */ p(K, { children: [
98
+ /* @__PURE__ */ i("rect", { x: "6", y: "10", width: "12", height: "11", rx: "2" }),
99
+ /* @__PURE__ */ i("path", { d: "M8 10V7a4 4 0 0 1 8 0v3" })
100
+ ] }) : /* @__PURE__ */ p(K, { children: [
101
+ /* @__PURE__ */ i("path", { d: "M3 9h4l5-5v16l-5-5H3zM17 12h5" }),
102
+ e === "volumeUp" && /* @__PURE__ */ i("path", { d: "M19.5 9.5v5" })
103
+ ] })
104
+ }
105
+ );
106
+ }
107
+ function _(e) {
108
+ if (!e || e.readyState < 2 || !e.videoWidth || !e.videoHeight) return;
109
+ const n = Math.min(1, 1024 / Math.max(e.videoWidth, e.videoHeight)), r = document.createElement("canvas");
110
+ try {
111
+ const c = r.getContext("2d");
112
+ return c ? (r.width = Math.round(e.videoWidth * n), r.height = Math.round(e.videoHeight * n), c.drawImage(e, 0, 0, r.width, r.height), r) : void 0;
113
+ } catch {
114
+ return;
115
+ }
116
+ }
117
+ function me(e, n) {
118
+ let r = !1, c;
119
+ const d = (a) => {
120
+ r || (l(), n(a));
121
+ }, s = () => {
122
+ if (r) return;
123
+ const a = _(e);
124
+ a && d(a);
125
+ }, u = () => {
126
+ c = void 0, s(), r || (c = e?.requestVideoFrameCallback?.(u));
127
+ }, f = setTimeout(() => d(void 0), 2500);
128
+ c = e?.requestVideoFrameCallback?.(u), e?.addEventListener("loadeddata", s), !e?.requestVideoFrameCallback && e && e.readyState >= 2 && s();
129
+ function l() {
130
+ r = !0, clearTimeout(f), c !== void 0 && e?.cancelVideoFrameCallback(c), e?.removeEventListener("loadeddata", s);
131
+ }
132
+ return l;
133
+ }
134
+ function ge(e, n, r, c, d = !0) {
135
+ const s = y(void 0), u = y(c), f = y({ inner: n, frame: r });
136
+ f.current = { inner: n, frame: r };
137
+ const [l, a] = C(), h = y(void 0), E = y(void 0), k = re(() => {
138
+ clearTimeout(E.current), h.current = void 0, a(void 0);
139
+ }, []), R = (m) => {
140
+ if (!d || m === n) {
141
+ k();
142
+ return;
143
+ }
144
+ if (window.matchMedia?.("(prefers-reduced-motion: reduce)").matches || h.current) return;
145
+ const x = _(e.current);
146
+ if (!x) return;
147
+ const D = f.current;
148
+ h.current = { from: D, to: D, before: x, ready: !1 }, a(h.current), E.current = setTimeout(k, 5e3);
149
+ };
150
+ return F(() => () => clearTimeout(E.current), []), ne(() => {
151
+ const m = s.current, x = { inner: n, frame: r };
152
+ s.current = x;
153
+ const D = u.current !== c;
154
+ if (u.current = c, !m) return;
155
+ const w = Math.abs(m.frame.rect.min.x + m.frame.rect.max.x - r.rect.min.x - r.rect.max.x) > 0.5 || Math.abs(m.frame.rect.min.y + m.frame.rect.max.y - r.rect.min.y - r.rect.max.y) > 0.5;
156
+ if (!d || w || D) {
157
+ k();
158
+ return;
159
+ }
160
+ if (m.inner === n || (a(void 0), !m.frame.scale || !r.scale) || window.matchMedia?.("(prefers-reduced-motion: reduce)").matches) return;
161
+ const M = h.current?.before ?? _(e.current), g = h.current?.from ?? m;
162
+ clearTimeout(E.current), h.current = void 0, M && (x.frame = A(
163
+ n,
164
+ (g.frame.turns + (n ? 1 : 0)) % 4,
165
+ r.rect.min.x + r.rect.max.x,
166
+ r.rect.min.y + r.rect.max.y
167
+ ), a({ from: g, to: x, before: M, ready: !1 }));
168
+ }, [n, r.scale, r.turns, r.rect.min.x, r.rect.min.y, c, d]), F(() => {
169
+ if (!l || l.from.inner === n) return;
170
+ const m = me(e.current, (w) => {
171
+ w ? a((M) => M && { ...M, after: w, ready: !0 }) : k();
172
+ }), x = window.matchMedia?.("(prefers-reduced-motion: reduce)"), D = () => {
173
+ x?.matches && a(void 0);
174
+ };
175
+ return x?.addEventListener("change", D), () => {
176
+ m(), x?.removeEventListener("change", D);
177
+ };
178
+ }, [l?.from, n]), { motion: l, finish: k, prepare: R };
179
+ }
180
+ function ye({ pose: e, image: n, scale: r }) {
181
+ const { bodyWidth: c, bodyHeight: d, screenWidth: s, screenHeight: u } = e.frame, f = s * r, l = u * r;
182
+ return /* @__PURE__ */ p("div", { className: "rc-duo-fold-still", style: { width: c * r, height: d * r }, children: [
183
+ /* @__PURE__ */ i(G, { inner: e.inner, width: c, height: d }),
184
+ /* @__PURE__ */ i(
185
+ "div",
186
+ {
187
+ className: "rc-duo-flat-screen",
188
+ style: {
189
+ width: f,
190
+ height: l,
191
+ left: (c - s) * r / 2,
192
+ top: (d - u) * r / 2,
193
+ borderRadius: e.inner ? 5.3 * r : [0.8, 6.6, 6.6, 0.8].map((a) => a * r + "px").join(" ")
194
+ },
195
+ children: n && /* @__PURE__ */ i(
196
+ "canvas",
197
+ {
198
+ ref: (a) => {
199
+ a && (a.width = n.width, a.height = n.height, a.getContext("2d")?.drawImage(n, 0, 0));
200
+ },
201
+ style: {
202
+ width: e.inner ? l : f,
203
+ height: e.inner ? f : l,
204
+ transform: `translate(-50%, -50%) rotate(${e.inner ? 90 : 0}deg)`
205
+ }
206
+ }
207
+ )
208
+ }
209
+ )
210
+ ] });
211
+ }
212
+ function we({ motion: e, onFinish: n }) {
213
+ const r = y(null), [c, d] = C(!1);
214
+ return F(() => {
215
+ if (d(!1), !e.ready) return;
216
+ let s = !1, u;
217
+ return import("./duo-fold-renderer-BXejNHcY.mjs").then(({ renderFold: f }) => {
218
+ s || !r.current || (u = f(r.current, e, n), d(!0));
219
+ }).catch(() => {
220
+ s || n();
221
+ }), () => {
222
+ s = !0, u?.();
223
+ };
224
+ }, [e.ready, e.from, n]), /* @__PURE__ */ p(K, { children: [
225
+ !c && /* @__PURE__ */ i(
226
+ "div",
227
+ {
228
+ className: "rc-duo-fold-hold",
229
+ "aria-hidden": "true",
230
+ style: {
231
+ width: e.from.frame.bodyWidth * e.from.frame.scale,
232
+ height: e.from.frame.bodyHeight * e.from.frame.scale,
233
+ transform: `translate(-50%, -50%) rotate(${e.from.frame.turns * 90}deg)`
234
+ },
235
+ children: /* @__PURE__ */ i(ye, { pose: e.from, image: e.before, scale: e.from.frame.scale })
236
+ }
237
+ ),
238
+ /* @__PURE__ */ i(
239
+ "canvas",
240
+ {
241
+ ref: r,
242
+ className: "rc-duo-fold-canvas",
243
+ "aria-hidden": "true",
244
+ style: { visibility: c ? "visible" : "hidden" }
245
+ }
246
+ )
247
+ ] });
248
+ }
249
+ const ve = ie(() => import("./duo-frame-Cmw4p2uN.mjs").then((e) => e.ac));
250
+ function be(e) {
251
+ const [n, r] = C("2d");
252
+ return /* @__PURE__ */ p("div", { className: "rc-duo-view", children: [
253
+ e.showFrame !== !1 && n === "3d" ? /* @__PURE__ */ i(oe, { fallback: /* @__PURE__ */ i(q, { ...e }), children: /* @__PURE__ */ i(ve, { ...e }) }) : /* @__PURE__ */ i(q, { ...e }),
254
+ e.showFrame !== !1 && /* @__PURE__ */ p("div", { className: "rc-duo-mode", role: "group", "aria-label": "Device rendering", children: [
255
+ /* @__PURE__ */ i("button", { type: "button", "aria-pressed": n === "2d", onClick: () => r("2d"), children: "2D" }),
256
+ /* @__PURE__ */ i("button", { type: "button", "aria-pressed": n === "3d", onClick: () => r("3d"), children: "3D" })
257
+ ] })
258
+ ] });
259
+ }
260
+ function q(e) {
261
+ const n = e.showFrame !== !1, r = y(null), c = y(null), d = y(e);
262
+ d.current = e;
263
+ const [s, u] = C({ width: 0, height: 0 }), [f, l] = C(!1), [a, h] = C(), [E, k] = C(), [R, m] = C(), [x, D] = C(), w = y(void 0), M = y(null), g = e.state.displays.find(
264
+ (t) => t.id === (e.state.angleDegrees < 90 ? "outer" : "inner")
265
+ ), H = g?.id === "inner" ? e.inner : e.outer, W = g?.orientation === 2 ? 2 : g?.orientation === 3 ? 1 : g?.orientation === 4 ? 3 : 0, P = g?.id === "inner", v = A(P, W, s.width, s.height), U = n ? v.screenWidth : (P ? g?.height : g?.width) ?? 1, z = n ? v.screenHeight : (P ? g?.width : g?.height) ?? 1, I = n ? v.bodyWidth : U, L = n ? v.bodyHeight : z, b = n ? v.scale : Math.max(
266
+ 0,
267
+ Math.min(
268
+ s.width / (v.turns % 2 ? L : I),
269
+ s.height / (v.turns % 2 ? I : L)
270
+ )
271
+ ), B = U * b, V = z * b;
272
+ F(() => {
273
+ const t = new ResizeObserver(([o]) => {
274
+ o && u({ width: o.contentRect.width, height: o.contentRect.height });
275
+ });
276
+ return r.current && t.observe(r.current), () => t.disconnect();
277
+ }, []), F(() => {
278
+ const t = c.current;
279
+ if (!t || !H) return;
280
+ const o = () => {
281
+ t.srcObject !== H.srcObject && (t.srcObject = H.srcObject), t.play().catch(() => {
282
+ }), e.outer?.pause(), e.inner?.pause();
283
+ };
284
+ return o(), H.addEventListener("loadedmetadata", o), () => {
285
+ H.removeEventListener("loadedmetadata", o), t.pause(), t.srcObject = null;
286
+ for (const j of [e.outer, e.inner]) j?.play().catch(() => {
287
+ });
288
+ };
289
+ }, [H, e.outer, e.inner]);
290
+ const {
291
+ motion: N,
292
+ finish: $,
293
+ prepare: J
294
+ } = ge(c, P, v, e.state.orientation, n), { angle: Q, changeAngle: Z, interacting: ee } = le(
295
+ e.state.angleDegrees,
296
+ async (t) => {
297
+ J(t >= 90);
298
+ try {
299
+ await e.setAngle(t);
300
+ } catch (o) {
301
+ throw $(), o;
302
+ }
303
+ },
304
+ h
305
+ ), T = () => {
306
+ if (!w.current) return;
307
+ const { screenId: t, x: o, y: j } = w.current;
308
+ d.current.touch(1, t, o, j), w.current = void 0;
309
+ };
310
+ F(() => {
311
+ M.current = new ce(
312
+ (o, j) => d.current.button(o, j),
313
+ (o) => h(String(o))
314
+ );
315
+ const t = () => {
316
+ T(), M.current?.release(), D(void 0);
317
+ };
318
+ return window.addEventListener("blur", t), () => {
319
+ t(), window.removeEventListener("blur", t);
320
+ };
321
+ }, []), F(() => {
322
+ T();
323
+ }, [g?.screenId, W]);
324
+ const S = () => {
325
+ M.current?.release(), D(void 0);
326
+ }, X = (t) => ({
327
+ onPointerDown: (o) => {
328
+ N || o.button !== 0 || (o.currentTarget.setPointerCapture(o.pointerId), M.current?.press(t), D(t));
329
+ },
330
+ onPointerUp: S,
331
+ onPointerCancel: S,
332
+ onLostPointerCapture: S,
333
+ onBlur: S,
334
+ onPointerEnter: () => m(t),
335
+ onPointerLeave: () => m(void 0),
336
+ onFocus: () => k(v.guides.find((o) => o.button === t)?.edge),
337
+ onKeyDown: (o) => {
338
+ N || (o.key === "Enter" || o.key === " ") && (o.preventDefault(), o.repeat || (M.current?.press(t), D(t)));
339
+ },
340
+ onKeyUp: (o) => {
341
+ (o.key === "Enter" || o.key === " ") && (o.preventDefault(), S());
342
+ }
343
+ }), Y = (t) => {
344
+ const o = t.currentTarget.getBoundingClientRect();
345
+ return ue(
346
+ (t.clientX - o.left) / o.width,
347
+ (t.clientY - o.top) / o.height,
348
+ W
349
+ );
350
+ };
351
+ return /* @__PURE__ */ p("div", { className: n ? "rc-duo" : "rc-duo rc-duo-frameless", children: [
352
+ /* @__PURE__ */ p(
353
+ "div",
354
+ {
355
+ ref: r,
356
+ className: "rc-duo-flat-stage",
357
+ "data-folding": !!N,
358
+ "aria-busy": !!N,
359
+ onPointerMove: (t) => {
360
+ if (!n) return;
361
+ const o = t.currentTarget.getBoundingClientRect();
362
+ k(de(t.clientX - o.left, t.clientY - o.top, v.rect));
363
+ },
364
+ onPointerLeave: () => {
365
+ k(void 0), m(void 0);
366
+ },
367
+ children: [
368
+ /* @__PURE__ */ p(
369
+ "div",
370
+ {
371
+ className: "rc-duo-flat-device",
372
+ "data-display": P ? "inner" : "outer",
373
+ style: {
374
+ width: I * b,
375
+ height: L * b,
376
+ transform: "translate(-50%, -50%) rotate(" + v.turns * 90 + "deg)"
377
+ },
378
+ children: [
379
+ n && /* @__PURE__ */ i(G, { inner: P, width: I, height: L }),
380
+ /* @__PURE__ */ p(
381
+ "div",
382
+ {
383
+ className: "rc-duo-flat-screen",
384
+ role: "application",
385
+ "aria-label": "iPhone Duo 2D simulator",
386
+ tabIndex: 0,
387
+ style: {
388
+ width: B,
389
+ height: V,
390
+ left: (I - U) / 2 * b,
391
+ top: (L - z) / 2 * b,
392
+ borderRadius: n ? P ? 5.3 * b : [0.8, 6.6, 6.6, 0.8].map((t) => t * b + "px").join(" ") : 0
393
+ },
394
+ onKeyDown: N ? void 0 : e.onKeyDown,
395
+ onKeyUp: e.onKeyUp,
396
+ onPointerDown: (t) => {
397
+ if (N || w.current || t.button !== 0 || !g) return;
398
+ t.currentTarget.focus({ preventScroll: !0 }), t.currentTarget.setPointerCapture(t.pointerId);
399
+ const o = Y(t);
400
+ w.current = { pointer: t.pointerId, screenId: g.screenId, ...o }, e.touch(0, g.screenId, o.x, o.y);
401
+ },
402
+ onPointerMove: (t) => {
403
+ if (w.current?.pointer !== t.pointerId) return;
404
+ const o = Y(t);
405
+ Object.assign(w.current, o), e.touch(2, w.current.screenId, o.x, o.y);
406
+ },
407
+ onPointerUp: (t) => {
408
+ w.current?.pointer === t.pointerId && T();
409
+ },
410
+ onPointerCancel: T,
411
+ onLostPointerCapture: T,
412
+ children: [
413
+ /* @__PURE__ */ i(
414
+ "video",
415
+ {
416
+ ref: c,
417
+ onPlaying: () => l(!0),
418
+ autoPlay: !0,
419
+ muted: !0,
420
+ playsInline: !0,
421
+ style: {
422
+ width: P ? V : B,
423
+ height: P ? B : V,
424
+ transform: "translate(-50%, -50%) rotate(" + (P ? 90 : 0) + "deg)"
425
+ }
426
+ }
427
+ ),
428
+ !f && /* @__PURE__ */ i(se, { logo: e.loadingLogo })
429
+ ]
430
+ }
431
+ ),
432
+ n && v.buttons.map((t) => /* @__PURE__ */ i(
433
+ "button",
434
+ {
435
+ type: "button",
436
+ className: "rc-duo-physical",
437
+ "data-duo-button": t.button,
438
+ "data-edge": t.edge,
439
+ "data-highlighted": R === t.button,
440
+ "data-pressed": x === t.button,
441
+ "aria-label": O[t.button] + " physical button",
442
+ title: O[t.button],
443
+ style: {
444
+ left: t.x * b,
445
+ top: t.y * b,
446
+ width: t.edge === "top" ? Math.max(28, t.width * b) : 28,
447
+ height: t.edge === "top" ? 28 : Math.max(28, t.height * b)
448
+ },
449
+ ...X(t.button),
450
+ children: /* @__PURE__ */ i(
451
+ "span",
452
+ {
453
+ style: { width: Math.max(2, t.width * b), height: Math.max(2, t.height * b) }
454
+ }
455
+ )
456
+ },
457
+ t.button
458
+ ))
459
+ ]
460
+ }
461
+ ),
462
+ n && v.guides.map((t) => /* @__PURE__ */ i(
463
+ "button",
464
+ {
465
+ type: "button",
466
+ className: "rc-duo-hardware",
467
+ "data-duo-button": t.button,
468
+ "data-visible": E === t.edge,
469
+ "data-pressed": x === t.button,
470
+ "aria-label": O[t.button],
471
+ title: O[t.button],
472
+ style: {
473
+ left: t.targetX,
474
+ top: t.targetY,
475
+ "--duo-hardware-icon-size": `${v.iconSize}px`,
476
+ "--duo-hardware-icon-x": `${t.x - t.targetX}px`,
477
+ "--duo-hardware-icon-y": `${t.y - t.targetY}px`
478
+ },
479
+ ...X(t.button),
480
+ children: /* @__PURE__ */ i(fe, { button: t.button })
481
+ },
482
+ t.button
483
+ )),
484
+ N && /* @__PURE__ */ i(we, { motion: N, onFinish: $ })
485
+ ]
486
+ }
487
+ ),
488
+ n && /* @__PURE__ */ i(
489
+ he,
490
+ {
491
+ angle: Q,
492
+ changeAngle: Z,
493
+ interacting: ee,
494
+ rotate: () => {
495
+ e.setOrientation(e.state.orientation === "portrait" ? "landscape-left" : "portrait").catch((t) => h(String(t)));
496
+ },
497
+ children: /* @__PURE__ */ i("span", { className: "rc-duo-view-label", children: "Front view" })
498
+ }
499
+ ),
500
+ a && /* @__PURE__ */ i("div", { role: "alert", className: "rc-duo-error", children: a })
501
+ ] });
502
+ }
503
+ const Me = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
504
+ __proto__: null,
505
+ default: be
506
+ }, Symbol.toStringTag, { value: "Module" }));
507
+ export {
508
+ fe as D,
509
+ he as a,
510
+ Me as d,
511
+ le as u
512
+ };