git.iko.soy/rowtype-yoga/purescript-yoga-react-native
on feature/macos-ios-support help sign in
184 lines 7.0 kB history raw
1# purescript-yoga-react-native
3PureScript bindings for React Native on macOS and iOS, including 55+ native AppKit components.
5## Quick Start
7```bash
8# Clone and install
9git clone https://github.com/rowtype-yoga/purescript-yoga-react-native.git
10cd purescript-yoga-react-native
11bun install
12cd example-macos && bun install && cd ..
14# Install CocoaPods for both Apple targets
15cd example-macos/macos && pod install && cd ../..
16cd example-macos/ios && pod install && cd ../..
18# Build PureScript before starting Metro
19cd example-macos && bunx spago build
21# Run macOS, or launch the default iOS simulator
22bun run macos
23bun run ios
25# To select an installed simulator explicitly
26bun run ios -- --simulator "iPhone 17 Pro"
28# List the exact simulator names available on this Mac
29xcrun simctl list devices available
31```
33`output/` is generated and ignored by Git, so the PureScript build is required after every clean checkout. `ios/Pods/`, `ios/build/`, and `.xcode.env.local` are local/generated files; regenerate Pods with `pod install` rather than committing them.
35For a physical iPhone, connect and trust the device, select an Apple Development team and a unique bundle identifier in Xcode, then run `bun run ios -- --device "Device Name"`. Distribution additionally requires Apple Developer Program membership, signing/provisioning, an App Store Connect record, an archive, and App Store Connect/TestFlight upload.
37## Using in Your Project
39Add the package dependency and source locations to `spago.yaml`:
40```yaml
41package:
42 dependencies:
43 - yoga-react-native
45workspace:
46 extraPackages:
47 yoga-react-native:
48 git: https://github.com/rowtype-yoga/purescript-yoga-react-native.git
49 ref: main
50 yoga-react:
51 git: https://github.com/rowtype-yoga/purescript-yoga-react.git
52 ref: main
53```
55The gesture and modern safe-area bindings require JavaScript peer dependencies. Install the React Native 0.81-compatible releases with Bun:
57```bash
58bun add react-native-gesture-handler@2.28.0 react-native-safe-area-context@^5.5.2
59```
61Autolink the native dependency on each Apple target after installation:
63```bash
64cd ios && pod install && cd ..
65# For a react-native-macos target as well:
66cd macos && pod install && cd ..
67```
69Wrap the registered application with both native root providers:
71```purescript
72import Yoga.React.Native.GestureHandler (gestureHandlerRootView)
73import Yoga.React.Native.IOS.SafeArea (safeAreaProvider)
75app :: {} -> JSX
76app _ = gestureHandlerRootView (safeAreaProvider {} application)
77```
79`Yoga.React.Native.GestureHandler` imports `react-native-gesture-handler` directly; applications that use it must provide the JavaScript package and linked native pod. The shared `Yoga.React.Native.SafeAreaView` and `Yoga.React.Native.IOS.SafeArea` bindings import `react-native-safe-area-context`; place `safeAreaProvider` at the application root before using either safe-area view. The gesture wrapper must be above every `panGestureView` in the rendered tree.
81### Swipeable cards from PureScript
83`Yoga.React.Native.GestureHandler` includes a reusable dismissal gesture for card decks. Application code stays in PureScript; the package privately owns the React Native `PanResponder` and `Animated` FFI.
85```purescript
86import Prelude
88import React.Basic.Hooks as React
89import Yoga.React (component)
90import Yoga.React.Native.Animated
91 ( Damping(..)
92 , Mass(..)
93 , Points(..)
94 , Stiffness(..)
95 , Velocity(..)
96 , animatedView
97 , physicalSpring
98 )
99import Yoga.React.Native.GestureHandler
100 ( SwipeDirection(..)
101 , swipeGestureView
102 , swipePosition
103 , useNativeSwipe
104 )
105import Yoga.React.Native.Style as Style
107swipeableCard = component "SwipeableCard" \{ card, onPass, onLike } -> React.do
108 swipe <- useNativeSwipe
109 { dismissalDistance: Points 110.0
110 , dismissalVelocity: Velocity 0.72
111 , returnSpring: physicalSpring
112 { stiffness: Stiffness 280.0, damping: Damping 24.0, mass: Mass 0.9 }
113 , dismissalSpring: physicalSpring
114 { stiffness: Stiffness 210.0, damping: Damping 22.0, mass: Mass 0.9 }
115 }
116 case _ of
117 SwipeLeft -> onPass
118 SwipeRight -> onLike
120 let x = swipePosition swipe
121 pure $ swipeGestureView swipe $
122 animatedView
123 { style: Style.style { transform: [ { translateX: x } ] } }
124 [ card ]
125```
127The callback runs once, after a committed card finishes moving offscreen. Short or vertically dominant drags do not dismiss; interrupted gestures return to center. `swipeProgress` exposes typed absolute progress from `0.0` at rest to `1.0` at either dismissal threshold, which can promote a pre-rendered card underneath with opacity, translation, or scale interpolation. Keep `gestureHandlerRootView` above the deck. On iOS, disable any parent full-screen back gesture for the card route so it does not compete for the same horizontal drag.
129```purescript
130import Yoga.React.Native (text, tw, view)
131import Yoga.React.Native.MacOS.Button (nativeButton)
132import Yoga.React.Native.MacOS.Types as T
134myButton = nativeButton
135 { title: "Click me"
136 , bezelStyle: T.push
137 , onPress: handler_ doSomething
138 , style: Style.style { height: 24.0 }
139 }
140```
142## Components
144### Input Controls
145`nativeButton` `nativeSwitch` `nativeSlider` `nativePopUp` `nativeComboBox` `nativeStepper` `nativeDatePicker` `nativeColorWell` `nativeCheckbox` `nativeRadioButton` `nativeSearchField` `nativeTokenField` `nativeSegmented`
147### Text
148`nativeTextField` `nativeTextEditor`
150### Display
151`nativeImage` `nativeAnimatedImage` `nativeVideoPlayer` `nativeLevelIndicator` `nativeProgress` `nativeSeparator` `nativePathControl`
153### Layout
154`nativeBox` `nativeSplitView` `nativeTabView` `nativeScrollView` `sidebarLayout` `nativeToolbar` `nativeVisualEffect` `nativePatternBackground`
156### Overlays
157`macosAlert` `nativeSheet` `nativePopover` `nativeContextMenu` `macosShowMenu`
159### Data Views
160`nativeTableView` `nativeOutlineView`
162### Files & Drag/Drop
163`nativeDropZone` `nativeFilePicker`
165### Rich Media
166`nativeMapView` `nativePDFView` `nativeWebView` `nativeCameraView` `nativeRiveView`
168### System Services
169`copyToClipboard` `macosShare` `macosNotify` `macosPlaySound` `macosSetStatusBarItem` `macosQuickLook` `macosShowColorPanel` `macosShowFontPanel` `say`
171### AI & ML
172`recognizeText` (OCR) `useSpeechRecognition` `detectLanguage` `analyzeSentiment` `tokenize`
174## Prerequisites
176- macOS 14.5+ and Xcode 16.1+ for React Native 0.81
177- Xcode Command Line Tools selected in **Xcode → Settings → Locations**
178- An iOS Simulator runtime installed in **Xcode → Settings → Platforms**, or an iPhone running iOS 15.1+
179- Node.js 20.19.4+ for React Native, CocoaPods, and Xcode build scripts
180- Bun for JavaScript dependency installation and project scripts
181- PureScript 0.15+; the example pins Spago 1.0.3 in `devDependencies`
182- CocoaPods 1.16.2, matching `ios/Podfile.lock`
184Watchman is recommended for Metro file-watching performance but is not required. Simulator builds require no Apple account or signing configuration.