Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 52 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ If we prefer this API over the existing react-basic API, we may eventually repla
- **React 16.8+**: Core hooks (useState, useEffect, useReducer, useRef, useContext, useMemo, useDebugValue, useLayoutEffect)
- **React 18+**: useId, useTransition, useDeferredValue, useSyncExternalStore, useInsertionEffect
- **React 19+**: useOptimistic, useActionState, useEffectEvent (experimental)
- **React 19.2+**: Activity component
- **React canary**: ViewTransition component (experimental)

## Example

Expand Down Expand Up @@ -125,20 +127,65 @@ mkComponent :: Component Props
mkComponent = do
component "Component" \{ url, onSuccess } -> React.do
count /\ setCount <- useState 0

-- onSuccess can use the latest count without re-running the effect
onSuccessEvent <- useEffectEvent \data -> do
onSuccess data count

-- Effect only re-runs when url changes, not when count changes
useEffect url do
response <- fetchData url
onSuccessEvent response
pure mempty

pure $ R.div_ [ ... ]
```

## React 19.2 Components

### Activity

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`. Requires React 19.2+.

```purs
import React.Basic.Hooks.Activity (activity, ActivityMode(..))

mkTabPanel :: Component Props
mkTabPanel = do
component "TabPanel" \{ activeTab } -> React.do
pure $ R.div_
[ activity
{ mode: if activeTab == "tab1" then Visible else Hidden
, children: [ tab1Content ]
}
, activity
{ mode: if activeTab == "tab2" then Visible else Hidden
, children: [ tab2Content ]
}
]
```

### ViewTransition (Experimental)

The `ViewTransition` component animates DOM elements when they update inside a Transition. Available in `React.Basic.Hooks.ViewTransition`. Requires React canary — this API is unstable and may change.

```purs
import React.Basic.Hooks.ViewTransition (viewTransition, viewTransitionDefaults, AnimationValue(..))

mkAnimatedList :: Component Props
mkAnimatedList = do
component "AnimatedList" \{ items } -> React.do
_isPending /\ startTransition <- useTransition

pure $ R.div_ $ items <#> \item ->
viewTransition $ viewTransitionDefaults
{ children = [ renderItem item ]
, enter = Just (ClassName "slide-in")
, exit = Just (ClassName "slide-out")
, name = Just ("item-" <> item.id)
}
```

## Available Hooks

### Core Hooks (React 16.8+)
Expand Down Expand Up @@ -169,4 +216,6 @@ mkComponent = do
- Custom hooks via `React.Basic.Hooks.Aff` for async effects
- `React.Basic.Hooks.Suspense` for Suspense support
- `React.Basic.Hooks.ErrorBoundary` for error boundaries
- `React.Basic.Hooks.Activity` for hiding/showing UI while preserving state (React 19.2)
- `React.Basic.Hooks.ViewTransition` for animated transitions (React canary, experimental)
```
85 changes: 23 additions & 62 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
"main": "index.js",
"module": "true",
"dependencies": {
"react": "19.0.0",
"react-dom": "19.0.0"
"react": "^19.2.0",
"react-dom": "^19.2.0"
},
"devDependencies": {
"@testing-library/react": "^16.0.0",
Expand Down
1 change: 1 addition & 0 deletions spago.dhall
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ You can edit this file as you like.
, "either"
, "exceptions"
, "foldable-traversable"
, "foreign-object"
, "functions"
, "indexed-monad"
, "integers"
Expand Down
3 changes: 3 additions & 0 deletions src/React/Basic/Hooks/Activity.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import React from "react";

export const activity_ = React.Activity;
18 changes: 18 additions & 0 deletions src/React/Basic/Hooks/Activity.purs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module React.Basic.Hooks.Activity
( activity
, ActivityMode(..)
) where

import React.Basic.Hooks (JSX, ReactComponent, element)

data ActivityMode
= Visible
| Hidden

activity :: { mode :: ActivityMode, children :: Array JSX } -> JSX
activity props = element activity_ { mode: modeToString props.mode, children: props.children }
where
modeToString Visible = "visible"
modeToString Hidden = "hidden"

foreign import activity_ :: ReactComponent { mode :: String, children :: Array JSX }
12 changes: 12 additions & 0 deletions src/React/Basic/Hooks/ViewTransition.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from "react";

export const viewTransition_ = React.unstable_ViewTransition;

export const mkClassName = (str) => str;

export const mkAnimationMap = (obj) => obj;

export const toCallback_ = (fn) => (instance, types) => {
const cleanup = fn(instance)(types)();
return cleanup;
};
Loading
Loading