eclosion 1.0.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 +139 -0
- package/dist/react/index.d.mts +55 -0
- package/dist/react/index.mjs +2 -0
- package/package.json +82 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jordan Mars
|
|
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
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# eclosion
|
|
2
|
+
|
|
3
|
+
[](https://github.com/jordankmars/eclose/actions/workflows/ci.yml)
|
|
4
|
+
[](./LICENSE)
|
|
5
|
+
|
|
6
|
+
> A dialog or popover that grows out of its trigger.
|
|
7
|
+
|
|
8
|
+
<p align="center">
|
|
9
|
+
<img src="./.github/assets/demo.gif" width="420" alt="A Now playing pill grows into a music player card, then shrinks back into the pill" />
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
A card becomes a detail view, a button becomes a menu, a pill becomes a panel. It's live DOM, every morph can be interrupted, and it dismisses with a swipe.
|
|
13
|
+
|
|
14
|
+
It's about 9 kB gzipped, with no dependencies beyond React.
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
npm install eclosion
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
import { Eclosion } from "eclosion/react";
|
|
26
|
+
|
|
27
|
+
<Eclosion.Root>
|
|
28
|
+
<Eclosion.Trigger>Share</Eclosion.Trigger>
|
|
29
|
+
<Eclosion.Content>
|
|
30
|
+
<Eclosion.Title>Share this</Eclosion.Title>
|
|
31
|
+
<Eclosion.Close />
|
|
32
|
+
</Eclosion.Content>
|
|
33
|
+
</Eclosion.Root>;
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
eclosion ships no CSS. Style the parts with your own classes, and the motion takes care of itself.
|
|
37
|
+
|
|
38
|
+
### Parts
|
|
39
|
+
|
|
40
|
+
| Part | Props |
|
|
41
|
+
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------ |
|
|
42
|
+
| `Eclosion.Root` | `open`, `defaultOpen`, `onOpenChange`, `placement`, `origin`, `modal`, `swipe`, `container` |
|
|
43
|
+
| `Eclosion.Trigger`, `Eclosion.Close` | `asChild`, plus button props |
|
|
44
|
+
| `Eclosion.Content` | `initialFocus` ref, plus div props. Without it, focus goes to an `autoFocus` child, or else the dialog |
|
|
45
|
+
| `Eclosion.Shared` | `id` (required), `asChild` |
|
|
46
|
+
| `Eclosion.Overlay` | div props. You color it, and it fades on its own |
|
|
47
|
+
| `Eclosion.Title`, `Eclosion.Description` | Label the dialog for assistive technology |
|
|
48
|
+
|
|
49
|
+
Every part also has `data-state`: `closed`, `opening`, `open` or `closing`.
|
|
50
|
+
|
|
51
|
+
### Placement
|
|
52
|
+
|
|
53
|
+
`placement="anchored"` is the default. The content rests on top of its trigger, follows it as it moves, and stays usable alongside the page. Set `modal` to opt in to focus trapping, an inert page and scroll lock.
|
|
54
|
+
|
|
55
|
+
`placement="centered"` puts it in the middle of the viewport, and is modal unless you set `modal={false}`.
|
|
56
|
+
|
|
57
|
+
### Origin
|
|
58
|
+
|
|
59
|
+
`origin` sets the point anchored content grows from. That point of the content sits on the same point of the trigger and stays still while the rest grows away from it. It's `center` by default, and can be a side (`top`, `right`, `bottom`, `left`) or a corner (`top-left`, `top-right`, `bottom-left`, `bottom-right`).
|
|
60
|
+
|
|
61
|
+
Near a viewport edge, it lines up the trigger's other edge if that fits, and otherwise stays on screen. Centered content ignores `origin` and always grows from its center.
|
|
62
|
+
|
|
63
|
+
### Shared elements
|
|
64
|
+
|
|
65
|
+
Put an `Eclosion.Shared` with the same `id` on each side, and that element flies across on its own while the surface grows around it.
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
<Eclosion.Root placement="centered">
|
|
69
|
+
<Eclosion.Trigger>
|
|
70
|
+
<Eclosion.Shared id="cover" className="thumbnail" />
|
|
71
|
+
</Eclosion.Trigger>
|
|
72
|
+
<Eclosion.Overlay className="scrim" />
|
|
73
|
+
<Eclosion.Content>
|
|
74
|
+
<Eclosion.Shared id="cover" className="hero" />
|
|
75
|
+
</Eclosion.Content>
|
|
76
|
+
</Eclosion.Root>;
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
A copy does the flying and the real element appears when it lands, so keep Shared for media-like elements. A copy won't carry over a playing video or a canvas, or CSS scoped under the content's parents.
|
|
80
|
+
|
|
81
|
+
### Swipe
|
|
82
|
+
|
|
83
|
+
On touch, dragging down dismisses. Inside a scroller, it only takes over from the top. Pass `swipe={false}` to turn it off, or mark an element with `data-eclosion-no-swipe` to exempt it.
|
|
84
|
+
|
|
85
|
+
### Good to know
|
|
86
|
+
|
|
87
|
+
- Don't put a CSS `transition` on `Eclosion.Content`. It fights the per-frame updates.
|
|
88
|
+
- Portals sit at `z-index: 9999`. Set `--eclosion-z` to change that.
|
|
89
|
+
- A trigger's position is followed through scrolling and resizing, but not through a CSS transform animating on its parent mid-morph. The browser doesn't report those.
|
|
90
|
+
- Don't pass a `container` that's scaled. Translated is fine.
|
|
91
|
+
- With reduced motion, everything becomes a fade.
|
|
92
|
+
|
|
93
|
+
## How it works
|
|
94
|
+
|
|
95
|
+
The engine in `src/core` knows nothing about React. The adapter renders state, and a layout effect hands the elements to the core once they're in the DOM, so a controlled `open` prop takes the same path as a click.
|
|
96
|
+
|
|
97
|
+
The surface rides five springs: x, y, width, height and corner radius. They're measured in page coordinates rather than the viewport, so a morph keeps pointing at the same place while the page scrolls under it. Each frame, the surface gets a real width and height plus a translate, not a scale, so borders and shadows are drawn exactly while the content inside holds still and is clipped.
|
|
98
|
+
|
|
99
|
+
Reopening halfway through a close retargets the springs from where they are and keeps their velocity, so the motion bends instead of starting over. Everything that's moving shares one `requestAnimationFrame` loop, which stops on the first frame with nothing left to do.
|
|
100
|
+
|
|
101
|
+
## Adapters
|
|
102
|
+
|
|
103
|
+
| Framework | Import path | Status |
|
|
104
|
+
| --------- | ----------------- | ----------- |
|
|
105
|
+
| React | `eclosion/react` | Available |
|
|
106
|
+
| Vue | `eclosion/vue` | Coming soon |
|
|
107
|
+
| Svelte | `eclosion/svelte` | Coming soon |
|
|
108
|
+
|
|
109
|
+
## Development
|
|
110
|
+
|
|
111
|
+
You'll need Node 20 or later and pnpm.
|
|
112
|
+
|
|
113
|
+
```sh
|
|
114
|
+
pnpm install
|
|
115
|
+
pnpm play # playground at localhost:5173
|
|
116
|
+
pnpm test # unit tests
|
|
117
|
+
pnpm lint # biome
|
|
118
|
+
pnpm typecheck
|
|
119
|
+
pnpm size # checks the built size against the budget
|
|
120
|
+
pnpm site:dev # docs site
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
| Path | What's there |
|
|
124
|
+
| ------------ | ------------------------------------------------ |
|
|
125
|
+
| `src/core` | The engine: springs, morphs, focus, scroll lock |
|
|
126
|
+
| `src/react` | The React adapter, published as `eclosion/react` |
|
|
127
|
+
| `playground` | A Vite page for working on the engine |
|
|
128
|
+
| `site` | The docs site, built with Next.js |
|
|
129
|
+
|
|
130
|
+
The playground has two halves: demos that drive the core engine directly from
|
|
131
|
+
React, and the same demos built with the public components.
|
|
132
|
+
|
|
133
|
+
## Contributing
|
|
134
|
+
|
|
135
|
+
Bug reports and pull requests are welcome. For anything bigger than a fix, open an issue first so we can agree on the approach. CI runs lint, typecheck, tests, the build and the size check on every pull request.
|
|
136
|
+
|
|
137
|
+
## License
|
|
138
|
+
|
|
139
|
+
[MIT](./LICENSE)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { ComponentPropsWithoutRef, ReactNode, RefObject } from "react";
|
|
3
|
+
/** The point of the content that sits on the same point of its trigger. */
|
|
4
|
+
type Origin = "center" | "top" | "right" | "bottom" | "left" | "top-left" | "top-right" | "bottom-left" | "bottom-right";
|
|
5
|
+
interface RootOptions {
|
|
6
|
+
open?: boolean;
|
|
7
|
+
defaultOpen?: boolean;
|
|
8
|
+
onOpenChange?: (open: boolean) => void;
|
|
9
|
+
/** Where the content rests: on top of its trigger, or in the viewport center. */
|
|
10
|
+
placement?: "anchored" | "centered";
|
|
11
|
+
/**
|
|
12
|
+
* The point of anchored content that sits on the same point of its trigger,
|
|
13
|
+
* and stays still as it grows. Centered content ignores this and always
|
|
14
|
+
* grows from its center. Default "center".
|
|
15
|
+
*/
|
|
16
|
+
origin?: Origin;
|
|
17
|
+
/** Trap focus, make the page inert and lock scroll. Centered defaults to on. */
|
|
18
|
+
modal?: boolean;
|
|
19
|
+
/** Swipe down to dismiss, on touch. Default true. */
|
|
20
|
+
swipe?: boolean;
|
|
21
|
+
/** Render into this element instead of the document body. */
|
|
22
|
+
container?: HTMLElement | null;
|
|
23
|
+
}
|
|
24
|
+
interface RootProps extends RootOptions {
|
|
25
|
+
children?: ReactNode;
|
|
26
|
+
}
|
|
27
|
+
declare function Root({ children, ...options }: RootProps): import("react").JSX.Element;
|
|
28
|
+
interface AsChild {
|
|
29
|
+
/** Put the behaviour on the only child instead of rendering a button. */
|
|
30
|
+
asChild?: boolean;
|
|
31
|
+
}
|
|
32
|
+
interface TriggerProps extends ComponentPropsWithoutRef<"button">, AsChild {}
|
|
33
|
+
type CloseProps = TriggerProps;
|
|
34
|
+
interface ContentProps extends ComponentPropsWithoutRef<"div"> {
|
|
35
|
+
/** Takes focus on opening, ahead of an `autoFocus` child or the dialog. */
|
|
36
|
+
initialFocus?: RefObject<HTMLElement | null>;
|
|
37
|
+
}
|
|
38
|
+
type OverlayProps = ComponentPropsWithoutRef<"div">;
|
|
39
|
+
type TitleProps = ComponentPropsWithoutRef<"h2">;
|
|
40
|
+
type DescriptionProps = ComponentPropsWithoutRef<"p">;
|
|
41
|
+
interface SharedProps extends Omit<ComponentPropsWithoutRef<"div">, "id">, AsChild {
|
|
42
|
+
/** Matches this element with the one of the same id on the other side. */
|
|
43
|
+
id: string;
|
|
44
|
+
}
|
|
45
|
+
export declare const Eclosion: {
|
|
46
|
+
Root: typeof Root;
|
|
47
|
+
Trigger: import("react").ForwardRefExoticComponent<TriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
48
|
+
Content: import("react").ForwardRefExoticComponent<ContentProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
49
|
+
Close: import("react").ForwardRefExoticComponent<TriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
50
|
+
Overlay: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
|
|
51
|
+
Title: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>, "ref"> & import("react").RefAttributes<HTMLHeadingElement>>;
|
|
52
|
+
Description: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>, "ref"> & import("react").RefAttributes<HTMLParagraphElement>>;
|
|
53
|
+
Shared: import("react").ForwardRefExoticComponent<SharedProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
54
|
+
};
|
|
55
|
+
export type { CloseProps, ContentProps, DescriptionProps, Origin, OverlayProps, RootProps, SharedProps, TitleProps, TriggerProps };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import{cloneElement as e,createContext as t,createElement as n,forwardRef as r,isValidElement as i,useContext as a,useEffect as o,useId as s,useInsertionEffect as c,useLayoutEffect as l,useRef as u,useState as d,useSyncExternalStore as f}from"react";import{createPortal as p}from"react-dom";import{jsx as m,jsxs as h}from"react/jsx-runtime";function g(e=``){let t=(t,n)=>e.includes(t)?0:e.includes(n)?1:.5;return{x:t(`left`,`right`),y:t(`top`,`bottom`)}}function _(e,t,n,r,i,a){let o=r+8,s=r+i-8-n,c=t-n,l=e=>Math.max(o,Math.min(e,s)),u=e+c*a,d=e+c*(1-a);return l(u)!==u&&l(d)===d?d:l(u)}function ee(e,t,n,r){return{x:_(e.x,e.w,t.w,n.x,n.w,r.x),y:_(e.y,e.h,t.h,n.y,n.h,r.y)}}function v(){let e=window.visualViewport;return e?{x:e.pageLeft,y:e.pageTop,w:e.width,h:e.height}:{x:scrollX,y:scrollY,w:innerWidth,h:innerHeight}}function y(e,t){let n=n=>{let r=e();r&&n.target.contains(r)&&t()},r=window.visualViewport;return addEventListener(`resize`,t),document.addEventListener(`scroll`,n,!0),r?.addEventListener(`resize`,t),r?.addEventListener(`scroll`,t),()=>{removeEventListener(`resize`,t),document.removeEventListener(`scroll`,n,!0),r?.removeEventListener(`resize`,t),r?.removeEventListener(`scroll`,t)}}const b=1e6;function x(e){let t=e.getBoundingClientRect(),n=Math.max(t.left,1),r=Math.max(t.top,1),i=Math.min(t.right,innerWidth-1)-n,a=Math.min(t.bottom,innerHeight-1)-r,o=/* @__PURE__ */ new Set;for(let t=0;t<9;t++){let s=document.elementsFromPoint(n+t%3*i/2,r+a*(t/3|0)/2),c=s.findIndex(t=>e.contains(t));for(let t of s.slice(0,Math.max(c,0)))if(!t.closest(`[data-eclosion]`)){for(;!/fixed|sticky/.test(getComputedStyle(t).position)&&t.parentElement;)t=t.parentElement;t.parentElement&&!t.contains(e)&&o.add(t)}}return[...o]}const S=(e,t,n,r)=>`${e}px ${t}px,${n}px ${t}px,${n}px ${r}px,${e}px ${r}px,${e}px ${t}px,-1000000px -1000000px`;function te(e,t){if(!e)return;let{left:n,top:r}=e.getBoundingClientRect(),i=t.map(e=>{let t=e.getBoundingClientRect();return S(t.left-n,t.top-r,t.right-n,t.bottom-r)});e.style.clipPath=t.length?`polygon(evenodd,${[S(-1e6,-1e6,b,b),...i]})`:``}const C={duration:.32,bounce:0,speed:1,reduced:null};function w(){return C.reduced===null?typeof window>`u`||!window.matchMedia?!1:window.matchMedia(`(prefers-reduced-motion: reduce)`).matches:C.reduced}const T=[`x`,`y`,`w`,`h`,`r`];function E(e){let t=e.getBoundingClientRect();return{x:t.left+scrollX,y:t.top+scrollY,w:t.width,h:t.height}}function ne(e,t){let[n=``,r=n]=e.trim().split(/\s+/),i=(e,t)=>{let n=Number.parseFloat(e)||0;return e.endsWith(`%`)?n/100*t:n};return Math.min(i(n,t.w),i(r,t.h))}function D(e,t){let n=ne(getComputedStyle(e).borderTopLeftRadius,t);return Math.min(n,t.w/2,t.h/2)}function O(e){let t=E(e);return{...t,r:D(e,t)}}function re(e,t){let n=Math.max(t.w,1),r=Math.max(t.h,1),i=Math.max(0,Math.min(t.r,n/2,r/2)),a=n/(e.w||1),o=r/(e.h||1);return{tx:t.x-e.x,ty:t.y-e.y,sx:a,sy:o,rx:i/a,ry:i/o}}function ie(e,t){let n=e;return()=>{--n===0&&t()}}function ae({x:e,y:t,w:n,h:r,r:i}){return{x:e+n*.05,y:t+r*.05,w:n*.9,h:r*.9,r:i}}var oe=class{phase=`closed`;options;flying=[];constructor(e){this.options=e}open(){if(this.phase===`opening`||this.phase===`open`)return;let{morph:e,source:t,commit:n,initialFocus:r,layout:i,flights:a}=this.options,o=e();if(!o)return;let s=this.phase===`closed`;s&&(this.flying=a?.()??[]);let c=t!==void 0,l=c&&s?t():null,u=l?O(l):o.now();o.release(),(!c||s)&&n(!0),s&&this.listen(),i?.();let d=o.measure();this.set(`opening`);let f=ie(1+this.flying.length,()=>this.set(`open`));for(let e of this.flying)e.fly(!0,f);o.go(u,d,f),this.options.onLaunch?.(),r?.()?.focus({preventScroll:!0})}close(){if(this.phase===`closing`||this.phase===`closed`)return;let{morph:e,source:t,commit:n}=this.options,r=e();if(!r)return;if(this.set(`closing`),t){let e=ie(1+this.flying.length,()=>this.land());for(let t of this.flying)t.fly(!1,e);let n=t();n?(r.to(O(n),e),this.options.onLaunch?.()):r.options.mode===`surface`?r.to(ae(r.now()),e):(r.destroy(),this.land());return}let i=r.now();r.release(),n(!1),this.restoreFocus(),r.go(i,r.measure(),()=>this.settleClosed())}settle(){if(this.phase===`closed`){this.flying=this.options.flights?.()??[];for(let e of this.flying)e.settle();this.listen(),this.set(`open`)}}reset(){this.destroy(),this.phase!==`closed`&&this.set(`closed`)}destroy(){this.unlisten(),this.dropFlights()}dropFlights(){for(let e of this.flying)e.destroy();this.flying=[]}land(){this.options.commit(!1),this.dropFlights(),this.restoreFocus(),this.settleClosed()}settleClosed(){this.unlisten(),this.set(`closed`)}set(e){this.phase=e,this.options.onPhase?.(e)}restoreFocus(){let e=document.activeElement;(!e||e===document.body||this.options.surface()?.contains(e))&&this.options.trigger()?.focus({preventScroll:!0})}onKeyDown=e=>{e.key===`Escape`&&this.close()};onPointerDown=e=>{let t=e.target;this.options.surface()?.contains(t)||this.options.trigger()?.contains(t)||this.close()};listen(){this.options.dismiss!==!1&&(document.addEventListener(`keydown`,this.onKeyDown),document.addEventListener(`pointerdown`,this.onPointerDown))}unlisten(){document.removeEventListener(`keydown`,this.onKeyDown),document.removeEventListener(`pointerdown`,this.onPointerDown)}};const k=/* @__PURE__ */ new Set;let se=0,A=0;function j(e){let t=Math.max(0,Math.min((e-A)/1e3,.03333333333333333))*C.speed;A=e;for(let e of[...k])e.step(t);se=k.size?requestAnimationFrame(j):0}function M(e){k.add(e),se||=(A=performance.now(),requestAnimationFrame(j))}function ce(e){k.delete(e)}function le({duration:e,bounce:t}){return{k:(2*Math.PI/e)**2,c:4*Math.PI*(1-t)/e}}function N(e,{k:t,c:n},r){if(r<=0)return;let i=Math.ceil(r*600),a=r/i;for(let r=0;r<i;r++)e.v+=(-t*(e.x-e.to)-n*e.v)*a,e.x+=e.v*a}function ue(e){return Math.abs(e.x-e.to)<.1&&Math.abs(e.v)<4}const de=[`display`,`gap`,`gridTemplateColumns`,`gridTemplateRows`,`alignItems`,`justifyItems`,`alignContent`,`justifyContent`,`flexDirection`,`flexWrap`],fe=[`boxSizing`,`paddingTop`,`paddingRight`,`paddingBottom`,`paddingLeft`,`minWidth`,`minHeight`,`maxWidth`,`maxHeight`,`overflow`,`contain`,`transform`,`width`,`height`,`marginRight`,`marginBottom`,`borderRadius`,`opacity`],P=e=>Number.parseFloat(e)||0,pe=e=>Math.max(0,Math.min(e,1));var me=class{el;options;running=!1;springs=null;layout={x:0,y:0,w:0,h:0};done=null;hold=!1;atRest=null;fader=null;still=!1;whole=!1;rest=null;surfaceStyles=[];innerCss=``;scrollTop=0;frozen=!1;constructor(e,t={}){this.el=e,this.options=t}current(){let e=this.springs;return e?{x:e.x.x,y:e.y.x,w:e.w.x,h:e.h.x,r:e.r.x}:O(this.el)}now(){return this.running||this.hold?this.current():O(this.el)}get held(){return this.hold}get progress(){return this.fader?.x??100}measure(){return this.layout=E(this.el),this.options.mode===`surface`&&this.readRest(),this.atRest={...this.layout,r:D(this.el,this.layout)},this.atRest}release(){if(this.hold=!1,this.options.mode===`surface`){this.unfreeze();return}let e=this.el.style;e.transform=``,e.transformOrigin=``,this.options.mode===`size`&&(e.width=``,e.height=``),this.options.radius!==!1&&(e.borderRadius=``);let t=this.options.counter?.style;t&&(t.transform=``,t.transformOrigin=``)}go(e,t,n=null){this.start(e,t,100,n)}start(e,t,n,r){this.hold=!1;let i=this.options.mode===`surface`;if(i&&w())e=t;else if(w()){this.destroy(),this.el.animate([{opacity:.2},{opacity:1}],{duration:200,easing:`ease-out`}),r?.();return}if(this.done=r,i){this.freeze();let r=this.fader;this.running&&r?r.to=n:(this.fader={x:100-n,v:0,to:n},this.whole=!n,this.still=Math.hypot(t.x-e.x,t.y-e.y,t.w-e.w,t.h-e.h)<(e.w+e.h)*.2)}if(this.running&&this.springs&&this.options.handoff!==!1)for(let e of T)this.springs[e].to=t[e];else{let n={};for(let r of T)n[r]={x:e[r],v:0,to:t[r]};this.springs=n}this.running=!0,M(this),this.apply()}to(e,t=null){let n=this.now();this.release(),this.measure();let r=this.options.mode===`surface`&&w();this.start(n,r?n:e,0,t),this.hold=this.running}retarget(e){let t=this.springs;if(!this.running||!t)return;let n=this.hold;this.release();let r=this.measure();this.hold=n;let i=e??r;for(let e of T)t[e].to=i[e];this.freeze(),this.apply()}drag(e){this.options.mode===`surface`&&!this.hold&&(this.release(),this.measure(),this.freeze()),this.stop(),this.hold=!0,this.done=null;let t={};for(let n of T)t[n]={x:e[n],v:0,to:e[n]};this.springs=t,this.fader={x:100,v:0,to:100},this.apply()}fling(e){let t=this.springs,n=this.atRest;if(t&&n){for(let r of T)t[r].to=n[r],t[r].v=e[r]??0;this.hold=!1,this.running=!0,M(this)}}step(e){let t=this.springs;if(!t)return;let n=le(C);for(let r of T)N(t[r],n,e);let r=this.fader;r&&N(r,n,e),T.every(e=>ue(t[e]))&&(!r||ue(r))?this.finish():this.apply()}stop(){ce(this),this.running=!1}finish(){this.stop(),this.hold||this.release();let e=this.done;this.done=null,e?.()}destroy(){this.done=null,this.stop(),this.release()}apply(){let{mode:e}=this.options;e===`surface`?this.applySurface():e===`size`?this.applySize():this.applyTransform(),this.options.onFrame?.(this)}readRest(){let e=getComputedStyle(this.el),t=P(e.paddingLeft),n=P(e.paddingTop);this.rest={padLeft:t,padTop:n,contentW:this.layout.w-t-P(e.paddingRight)-P(e.borderLeftWidth)-P(e.borderRightWidth),contentH:this.layout.h-n-P(e.paddingBottom)-P(e.borderTopWidth)-P(e.borderBottomWidth),marginRight:P(e.marginRight),marginBottom:P(e.marginBottom),layout:de.map(t=>e[t])}}freeze(){let e=this.rest;if(this.frozen||!e)return;this.frozen=!0;let{el:t,options:n}=this;this.scrollTop=t.scrollTop,this.surfaceStyles=fe.map(e=>t.style[e]),Object.assign(t.style,{boxSizing:`border-box`,paddingTop:`0`,paddingRight:`0`,paddingBottom:`0`,paddingLeft:`0`,minWidth:`0`,minHeight:`0`,maxWidth:`none`,maxHeight:`none`,overflow:`hidden`,contain:`layout paint`}),t.scrollTop=0;let r=n.inner;if(!r)return;this.innerCss=r.style.cssText;let i=r.style;de.forEach((t,n)=>{i[t]=e.layout[n]}),Object.assign(i,{position:`absolute`,left:`${e.padLeft}px`,top:`${e.padTop-this.scrollTop}px`,width:`${e.contentW}px`,height:`${e.contentH}px`,willChange:`opacity`})}unfreeze(){if(!this.frozen)return;this.frozen=!1;let e=this.el.style;fe.forEach((t,n)=>{e[t]=this.surfaceStyles[n]});let t=this.options.inner;t&&(t.style.cssText=this.innerCss),this.scrollTop&&(this.el.scrollTop=this.scrollTop)}applySurface(){let e=this.el.style,{x:t,y:n,w:r,h:i,r:a}=this.current(),o=Math.max(r,1),s=Math.max(i,1),{layout:c,rest:l}=this;e.transform=`translate(${t-c.x}px, ${n-c.y}px)`,e.width=`${o}px`,e.height=`${s}px`,e.marginRight=`${(l?.marginRight??0)+c.w-o}px`,e.marginBottom=`${(l?.marginBottom??0)+c.h-s}px`,e.borderRadius=`${Math.max(0,Math.min(a,o/2,s/2))}px`;let u=this.options.inner,d=this.options.align?.();if(d&&u&&(u.style.transform=`translate(${d.x*(o-c.w)}px, ${d.y*(s-c.h)}px)`),this.options.fade){let t=this.progress;this.whole||=t>=25,e.opacity=`${pe(this.still?(t-5)/60:this.whole?(t-1)/5:t/25)}`,u&&(u.style.opacity=`${pe((this.progress-15)/35)}`)}}applySize(){let e=this.el.style,{w:t,h:n,r}=this.current(),i=Math.max(t,1),a=Math.max(n,1);e.width=`${i}px`,e.height=`${a}px`,this.options.radius!==!1&&(e.borderRadius=`${Math.max(0,Math.min(r,i/2,a/2))}px`)}applyTransform(){let e=this.el.style,{tx:t,ty:n,sx:r,sy:i,rx:a,ry:o}=re(this.layout,this.current());e.transformOrigin=`0 0`,e.transform=`translate(${t}px, ${n}px) scale(${r}, ${i})`,this.options.radius!==!1&&(e.borderRadius=`${a}px / ${o}px`);let s=this.options.counter?.style;s&&(s.transformOrigin=`0 0`,s.transform=`scale(${1/r}, ${1/i})`)}};const he=[`background`,`borderRadius`,`boxShadow`,`objectFit`];function F(e,t){e&&(e.style.visibility=t?`hidden`:``)}var ge=class{source;dest;layer;clone=null;morph=null;constructor(e,t,n){this.source=e,this.dest=t,this.layer=n}settle(){F(this.source(),!0)}fly(e,t){let n=this.source(),r=this.dest();if(F(n,!0),w()||!r){t();return}let i=this.morph??this.launch(r);if(F(r,!0),!i)F(r,!1),t();else if(e){let e=i.running?i.now():O(n||r);i.release(),i.measure(),i.go(e,O(r),()=>{F(r,!1),this.land(),t()})}else n?.isConnected?i.to(O(n),t):(i.options.fade=!0,i.to(i.now(),t))}destroy(){this.land(),F(this.source(),!1),F(this.dest(),!1)}land(){this.morph?.destroy(),this.clone?.remove(),this.morph=null,this.clone=null}launch(e){let t=this.layer();if(!t)return null;let n=e.cloneNode(!0);n.removeAttribute(`id`);for(let e of n.querySelectorAll(`[id]`))e.removeAttribute(`id`);let r=getComputedStyle(e),i=E(e),a=E(t);for(let e of he)n.style[e]=r[e];return Object.assign(n.style,{position:`absolute`,left:`${i.x-a.x}px`,top:`${i.y-a.y}px`,margin:`0`,width:`${i.w}px`,height:`${i.h}px`,visibility:`visible`}),t.append(n),this.clone=n,this.morph=new me(n,{mode:`surface`}),this.morph}};function _e(e){return[...e.querySelectorAll(`a[href],button:not([disabled]),input:not([disabled]):not([type="hidden"]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"]),[contenteditable]:not([contenteditable="false"])`)].filter(e=>!e.closest(`[inert]`)&&e.checkVisibility?.({visibilityProperty:!0})!==!1)}function ve(e,t){let n=_e(t),r=n[0]??t,i=n[n.length-1]??t,a=document.activeElement;return t.contains(a)?e.shiftKey?a===r||a===t?i:null:a===i?r:null:r}const I=/* @__PURE__ */ new Map;function ye(e){let t=[];for(let n=e;n&&n!==document.body;n=n.parentElement)for(let e of n.parentElement?.children??[]){if(e===n)continue;let r=I.get(e);(r||!e.hasAttribute(`inert`))&&(e.setAttribute(`inert`,``),I.set(e,(r??0)+1),t.push(e))}return()=>{for(let e of t){let t=(I.get(e)??1)-1;t?I.set(e,t):(I.delete(e),e.removeAttribute(`inert`))}}}const L=[];function be(e,t){return!!(e.surface()?.contains(t)||e.trigger()?.contains(t))}function xe(e){return L[L.length-1]===e}function Se(e){if(e.defaultPrevented)return;let t=L[L.length-1];e.key===`Escape`?t?.dismiss():e.key===`Tab`&&t?.tab?.(e)}function R(e){for(let t=L.length-1;t>=0;t--)if(be(L[t],e)){for(let e of L.slice(t+1).reverse())e.dismiss();return}for(let e of[...L].reverse())if(e.dismiss(),e.modal)return}let z=!1;function Ce(e){z=e.pointerType===`touch`,z||R(e.target)}function we(e){z&&R(e.target),z=!1}function B(e){document[e](`keydown`,Se),document[e](`pointerdown`,Ce),document[e](`click`,we)}function Te(e){return L.length||B(`addEventListener`),L.push(e),()=>{let t=L.indexOf(e);t<0||(L.splice(t,1),L.length||B(`removeEventListener`))}}function V(e,t){for(let n=e;n;n=n.parentElement){if(n.scrollHeight>n.clientHeight){let{overflowY:e}=getComputedStyle(n);if(e===`auto`||e===`scroll`)return n}if(n===t)break}return null}const H=[];let U=0,W=null;function G(e){U=e.touches[0].clientY}function Ee(e){let t=e.touches[0].clientY,n=t-U;if(U=t,!e.cancelable||e.touches.length>1)return;let r=e.target;if(r.closest(`input[type=range]`))return;let i=H[H.length-1]?.(),a=i?.contains(r)?V(r,i):null;if(a){let e=a.scrollTop<=0,t=a.scrollTop+a.clientHeight>=a.scrollHeight-1;if(!(n>0&&e)&&!(n<0&&t))return}e.preventDefault()}function De(){let e=document.documentElement,t=e.style,{overflow:n,overscrollBehavior:r,scrollbarGutter:i}=t;return innerWidth>e.clientWidth&&(t.scrollbarGutter=`stable`),t.overflow=`hidden`,t.overscrollBehavior=`none`,document.addEventListener(`touchstart`,G,{passive:!0}),document.addEventListener(`touchmove`,Ee,{passive:!1}),()=>{Object.assign(t,{overflow:n,overscrollBehavior:r,scrollbarGutter:i}),document.removeEventListener(`touchstart`,G),document.removeEventListener(`touchmove`,Ee)}}function Oe(e){H.length||(W=De()),H.push(e);let t=!1;return()=>{t||(t=!0,H.splice(H.indexOf(e),1),H.length||(W?.(),W=null))}}function ke(e,t,n){return Math.hypot(e,t)<6?`wait`:Math.abs(e)>t?`abort`:n===null||n<=0?`claim`:`abort`}function Ae(e){let t=e[e.length-1];if(!t)return 0;let n=e.find(e=>t.t-e.t<=100)??e[0],r=t.t-n.t;return r>0?(t.y-n.y)/r*1e3:0}function je(e,t,n){return Math.max(e,e+t*.2)>Math.min(n*.3,120)}function Me(e,t){let n=0,r=0,i=null,a=`idle`,o=null,s=null,c=0,l=[],u=o=>{a=`idle`;let s=o.target;o.touches.length===1&&t.enabled()&&(s.closest(`input[type=range],[data-eclosion-no-swipe]`)||(n=o.touches[0].clientX,r=o.touches[0].clientY,i=V(s,e),a=`judging`))},d=e=>{if(a===`idle`)return;let{clientX:u,clientY:d}=e.touches[0];if(a===`judging`){let f=ke(u-n,d-r,i?i.scrollTop:null);if(f===`wait`)return;if(o=t.morph(),f===`abort`||!e.cancelable||!o){a=`idle`;return}a=`dragging`,s=o.now(),c=d,l=[]}e.preventDefault();let f=d-c;l.push({t:e.timeStamp,y:d}),s&&o?.drag({...s,y:s.y+(f<0?f/4:f)})},f=e=>{if(a!==`dragging`||!o||!s){a=`idle`;return}a=`idle`;let n=l[l.length-1]?.y??c,r=e?0:Ae(l);o.fling({y:r}),!e&&je(n-c,r,s.h)&&t.dismiss()},p=()=>f(!1),m=()=>f(!0),h={passive:!0};return e.addEventListener(`touchstart`,u,h),e.addEventListener(`touchmove`,d,{passive:!1}),e.addEventListener(`touchend`,p,h),e.addEventListener(`touchcancel`,m,h),()=>{e.removeEventListener(`touchstart`,u),e.removeEventListener(`touchmove`,d),e.removeEventListener(`touchend`,p),e.removeEventListener(`touchcancel`,m)}}const K=typeof document>`u`?o:l,Ne=()=>()=>{};function Pe(){return f(Ne,()=>!0,()=>!1)}const Fe=t(null),Ie=t(null),Le=Fe.Provider,Re=Ie.Provider,q=t(!1);function J(){let e=a(Fe);if(!e)throw Error(`eclosion: parts must be inside Eclosion.Root`);return e}function Y({modal:e,placement:t}){return e??t===`centered`}function ze({origin:e,placement:t}){return g(t===`centered`?``:e)}function X(e,t){let{positioner:n,surface:r,trigger:i}=e;if(t.placement===`centered`||!n||!r||!i?.isConnected)return;n.style.transform=``,n.style.position=`absolute`;let a=E(n),{x:o,y:s}=ee(E(i),E(r),v(),ze(t));n.style.transform=`translate(${o-a.x}px, ${s-a.y}px)`}function Z(e,t){let n=e.morph?.atRest,r=t.filter(e=>{let{x:t,y:r,w:i,h:a}=E(e);return!n||t>=n.x+n.w||n.x>=t+i||r>=n.y+n.h||n.y>=r+a});te(e.positioner,r),te(e.flightLayer,r)}function Be({surface:e,initialFocus:t}){return e?t?.current?t.current:e.contains(document.activeElement)?null:e.querySelector(`[autofocus]`)??e:null}function Ve(){let e=document.createElement(`div`);return e.setAttribute(`data-eclosion`,``),e.style.cssText=`position:absolute;top:0;left:0;z-index:var(--eclosion-z,9999)`,e}function He(e){let[t,n]=d(!!e.defaultOpen),r=e.open??t,[i,o]=d(`closed`),l=r||i!==`closed`,f=Pe(),p=a(Ie),m=s(),h=u(e);h.current=e;let g=u({trigger:null,surface:null,inner:null,positioner:null,overlay:null,flightLayer:null,morph:null,layer:null,initialFocus:void 0,bars:[]}).current,_=u(/* @__PURE__ */ new Map).current,ee=u(e=>{h.current.open===void 0&&n(e),h.current.onOpenChange?.(e)}),v=u(null);v.current??=new oe({morph:()=>g.morph,commit:()=>{},dismiss:!1,layout:()=>X(g,h.current),flights:()=>{let e=[];for(let t of _.values())t.source&&t.dest&&e.push(new ge(()=>t.source,()=>t.dest,()=>g.flightLayer));return e},trigger:()=>g.trigger,surface:()=>g.surface,source:()=>g.trigger?.isConnected?g.trigger:null,initialFocus:()=>Be(g),onLaunch:()=>Z(g,g.bars),onPhase:e=>{o(e),g.surface?.toggleAttribute(`inert`,e===`closing`),(e===`open`||e===`closed`)&&Z(g,[]),e===`open`&&g.overlay&&(g.overlay.style.opacity=``),e===`closed`&&g.trigger&&(g.trigger.style.opacity=``)}});let y=u(null),b=l&&f;b&&(y.current??=Ve());let x=y.current;c(()=>{if(b&&x)return(e.container??p??document.body).append(x),()=>x.remove()},[b,x,e.container,p]);let S=u(r);return{open:r,present:b,phase:i,request:ee.current,controller:v.current,refs:g,portal:x,contentId:m,titleId:`${m}t`,descriptionId:`${m}d`,modal:Y(e),centered:e.placement===`centered`,swipeable:e.swipe!==!1,shared:_,live:h,settleNext:S}}function Ue(e){let{open:t,controller:n,refs:r,settleNext:i,portal:a,request:o,live:s,titleId:c,descriptionId:l,swipeable:u}=e;K(()=>{let e=r.surface;if(e&&u)return Me(e,{morph:()=>r.morph,enabled:()=>n.phase===`open`&&!!r.layer&&xe(r.layer),dismiss:()=>o(!1)})},[r,n,o,u]),K(()=>{let{surface:e,inner:t}=r;if(!e)return;let i=e=>{r.trigger&&(r.trigger.style.opacity=e.el.style.opacity===`1`?`0`:``)},a=new me(e,{mode:`surface`,inner:t,align:()=>ze(s.current),fade:!0,onFrame:e=>{i(e),r.overlay&&(r.overlay.style.opacity=`${e.progress/100}`)}});return r.morph=a,()=>{a.destroy(),r.morph=null,n.reset()}},[n,r,s]),K(()=>{let e=()=>{let e=r.morph,{trigger:t}=r;e&&(n.phase===`closing`?t?.isConnected&&e.retarget(O(t)):e.running?(e.release(),X(r,s.current),e.retarget()):e.held||X(r,s.current),n.phase.endsWith(`ing`)&&Z(r,r.bars))},t=y(()=>r.trigger,e),i=!1,a=new ResizeObserver(()=>{i&&e(),i=!0});for(let e of r.inner?.children??[])a.observe(e);return()=>{t(),a.disconnect()}},[n,r,s]),K(()=>{let{trigger:e}=r;if(r.bars=s.current.placement===`centered`&&e?.isConnected?x(e):[],!t){i.current=!1;let e=document.activeElement;(!e||e===document.body||r.surface?.contains(e))&&r.trigger?.focus({preventScroll:!0}),n.close();return}let u=r.surface;if(!u||!a)return;for(let[e,t]of[[`aria-labelledby`,c],[`aria-describedby`,l]])document.getElementById(t)&&u.setAttribute(e,t);let d=Y(s.current),f={surface:()=>r.surface,trigger:()=>r.trigger,modal:d,dismiss:()=>o(!1),tab:e=>{let t=ve(e,u);t&&(e.preventDefault(),d?t.focus():o(!1))}};r.layer=f;let p=Te(f),m=d?[Oe(()=>r.surface),ye(a)]:[];return i.current?(X(r,s.current),n.settle(),r.trigger&&(r.trigger.style.opacity=`0`),Be(r)?.focus({preventScroll:!0})):n.open(),()=>{p();for(let e of m)e()}},[t,n,r,i,a,o,s,c,l])}function We(e,t){typeof e==`function`?e(t):e&&(e.current=t)}function Q(...e){return t=>{for(let n of e)We(n,t)}}function Ge(e,t){let n={...e,...t};for(let r of Object.keys(e)){let i=e[r],a=t[r];/^on[A-Z]/.test(r)&&typeof a==`function`&&(n[r]=(...e)=>{a(...e),i(...e)})}return n.style={...e.style,...t.style},e.className&&t.className&&(n.className=`${e.className} ${t.className}`),n}function $(t,r,a,o){let s=a.children;if(r&&i(s)){let t=s.props.ref??s.ref,{children:n,...r}=a;return e(s,{...Ge(r,s.props),ref:Q(o,t)})}return n(t,{...a,ref:o})}function Ke({children:e,...t}){return/* @__PURE__ */ m(Le,{value:He(t),children:/* @__PURE__ */ m(q.Provider,{value:!1,children:e})})}const qe=r(function({asChild:e,onClick:t,...n},r){let{open:i,phase:a,request:o,refs:s,contentId:c,present:l}=J(),u=e=>{t?.(e),e.defaultPrevented||o(!i)};return $(`button`,e,{type:e?void 0:`button`,"aria-haspopup":`dialog`,"aria-expanded":i,"aria-controls":l?c:void 0,"data-state":a,...n,onClick:u},Q(r,e=>{e&&(s.trigger=e,a===`open`&&(e.style.opacity=`0`))}))}),Je=r(function({asChild:e,onClick:t,children:n,...r},i){let{phase:a,request:o}=J(),s=e=>{t?.(e),e.defaultPrevented||o(!1)};return $(`button`,e,{type:e?void 0:`button`,"aria-label":n===void 0?`Close`:void 0,"data-state":a,...r,children:n??`×`,onClick:s},i)}),Ye={position:`fixed`,pointerEvents:`none`,zIndex:1},Xe={...Ye,inset:0,display:`grid`,placeItems:`center`},Ze={position:`absolute`,top:0,left:0,pointerEvents:`none`,zIndex:2},Qe={...Ye,top:0,left:0,width:`max-content`};function $e(){return Ue(J()),null}const et={Root:Ke,Trigger:qe,Content:r(function({children:e,style:t,initialFocus:n,...r},i){let{present:a,portal:o,phase:s,refs:c,contentId:l,modal:u,centered:d}=J();return c.initialFocus=n,!a||!o?null:p(/* @__PURE__ */ h(Re,{value:o,children:[/* @__PURE__ */ m(q.Provider,{value:!0,children:/* @__PURE__ */ m(`div`,{ref:e=>{e&&(c.positioner=e)},style:d?Xe:Qe,children:/* @__PURE__ */ m(`div`,{id:l,role:`dialog`,"aria-modal":u||void 0,tabIndex:-1,"data-state":s,...r,ref:Q(i,e=>{e&&(c.surface=e)}),style:{outline:`none`,pointerEvents:`auto`,...t},children:/* @__PURE__ */ m(`div`,{ref:e=>{e&&(c.inner=e)},style:{display:`contents`},children:e})})})}),/* @__PURE__ */ m(`div`,{ref:e=>{e&&(c.flightLayer=e,e.setAttribute(`inert`,``))},"aria-hidden":!0,style:Ze}),/* @__PURE__ */ m($e,{})]}),o)}),Close:Je,Overlay:r(function({style:e,...t},n){let{present:r,portal:i,phase:a,refs:o}=J();return!r||!i?null:p(/* @__PURE__ */ m(`div`,{"aria-hidden":!0,"data-state":a,...t,ref:Q(n,e=>{e&&(o.overlay=e)}),style:{position:`fixed`,inset:0,...e}}),i)}),Title:r(function(e,t){return/* @__PURE__ */ m(`h2`,{id:J().titleId,...e,ref:t})}),Description:r(function(e,t){return/* @__PURE__ */ m(`p`,{id:J().descriptionId,...e,ref:t})}),Shared:r(function({id:e,asChild:t,...n},r){let{shared:i,controller:o}=J(),s=a(q),c=u(null);return K(()=>{let t=c.current;if(!t)return;let n=s?`dest`:`source`,r=i.get(e)??{source:null,dest:null};return i.set(e,r),r[n]=t,!s&&o.phase===`open`&&(t.style.visibility=`hidden`),()=>{r[n]===t&&(r[n]=null)}},[i,o,e,s]),$(`div`,t,n,Q(r,c))})};export{et as Eclosion};
|
package/package.json
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "eclosion",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A dialog or popover that grows out of its trigger.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"react",
|
|
7
|
+
"dialog",
|
|
8
|
+
"popover",
|
|
9
|
+
"modal",
|
|
10
|
+
"animation",
|
|
11
|
+
"morph",
|
|
12
|
+
"spring",
|
|
13
|
+
"shared-element-transition"
|
|
14
|
+
],
|
|
15
|
+
"homepage": "https://github.com/jordankmars/eclose#readme",
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/jordankmars/eclose/issues"
|
|
18
|
+
},
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/jordankmars/eclose.git"
|
|
22
|
+
},
|
|
23
|
+
"author": "Jordan Mars",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"type": "module",
|
|
26
|
+
"sideEffects": false,
|
|
27
|
+
"files": [
|
|
28
|
+
"dist"
|
|
29
|
+
],
|
|
30
|
+
"exports": {
|
|
31
|
+
"./react": {
|
|
32
|
+
"types": "./dist/react/index.d.mts",
|
|
33
|
+
"import": "./dist/react/index.mjs"
|
|
34
|
+
},
|
|
35
|
+
"./package.json": "./package.json"
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsdown",
|
|
39
|
+
"dev": "tsdown --watch",
|
|
40
|
+
"typecheck": "tsc --noEmit",
|
|
41
|
+
"prepack": "pnpm build && pnpm size",
|
|
42
|
+
"lint": "biome check .",
|
|
43
|
+
"format": "biome check --write .",
|
|
44
|
+
"test": "vitest run",
|
|
45
|
+
"play": "vite playground",
|
|
46
|
+
"site:dev": "pnpm build && pnpm --filter site dev",
|
|
47
|
+
"site:build": "pnpm build && pnpm --filter site build",
|
|
48
|
+
"size": "node scripts/size.mjs"
|
|
49
|
+
},
|
|
50
|
+
"peerDependencies": {
|
|
51
|
+
"react": ">=18",
|
|
52
|
+
"react-dom": ">=18"
|
|
53
|
+
},
|
|
54
|
+
"peerDependenciesMeta": {
|
|
55
|
+
"react": {
|
|
56
|
+
"optional": true
|
|
57
|
+
},
|
|
58
|
+
"react-dom": {
|
|
59
|
+
"optional": true
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"packageManager": "pnpm@10.15.1",
|
|
63
|
+
"engines": {
|
|
64
|
+
"node": ">=20"
|
|
65
|
+
},
|
|
66
|
+
"devDependencies": {
|
|
67
|
+
"@arethetypeswrong/core": "^0.18.5",
|
|
68
|
+
"@biomejs/biome": "2.6.6",
|
|
69
|
+
"@types/jsdom": "^30.0.0",
|
|
70
|
+
"@types/react": "^19.3.0",
|
|
71
|
+
"@types/react-dom": "^19.3.0",
|
|
72
|
+
"@vitejs/plugin-react": "^6.2.1",
|
|
73
|
+
"jsdom": "^31.0.0",
|
|
74
|
+
"publint": "^0.3.25",
|
|
75
|
+
"react": "^19.3.1",
|
|
76
|
+
"react-dom": "^19.3.1",
|
|
77
|
+
"tsdown": "^0.23.7",
|
|
78
|
+
"typescript": "^7.0.2",
|
|
79
|
+
"vite": "^8.3.6",
|
|
80
|
+
"vitest": "^5.1.0"
|
|
81
|
+
}
|
|
82
|
+
}
|