@toneflix/flipbook 0.2.3 → 0.2.4

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,8 +1,8 @@
1
- var Flipbook=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});let t=(e,t)=>({x:e.x-t.x,y:e.y-t.y}),n=(e,t)=>e.x*t.x+e.y*t.y,r=e=>Math.hypot(e.x,e.y);var i=class e{a;b;c;d;e;f;constructor(e=1,t=0,n=0,r=1,i=0,a=0){this.a=e,this.b=t,this.c=n,this.d=r,this.e=i,this.f=a}static translate(t,n){return new e(1,0,0,1,t,n)}static rotate(t){let n=Math.cos(t),r=Math.sin(t);return new e(n,r,-r,n,0,0)}static scale(t,n=t){return new e(t,0,0,n,0,0)}static reflect(t,r){let{x:i,y:a}=r,o=2*n(t,r);return new e(1-2*i*i,-2*i*a,-2*i*a,1-2*a*a,o*i,o*a)}after(t){let{a:n,b:r,c:i,d:a,e:o,f:s}=this;return new e(n*t.a+i*t.b,r*t.a+a*t.b,n*t.c+i*t.d,r*t.c+a*t.d,n*t.e+i*t.f+o,r*t.e+a*t.f+s)}invert(){let{a:t,b:n,c:r,d:i,e:a,f:o}=this,s=t*i-n*r;return new e(i/s,-n/s,-r/s,t/s,(r*o-i*a)/s,(n*a-t*o)/s)}apply(e){return{x:this.a*e.x+this.c*e.y+this.e,y:this.b*e.x+this.d*e.y+this.f}}toCss(){return`matrix(${this.a}, ${this.b}, ${this.c}, ${this.d}, ${this.e}, ${this.f})`}place(e,t){let n=this.apply({x:e/2,y:t/2}),r=this.a*this.d-this.b*this.c<0,i=r?Math.atan2(-this.b,-this.a):Math.atan2(this.b,this.a);return{left:n.x-e/2,top:n.y-t/2,width:e,height:t,angle:i,mirror:r}}},a=class e{width;height;origin;point;center;normal;progress;flat;folded;constructor(n,i,a,o){this.width=n,this.height=i,this.origin=a,this.point=e.attach(o,a,i);let s=t(a,this.point),c=r(s),l=[{x:0,y:0},{x:n,y:0},{x:n,y:i},{x:0,y:i}];this.center={x:(a.x+this.point.x)/2,y:(a.y+this.point.y)/2},this.progress=Math.min(1,c/Math.max(1,2*a.x)),c<.5?(this.normal={x:1,y:0},this.flat=l,this.folded=[]):(this.normal={x:s.x/c,y:s.y/c},this.flat=this.clip(l,-1),this.folded=this.clip(l,1))}static attach(e,n,i){let a=[{x:0,y:0},{x:0,y:i}],o=e;for(let e=0;e<3;e++)for(let e of a){let i=r(t(n,e)),a=t(o,e),s=r(a);s>i&&(o={x:e.x+a.x*i/s,y:e.y+a.y*i/s})}return o}static hinge(e,t,n){let r=Math.max(-1,Math.min(1,n*t.x/Math.max(1,e.x)));return-Math.acos(r)*180/Math.PI}get shade(){return Math.min(1,this.progress*8)*Math.min(1,(1-this.progress)*6)}reflect(e){let r=2*n(t(e,this.center),this.normal);return{x:e.x-r*this.normal.x,y:e.y-r*this.normal.y}}get reflection(){return i.reflect(this.center,this.normal)}get flap(){return this.folded.map(e=>this.reflect(e))}flapMatrix(e){let{x:t,y:n}=this.normal,r=e===1?-1:1,i=e*(1-2*t*t)*r,a=-2*t*n*r,o=-2*e*t*n,s=1-2*n*n,c=this.reflect({x:e===1?this.width:0,y:0});return`matrix(${i}, ${a}, ${o}, ${s}, ${e*c.x}, ${c.y})`}clip(e,r){let i=[],a=e=>r*n(t(e,this.center),this.normal)>=0;return e.forEach((o,s)=>{let c=e[(s+e.length-1)%e.length],l=r*n(t(c,this.center),this.normal),u=r*n(t(o,this.center),this.normal);if(a(o)!==a(c)){let e=l/(l-u);i.push({x:c.x+(o.x-c.x)*e,y:c.y+(o.y-c.y)*e})}a(o)&&i.push(o)}),i}};let o={fall:.0075,auto:.0055,peek:.02,flick:170,lift:.12},s={now:()=>performance.now(),request:e=>requestAnimationFrame(e),cancel:e=>cancelAnimationFrame(e)},c=()=>typeof matchMedia==`function`&&matchMedia(`(prefers-reduced-motion: reduce)`).matches;var l=class{listener;physics;mode=`idle`;origin={x:0,y:0};point={x:0,y:0};stiff=!1;size={width:1,height:1};position={x:0,y:0};velocity={x:0,y:0};target={x:0,y:0};omega=o.fall;lift=0;turned=!1;trail=[];handle=0;last=0;scheduler;reducedMotion;constructor(e,t={}){this.listener=e,this.physics={...o,...t.physics},this.scheduler=t.scheduler??s,this.reducedMotion=t.reducedMotion??c}get active(){return this.mode!==`idle`}get dragging(){return this.mode===`drag`}get peeking(){return this.mode===`peek`}get frame(){return{origin:this.origin,point:this.point,stiff:this.stiff}}grab(e,t,n,r){this.size=n,this.origin=e,this.stiff=r,this.mode=`drag`,this.trail=[],this.stop(),this.moveTo(t)}drag(e){this.mode===`drag`&&this.moveTo(e)}release(){if(this.mode!==`drag`)return!1;let e=this.speed(),t=this.point.x+e.x*this.physics.flick;return this.fall(t<0,e,this.physics.fall),this.turned}turn(e,t,n){this.size=t,this.origin=e,this.stiff=n,this.point={...e},this.fall(!0,{x:0,y:0},this.physics.auto)}peek(e,t,n,r){this.mode!==`drag`&&this.mode!==`fall`&&((this.mode===`idle`||this.origin.x!==e.x||this.origin.y!==e.y)&&(this.size=n,this.origin=e,this.stiff=r,this.point={...e},this.position={...this.point},this.velocity={x:0,y:0},this.lift=0),this.mode=`peek`,this.omega=this.physics.peek,this.target=t,this.turned=t.x<0,this.run())}unpeek(){this.mode===`peek`&&(this.mode=`fall`,this.target=this.turned?{x:-this.origin.x,y:this.origin.y}:{...this.origin},this.run())}finish(){if(this.mode===`idle`)return;let e=this.mode===`fall`?this.turned:this.point.x<0;this.stop(),this.mode=`idle`,this.listener.settle(e)}cancel(){this.stop(),this.mode=`idle`}moveTo(e){let t=this.stiff?{x:Math.max(-this.origin.x,Math.min(this.origin.x,e.x)),y:this.origin.y}:a.attach(e,this.origin,this.size.height),n=this.scheduler.now();this.point=t,this.trail.push({p:t,t:n}),this.trail=this.trail.filter(e=>n-e.t<100),this.listener.frame(this.frame)}speed(){if(this.trail.length<2)return{x:0,y:0};let e=this.trail[0],t=this.trail[this.trail.length-1],n=Math.max(1,t.t-e.t);return{x:(t.p.x-e.p.x)/n,y:(t.p.y-e.p.y)/n}}fall(e,t,n){this.reducedMotion()?(this.stop(),this.mode=`idle`,this.listener.settle(e)):(this.mode=`fall`,this.turned=e,this.omega=n,this.target=e?{x:-this.origin.x,y:this.origin.y}:{...this.origin},this.lift=this.stiff?0:this.size.height*this.physics.lift*(this.origin.y>this.size.height/2?-1:1),this.position={x:this.point.x,y:this.point.y-this.arc(this.point.x)},this.velocity=t,this.run())}arc(e){let t=Math.max(1,this.origin.x),n=Math.min(1,Math.abs(e)/t);return this.lift*(1-n*n)}run(){this.handle||=(this.last=this.scheduler.now(),this.scheduler.request(this.tick))}stop(){this.handle&&this.scheduler.cancel(this.handle),this.handle=0}tick=e=>{let n=Math.min(48,e-this.last),i=this.omega;this.last=e;for(let e=0;e<n;e+=4){let t=Math.min(4,n-e);for(let e of[`x`,`y`]){let n=i*i*(this.target[e]-this.position[e])-2*i*this.velocity[e];this.velocity[e]+=n*t,this.position[e]+=this.velocity[e]*t}}let o={x:this.position.x,y:this.position.y+(this.mode===`fall`?this.arc(this.position.x):0)};this.point=this.stiff?{x:o.x,y:this.origin.y}:a.attach(o,this.origin,this.size.height),this.listener.frame(this.frame);let s=r(t(this.target,this.position))<.5&&r(this.velocity)<.02;s&&this.mode===`fall`?(this.handle=0,this.mode=`idle`,this.listener.settle(this.turned)):this.handle=s?0:this.scheduler.request(this.tick)}};let u={single:{label:`Full bleed`,slots:1},framed:{label:`Framed`,slots:1},pair:{label:`Pair`,slots:2},grid:{label:`Grid`,slots:4},collage:{label:`Collage`,slots:3},text:{label:`Words`,slots:0},triptych:{label:`Triptych`,slots:3},mosaic:{label:`Mosaic`,slots:3},strip:{label:`Film strip`,slots:3},contact:{label:`Contact sheet`,slots:6},scatter:{label:`Loose prints`,slots:3},story:{label:`Story`,slots:1}},d=(e,t,n,r=7,i=108,a=3)=>{let o=(i-a*(n-1))/n;return Array.from({length:n},(n,i)=>({x:e,y:r+i*(o+a),width:t,height:o}))},f={x:7,y:118,width:86,height:10},p={triptych:{slots:[7,36.67,66.33].map(e=>({x:e,y:14,width:26.67,height:94})),caption:{...f,y:114}},mosaic:{slots:[{x:7,y:7,width:51,height:108},...d(61,32,2)],caption:f},strip:{slots:d(7,86,3),caption:f},contact:{slots:d(7,41.5,3).flatMap((e,t)=>[e,d(51.5,41.5,3)[t]]),caption:f},scatter:{slots:[{x:9,y:9,width:54,height:41,rotate:-4},{x:38,y:43,width:54,height:41,rotate:3},{x:11,y:80,width:48,height:35,rotate:-2}],caption:{...f,x:63,y:92,width:30,height:28},loose:!0},story:{slots:[{x:7,y:7,width:86,height:66}],caption:{x:9,y:80,width:82,height:45},prose:!0}},m={classic:{label:`Classic`,cloth:`#5a1d22`,ink:`#e2c58f`,stage:[`#4a2a27`,`#22140f`,`#0d0807`]},linen:{label:`Linen`,cloth:`#e6dcc6`,ink:`#3d3226`,stage:[`#4a4134`,`#241f18`,`#0e0c09`]},midnight:{label:`Midnight`,cloth:`#141b2e`,ink:`#d5dbe8`,stage:[`#27324d`,`#121827`,`#07090f`]},leather:{label:`Tan leather`,cloth:`#6b3f24`,ink:`#ecc77d`,stage:[`#4d3121`,`#24170f`,`#0d0805`]},sage:{label:`Sage`,cloth:`#5d6f5c`,ink:`#f1e9d2`,stage:[`#3c4a3c`,`#1c241c`,`#0a0d0a`]},blush:{label:`Blush`,cloth:`#d8b4a8`,ink:`#5a2f2a`,stage:[`#5a4440`,`#2a1f1d`,`#100b0a`]}},h={classic:{label:`Classic`,description:`A ruled panel with the title over an inset photo`},gilt:{label:`Gilt`,description:`Gold rules and corner flourishes around an oval portrait`},window:{label:`Window`,description:`The photo set into a window pressed into the board`},label:{label:`Tipped-in print`,description:`A print held by photo corners over a paper title label`},deco:{label:`Art deco`,description:`Gold rays rising to an arched photo`},image:{label:`Full image`,description:`Your photo across the whole cover, finished like the board`}},g={ivory:{label:`Ivory`,swatch:`#fbf8f1`},white:{label:`White`,swatch:`#ffffff`},kraft:{label:`Kraft`,swatch:`#d8c4a2`},charcoal:{label:`Charcoal`,swatch:`#2a2826`}},_={none:{label:`Plain`,description:`The photo printed straight onto the page`},hairline:{label:`Hairline`,description:`A fine printed rule around the photo`},double:{label:`Double rule`,description:`Two printed rules, like a classic album keyline`},mat:{label:`Gallery mat`,description:`A wide printed mat with a thin frame line`},corners:{label:`Photo corners`,description:`Printed album corners holding the photo`},deckle:{label:`Deckled edge`,description:`A vintage print with a scalloped border`},plate:{label:`Plate mark`,description:`The photo sits in a plate pressed into the paper`},feather:{label:`Soft edge`,description:`The photo fades into the paper at its edges`},oval:{label:`Oval`,description:`An oval cameo inside a fine printed ring`},botanical:{label:`Botanical`,description:`Line-drawn sprigs of leaves around a fine rule`},watercolor:{label:`Watercolour`,description:`A wash of soft colour printed around a mat`},arcs:{label:`Rainbow arcs`,description:`A printed border of little rainbow arcs around a mat`},gilt:{label:`Gilt`,description:`An engraved border printed in gold ink`},woodgrain:{label:`Woodgrain`,description:`A printed woodgrain border around a mat`}},v={watercolor:3,arcs:3,gilt:2.6,woodgrain:3};function y(e){return e.coverText??e.coverDesign!==`image`}function b(e,t,n=`none`){return e.layout===`single`?`none`:t?.frame??x(e,n)}function x(e,t=`none`){return e.layout===`single`?`none`:e.frame??t}var S=class e{pageCount;faces;leaves;spread;stiffCovers;constructor(t,{spread:n,stiffCovers:r=!0}){this.pageCount=t;let i=Array.from({length:t},(e,t)=>({kind:`page`,index:t})),a=n&&t%2==1?[{kind:`blank`}]:[];this.spread=n,this.stiffCovers=r,this.faces=[{kind:`cover`},{kind:`title`},...i,...a,{kind:`colophon`},{kind:`back`}],this.leaves=n?e.pair(this.faces):this.faces.map(e=>({front:e,back:{kind:`blank`}}))}static pair(e){let t=[];for(let n=0;n<e.length;n+=2)t.push({front:e[n],back:e[n+1]});return t}get length(){return this.leaves.length}flippedForFace(e){return this.spread?Math.ceil(e/2):e}flippedForPage(e){return!e||e<1||e>this.pageCount?0:this.flippedForFace(e+1)}convert(e,t){return t.spread===this.spread?Math.min(e,this.length):this.spread?Math.ceil(e/2):Math.max(0,e*2-1)}isStiff(e){let{front:t,back:n}=this.leaves[e]??{};return this.stiffCovers&&(t?.kind===`cover`||t?.kind===`back`||n?.kind===`back`)}visible(e){return e<=0?[this.leaves[0].front]:e>=this.length?[this.spread?this.leaves[this.length-1].back:this.faces[this.faces.length-1]]:this.spread?[this.leaves[e-1].back,this.leaves[e].front]:[this.leaves[e].front]}stops(){if(!this.spread)return this.faces.map((e,t)=>({flipped:t,faces:[e]}));let e=[{flipped:0,faces:[this.faces[0]]}];for(let t=1;t<this.faces.length-1;t+=2)e.push({flipped:this.flippedForFace(t),faces:[this.faces[t],this.faces[t+1]]});return e.push({flipped:this.length,faces:[this.faces[this.faces.length-1]]}),e}label(t){if(t<=0)return`Cover`;if(t>=this.length)return`Back cover`;let n=e.pageNumbers(this.visible(t));return n.length===0?this.visible(t).some(e=>e.kind===`title`)?`Title page`:`The end`:n.length===1?`Page ${n[0]} of ${this.pageCount}`:`Pages ${n[0]}–${n[1]} of ${this.pageCount}`}static describe(t){let n=e.pageNumbers(t);return n.length?`page ${n.join(` and `)}`:t[0].kind===`back`?`the back cover`:t[0].kind===`cover`?`the cover`:`the title page`}static pageNumbers(e){return e.filter(e=>e.kind===`page`).map(e=>e.index+1)}};let C={edgeX:.15,edgeY:.08,peek:!0};var w=class{events;flipped;active=null;layout;width=0;height=0;grip;engine;press=null;grabStart={x:0,y:0};grabDir=1;grabReach=1;constructor(e,t,n={}){this.events=t,this.layout=e,this.flipped=Math.max(0,Math.min(e.length,n.flipped??0)),this.grip={...C,...n.grip},this.engine=new l({frame:e=>this.active&&this.events.frame(e,this.active),settle:e=>this.settle(e)},n)}get size(){return{width:this.width,height:this.height}}get atStart(){return this.flipped===0}get atEnd(){return this.flipped===this.layout.length}get settled(){return!this.active||this.active.peek}get label(){return this.layout.label(this.flipped)}configure({layout:e,width:t,height:n}){let r=e&&e!==this.layout,i=t!==void 0&&t!==this.width||n!==void 0&&n!==this.height;(r||i)&&(e&&r&&(this.flipped=e.convert(this.flipped,this.layout),this.layout=e),this.width=t??this.width,this.height=n??this.height,this.engine.cancel(),this.active=null,this.press=null,this.events.change())}go(e){let t=Math.max(0,Math.min(this.layout.length,e));if(t===this.flipped||this.width===0)return;if(this.engine.active&&!this.engine.peeking){this.engine.finish();return}if(this.engine.cancel(),this.events.flip(),Math.abs(t-this.flipped)!==1){this.active=null,this.flipped=t,this.events.change();return}let n=Math.min(t,this.flipped),r=this.layout.isStiff(n);this.begin({leaf:n,dir:t>this.flipped?1:-1,stiff:r,peek:!1}),this.engine.turn({x:this.width,y:r?this.height/2:this.height},this.size,r)}next(){this.go(this.flipped+1)}prev(){this.go(this.flipped-1)}hover(e){if(this.press||this.engine.dragging)return;let t=this.grip.peek?this.cornerAt(e):null;if(!t){this.engine.unpeek();return}let{width:n,height:r}=this,i=t.x>0?1:-1,a=i===1?this.flipped:this.flipped-1,o=this.layout.isStiff(a),s={x:n,y:o?r/2:t.y},c={x:i*(e.x-t.x),y:e.y-t.y},l=Math.hypot(c.x,c.y)||1,u=Math.max(n*.12,Math.min(n*.2,l*2)),d={x:n+c.x/l*u,y:o?s.y:t.y+c.y/l*u};(this.active?.leaf!==a||this.active.dir!==i)&&this.begin({leaf:a,dir:i,stiff:o,peek:!0}),this.engine.peek(s,d,this.size,o)}leave(){this.engine.unpeek()}down(e,t){this.press={at:e,id:t,grabbed:!1}}move(e,t){let n=this.press;if(!n||n.id!==t)return!1;let r=e.x-n.at.x,i=e.y-n.at.y;if(!n.grabbed){if(Math.hypot(r,i)<6||this.engine.active&&!this.engine.peeking)return!1;let e=(this.engine.peeking&&this.active?{...this.active,origin:this.engine.frame.origin,start:this.engine.frame.point}:null)??this.holdAt(n.at);if(!e)return!1;n.grabbed=!0,this.grabStart=e.start,this.grabDir=e.dir,this.grabReach=!this.layout.spread&&e.dir===-1?2:1,this.begin({leaf:e.leaf,dir:e.dir,stiff:e.stiff,peek:!1}),this.engine.grab(e.origin,e.start,this.size,e.stiff)}return this.engine.drag({x:this.grabStart.x+this.grabDir*this.grabReach*r,y:this.grabStart.y+i}),!0}up(e,t){let n=this.press;return!n||n.id!==t?null:(this.press=null,n.grabbed?(this.engine.release()&&this.events.flip(),`turn`):Math.abs(e.x-n.at.x)<8&&Math.abs(e.y-n.at.y)<8?`tap`:null)}cancel(){this.press=null,this.engine.dragging&&this.engine.release()}destroy(){this.engine.cancel()}begin(e){this.active=e,this.events.change()}settle(e){let t=this.active;if(!t)return;let n=t.dir===1?e:!e;this.flipped=n?t.leaf+1:t.leaf,this.active=null,this.events.change()}holdAt(e){let{width:t,height:n,layout:r}=this,i=r.spread?e.x>=0:e.x>=t*.3,a=i?this.flipped:this.flipped-1;if(a<0||a>=r.length)return null;let o=i?e:{x:r.spread?-e.x:t,y:e.y},s=o.x>t*(1-this.grip.edgeX),c=o.y<n*this.grip.edgeY,l=o.y>n*(1-this.grip.edgeY),u=r.isStiff(a),d={x:s||!(c||l)?t:Math.max(1,o.x),y:u?n/2:c?0:l?n:Math.max(0,Math.min(n,o.y))};return{leaf:a,dir:i?1:-1,origin:d,stiff:u,start:d}}cornerAt(e){let{width:t,height:n,layout:r,flipped:i}=this,a=Math.max(36,t*.12);return[...i<r.length?[{x:t,y:0},{x:t,y:n}]:[],...r.spread&&i>0?[{x:-t,y:0},{x:-t,y:n}]:[]].find(t=>Math.hypot(e.x-t.x,e.y-t.y)<a)??null}};let T={previous:`Previous page`,next:`Next page`,soundOn:`Turn page sound on`,soundOff:`Turn page sound off`,fullscreen:`Full screen`,exitFullscreen:`Exit full screen`,byline:e=>`by ${e}`,rotateTitle:`Turn your phone sideways`,rotateBody:`Photo books open across two pages, just like the real thing.`,rotateFullscreen:`Open full screen`,rotateSingle:`Read one page at a time`},E={viewBox:`0 0 40 40`,strokes:[{d:`M3 37V12Q3 3 12 3H37`,width:1},{d:`M7 37V16Q7 7 16 7H37`,width:.6},{d:`M12 12C16 10 20 12 20 16C20 19 17 20 15.5 18.5`,width:.8}],fills:[`M16 7C18 10 21 11 24 10C22 8 19 7 16 7Z`,`M7 16C10 18 11 21 10 24C8 22 7 19 7 16Z`,`M10.7 12a1.3 1.3 0 1 0 2.6 0a1.3 1.3 0 1 0 -2.6 0Z`]},D={x:50,y:124},ee={viewBox:`0 0 100 133.33`,strokes:[...Array.from({length:17},(e,t)=>{let n=12+t/16*76,r=(D.y-88)/(D.y-16);return{d:`M${(D.x+(n-D.x)*r).toFixed(2)} 88L${n.toFixed(2)} 16`,width:.25,opacity:.3}}),{d:`M5 5H95V128.33H5Z`,width:.5},{d:`M11 8H89L92 11V122.33L89 125.33H11L8 122.33V11Z`,width:.35}],fills:[`M50 8.5L52 11L50 13.5L48 11Z`,`M50 119.83L52 122.33L50 124.83L48 122.33Z`]};function O(e,t={},...n){let r=document.createElement(e);for(let[e,n]of Object.entries(t))e===`style`?Object.assign(r.style,n):n!=null&&n!==!1&&r.setAttribute(e,n===!0?``:String(n));return te(r,n),r}function te(e,t){for(let n of t)n&&e.append(n)}function k(e){let t=document.createElement(`template`);return t.innerHTML=e.trim(),t.content.firstElementChild}async function A(e){try{!document.fullscreenElement&&e.requestFullscreen&&await e.requestFullscreen({navigationUI:`hide`})}catch{}try{let e=screen.orientation;if(e?.lock)return await e.lock(`landscape`),!0}catch{}return!1}function j(e){let t=matchMedia(`(orientation: portrait)`),n=matchMedia(`(pointer: coarse)`),r=()=>e({portrait:t.matches,touch:n.matches});return r(),t.addEventListener(`change`,r),n.addEventListener(`change`,r),window.addEventListener(`resize`,r),()=>{t.removeEventListener(`change`,r),n.removeEventListener(`change`,r),window.removeEventListener(`resize`,r)}}let M=[`tl`,`tr`,`bl`,`br`];function N(e,t){let n=e.strokes.map(({d:e,width:t,opacity:n=1})=>`<path d="${e}" fill="none" stroke="currentColor" stroke-width="${t}" stroke-opacity="${n}"/>`).join(``),r=e.fills.map(e=>`<path d="${e}" fill="currentColor"/>`).join(``);return`<svg viewBox="${e.viewBox}" class="${t}" preserveAspectRatio="none" aria-hidden="true">${n}${r}</svg>`}let ne=()=>M.map(e=>k(N(E,`fb-fleuron is-${e}`))),P=(e,t,n)=>e.cover&&O(`div`,{class:t},n?U(e.cover,`fb-photo`):O(`div`,{class:`fb-placeholder`})),F=e=>O(`h1`,{class:`fb-serif fb-cover-title`},e.title),I=e=>e.kicker&&O(`p`,{class:`fb-kicker`},e.kicker),L=e=>e.subtitle&&O(`p`,{class:`fb-serif fb-italic fb-cover-subtitle`},e.subtitle);function re(e,t){let n=y(e);switch(e.coverDesign??`classic`){case`gilt`:return[O(`div`,{class:`fb-cover-frame`}),...ne(),O(`div`,{class:`fb-cover-stack`},n&&I(e),n&&F(e),P(e,`fb-cover-photo is-oval`,t),n&&L(e))];case`window`:return[P(e,`fb-cover-window`,t)||O(`div`,{class:`fb-cover-window is-empty`},H()),n&&O(`div`,{class:`fb-cover-stamp`},I(e),F(e),L(e))];case`label`:return[e.cover&&O(`div`,{class:`fb-cover-print`},P(e,`fb-cover-print-photo`,t),...M.map(e=>O(`span`,{class:`fb-print-frame-corner is-${e}`,"aria-hidden":`true`}))),n&&O(`div`,{class:`fb-cover-label ${e.cover?``:`is-alone`}`},I(e),F(e),L(e))];case`deco`:return[k(N(ee,`fb-cover-rays`)),O(`div`,{class:`fb-cover-stack is-deco`},n&&I(e),P(e,`fb-cover-photo is-arch`,t),n&&F(e),n&&L(e))];case`image`:return[e.cover&&O(`div`,{class:`fb-cover-art`},t?U(e.cover,`fb-photo`):O(`div`,{class:`fb-placeholder`})),e.cover&&O(`div`,{class:`fb-cover-tint`}),n&&O(`div`,{class:`fb-cover-caption ${e.cover?``:`is-plain`}`},I(e),F(e),L(e))];default:return[O(`div`,{class:`fb-cover-panel`},n&&I(e),n&&F(e),P(e,`fb-cover-photo`,t)||n&&L(e))]}}let R=(e,t,...n)=>O(`div`,{class:`fb-cover fb-cover-${e.theme??`classic`} fb-design-${e.coverDesign??`classic`}`},...n,O(`div`,{class:`fb-hinge is-${t}`}),O(`div`,{class:`fb-cover-finish`,"aria-hidden":`true`}));function z(e,t=!0){return R(e,`left`,...re(e,t))}function B(e){let t=e.coverDesign===`gilt`;return R(e,`right`,t&&O(`div`,{class:`fb-cover-frame`}),...t?ne():[],O(`div`,{class:`fb-imprint`},H(),e.imprint&&O(`p`,{class:`fb-kicker`,style:{marginTop:`2cqw`,fontSize:`2.4cqw`,opacity:`0.6`}},e.imprint)))}let ie=[14,24,34,44,54,64,74].map((e,t)=>({x:e,angle:t%2?38:-38,length:26-t*2})),V=e=>k(`<svg viewBox="0 0 100 40" class="fb-print-frame-sprig is-${e}" fill="none" stroke="currentColor" stroke-linecap="round" aria-hidden="true">
1
+ var Flipbook=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});let t=(e,t)=>({x:e.x-t.x,y:e.y-t.y}),n=(e,t)=>e.x*t.x+e.y*t.y,r=e=>Math.hypot(e.x,e.y);var i=class e{a;b;c;d;e;f;constructor(e=1,t=0,n=0,r=1,i=0,a=0){this.a=e,this.b=t,this.c=n,this.d=r,this.e=i,this.f=a}static translate(t,n){return new e(1,0,0,1,t,n)}static rotate(t){let n=Math.cos(t),r=Math.sin(t);return new e(n,r,-r,n,0,0)}static scale(t,n=t){return new e(t,0,0,n,0,0)}static reflect(t,r){let{x:i,y:a}=r,o=2*n(t,r);return new e(1-2*i*i,-2*i*a,-2*i*a,1-2*a*a,o*i,o*a)}after(t){let{a:n,b:r,c:i,d:a,e:o,f:s}=this;return new e(n*t.a+i*t.b,r*t.a+a*t.b,n*t.c+i*t.d,r*t.c+a*t.d,n*t.e+i*t.f+o,r*t.e+a*t.f+s)}invert(){let{a:t,b:n,c:r,d:i,e:a,f:o}=this,s=t*i-n*r;return new e(i/s,-n/s,-r/s,t/s,(r*o-i*a)/s,(n*a-t*o)/s)}apply(e){return{x:this.a*e.x+this.c*e.y+this.e,y:this.b*e.x+this.d*e.y+this.f}}toCss(){return`matrix(${this.a}, ${this.b}, ${this.c}, ${this.d}, ${this.e}, ${this.f})`}place(e,t){let n=this.apply({x:e/2,y:t/2}),r=this.a*this.d-this.b*this.c<0,i=r?Math.atan2(-this.b,-this.a):Math.atan2(this.b,this.a);return{left:n.x-e/2,top:n.y-t/2,width:e,height:t,angle:i,mirror:r}}},a=class e{width;height;origin;point;center;normal;progress;flat;folded;constructor(n,i,a,o){this.width=n,this.height=i,this.origin=a,this.point=e.attach(o,a,i);let s=t(a,this.point),c=r(s),l=[{x:0,y:0},{x:n,y:0},{x:n,y:i},{x:0,y:i}];this.center={x:(a.x+this.point.x)/2,y:(a.y+this.point.y)/2},this.progress=Math.min(1,c/Math.max(1,2*a.x)),c<.5?(this.normal={x:1,y:0},this.flat=l,this.folded=[]):(this.normal={x:s.x/c,y:s.y/c},this.flat=this.clip(l,-1),this.folded=this.clip(l,1))}static attach(e,n,i){let a=[{x:0,y:0},{x:0,y:i}],o=e;for(let e=0;e<3;e++)for(let e of a){let i=r(t(n,e)),a=t(o,e),s=r(a);s>i&&(o={x:e.x+a.x*i/s,y:e.y+a.y*i/s})}return o}static hinge(e,t,n){let r=Math.max(-1,Math.min(1,n*t.x/Math.max(1,e.x)));return-Math.acos(r)*180/Math.PI}get shade(){return Math.min(1,this.progress*8)*Math.min(1,(1-this.progress)*6)}reflect(e){let r=2*n(t(e,this.center),this.normal);return{x:e.x-r*this.normal.x,y:e.y-r*this.normal.y}}get reflection(){return i.reflect(this.center,this.normal)}get flap(){return this.folded.map(e=>this.reflect(e))}flapMatrix(e){let{x:t,y:n}=this.normal,r=e===1?-1:1,i=e*(1-2*t*t)*r,a=-2*t*n*r,o=-2*e*t*n,s=1-2*n*n,c=this.reflect({x:e===1?this.width:0,y:0});return`matrix(${i}, ${a}, ${o}, ${s}, ${e*c.x}, ${c.y})`}clip(e,r){let i=[],a=e=>r*n(t(e,this.center),this.normal)>=0;return e.forEach((o,s)=>{let c=e[(s+e.length-1)%e.length],l=r*n(t(c,this.center),this.normal),u=r*n(t(o,this.center),this.normal);if(a(o)!==a(c)){let e=l/(l-u);i.push({x:c.x+(o.x-c.x)*e,y:c.y+(o.y-c.y)*e})}a(o)&&i.push(o)}),i}};let o={fall:.0075,auto:.0055,peek:.02,flick:170,lift:.12},s={now:()=>performance.now(),request:e=>requestAnimationFrame(e),cancel:e=>cancelAnimationFrame(e)},c=()=>typeof matchMedia==`function`&&matchMedia(`(prefers-reduced-motion: reduce)`).matches;var l=class{listener;physics;mode=`idle`;origin={x:0,y:0};point={x:0,y:0};stiff=!1;size={width:1,height:1};position={x:0,y:0};velocity={x:0,y:0};target={x:0,y:0};omega=o.fall;lift=0;turned=!1;trail=[];handle=0;last=0;scheduler;reducedMotion;constructor(e,t={}){this.listener=e,this.physics={...o,...t.physics},this.scheduler=t.scheduler??s,this.reducedMotion=t.reducedMotion??c}get active(){return this.mode!==`idle`}get dragging(){return this.mode===`drag`}get peeking(){return this.mode===`peek`}get frame(){return{origin:this.origin,point:this.point,stiff:this.stiff}}grab(e,t,n,r){this.size=n,this.origin=e,this.stiff=r,this.mode=`drag`,this.trail=[],this.stop(),this.moveTo(t)}drag(e){this.mode===`drag`&&this.moveTo(e)}release(){if(this.mode!==`drag`)return!1;let e=this.speed(),t=this.point.x+e.x*this.physics.flick;return this.fall(t<0,e,this.physics.fall),this.turned}turn(e,t,n){this.size=t,this.origin=e,this.stiff=n,this.point={...e},this.fall(!0,{x:0,y:0},this.physics.auto)}peek(e,t,n,r){this.mode!==`drag`&&this.mode!==`fall`&&((this.mode===`idle`||this.origin.x!==e.x||this.origin.y!==e.y)&&(this.size=n,this.origin=e,this.stiff=r,this.point={...e},this.position={...this.point},this.velocity={x:0,y:0},this.lift=0),this.mode=`peek`,this.omega=this.physics.peek,this.target=t,this.turned=t.x<0,this.run())}unpeek(){this.mode===`peek`&&(this.mode=`fall`,this.target=this.turned?{x:-this.origin.x,y:this.origin.y}:{...this.origin},this.run())}finish(){if(this.mode===`idle`)return;let e=this.mode===`fall`?this.turned:this.point.x<0;this.stop(),this.mode=`idle`,this.listener.settle(e)}cancel(){this.stop(),this.mode=`idle`}moveTo(e){let t=this.stiff?{x:Math.max(-this.origin.x,Math.min(this.origin.x,e.x)),y:this.origin.y}:a.attach(e,this.origin,this.size.height),n=this.scheduler.now();this.point=t,this.trail.push({p:t,t:n}),this.trail=this.trail.filter(e=>n-e.t<100),this.listener.frame(this.frame)}speed(){if(this.trail.length<2)return{x:0,y:0};let e=this.trail[0],t=this.trail[this.trail.length-1],n=Math.max(1,t.t-e.t);return{x:(t.p.x-e.p.x)/n,y:(t.p.y-e.p.y)/n}}fall(e,t,n){this.reducedMotion()?(this.stop(),this.mode=`idle`,this.listener.settle(e)):(this.mode=`fall`,this.turned=e,this.omega=n,this.target=e?{x:-this.origin.x,y:this.origin.y}:{...this.origin},this.lift=this.stiff?0:this.size.height*this.physics.lift*(this.origin.y>this.size.height/2?-1:1),this.position={x:this.point.x,y:this.point.y-this.arc(this.point.x)},this.velocity=t,this.run())}arc(e){let t=Math.max(1,this.origin.x),n=Math.min(1,Math.abs(e)/t);return this.lift*(1-n*n)}run(){this.handle||=(this.last=this.scheduler.now(),this.scheduler.request(this.tick))}stop(){this.handle&&this.scheduler.cancel(this.handle),this.handle=0}tick=e=>{let n=Math.min(48,e-this.last),i=this.omega;this.last=e;for(let e=0;e<n;e+=4){let t=Math.min(4,n-e);for(let e of[`x`,`y`]){let n=i*i*(this.target[e]-this.position[e])-2*i*this.velocity[e];this.velocity[e]+=n*t,this.position[e]+=this.velocity[e]*t}}let o={x:this.position.x,y:this.position.y+(this.mode===`fall`?this.arc(this.position.x):0)};this.point=this.stiff?{x:o.x,y:this.origin.y}:a.attach(o,this.origin,this.size.height),this.listener.frame(this.frame);let s=r(t(this.target,this.position))<.5&&r(this.velocity)<.02;s&&this.mode===`fall`?(this.handle=0,this.mode=`idle`,this.listener.settle(this.turned)):this.handle=s?0:this.scheduler.request(this.tick)}};let u={single:{label:`Full bleed`,slots:1},framed:{label:`Framed`,slots:1},pair:{label:`Pair`,slots:2},grid:{label:`Grid`,slots:4},collage:{label:`Collage`,slots:3},text:{label:`Words`,slots:0},triptych:{label:`Triptych`,slots:3},mosaic:{label:`Mosaic`,slots:3},strip:{label:`Film strip`,slots:3},contact:{label:`Contact sheet`,slots:6},scatter:{label:`Loose prints`,slots:3},story:{label:`Story`,slots:1}},d=(e,t,n,r=7,i=108,a=3)=>{let o=(i-a*(n-1))/n;return Array.from({length:n},(n,i)=>({x:e,y:r+i*(o+a),width:t,height:o}))},f={x:7,y:118,width:86,height:10},p={triptych:{slots:[7,36.67,66.33].map(e=>({x:e,y:14,width:26.67,height:94})),caption:{...f,y:114}},mosaic:{slots:[{x:7,y:7,width:51,height:108},...d(61,32,2)],caption:f},strip:{slots:d(7,86,3),caption:f},contact:{slots:d(7,41.5,3).flatMap((e,t)=>[e,d(51.5,41.5,3)[t]]),caption:f},scatter:{slots:[{x:9,y:9,width:54,height:41,rotate:-4},{x:38,y:43,width:54,height:41,rotate:3},{x:11,y:80,width:48,height:35,rotate:-2}],caption:{...f,x:63,y:92,width:30,height:28},loose:!0},story:{slots:[{x:7,y:7,width:86,height:66}],caption:{x:9,y:80,width:82,height:45},prose:!0}},m={classic:{label:`Classic`,cloth:`#5a1d22`,ink:`#e2c58f`,stage:[`#4a2a27`,`#22140f`,`#0d0807`]},linen:{label:`Linen`,cloth:`#e6dcc6`,ink:`#3d3226`,stage:[`#4a4134`,`#241f18`,`#0e0c09`]},midnight:{label:`Midnight`,cloth:`#141b2e`,ink:`#d5dbe8`,stage:[`#27324d`,`#121827`,`#07090f`]},leather:{label:`Tan leather`,cloth:`#6b3f24`,ink:`#ecc77d`,stage:[`#4d3121`,`#24170f`,`#0d0805`]},sage:{label:`Sage`,cloth:`#5d6f5c`,ink:`#f1e9d2`,stage:[`#3c4a3c`,`#1c241c`,`#0a0d0a`]},blush:{label:`Blush`,cloth:`#d8b4a8`,ink:`#5a2f2a`,stage:[`#5a4440`,`#2a1f1d`,`#100b0a`]}},h={classic:{label:`Classic`,description:`A ruled panel with the title over an inset photo`},gilt:{label:`Gilt`,description:`Gold rules and corner flourishes around an oval portrait`},window:{label:`Window`,description:`The photo set into a window pressed into the board`},label:{label:`Tipped-in print`,description:`A print held by photo corners over a paper title label`},deco:{label:`Art deco`,description:`Gold rays rising to an arched photo`},image:{label:`Full image`,description:`Your photo across the whole cover, finished like the board`}},g={ivory:{label:`Ivory`,swatch:`#fbf8f1`},white:{label:`White`,swatch:`#ffffff`},kraft:{label:`Kraft`,swatch:`#d8c4a2`},charcoal:{label:`Charcoal`,swatch:`#2a2826`}},_={none:{label:`Plain`,description:`The photo printed straight onto the page`},hairline:{label:`Hairline`,description:`A fine printed rule around the photo`},double:{label:`Double rule`,description:`Two printed rules, like a classic album keyline`},mat:{label:`Gallery mat`,description:`A wide printed mat with a thin frame line`},corners:{label:`Photo corners`,description:`Printed album corners holding the photo`},deckle:{label:`Deckled edge`,description:`A vintage print with a scalloped border`},plate:{label:`Plate mark`,description:`The photo sits in a plate pressed into the paper`},feather:{label:`Soft edge`,description:`The photo fades into the paper at its edges`},oval:{label:`Oval`,description:`An oval cameo inside a fine printed ring`},botanical:{label:`Botanical`,description:`Line-drawn sprigs of leaves around a fine rule`},watercolor:{label:`Watercolour`,description:`A wash of soft colour printed around a mat`},arcs:{label:`Rainbow arcs`,description:`A printed border of little rainbow arcs around a mat`},gilt:{label:`Gilt`,description:`An engraved border printed in gold ink`},woodgrain:{label:`Woodgrain`,description:`A printed woodgrain border around a mat`}},v={watercolor:3,arcs:3,gilt:2.6,woodgrain:3};function y(e){return e.coverText??e.coverDesign!==`image`}function b(e,t,n=`none`){return e.layout===`single`?`none`:t?.frame??x(e,n)}function x(e,t=`none`){return e.layout===`single`?`none`:e.frame??t}var S=class e{pageCount;faces;leaves;spread;stiffCovers;constructor(t,{spread:n,stiffCovers:r=!0}){this.pageCount=t;let i=Array.from({length:t},(e,t)=>({kind:`page`,index:t})),a=n&&t%2==1?[{kind:`blank`}]:[];this.spread=n,this.stiffCovers=r,this.faces=[{kind:`cover`},{kind:`title`},...i,...a,{kind:`colophon`},{kind:`back`}],this.leaves=n?e.pair(this.faces):this.faces.map(e=>({front:e,back:{kind:`blank`}}))}static pair(e){let t=[];for(let n=0;n<e.length;n+=2)t.push({front:e[n],back:e[n+1]});return t}get length(){return this.leaves.length}flippedForFace(e){return this.spread?Math.ceil(e/2):e}flippedForPage(e){return!e||e<1||e>this.pageCount?0:this.flippedForFace(e+1)}convert(e,t){return t.spread===this.spread?Math.min(e,this.length):this.spread?Math.ceil(e/2):Math.max(0,e*2-1)}isStiff(e){let{front:t,back:n}=this.leaves[e]??{};return this.stiffCovers&&(t?.kind===`cover`||t?.kind===`back`||n?.kind===`back`)}visible(e){return e<=0?[this.leaves[0].front]:e>=this.length?[this.spread?this.leaves[this.length-1].back:this.faces[this.faces.length-1]]:this.spread?[this.leaves[e-1].back,this.leaves[e].front]:[this.leaves[e].front]}stops(){if(!this.spread)return this.faces.map((e,t)=>({flipped:t,faces:[e]}));let e=[{flipped:0,faces:[this.faces[0]]}];for(let t=1;t<this.faces.length-1;t+=2)e.push({flipped:this.flippedForFace(t),faces:[this.faces[t],this.faces[t+1]]});return e.push({flipped:this.length,faces:[this.faces[this.faces.length-1]]}),e}label(t){if(t<=0)return`Cover`;if(t>=this.length)return`Back cover`;let n=e.pageNumbers(this.visible(t));return n.length===0?this.visible(t).some(e=>e.kind===`title`)?`Title page`:`The end`:n.length===1?`Page ${n[0]} of ${this.pageCount}`:`Pages ${n[0]}–${n[1]} of ${this.pageCount}`}static describe(t){let n=e.pageNumbers(t);return n.length?`page ${n.join(` and `)}`:t[0].kind===`back`?`the back cover`:t[0].kind===`cover`?`the cover`:`the title page`}static pageNumbers(e){return e.filter(e=>e.kind===`page`).map(e=>e.index+1)}};let C={edgeX:.15,edgeY:.08,peek:!0};var w=class{events;flipped;active=null;layout;width=0;height=0;grip;engine;press=null;grabStart={x:0,y:0};grabDir=1;grabReach=1;constructor(e,t,n={}){this.events=t,this.layout=e,this.flipped=Math.max(0,Math.min(e.length,n.flipped??0)),this.grip={...C,...n.grip},this.engine=new l({frame:e=>this.active&&this.events.frame(e,this.active),settle:e=>this.settle(e)},n)}get size(){return{width:this.width,height:this.height}}get atStart(){return this.flipped===0}get atEnd(){return this.flipped===this.layout.length}get settled(){return!this.active||this.active.peek}get label(){return this.layout.label(this.flipped)}configure({layout:e,width:t,height:n}){let r=e&&e!==this.layout,i=t!==void 0&&t!==this.width||n!==void 0&&n!==this.height;(r||i)&&(e&&r&&(this.flipped=e.convert(this.flipped,this.layout),this.layout=e),this.width=t??this.width,this.height=n??this.height,this.engine.cancel(),this.active=null,this.press=null,this.events.change())}go(e){let t=Math.max(0,Math.min(this.layout.length,e));if(t===this.flipped||this.width===0)return;if(this.engine.active&&!this.engine.peeking){this.engine.finish();return}if(this.engine.cancel(),this.events.flip(),Math.abs(t-this.flipped)!==1){this.active=null,this.flipped=t,this.events.change();return}let n=Math.min(t,this.flipped),r=this.layout.isStiff(n);this.begin({leaf:n,dir:t>this.flipped?1:-1,stiff:r,peek:!1}),this.engine.turn({x:this.width,y:r?this.height/2:this.height},this.size,r)}next(){this.go(this.flipped+1)}prev(){this.go(this.flipped-1)}hover(e){if(this.press||this.engine.dragging)return;let t=this.grip.peek?this.cornerAt(e):null;if(!t){this.engine.unpeek();return}let{width:n,height:r}=this,i=t.x>0?1:-1,a=i===1?this.flipped:this.flipped-1,o=this.layout.isStiff(a),s={x:n,y:o?r/2:t.y},c={x:i*(e.x-t.x),y:e.y-t.y},l=Math.hypot(c.x,c.y)||1,u=Math.max(n*.12,Math.min(n*.2,l*2)),d={x:n+c.x/l*u,y:o?s.y:t.y+c.y/l*u};(this.active?.leaf!==a||this.active.dir!==i)&&this.begin({leaf:a,dir:i,stiff:o,peek:!0}),this.engine.peek(s,d,this.size,o)}leave(){this.engine.unpeek()}down(e,t){this.press={at:e,id:t,grabbed:!1}}move(e,t){let n=this.press;if(!n||n.id!==t)return!1;let r=e.x-n.at.x,i=e.y-n.at.y;if(!n.grabbed){if(Math.hypot(r,i)<6||this.engine.active&&!this.engine.peeking)return!1;let e=(this.engine.peeking&&this.active?{...this.active,origin:this.engine.frame.origin,start:this.engine.frame.point}:null)??this.holdAt(n.at);if(!e)return!1;n.grabbed=!0,this.grabStart=e.start,this.grabDir=e.dir,this.grabReach=!this.layout.spread&&e.dir===-1?2:1,this.begin({leaf:e.leaf,dir:e.dir,stiff:e.stiff,peek:!1}),this.engine.grab(e.origin,e.start,this.size,e.stiff)}return this.engine.drag({x:this.grabStart.x+this.grabDir*this.grabReach*r,y:this.grabStart.y+i}),!0}up(e,t){let n=this.press;return!n||n.id!==t?null:(this.press=null,n.grabbed?(this.engine.release()&&this.events.flip(),`turn`):Math.abs(e.x-n.at.x)<8&&Math.abs(e.y-n.at.y)<8?`tap`:null)}cancel(){this.press=null,this.engine.dragging&&this.engine.release()}destroy(){this.engine.cancel()}begin(e){this.active=e,this.events.change()}settle(e){let t=this.active;if(!t)return;let n=t.dir===1?e:!e;this.flipped=n?t.leaf+1:t.leaf,this.active=null,this.events.change()}holdAt(e){let{width:t,height:n,layout:r}=this,i=r.spread?e.x>=0:e.x>=t*.3,a=i?this.flipped:this.flipped-1;if(a<0||a>=r.length)return null;let o=i?e:{x:r.spread?-e.x:t,y:e.y},s=o.x>t*(1-this.grip.edgeX),c=o.y<n*this.grip.edgeY,l=o.y>n*(1-this.grip.edgeY),u=r.isStiff(a),d={x:s||!(c||l)?t:Math.max(1,o.x),y:u?n/2:c?0:l?n:Math.max(0,Math.min(n,o.y))};return{leaf:a,dir:i?1:-1,origin:d,stiff:u,start:d}}cornerAt(e){let{width:t,height:n,layout:r,flipped:i}=this,a=Math.max(36,t*.12);return[...i<r.length?[{x:t,y:0},{x:t,y:n}]:[],...r.spread&&i>0?[{x:-t,y:0},{x:-t,y:n}]:[]].find(t=>Math.hypot(e.x-t.x,e.y-t.y)<a)??null}};let T={previous:`Previous page`,next:`Next page`,soundOn:`Turn page sound on`,soundOff:`Turn page sound off`,fullscreen:`Full screen`,exitFullscreen:`Exit full screen`,fullscreenPrompt:`Tap to open full screen`,byline:e=>`by ${e}`,rotateTitle:`Turn your phone sideways`,rotateBody:`Photo books open across two pages, just like the real thing.`,rotateFullscreen:`Open full screen`,rotateSingle:`Read one page at a time`},ee={viewBox:`0 0 40 40`,strokes:[{d:`M3 37V12Q3 3 12 3H37`,width:1},{d:`M7 37V16Q7 7 16 7H37`,width:.6},{d:`M12 12C16 10 20 12 20 16C20 19 17 20 15.5 18.5`,width:.8}],fills:[`M16 7C18 10 21 11 24 10C22 8 19 7 16 7Z`,`M7 16C10 18 11 21 10 24C8 22 7 19 7 16Z`,`M10.7 12a1.3 1.3 0 1 0 2.6 0a1.3 1.3 0 1 0 -2.6 0Z`]},E={x:50,y:124},D={viewBox:`0 0 100 133.33`,strokes:[...Array.from({length:17},(e,t)=>{let n=12+t/16*76,r=(E.y-88)/(E.y-16);return{d:`M${(E.x+(n-E.x)*r).toFixed(2)} 88L${n.toFixed(2)} 16`,width:.25,opacity:.3}}),{d:`M5 5H95V128.33H5Z`,width:.5},{d:`M11 8H89L92 11V122.33L89 125.33H11L8 122.33V11Z`,width:.35}],fills:[`M50 8.5L52 11L50 13.5L48 11Z`,`M50 119.83L52 122.33L50 124.83L48 122.33Z`]};function O(e,t={},...n){let r=document.createElement(e);for(let[e,n]of Object.entries(t))e===`style`?Object.assign(r.style,n):n!=null&&n!==!1&&r.setAttribute(e,n===!0?``:String(n));return te(r,n),r}function te(e,t){for(let n of t)n&&e.append(n)}function k(e){let t=document.createElement(`template`);return t.innerHTML=e.trim(),t.content.firstElementChild}async function A(e){try{!document.fullscreenElement&&e.requestFullscreen&&await e.requestFullscreen({navigationUI:`hide`})}catch{}try{let e=screen.orientation;if(e?.lock)return await e.lock(`landscape`),!0}catch{}return!1}function ne(e){let t=matchMedia(`(orientation: portrait)`),n=matchMedia(`(pointer: coarse)`),r=()=>e({portrait:t.matches,touch:n.matches});return r(),t.addEventListener(`change`,r),n.addEventListener(`change`,r),window.addEventListener(`resize`,r),()=>{t.removeEventListener(`change`,r),n.removeEventListener(`change`,r),window.removeEventListener(`resize`,r)}}let re=[`tl`,`tr`,`bl`,`br`];function j(e,t){let n=e.strokes.map(({d:e,width:t,opacity:n=1})=>`<path d="${e}" fill="none" stroke="currentColor" stroke-width="${t}" stroke-opacity="${n}"/>`).join(``),r=e.fills.map(e=>`<path d="${e}" fill="currentColor"/>`).join(``);return`<svg viewBox="${e.viewBox}" class="${t}" preserveAspectRatio="none" aria-hidden="true">${n}${r}</svg>`}let M=()=>re.map(e=>k(j(ee,`fb-fleuron is-${e}`))),N=(e,t,n)=>e.cover&&O(`div`,{class:t},n?H(e.cover,`fb-photo`):O(`div`,{class:`fb-placeholder`})),P=e=>O(`h1`,{class:`fb-serif fb-cover-title`},e.title),F=e=>e.kicker&&O(`p`,{class:`fb-kicker`},e.kicker),I=e=>e.subtitle&&O(`p`,{class:`fb-serif fb-italic fb-cover-subtitle`},e.subtitle);function ie(e,t){let n=y(e);switch(e.coverDesign??`classic`){case`gilt`:return[O(`div`,{class:`fb-cover-frame`}),...M(),O(`div`,{class:`fb-cover-stack`},n&&F(e),n&&P(e),N(e,`fb-cover-photo is-oval`,t),n&&I(e))];case`window`:return[N(e,`fb-cover-window`,t)||O(`div`,{class:`fb-cover-window is-empty`},V()),n&&O(`div`,{class:`fb-cover-stamp`},F(e),P(e),I(e))];case`label`:return[e.cover&&O(`div`,{class:`fb-cover-print`},N(e,`fb-cover-print-photo`,t),...re.map(e=>O(`span`,{class:`fb-print-frame-corner is-${e}`,"aria-hidden":`true`}))),n&&O(`div`,{class:`fb-cover-label ${e.cover?``:`is-alone`}`},F(e),P(e),I(e))];case`deco`:return[k(j(D,`fb-cover-rays`)),O(`div`,{class:`fb-cover-stack is-deco`},n&&F(e),N(e,`fb-cover-photo is-arch`,t),n&&P(e),n&&I(e))];case`image`:return[e.cover&&O(`div`,{class:`fb-cover-art`},t?H(e.cover,`fb-photo`):O(`div`,{class:`fb-placeholder`})),e.cover&&O(`div`,{class:`fb-cover-tint`}),n&&O(`div`,{class:`fb-cover-caption ${e.cover?``:`is-plain`}`},F(e),P(e),I(e))];default:return[O(`div`,{class:`fb-cover-panel`},n&&F(e),n&&P(e),N(e,`fb-cover-photo`,t)||n&&I(e))]}}let L=(e,t,...n)=>O(`div`,{class:`fb-cover fb-cover-${e.theme??`classic`} fb-design-${e.coverDesign??`classic`}`},...n,O(`div`,{class:`fb-hinge is-${t}`}),O(`div`,{class:`fb-cover-finish`,"aria-hidden":`true`}));function R(e,t=!0){return L(e,`left`,...ie(e,t))}function z(e){let t=e.coverDesign===`gilt`;return L(e,`right`,t&&O(`div`,{class:`fb-cover-frame`}),...t?M():[],O(`div`,{class:`fb-imprint`},V(),e.imprint&&O(`p`,{class:`fb-kicker`,style:{marginTop:`2cqw`,fontSize:`2.4cqw`,opacity:`0.6`}},e.imprint)))}let ae=[14,24,34,44,54,64,74].map((e,t)=>({x:e,angle:t%2?38:-38,length:26-t*2})),B=e=>k(`<svg viewBox="0 0 100 40" class="fb-print-frame-sprig is-${e}" fill="none" stroke="currentColor" stroke-linecap="round" aria-hidden="true">
2
2
  <path d="M4 20 Q 50 17, 92 20" stroke-width="1.2"/>
3
- ${ie.map(({x:e,angle:t,length:n})=>`<g transform="translate(${e} 20) rotate(${t}) scale(${n/20})"><path d="M0 0 C 5 -5, 14 -5, 20 0 C 14 5, 5 5, 0 0 Z" stroke-width="1"/><path d="M2 0 L 16 0" stroke-width="0.6"/></g>`).join(``)}
4
- </svg>`),H=()=>k(`<svg viewBox="0 0 40 40" class="fb-ornament" aria-hidden="true">
3
+ ${ae.map(({x:e,angle:t,length:n})=>`<g transform="translate(${e} 20) rotate(${t}) scale(${n/20})"><path d="M0 0 C 5 -5, 14 -5, 20 0 C 14 5, 5 5, 0 0 Z" stroke-width="1"/><path d="M2 0 L 16 0" stroke-width="0.6"/></g>`).join(``)}
4
+ </svg>`),V=()=>k(`<svg viewBox="0 0 40 40" class="fb-ornament" aria-hidden="true">
5
5
  <circle cx="20" cy="20" r="18.5" fill="none" stroke="currentColor" stroke-opacity="0.6"/>
6
6
  <path d="M20 9 L 27 20 L 20 31 L 13 20 Z" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linejoin="round"/>
7
7
  <circle cx="20" cy="20" r="2.2" fill="currentColor"/>
8
- </svg>`),U=(e,t)=>O(`img`,{src:e.src,alt:e.alt??``,draggable:`false`,decoding:`async`,width:e.width??void 0,height:e.height??void 0,class:t}),W=({x:e,y:t,width:n,height:r,rotate:i})=>({left:`${e}cqw`,top:`${t}cqw`,width:`${n}cqw`,height:`${r}cqw`,...i?{transform:`rotate(${i}deg)`}:{}}),G=e=>O(`div`,{class:`fb-page-surface ${e?`is-${e}`:``}`,"aria-hidden":`true`},O(`div`,{class:`fb-page-surface-grain`}),e&&O(`div`,{class:`fb-page-surface-gutter`}),e&&O(`div`,{class:`fb-page-surface-sheen`})),K=(e,t,n=!0,r=!0)=>O(`p`,{class:`fb-serif ${n?`fb-italic`:``} ${r?`fb-center`:``}`,style:t},e);function q(e,t,n=`cover`,r=!0,i=1){let a=e?.width&&e.height?e.width/e.height:4/3,o=O(`div`,{class:`fb-print-frame-box`,style:{fontSize:`${i}cqw`}}),s=O(`div`,{class:`fb-print-frame fb-frame-${t} ${n===`contain`?`is-contained`:``}`});if(n===`contain`&&s.style.setProperty(`--ratio`,String(a)),v[t]&&s.append(O(`span`,{class:`fb-print-frame-band`,"aria-hidden":`true`})),s.append(e&&r?U(e,`fb-print-photo fb-print-frame-photo`):O(`div`,{class:`fb-print-frame-photo fb-placeholder`})),t===`corners`)for(let e of[`tl`,`tr`,`bl`,`br`])s.append(O(`span`,{class:`fb-print-frame-corner is-${e}`,"aria-hidden":`true`}));return t===`botanical`&&s.append(V(`tl`),V(`br`)),o.append(s),o}function ae(e,t,n={}){let{layout:r,caption:i,photos:a}=e,{number:o,side:s,showImages:c=!0,onSlotClick:l,activeSlot:u}=n,d=p[r],f=O(`div`,{class:`fb-paper fb-paper-${t.paper} fb-page`}),m=(n,r=``,i=!1,o)=>{let s=a[n]??null,d=b(e,s,t.frame),f=O(`div`,{class:[`fb-slot`,r,i&&`is-framed`,l&&`is-editable`,l&&u===n&&`is-active`].filter(Boolean).join(` `),role:l?`button`:void 0,"aria-label":l?`Photo slot ${n+1}`:void 0,style:o});return l&&f.addEventListener(`click`,()=>l(n)),f.append(s?q(s,d,i?`contain`:`cover`,c):O(`div`,{class:`fb-slot-empty`},l?`Add a photo`:``)),f},h=(e,...t)=>O(`div`,{class:`fb-column`,style:e},...t),g=i?K(i,{fontSize:`3.8cqw`}):null;switch(r){case`single`:f.append(m(0,`fb-bleed`)),i&&f.append(O(`div`,{class:`fb-caption-over`},i));break;case`framed`:f.append(h({padding:`10cqw 9cqw 6cqw`},O(`div`,{class:`fb-grow`},m(0,`fb-fill`,!0)),K(i??``,{marginTop:`5cqw`,fontSize:`4.2cqw`,minHeight:`6cqw`,lineHeight:`1.35`})));break;case`pair`:f.append(h({padding:`7cqw`,gap:`4cqw`},m(0,`fb-grow`),m(1,`fb-grow`),g));break;case`grid`:f.append(h({padding:`7cqw`,gap:`3cqw`},O(`div`,{class:`fb-grid fb-grow`,style:{gap:`3cqw`}},...[0,1,2,3].map(e=>m(e))),g));break;case`collage`:f.append(h({padding:`7cqw`,gap:`3cqw`},m(0,`fb-grow-large`),O(`div`,{class:`fb-row fb-grow`,style:{gap:`3cqw`}},m(1,`fb-grow`),m(2,`fb-grow`)),g));break;case`text`:f.append(O(`div`,{class:`fb-column fb-center`,style:{alignItems:`center`,justifyContent:`center`,padding:`14cqw 12cqw`}},O(`span`,{class:`fb-serif`,style:{fontSize:`18cqw`,lineHeight:`0.6`,opacity:`0.3`},"aria-hidden":`true`},`“`),K(i||(l?`Write something in the caption box below.`:``),{marginTop:`4cqw`,fontSize:`6cqw`,lineHeight:`1.4`,textWrap:`balance`},!0,!1)))}return d&&(f.append(...d.slots.map((e,t)=>m(t,`fb-placed ${d.loose?`is-loose`:``}`,!1,W(e)))),i&&f.append(O(`p`,{class:`fb-placed-caption fb-serif ${d.prose?`is-prose`:`fb-italic`}`,style:W(d.caption)},i))),o!==void 0&&r!==`single`&&f.append(O(`span`,{class:`fb-page-number`,style:s===`left`?{left:`0`}:{right:`0`}},String(o))),f.append(G(s)),f}function oe(e,t,n){let r=[e.author,e.year].filter(Boolean).join(` · `);return O(`div`,{class:`fb-paper fb-paper-${t.paper} fb-page fb-center`,style:{alignItems:`center`,justifyContent:`center`,padding:`12cqw`}},H(),O(`h2`,{class:`fb-serif`,style:{marginTop:`6cqw`,fontSize:`7.5cqw`,fontWeight:`400`,lineHeight:`1.1`,textWrap:`balance`}},e.title),e.subtitle&&K(e.subtitle,{marginTop:`4cqw`,fontSize:`4cqw`,lineHeight:`1.45`},!0,!1),O(`div`,{style:{marginTop:`7cqw`,height:`1px`,width:`20cqw`,background:`currentColor`,opacity:`0.3`}}),r&&O(`p`,{style:{marginTop:`5cqw`,fontSize:`2.6cqw`,letterSpacing:`0.2em`,textTransform:`uppercase`}},r),G(n))}function se(e,t,n){return O(`div`,{class:`fb-paper fb-paper-${t.paper} fb-page fb-center`,style:{alignItems:`center`,justifyContent:`flex-end`,padding:`12cqw`,opacity:`0.9`}},e.colophon&&K(e.colophon,{fontSize:`3.6cqw`},!0,!1),G(n))}function ce(e,t){return O(`div`,{class:`fb-paper fb-paper-${e.paper} fb-page`},G(t))}function J(e,t,n,r=!0){let i={paper:t.paper??`ivory`,frame:t.frame??`none`};switch(e.kind){case`cover`:return z(t);case`back`:return B(t);case`title`:return oe(t,i,n);case`colophon`:return se(t,i,n);case`blank`:return ce(i,n);case`page`:return ae(t.pages[e.index],i,{number:r?e.index+1:void 0,side:n})}}let Y=null;function X(e=.18){try{Y??=new AudioContext;let t=Y.createBuffer(1,Math.floor(Y.sampleRate*.45),Y.sampleRate),n=t.getChannelData(0);for(let e=0;e<n.length;e++){let t=e/n.length,r=Math.sin(Math.PI*Math.min(1,t*2.2))*(1-t)**1.5;n[e]=(Math.random()*2-1)*r*(.6+.4*Math.sin(t*40))}let r=Y.createBufferSource(),i=Y.createBiquadFilter(),a=Y.createGain();r.buffer=t,i.type=`bandpass`,i.frequency.value=2200,i.Q.value=.6,a.gain.value=e,r.connect(i).connect(a).connect(Y.destination),r.start()}catch{}}let le=3/4,ue=`flipbook:sound`,de={layout:`auto`,controls:!0,autoHide:3200,thumbnails:!0,soundButton:!0,sound:!1,fullscreenButton:!0,landscape:!0,keyboard:!0,stiffCovers:!0,shading:1,labels:T},fe=[{name:`under`,z:2},{name:`bend`,z:4},{name:`shadow`,z:5},{name:`curl`,z:7}],Z=(e,t=0,n=0)=>e.length?`polygon(${e.map(e=>`${(e.x+t).toFixed(2)}px ${(e.y+n).toFixed(2)}px`).join(`, `)})`:`polygon(0 0)`,Q=e=>`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="${e}" stroke-linecap="round" stroke-linejoin="round"/></svg>`,$={prev:Q(`M15 6l-6 6 6 6`),next:Q(`M9 6l6 6-6 6`),expand:Q(`M4 9V4h5M20 9V4h-5M4 15v5h5M20 15v5h-5`),collapse:Q(`M9 4v5H4M15 4v5h5M9 20v-5H4M15 20v-5h5`),soundOn:Q(`M4 10v4h3l5 4V6L7 10H4zM16 9a4 4 0 0 1 0 6M18.5 6.5a8 8 0 0 1 0 11`),soundOff:Q(`M4 10v4h3l5 4V6L7 10H4zM17 10l4 4M21 10l-4 4`),grid:`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="3" y="5" width="8" height="14" rx="1"/><rect x="13" y="5" width="8" height="14" rx="1"/></svg>`,phone:`<svg viewBox="0 0 64 64" class="fb-rotate-hint" aria-hidden="true"><rect x="20" y="6" width="24" height="52" rx="4" fill="none" stroke="currentColor" stroke-width="2.5"/><circle cx="32" cy="51" r="2" fill="currentColor"/></svg>`},pe=()=>{try{return localStorage.getItem(ue)}catch{return null}};var me=class e{container;root;reader;settings;layout;size={width:0,height:0};orientation={portrait:!1,touch:!1};portraitChoice=`ask`;soundOn;stripOpen=!1;chromeVisible=!0;hideTimer;lastPlace=``;rendering=!1;dirty=!1;faces=/* @__PURE__ */ new Map;overlays=/* @__PURE__ */ new Map;cleanups=[];els;constructor(t,n){this.container=t,this.settings=e.resolve(n),this.soundOn=this.settings.sound,this.layout=this.buildLayout(),this.reader=new w(this.layout,{frame:(e,t)=>this.paint(e,t),change:()=>this.render(),flip:()=>{this.soundOn&&X(),this.settings.onFlip?.()}},{flipped:this.layout.flippedForPage(this.settings.startPage),physics:n.physics,grip:n.grip}),this.root=O(`div`,{class:`fb-root`}),this.els=this.build(),t.append(this.root);let r=pe();this.settings.soundButton&&r&&(this.soundOn=r===`on`),this.listen(),this.poke(),this.render()}update(t){let n=t.book&&t.book!==this.settings.book;this.settings=e.resolve({...this.settings,...t,labels:{...this.settings.labels,...t.labels}}),t.sound!==void 0&&(this.soundOn=t.sound),t.physics&&(this.reader.engine.physics={...this.reader.engine.physics,...t.physics}),t.grip&&(this.reader.grip={...this.reader.grip,...t.grip}),(n||t.stiffCovers!==void 0)&&this.clearFaces(),this.els.title.textContent=this.settings.book.title,this.poke(),this.render()}next(){this.reader.next()}prev(){this.reader.prev()}go(e){this.reader.go(e)}goToPage(e){this.reader.go(this.reader.layout.flippedForPage(e))}destroy(){this.reader.destroy(),clearTimeout(this.hideTimer),this.cleanups.forEach(e=>e()),this.root.remove()}static resolve(e){let t=Object.fromEntries(Object.entries(e).filter(([,e])=>e!==void 0));return{...de,...t,labels:{...T,...e.labels}}}get spread(){let{layout:e,landscape:t}=this.settings,n=t&&this.orientation.touch&&this.orientation.portrait,r=this.els?.stage.getBoundingClientRect(),i=!!r&&r.width>0&&r.width/r.height<.95;return e===`auto`?!(n&&this.portraitChoice===`single`)&&!i:e===`spread`}buildLayout(){return new S(this.settings.book.pages.length,{spread:this.spread,stiffCovers:this.settings.stiffCovers})}build(){let e=(e,t,n)=>{let r=O(`button`,{type:`button`,class:`fb-button`,"aria-label":e,title:e});return r.append(k(t)),r.addEventListener(`click`,n),r},t=O(`h1`,{class:`fb-title`},this.settings.book.title),n=O(`p`,{class:`fb-byline`}),r=e(``,$.soundOff,()=>this.toggleSound()),i=e(``,$.expand,()=>this.toggleFullscreen()),a=O(`div`,{class:`fb-bar-group`},r,i),o=O(`div`,{class:`fb-bar fb-bar-top`},O(`div`,{class:`fb-bar-group`},O(`div`,{class:`fb-heading`},t,n)),a),s=O(`div`,{class:`fb-book-shadow`}),c=O(`div`,{class:`fb-edge`}),l=O(`div`,{class:`fb-edge`}),u=O(`div`,{class:`fb-spine`}),d=O(`div`,{class:`fb-book`},s,c,l,u),f=O(`div`,{class:`fb-stage`},d),p=e(``,$.prev,()=>this.reader.prev()),m=e(``,$.next,()=>this.reader.next()),h=O(`button`,{type:`button`,class:`fb-pages-button`,"aria-live":`polite`}),g=O(`div`,{class:`fb-bar fb-bar-bottom`},p,h,m);h.addEventListener(`click`,()=>{this.settings.thumbnails&&(this.stripOpen=!this.stripOpen,this.render())});for(let{name:e,z:t}of fe){let n=O(`div`,{class:`fb-light`}),r=O(`div`,{class:`fb-overlay`,style:{zIndex:String(t)}},n);this.overlays.set(e,{clip:r,light:n})}return this.root.append(o,f,g),{top:o,title:t,byline:n,topRight:a,sound:r,fullscreen:i,stage:f,book:d,shadow:s,leftEdge:c,rightEdge:l,spine:u,bottom:g,prev:p,pages:h,next:m,strip:null,rotate:null}}listen(){let{stage:e}=this.els,t=(e,t,n)=>{e.addEventListener(t,n),this.cleanups.push(()=>e.removeEventListener(t,n))},n=new ResizeObserver(()=>this.render());n.observe(e),this.cleanups.push(()=>n.disconnect()),this.cleanups.push(j(e=>{this.orientation=e,this.render()})),t(e,`pointerdown`,e=>{e.button===0&&this.reader.down(this.toBook(e),e.pointerId)}),t(e,`pointermove`,t=>{let n=this.toBook(t);this.poke(),t.pointerType===`mouse`&&this.reader.hover(n),this.reader.move(n,t.pointerId)&&!e.hasPointerCapture(t.pointerId)&&e.setPointerCapture(t.pointerId)}),t(e,`pointerup`,t=>{if(this.reader.up(this.toBook(t),t.pointerId)!==`tap`)return;let n=e.getBoundingClientRect(),r=t.clientX-n.left;r>n.width*2/3?this.reader.next():r<n.width/3&&this.reader.prev()}),t(e,`pointerleave`,()=>this.reader.leave()),t(e,`pointercancel`,()=>this.reader.cancel()),t(this.root,`keydown`,e=>this.settings.keyboard===!0&&this.onKey(e)),t(window,`keydown`,e=>this.settings.keyboard===`global`&&this.onKey(e)),t(document,`fullscreenchange`,()=>this.render())}onKey(e){e.target instanceof HTMLInputElement||e.target instanceof HTMLTextAreaElement||e.target instanceof HTMLSelectElement||([`ArrowRight`,`PageDown`,` `].includes(e.key)?(e.preventDefault(),this.reader.next()):[`ArrowLeft`,`PageUp`].includes(e.key)?(e.preventDefault(),this.reader.prev()):e.key===`Home`?this.reader.go(0):e.key===`End`?this.reader.go(this.reader.layout.length):e.key===`Escape`&&this.stripOpen&&(this.stripOpen=!1,this.render()))}toBook(e){let t=this.els.book.getBoundingClientRect();return{x:e.clientX-(t.left+(this.layout.spread?t.width/2:0)),y:e.clientY-t.top}}poke(){let{autoHide:e}=this.settings;clearTimeout(this.hideTimer),this.chromeVisible||(this.chromeVisible=!0,this.renderChrome()),e!==!1&&(this.hideTimer=setTimeout(()=>{this.chromeVisible=!1,this.renderChrome()},e))}toggleSound(){this.soundOn=!this.soundOn,this.soundOn&&X();try{localStorage.setItem(ue,this.soundOn?`on`:`off`)}catch{}this.renderChrome()}async toggleFullscreen(){document.fullscreenElement?await document.exitFullscreen().catch(()=>{}):await A(this.root)}clearFaces(){this.faces.forEach(e=>e.remove()),this.faces.clear()}render(){if(this.rendering)this.dirty=!0;else{this.rendering=!0;do this.dirty=!1,this.renderOnce();while(this.dirty);this.rendering=!1}}renderOnce(){let{settings:t,reader:n,els:r}=this,{book:i,controls:a}=t,o=r.stage.getBoundingClientRect(),s=this.spread;(s!==this.layout.spread||i.pages.length!==this.layout.pageCount||t.stiffCovers!==this.layout.stiffCovers)&&(this.layout=this.buildLayout(),this.clearFaces());let c=s?2:1,l=!a||o.height<500?16:Math.min(150,o.height*.16),u=Math.max(0,o.width-(s?64:24)),d=Math.max(0,o.height-l),f=Math.floor(Math.min(d*le,u/c)),p=Math.floor(f/le);this.size={width:f,height:p},n.configure({layout:this.layout,width:f,height:p});let{flipped:m,active:h,settled:g,atStart:_,atEnd:v}=n,y=this.layout.leaves,b=0;s&&_&&g&&(b=-f/2),s&&v&&g&&(b=f/2),this.root.style.background=t.background??e.stageTint(i),this.root.tabIndex=t.keyboard===!0?0:-1,r.book.hidden=f<=0,Object.assign(r.book.style,{width:`${f*c}px`,height:`${p}px`,transform:`translateX(${b}px)`,cursor:n.engine.dragging?`grabbing`:`grab`,clipPath:s?``:`inset(-50% -50% -50% 0)`}),Object.assign(r.shadow.style,{left:s&&_&&g?`52%`:`2%`,right:s&&v&&g?`52%`:`2%`});let x=s&&!_&&!v,S=e=>Math.min(10,Math.max(0,e)*.8),C=x&&m>1?S(m-1):0,w=(x||s&&_)&&m<y.length-1?S(y.length-m-1):0;Object.assign(r.leftEdge.style,{display:C?``:`none`,left:`${-C}px`,width:`${C}px`}),Object.assign(r.rightEdge.style,{display:w?``:`none`,right:`${-w}px`,width:`${w}px`}),r.spine.style.left=`${s?f:0}px`,this.renderFaces(h,m,f,p),this.renderOverlays(h,f,p),this.renderChrome(),this.renderStrip(),this.renderRotatePrompt();let T=`${s}:${m}`;T!==this.lastPlace&&(this.lastPlace=T,t.onPageChange?.({flipped:m,label:n.label,faces:this.layout.visible(m)}))}renderFaces(e,t,n,r){let i=this.layout.leaves,a=e?.leaf??null,o=e?.dir??1,s=a===null?t:a+1,c=a===null?t-1:a-1,l=/* @__PURE__ */ new Set;for(let u=Math.max(0,t-2);u<=Math.min(i.length-1,t+1);u++)for(let t of[`front`,`back`]){let d=`${u}:${t}`,f=u===a?t===`front`==(o===1)?`turning`:`flap`:t===`front`?u===s?`right`:`spare`:u===c&&this.layout.spread?`left`:`spare`,p=f===`left`||f===`turning`&&o===-1&&!e?.stiff,m=this.faces.get(d);m||(m=O(`div`,{class:`fb-face`}),m.append(J(t===`front`?i[u].front:i[u].back,this.settings.book,t===`front`?`right`:`left`)),this.faces.set(d,m),this.els.spine.append(m)),l.add(d),Object.assign(m.style,{left:`${p?-n:0}px`,width:`${n}px`,height:`${r}px`,zIndex:String({right:1,left:1,turning:3,flap:6,spare:0}[f]),visibility:f===`spare`?`hidden`:`visible`}),m.setAttribute(`aria-hidden`,String(f!==`left`&&f!==`right`)),u!==a&&Object.assign(m.style,{transform:``,transformOrigin:``,clipPath:``})}for(let[e,t]of this.faces)l.has(e)||(t.remove(),this.faces.delete(e));e&&this.paint(this.reader.engine.frame,e)}renderOverlays(e,t,n){let r=!!e&&!e.stiff,i=e=>`${(t*e).toFixed(1)}px`,a={under:`linear-gradient(to right, rgb(0 0 0 / 0.42), rgb(0 0 0 / 0.2) ${i(.05)}, rgb(0 0 0 / 0.06) ${i(.16)}, transparent ${i(.3)})`,bend:`linear-gradient(to right, rgb(0 0 0 / 0.16), rgb(0 0 0 / 0.04) ${i(.05)}, transparent ${i(.1)})`,shadow:`rgb(0 0 0 / 0.55)`,curl:`linear-gradient(to right, rgb(0 0 0 / 0.3), rgb(0 0 0 / 0.1) ${i(.035)}, rgb(255 255 255 / 0.2) ${i(.11)}, rgb(255 255 255 / 0.06) ${i(.25)}, rgb(0 0 0 / 0.05) ${i(.6)}, rgb(0 0 0 / 0.12) ${i(1)})`};for(let[e,{clip:i,light:o}]of this.overlays){if(!r){i.remove();continue}let s=e===`shadow`;Object.assign(i.style,{left:`${-t}px`,top:`${-n}px`,width:`${t*2}px`,height:`${n*3}px`,filter:s?`blur(${Math.max(3,t*.012)}px)`:``}),Object.assign(o.style,s?{inset:`0`,background:a[e]}:{width:`${t*3}px`,height:`${n*4}px`,background:a[e]}),i.isConnected||this.els.spine.append(i)}r&&e&&this.paint(this.reader.engine.frame,e)}paint(e,t){let{width:n,height:r}=this.size,i=t.dir,o=this.faces.get(`${t.leaf}:front`),s=this.faces.get(`${t.leaf}:back`);if(e.stiff){let t=`perspective(${Math.max(1800,n*5)}px) rotateY(${a.hinge(e.origin,e.point,i)}deg)`;o&&Object.assign(o.style,{transformOrigin:`0 50%`,transform:t,clipPath:``}),s&&Object.assign(s.style,{transformOrigin:`0 50%`,transform:`${t} translateX(${n}px) rotateY(180deg)`,clipPath:``});return}let c=i===1?o:s,l=i===1?s:o,u=new a(n,r,e.origin,e.point),d=u.shade*this.settings.shading;c&&Object.assign(c.style,{transformOrigin:``,transform:``,clipPath:Z(u.flat.map(e=>({x:i===1?e.x:n-e.x,y:e.y})))}),l&&Object.assign(l.style,{transformOrigin:`0 0`,transform:u.flapMatrix(i),clipPath:Z(u.folded.map(e=>({x:i===1?n-e.x:e.x,y:e.y})))});let f=(e,t,a,o)=>{let s=this.overlays.get(e);if(!s)return;let c=Z(t.map(e=>({x:i*e.x,y:e.y})),n,r);if(s.clip.style.opacity=String(o),e===`shadow`){s.light.style.clipPath=c;return}let l=Math.atan2(a*u.normal.y,i*a*u.normal.x);s.clip.style.clipPath=c,s.light.style.transform=`translate(${i*u.center.x+n}px, ${u.center.y+r}px) rotate(${l}rad) translateY(-50%)`};f(`under`,u.folded,1,d),f(`bend`,u.flat,-1,d),f(`shadow`,u.flap,-1,d*.6),f(`curl`,u.flap,-1,d)}renderChrome(){let{els:e,settings:t,reader:n}=this,{labels:r}=t,i=this.chromeVisible||this.stripOpen,a=document.fullscreenElement===this.root,o=(e,t,n)=>{e.setAttribute(`aria-label`,t),e.title=t,n&&e.replaceChildren(k(n))};e.top.hidden=!t.controls,e.bottom.hidden=!t.controls,e.top.classList.toggle(`is-hidden`,!i),e.bottom.classList.toggle(`is-hidden`,!i),e.title.textContent=t.book.title,e.byline.textContent=t.book.author?r.byline(t.book.author):``,e.byline.hidden=!t.book.author,e.sound.hidden=!t.soundButton,e.fullscreen.hidden=!t.fullscreenButton,o(e.sound,this.soundOn?r.soundOff:r.soundOn,this.soundOn?$.soundOn:$.soundOff),o(e.fullscreen,a?r.exitFullscreen:r.fullscreen,a?$.collapse:$.expand),o(e.prev,r.previous),o(e.next,r.next),e.prev.disabled=n.atStart,e.next.disabled=n.atEnd,e.pages.replaceChildren(...t.thumbnails?[k($.grid)]:[],n.label),e.pages.setAttribute(`aria-expanded`,String(this.stripOpen))}renderStrip(){let e=this.stripOpen&&this.settings.thumbnails,{book:t}=this.settings;if(!e){this.els.strip?.remove(),this.els.strip=null;return}let n=O(`div`,{class:`fb-strip-list`});for(let e of this.layout.stops()){let r=O(`button`,{type:`button`,class:`fb-strip-stop`,"aria-current":String(e.flipped===this.reader.flipped),"aria-label":`Go to ${S.describe(e.faces)}`});for(let n of e.faces)r.append(O(`div`,{class:`fb-strip-face`},J(n,t,void 0,!1)));r.addEventListener(`click`,()=>{this.stripOpen=!1,this.reader.go(e.flipped),this.render()}),n.append(r)}let r=O(`div`,{class:`fb-strip`},n);this.els.strip?.remove(),this.els.strip=r,this.els.bottom.before(r),n.querySelector(`[aria-current='true']`)?.scrollIntoView({inline:`center`,block:`nearest`})}renderRotatePrompt(){let{landscape:e,layout:t,labels:n}=this.settings;if(!(e&&t!==`single`&&this.orientation.touch&&this.orientation.portrait&&this.portraitChoice===`ask`)){this.els.rotate?.remove(),this.els.rotate=null;return}if(this.els.rotate)return;let r=O(`button`,{type:`button`,class:`fb-rotate-primary`},n.rotateFullscreen),i=O(`button`,{type:`button`,class:`fb-rotate-secondary`},n.rotateSingle);r.addEventListener(`click`,()=>A(this.root)),i.addEventListener(`click`,()=>{this.portraitChoice=`single`,this.render()}),this.els.rotate=O(`div`,{class:`fb-rotate`},k($.phone),O(`div`,{},O(`p`,{class:`fb-rotate-title`},n.rotateTitle),O(`p`,{class:`fb-rotate-body`},n.rotateBody)),r,i),this.root.append(this.els.rotate)}static stageTint(e){let[t,n,r]=m[e.theme??`classic`].stage;return`radial-gradient(ellipse at 50% 40%, ${t} 0%, ${n} 55%, ${r} 100%)`}};return e.Affine=i,e.BANDED_FRAMES=v,e.BookLayout=S,e.COVER_DESIGNS=h,e.COVER_THEMES=m,e.DECO=ee,e.DEFAULT_GRIP=C,e.DEFAULT_LABELS=T,e.DEFAULT_PHYSICS=o,e.FLEURON=E,e.FRAME_STYLES=_,e.Flipbook=me,e.FlipbookReader=w,e.Fold=a,e.PAGE_LAYOUTS=u,e.PAPER_COLORS=g,e.PLACED_LAYOUTS=p,e.PageTurn=l,e.coverArtMarkup=N,e.coverHasText=y,e.dot=n,e.enterLandscape=A,e.frameOf=x,e.length=r,e.photoFrame=b,e.playPageTurn=X,e.printedPhoto=q,e.renderBackCover=B,e.renderBlank=ce,e.renderColophon=se,e.renderCover=z,e.renderFace=J,e.renderPage=ae,e.renderTitlePage=oe,e.sub=t,e.watchOrientation=j,e})({});
8
+ </svg>`),H=(e,t)=>O(`img`,{src:e.src,alt:e.alt??``,draggable:`false`,decoding:`async`,width:e.width??void 0,height:e.height??void 0,class:t}),U=({x:e,y:t,width:n,height:r,rotate:i})=>({left:`${e}cqw`,top:`${t}cqw`,width:`${n}cqw`,height:`${r}cqw`,...i?{transform:`rotate(${i}deg)`}:{}}),W=e=>O(`div`,{class:`fb-page-surface ${e?`is-${e}`:``}`,"aria-hidden":`true`},O(`div`,{class:`fb-page-surface-grain`}),e&&O(`div`,{class:`fb-page-surface-gutter`}),e&&O(`div`,{class:`fb-page-surface-sheen`})),G=(e,t,n=!0,r=!0)=>O(`p`,{class:`fb-serif ${n?`fb-italic`:``} ${r?`fb-center`:``}`,style:t},e);function K(e,t,n=`cover`,r=!0,i=1){let a=e?.width&&e.height?e.width/e.height:4/3,o=O(`div`,{class:`fb-print-frame-box`,style:{fontSize:`${i}cqw`}}),s=O(`div`,{class:`fb-print-frame fb-frame-${t} ${n===`contain`?`is-contained`:``}`});if(n===`contain`&&s.style.setProperty(`--ratio`,String(a)),v[t]&&s.append(O(`span`,{class:`fb-print-frame-band`,"aria-hidden":`true`})),s.append(e&&r?H(e,`fb-print-photo fb-print-frame-photo`):O(`div`,{class:`fb-print-frame-photo fb-placeholder`})),t===`corners`)for(let e of[`tl`,`tr`,`bl`,`br`])s.append(O(`span`,{class:`fb-print-frame-corner is-${e}`,"aria-hidden":`true`}));return t===`botanical`&&s.append(B(`tl`),B(`br`)),o.append(s),o}function q(e,t,n={}){let{layout:r,caption:i,photos:a}=e,{number:o,side:s,showImages:c=!0,onSlotClick:l,activeSlot:u}=n,d=p[r],f=O(`div`,{class:`fb-paper fb-paper-${t.paper} fb-page`}),m=(n,r=``,i=!1,o)=>{let s=a[n]??null,d=b(e,s,t.frame),f=O(`div`,{class:[`fb-slot`,r,i&&`is-framed`,l&&`is-editable`,l&&u===n&&`is-active`].filter(Boolean).join(` `),role:l?`button`:void 0,"aria-label":l?`Photo slot ${n+1}`:void 0,style:o});return l&&f.addEventListener(`click`,()=>l(n)),f.append(s?K(s,d,i?`contain`:`cover`,c):O(`div`,{class:`fb-slot-empty`},l?`Add a photo`:``)),f},h=(e,...t)=>O(`div`,{class:`fb-column`,style:e},...t),g=i?G(i,{fontSize:`3.8cqw`}):null;switch(r){case`single`:f.append(m(0,`fb-bleed`)),i&&f.append(O(`div`,{class:`fb-caption-over`},i));break;case`framed`:f.append(h({padding:`10cqw 9cqw 6cqw`},O(`div`,{class:`fb-grow`},m(0,`fb-fill`,!0)),G(i??``,{marginTop:`5cqw`,fontSize:`4.2cqw`,minHeight:`6cqw`,lineHeight:`1.35`})));break;case`pair`:f.append(h({padding:`7cqw`,gap:`4cqw`},m(0,`fb-grow`),m(1,`fb-grow`),g));break;case`grid`:f.append(h({padding:`7cqw`,gap:`3cqw`},O(`div`,{class:`fb-grid fb-grow`,style:{gap:`3cqw`}},...[0,1,2,3].map(e=>m(e))),g));break;case`collage`:f.append(h({padding:`7cqw`,gap:`3cqw`},m(0,`fb-grow-large`),O(`div`,{class:`fb-row fb-grow`,style:{gap:`3cqw`}},m(1,`fb-grow`),m(2,`fb-grow`)),g));break;case`text`:f.append(O(`div`,{class:`fb-column fb-center`,style:{alignItems:`center`,justifyContent:`center`,padding:`14cqw 12cqw`}},O(`span`,{class:`fb-serif`,style:{fontSize:`18cqw`,lineHeight:`0.6`,opacity:`0.3`},"aria-hidden":`true`},`“`),G(i||(l?`Write something in the caption box below.`:``),{marginTop:`4cqw`,fontSize:`6cqw`,lineHeight:`1.4`,textWrap:`balance`},!0,!1)))}return d&&(f.append(...d.slots.map((e,t)=>m(t,`fb-placed ${d.loose?`is-loose`:``}`,!1,U(e)))),i&&f.append(O(`p`,{class:`fb-placed-caption fb-serif ${d.prose?`is-prose`:`fb-italic`}`,style:U(d.caption)},i))),o!==void 0&&r!==`single`&&f.append(O(`span`,{class:`fb-page-number`,style:s===`left`?{left:`0`}:{right:`0`}},String(o))),f.append(W(s)),f}function oe(e,t,n){let r=[e.author,e.year].filter(Boolean).join(` · `);return O(`div`,{class:`fb-paper fb-paper-${t.paper} fb-page fb-center`,style:{alignItems:`center`,justifyContent:`center`,padding:`12cqw`}},V(),O(`h2`,{class:`fb-serif`,style:{marginTop:`6cqw`,fontSize:`7.5cqw`,fontWeight:`400`,lineHeight:`1.1`,textWrap:`balance`}},e.title),e.subtitle&&G(e.subtitle,{marginTop:`4cqw`,fontSize:`4cqw`,lineHeight:`1.45`},!0,!1),O(`div`,{style:{marginTop:`7cqw`,height:`1px`,width:`20cqw`,background:`currentColor`,opacity:`0.3`}}),r&&O(`p`,{style:{marginTop:`5cqw`,fontSize:`2.6cqw`,letterSpacing:`0.2em`,textTransform:`uppercase`}},r),W(n))}function se(e,t,n){return O(`div`,{class:`fb-paper fb-paper-${t.paper} fb-page fb-center`,style:{alignItems:`center`,justifyContent:`flex-end`,padding:`12cqw`,opacity:`0.9`}},e.colophon&&G(e.colophon,{fontSize:`3.6cqw`},!0,!1),W(n))}function ce(e,t){return O(`div`,{class:`fb-paper fb-paper-${e.paper} fb-page`},W(t))}function J(e,t,n,r=!0){let i={paper:t.paper??`ivory`,frame:t.frame??`none`};switch(e.kind){case`cover`:return R(t);case`back`:return z(t);case`title`:return oe(t,i,n);case`colophon`:return se(t,i,n);case`blank`:return ce(i,n);case`page`:return q(t.pages[e.index],i,{number:r?e.index+1:void 0,side:n})}}let Y=null;function X(e=.18){try{Y??=new AudioContext;let t=Y.createBuffer(1,Math.floor(Y.sampleRate*.45),Y.sampleRate),n=t.getChannelData(0);for(let e=0;e<n.length;e++){let t=e/n.length,r=Math.sin(Math.PI*Math.min(1,t*2.2))*(1-t)**1.5;n[e]=(Math.random()*2-1)*r*(.6+.4*Math.sin(t*40))}let r=Y.createBufferSource(),i=Y.createBiquadFilter(),a=Y.createGain();r.buffer=t,i.type=`bandpass`,i.frequency.value=2200,i.Q.value=.6,a.gain.value=e,r.connect(i).connect(a).connect(Y.destination),r.start()}catch{}}let le=3/4,ue=`flipbook:sound`,de={layout:`auto`,controls:!0,autoHide:3200,thumbnails:!0,soundButton:!0,sound:!1,fullscreenButton:!0,fullscreenPrompt:!1,landscape:!0,keyboard:!0,stiffCovers:!0,shading:1,labels:T},fe=[{name:`under`,z:2},{name:`bend`,z:4},{name:`shadow`,z:5},{name:`curl`,z:7}],Z=(e,t=0,n=0)=>e.length?`polygon(${e.map(e=>`${(e.x+t).toFixed(2)}px ${(e.y+n).toFixed(2)}px`).join(`, `)})`:`polygon(0 0)`,Q=e=>`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="${e}" stroke-linecap="round" stroke-linejoin="round"/></svg>`,$={prev:Q(`M15 6l-6 6 6 6`),next:Q(`M9 6l6 6-6 6`),expand:Q(`M4 9V4h5M20 9V4h-5M4 15v5h5M20 15v5h-5`),collapse:Q(`M9 4v5H4M15 4v5h5M9 20v-5H4M15 20v-5h5`),soundOn:Q(`M4 10v4h3l5 4V6L7 10H4zM16 9a4 4 0 0 1 0 6M18.5 6.5a8 8 0 0 1 0 11`),soundOff:Q(`M4 10v4h3l5 4V6L7 10H4zM17 10l4 4M21 10l-4 4`),grid:`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="3" y="5" width="8" height="14" rx="1"/><rect x="13" y="5" width="8" height="14" rx="1"/></svg>`,phone:`<svg viewBox="0 0 64 64" class="fb-rotate-hint" aria-hidden="true"><rect x="20" y="6" width="24" height="52" rx="4" fill="none" stroke="currentColor" stroke-width="2.5"/><circle cx="32" cy="51" r="2" fill="currentColor"/></svg>`},pe=()=>{try{return localStorage.getItem(ue)}catch{return null}};var me=class e{container;root;reader;settings;layout;size={width:0,height:0};orientation={portrait:!1,touch:!1};portraitChoice=`ask`;promptAnswered=!1;soundOn;stripOpen=!1;chromeVisible=!0;hideTimer;lastPlace=``;rendering=!1;dirty=!1;faces=/* @__PURE__ */ new Map;overlays=/* @__PURE__ */ new Map;cleanups=[];els;constructor(t,n){this.container=t,this.settings=e.resolve(n),this.soundOn=this.settings.sound,this.layout=this.buildLayout(),this.reader=new w(this.layout,{frame:(e,t)=>this.paint(e,t),change:()=>this.render(),flip:()=>{this.soundOn&&X(),this.settings.onFlip?.()}},{flipped:this.layout.flippedForPage(this.settings.startPage),physics:n.physics,grip:n.grip}),this.root=O(`div`,{class:`fb-root`}),this.els=this.build(),t.append(this.root);let r=pe();this.settings.soundButton&&r&&(this.soundOn=r===`on`),this.listen(),this.poke(),this.render()}update(t){let n=t.book&&t.book!==this.settings.book;t.fullscreenPrompt&&!this.settings.fullscreenPrompt&&(this.promptAnswered=!1),this.settings=e.resolve({...this.settings,...t,labels:{...this.settings.labels,...t.labels}}),t.sound!==void 0&&(this.soundOn=t.sound),t.physics&&(this.reader.engine.physics={...this.reader.engine.physics,...t.physics}),t.grip&&(this.reader.grip={...this.reader.grip,...t.grip}),(n||t.stiffCovers!==void 0)&&this.clearFaces(),this.els.title.textContent=this.settings.book.title,this.poke(),this.render()}next(){this.reader.next()}prev(){this.reader.prev()}go(e){this.reader.go(e)}goToPage(e){this.reader.go(this.reader.layout.flippedForPage(e))}destroy(){this.reader.destroy(),clearTimeout(this.hideTimer),this.cleanups.forEach(e=>e()),this.root.remove()}static resolve(e){let t=Object.fromEntries(Object.entries(e).filter(([,e])=>e!==void 0));return{...de,...t,labels:{...T,...e.labels}}}get spread(){let{layout:e,landscape:t}=this.settings,n=t&&this.orientation.touch&&this.orientation.portrait,r=this.els?.stage.getBoundingClientRect(),i=!!r&&r.width>0&&r.width/r.height<.95;return e===`auto`?!(n&&this.portraitChoice===`single`)&&!i:e===`spread`}buildLayout(){return new S(this.settings.book.pages.length,{spread:this.spread,stiffCovers:this.settings.stiffCovers})}build(){let e=(e,t,n)=>{let r=O(`button`,{type:`button`,class:`fb-button`,"aria-label":e,title:e});return r.append(k(t)),r.addEventListener(`click`,n),r},t=O(`h1`,{class:`fb-title`},this.settings.book.title),n=O(`p`,{class:`fb-byline`}),r=e(``,$.soundOff,()=>this.toggleSound()),i=e(``,$.expand,()=>this.toggleFullscreen()),a=O(`div`,{class:`fb-bar-group`},r,i),o=O(`div`,{class:`fb-bar fb-bar-top`},O(`div`,{class:`fb-bar-group`},O(`div`,{class:`fb-heading`},t,n)),a),s=O(`div`,{class:`fb-book-shadow`}),c=O(`div`,{class:`fb-edge`}),l=O(`div`,{class:`fb-edge`}),u=O(`div`,{class:`fb-spine`}),d=O(`div`,{class:`fb-book`},s,c,l,u),f=O(`div`,{class:`fb-stage`},d),p=e(``,$.prev,()=>this.reader.prev()),m=e(``,$.next,()=>this.reader.next()),h=O(`button`,{type:`button`,class:`fb-pages-button`,"aria-live":`polite`}),g=O(`div`,{class:`fb-bar fb-bar-bottom`},p,h,m);h.addEventListener(`click`,()=>{this.settings.thumbnails&&(this.stripOpen=!this.stripOpen,this.render())});for(let{name:e,z:t}of fe){let n=O(`div`,{class:`fb-light`}),r=O(`div`,{class:`fb-overlay`,style:{zIndex:String(t)}},n);this.overlays.set(e,{clip:r,light:n})}return this.root.append(o,f,g),{top:o,title:t,byline:n,topRight:a,sound:r,fullscreen:i,stage:f,book:d,shadow:s,leftEdge:c,rightEdge:l,spine:u,bottom:g,prev:p,pages:h,next:m,strip:null,rotate:null,prompt:null}}listen(){let{stage:e}=this.els,t=(e,t,n)=>{e.addEventListener(t,n),this.cleanups.push(()=>e.removeEventListener(t,n))},n=new ResizeObserver(()=>this.render());n.observe(e),this.cleanups.push(()=>n.disconnect()),this.cleanups.push(ne(e=>{this.orientation=e,this.render()})),t(e,`pointerdown`,e=>{e.button===0&&this.reader.down(this.toBook(e),e.pointerId)}),t(e,`pointermove`,t=>{let n=this.toBook(t);this.poke(),t.pointerType===`mouse`&&this.reader.hover(n),this.reader.move(n,t.pointerId)&&!e.hasPointerCapture(t.pointerId)&&e.setPointerCapture(t.pointerId)}),t(e,`pointerup`,t=>{if(this.reader.up(this.toBook(t),t.pointerId)!==`tap`)return;let n=e.getBoundingClientRect(),r=t.clientX-n.left;r>n.width*2/3?this.reader.next():r<n.width/3&&this.reader.prev()}),t(e,`pointerleave`,()=>this.reader.leave()),t(e,`pointercancel`,()=>this.reader.cancel()),t(this.root,`keydown`,e=>this.settings.keyboard===!0&&this.onKey(e)),t(window,`keydown`,e=>this.els.prompt&&this.answerPrompt(e.key!==`Escape`)),t(window,`keydown`,e=>this.settings.keyboard===`global`&&this.onKey(e)),t(document,`fullscreenchange`,()=>{document.fullscreenElement===this.root&&(this.promptAnswered=!0),this.render()})}onKey(e){e.target instanceof HTMLInputElement||e.target instanceof HTMLTextAreaElement||e.target instanceof HTMLSelectElement||([`ArrowRight`,`PageDown`,` `].includes(e.key)?(e.preventDefault(),this.reader.next()):[`ArrowLeft`,`PageUp`].includes(e.key)?(e.preventDefault(),this.reader.prev()):e.key===`Home`?this.reader.go(0):e.key===`End`?this.reader.go(this.reader.layout.length):e.key===`Escape`&&this.stripOpen&&(this.stripOpen=!1,this.render()))}toBook(e){let t=this.els.book.getBoundingClientRect();return{x:e.clientX-(t.left+(this.layout.spread?t.width/2:0)),y:e.clientY-t.top}}poke(){let{autoHide:e}=this.settings;clearTimeout(this.hideTimer),this.chromeVisible||(this.chromeVisible=!0,this.renderChrome()),e!==!1&&(this.hideTimer=setTimeout(()=>{this.chromeVisible=!1,this.renderChrome()},e))}toggleSound(){this.soundOn=!this.soundOn,this.soundOn&&X();try{localStorage.setItem(ue,this.soundOn?`on`:`off`)}catch{}this.renderChrome()}async toggleFullscreen(){document.fullscreenElement?await document.exitFullscreen().catch(()=>{}):await A(this.root)}answerPrompt(e){this.promptAnswered=!0,this.render(),e&&A(this.root)}clearFaces(){this.faces.forEach(e=>e.remove()),this.faces.clear()}render(){if(this.rendering)this.dirty=!0;else{this.rendering=!0;do this.dirty=!1,this.renderOnce();while(this.dirty);this.rendering=!1}}renderOnce(){let{settings:t,reader:n,els:r}=this,{book:i,controls:a}=t,o=r.stage.getBoundingClientRect(),s=this.spread;(s!==this.layout.spread||i.pages.length!==this.layout.pageCount||t.stiffCovers!==this.layout.stiffCovers)&&(this.layout=this.buildLayout(),this.clearFaces());let c=s?2:1,l=!a||o.height<500?16:Math.min(150,o.height*.16),u=Math.max(0,o.width-(s?64:24)),d=Math.max(0,o.height-l),f=Math.floor(Math.min(d*le,u/c)),p=Math.floor(f/le);this.size={width:f,height:p},n.configure({layout:this.layout,width:f,height:p});let{flipped:m,active:h,settled:g,atStart:_,atEnd:v}=n,y=this.layout.leaves,b=0;s&&_&&g&&(b=-f/2),s&&v&&g&&(b=f/2),this.root.style.background=t.background??e.stageTint(i),this.root.tabIndex=t.keyboard===!0?0:-1,r.book.hidden=f<=0,Object.assign(r.book.style,{width:`${f*c}px`,height:`${p}px`,transform:`translateX(${b}px)`,cursor:n.engine.dragging?`grabbing`:`grab`,clipPath:s?``:`inset(-50% -50% -50% 0)`}),Object.assign(r.shadow.style,{left:s&&_&&g?`52%`:`2%`,right:s&&v&&g?`52%`:`2%`});let x=s&&!_&&!v,S=e=>Math.min(10,Math.max(0,e)*.8),C=x&&m>1?S(m-1):0,w=(x||s&&_)&&m<y.length-1?S(y.length-m-1):0;Object.assign(r.leftEdge.style,{display:C?``:`none`,left:`${-C}px`,width:`${C}px`}),Object.assign(r.rightEdge.style,{display:w?``:`none`,right:`${-w}px`,width:`${w}px`}),r.spine.style.left=`${s?f:0}px`,this.renderFaces(h,m,f,p),this.renderOverlays(h,f,p),this.renderChrome(),this.renderStrip(),this.renderRotatePrompt(),this.renderFullscreenPrompt();let T=`${s}:${m}`;T!==this.lastPlace&&(this.lastPlace=T,t.onPageChange?.({flipped:m,label:n.label,faces:this.layout.visible(m)}))}renderFaces(e,t,n,r){let i=this.layout.leaves,a=e?.leaf??null,o=e?.dir??1,s=a===null?t:a+1,c=a===null?t-1:a-1,l=/* @__PURE__ */ new Set;for(let u=Math.max(0,t-2);u<=Math.min(i.length-1,t+1);u++)for(let t of[`front`,`back`]){let d=`${u}:${t}`,f=u===a?t===`front`==(o===1)?`turning`:`flap`:t===`front`?u===s?`right`:`spare`:u===c&&this.layout.spread?`left`:`spare`,p=f===`left`||f===`turning`&&o===-1&&!e?.stiff,m=this.faces.get(d);m||(m=O(`div`,{class:`fb-face`}),m.append(J(t===`front`?i[u].front:i[u].back,this.settings.book,t===`front`?`right`:`left`)),this.faces.set(d,m),this.els.spine.append(m)),l.add(d),Object.assign(m.style,{left:`${p?-n:0}px`,width:`${n}px`,height:`${r}px`,zIndex:String({right:1,left:1,turning:3,flap:6,spare:0}[f]),visibility:f===`spare`?`hidden`:`visible`}),m.setAttribute(`aria-hidden`,String(f!==`left`&&f!==`right`)),u!==a&&Object.assign(m.style,{transform:``,transformOrigin:``,clipPath:``})}for(let[e,t]of this.faces)l.has(e)||(t.remove(),this.faces.delete(e));e&&this.paint(this.reader.engine.frame,e)}renderOverlays(e,t,n){let r=!!e&&!e.stiff,i=e=>`${(t*e).toFixed(1)}px`,a={under:`linear-gradient(to right, rgb(0 0 0 / 0.42), rgb(0 0 0 / 0.2) ${i(.05)}, rgb(0 0 0 / 0.06) ${i(.16)}, transparent ${i(.3)})`,bend:`linear-gradient(to right, rgb(0 0 0 / 0.16), rgb(0 0 0 / 0.04) ${i(.05)}, transparent ${i(.1)})`,shadow:`rgb(0 0 0 / 0.55)`,curl:`linear-gradient(to right, rgb(0 0 0 / 0.3), rgb(0 0 0 / 0.1) ${i(.035)}, rgb(255 255 255 / 0.2) ${i(.11)}, rgb(255 255 255 / 0.06) ${i(.25)}, rgb(0 0 0 / 0.05) ${i(.6)}, rgb(0 0 0 / 0.12) ${i(1)})`};for(let[e,{clip:i,light:o}]of this.overlays){if(!r){i.remove();continue}let s=e===`shadow`;Object.assign(i.style,{left:`${-t}px`,top:`${-n}px`,width:`${t*2}px`,height:`${n*3}px`,filter:s?`blur(${Math.max(3,t*.012)}px)`:``}),Object.assign(o.style,s?{inset:`0`,background:a[e]}:{width:`${t*3}px`,height:`${n*4}px`,background:a[e]}),i.isConnected||this.els.spine.append(i)}r&&e&&this.paint(this.reader.engine.frame,e)}paint(e,t){let{width:n,height:r}=this.size,i=t.dir,o=this.faces.get(`${t.leaf}:front`),s=this.faces.get(`${t.leaf}:back`);if(e.stiff){let t=`perspective(${Math.max(1800,n*5)}px) rotateY(${a.hinge(e.origin,e.point,i)}deg)`;o&&Object.assign(o.style,{transformOrigin:`0 50%`,transform:t,clipPath:``}),s&&Object.assign(s.style,{transformOrigin:`0 50%`,transform:`${t} translateX(${n}px) rotateY(180deg)`,clipPath:``});return}let c=i===1?o:s,l=i===1?s:o,u=new a(n,r,e.origin,e.point),d=u.shade*this.settings.shading;c&&Object.assign(c.style,{transformOrigin:``,transform:``,clipPath:Z(u.flat.map(e=>({x:i===1?e.x:n-e.x,y:e.y})))}),l&&Object.assign(l.style,{transformOrigin:`0 0`,transform:u.flapMatrix(i),clipPath:Z(u.folded.map(e=>({x:i===1?n-e.x:e.x,y:e.y})))});let f=(e,t,a,o)=>{let s=this.overlays.get(e);if(!s)return;let c=Z(t.map(e=>({x:i*e.x,y:e.y})),n,r);if(s.clip.style.opacity=String(o),e===`shadow`){s.light.style.clipPath=c;return}let l=Math.atan2(a*u.normal.y,i*a*u.normal.x);s.clip.style.clipPath=c,s.light.style.transform=`translate(${i*u.center.x+n}px, ${u.center.y+r}px) rotate(${l}rad) translateY(-50%)`};f(`under`,u.folded,1,d),f(`bend`,u.flat,-1,d),f(`shadow`,u.flap,-1,d*.6),f(`curl`,u.flap,-1,d)}renderChrome(){let{els:e,settings:t,reader:n}=this,{labels:r}=t,i=this.chromeVisible||this.stripOpen,a=document.fullscreenElement===this.root,o=(e,t,n)=>{e.setAttribute(`aria-label`,t),e.title=t,n&&e.replaceChildren(k(n))};e.top.hidden=!t.controls,e.bottom.hidden=!t.controls,e.top.classList.toggle(`is-hidden`,!i),e.bottom.classList.toggle(`is-hidden`,!i),e.title.textContent=t.book.title,e.byline.textContent=t.book.author?r.byline(t.book.author):``,e.byline.hidden=!t.book.author,e.sound.hidden=!t.soundButton,e.fullscreen.hidden=!t.fullscreenButton,o(e.sound,this.soundOn?r.soundOff:r.soundOn,this.soundOn?$.soundOn:$.soundOff),o(e.fullscreen,a?r.exitFullscreen:r.fullscreen,a?$.collapse:$.expand),o(e.prev,r.previous),o(e.next,r.next),e.prev.disabled=n.atStart,e.next.disabled=n.atEnd,e.pages.replaceChildren(...t.thumbnails?[k($.grid)]:[],n.label),e.pages.setAttribute(`aria-expanded`,String(this.stripOpen))}renderStrip(){let e=this.stripOpen&&this.settings.thumbnails,{book:t}=this.settings;if(!e){this.els.strip?.remove(),this.els.strip=null;return}let n=O(`div`,{class:`fb-strip-list`});for(let e of this.layout.stops()){let r=O(`button`,{type:`button`,class:`fb-strip-stop`,"aria-current":String(e.flipped===this.reader.flipped),"aria-label":`Go to ${S.describe(e.faces)}`});for(let n of e.faces)r.append(O(`div`,{class:`fb-strip-face`},J(n,t,void 0,!1)));r.addEventListener(`click`,()=>{this.stripOpen=!1,this.reader.go(e.flipped),this.render()}),n.append(r)}let r=O(`div`,{class:`fb-strip`},n);this.els.strip?.remove(),this.els.strip=r,this.els.bottom.before(r),n.querySelector(`[aria-current='true']`)?.scrollIntoView({inline:`center`,block:`nearest`})}renderRotatePrompt(){let{landscape:e,layout:t,labels:n}=this.settings;if(!(e&&t!==`single`&&this.orientation.touch&&this.orientation.portrait&&this.portraitChoice===`ask`)){this.els.rotate?.remove(),this.els.rotate=null;return}if(this.els.rotate)return;let r=O(`button`,{type:`button`,class:`fb-rotate-primary`},n.rotateFullscreen),i=O(`button`,{type:`button`,class:`fb-rotate-secondary`},n.rotateSingle);r.addEventListener(`click`,()=>A(this.root)),i.addEventListener(`click`,()=>{this.portraitChoice=`single`,this.render()}),this.els.rotate=O(`div`,{class:`fb-rotate`},k($.phone),O(`div`,{},O(`p`,{class:`fb-rotate-title`},n.rotateTitle),O(`p`,{class:`fb-rotate-body`},n.rotateBody)),r,i),this.root.append(this.els.rotate)}renderFullscreenPrompt(){let{fullscreenPrompt:e,labels:t}=this.settings;if(!e||this.promptAnswered||!document.fullscreenEnabled||document.fullscreenElement||this.els.rotate){this.els.prompt?.remove(),this.els.prompt=null;return}if(this.els.prompt)return;let n=O(`button`,{type:`button`,class:`fb-fullscreen-prompt`}),r=O(`span`,{class:`fb-fullscreen-prompt-label`},t.fullscreenPrompt);r.prepend(k($.expand)),n.append(r),n.addEventListener(`click`,()=>this.answerPrompt(!0)),this.els.prompt=n,this.root.append(n)}static stageTint(e){let[t,n,r]=m[e.theme??`classic`].stage;return`radial-gradient(ellipse at 50% 40%, ${t} 0%, ${n} 55%, ${r} 100%)`}};return e.Affine=i,e.BANDED_FRAMES=v,e.BookLayout=S,e.COVER_DESIGNS=h,e.COVER_THEMES=m,e.DECO=D,e.DEFAULT_GRIP=C,e.DEFAULT_LABELS=T,e.DEFAULT_PHYSICS=o,e.FLEURON=ee,e.FRAME_STYLES=_,e.Flipbook=me,e.FlipbookReader=w,e.Fold=a,e.PAGE_LAYOUTS=u,e.PAPER_COLORS=g,e.PLACED_LAYOUTS=p,e.PageTurn=l,e.coverArtMarkup=j,e.coverHasText=y,e.dot=n,e.enterLandscape=A,e.frameOf=x,e.length=r,e.photoFrame=b,e.playPageTurn=X,e.printedPhoto=K,e.renderBackCover=z,e.renderBlank=ce,e.renderColophon=se,e.renderCover=R,e.renderFace=J,e.renderPage=q,e.renderTitlePage=oe,e.sub=t,e.watchOrientation=ne,e})({});
package/dist/index.cjs CHANGED
@@ -405,6 +405,7 @@ const DEFAULTS = {
405
405
  soundButton: true,
406
406
  sound: false,
407
407
  fullscreenButton: true,
408
+ fullscreenPrompt: false,
408
409
  landscape: true,
409
410
  keyboard: true,
410
411
  stiffCovers: true,
@@ -467,6 +468,7 @@ var Flipbook = class Flipbook {
467
468
  touch: false
468
469
  };
469
470
  portraitChoice = "ask";
471
+ promptAnswered = false;
470
472
  soundOn;
471
473
  stripOpen = false;
472
474
  chromeVisible = true;
@@ -507,6 +509,7 @@ var Flipbook = class Flipbook {
507
509
  /** Changes options in place; the reader keeps their page. */
508
510
  update(options) {
509
511
  const bookChanged = options.book && options.book !== this.settings.book;
512
+ if (options.fullscreenPrompt && !this.settings.fullscreenPrompt) this.promptAnswered = false;
510
513
  this.settings = Flipbook.resolve({
511
514
  ...this.settings,
512
515
  ...options,
@@ -641,7 +644,8 @@ var Flipbook = class Flipbook {
641
644
  pages,
642
645
  next,
643
646
  strip: null,
644
- rotate: null
647
+ rotate: null,
648
+ prompt: null
645
649
  };
646
650
  }
647
651
  listen() {
@@ -676,8 +680,12 @@ var Flipbook = class Flipbook {
676
680
  on(stage, "pointerleave", () => this.reader.leave());
677
681
  on(stage, "pointercancel", () => this.reader.cancel());
678
682
  on(this.root, "keydown", (e) => this.settings.keyboard === true && this.onKey(e));
683
+ on(window, "keydown", (e) => this.els.prompt && this.answerPrompt(e.key !== "Escape"));
679
684
  on(window, "keydown", (e) => this.settings.keyboard === "global" && this.onKey(e));
680
- on(document, "fullscreenchange", () => this.render());
685
+ on(document, "fullscreenchange", () => {
686
+ if (document.fullscreenElement === this.root) this.promptAnswered = true;
687
+ this.render();
688
+ });
681
689
  }
682
690
  onKey(e) {
683
691
  if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement || e.target instanceof HTMLSelectElement) return;
@@ -731,6 +739,12 @@ var Flipbook = class Flipbook {
731
739
  if (document.fullscreenElement) await document.exitFullscreen().catch(() => {});
732
740
  else await enterLandscape(this.root);
733
741
  }
742
+ /** Closes the full screen prompt, going full screen unless the reader declined. */
743
+ answerPrompt(open) {
744
+ this.promptAnswered = true;
745
+ this.render();
746
+ if (open) enterLandscape(this.root);
747
+ }
734
748
  clearFaces() {
735
749
  this.faces.forEach((el) => el.remove());
736
750
  this.faces.clear();
@@ -811,6 +825,7 @@ var Flipbook = class Flipbook {
811
825
  this.renderChrome();
812
826
  this.renderStrip();
813
827
  this.renderRotatePrompt();
828
+ this.renderFullscreenPrompt();
814
829
  const place = `${spread}:${flipped}`;
815
830
  if (place !== this.lastPlace) {
816
831
  this.lastPlace = place;
@@ -1049,6 +1064,26 @@ var Flipbook = class Flipbook {
1049
1064
  this.els.rotate = h("div", { class: "fb-rotate" }, svg(ICONS.phone), h("div", {}, h("p", { class: "fb-rotate-title" }, labels.rotateTitle), h("p", { class: "fb-rotate-body" }, labels.rotateBody)), primary, secondary);
1050
1065
  this.root.append(this.els.rotate);
1051
1066
  }
1067
+ /** Browsers only go full screen after a gesture, so the first tap or key press does it. The rotate prompt offers it already. */
1068
+ renderFullscreenPrompt() {
1069
+ const { fullscreenPrompt, labels } = this.settings;
1070
+ if (!(fullscreenPrompt && !this.promptAnswered && document.fullscreenEnabled && !document.fullscreenElement && !this.els.rotate)) {
1071
+ this.els.prompt?.remove();
1072
+ this.els.prompt = null;
1073
+ return;
1074
+ }
1075
+ if (this.els.prompt) return;
1076
+ const prompt = h("button", {
1077
+ type: "button",
1078
+ class: "fb-fullscreen-prompt"
1079
+ });
1080
+ const pill = h("span", { class: "fb-fullscreen-prompt-label" }, labels.fullscreenPrompt);
1081
+ pill.prepend(svg(ICONS.expand));
1082
+ prompt.append(pill);
1083
+ prompt.addEventListener("click", () => this.answerPrompt(true));
1084
+ this.els.prompt = prompt;
1085
+ this.root.append(prompt);
1086
+ }
1052
1087
  static stageTint(book) {
1053
1088
  const [inner, middle, outer] = _toneflix_flipbook_core.COVER_THEMES[book.theme ?? "classic"].stage;
1054
1089
  return `radial-gradient(ellipse at 50% 40%, ${inner} 0%, ${middle} 55%, ${outer} 100%)`;
package/dist/index.d.cts CHANGED
@@ -21,6 +21,8 @@ interface FlipbookOptions {
21
21
  /** Play a paper sound on each turn. The sound button remembers the reader's choice. */
22
22
  sound?: boolean;
23
23
  fullscreenButton?: boolean;
24
+ /** Cover the book with a "Tap to open full screen" prompt until the first tap or key press, where pages can go full screen. */
25
+ fullscreenPrompt?: boolean;
24
26
  /** Ask phones held upright to turn sideways, offering single pages instead. */
25
27
  landscape?: boolean;
26
28
  /** Arrow, page and Home/End keys: while the book has focus (true) or anywhere on the page ('global'). */
@@ -51,6 +53,7 @@ export declare class Flipbook {
51
53
  private size;
52
54
  private orientation;
53
55
  private portraitChoice;
56
+ private promptAnswered;
54
57
  private soundOn;
55
58
  private stripOpen;
56
59
  private chromeVisible;
@@ -83,6 +86,8 @@ export declare class Flipbook {
83
86
  private poke;
84
87
  private toggleSound;
85
88
  private toggleFullscreen;
89
+ /** Closes the full screen prompt, going full screen unless the reader declined. */
90
+ private answerPrompt;
86
91
  private clearFaces;
87
92
  /** Brings the DOM in line with the reader. Re-entrant calls (from the reader) run once more at the end. */
88
93
  private render;
@@ -96,6 +101,8 @@ export declare class Flipbook {
96
101
  private renderStrip;
97
102
  /** Shown on phones held upright: books are read sideways. */
98
103
  private renderRotatePrompt;
104
+ /** Browsers only go full screen after a gesture, so the first tap or key press does it. The rotate prompt offers it already. */
105
+ private renderFullscreenPrompt;
99
106
  private static stageTint;
100
107
  }
101
108
  type Side = 'left' | 'right';
package/dist/index.d.mts CHANGED
@@ -21,6 +21,8 @@ interface FlipbookOptions {
21
21
  /** Play a paper sound on each turn. The sound button remembers the reader's choice. */
22
22
  sound?: boolean;
23
23
  fullscreenButton?: boolean;
24
+ /** Cover the book with a "Tap to open full screen" prompt until the first tap or key press, where pages can go full screen. */
25
+ fullscreenPrompt?: boolean;
24
26
  /** Ask phones held upright to turn sideways, offering single pages instead. */
25
27
  landscape?: boolean;
26
28
  /** Arrow, page and Home/End keys: while the book has focus (true) or anywhere on the page ('global'). */
@@ -51,6 +53,7 @@ export declare class Flipbook {
51
53
  private size;
52
54
  private orientation;
53
55
  private portraitChoice;
56
+ private promptAnswered;
54
57
  private soundOn;
55
58
  private stripOpen;
56
59
  private chromeVisible;
@@ -83,6 +86,8 @@ export declare class Flipbook {
83
86
  private poke;
84
87
  private toggleSound;
85
88
  private toggleFullscreen;
89
+ /** Closes the full screen prompt, going full screen unless the reader declined. */
90
+ private answerPrompt;
86
91
  private clearFaces;
87
92
  /** Brings the DOM in line with the reader. Re-entrant calls (from the reader) run once more at the end. */
88
93
  private render;
@@ -96,6 +101,8 @@ export declare class Flipbook {
96
101
  private renderStrip;
97
102
  /** Shown on phones held upright: books are read sideways. */
98
103
  private renderRotatePrompt;
104
+ /** Browsers only go full screen after a gesture, so the first tap or key press does it. The rotate prompt offers it already. */
105
+ private renderFullscreenPrompt;
99
106
  private static stageTint;
100
107
  }
101
108
  type Side = 'left' | 'right';
package/dist/index.mjs CHANGED
@@ -405,6 +405,7 @@ const DEFAULTS = {
405
405
  soundButton: true,
406
406
  sound: false,
407
407
  fullscreenButton: true,
408
+ fullscreenPrompt: false,
408
409
  landscape: true,
409
410
  keyboard: true,
410
411
  stiffCovers: true,
@@ -467,6 +468,7 @@ var Flipbook = class Flipbook {
467
468
  touch: false
468
469
  };
469
470
  portraitChoice = "ask";
471
+ promptAnswered = false;
470
472
  soundOn;
471
473
  stripOpen = false;
472
474
  chromeVisible = true;
@@ -507,6 +509,7 @@ var Flipbook = class Flipbook {
507
509
  /** Changes options in place; the reader keeps their page. */
508
510
  update(options) {
509
511
  const bookChanged = options.book && options.book !== this.settings.book;
512
+ if (options.fullscreenPrompt && !this.settings.fullscreenPrompt) this.promptAnswered = false;
510
513
  this.settings = Flipbook.resolve({
511
514
  ...this.settings,
512
515
  ...options,
@@ -641,7 +644,8 @@ var Flipbook = class Flipbook {
641
644
  pages,
642
645
  next,
643
646
  strip: null,
644
- rotate: null
647
+ rotate: null,
648
+ prompt: null
645
649
  };
646
650
  }
647
651
  listen() {
@@ -676,8 +680,12 @@ var Flipbook = class Flipbook {
676
680
  on(stage, "pointerleave", () => this.reader.leave());
677
681
  on(stage, "pointercancel", () => this.reader.cancel());
678
682
  on(this.root, "keydown", (e) => this.settings.keyboard === true && this.onKey(e));
683
+ on(window, "keydown", (e) => this.els.prompt && this.answerPrompt(e.key !== "Escape"));
679
684
  on(window, "keydown", (e) => this.settings.keyboard === "global" && this.onKey(e));
680
- on(document, "fullscreenchange", () => this.render());
685
+ on(document, "fullscreenchange", () => {
686
+ if (document.fullscreenElement === this.root) this.promptAnswered = true;
687
+ this.render();
688
+ });
681
689
  }
682
690
  onKey(e) {
683
691
  if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement || e.target instanceof HTMLSelectElement) return;
@@ -731,6 +739,12 @@ var Flipbook = class Flipbook {
731
739
  if (document.fullscreenElement) await document.exitFullscreen().catch(() => {});
732
740
  else await enterLandscape(this.root);
733
741
  }
742
+ /** Closes the full screen prompt, going full screen unless the reader declined. */
743
+ answerPrompt(open) {
744
+ this.promptAnswered = true;
745
+ this.render();
746
+ if (open) enterLandscape(this.root);
747
+ }
734
748
  clearFaces() {
735
749
  this.faces.forEach((el) => el.remove());
736
750
  this.faces.clear();
@@ -811,6 +825,7 @@ var Flipbook = class Flipbook {
811
825
  this.renderChrome();
812
826
  this.renderStrip();
813
827
  this.renderRotatePrompt();
828
+ this.renderFullscreenPrompt();
814
829
  const place = `${spread}:${flipped}`;
815
830
  if (place !== this.lastPlace) {
816
831
  this.lastPlace = place;
@@ -1049,6 +1064,26 @@ var Flipbook = class Flipbook {
1049
1064
  this.els.rotate = h("div", { class: "fb-rotate" }, svg(ICONS.phone), h("div", {}, h("p", { class: "fb-rotate-title" }, labels.rotateTitle), h("p", { class: "fb-rotate-body" }, labels.rotateBody)), primary, secondary);
1050
1065
  this.root.append(this.els.rotate);
1051
1066
  }
1067
+ /** Browsers only go full screen after a gesture, so the first tap or key press does it. The rotate prompt offers it already. */
1068
+ renderFullscreenPrompt() {
1069
+ const { fullscreenPrompt, labels } = this.settings;
1070
+ if (!(fullscreenPrompt && !this.promptAnswered && document.fullscreenEnabled && !document.fullscreenElement && !this.els.rotate)) {
1071
+ this.els.prompt?.remove();
1072
+ this.els.prompt = null;
1073
+ return;
1074
+ }
1075
+ if (this.els.prompt) return;
1076
+ const prompt = h("button", {
1077
+ type: "button",
1078
+ class: "fb-fullscreen-prompt"
1079
+ });
1080
+ const pill = h("span", { class: "fb-fullscreen-prompt-label" }, labels.fullscreenPrompt);
1081
+ pill.prepend(svg(ICONS.expand));
1082
+ prompt.append(pill);
1083
+ prompt.addEventListener("click", () => this.answerPrompt(true));
1084
+ this.els.prompt = prompt;
1085
+ this.root.append(prompt);
1086
+ }
1052
1087
  static stageTint(book) {
1053
1088
  const [inner, middle, outer] = COVER_THEMES[book.theme ?? "classic"].stage;
1054
1089
  return `radial-gradient(ellipse at 50% 40%, ${inner} 0%, ${middle} 55%, ${outer} 100%)`;
package/dist/style.css CHANGED
@@ -311,6 +311,33 @@
311
311
  text-decoration: underline;
312
312
  text-underline-offset: 4px;
313
313
  }
314
+ /* Covers the book until the first tap or key press opens it full screen. */
315
+ .fb-root .fb-fullscreen-prompt {
316
+ position: absolute;
317
+ inset: 0;
318
+ z-index: 40;
319
+ display: flex;
320
+ align-items: flex-end;
321
+ justify-content: center;
322
+ padding: 0 16px 96px;
323
+ background: rgb(0 0 0 / 0.3);
324
+ }
325
+ .fb-fullscreen-prompt-label {
326
+ display: flex;
327
+ align-items: center;
328
+ gap: 8px;
329
+ padding: 10px 20px;
330
+ border-radius: 999px;
331
+ background: #fff;
332
+ box-shadow: 0 10px 24px rgb(0 0 0 / 0.3);
333
+ font-size: 14px;
334
+ font-weight: 500;
335
+ color: #2c343e;
336
+ }
337
+ .fb-fullscreen-prompt-label svg {
338
+ width: 20px;
339
+ height: 20px;
340
+ }
314
341
  @keyframes fb-rotate-hint {
315
342
  0%,
316
343
  20% {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toneflix/flipbook",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "An expressive flipbook for creating personalised and interactive reading and photo viewing experiences, for any web page, no framework needed.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://toneflix.github.io/flipbook/frameworks/vanilla",
@@ -46,7 +46,7 @@
46
46
  "dist"
47
47
  ],
48
48
  "dependencies": {
49
- "@toneflix/flipbook-core": "^0.2.3"
49
+ "@toneflix/flipbook-core": "^0.2.4"
50
50
  },
51
51
  "devDependencies": {
52
52
  "tsdown": "^0.23.5",