react-morpheus 0.1.9 → 0.1.10

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
@@ -1,5 +1,7 @@
1
1
  # React Morpheus
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/react-morpheus.svg)](https://www.npmjs.com/package/react-morpheus)
4
+
3
5
  A controlled React component for morphing one UI state into another.
4
6
 
5
7
  React Morpheus exists for interfaces where a control should become the next
@@ -17,17 +19,20 @@ https://github.com/user-attachments/assets/f90e7096-f587-4793-8e80-476cf844569d
17
19
  ## Installation
18
20
 
19
21
  ```sh
20
- bun add react-morpheus
22
+ bun add react-morpheus cuelume
21
23
  ```
22
24
 
23
25
  ```sh
24
- npm i react-morpheus
26
+ npm i react-morpheus cuelume
25
27
  ```
26
28
 
27
29
  ```sh
28
- yarn add react-morpheus
30
+ yarn add react-morpheus cuelume
29
31
  ```
30
32
 
33
+ Cuelume is a peer dependency that provides the optional synthesized sound
34
+ palette. No audio files are bundled.
35
+
31
36
  ## Usage
32
37
 
33
38
  Import the component and stylesheet, keep the open state in your app, and pass
@@ -55,6 +60,8 @@ function Example() {
55
60
  anchor={MorphAnchor.TopMiddle}
56
61
  expanded={expanded}
57
62
  onClose={() => setExpanded(false)}
63
+ openSound="bloom"
64
+ closeSound="droplet"
58
65
  overlayColor="#0f172a"
59
66
  overlayOpacity={0.18}
60
67
  overlayBlur={3}
@@ -90,6 +97,8 @@ should run around the closing animation.
90
97
  | `onClose` | `() => void` | Optional | Called when the overlay requests closing. Use it to update your controlled open state. |
91
98
  | `beforeClose` | `() => void` | Optional | Called when the closing animation starts, after `expanded` has changed to `false`. Useful for close-intent side effects. |
92
99
  | `afterClose` | `() => void` | Optional | Called after the closing animation completes. |
100
+ | `openSound` | `SoundName` | Optional | Cuelume sound played once when `expanded` changes to `true`. |
101
+ | `closeSound` | `SoundName` | Optional | Cuelume sound played once when `expanded` changes to `false`. |
93
102
  | `collapsedContent` | `ReactNode` | Required | The source surface Morpheus measures, renders, and uses as the opener. |
94
103
  | `expandedContent` | `ReactNode` | Required | The destination surface Morpheus measures and animates into. |
95
104
  | `className` | `string` | Optional | Classes applied to the root wrapper. Useful for block layout and responsive width constraints. |
@@ -102,6 +111,10 @@ should run around the closing animation.
102
111
  | `overlayZIndex` | `number` | Optional | Stacking level for the expanded surface. Defaults to `1000`; the overlay renders one layer below it. |
103
112
  | `spring` | `Transition` | Optional | Framer Motion transition. Pass your own transition or use `morphSpringPresets`. |
104
113
 
114
+ Sound is opt-in. Both props accept any Cuelume sound name, including `bloom`,
115
+ `droplet`, `toggle`, `release`, and `whisper`. Omitting a prop keeps that
116
+ transition silent.
117
+
105
118
  ## Pitfalls
106
119
 
107
120
  ### Responsiveness
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode, RefObject } from 'react';
3
+ import { SoundName } from 'cuelume';
3
4
  import { Transition } from 'framer-motion';
4
5
 
5
6
  declare enum MorphAnchor {
@@ -81,6 +82,8 @@ type MorphProps = {
81
82
  onClose?: (() => void) | undefined;
82
83
  beforeClose?: (() => void) | undefined;
83
84
  afterClose?: (() => void) | undefined;
85
+ openSound?: SoundName | undefined;
86
+ closeSound?: SoundName | undefined;
84
87
  collapsedContent: ReactNode;
85
88
  expandedContent: ReactNode;
86
89
  className?: string;
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  // src/component.tsx
2
+ import { play } from "cuelume";
2
3
  import { motion as motion2 } from "framer-motion";
3
4
  import {
4
5
  createContext,
@@ -652,6 +653,8 @@ function MorpheusRoot({
652
653
  onClose,
653
654
  beforeClose,
654
655
  afterClose,
656
+ openSound,
657
+ closeSound,
655
658
  collapsedContent,
656
659
  expandedContent,
657
660
  className = "rmorph:relative rmorph:inline-block rmorph:align-top",
@@ -682,6 +685,9 @@ function MorpheusRoot({
682
685
  const beforeCloseRef = useRef2(beforeClose);
683
686
  const afterCloseRef = useRef2(afterClose);
684
687
  const previousExpandedRef = useRef2(expanded);
688
+ const previousSoundExpandedRef = useRef2(expanded);
689
+ const openSoundRef = useRef2(openSound);
690
+ const closeSoundRef = useRef2(closeSound);
685
691
  const portalStartFrameRef = useRef2(null);
686
692
  const handoffFirstFrameRef = useRef2(null);
687
693
  const handoffSecondFrameRef = useRef2(null);
@@ -691,6 +697,18 @@ function MorpheusRoot({
691
697
  expandedRef.current = expanded;
692
698
  beforeCloseRef.current = beforeClose;
693
699
  afterCloseRef.current = afterClose;
700
+ openSoundRef.current = openSound;
701
+ closeSoundRef.current = closeSound;
702
+ useEffect(() => {
703
+ if (previousSoundExpandedRef.current === expanded) {
704
+ return;
705
+ }
706
+ previousSoundExpandedRef.current = expanded;
707
+ const sound = expanded ? openSoundRef.current : closeSoundRef.current;
708
+ if (sound) {
709
+ play(sound);
710
+ }
711
+ }, [expanded]);
694
712
  const cancelPortalFrames = useCallback(() => {
695
713
  if (portalStartFrameRef.current !== null) {
696
714
  cancelAnimationFrame(portalStartFrameRef.current);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-morpheus",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "A controlled React component for morphing one UI surface into another.",
5
5
  "keywords": [
6
6
  "react",
@@ -38,7 +38,7 @@
38
38
  "scripts": {
39
39
  "prepare": "bun run build",
40
40
  "build": "bun run build:js && bun run build:css",
41
- "build:js": "tsup src/index.ts --format esm --dts --external react --external react-dom --external framer-motion --clean",
41
+ "build:js": "tsup src/index.ts --format esm --dts --external react --external react-dom --external framer-motion --external cuelume --clean",
42
42
  "build:css": "tailwindcss -i src/style.css -o dist/style.css --minify",
43
43
  "check": "tsc --noEmit",
44
44
  "test": "bun test",
@@ -48,6 +48,7 @@
48
48
  "release:patch": "bun run scripts/release.ts patch"
49
49
  },
50
50
  "peerDependencies": {
51
+ "cuelume": "^0.2.2",
51
52
  "framer-motion": "^12.42.2",
52
53
  "react": "^19.0.0",
53
54
  "react-dom": "^19.0.0"