react-morpheus 0.1.3 → 0.1.5

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/README.md CHANGED
@@ -2,46 +2,151 @@
2
2
 
3
3
  A controlled React component for morphing one UI state into another.
4
4
 
5
- `Morpheus` does not manage its own open state. Keep the `expanded` boolean in
6
- your app state, render your trigger wherever it belongs, and pass the same
7
- source content to `collapsedContent` so Morpheus can measure and morph from it.
8
- Overlay clicks and Escape key presses call `onCloseIntent`; update your
9
- controlled state there. Use `afterClose` for work that should run after the
10
- closing animation completes.
5
+ React Morpheus exists for interfaces where a control should become the next
6
+ piece of UI instead of opening a detached popover. The component keeps the
7
+ source surface, destination surface, and overlay explicit. Your app still owns
8
+ state and content; Morpheus owns the measured transition between those two
9
+ surfaces.
10
+
11
+ ## Demo
12
+
13
+ <!-- react-morpheus-demo:start -->
14
+ https://github.com/user-attachments/assets/f90e7096-f587-4793-8e80-476cf844569d
15
+ <!-- react-morpheus-demo:end -->
16
+
17
+ ## Installation
18
+
19
+ ```sh
20
+ bun add react-morpheus
21
+ ```
22
+
23
+ ```sh
24
+ npm i react-morpheus
25
+ ```
26
+
27
+ ```sh
28
+ yarn add react-morpheus
29
+ ```
30
+
31
+ ## Usage
32
+
33
+ Import the component and stylesheet, keep the open state in your app, and pass
34
+ both surfaces to Morpheus.
11
35
 
12
36
  ```tsx
13
- import { Morpheus, MorphAnchor } from "react-morpheus";
37
+ import { useState } from "react";
38
+ import {
39
+ Morpheus,
40
+ MorphAnchor,
41
+ morphSpringPresets,
42
+ } from "react-morpheus";
14
43
  import "react-morpheus/style.css";
15
44
 
16
45
  function Example() {
17
46
  const [expanded, setExpanded] = useState(false);
18
47
  const source = (
19
48
  <button type="button" onClick={() => setExpanded(true)}>
20
- Open
49
+ Open menu
21
50
  </button>
22
51
  );
23
52
 
24
53
  return (
25
- <>
26
- {source}
27
- <Morpheus
28
- direction="bottom"
29
- anchor={MorphAnchor.TopMiddle}
30
- expanded={expanded}
31
- onCloseIntent={() => setExpanded(false)}
32
- afterClose={() => console.log("closed")}
33
- collapsedContent={source}
34
- expandedContent={<div>Expanded content</div>}
35
- />
36
- </>
54
+ <Morpheus
55
+ direction="bottom"
56
+ anchor={MorphAnchor.TopMiddle}
57
+ expanded={expanded}
58
+ onClose={() => setExpanded(false)}
59
+ overlayColor="#0f172a"
60
+ overlayOpacity={0.18}
61
+ overlayBlur={3}
62
+ overlayZIndex={1200}
63
+ spring={morphSpringPresets.smooth}
64
+ collapsedContent={source}
65
+ expandedContent={
66
+ <section>
67
+ <h2>San Francisco</h2>
68
+ <p>Context, actions, and details live here.</p>
69
+ <button type="button" onClick={() => setExpanded(false)}>
70
+ Close
71
+ </button>
72
+ </section>
73
+ }
74
+ />
37
75
  );
38
76
  }
39
77
  ```
40
78
 
