Skip to content

Commit af59b00

Browse files
Add Activity and ViewTransition components for React 19.2+
Adds two new React 19.2+ experimental components with full PureScript bindings and comprehensive test coverage. New modules: - React.Basic.Hooks.Activity - Hide/show UI while preserving state - React.Basic.Hooks.ViewTransition - Animated transitions with View Transition API Features: - Complete FFI bindings to React.Activity and React.ViewTransition - Type-safe APIs with ActivityMode and AnimationValue types - Support for all props including callbacks and shared element transitions - Comprehensive test suites (pending until React 19.2+ is available) - Full documentation with examples in README Dependencies: - Added foreign-object and web-dom to main dependencies - Tests marked as pending (require React 19.2+ experimental/canary) Note: These components are only available in React 19.2+ experimental releases, not in stable React 19.0.x
1 parent 7988118 commit af59b00

File tree

9 files changed

+516
-72
lines changed

9 files changed

+516
-72
lines changed

README.md

Lines changed: 106 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,20 +125,121 @@ mkComponent :: Component Props
125125
mkComponent = do
126126
component "Component" \{ url, onSuccess } -> React.do
127127
count /\ setCount <- useState 0
128-
128+
129129
-- onSuccess can use the latest count without re-running the effect
130130
onSuccessEvent <- useEffectEvent \data -> do
131131
onSuccess data count
132-
132+
133133
-- Effect only re-runs when url changes, not when count changes
134134
useEffect url do
135135
response <- fetchData url
136136
onSuccessEvent response
137137
pure mempty
138-
138+
139139
pure $ R.div_ [ ... ]
140140
```
141141

142+
## React 19 Components
143+
144+
**Note:** These components require React 19.2+ experimental/canary versions. They are not available in stable React 19.0.x releases.
145+
146+
### Activity
147+
148+
The `Activity` component lets you hide and restore the UI and internal state of its children while preserving their state and DOM. Available in `React.Basic.Hooks.Activity`.
149+
150+
```purs
151+
import React.Basic.Hooks.Activity (activity, ActivityMode(..))
152+
153+
mkTabPanel :: Component Props
154+
mkTabPanel = do
155+
component "TabPanel" \{ activeTab } -> React.do
156+
pure $ R.div_
157+
[ activity
158+
{ mode: if activeTab == "tab1" then Visible else Hidden
159+
, children: [ tab1Content ]
160+
}
161+
, activity
162+
{ mode: if activeTab == "tab2" then Visible else Hidden
163+
, children: [ tab2Content ]
164+
}
165+
]
166+
```
167+
168+
**Key Features:**
169+
- Preserves component state when hidden (unlike conditional rendering)
170+
- Hides children using CSS `display: none`
171+
- Effects are cleaned up when hidden and re-created when visible
172+
- Useful for tabs, sidebars, or pre-rendering content for faster navigation
173+
174+
**Props:**
175+
- `mode``Visible` or `Hidden` (defaults to `Visible`)
176+
- `children` — Array of JSX elements to show/hide
177+
178+
### ViewTransition
179+
180+
The `ViewTransition` component animates DOM elements when they update inside a Transition. Available in `React.Basic.Hooks.ViewTransition`.
181+
182+
```purs
183+
import React.Basic.Hooks.ViewTransition (viewTransition, AnimationValue(..))
184+
185+
mkAnimatedList :: Component Props
186+
mkAnimatedList = do
187+
component "AnimatedList" \{ items } -> React.do
188+
_isPending /\ startTransition <- useTransition
189+
190+
let handleRemove item = startTransition do
191+
removeItem item
192+
193+
pure $ R.div_ $ items <#> \item ->
194+
viewTransition
195+
{ children: [ renderItem item ]
196+
, enter: Just (ClassName "slide-in")
197+
, exit: Just (ClassName "slide-out")
198+
, update: Just (ClassName "fade")
199+
, share: Nothing
200+
, default: Nothing
201+
, name: Just ("item-" <> item.id)
202+
, onEnter: Nothing
203+
, onExit: Nothing
204+
, onUpdate: Nothing
205+
, onShare: Nothing
206+
}
207+
```
208+
209+
**Animation Triggers:**
210+
- `enter` — Animates when `ViewTransition` is inserted
211+
- `exit` — Animates when `ViewTransition` is deleted
212+
- `update` — Animates when DOM mutations occur inside
213+
- `share` — Animates shared element transitions (requires `name` prop)
214+
- `default` — Fallback animation if no matching trigger
215+
216+
**Shared Element Transitions:**
217+
```purs
218+
-- When the same name transitions between views, React creates a smooth shared animation
219+
viewTransition
220+
{ name: Just "hero-image"
221+
, share: Just (ClassName "morph")
222+
, children: [ thumbnail ]
223+
, enter: Nothing, exit: Nothing, update: Nothing, default: Nothing
224+
, onEnter: Nothing, onExit: Nothing, onUpdate: Nothing, onShare: Nothing
225+
}
226+
227+
-- Later, in a different view with the same name
228+
viewTransition
229+
{ name: Just "hero-image"
230+
, share: Just (ClassName "morph")
231+
, children: [ fullImage ]
232+
, enter: Nothing, exit: Nothing, update: Nothing, default: Nothing
233+
, onEnter: Nothing, onExit: Nothing, onUpdate: Nothing, onShare: Nothing
234+
}
235+
```
236+
237+
**Animation Values:**
238+
- `ClassName String` — CSS class name to apply
239+
- `AnimationMap (Object String)` — Map transition types to class names
240+
241+
**Note:** ViewTransition only activates inside a `Transition` (via `startTransition`)
242+
142243
## Available Hooks
143244

144245
### Core Hooks (React 16.8+)
@@ -169,4 +270,6 @@ mkComponent = do
169270
- Custom hooks via `React.Basic.Hooks.Aff` for async effects
170271
- `React.Basic.Hooks.Suspense` for Suspense support
171272
- `React.Basic.Hooks.ErrorBoundary` for error boundaries
273+
- `React.Basic.Hooks.Activity` for hiding/showing UI while preserving state (React 19.2+)
274+
- `React.Basic.Hooks.ViewTransition` for animated transitions (React 19+)
172275
```

0 commit comments

Comments
 (0)