brickbox 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +76 -2
- package/dist/chunk-3CCNRF7U.js +1 -0
- package/dist/element.cjs +1 -0
- package/dist/element.d.cts +11 -0
- package/dist/element.d.ts +11 -0
- package/dist/element.js +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +1 -0
- package/dist/react.cjs +1 -0
- package/dist/react.d.cts +18 -0
- package/dist/react.d.ts +18 -0
- package/dist/react.js +1 -0
- package/dist/types-Cdnliv69.d.cts +59 -0
- package/dist/types-Cdnliv69.d.ts +59 -0
- package/package.json +103 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 PRASHANT PRASAD
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,77 @@
|
|
|
1
|
-
#
|
|
1
|
+
# brickbox
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Wrap any element and give it real 3D depth. The element stays real DOM (selectable, accessible, styled by you), and brickbox draws the side walls behind it. Rounded corners and gradient backgrounds carry through.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
npm i brickbox
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Status: early release (v0.1.0). Expect small API changes before 1.0.
|
|
12
|
+
|
|
13
|
+
## Use
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import { BrickBox } from 'brickbox/react';
|
|
17
|
+
|
|
18
|
+
<BrickBox depth={24} control="hover" tilt={{ x: 14, y: 22 }}>
|
|
19
|
+
<div className="rectangle">this is a rectangle</div>
|
|
20
|
+
</BrickBox>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```html
|
|
24
|
+
<brick-box depth="24" control="hover" tilt="14 22">
|
|
25
|
+
<div class="rectangle">this is a rectangle</div>
|
|
26
|
+
</brick-box>
|
|
27
|
+
<script type="module">
|
|
28
|
+
import { defineBrickBox } from 'brickbox/element';
|
|
29
|
+
defineBrickBox();
|
|
30
|
+
</script>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
```js
|
|
34
|
+
import { brickbox } from 'brickbox';
|
|
35
|
+
const box = brickbox(wrapperEl, { depth: 24 }); // wrapperEl contains exactly one element child
|
|
36
|
+
box.update({ depth: 40 });
|
|
37
|
+
box.destroy();
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Layout on the wrapper, looks on the child: flex, grid, margins and position belong on the wrapper (`className`/`style`, or the `<brick-box>` element). Background, radius and padding stay on the child. Put opacity, filter and overflow on the wrapper, never on the 3D layer.
|
|
41
|
+
|
|
42
|
+
## Options
|
|
43
|
+
|
|
44
|
+
| Option | Default | Notes |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| `depth` | `24` | number (px) or CSS length |
|
|
47
|
+
| `control` | `"hover"` | `"hover"`, `"drag"`, `"static"`. On touch, `"hover"` behaves as drag |
|
|
48
|
+
| `tilt` | `{ x: 14, y: 22 }` | degrees. +x shows the bottom wall, +y the right wall |
|
|
49
|
+
| `maxAngle` | `60` | clamp for hover and drag |
|
|
50
|
+
| `springBack` | `true` | |
|
|
51
|
+
| `springDuration` | `700` | ms |
|
|
52
|
+
| `pressDepth` | same as `depth` | smaller value makes it sink on press |
|
|
53
|
+
| `pressDuration` | `150` | ms |
|
|
54
|
+
| `sideColor` | `"match"` | follows the element's background, or any CSS colour |
|
|
55
|
+
| `shading` | on for `"match"` | lighting on the walls |
|
|
56
|
+
| `light` | `"top-left"` | word or degrees (0 top, clockwise) |
|
|
57
|
+
| `perspective` | `1000` | px |
|
|
58
|
+
| `edgeColor` | `"none"` | `"none"`, `"auto"` or a CSS colour |
|
|
59
|
+
| `edgeWidth` | `1` | px |
|
|
60
|
+
| `touchScroll` | `true` | touch only: vertical swipes scroll the page |
|
|
61
|
+
| `disabled` | `false` | |
|
|
62
|
+
| `advanced` | | `tolerance` (0.25), `sensitivity` (0.5), `bounce` (1), `cull` (true) |
|
|
63
|
+
|
|
64
|
+
## Limitations
|
|
65
|
+
|
|
66
|
+
- Rectangles with uniform or per-corner radii (pills and circles included). Clip-path shapes, blobs and elliptical radii are not supported yet.
|
|
67
|
+
- Walls follow the child's background colour, or a single linear gradient with `rgb()` stops. Images and other backgrounds fall back to a solid colour. Wall colours are read when the walls are built, so they do not follow a later colour change.
|
|
68
|
+
- The element's own `box-shadow` and `outline` are not extruded, and borders stay on the front face.
|
|
69
|
+
- Depth beyond about half of `perspective` can clip or distort (a warning is logged in development).
|
|
70
|
+
- Tested by the author on desktop and phone browsers. Safari, Firefox and older mobile browsers have not been verified yet.
|
|
71
|
+
|
|
72
|
+
## Develop
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
npm install
|
|
76
|
+
npm run typecheck && npm test && npm run build && npm run size
|
|
77
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var oe={persp:{display:"grid",width:"100%",height:"100%"},obj:{display:"grid",width:"100%",height:"100%",transformStyle:"preserve-3d",willChange:"transform"},sink:{display:"grid",width:"100%",height:"100%",position:"relative",transformStyle:"preserve-3d"},walls:{position:"absolute",transformStyle:"preserve-3d",pointerEvents:"none"}},W="data-bb";function ke(e){let i=[],o=0,s="";for(let n of e)n==="("&&o++,n===")"&&o--,n===","&&!o?(i.push(s.trim()),s=""):s+=n;return i.push(s.trim()),i}function ie(e){if((e.match(/gradient\(/g)||[]).length!==1)return null;let i=ke(e.slice(e.indexOf("(")+1,e.lastIndexOf(")"))),o=180;if(/^to /.test(i[0])||/deg$/.test(i[0])){let n=i.shift();if(/deg$/.test(n))o=parseFloat(n);else {let l=/top/.test(n),d=/bottom/.test(n),p=/left/.test(n),c=/right/.test(n);o=l&&c?45:d&&c?135:d&&p?225:l&&p?315:c?90:p?270:l?0:180;}}let s=[];for(let n of i){let l=n.match(/^(rgba?\([^)]*\))\s*([\d.]+)?%?$/);if(!l||/px|em/.test(n))return null;let d=l[1].match(/[\d.]+/g).map(Number);d.length<4&&d.push(1),s.push({raw:n,c:d,t:l[2]==null?null:+l[2]/100});}if(s.length<2)return null;s[0].t==null&&(s[0].t=0),s[s.length-1].t==null&&(s[s.length-1].t=1);for(let n=1;n<s.length;n++){if(s[n].t!=null)continue;let l=n;for(;s[l].t==null;)l++;let d=s[n-1].t,p=s[l].t;for(let c=n;c<l;c++)s[c].t=d+(p-d)*(c-n+1)/(l-n+1);}return {ang:o,st:s}}function G(e,i,o,s,n){let l=e.ang*Math.PI/180,d=Math.abs(s*Math.sin(l))+Math.abs(n*Math.cos(l)),p=((i-s/2)*Math.sin(l)-(o-n/2)*Math.cos(l))/d+.5,c=e.st;if(p<=c[0].t)return `rgba(${c[0].c})`;for(let u=1;u<c.length;u++)if(p<=c[u].t){let t=(p-c[u-1].t)/(c[u].t-c[u-1].t||1),h=c[u-1].c,v=c[u].c;return `rgba(${h.map((M,y)=>+(M+(v[y]-M)*t).toFixed(2))})`}return `rgba(${c[c.length-1].c})`}function le(e,i,o){let s=Math.min(1,i/(e[0]+e[1]),i/(e[3]+e[2]),o/(e[0]+e[3]),o/(e[1]+e[2]));return e.map(n=>n*s)}function ae(e,i,o,s){let n=[],l=[[1,e-o[1],o[1],-90,e,0],[2,e-o[2],i-o[2],0,e,i],[3,o[3],i-o[3],90,0,i],[0,o[0],o[0],180,0,0]];for(let[d,p,c,u,t,h]of l){let v=o[d],M=v>.5?Math.max(1,Math.ceil(Math.PI/2/(2*Math.acos(Math.max(0,1-s/v))))):0;if(!M)n.push([t,h]);else for(let y=0;y<=M;y++){let k=(u+90*y/M)*Math.PI/180;n.push([p+v*Math.cos(k),c+v*Math.sin(k)]);}}return n.reverse()}var Le={top:0,"top-right":45,right:90,"bottom-right":135,bottom:180,"bottom-left":225,left:270,"top-left":315},H=(e,i)=>Math.max(-i,Math.min(i,e)),Se=()=>typeof process<"u"&&!!process.env&&process.env.NODE_ENV!=="production",ce=false;function we(){if(!(ce||typeof CSS>"u"||!CSS.registerProperty)){ce=true;try{CSS.registerProperty({name:"--bb-p",syntax:"<number>",inherits:!0,initialValue:"1"});}catch{}}}function pe(e){let i=e.advanced||{},o=(e.sideColor??"match").trim();return {depth:e.depth??24,control:e.control??"hover",tx:e.tilt?.x??14,ty:e.tilt?.y??22,max:e.maxAngle??60,springBack:e.springBack??true,springDur:e.springDuration??700,pressDepth:e.pressDepth,pressDur:e.pressDuration??150,side:o,shading:e.shading??o==="match",light:typeof e.light=="number"?e.light:Le[e.light??"top-left"]??315,persp:e.perspective??1e3,edge:e.edgeColor??"none",edgeW:e.edgeWidth??1,touchScroll:e.touchScroll??true,disabled:e.disabled??false,tol:i.tolerance??.25,sens:i.sensitivity??.5,bounce:i.bounce??1,cull:i.cull??true}}function ue(e,i){if(typeof e=="number")return e;if(/^\s*-?[\d.]+(px)?\s*$/.test(e))return parseFloat(e);let o=document.createElement("div");o.style.cssText=`position:absolute;visibility:hidden;width:${e}`,i.appendChild(o);let s=o.getBoundingClientRect().width;return o.remove(),s}function Te(e){let i=u=>e.querySelector(`[${W}="${u}"]`),o=i("persp");if(o){let u=i("sink");return {persp:o,obj:i("obj"),sink:u,walls:i("walls"),child:u.firstElementChild,built:false}}let s=e.firstElementChild;if(!s)throw new Error("brickbox: the root needs one element child");let n=u=>{let t=document.createElement("div");return t.setAttribute(W,u),Object.assign(t.style,oe[u]),t},l=n("persp"),d=n("obj"),p=n("sink"),c=n("walls");return c.setAttribute("aria-hidden","true"),e.append(l),l.append(d),d.append(p),p.append(s,c),{persp:l,obj:d,sink:p,walls:c,child:s,built:true}}function He(e,i={}){we();let o=Te(e),{persp:s,obj:n,sink:l,walls:d,child:p}=o,c=typeof matchMedia<"u"?matchMedia("(prefers-reduced-motion: reduce)"):null,u=i,t=pe(u),h={w:0,h:0,ox:0,oy:0,pp:1},v=t.tx,M=t.ty,y=false,k=null,D=false,X=false;if(!e.style.display){let r=l.style.display;l.style.display="block";let a=/^inline/.test(getComputedStyle(p).display);l.style.display=r,e.style.display=a?"inline-block":"block",X=true;}let P=(r,a,g)=>{v=r,M=a,n.style.transition=g||"none",n.style.transform=`rotateX(${r}deg) rotateY(${-a}deg)`;},de=()=>c?.matches?"none":`transform ${t.springDur}ms cubic-bezier(.2,${1+.5*t.bounce},.4,1)`,N=()=>P(t.tx,t.ty,de()),j=r=>l.style.setProperty("--bb-p",String(r&&h.pp<1?h.pp:1));function I(){t=pe(u);let r=p.offsetWidth,a=p.offsetHeight,g=p.offsetLeft,f=p.offsetTop,x=Math.max(0,ue(t.depth,e));Se()&&x>t.persp*.5&&console.warn(`[brickbox] depth ${x}px is more than half of perspective (${t.persp}px); the box may clip or distort.`);let S=t.pressDepth==null?1:Math.min(1,Math.max(0,ue(t.pressDepth,e)/(x||1)));h={w:r,h:a,ox:g,oy:f,pp:S};let w=!!c?.matches;if(d.innerHTML="",d.hidden=t.disabled,Object.assign(d.style,{left:g+"px",top:f+"px",width:r+"px",height:a+"px"}),l.style.setProperty("--bb-d",x+"px"),l.style.transform="translateZ(calc(var(--bb-d) * (var(--bb-p) - 1)))",l.style.transition=`--bb-p ${w?0:t.pressDur}ms ease`,s.style.perspective=t.persp+"px",n.style.transformOrigin=`${g+r/2}px ${f+a/2}px ${-x/2}px`,e.style.touchAction=t.control==="drag"||t.control==="hover"&&!t.touchScroll?"none":t.control==="hover"?"pan-y":"auto",e.style.cursor=t.control==="drag"?"grab":"",t.disabled||!r||!a){n.style.transform="none";return}let $=getComputedStyle(p),me=le(["top-left","top-right","bottom-right","bottom-left"].map(m=>{let b=$.getPropertyValue(`border-${m}-radius`).split(" ")[0];return b.endsWith("%")?parseFloat(b)/100*r:parseFloat(b)||0}),r,a),K=$.backgroundImage,A=K.startsWith("linear-gradient")?ie(K):null,C=$.backgroundColor;(C==="rgba(0, 0, 0, 0)"||C==="transparent")&&(C="rgb(120,120,130)");let Q=t.side==="match",U=Q?C:t.side,R=t.light*Math.PI/180,be=Math.sin(R),he=-Math.cos(R),E=ae(r,a,me,t.tol),L=E.length,ge=m=>{let b=E[(m+1)%L];return {a:Math.atan2(b[1]-E[m][1],b[0]-E[m][0]),len:Math.hypot(b[0]-E[m][0],b[1]-E[m][1])}},T=E.map((m,b)=>ge(b)),Y=t.edge==="none"||t.edge===""?null:t.edge==="auto"?"rgba(0,0,0,.5)":t.edge,ee=document.createDocumentFragment();for(let m=0;m<L;m++){if(T[m].len<.01)continue;let b=(m+L-1)%L;for(;T[b].len<.01&&b!==m;)b=(b+L-1)%L;let B=Math.abs(T[m].a-T[b].a);B=Math.min(B,2*Math.PI-B);let[te,ne]=E[m],[fe,ye]=E[(m+1)%L],F=T[m].a,xe=(-Math.sin(F)*be+Math.cos(F)*he+1)/2,re=.08+.3*(1-xe),ve=re+.28,Me=Q&&A?`linear-gradient(90deg,${G(A,te,ne,r,a)},${G(A,fe,ye,r,a)})`:`linear-gradient(${U},${U})`,Ee=t.shading?`linear-gradient(rgba(0,0,0,${re.toFixed(2)}),rgba(0,0,0,${ve.toFixed(2)})),`:"",$e=Y?`border-bottom:${t.edgeW}px solid ${Y};${B>.9?`border-left:${t.edgeW}px solid ${Y};`:""}`:"",se=document.createElement("i");se.style.cssText=`position:absolute;left:0;top:0;box-sizing:border-box;height:var(--bb-d);transform-origin:0 0;${t.cull?"backface-visibility:hidden;":""}width:${T[m].len+.5}px;${$e}background:${Ee}${Me};transform:translate(${te}px,${ne}px) rotate(${F*180/Math.PI}deg) rotateX(-90deg) scaleY(var(--bb-p))`,ee.appendChild(se);}d.appendChild(ee),!k&&!y&&P(t.tx,t.ty);}let z=r=>{let a=e.getBoundingClientRect(),g=a.left+h.ox,f=a.top+h.oy;return r.clientX>=g&&r.clientX<=g+h.w&&r.clientY>=f&&r.clientY<=f+h.h},V=()=>{y=false,t.springBack&&N();},q=r=>{if(t.disabled||k||t.control!=="hover"||r.pointerType==="touch"||c?.matches)return;if(!z(r)){y&&V();return}let a=e.getBoundingClientRect(),g=(S,w,$)=>Math.max(-1,Math.min(1,(S-w-$/2)/($/2))),f=g(r.clientX,a.left+h.ox,h.w),x=g(r.clientY,a.top+h.oy,h.h);y=true,P(H(t.tx*.3-x*t.max*.7,t.max),H(t.ty*.3-f*t.max*.7,t.max),"transform .15s ease-out");},_=()=>{y&&V();},Z=r=>{if(t.disabled||!z(r))return;let a={x:r.clientX,y:r.clientY,tx:v,ty:M,moved:false,touch:r.pointerType==="touch",dragging:t.control==="drag"||t.control==="hover"&&r.pointerType==="touch"};k=a,j(true);let g=x=>{let S=x.clientX-a.x,w=x.clientY-a.y;if(!a.moved){if(Math.hypot(S,w)<5)return;a.moved=true,j(false);}if(!a.dragging)return;let $=a.touch&&t.control==="hover"&&t.touchScroll?0:w;P(H(a.tx-$*t.sens,t.max),H(a.ty-S*t.sens,t.max));},f=()=>{removeEventListener("pointermove",g),removeEventListener("pointerup",f),removeEventListener("pointercancel",f),k=null,j(false),D=a.moved&&a.dragging,D&&t.springBack&&N();};addEventListener("pointermove",g),addEventListener("pointerup",f),addEventListener("pointercancel",f);},J=r=>{D&&(r.stopPropagation(),r.preventDefault(),D=false);};e.addEventListener("pointermove",q),e.addEventListener("pointerleave",_),e.addEventListener("pointerdown",Z),p.addEventListener("click",J,true);let O=new ResizeObserver(I);return O.observe(p),O.observe(l),I(),{update(r){u={...u,...r,advanced:{...u.advanced,...r.advanced}},I();},destroy(){O.disconnect(),e.removeEventListener("pointermove",q),e.removeEventListener("pointerleave",_),e.removeEventListener("pointerdown",Z),p.removeEventListener("click",J,true),e.style.touchAction="",e.style.cursor="",X&&(e.style.display=""),o.built&&(e.insertBefore(p,s),s.remove());}}}export{oe as a,W as b,He as c};
|
package/dist/element.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
'use strict';function Te(e){let r=[],s=0,o="";for(let n of e)n==="("&&s++,n===")"&&s--,n===","&&!s?(r.push(o.trim()),o=""):o+=n;return r.push(o.trim()),r}function ie(e){if((e.match(/gradient\(/g)||[]).length!==1)return null;let r=Te(e.slice(e.indexOf("(")+1,e.lastIndexOf(")"))),s=180;if(/^to /.test(r[0])||/deg$/.test(r[0])){let n=r.shift();if(/deg$/.test(n))s=parseFloat(n);else {let c=/top/.test(n),u=/bottom/.test(n),d=/left/.test(n),i=/right/.test(n);s=c&&i?45:u&&i?135:u&&d?225:c&&d?315:i?90:d?270:c?0:180;}}let o=[];for(let n of r){let c=n.match(/^(rgba?\([^)]*\))\s*([\d.]+)?%?$/);if(!c||/px|em/.test(n))return null;let u=c[1].match(/[\d.]+/g).map(Number);u.length<4&&u.push(1),o.push({raw:n,c:u,t:c[2]==null?null:+c[2]/100});}if(o.length<2)return null;o[0].t==null&&(o[0].t=0),o[o.length-1].t==null&&(o[o.length-1].t=1);for(let n=1;n<o.length;n++){if(o[n].t!=null)continue;let c=n;for(;o[c].t==null;)c++;let u=o[n-1].t,d=o[c].t;for(let i=n;i<c;i++)o[i].t=u+(d-u)*(i-n+1)/(c-n+1);}return {ang:s,st:o}}function F(e,r,s,o,n){let c=e.ang*Math.PI/180,u=Math.abs(o*Math.sin(c))+Math.abs(n*Math.cos(c)),d=((r-o/2)*Math.sin(c)-(s-n/2)*Math.cos(c))/u+.5,i=e.st;if(d<=i[0].t)return `rgba(${i[0].c})`;for(let l=1;l<i.length;l++)if(d<=i[l].t){let t=(d-i[l-1].t)/(i[l].t-i[l-1].t||1),b=i[l-1].c,v=i[l].c;return `rgba(${b.map((M,x)=>+(M+(v[x]-M)*t).toFixed(2))})`}return `rgba(${i[i.length-1].c})`}function le(e,r,s){let o=Math.min(1,r/(e[0]+e[1]),r/(e[3]+e[2]),s/(e[0]+e[3]),s/(e[1]+e[2]));return e.map(n=>n*o)}function ae(e,r,s,o){let n=[],c=[[1,e-s[1],s[1],-90,e,0],[2,e-s[2],r-s[2],0,e,r],[3,s[3],r-s[3],90,0,r],[0,s[0],s[0],180,0,0]];for(let[u,d,i,l,t,b]of c){let v=s[u],M=v>.5?Math.max(1,Math.ceil(Math.PI/2/(2*Math.acos(Math.max(0,1-o/v))))):0;if(!M)n.push([t,b]);else for(let x=0;x<=M;x++){let $=(l+90*x/M)*Math.PI/180;n.push([d+v*Math.cos($),i+v*Math.sin($)]);}}return n.reverse()}var ce={persp:{display:"grid",width:"100%",height:"100%"},obj:{display:"grid",width:"100%",height:"100%",transformStyle:"preserve-3d",willChange:"transform"},sink:{display:"grid",width:"100%",height:"100%",position:"relative",transformStyle:"preserve-3d"},walls:{position:"absolute",transformStyle:"preserve-3d",pointerEvents:"none"}},G="data-bb";var we={top:0,"top-right":45,right:90,"bottom-right":135,bottom:180,"bottom-left":225,left:270,"top-left":315},H=(e,r)=>Math.max(-r,Math.min(r,e)),Be=()=>typeof process<"u"&&!!process.env&&process.env.NODE_ENV!=="production",de=false;function Ce(){if(!(de||typeof CSS>"u"||!CSS.registerProperty)){de=true;try{CSS.registerProperty({name:"--bb-p",syntax:"<number>",inherits:!0,initialValue:"1"});}catch{}}}function pe(e){let r=e.advanced||{},s=(e.sideColor??"match").trim();return {depth:e.depth??24,control:e.control??"hover",tx:e.tilt?.x??14,ty:e.tilt?.y??22,max:e.maxAngle??60,springBack:e.springBack??true,springDur:e.springDuration??700,pressDepth:e.pressDepth,pressDur:e.pressDuration??150,side:s,shading:e.shading??s==="match",light:typeof e.light=="number"?e.light:we[e.light??"top-left"]??315,persp:e.perspective??1e3,edge:e.edgeColor??"none",edgeW:e.edgeWidth??1,touchScroll:e.touchScroll??true,disabled:e.disabled??false,tol:r.tolerance??.25,sens:r.sensitivity??.5,bounce:r.bounce??1,cull:r.cull??true}}function ue(e,r){if(typeof e=="number")return e;if(/^\s*-?[\d.]+(px)?\s*$/.test(e))return parseFloat(e);let s=document.createElement("div");s.style.cssText=`position:absolute;visibility:hidden;width:${e}`,r.appendChild(s);let o=s.getBoundingClientRect().width;return s.remove(),o}function De(e){let r=l=>e.querySelector(`[${G}="${l}"]`),s=r("persp");if(s){let l=r("sink");return {persp:s,obj:r("obj"),sink:l,walls:r("walls"),child:l.firstElementChild,built:false}}let o=e.firstElementChild;if(!o)throw new Error("brickbox: the root needs one element child");let n=l=>{let t=document.createElement("div");return t.setAttribute(G,l),Object.assign(t.style,ce[l]),t},c=n("persp"),u=n("obj"),d=n("sink"),i=n("walls");return i.setAttribute("aria-hidden","true"),e.append(c),c.append(u),u.append(d),d.append(o,i),{persp:c,obj:u,sink:d,walls:i,child:o,built:true}}function me(e,r={}){Ce();let s=De(e),{persp:o,obj:n,sink:c,walls:u,child:d}=s,i=typeof matchMedia<"u"?matchMedia("(prefers-reduced-motion: reduce)"):null,l=r,t=pe(l),b={w:0,h:0,ox:0,oy:0,pp:1},v=t.tx,M=t.ty,x=false,$=null,B=false,X=false;if(!e.style.display){let a=c.style.display;c.style.display="block";let p=/^inline/.test(getComputedStyle(d).display);c.style.display=a,e.style.display=p?"inline-block":"block",X=true;}let C=(a,p,g)=>{v=a,M=p,n.style.transition=g||"none",n.style.transform=`rotateX(${a}deg) rotateY(${-p}deg)`;},be=()=>i?.matches?"none":`transform ${t.springDur}ms cubic-bezier(.2,${1+.5*t.bounce},.4,1)`,z=()=>C(t.tx,t.ty,be()),O=a=>c.style.setProperty("--bb-p",String(a&&b.pp<1?b.pp:1));function I(){t=pe(l);let a=d.offsetWidth,p=d.offsetHeight,g=d.offsetLeft,f=d.offsetTop,y=Math.max(0,ue(t.depth,e));Be()&&y>t.persp*.5&&console.warn(`[brickbox] depth ${y}px is more than half of perspective (${t.persp}px); the box may clip or distort.`);let S=t.pressDepth==null?1:Math.min(1,Math.max(0,ue(t.pressDepth,e)/(y||1)));b={w:a,h:p,ox:g,oy:f,pp:S};let T=!!i?.matches;if(u.innerHTML="",u.hidden=t.disabled,Object.assign(u.style,{left:g+"px",top:f+"px",width:a+"px",height:p+"px"}),c.style.setProperty("--bb-d",y+"px"),c.style.transform="translateZ(calc(var(--bb-d) * (var(--bb-p) - 1)))",c.style.transition=`--bb-p ${T?0:t.pressDur}ms ease`,o.style.perspective=t.persp+"px",n.style.transformOrigin=`${g+a/2}px ${f+p/2}px ${-y/2}px`,e.style.touchAction=t.control==="drag"||t.control==="hover"&&!t.touchScroll?"none":t.control==="hover"?"pan-y":"auto",e.style.cursor=t.control==="drag"?"grab":"",t.disabled||!a||!p){n.style.transform="none";return}let E=getComputedStyle(d),ge=le(["top-left","top-right","bottom-right","bottom-left"].map(m=>{let h=E.getPropertyValue(`border-${m}-radius`).split(" ")[0];return h.endsWith("%")?parseFloat(h)/100*a:parseFloat(h)||0}),a,p),Q=E.backgroundImage,N=Q.startsWith("linear-gradient")?ie(Q):null,D=E.backgroundColor;(D==="rgba(0, 0, 0, 0)"||D==="transparent")&&(D="rgb(120,120,130)");let U=t.side==="match",R=U?D:t.side,ee=t.light*Math.PI/180,fe=Math.sin(ee),xe=-Math.cos(ee),k=ae(a,p,ge,t.tol),L=k.length,ye=m=>{let h=k[(m+1)%L];return {a:Math.atan2(h[1]-k[m][1],h[0]-k[m][0]),len:Math.hypot(h[0]-k[m][0],h[1]-k[m][1])}},w=k.map((m,h)=>ye(h)),W=t.edge==="none"||t.edge===""?null:t.edge==="auto"?"rgba(0,0,0,.5)":t.edge,te=document.createDocumentFragment();for(let m=0;m<L;m++){if(w[m].len<.01)continue;let h=(m+L-1)%L;for(;w[h].len<.01&&h!==m;)h=(h+L-1)%L;let P=Math.abs(w[m].a-w[h].a);P=Math.min(P,2*Math.PI-P);let[ne,re]=k[m],[ve,Me]=k[(m+1)%L],Y=w[m].a,ke=(-Math.sin(Y)*fe+Math.cos(Y)*xe+1)/2,se=.08+.3*(1-ke),Ee=se+.28,$e=U&&N?`linear-gradient(90deg,${F(N,ne,re,a,p)},${F(N,ve,Me,a,p)})`:`linear-gradient(${R},${R})`,Le=t.shading?`linear-gradient(rgba(0,0,0,${se.toFixed(2)}),rgba(0,0,0,${Ee.toFixed(2)})),`:"",Se=W?`border-bottom:${t.edgeW}px solid ${W};${P>.9?`border-left:${t.edgeW}px solid ${W};`:""}`:"",oe=document.createElement("i");oe.style.cssText=`position:absolute;left:0;top:0;box-sizing:border-box;height:var(--bb-d);transform-origin:0 0;${t.cull?"backface-visibility:hidden;":""}width:${w[m].len+.5}px;${Se}background:${Le}${$e};transform:translate(${ne}px,${re}px) rotate(${Y*180/Math.PI}deg) rotateX(-90deg) scaleY(var(--bb-p))`,te.appendChild(oe);}u.appendChild(te),!$&&!x&&C(t.tx,t.ty);}let V=a=>{let p=e.getBoundingClientRect(),g=p.left+b.ox,f=p.top+b.oy;return a.clientX>=g&&a.clientX<=g+b.w&&a.clientY>=f&&a.clientY<=f+b.h},q=()=>{x=false,t.springBack&&z();},_=a=>{if(t.disabled||$||t.control!=="hover"||a.pointerType==="touch"||i?.matches)return;if(!V(a)){x&&q();return}let p=e.getBoundingClientRect(),g=(S,T,E)=>Math.max(-1,Math.min(1,(S-T-E/2)/(E/2))),f=g(a.clientX,p.left+b.ox,b.w),y=g(a.clientY,p.top+b.oy,b.h);x=true,C(H(t.tx*.3-y*t.max*.7,t.max),H(t.ty*.3-f*t.max*.7,t.max),"transform .15s ease-out");},Z=()=>{x&&q();},J=a=>{if(t.disabled||!V(a))return;let p={x:a.clientX,y:a.clientY,tx:v,ty:M,moved:false,touch:a.pointerType==="touch",dragging:t.control==="drag"||t.control==="hover"&&a.pointerType==="touch"};$=p,O(true);let g=y=>{let S=y.clientX-p.x,T=y.clientY-p.y;if(!p.moved){if(Math.hypot(S,T)<5)return;p.moved=true,O(false);}if(!p.dragging)return;let E=p.touch&&t.control==="hover"&&t.touchScroll?0:T;C(H(p.tx-E*t.sens,t.max),H(p.ty-S*t.sens,t.max));},f=()=>{removeEventListener("pointermove",g),removeEventListener("pointerup",f),removeEventListener("pointercancel",f),$=null,O(false),B=p.moved&&p.dragging,B&&t.springBack&&z();};addEventListener("pointermove",g),addEventListener("pointerup",f),addEventListener("pointercancel",f);},K=a=>{B&&(a.stopPropagation(),a.preventDefault(),B=false);};e.addEventListener("pointermove",_),e.addEventListener("pointerleave",Z),e.addEventListener("pointerdown",J),d.addEventListener("click",K,true);let j=new ResizeObserver(I);return j.observe(d),j.observe(c),I(),{update(a){l={...l,...a,advanced:{...l.advanced,...a.advanced}},I();},destroy(){j.disconnect(),e.removeEventListener("pointermove",_),e.removeEventListener("pointerleave",Z),e.removeEventListener("pointerdown",J),d.removeEventListener("click",K,true),e.style.touchAction="",e.style.cursor="",X&&(e.style.display=""),s.built&&(e.insertBefore(d,o),o.remove());}}}var Pe=["depth","control","tilt","max-angle","spring-back","spring-duration","press-depth","press-duration","side-color","shading","light","perspective","edge-color","edge-width","touch-scroll","disabled","tolerance"];function he(e){let r=i=>e.getAttribute(i),s=i=>{let l=r(i);return l==null||l===""||isNaN(+l)?void 0:+l},o=i=>{let l=r(i);return l==null?void 0:l!=="false"},n=i=>{let l=r(i);return l==null?void 0:l!==""&&!isNaN(+l)?+l:l},c=r("tilt"),u;if(c){let[i,l]=c.split(/[ ,]+/).map(Number);u={x:i,y:l};}let d=r("light");return {depth:n("depth"),control:r("control")||void 0,tilt:u,maxAngle:s("max-angle"),springBack:o("spring-back"),springDuration:s("spring-duration"),pressDepth:n("press-depth"),pressDuration:s("press-duration"),sideColor:r("side-color")||void 0,shading:o("shading"),light:d==null?void 0:isNaN(+d)?d:+d,perspective:s("perspective"),edgeColor:r("edge-color")||void 0,edgeWidth:s("edge-width"),touchScroll:o("touch-scroll"),disabled:o("disabled"),advanced:{tolerance:s("tolerance")}}}var A=class extends HTMLElement{connectedCallback(){this.inst||(this.inst=me(this,he(this)));}attributeChangedCallback(){this.inst?.update(he(this));}disconnectedCallback(){this.inst?.destroy(),this.inst=void 0;}};A.observedAttributes=Pe;function We(e="brick-box"){typeof customElements<"u"&&!customElements.get(e)&&customElements.define(e,A);}exports.BrickBoxElement=A;exports.defineBrickBox=We;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** `<brick-box>`: wrap exactly one element child. Define it after the page has parsed (module scripts do). */
|
|
2
|
+
declare class BrickBoxElement extends HTMLElement {
|
|
3
|
+
static observedAttributes: string[];
|
|
4
|
+
private inst?;
|
|
5
|
+
connectedCallback(): void;
|
|
6
|
+
attributeChangedCallback(): void;
|
|
7
|
+
disconnectedCallback(): void;
|
|
8
|
+
}
|
|
9
|
+
declare function defineBrickBox(tag?: string): void;
|
|
10
|
+
|
|
11
|
+
export { BrickBoxElement, defineBrickBox };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** `<brick-box>`: wrap exactly one element child. Define it after the page has parsed (module scripts do). */
|
|
2
|
+
declare class BrickBoxElement extends HTMLElement {
|
|
3
|
+
static observedAttributes: string[];
|
|
4
|
+
private inst?;
|
|
5
|
+
connectedCallback(): void;
|
|
6
|
+
attributeChangedCallback(): void;
|
|
7
|
+
disconnectedCallback(): void;
|
|
8
|
+
}
|
|
9
|
+
declare function defineBrickBox(tag?: string): void;
|
|
10
|
+
|
|
11
|
+
export { BrickBoxElement, defineBrickBox };
|
package/dist/element.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import {c}from'./chunk-3CCNRF7U.js';var g=["depth","control","tilt","max-angle","spring-back","spring-duration","press-depth","press-duration","side-color","shading","light","perspective","edge-color","edge-width","touch-scroll","disabled","tolerance"];function u(s){let n=e=>s.getAttribute(e),i=e=>{let t=n(e);return t==null||t===""||isNaN(+t)?void 0:+t},o=e=>{let t=n(e);return t==null?void 0:t!=="false"},l=e=>{let t=n(e);return t==null?void 0:t!==""&&!isNaN(+t)?+t:t},c=n("tilt"),a;if(c){let[e,t]=c.split(/[ ,]+/).map(Number);a={x:e,y:t};}let r=n("light");return {depth:l("depth"),control:n("control")||void 0,tilt:a,maxAngle:i("max-angle"),springBack:o("spring-back"),springDuration:i("spring-duration"),pressDepth:l("press-depth"),pressDuration:i("press-duration"),sideColor:n("side-color")||void 0,shading:o("shading"),light:r==null?void 0:isNaN(+r)?r:+r,perspective:i("perspective"),edgeColor:n("edge-color")||void 0,edgeWidth:i("edge-width"),touchScroll:o("touch-scroll"),disabled:o("disabled"),advanced:{tolerance:i("tolerance")}}}var d=class extends HTMLElement{connectedCallback(){this.inst||(this.inst=c(this,u(this)));}attributeChangedCallback(){this.inst?.update(u(this));}disconnectedCallback(){this.inst?.destroy(),this.inst=void 0;}};d.observedAttributes=g;function f(s="brick-box"){typeof customElements<"u"&&!customElements.get(s)&&customElements.define(s,d);}export{d as BrickBoxElement,f as defineBrickBox};
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
'use strict';function ke(e){let i=[],o=0,s="";for(let n of e)n==="("&&o++,n===")"&&o--,n===","&&!o?(i.push(s.trim()),s=""):s+=n;return i.push(s.trim()),i}function oe(e){if((e.match(/gradient\(/g)||[]).length!==1)return null;let i=ke(e.slice(e.indexOf("(")+1,e.lastIndexOf(")"))),o=180;if(/^to /.test(i[0])||/deg$/.test(i[0])){let n=i.shift();if(/deg$/.test(n))o=parseFloat(n);else {let l=/top/.test(n),d=/bottom/.test(n),p=/left/.test(n),c=/right/.test(n);o=l&&c?45:d&&c?135:d&&p?225:l&&p?315:c?90:p?270:l?0:180;}}let s=[];for(let n of i){let l=n.match(/^(rgba?\([^)]*\))\s*([\d.]+)?%?$/);if(!l||/px|em/.test(n))return null;let d=l[1].match(/[\d.]+/g).map(Number);d.length<4&&d.push(1),s.push({raw:n,c:d,t:l[2]==null?null:+l[2]/100});}if(s.length<2)return null;s[0].t==null&&(s[0].t=0),s[s.length-1].t==null&&(s[s.length-1].t=1);for(let n=1;n<s.length;n++){if(s[n].t!=null)continue;let l=n;for(;s[l].t==null;)l++;let d=s[n-1].t,p=s[l].t;for(let c=n;c<l;c++)s[c].t=d+(p-d)*(c-n+1)/(l-n+1);}return {ang:o,st:s}}function F(e,i,o,s,n){let l=e.ang*Math.PI/180,d=Math.abs(s*Math.sin(l))+Math.abs(n*Math.cos(l)),p=((i-s/2)*Math.sin(l)-(o-n/2)*Math.cos(l))/d+.5,c=e.st;if(p<=c[0].t)return `rgba(${c[0].c})`;for(let u=1;u<c.length;u++)if(p<=c[u].t){let t=(p-c[u-1].t)/(c[u].t-c[u-1].t||1),h=c[u-1].c,v=c[u].c;return `rgba(${h.map((M,y)=>+(M+(v[y]-M)*t).toFixed(2))})`}return `rgba(${c[c.length-1].c})`}function ie(e,i,o){let s=Math.min(1,i/(e[0]+e[1]),i/(e[3]+e[2]),o/(e[0]+e[3]),o/(e[1]+e[2]));return e.map(n=>n*s)}function le(e,i,o,s){let n=[],l=[[1,e-o[1],o[1],-90,e,0],[2,e-o[2],i-o[2],0,e,i],[3,o[3],i-o[3],90,0,i],[0,o[0],o[0],180,0,0]];for(let[d,p,c,u,t,h]of l){let v=o[d],M=v>.5?Math.max(1,Math.ceil(Math.PI/2/(2*Math.acos(Math.max(0,1-s/v))))):0;if(!M)n.push([t,h]);else for(let y=0;y<=M;y++){let k=(u+90*y/M)*Math.PI/180;n.push([p+v*Math.cos(k),c+v*Math.sin(k)]);}}return n.reverse()}var ae={persp:{display:"grid",width:"100%",height:"100%"},obj:{display:"grid",width:"100%",height:"100%",transformStyle:"preserve-3d",willChange:"transform"},sink:{display:"grid",width:"100%",height:"100%",position:"relative",transformStyle:"preserve-3d"},walls:{position:"absolute",transformStyle:"preserve-3d",pointerEvents:"none"}},G="data-bb";var Le={top:0,"top-right":45,right:90,"bottom-right":135,bottom:180,"bottom-left":225,left:270,"top-left":315},H=(e,i)=>Math.max(-i,Math.min(i,e)),Se=()=>typeof process<"u"&&!!process.env&&process.env.NODE_ENV!=="production",ce=false;function Te(){if(!(ce||typeof CSS>"u"||!CSS.registerProperty)){ce=true;try{CSS.registerProperty({name:"--bb-p",syntax:"<number>",inherits:!0,initialValue:"1"});}catch{}}}function pe(e){let i=e.advanced||{},o=(e.sideColor??"match").trim();return {depth:e.depth??24,control:e.control??"hover",tx:e.tilt?.x??14,ty:e.tilt?.y??22,max:e.maxAngle??60,springBack:e.springBack??true,springDur:e.springDuration??700,pressDepth:e.pressDepth,pressDur:e.pressDuration??150,side:o,shading:e.shading??o==="match",light:typeof e.light=="number"?e.light:Le[e.light??"top-left"]??315,persp:e.perspective??1e3,edge:e.edgeColor??"none",edgeW:e.edgeWidth??1,touchScroll:e.touchScroll??true,disabled:e.disabled??false,tol:i.tolerance??.25,sens:i.sensitivity??.5,bounce:i.bounce??1,cull:i.cull??true}}function ue(e,i){if(typeof e=="number")return e;if(/^\s*-?[\d.]+(px)?\s*$/.test(e))return parseFloat(e);let o=document.createElement("div");o.style.cssText=`position:absolute;visibility:hidden;width:${e}`,i.appendChild(o);let s=o.getBoundingClientRect().width;return o.remove(),s}function we(e){let i=u=>e.querySelector(`[${G}="${u}"]`),o=i("persp");if(o){let u=i("sink");return {persp:o,obj:i("obj"),sink:u,walls:i("walls"),child:u.firstElementChild,built:false}}let s=e.firstElementChild;if(!s)throw new Error("brickbox: the root needs one element child");let n=u=>{let t=document.createElement("div");return t.setAttribute(G,u),Object.assign(t.style,ae[u]),t},l=n("persp"),d=n("obj"),p=n("sink"),c=n("walls");return c.setAttribute("aria-hidden","true"),e.append(l),l.append(d),d.append(p),p.append(s,c),{persp:l,obj:d,sink:p,walls:c,child:s,built:true}}function Be(e,i={}){Te();let o=we(e),{persp:s,obj:n,sink:l,walls:d,child:p}=o,c=typeof matchMedia<"u"?matchMedia("(prefers-reduced-motion: reduce)"):null,u=i,t=pe(u),h={w:0,h:0,ox:0,oy:0,pp:1},v=t.tx,M=t.ty,y=false,k=null,B=false,X=false;if(!e.style.display){let r=l.style.display;l.style.display="block";let a=/^inline/.test(getComputedStyle(p).display);l.style.display=r,e.style.display=a?"inline-block":"block",X=true;}let D=(r,a,g)=>{v=r,M=a,n.style.transition=g||"none",n.style.transform=`rotateX(${r}deg) rotateY(${-a}deg)`;},de=()=>c?.matches?"none":`transform ${t.springDur}ms cubic-bezier(.2,${1+.5*t.bounce},.4,1)`,N=()=>D(t.tx,t.ty,de()),j=r=>l.style.setProperty("--bb-p",String(r&&h.pp<1?h.pp:1));function I(){t=pe(u);let r=p.offsetWidth,a=p.offsetHeight,g=p.offsetLeft,f=p.offsetTop,x=Math.max(0,ue(t.depth,e));Se()&&x>t.persp*.5&&console.warn(`[brickbox] depth ${x}px is more than half of perspective (${t.persp}px); the box may clip or distort.`);let S=t.pressDepth==null?1:Math.min(1,Math.max(0,ue(t.pressDepth,e)/(x||1)));h={w:r,h:a,ox:g,oy:f,pp:S};let T=!!c?.matches;if(d.innerHTML="",d.hidden=t.disabled,Object.assign(d.style,{left:g+"px",top:f+"px",width:r+"px",height:a+"px"}),l.style.setProperty("--bb-d",x+"px"),l.style.transform="translateZ(calc(var(--bb-d) * (var(--bb-p) - 1)))",l.style.transition=`--bb-p ${T?0:t.pressDur}ms ease`,s.style.perspective=t.persp+"px",n.style.transformOrigin=`${g+r/2}px ${f+a/2}px ${-x/2}px`,e.style.touchAction=t.control==="drag"||t.control==="hover"&&!t.touchScroll?"none":t.control==="hover"?"pan-y":"auto",e.style.cursor=t.control==="drag"?"grab":"",t.disabled||!r||!a){n.style.transform="none";return}let $=getComputedStyle(p),me=ie(["top-left","top-right","bottom-right","bottom-left"].map(m=>{let b=$.getPropertyValue(`border-${m}-radius`).split(" ")[0];return b.endsWith("%")?parseFloat(b)/100*r:parseFloat(b)||0}),r,a),K=$.backgroundImage,A=K.startsWith("linear-gradient")?oe(K):null,P=$.backgroundColor;(P==="rgba(0, 0, 0, 0)"||P==="transparent")&&(P="rgb(120,120,130)");let Q=t.side==="match",U=Q?P:t.side,R=t.light*Math.PI/180,be=Math.sin(R),he=-Math.cos(R),E=le(r,a,me,t.tol),L=E.length,ge=m=>{let b=E[(m+1)%L];return {a:Math.atan2(b[1]-E[m][1],b[0]-E[m][0]),len:Math.hypot(b[0]-E[m][0],b[1]-E[m][1])}},w=E.map((m,b)=>ge(b)),Y=t.edge==="none"||t.edge===""?null:t.edge==="auto"?"rgba(0,0,0,.5)":t.edge,ee=document.createDocumentFragment();for(let m=0;m<L;m++){if(w[m].len<.01)continue;let b=(m+L-1)%L;for(;w[b].len<.01&&b!==m;)b=(b+L-1)%L;let C=Math.abs(w[m].a-w[b].a);C=Math.min(C,2*Math.PI-C);let[te,ne]=E[m],[fe,ye]=E[(m+1)%L],W=w[m].a,xe=(-Math.sin(W)*be+Math.cos(W)*he+1)/2,re=.08+.3*(1-xe),ve=re+.28,Me=Q&&A?`linear-gradient(90deg,${F(A,te,ne,r,a)},${F(A,fe,ye,r,a)})`:`linear-gradient(${U},${U})`,Ee=t.shading?`linear-gradient(rgba(0,0,0,${re.toFixed(2)}),rgba(0,0,0,${ve.toFixed(2)})),`:"",$e=Y?`border-bottom:${t.edgeW}px solid ${Y};${C>.9?`border-left:${t.edgeW}px solid ${Y};`:""}`:"",se=document.createElement("i");se.style.cssText=`position:absolute;left:0;top:0;box-sizing:border-box;height:var(--bb-d);transform-origin:0 0;${t.cull?"backface-visibility:hidden;":""}width:${w[m].len+.5}px;${$e}background:${Ee}${Me};transform:translate(${te}px,${ne}px) rotate(${W*180/Math.PI}deg) rotateX(-90deg) scaleY(var(--bb-p))`,ee.appendChild(se);}d.appendChild(ee),!k&&!y&&D(t.tx,t.ty);}let z=r=>{let a=e.getBoundingClientRect(),g=a.left+h.ox,f=a.top+h.oy;return r.clientX>=g&&r.clientX<=g+h.w&&r.clientY>=f&&r.clientY<=f+h.h},V=()=>{y=false,t.springBack&&N();},q=r=>{if(t.disabled||k||t.control!=="hover"||r.pointerType==="touch"||c?.matches)return;if(!z(r)){y&&V();return}let a=e.getBoundingClientRect(),g=(S,T,$)=>Math.max(-1,Math.min(1,(S-T-$/2)/($/2))),f=g(r.clientX,a.left+h.ox,h.w),x=g(r.clientY,a.top+h.oy,h.h);y=true,D(H(t.tx*.3-x*t.max*.7,t.max),H(t.ty*.3-f*t.max*.7,t.max),"transform .15s ease-out");},_=()=>{y&&V();},Z=r=>{if(t.disabled||!z(r))return;let a={x:r.clientX,y:r.clientY,tx:v,ty:M,moved:false,touch:r.pointerType==="touch",dragging:t.control==="drag"||t.control==="hover"&&r.pointerType==="touch"};k=a,j(true);let g=x=>{let S=x.clientX-a.x,T=x.clientY-a.y;if(!a.moved){if(Math.hypot(S,T)<5)return;a.moved=true,j(false);}if(!a.dragging)return;let $=a.touch&&t.control==="hover"&&t.touchScroll?0:T;D(H(a.tx-$*t.sens,t.max),H(a.ty-S*t.sens,t.max));},f=()=>{removeEventListener("pointermove",g),removeEventListener("pointerup",f),removeEventListener("pointercancel",f),k=null,j(false),B=a.moved&&a.dragging,B&&t.springBack&&N();};addEventListener("pointermove",g),addEventListener("pointerup",f),addEventListener("pointercancel",f);},J=r=>{B&&(r.stopPropagation(),r.preventDefault(),B=false);};e.addEventListener("pointermove",q),e.addEventListener("pointerleave",_),e.addEventListener("pointerdown",Z),p.addEventListener("click",J,true);let O=new ResizeObserver(I);return O.observe(p),O.observe(l),I(),{update(r){u={...u,...r,advanced:{...u.advanced,...r.advanced}},I();},destroy(){O.disconnect(),e.removeEventListener("pointermove",q),e.removeEventListener("pointerleave",_),e.removeEventListener("pointerdown",Z),p.removeEventListener("click",J,true),e.style.touchAction="",e.style.cursor="",X&&(e.style.display=""),o.built&&(e.insertBefore(p,s),s.remove());}}}exports.brickbox=Be;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { B as BrickBoxOptions, a as BrickBoxInstance } from './types-Cdnliv69.cjs';
|
|
2
|
+
export { A as Advanced, C as Control, L as LightWord, T as Tilt } from './types-Cdnliv69.cjs';
|
|
3
|
+
|
|
4
|
+
declare function brickbox(root: HTMLElement, options?: BrickBoxOptions): BrickBoxInstance;
|
|
5
|
+
|
|
6
|
+
export { BrickBoxInstance, BrickBoxOptions, brickbox };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { B as BrickBoxOptions, a as BrickBoxInstance } from './types-Cdnliv69.js';
|
|
2
|
+
export { A as Advanced, C as Control, L as LightWord, T as Tilt } from './types-Cdnliv69.js';
|
|
3
|
+
|
|
4
|
+
declare function brickbox(root: HTMLElement, options?: BrickBoxOptions): BrickBoxInstance;
|
|
5
|
+
|
|
6
|
+
export { BrickBoxInstance, BrickBoxOptions, brickbox };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{c as brickbox}from'./chunk-3CCNRF7U.js';
|
package/dist/react.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
'use strict';var react=require('react'),jsxRuntime=require('react/jsx-runtime');function Be(e){let i=[],r=0,o="";for(let n of e)n==="("&&r++,n===")"&&r--,n===","&&!r?(i.push(o.trim()),o=""):o+=n;return i.push(o.trim()),i}function ce(e){if((e.match(/gradient\(/g)||[]).length!==1)return null;let i=Be(e.slice(e.indexOf("(")+1,e.lastIndexOf(")"))),r=180;if(/^to /.test(i[0])||/deg$/.test(i[0])){let n=i.shift();if(/deg$/.test(n))r=parseFloat(n);else {let l=/top/.test(n),d=/bottom/.test(n),p=/left/.test(n),c=/right/.test(n);r=l&&c?45:d&&c?135:d&&p?225:l&&p?315:c?90:p?270:l?0:180;}}let o=[];for(let n of i){let l=n.match(/^(rgba?\([^)]*\))\s*([\d.]+)?%?$/);if(!l||/px|em/.test(n))return null;let d=l[1].match(/[\d.]+/g).map(Number);d.length<4&&d.push(1),o.push({raw:n,c:d,t:l[2]==null?null:+l[2]/100});}if(o.length<2)return null;o[0].t==null&&(o[0].t=0),o[o.length-1].t==null&&(o[o.length-1].t=1);for(let n=1;n<o.length;n++){if(o[n].t!=null)continue;let l=n;for(;o[l].t==null;)l++;let d=o[n-1].t,p=o[l].t;for(let c=n;c<l;c++)o[c].t=d+(p-d)*(c-n+1)/(l-n+1);}return {ang:r,st:o}}function U(e,i,r,o,n){let l=e.ang*Math.PI/180,d=Math.abs(o*Math.sin(l))+Math.abs(n*Math.cos(l)),p=((i-o/2)*Math.sin(l)-(r-n/2)*Math.cos(l))/d+.5,c=e.st;if(p<=c[0].t)return `rgba(${c[0].c})`;for(let u=1;u<c.length;u++)if(p<=c[u].t){let t=(p-c[u-1].t)/(c[u].t-c[u-1].t||1),b=c[u-1].c,x=c[u].c;return `rgba(${b.map((v,g)=>+(v+(x[g]-v)*t).toFixed(2))})`}return `rgba(${c[c.length-1].c})`}function pe(e,i,r){let o=Math.min(1,i/(e[0]+e[1]),i/(e[3]+e[2]),r/(e[0]+e[3]),r/(e[1]+e[2]));return e.map(n=>n*o)}function ue(e,i,r,o){let n=[],l=[[1,e-r[1],r[1],-90,e,0],[2,e-r[2],i-r[2],0,e,i],[3,r[3],i-r[3],90,0,i],[0,r[0],r[0],180,0,0]];for(let[d,p,c,u,t,b]of l){let x=r[d],v=x>.5?Math.max(1,Math.ceil(Math.PI/2/(2*Math.acos(Math.max(0,1-o/x))))):0;if(!v)n.push([t,b]);else for(let g=0;g<=v;g++){let M=(u+90*g/v)*Math.PI/180;n.push([p+x*Math.cos(M),c+x*Math.sin(M)]);}}return n.reverse()}var B={persp:{display:"grid",width:"100%",height:"100%"},obj:{display:"grid",width:"100%",height:"100%",transformStyle:"preserve-3d",willChange:"transform"},sink:{display:"grid",width:"100%",height:"100%",position:"relative",transformStyle:"preserve-3d"},walls:{position:"absolute",transformStyle:"preserve-3d",pointerEvents:"none"}},S="data-bb";var we={top:0,"top-right":45,right:90,"bottom-right":135,bottom:180,"bottom-left":225,left:270,"top-left":315},V=(e,i)=>Math.max(-i,Math.min(i,e)),Pe=()=>typeof process<"u"&&!!process.env&&process.env.NODE_ENV!=="production",de=false;function Ce(){if(!(de||typeof CSS>"u"||!CSS.registerProperty)){de=true;try{CSS.registerProperty({name:"--bb-p",syntax:"<number>",inherits:!0,initialValue:"1"});}catch{}}}function me(e){let i=e.advanced||{},r=(e.sideColor??"match").trim();return {depth:e.depth??24,control:e.control??"hover",tx:e.tilt?.x??14,ty:e.tilt?.y??22,max:e.maxAngle??60,springBack:e.springBack??true,springDur:e.springDuration??700,pressDepth:e.pressDepth,pressDur:e.pressDuration??150,side:r,shading:e.shading??r==="match",light:typeof e.light=="number"?e.light:we[e.light??"top-left"]??315,persp:e.perspective??1e3,edge:e.edgeColor??"none",edgeW:e.edgeWidth??1,touchScroll:e.touchScroll??true,disabled:e.disabled??false,tol:i.tolerance??.25,sens:i.sensitivity??.5,bounce:i.bounce??1,cull:i.cull??true}}function be(e,i){if(typeof e=="number")return e;if(/^\s*-?[\d.]+(px)?\s*$/.test(e))return parseFloat(e);let r=document.createElement("div");r.style.cssText=`position:absolute;visibility:hidden;width:${e}`,i.appendChild(r);let o=r.getBoundingClientRect().width;return r.remove(),o}function De(e){let i=u=>e.querySelector(`[${S}="${u}"]`),r=i("persp");if(r){let u=i("sink");return {persp:r,obj:i("obj"),sink:u,walls:i("walls"),child:u.firstElementChild,built:false}}let o=e.firstElementChild;if(!o)throw new Error("brickbox: the root needs one element child");let n=u=>{let t=document.createElement("div");return t.setAttribute(S,u),Object.assign(t.style,B[u]),t},l=n("persp"),d=n("obj"),p=n("sink"),c=n("walls");return c.setAttribute("aria-hidden","true"),e.append(l),l.append(d),d.append(p),p.append(o,c),{persp:l,obj:d,sink:p,walls:c,child:o,built:true}}function he(e,i={}){Ce();let r=De(e),{persp:o,obj:n,sink:l,walls:d,child:p}=r,c=typeof matchMedia<"u"?matchMedia("(prefers-reduced-motion: reduce)"):null,u=i,t=me(u),b={w:0,h:0,ox:0,oy:0,pp:1},x=t.tx,v=t.ty,g=false,M=null,w=false,F=false;if(!e.style.display){let s=l.style.display;l.style.display="block";let a=/^inline/.test(getComputedStyle(p).display);l.style.display=s,e.style.display=a?"inline-block":"block",F=true;}let P=(s,a,f)=>{x=s,v=a,n.style.transition=f||"none",n.style.transform=`rotateX(${s}deg) rotateY(${-a}deg)`;},J=()=>c?.matches?"none":`transform ${t.springDur}ms cubic-bezier(.2,${1+.5*t.bounce},.4,1)`,G=()=>P(t.tx,t.ty,J()),j=s=>l.style.setProperty("--bb-p",String(s&&b.pp<1?b.pp:1));function Y(){t=me(u);let s=p.offsetWidth,a=p.offsetHeight,f=p.offsetLeft,y=p.offsetTop,E=Math.max(0,be(t.depth,e));Pe()&&E>t.persp*.5&&console.warn(`[brickbox] depth ${E}px is more than half of perspective (${t.persp}px); the box may clip or distort.`);let O=t.pressDepth==null?1:Math.min(1,Math.max(0,be(t.pressDepth,e)/(E||1)));b={w:s,h:a,ox:f,oy:y,pp:O};let A=!!c?.matches;if(d.innerHTML="",d.hidden=t.disabled,Object.assign(d.style,{left:f+"px",top:y+"px",width:s+"px",height:a+"px"}),l.style.setProperty("--bb-d",E+"px"),l.style.transform="translateZ(calc(var(--bb-d) * (var(--bb-p) - 1)))",l.style.transition=`--bb-p ${A?0:t.pressDur}ms ease`,o.style.perspective=t.persp+"px",n.style.transformOrigin=`${f+s/2}px ${y+a/2}px ${-E/2}px`,e.style.touchAction=t.control==="drag"||t.control==="hover"&&!t.touchScroll?"none":t.control==="hover"?"pan-y":"auto",e.style.cursor=t.control==="drag"?"grab":"",t.disabled||!s||!a){n.style.transform="none";return}let L=getComputedStyle(p),ge=pe(["top-left","top-right","bottom-right","bottom-left"].map(m=>{let h=L.getPropertyValue(`border-${m}-radius`).split(" ")[0];return h.endsWith("%")?parseFloat(h)/100*s:parseFloat(h)||0}),s,a),ee=L.backgroundImage,Z=ee.startsWith("linear-gradient")?ce(ee):null,z=L.backgroundColor;(z==="rgba(0, 0, 0, 0)"||z==="transparent")&&(z="rgb(120,120,130)");let te=t.side==="match",ne=te?z:t.side,re=t.light*Math.PI/180,ye=Math.sin(re),xe=-Math.cos(re),k=ue(s,a,ge,t.tol),$=k.length,ve=m=>{let h=k[(m+1)%$];return {a:Math.atan2(h[1]-k[m][1],h[0]-k[m][0]),len:Math.hypot(h[0]-k[m][0],h[1]-k[m][1])}},I=k.map((m,h)=>ve(h)),K=t.edge==="none"||t.edge===""?null:t.edge==="auto"?"rgba(0,0,0,.5)":t.edge,se=document.createDocumentFragment();for(let m=0;m<$;m++){if(I[m].len<.01)continue;let h=(m+$-1)%$;for(;I[h].len<.01&&h!==m;)h=(h+$-1)%$;let R=Math.abs(I[m].a-I[h].a);R=Math.min(R,2*Math.PI-R);let[oe,ie]=k[m],[Ee,Me]=k[(m+1)%$],Q=I[m].a,ke=(-Math.sin(Q)*ye+Math.cos(Q)*xe+1)/2,le=.08+.3*(1-ke),Le=le+.28,Se=te&&Z?`linear-gradient(90deg,${U(Z,oe,ie,s,a)},${U(Z,Ee,Me,s,a)})`:`linear-gradient(${ne},${ne})`,Te=t.shading?`linear-gradient(rgba(0,0,0,${le.toFixed(2)}),rgba(0,0,0,${Le.toFixed(2)})),`:"",$e=K?`border-bottom:${t.edgeW}px solid ${K};${R>.9?`border-left:${t.edgeW}px solid ${K};`:""}`:"",ae=document.createElement("i");ae.style.cssText=`position:absolute;left:0;top:0;box-sizing:border-box;height:var(--bb-d);transform-origin:0 0;${t.cull?"backface-visibility:hidden;":""}width:${I[m].len+.5}px;${$e}background:${Te}${Se};transform:translate(${oe}px,${ie}px) rotate(${Q*180/Math.PI}deg) rotateX(-90deg) scaleY(var(--bb-p))`,se.appendChild(ae);}d.appendChild(se),!M&&!g&&P(t.tx,t.ty);}let X=s=>{let a=e.getBoundingClientRect(),f=a.left+b.ox,y=a.top+b.oy;return s.clientX>=f&&s.clientX<=f+b.w&&s.clientY>=y&&s.clientY<=y+b.h},C=()=>{g=false,t.springBack&&G();},N=s=>{if(t.disabled||M||t.control!=="hover"||s.pointerType==="touch"||c?.matches)return;if(!X(s)){g&&C();return}let a=e.getBoundingClientRect(),f=(O,A,L)=>Math.max(-1,Math.min(1,(O-A-L/2)/(L/2))),y=f(s.clientX,a.left+b.ox,b.w),E=f(s.clientY,a.top+b.oy,b.h);g=true,P(V(t.tx*.3-E*t.max*.7,t.max),V(t.ty*.3-y*t.max*.7,t.max),"transform .15s ease-out");},W=()=>{g&&C();},T=s=>{if(t.disabled||!X(s))return;let a={x:s.clientX,y:s.clientY,tx:x,ty:v,moved:false,touch:s.pointerType==="touch",dragging:t.control==="drag"||t.control==="hover"&&s.pointerType==="touch"};M=a,j(true);let f=E=>{let O=E.clientX-a.x,A=E.clientY-a.y;if(!a.moved){if(Math.hypot(O,A)<5)return;a.moved=true,j(false);}if(!a.dragging)return;let L=a.touch&&t.control==="hover"&&t.touchScroll?0:A;P(V(a.tx-L*t.sens,t.max),V(a.ty-O*t.sens,t.max));},y=()=>{removeEventListener("pointermove",f),removeEventListener("pointerup",y),removeEventListener("pointercancel",y),M=null,j(false),w=a.moved&&a.dragging,w&&t.springBack&&G();};addEventListener("pointermove",f),addEventListener("pointerup",y),addEventListener("pointercancel",y);},D=s=>{w&&(s.stopPropagation(),s.preventDefault(),w=false);};e.addEventListener("pointermove",N),e.addEventListener("pointerleave",W),e.addEventListener("pointerdown",T),p.addEventListener("click",D,true);let H=new ResizeObserver(Y);return H.observe(p),H.observe(l),Y(),{update(s){u={...u,...s,advanced:{...u.advanced,...s.advanced}},Y();},destroy(){H.disconnect(),e.removeEventListener("pointermove",N),e.removeEventListener("pointerleave",W),e.removeEventListener("pointerdown",T),p.removeEventListener("click",D,true),e.style.touchAction="",e.style.cursor="",F&&(e.style.display=""),r.built&&(e.insertBefore(p,o),o.remove());}}}var fe=typeof window<"u"?react.useLayoutEffect:react.useEffect,Ve=react.forwardRef(function(i,r){let{as:o,children:n,depth:l,control:d,tilt:p,maxAngle:c,springBack:u,springDuration:t,pressDepth:b,pressDuration:x,sideColor:v,shading:g,light:M,perspective:w,edgeColor:F,edgeWidth:P,touchScroll:J,disabled:G,advanced:j,...Y}=i,X=o||"div",C={depth:l,control:d,tilt:p,maxAngle:c,springBack:u,springDuration:t,pressDepth:b,pressDuration:x,sideColor:v,shading:g,light:M,perspective:w,edgeColor:F,edgeWidth:P,touchScroll:J,disabled:G,advanced:j},N=JSON.stringify(C),W=react.useRef(null),T=react.useRef(null),D=react.useRef(C),H=react.useRef(true);D.current=C;let s=react.useCallback(a=>{W.current=a,typeof r=="function"?r(a):r&&(r.current=a);},[r]);return fe(()=>(T.current=he(W.current,D.current),()=>{T.current?.destroy(),T.current=null;}),[]),fe(()=>{if(H.current){H.current=false;return}T.current?.update(D.current);},[N]),jsxRuntime.jsx(X,{...Y,ref:s,suppressHydrationWarning:true,children:jsxRuntime.jsx("div",{[S]:"persp",style:B.persp,children:jsxRuntime.jsx("div",{[S]:"obj",style:B.obj,children:jsxRuntime.jsxs("div",{[S]:"sink",style:B.sink,children:[n,jsxRuntime.jsx("div",{[S]:"walls","aria-hidden":"true",style:B.walls})]})})})})});exports.BrickBox=Ve;
|
package/dist/react.d.cts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { HTMLAttributes, ElementType, ReactElement } from 'react';
|
|
3
|
+
import { BrickBoxOptions } from './index.cjs';
|
|
4
|
+
|
|
5
|
+
interface BrickBoxProps extends BrickBoxOptions, Omit<HTMLAttributes<HTMLElement>, 'children'> {
|
|
6
|
+
/** Element type of the outer wrapper. Layout props (flex, grid, margin) belong here. @default "div" */
|
|
7
|
+
as?: ElementType;
|
|
8
|
+
/** Exactly one element: the front face. */
|
|
9
|
+
children: ReactElement;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Gives its single child real 3D depth.
|
|
13
|
+
* Layout on the wrapper (className, style), looks on the child.
|
|
14
|
+
*/
|
|
15
|
+
declare const BrickBox: react.ForwardRefExoticComponent<BrickBoxProps & react.RefAttributes<HTMLElement>>;
|
|
16
|
+
|
|
17
|
+
export { BrickBox };
|
|
18
|
+
export type { BrickBoxProps };
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { HTMLAttributes, ElementType, ReactElement } from 'react';
|
|
3
|
+
import { BrickBoxOptions } from './index.js';
|
|
4
|
+
|
|
5
|
+
interface BrickBoxProps extends BrickBoxOptions, Omit<HTMLAttributes<HTMLElement>, 'children'> {
|
|
6
|
+
/** Element type of the outer wrapper. Layout props (flex, grid, margin) belong here. @default "div" */
|
|
7
|
+
as?: ElementType;
|
|
8
|
+
/** Exactly one element: the front face. */
|
|
9
|
+
children: ReactElement;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Gives its single child real 3D depth.
|
|
13
|
+
* Layout on the wrapper (className, style), looks on the child.
|
|
14
|
+
*/
|
|
15
|
+
declare const BrickBox: react.ForwardRefExoticComponent<BrickBoxProps & react.RefAttributes<HTMLElement>>;
|
|
16
|
+
|
|
17
|
+
export { BrickBox };
|
|
18
|
+
export type { BrickBoxProps };
|
package/dist/react.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import {c,a,b}from'./chunk-3CCNRF7U.js';import {forwardRef,useRef,useCallback,useLayoutEffect,useEffect}from'react';import {jsx,jsxs}from'react/jsx-runtime';var d=typeof window<"u"?useLayoutEffect:useEffect,K=forwardRef(function(f,e){let{as:m,children:B,depth:y,control:k,tilt:T,maxAngle:E,springBack:S,springDuration:x,pressDepth:g,pressDuration:h,sideColor:v,shading:L,light:b$1,perspective:C,edgeColor:H,edgeWidth:M,touchScroll:P,disabled:R,advanced:w,...O}=f,A=m||"div",i={depth:y,control:k,tilt:T,maxAngle:E,springBack:S,springDuration:x,pressDepth:g,pressDuration:h,sideColor:v,shading:L,light:b$1,perspective:C,edgeColor:H,edgeWidth:M,touchScroll:P,disabled:R,advanced:w},D=JSON.stringify(i),p=useRef(null),n=useRef(null),c$1=useRef(i),u=useRef(true);c$1.current=i;let I=useCallback(l=>{p.current=l,typeof e=="function"?e(l):e&&(e.current=l);},[e]);return d(()=>(n.current=c(p.current,c$1.current),()=>{n.current?.destroy(),n.current=null;}),[]),d(()=>{if(u.current){u.current=false;return}n.current?.update(c$1.current);},[D]),jsx(A,{...O,ref:I,suppressHydrationWarning:true,children:jsx("div",{[b]:"persp",style:a.persp,children:jsx("div",{[b]:"obj",style:a.obj,children:jsxs("div",{[b]:"sink",style:a.sink,children:[B,jsx("div",{[b]:"walls","aria-hidden":"true",style:a.walls})]})})})})});export{K as BrickBox};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
type Control = 'hover' | 'drag' | 'static';
|
|
2
|
+
type LightWord = 'top' | 'top-right' | 'right' | 'bottom-right' | 'bottom' | 'bottom-left' | 'left' | 'top-left';
|
|
3
|
+
/** Resting angle in degrees. Positive x shows the bottom wall, positive y shows the right wall. */
|
|
4
|
+
interface Tilt {
|
|
5
|
+
x: number;
|
|
6
|
+
y: number;
|
|
7
|
+
}
|
|
8
|
+
interface Advanced {
|
|
9
|
+
/** Max distance (px) between a curved wall and the true curve. Lower is smoother and heavier. @default 0.25 */
|
|
10
|
+
tolerance?: number;
|
|
11
|
+
/** Degrees of tilt per pixel of drag. @default 0.5 */
|
|
12
|
+
sensitivity?: number;
|
|
13
|
+
/** 0 is a plain ease, 1 is the default springy overshoot. @default 1 */
|
|
14
|
+
bounce?: number;
|
|
15
|
+
/** Hide back-facing walls to halve wall painting. @default true */
|
|
16
|
+
cull?: boolean;
|
|
17
|
+
}
|
|
18
|
+
interface BrickBoxOptions {
|
|
19
|
+
/** Extrusion length. A number is px, a string is any CSS length. @default 24 */
|
|
20
|
+
depth?: number | string;
|
|
21
|
+
/** How the box reacts to the pointer. On touch, "hover" behaves as drag. @default "hover" */
|
|
22
|
+
control?: Control;
|
|
23
|
+
/** Resting angle in degrees. @default { x: 14, y: 22 } */
|
|
24
|
+
tilt?: Tilt;
|
|
25
|
+
/** Largest angle hover and drag may reach, in degrees. @default 60 */
|
|
26
|
+
maxAngle?: number;
|
|
27
|
+
/** Return to the resting tilt after release or leave. @default true */
|
|
28
|
+
springBack?: boolean;
|
|
29
|
+
/** Length of the return animation in ms. @default 700 */
|
|
30
|
+
springDuration?: number;
|
|
31
|
+
/** Depth while pressed. Defaults to `depth`, which means no sinking. */
|
|
32
|
+
pressDepth?: number | string;
|
|
33
|
+
/** Length of the press transition in ms. @default 150 */
|
|
34
|
+
pressDuration?: number;
|
|
35
|
+
/** "match" follows the element's background, or pass one CSS colour. @default "match" */
|
|
36
|
+
sideColor?: 'match' | (string & {});
|
|
37
|
+
/** Lighting on the walls. @default true for "match", false for an explicit colour */
|
|
38
|
+
shading?: boolean;
|
|
39
|
+
/** Where the light comes from: a word, or degrees (0 is top, clockwise). @default "top-left" */
|
|
40
|
+
light?: LightWord | number;
|
|
41
|
+
/** Perspective distance in px. @default 1000 */
|
|
42
|
+
perspective?: number;
|
|
43
|
+
/** Lines on the back rim and sharp corners. "auto" is a darker line. @default "none" */
|
|
44
|
+
edgeColor?: 'none' | 'auto' | (string & {});
|
|
45
|
+
/** Edge line width in px. @default 1 */
|
|
46
|
+
edgeWidth?: number;
|
|
47
|
+
/** Touch only: true lets vertical swipes scroll the page (only horizontal drags tilt). @default true */
|
|
48
|
+
touchScroll?: boolean;
|
|
49
|
+
/** Render the child normally with no 3D. @default false */
|
|
50
|
+
disabled?: boolean;
|
|
51
|
+
advanced?: Advanced;
|
|
52
|
+
}
|
|
53
|
+
interface BrickBoxInstance {
|
|
54
|
+
/** Merge new options and rebuild. Keys set to undefined reset to their default. */
|
|
55
|
+
update(options: BrickBoxOptions): void;
|
|
56
|
+
destroy(): void;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export type { Advanced as A, BrickBoxOptions as B, Control as C, LightWord as L, Tilt as T, BrickBoxInstance as a };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
type Control = 'hover' | 'drag' | 'static';
|
|
2
|
+
type LightWord = 'top' | 'top-right' | 'right' | 'bottom-right' | 'bottom' | 'bottom-left' | 'left' | 'top-left';
|
|
3
|
+
/** Resting angle in degrees. Positive x shows the bottom wall, positive y shows the right wall. */
|
|
4
|
+
interface Tilt {
|
|
5
|
+
x: number;
|
|
6
|
+
y: number;
|
|
7
|
+
}
|
|
8
|
+
interface Advanced {
|
|
9
|
+
/** Max distance (px) between a curved wall and the true curve. Lower is smoother and heavier. @default 0.25 */
|
|
10
|
+
tolerance?: number;
|
|
11
|
+
/** Degrees of tilt per pixel of drag. @default 0.5 */
|
|
12
|
+
sensitivity?: number;
|
|
13
|
+
/** 0 is a plain ease, 1 is the default springy overshoot. @default 1 */
|
|
14
|
+
bounce?: number;
|
|
15
|
+
/** Hide back-facing walls to halve wall painting. @default true */
|
|
16
|
+
cull?: boolean;
|
|
17
|
+
}
|
|
18
|
+
interface BrickBoxOptions {
|
|
19
|
+
/** Extrusion length. A number is px, a string is any CSS length. @default 24 */
|
|
20
|
+
depth?: number | string;
|
|
21
|
+
/** How the box reacts to the pointer. On touch, "hover" behaves as drag. @default "hover" */
|
|
22
|
+
control?: Control;
|
|
23
|
+
/** Resting angle in degrees. @default { x: 14, y: 22 } */
|
|
24
|
+
tilt?: Tilt;
|
|
25
|
+
/** Largest angle hover and drag may reach, in degrees. @default 60 */
|
|
26
|
+
maxAngle?: number;
|
|
27
|
+
/** Return to the resting tilt after release or leave. @default true */
|
|
28
|
+
springBack?: boolean;
|
|
29
|
+
/** Length of the return animation in ms. @default 700 */
|
|
30
|
+
springDuration?: number;
|
|
31
|
+
/** Depth while pressed. Defaults to `depth`, which means no sinking. */
|
|
32
|
+
pressDepth?: number | string;
|
|
33
|
+
/** Length of the press transition in ms. @default 150 */
|
|
34
|
+
pressDuration?: number;
|
|
35
|
+
/** "match" follows the element's background, or pass one CSS colour. @default "match" */
|
|
36
|
+
sideColor?: 'match' | (string & {});
|
|
37
|
+
/** Lighting on the walls. @default true for "match", false for an explicit colour */
|
|
38
|
+
shading?: boolean;
|
|
39
|
+
/** Where the light comes from: a word, or degrees (0 is top, clockwise). @default "top-left" */
|
|
40
|
+
light?: LightWord | number;
|
|
41
|
+
/** Perspective distance in px. @default 1000 */
|
|
42
|
+
perspective?: number;
|
|
43
|
+
/** Lines on the back rim and sharp corners. "auto" is a darker line. @default "none" */
|
|
44
|
+
edgeColor?: 'none' | 'auto' | (string & {});
|
|
45
|
+
/** Edge line width in px. @default 1 */
|
|
46
|
+
edgeWidth?: number;
|
|
47
|
+
/** Touch only: true lets vertical swipes scroll the page (only horizontal drags tilt). @default true */
|
|
48
|
+
touchScroll?: boolean;
|
|
49
|
+
/** Render the child normally with no 3D. @default false */
|
|
50
|
+
disabled?: boolean;
|
|
51
|
+
advanced?: Advanced;
|
|
52
|
+
}
|
|
53
|
+
interface BrickBoxInstance {
|
|
54
|
+
/** Merge new options and rebuild. Keys set to undefined reset to their default. */
|
|
55
|
+
update(options: BrickBoxOptions): void;
|
|
56
|
+
destroy(): void;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export type { Advanced as A, BrickBoxOptions as B, Control as C, LightWord as L, Tilt as T, BrickBoxInstance as a };
|
package/package.json
CHANGED
|
@@ -1,6 +1,105 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brickbox",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Wrap any element and give it real 3D depth. Tiny framework-free core with a React wrapper.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"3d",
|
|
7
|
+
"css",
|
|
8
|
+
"depth",
|
|
9
|
+
"extrude",
|
|
10
|
+
"tilt",
|
|
11
|
+
"react",
|
|
12
|
+
"web-component",
|
|
13
|
+
"custom-element",
|
|
14
|
+
"ui",
|
|
15
|
+
"tactile",
|
|
16
|
+
"button",
|
|
17
|
+
"card"
|
|
18
|
+
],
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"author": "PRASHANT PRASAD",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/Prashaxt/brickbox.git"
|
|
24
|
+
},
|
|
25
|
+
"homepage": "https://github.com/Prashaxt/brickbox#readme",
|
|
26
|
+
"bugs": {
|
|
27
|
+
"url": "https://github.com/Prashaxt/brickbox/issues"
|
|
28
|
+
},
|
|
29
|
+
"type": "module",
|
|
30
|
+
"sideEffects": false,
|
|
31
|
+
"main": "./dist/index.cjs",
|
|
32
|
+
"module": "./dist/index.js",
|
|
33
|
+
"types": "./dist/index.d.ts",
|
|
34
|
+
"typesVersions": {
|
|
35
|
+
"*": {
|
|
36
|
+
"react": [
|
|
37
|
+
"./dist/react.d.ts"
|
|
38
|
+
],
|
|
39
|
+
"element": [
|
|
40
|
+
"./dist/element.d.ts"
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"exports": {
|
|
45
|
+
".": {
|
|
46
|
+
"import": {
|
|
47
|
+
"types": "./dist/index.d.ts",
|
|
48
|
+
"default": "./dist/index.js"
|
|
49
|
+
},
|
|
50
|
+
"require": {
|
|
51
|
+
"types": "./dist/index.d.cts",
|
|
52
|
+
"default": "./dist/index.cjs"
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"./react": {
|
|
56
|
+
"import": {
|
|
57
|
+
"types": "./dist/react.d.ts",
|
|
58
|
+
"default": "./dist/react.js"
|
|
59
|
+
},
|
|
60
|
+
"require": {
|
|
61
|
+
"types": "./dist/react.d.cts",
|
|
62
|
+
"default": "./dist/react.cjs"
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"./element": {
|
|
66
|
+
"import": {
|
|
67
|
+
"types": "./dist/element.d.ts",
|
|
68
|
+
"default": "./dist/element.js"
|
|
69
|
+
},
|
|
70
|
+
"require": {
|
|
71
|
+
"types": "./dist/element.d.cts",
|
|
72
|
+
"default": "./dist/element.cjs"
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"files": [
|
|
77
|
+
"dist"
|
|
78
|
+
],
|
|
79
|
+
"engines": {
|
|
80
|
+
"node": ">=18"
|
|
81
|
+
},
|
|
82
|
+
"scripts": {
|
|
83
|
+
"build": "tsup",
|
|
84
|
+
"test": "vitest run",
|
|
85
|
+
"typecheck": "tsc --noEmit",
|
|
86
|
+
"size": "node scripts/size.mjs",
|
|
87
|
+
"prepublishOnly": "npm run typecheck && npm test && npm run build"
|
|
88
|
+
},
|
|
89
|
+
"peerDependencies": {
|
|
90
|
+
"react": ">=17"
|
|
91
|
+
},
|
|
92
|
+
"peerDependenciesMeta": {
|
|
93
|
+
"react": {
|
|
94
|
+
"optional": true
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
"devDependencies": {
|
|
98
|
+
"@types/react": "^19.3.0",
|
|
99
|
+
"react": "^19.3.1",
|
|
100
|
+
"react-dom": "^19.3.1",
|
|
101
|
+
"tsup": "^9.0.0",
|
|
102
|
+
"typescript": "^5.9.3",
|
|
103
|
+
"vitest": "^5.0.5"
|
|
104
|
+
}
|
|
105
|
+
}
|