41
- ## Scripts
79
+ `Morpheus` does not manage its own open state. Opening is the responsibility of
80
+ the source component's own click handler. Overlay clicks call `onClose`; update
81
+ your controlled state there. Use `beforeClose` and `afterClose` for work that
82
+ should run around the closing animation.
83
+
84
+ ## Props
85
+
86
+ | Prop | Type | Required | Notes |
87
+ | --- | --- | --- | --- |
88
+ | `direction` | `"top" \| "right" \| "bottom" \| "left"` | Required | Where the panel opens from. Also chooses the default anchor when `anchor` is omitted. |
89
+ | `anchor` | `MorphAnchor` | Optional | The edge or point that stays visually anchored. |
90
+ | `expanded` | `boolean` | Required | Controlled open state owned by your app. |
91
+ | `onClose` | `() => void` | Optional | Called when the overlay requests closing. Use it to update your controlled open state. |
92
+ | `beforeClose` | `() => void` | Optional | Called when the closing animation starts, after `expanded` has changed to `false`. Useful for close-intent side effects. |
93
+ | `afterClose` | `() => void` | Optional | Called after the closing animation completes. |
94
+ | `collapsedContent` | `ReactNode` | Required | The source surface Morpheus measures, renders, and uses as the opener. |
95
+ | `expandedContent` | `ReactNode` | Required | The destination surface Morpheus measures and animates into. |
96
+ | `className` | `string` | Optional | Classes applied to the root wrapper. Useful for block layout and responsive width constraints. |
97
+ | `overlayColor` | `string` | Optional | Backdrop color shown while expanded. |
98
+ | `overlayOpacity` | `number` | Optional | Backdrop opacity from `0` to `1`. |
99
+ | `overlayBlur` | `number` | Optional | Backdrop blur in pixels. |
100
+ | `overlayZIndex` | `number` | Optional | Stacking level for the expanded surface. Defaults to `1000`; the overlay renders one layer below it. |
101
+ | `spring` | `Transition` | Optional | Framer Motion transition. Pass your own transition or use `morphSpringPresets`. |
102
+
103
+ ## Pitfalls
104
+
105
+ ### Responsiveness
106
+
107
+ Let the collapsed trigger keep its natural size. Morpheus reads that box before
108
+ animating to the expanded surface.
109
+
110
+ Put responsive width rules on `className`, such as viewport-bound max widths, so
111
+ the animated shell has stable constraints on narrow screens.
112
+
113
+ Pick an anchor that matches the source location. Top anchors feel right for
114
+ menus opening below a trigger; bottom anchors feel right for surfaces opening
115
+ upward; middle anchors feel better for centered inspectors or command surfaces.
116
+
117
+ ### Parent Container Overflow
118
+
119
+ Do not place Morpheus inside a container that clips overflow, such as
120
+ `overflow: hidden`, `overflow: clip`, or scroll containers. The expanded surface
121
+ is positioned from the local source element and can extend outside its original
122
+ container while animating.
123
+
124
+ ### Stacking
125
+
126
+ `overlayZIndex` controls the expanded morph surface. The overlay renders one
127
+ layer below it so apps can move the whole morphing stack above their own chrome.
128
+ Without this prop, Morpheus uses surface `1000` and overlay `999`.
129
+
130
+ ## Development
131
+
132
+ `example.html` is a small local playground for trying Morpheus in a browser
133
+ without setting up an app shell. Use it to check the default interaction,
134
+ directions, anchors, and overlay behavior while changing the component.
135
+
136
+ ### Scripts
137
+
138
+ - `bun run build` builds declarations, bundled ESM output, and CSS.
139
+ - `bun run check` runs TypeScript without emitting files.
140
+ - `bun run publish:npm` builds and publishes to npm.
141
+ - `bun run release:patch` bumps the patch version, builds, tags, and publishes.
142
+ - `bun run release:minor` bumps the minor version, builds, tags, and publishes.
143
+ - `bun run release:major` bumps the major version, builds, tags, and publishes.
144
+
145
+ ## Credits
146
+
147
+ Inspired by Family Wallet and Benji Taylor's
148
+ [Family Values](https://benji.org/family-values) post.
149
+
150
+ ## License
42
151
 
43
- - `bun run build` builds declarations and bundled ESM output.
44
- - `bun run tag` creates an annotated git tag for the current package version.
45
- - `bun run tag:push` pushes tags to `origin`.
46
- - `bun run deploy:npm` builds and publishes to npm.
47
- - `bun run release:npm` builds, creates the version tag, and publishes to npm.
152
+ Released under the [MIT License](https://github.com/shivekkhurana/react-morpheus/blob/master/LICENSE).
package/dist/index.d.ts CHANGED
@@ -77,7 +77,8 @@ type MorphProps = {
77
77
  direction: MorphDirection;
78
78
  anchor?: MorphAnchor | undefined;
79
79
  expanded: boolean;
80
- onCloseIntent?: (() => void) | undefined;
80
+ onClose?: (() => void) | undefined;
81
+ beforeClose?: (() => void) | undefined;
81
82
  afterClose?: (() => void) | undefined;
82
83
  collapsedContent: ReactNode;
83
84
  expandedContent: ReactNode;
@@ -85,14 +86,16 @@ type MorphProps = {
85
86
  overlayColor?: string;
86
87
  overlayOpacity?: number;
87
88
  overlayBlur?: number;
89
+ overlayZIndex?: number;
88
90
  spring?: Transition;
89
91
  };
90
92
  type MorphOverlayProps = {
91
93
  expanded: boolean;
92
- onCloseIntent?: (() => void) | undefined;
94
+ onClose?: (() => void) | undefined;
93
95
  color: string;
94
96
  opacity: number;
95
97
  blur: number;
98
+ zIndex: number;
96
99
  };
97
100
  type MorphMeasurementNodesProps = {
98
101
  collapsedRef: RefObject<HTMLDivElement | null>;
@@ -106,6 +109,7 @@ type MorphShellProps = {
106
109
  animatedSize: PanelSize;
107
110
  visualStyle: PanelVisualStyle;
108
111
  overflowVisible: boolean;
112
+ zIndex: number;
109
113
  spring: Transition;
110
114
  onMorphComplete: () => void;
111
115
  onMorphStart: () => void;
@@ -113,6 +117,7 @@ type MorphShellProps = {
113
117
  };
114
118
  type MorphContentLayersProps = {
115
119
  expanded: boolean;
120
+ settledState: "collapsed" | "expanded" | null;
116
121
  collapsedContent: ReactNode;
117
122
  expandedContent: ReactNode;
118
123
  collapsedLayerSize: PanelSize;
@@ -128,11 +133,10 @@ type MorphContentLayersProps = {
128
133
  targetOpacityTransition: Transition;
129
134
  };
130
135
  type MorphLayerInteractivityProps = {
131
- "aria-hidden": boolean;
132
136
  inert?: boolean;
133
137
  };
134
138
 
135
- declare function Morpheus({ direction, anchor, expanded, onCloseIntent, afterClose, collapsedContent, expandedContent, className, overlayColor, overlayOpacity, overlayBlur, spring, }: MorphProps): react.JSX.Element;
139
+ declare function Morpheus({ direction, anchor, expanded, onClose, beforeClose, afterClose, collapsedContent, expandedContent, className, overlayColor, overlayOpacity, overlayBlur, overlayZIndex: zIndex, spring, }: MorphProps): react.JSX.Element;
136
140
 
137
141
  declare const defaultAnchorByDirection: Record<MorphDirection, MorphAnchor>;
138
142
  declare const morphSpringPresets: {
package/dist/index.js CHANGED
@@ -226,7 +226,7 @@ function invertPosition(position) {
226
226
  };
227
227
  }
228
228
  function getLayerInteractivityProps(interactive) {
229
- return interactive ? { "aria-hidden": false } : { "aria-hidden": true, inert: true };
229
+ return interactive ? {} : { inert: true };
230
230
  }
231
231
  function getMorphMotionState({
232
232
  expanded,
@@ -291,17 +291,18 @@ function getOverlayBackgroundColor(color, opacity) {
291
291
  }
292
292
  function MorphOverlay({
293
293
  expanded,
294
- onCloseIntent,
294
+ onClose,
295
295
  color,
296
296
  opacity,
297
- blur
297
+ blur,
298
+ zIndex
298
299
  }) {
299
- return /* @__PURE__ */ jsx(AnimatePresence, { children: expanded && onCloseIntent ? /* @__PURE__ */ jsx(
300
- motion.button,
300
+ const MotionOverlay = onClose ? motion.button : motion.div;
301
+ return /* @__PURE__ */ jsx(AnimatePresence, { children: expanded ? /* @__PURE__ */ jsx(
302
+ MotionOverlay,
301
303
  {
302
- type: "button",
303
- "aria-label": "Close morph",
304
- className: "fixed inset-0 z-40 cursor-default",
304
+ ...onClose ? { type: "button", "aria-label": "Close morph" } : { "aria-hidden": true },
305
+ className: "rmorph:fixed rmorph:inset-0 rmorph:cursor-default",
305
306
  initial: {
306
307
  opacity: 0
307
308
  },
@@ -315,16 +316,17 @@ function MorphOverlay({
315
316
  style: {
316
317
  backdropFilter: `blur(${blur}px)`,
317
318
  backgroundColor: getOverlayBackgroundColor(color, opacity),
318
- WebkitBackdropFilter: `blur(${blur}px)`
319
+ WebkitBackdropFilter: `blur(${blur}px)`,
320
+ zIndex: zIndex - 1
319
321
  },
320
- onClick: onCloseIntent
322
+ onClick: onClose
321
323
  }
322
324
  ) : null });
323
325
  }
324
326
 
325
327
  // src/component.tsx
326
328
  import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
327
- var liveSurfaceContentClassName = "absolute [&>*:first-child]:!border-transparent [&>*:first-child]:!bg-transparent [&>*:first-child]:!shadow-none";
329
+ var liveSurfaceContentClassName = "rmorph:absolute";
328
330
  function MorphMeasurementNodes({
329
331
  collapsedRef,
330
332
  expandedRef,
@@ -337,7 +339,7 @@ function MorphMeasurementNodes({
337
339
  {
338
340
  ref: collapsedRef,
339
341
  "aria-hidden": "true",
340
- className: "invisible absolute inset-x-0 top-0 pointer-events-none",
342
+ className: "rmorph:invisible rmorph:absolute rmorph:inset-x-0 rmorph:top-0 rmorph:pointer-events-none",
341
343
  children: collapsedContent
342
344
  }
343
345
  ),
@@ -346,7 +348,7 @@ function MorphMeasurementNodes({
346
348
  {
347
349
  ref: expandedRef,
348
350
  "aria-hidden": "true",
349
- className: "invisible absolute inset-x-0 top-0 pointer-events-none",
351
+ className: "rmorph:invisible rmorph:absolute rmorph:inset-x-0 rmorph:top-0 rmorph:pointer-events-none",
350
352
  children: expandedContent
351
353
  }
352
354
  )
@@ -358,6 +360,7 @@ function MorphShell({
358
360
  animatedSize,
359
361
  visualStyle,
360
362
  overflowVisible,
363
+ zIndex,
361
364
  spring,
362
365
  onMorphComplete,
363
366
  onMorphStart,
@@ -366,7 +369,7 @@ function MorphShell({
366
369
  return /* @__PURE__ */ jsx2(
367
370
  motion2.div,
368
371
  {
369
- className: `absolute shadow-xs ${expanded ? "z-50" : "z-0"}`,
372
+ className: "rmorph:absolute rmorph:shadow-xs",
370
373
  initial: false,
371
374
  animate: {
372
375
  width: animatedSize.width,
@@ -378,7 +381,8 @@ function MorphShell({
378
381
  onAnimationComplete: onMorphComplete,
379
382
  onAnimationStart: onMorphStart,
380
383
  style: {
381
- overflow: overflowVisible ? "visible" : "hidden"
384
+ overflow: overflowVisible ? "visible" : "hidden",
385
+ zIndex: expanded ? zIndex : 0
382
386
  },
383
387
  transition: spring,
384
388
  children
@@ -387,6 +391,7 @@ function MorphShell({
387
391
  }
388
392
  function MorphContentLayers({
389
393
  expanded,
394
+ settledState,
390
395
  collapsedContent,
391
396
  expandedContent,
392
397
  collapsedLayerSize,
@@ -419,6 +424,7 @@ function MorphContentLayers({
419
424
  opacity: sourceOpacityTransition
420
425
  },
421
426
  style: {
427
+ display: expanded && settledState === "expanded" ? "none" : void 0,
422
428
  width: collapsedLayerSize.width,
423
429
  height: collapsedLayerSize.height,
424
430
  pointerEvents: expanded ? "none" : "auto",
@@ -444,6 +450,7 @@ function MorphContentLayers({
444
450
  opacity: targetOpacityTransition
445
451
  },
446
452
  style: {
453
+ display: !expanded && settledState === "collapsed" ? "none" : void 0,
447
454
  width: expandedLayerSize.width,
448
455
  height: expandedLayerSize.height,
449
456
  pointerEvents: expanded ? "auto" : "none",
@@ -458,20 +465,26 @@ function Morpheus({
458
465
  direction,
459
466
  anchor,
460
467
  expanded,
461
- onCloseIntent,
468
+ onClose,
469
+ beforeClose,
462
470
  afterClose,
463
471
  collapsedContent,
464
472
  expandedContent,
465
- className = "relative inline-block align-top",
473
+ className = "rmorph:relative rmorph:inline-block rmorph:align-top",
466
474
  overlayColor = "#05070a",
467
475
  overlayOpacity = 0.54,
468
476
  overlayBlur = 0,
477
+ overlayZIndex: zIndex = 1e3,
469
478
  spring = defaultPanelSpring
470
479
  }) {
471
480
  const measurements = useMorphMeasurements();
472
481
  const [animationEnabled, setAnimationEnabled] = useState2(false);
473
482
  const [shellOverflowVisible, setShellOverflowVisible] = useState2(false);
483
+ const [settledState, setSettledState] = useState2(
484
+ expanded ? "expanded" : "collapsed"
485
+ );
474
486
  const hasOpenedRef = useRef2(expanded);
487
+ const beforeCloseCalledRef = useRef2(false);
475
488
  useEffect(() => {
476
489
  if (!measurements.ready) {
477
490
  return;
@@ -479,18 +492,6 @@ function Morpheus({
479
492
  const frame = requestAnimationFrame(() => setAnimationEnabled(true));
480
493
  return () => cancelAnimationFrame(frame);
481
494
  }, [measurements.ready]);
482
- useEffect(() => {
483
- if (!expanded || !onCloseIntent) {
484
- return;
485
- }
486
- const handleKeyDown = (event) => {
487
- if (event.key === "Escape" && !event.repeat) {
488
- onCloseIntent();
489
- }
490
- };
491
- document.addEventListener("keydown", handleKeyDown);
492
- return () => document.removeEventListener("keydown", handleKeyDown);
493
- }, [expanded, onCloseIntent]);
494
495
  const motionState = getMorphMotionState({
495
496
  expanded,
496
497
  direction,
@@ -507,10 +508,11 @@ function Morpheus({
507
508
  MorphOverlay,
508
509
  {
509
510
  expanded,
510
- onCloseIntent,
511
+ onClose,
511
512
  color: overlayColor,
512
513
  opacity: overlayOpacity,
513
- blur: overlayBlur
514
+ blur: overlayBlur,
515
+ zIndex
514
516
  }
515
517
  ),
516
518
  /* @__PURE__ */ jsxs("div", { className, "aria-live": "polite", children: [
@@ -523,7 +525,7 @@ function Morpheus({
523
525
  expandedContent
524
526
  }
525
527
  ),
526
- /* @__PURE__ */ jsx2("div", { className: "relative mx-auto block w-fit align-top", children: shouldRenderStaticSource ? /* @__PURE__ */ jsx2("div", { className: "inline-block align-top", children: collapsedContent }) : /* @__PURE__ */ jsxs(Fragment, { children: [
528
+ /* @__PURE__ */ jsx2("div", { className: "rmorph:relative rmorph:mx-auto rmorph:block rmorph:w-fit rmorph:align-top", children: shouldRenderStaticSource ? /* @__PURE__ */ jsx2("div", { className: "rmorph:inline-block rmorph:align-top", children: collapsedContent }) : /* @__PURE__ */ jsxs(Fragment, { children: [
527
529
  /* @__PURE__ */ jsx2(
528
530
  "div",
529
531
  {
@@ -543,23 +545,35 @@ function Morpheus({
543
545
  animatedSize: motionState.animatedSize,
544
546
  visualStyle: motionState.visualStyle,
545
547
  overflowVisible,
548
+ zIndex,
546
549
  spring: motionState.activeSpring,
547
550
  onMorphComplete: () => {
548
551
  if (expanded) {
549
552
  hasOpenedRef.current = true;
553
+ beforeCloseCalledRef.current = false;
554
+ setSettledState("expanded");
550
555
  setShellOverflowVisible(true);
551
556
  return;
552
557
  }
558
+ setSettledState("collapsed");
553
559
  if (hasOpenedRef.current) {
554
560
  hasOpenedRef.current = false;
555
561
  afterClose?.();
556
562
  }
557
563
  },
558
- onMorphStart: () => setShellOverflowVisible(false),
564
+ onMorphStart: () => {
565
+ if (!expanded && hasOpenedRef.current && !beforeCloseCalledRef.current) {
566
+ beforeCloseCalledRef.current = true;
567
+ beforeClose?.();
568
+ }
569
+ setShellOverflowVisible(false);
570
+ setSettledState(expanded ? "collapsed" : "expanded");
571
+ },
559
572
  children: /* @__PURE__ */ jsx2(
560
573
  MorphContentLayers,
561
574
  {
562
575
  expanded,
576
+ settledState,
563
577
  collapsedContent,
564
578
  expandedContent,
565
579
  collapsedLayerSize: motionState.collapsedLayerSize,
package/dist/style.css CHANGED
@@ -1,2 +1,2 @@
1
1
  /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
2
- @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}@layer theme{:root,:host{--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1)}}@layer utilities{.pointer-events-none{pointer-events:none}.invisible{visibility:hidden}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.inset-0{inset:0}.inset-x-0{inset-inline:0}.top-0{top:0}.z-0{z-index:0}.z-40{z-index:40}.z-50{z-index:50}.mx-auto{margin-inline:auto}.block{display:block}.hidden{display:none}.inline-block{display:inline-block}.w-fit{width:fit-content}.cursor-default{cursor:default}.align-top{vertical-align:top}.shadow-xs{--tw-shadow:0 1px 2px 0 var(--tw-shadow-color,#0000000d);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.blur{--tw-blur:blur(8px);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.\[\&\>\*\:first-child\]\:\!border-transparent>:first-child{border-color:#0000!important}.\[\&\>\*\:first-child\]\:\!bg-transparent>:first-child{background-color:#0000!important}.\[\&\>\*\:first-child\]\:\!shadow-none>:first-child{--tw-shadow:0 0 #0000!important;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)!important}}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}
2
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000}}}.rmorph\:pointer-events-none{pointer-events:none}.rmorph\:invisible{visibility:hidden}.rmorph\:absolute{position:absolute}.rmorph\:fixed{position:fixed}.rmorph\:relative{position:relative}.rmorph\:inset-0{inset:0}.rmorph\:inset-x-0{inset-inline:0}.rmorph\:top-0{top:0}.rmorph\:mx-auto{margin-inline:auto}.rmorph\:block{display:block}.rmorph\:inline-block{display:inline-block}.rmorph\:w-fit{width:fit-content}.rmorph\:cursor-default{cursor:default}.rmorph\:align-top{vertical-align:top}.rmorph\:shadow-xs{--tw-shadow:0 1px 2px 0 var(--tw-shadow-color,#0000000d);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-morpheus",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "A React component for morphing one surface into other.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -24,6 +24,7 @@
24
24
  "./package.json": "./package.json"
25
25
  },
26
26
  "scripts": {
27
+ "prepare": "bun run build",
27
28
  "build": "bun run build:js && bun run build:css",
28
29
  "build:js": "tsup src/index.ts --format esm --dts --external react --external react-dom --external framer-motion --clean",
29
30
  "build:css": "tailwindcss -i src/style.css -o dist/style.css --minify",