diff --git a/CHANGELOG.md b/CHANGELOG.md index 358bc7a1..4311ed56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,42 @@ # Changelog of `rescript-react-native` +## Unreleased + +- Upgrade to `react-native@0.85` + - Breaking: remove `StyleSheet.absoluteFillObject` (removed upstream, use `StyleSheet.absoluteFill`) + - Add `Animated.useAnimatedValueXY` and `Animated.useAnimatedColor` + - Add `EventEmitter` module + - Add `selection` to `TextInput.ChangeEvent` payload + - Add `onPressMove` prop to `Pressable` + - Add `scrollsChildToFocus` Android prop to `ScrollView` +- `Animated` improvements + - Breaking: `Animated.Color.create(~initialValue=?, ~config=?)` takes `Animated.Color.input` (`Rgba({r, g, b, a})` / `String("red")`), replaces `create(rawValue)` / `createFromString`; `rgbaValue` removed, `rawValue` is now the `Animated.Color.rgba` record + - Breaking: `Animated.Color.setValue` takes `Animated.Color.input` + - Breaking: `Animated.Color` listener / `stopAnimation` / `resetAnimation` callbacks receive a color string (was wrongly typed as an rgba object) + - Breaking: `Animated.parallel(anims, ~config=?)`, `stopTogether` is optional (`parallelPayload` renamed `parallelConfig`) + - Fix `Animated.StyleProp.color` returning `Animated.Color.t` instead of `Color.t` + - Add `Animated.StyleProp.animatedColor` to use an `Animated.Color` in styles + - Add optional `~config` to `Animated.Value.create` and `Animated.ValueXY.create` + - Add `Animated.ValueXY.createFromValues` (from existing `Animated.Value`s) + - Add `Timing.fromInterpolation` / `Spring.fromInterpolation` for `toValue` + - Add `hasListeners`, `Animated.attachNativeEvent`, `Animated.forkEvent`, `Animated.unforkEvent` + - Zero-cost `Animated.timing` / `spring` / `decay` / `start` / `stop` / `reset` and `Value.interpolate` (were compiled to JS wrapper functions) +- Fix `Color.hsla` generating an invalid `hsl(h, s%, l%, a)` color instead of `hsla(...)` +- New APIs: `I18nManager`, `DeviceEventEmitter`, `ReactNativeVersion` +- New globals installed by React Native: `Global.requestIdleCallback` / `cancelIdleCallback` / `setImmediate` / `clearImmediate` / `queueMicrotask`, `ErrorUtils` (`setGlobalHandler`, `getGlobalHandler`, `reportError`, `reportFatalError`) +- New props + - `View`: touch events (`onTouchStart`, `onTouchMove`, `onTouchEnd`, `onTouchCancel` and their `Capture` variants), `onFocusCapture`, `onBlurCapture`, `nextFocus*` (Android), `experimental_accessibilityOrder` + - `Pressable`: `cancelable`; `TouchableWithoutFeedback`: `rejectResponderTermination`; `TextInput`: `inputAccessoryViewButtonLabel`; `Image`: `src` (`source` is now optional) + - `aria-*` accessibility props (`ariaLabel`, `ariaChecked`, `ariaHidden`, `ariaLive`, …) on all components using `Accessibility` props +- Breaking: `ScrollView` `StickyHeaderComponent` is a `React.component` (was wrongly typed as `React.element`), add `Animated.Value.fromStickyHeaderScrollValue` +- Add `Style.matrix` transform +- Breaking: `VirtualizedList.cellRendererComponentProps` is now typed (`cellKey`, `children`, `index`, `item`, `onLayout`, …) +- Deprecate `InteractionManager` (deprecated by React Native, use `Global.requestIdleCallback`), `runAfterInteractions` returns a cancellable `task` +- Deprecate `ProgressBarAndroid` and `Clipboard` (extracted from react-native core), `StatusBar.setNetworkActivityIndicatorVisible` +- Mark as deprecated (documentation only, ReScript does not warn on record fields): `TextInput` `blurOnSubmit` (use `submitBehavior`), `hasTVPreferredFocus` on `Button` / `TouchableHighlight` / `TouchableOpacity` (use `focusable`) +- Add all `fontVariant` values (ligatures, `contextual`, `stylistic-*`) +- Bump dev dependency to `rescript@12.3.1` + ## 0.84.0 - 2026-09-15 - Upgrade to `rescript@12` and `@rescript/react@0.15` diff --git a/package-lock.json b/package-lock.json index c8a91a9d..fe471aa5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,7 @@ "npm-run-all": "^4.0.0", "npmpub": "^6.1.0", "prettier": "^2.0.0", - "rescript": "~12.0.2" + "rescript": "~12.3.1" }, "funding": { "url": "https://github.com/rescript-react-native/rescript-react-native?sponsor=1" @@ -941,13 +941,14 @@ } }, "node_modules/@rescript/darwin-arm64": { - "version": "12.0.2", - "resolved": "https://registry.npmjs.org/@rescript/darwin-arm64/-/darwin-arm64-12.0.2.tgz", - "integrity": "sha512-GcfiPE0L2N7smWXMBEW4pvlcqblSbKh2tisZTuOaLPr9+WmaXnBLap6OUT+XoEWzTY0RA4QURfpNJLAgqZPrzw==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@rescript/darwin-arm64/-/darwin-arm64-12.3.1.tgz", + "integrity": "sha512-pwdnHhuIMH4Y5nuEwBLAMOYvGIcAVgnSZq/DWUNZJWoUr7YZpNkABJp0TFGiyYePT5ld+nvjQ40oI0rKjEWK8w==", "cpu": [ "arm64" ], "dev": true, + "license": "(LGPL-3.0-or-later AND MIT)", "optional": true, "os": [ "darwin" @@ -957,13 +958,14 @@ } }, "node_modules/@rescript/darwin-x64": { - "version": "12.0.2", - "resolved": "https://registry.npmjs.org/@rescript/darwin-x64/-/darwin-x64-12.0.2.tgz", - "integrity": "sha512-di4eucoDdLsLqz86h7Cwywsmt+xFup7rpVlkx8L7i22RTqyTw+CD6aGjFj1Ddj2sVUd5SSFiE9Hj86QggzUgbg==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@rescript/darwin-x64/-/darwin-x64-12.3.1.tgz", + "integrity": "sha512-Eu39cHkzoHyC18BCRqnmZnLgP42c7JhR74UBl6XhaFOzuf63tddOssgTyX9mEihzok2xFBGLpETrCvZN8Qqtkg==", "cpu": [ "x64" ], "dev": true, + "license": "(LGPL-3.0-or-later AND MIT)", "optional": true, "os": [ "darwin" @@ -973,13 +975,14 @@ } }, "node_modules/@rescript/linux-arm64": { - "version": "12.0.2", - "resolved": "https://registry.npmjs.org/@rescript/linux-arm64/-/linux-arm64-12.0.2.tgz", - "integrity": "sha512-x6WOyimX0kw9DGADQ02R2rmvKu8SQOrskfYrKREfc2CgDT+FOKAH+qxvpUiljKhrvthoHkVBJOXtlKk854OdjQ==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@rescript/linux-arm64/-/linux-arm64-12.3.1.tgz", + "integrity": "sha512-Nsk3qfDRrp9b6RI85t0xzrr8LoxwXAI678V7zpQMaRfhltYl+N5fsK66MWx9rSrv6SIWPVSyU8FrJG0MskONwQ==", "cpu": [ "arm64" ], "dev": true, + "license": "(LGPL-3.0-or-later AND MIT)", "optional": true, "os": [ "linux" @@ -989,13 +992,14 @@ } }, "node_modules/@rescript/linux-x64": { - "version": "12.0.2", - "resolved": "https://registry.npmjs.org/@rescript/linux-x64/-/linux-x64-12.0.2.tgz", - "integrity": "sha512-5QHE+Ca1h3qXxDkw343923WTEdEyBeXphrv+8SZLhLOFNabQ5t6m4rWf52RluDqQpa67j6GB8kVAZpqc2rA2Qw==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@rescript/linux-x64/-/linux-x64-12.3.1.tgz", + "integrity": "sha512-CfAJ3q/y/GSwrSJCLdCdyLWWdb7kTZkl2vjC+mSAw3pMqknEyCbt4ukS64Xn8PrqxVGHIs+kdefEphU7dt77xA==", "cpu": [ "x64" ], "dev": true, + "license": "(LGPL-3.0-or-later AND MIT)", "optional": true, "os": [ "linux" @@ -1017,21 +1021,21 @@ } }, "node_modules/@rescript/runtime": { - "version": "12.2.0", - "resolved": "https://registry.npmjs.org/@rescript/runtime/-/runtime-12.2.0.tgz", - "integrity": "sha512-NwfljDRq1rjFPHUaca1nzFz13xsa9ZGkBkLvMhvVgavJT5+A4rMcLu8XAaVTi/oAhO/tlHf9ZDoOTF1AfyAk9Q==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@rescript/runtime/-/runtime-12.3.1.tgz", + "integrity": "sha512-yTM0iTl6owyA37UEtPAZR0A3G1kFffJWb+UE6+rcG/N2kxYQnuSlNDfVvsry7l8O+o/ME6QE7Zt7efjCDGM3xg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@rescript/win32-x64": { - "version": "12.0.2", - "resolved": "https://registry.npmjs.org/@rescript/win32-x64/-/win32-x64-12.0.2.tgz", - "integrity": "sha512-QcNQiok3H2Xd+cReB1kpH4hlPXnT7DA6ETsJfZugTUOKOdAYLTJ+Imynv+ojuafkUrwa2v0tZAiqHaQsDjf9IQ==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@rescript/win32-x64/-/win32-x64-12.3.1.tgz", + "integrity": "sha512-1ffFbw9IJnJmGTNshWzRcG6wQ7GkzOeWxLLrarvxI38p2aYPQKTbVovUraXpw1Jfg2bbWkm8hPMMrFIezI/pkA==", "cpu": [ "x64" ], "dev": true, + "license": "(LGPL-3.0-or-later AND MIT)", "optional": true, "os": [ "win32" @@ -5557,11 +5561,11 @@ } }, "node_modules/rescript": { - "version": "12.0.2", - "resolved": "https://registry.npmjs.org/rescript/-/rescript-12.0.2.tgz", - "integrity": "sha512-H1K9ovIxg2BVwJcXN1cZv0Q1pJEyFgNcUDKHSkmKmv5eBZMpXBASTZ2+grDt0zFFNoeFA1B9abAjSf+oTTi7hg==", + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/rescript/-/rescript-12.3.1.tgz", + "integrity": "sha512-Q4y0SQ7EUShiX1ymEG5iOCGzbVSOh7CCLEnQUkq19FX2i64eQ2uEGeMCKFl0AsL7TcK5pS+66QTSP6jf6LSgaA==", "dev": true, - "license": "SEE LICENSE IN LICENSE", + "license": "(LGPL-3.0-or-later AND MIT)", "workspaces": [ "packages/playground", "packages/@rescript/*", @@ -5570,10 +5574,11 @@ "tests/docstring_tests", "tests/gentype_tests/**", "tests/tools_tests", + "tests/commonjs_tests", "scripts/res" ], "dependencies": { - "@rescript/runtime": "12.0.2" + "@rescript/runtime": "12.3.1" }, "bin": { "bsc": "cli/bsc.js", @@ -5586,18 +5591,12 @@ "node": ">=20.11.0" }, "optionalDependencies": { - "@rescript/darwin-arm64": "12.0.2", - "@rescript/darwin-x64": "12.0.2", - "@rescript/linux-arm64": "12.0.2", - "@rescript/linux-x64": "12.0.2", - "@rescript/win32-x64": "12.0.2" - } - }, - "node_modules/rescript/node_modules/@rescript/runtime": { - "version": "12.0.2", - "resolved": "https://registry.npmjs.org/@rescript/runtime/-/runtime-12.0.2.tgz", - "integrity": "sha512-Jma1QEgns/WlWeVap/Mv6dVbFEKmftPOrmwQbzLQnnrQ9z6PJjorHIvDMQUigQKnvM/4RhRJ3LiG+CsNtgS9ww==", - "dev": true + "@rescript/darwin-arm64": "12.3.1", + "@rescript/darwin-x64": "12.3.1", + "@rescript/linux-arm64": "12.3.1", + "@rescript/linux-x64": "12.3.1", + "@rescript/win32-x64": "12.3.1" + } }, "node_modules/resolve": { "version": "1.22.12", diff --git a/package.json b/package.json index ba54cd90..748d1cf0 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "version": "0.84.0", "peerDependencies": { "@rescript/react": ">=0.15.0", - "react-native": ">=0.84.0", + "react-native": ">=0.85.0", "rescript": ">=12.0.0" }, "overrides": { @@ -45,7 +45,7 @@ "npm-run-all": "^4.0.0", "npmpub": "^6.1.0", "prettier": "^2.0.0", - "rescript": "~12.0.2" + "rescript": "~12.3.1" }, "prettier": { "trailingComma": "all" diff --git a/src/apis/Animated.res b/src/apis/Animated.res index 0cb2ff5a..c2aef808 100644 --- a/src/apis/Animated.res +++ b/src/apis/Animated.res @@ -1,3 +1,8 @@ +// alias of the global `Color.t` (a string), shadowed below by `Animated.Color` +type colorValue = Color.t + +type config = {useNativeDriver: bool} + module Animation = { type t type endResult = {finished: bool} @@ -13,6 +18,7 @@ module type Value = { type t type rawValue type addListenerCallback + type callback } type calculated @@ -21,6 +27,26 @@ type regular type value<'a> +module Interpolation = { + type t = value + type outputRange + external fromStringArray: array => outputRange = "%identity" + external fromFloatArray: array => outputRange = "%identity" + + type extrapolate = [#extend | #clamp | #identity] + + type config = { + inputRange: array, + outputRange: outputRange, + easing?: Easing.t, + extrapolate?: extrapolate, + extrapolateLeft?: extrapolate, + extrapolateRight?: extrapolate, + } + + @send external interpolate: (value<'a>, config) => t = "interpolate" +} + module ValueAnimations = (Val: Value) => { module Decay = { type config = { @@ -40,6 +66,7 @@ module ValueAnimations = (Val: Value) => { type toValue external fromRawValue: Val.rawValue => toValue = "%identity" external fromAnimatedValue: Val.t => toValue = "%identity" + external fromInterpolation: Interpolation.t => toValue = "%identity" type config = { toValue: toValue, @@ -70,6 +97,7 @@ module ValueAnimations = (Val: Value) => { external fromRawValue: Val.rawValue => toValue = "%identity" external fromAnimatedValue: Val.t => toValue = "%identity" + external fromInterpolation: Interpolation.t => toValue = "%identity" type config = { toValue: toValue, @@ -87,26 +115,6 @@ module ValueAnimations = (Val: Value) => { } } -module Interpolation = { - type t = value - type outputRange - external fromStringArray: array => outputRange = "%identity" - external fromFloatArray: array => outputRange = "%identity" - - type extrapolate = [#extend | #clamp | #identity] - - type config = { - inputRange: array, - outputRange: outputRange, - easing?: Easing.t, - extrapolate?: extrapolate, - extrapolateLeft?: extrapolate, - extrapolateRight?: extrapolate, - } - - @send external interpolate: (value<'a>, config) => t = "interpolate" -} - module ValueOperations = { @module("react-native") @scope("Animated") external add: (value<'a>, value<'b>) => value = "add" @@ -120,14 +128,15 @@ module ValueOperations = { external subtract: (value<'a>, value<'b>) => value = "subtract" @module("react-native") @scope("Animated") external diffClamp: (value<'a>, float, float) => value = "diffClamp" - let interpolate = Interpolation.interpolate + // externals rather than `let` aliases, which would compile to JS wrapper functions + @send external interpolate: (value<'a>, Interpolation.config) => Interpolation.t = "interpolate" } module ValueMethods = (Val: Value) => { type t = Val.t type rawValue = Val.rawValue type addListenerCallback = Val.addListenerCallback - type callback = rawValue => unit + type callback = Val.callback @send external setValue: (t, rawValue) => unit = "setValue" @send external setOffset: (t, rawValue) => unit = "setOffset" @@ -137,6 +146,7 @@ module ValueMethods = (Val: Value) => { external addListener: (t, addListenerCallback) => string = "addListener" @send external removeListener: (t, string) => unit = "removeListener" @send external removeAllListeners: t => unit = "removeAllListeners" + @send external hasListeners: t => bool = "hasListeners" @send external resetAnimation: (t, ~callback: callback=?) => unit = "resetAnimation" @@ -152,10 +162,15 @@ module Value = { type t = value type rawValue = float type addListenerCallback = {"value": rawValue} => unit + type callback = rawValue => unit }) @new @scope("Animated") @module("react-native") - external create: float => t = "Value" + external create: (float, ~config: config=?) => t = "Value" + + // the scroll value received by a `ScrollView` `StickyHeaderComponent` + external fromStickyHeaderScrollValue: ScrollView.stickyHeaderScrollAnimatedValue => t = + "%identity" include ValueOperations } @@ -165,6 +180,7 @@ module ValueXY = { type t = {"x": Value.t, "y": Value.t} type rawValue = {"x": float, "y": float} type addListenerCallback = rawValue => unit + type callback = rawValue => unit }) type layout = { @@ -172,26 +188,33 @@ module ValueXY = { top: Value.t, } @new @scope("Animated") @module("react-native") - external create: rawValue => t = "ValueXY" + external create: (rawValue, ~config: config=?) => t = "ValueXY" + // reuse existing `Animated.Value`s for x and y + @new @scope("Animated") @module("react-native") + external createFromValues: (t, ~config: config=?) => t = "ValueXY" @send external getLayout: t => layout = "getLayout" @send external getTranslateTransform: t => array = "getTranslateTransform" } module Color = { + type rgba = {r: float, g: float, b: float, a: float} + include ValueMethods({ type t = {"r": Value.t, "g": Value.t, "b": Value.t, "a": Value.t} - type rawValue = {"r": float, "g": float, "b": float, "a": float} - type addListenerCallback = rawValue => unit + type rawValue = rgba + // listeners receive the current color as a string, e.g. "rgba(255, 0, 0, 1)" + type addListenerCallback = colorValue => unit + type callback = colorValue => unit }) - @obj external rgbaValue: (~r: float, ~g: float, ~b: float, ~a: float) => rawValue = "" + @unboxed type input = Rgba(rgba) | String(colorValue) @new @scope("Animated") @module("react-native") - external create: rawValue => t = "Color" + external create: (~initialValue: input=?, ~config: config=?) => t = "Color" - @new @scope("Animated") @module("react-native") - external createFromString: Color.t => t = "Color" + // shadows `ValueMethods.setValue` to also accept a color string + @send external setValue: (t, input) => unit = "setValue" } @module("react-native") @scope("Animated") @@ -200,9 +223,9 @@ external delay: float => Animation.t = "delay" @module("react-native") @scope("Animated") external sequence: array => Animation.t = "sequence" -type parallelPayload = {stopTogether: bool} +type parallelConfig = {stopTogether?: bool} @module("react-native") @scope("Animated") -external parallel: (array, parallelPayload) => Animation.t = "parallel" +external parallel: (array, ~config: parallelConfig=?) => Animation.t = "parallel" @module("react-native") @scope("Animated") external stagger: (float, array) => Animation.t = "stagger" @@ -227,21 +250,44 @@ external event1: (array<'mapping>, ~config: eventConfig<'a, 'platformConfig>=?) external event2: (('mapping1, 'mapping2), ~config: eventConfig<'a, 'platformConfig>=?) => 'a = "event" +type attachedEvent = {detach: unit => unit} + +@module("react-native") @scope("Animated") +external attachNativeEvent: ( + 'viewRef, + string, + array<'mapping>, + ~platformConfig: 'platformConfig=?, +) => attachedEvent = "attachNativeEvent" + +// adds a JS listener to an event handler (e.g. one returned by `event1`) +@module("react-native") @scope("Animated") +external forkEvent: (option<'handler>, 'handler) => 'handler = "forkEvent" + +@module("react-native") @scope("Animated") +external unforkEvent: (option<'handler>, 'handler) => unit = "unforkEvent" + @module("react-native") @scope("Animated") external createAnimatedComponent: React.component<'props> => React.component<'props> = "createAnimatedComponent" -let timing = Value.Timing.timing +// shortcuts for `Value`, as externals rather than `let` aliases, +// which would compile to JS wrapper functions +@module("react-native") @scope("Animated") +external timing: (Value.t, Value.Timing.config) => Animation.t = "timing" -let spring = Value.Spring.spring +@module("react-native") @scope("Animated") +external spring: (Value.t, Value.Spring.config) => Animation.t = "spring" -let decay = Value.Decay.decay +@module("react-native") @scope("Animated") +external decay: (Value.t, Value.Decay.config) => Animation.t = "decay" -let start = Animation.start +@send +external start: (Animation.t, ~endCallback: Animation.endCallback=?) => unit = "start" -let stop = Animation.stop +@send external stop: Animation.t => unit = "stop" -let reset = Animation.reset +@send external reset: Animation.t => unit = "reset" module StyleProp = { // methods to allow use of Animated values with Style props @@ -256,7 +302,8 @@ module StyleProp = { external angle: value => Style.angle = "%identity" external size: value<'a> => Style.size = "%identity" external margin: value<'a> => Style.margin = "%identity" - external color: value => Color.t = "%identity" + external color: value => colorValue = "%identity" + external animatedColor: Color.t => colorValue = "%identity" // UNSAFE: allows to pass animated values everywhere, // use of more precise methods above is recommended @@ -295,7 +342,13 @@ module View = { external make: View.props => React.element = "View" } -type config = {useNativeDriver: bool} - @module("react-native") external useAnimatedValue: (~initialValue: float, ~config: config=?) => Value.t = "useAnimatedValue" + +@module("react-native") +external useAnimatedValueXY: (~initialValue: ValueXY.rawValue, ~config: config=?) => ValueXY.t = + "useAnimatedValueXY" + +@module("react-native") +external useAnimatedColor: (~initialValue: Color.input=?, ~config: config=?) => Color.t = + "useAnimatedColor" diff --git a/src/apis/Animated.res.js b/src/apis/Animated.res.js index b28e12ea..e55dcce5 100644 --- a/src/apis/Animated.res.js +++ b/src/apis/Animated.res.js @@ -1,10 +1,10 @@ -import * as ReactNative from "react-native"; -import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js"; let Animation = {}; +let Interpolation = {}; + function ValueAnimations(Val) { let Decay = {}; let Spring = {}; @@ -16,15 +16,7 @@ function ValueAnimations(Val) { }; } -let Interpolation = {}; - -function interpolate(prim0, prim1) { - return prim0.interpolate(prim1); -} - -let ValueOperations = { - interpolate: interpolate -}; +let ValueOperations = {}; function ValueMethods(Val) { let Decay = {}; @@ -46,8 +38,7 @@ let Timing = {}; let Value = { Decay: Decay, Spring: Spring, - Timing: Timing, - interpolate: interpolate + Timing: Timing }; let Decay$1 = {}; @@ -74,30 +65,6 @@ let Color = { Timing: Timing$2 }; -function timing(prim0, prim1) { - return ReactNative.Animated.timing(prim0, prim1); -} - -function spring(prim0, prim1) { - return ReactNative.Animated.spring(prim0, prim1); -} - -function decay(prim0, prim1) { - return ReactNative.Animated.decay(prim0, prim1); -} - -function start(prim0, prim1) { - prim0.start(prim1 !== undefined ? Primitive_option.valFromOption(prim1) : undefined); -} - -function stop(prim) { - prim.stop(); -} - -function reset(prim) { - prim.reset(); -} - let StyleProp = {}; let FlatList = {}; @@ -114,19 +81,13 @@ let View = {}; export { Animation, - ValueAnimations, Interpolation, + ValueAnimations, ValueOperations, ValueMethods, Value, ValueXY, Color, - timing, - spring, - decay, - start, - stop, - reset, StyleProp, FlatList, Image, @@ -135,4 +96,4 @@ export { Text, View, } -/* react-native Not a pure module */ +/* No side effect */ diff --git a/src/apis/Clipboard.res b/src/apis/Clipboard.res index b646099a..0444e7ca 100644 --- a/src/apis/Clipboard.res +++ b/src/apis/Clipboard.res @@ -1,5 +1,13 @@ -@module("react-native") @scope("Clipboard") +@deprecated( + "Clipboard has been extracted from react-native core and will be removed in a future release, use @react-native-clipboard/clipboard instead." +) +@module("react-native") +@scope("Clipboard") external getString: unit => promise = "getString" -@module("react-native") @scope("Clipboard") +@deprecated( + "Clipboard has been extracted from react-native core and will be removed in a future release, use @react-native-clipboard/clipboard instead." +) +@module("react-native") +@scope("Clipboard") external setString: string => unit = "setString" diff --git a/src/apis/Color.res b/src/apis/Color.res index 007af732..7e4f3fc2 100644 --- a/src/apis/Color.res +++ b/src/apis/Color.res @@ -11,7 +11,7 @@ let rgba = (~r: int, ~g: int, ~b: int, ~a: float) => let hsl = (~h: float, ~s: float, ~l: float) => `hsl(${h->Float.toString}, ${s->Float.toString}%, ${l->Float.toString}%)` let hsla = (~h: float, ~s: float, ~l: float, ~a: float) => - `hsl(${h->Float.toString}, ${s->Float.toString}%, ${l->Float.toString}%, ${a->Float.toString})` + `hsla(${h->Float.toString}, ${s->Float.toString}%, ${l->Float.toString}%, ${a->Float.toString})` @inline let transparent = "transparent" diff --git a/src/apis/Color.res.js b/src/apis/Color.res.js index bacddb17..10997139 100644 --- a/src/apis/Color.res.js +++ b/src/apis/Color.res.js @@ -14,7 +14,7 @@ function hsl(h, s, l) { } function hsla(h, s, l, a) { - return `hsl(` + h.toString() + `, ` + s.toString() + `%, ` + l.toString() + `%, ` + a.toString() + `)`; + return `hsla(` + h.toString() + `, ` + s.toString() + `%, ` + l.toString() + `%, ` + a.toString() + `)`; } export { diff --git a/src/apis/DeviceEventEmitter.res b/src/apis/DeviceEventEmitter.res new file mode 100644 index 00000000..fe3ca62c --- /dev/null +++ b/src/apis/DeviceEventEmitter.res @@ -0,0 +1,12 @@ +@module("react-native") @scope("DeviceEventEmitter") +external addListener: (string, 'a => unit, ~context: 'context=?) => EventSubscription.t = + "addListener" + +@module("react-native") @scope("DeviceEventEmitter") +external emit: (string, 'a) => unit = "emit" + +@module("react-native") @scope("DeviceEventEmitter") +external removeAllListeners: (~eventType: string=?) => unit = "removeAllListeners" + +@module("react-native") @scope("DeviceEventEmitter") +external listenerCount: string => int = "listenerCount" diff --git a/src/apis/DeviceEventEmitter.res.js b/src/apis/DeviceEventEmitter.res.js new file mode 100644 index 00000000..ae1b9f17 --- /dev/null +++ b/src/apis/DeviceEventEmitter.res.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/src/apis/ErrorUtils.res b/src/apis/ErrorUtils.res new file mode 100644 index 00000000..415073f4 --- /dev/null +++ b/src/apis/ErrorUtils.res @@ -0,0 +1,18 @@ +/* + `ErrorUtils` global, installed by React Native + */ + +// receives the error (usually a JS `Error`, but anything can be thrown) and `isFatal` +type handler = (JsExn.t, bool) => unit + +@val @scope("ErrorUtils") +external setGlobalHandler: handler => unit = "setGlobalHandler" + +@val @scope("ErrorUtils") +external getGlobalHandler: unit => handler = "getGlobalHandler" + +@val @scope("ErrorUtils") +external reportError: JsExn.t => unit = "reportError" + +@val @scope("ErrorUtils") +external reportFatalError: JsExn.t => unit = "reportFatalError" diff --git a/src/apis/ErrorUtils.res.js b/src/apis/ErrorUtils.res.js new file mode 100644 index 00000000..ae1b9f17 --- /dev/null +++ b/src/apis/ErrorUtils.res.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/src/apis/EventEmitter.res b/src/apis/EventEmitter.res new file mode 100644 index 00000000..c9bc585d --- /dev/null +++ b/src/apis/EventEmitter.res @@ -0,0 +1,15 @@ +type t + +@new @module("react-native") +external make: unit => t = "EventEmitter" + +@send +external addListener: (t, string, 'a => unit, ~context: 'context=?) => EventSubscription.t = + "addListener" + +@send external emit: (t, string, 'a) => unit = "emit" + +@send +external removeAllListeners: (t, ~eventType: string=?) => unit = "removeAllListeners" + +@send external listenerCount: (t, string) => int = "listenerCount" diff --git a/src/apis/EventEmitter.res.js b/src/apis/EventEmitter.res.js new file mode 100644 index 00000000..ae1b9f17 --- /dev/null +++ b/src/apis/EventEmitter.res.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/src/apis/Global.res b/src/apis/Global.res index dd7c0fb0..5f09d465 100644 --- a/src/apis/Global.res +++ b/src/apis/Global.res @@ -2,3 +2,26 @@ @scope("global") @val external hermesInternal: option<{..}> = "HermesInternal" + +type immediateId + +@val external setImmediate: (unit => unit) => immediateId = "setImmediate" +@val external clearImmediate: immediateId => unit = "clearImmediate" + +@val external queueMicrotask: (unit => unit) => unit = "queueMicrotask" + +type idleCallbackId + +type idleDeadline = { + didTimeout: bool, + timeRemaining: unit => float, +} + +type idleRequestOptions = {timeout?: float} + +@val +external requestIdleCallback: ( + idleDeadline => unit, + ~options: idleRequestOptions=?, +) => idleCallbackId = "requestIdleCallback" +@val external cancelIdleCallback: idleCallbackId => unit = "cancelIdleCallback" diff --git a/src/apis/I18nManager.res b/src/apis/I18nManager.res new file mode 100644 index 00000000..d16935bf --- /dev/null +++ b/src/apis/I18nManager.res @@ -0,0 +1,25 @@ +type constants = { + isRTL: bool, + doLeftAndRightSwapInRTL: bool, + // This is usually only read and not created by the user. + // Therefore prefer option<...> to an optional field for easier matching. + localeIdentifier: option, +} + +@module("react-native") @scope("I18nManager") +external isRTL: bool = "isRTL" + +@module("react-native") @scope("I18nManager") +external doLeftAndRightSwapInRTL: bool = "doLeftAndRightSwapInRTL" + +@module("react-native") @scope("I18nManager") +external getConstants: unit => constants = "getConstants" + +@module("react-native") @scope("I18nManager") +external allowRTL: bool => unit = "allowRTL" + +@module("react-native") @scope("I18nManager") +external forceRTL: bool => unit = "forceRTL" + +@module("react-native") @scope("I18nManager") +external swapLeftAndRightInRTL: bool => unit = "swapLeftAndRightInRTL" diff --git a/src/apis/I18nManager.res.js b/src/apis/I18nManager.res.js new file mode 100644 index 00000000..ae1b9f17 --- /dev/null +++ b/src/apis/I18nManager.res.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/src/apis/InteractionManager.res b/src/apis/InteractionManager.res index 68e95d41..810ece49 100644 --- a/src/apis/InteractionManager.res +++ b/src/apis/InteractionManager.res @@ -4,15 +4,33 @@ type interactionHandle -@module("react-native") @scope("InteractionManager") -external /* @todo this returns a cancellable "promise", we need to type return correctly */ -runAfterInteractions: (unit => unit) => {.} = "runAfterInteractions" +// cancellable "promise" returned by `runAfterInteractions` +type task = {cancel: unit => unit} -@module("react-native") @scope("InteractionManager") +@deprecated( + "InteractionManager is deprecated by React Native: split long tasks into smaller ones and use `Global.requestIdleCallback` instead." +) +@module("react-native") +@scope("InteractionManager") +external runAfterInteractions: (unit => unit) => task = "runAfterInteractions" + +@deprecated( + "InteractionManager is deprecated by React Native: split long tasks into smaller ones and use `Global.requestIdleCallback` instead." +) +@module("react-native") +@scope("InteractionManager") external createInteractionHandle: unit => interactionHandle = "createInteractionHandle" -@module("react-native") @scope("InteractionManager") +@deprecated( + "InteractionManager is deprecated by React Native: split long tasks into smaller ones and use `Global.requestIdleCallback` instead." +) +@module("react-native") +@scope("InteractionManager") external clearInteractionHandle: interactionHandle => unit = "clearInteractionHandle" -@module("react-native") @scope("InteractionManager") +@deprecated( + "InteractionManager is deprecated by React Native: split long tasks into smaller ones and use `Global.requestIdleCallback` instead." +) +@module("react-native") +@scope("InteractionManager") external setDeadline: float => unit = "setDeadline" diff --git a/src/apis/ReactNativeVersion.res b/src/apis/ReactNativeVersion.res new file mode 100644 index 00000000..de585cd7 --- /dev/null +++ b/src/apis/ReactNativeVersion.res @@ -0,0 +1,14 @@ +@module("react-native") @scope("ReactNativeVersion") +external major: int = "major" + +@module("react-native") @scope("ReactNativeVersion") +external minor: int = "minor" + +@module("react-native") @scope("ReactNativeVersion") +external patch: int = "patch" + +@module("react-native") @scope("ReactNativeVersion") +external prerelease: Null.t = "prerelease" + +@module("react-native") @scope("ReactNativeVersion") +external getVersionString: unit => string = "getVersionString" diff --git a/src/apis/ReactNativeVersion.res.js b/src/apis/ReactNativeVersion.res.js new file mode 100644 index 00000000..ae1b9f17 --- /dev/null +++ b/src/apis/ReactNativeVersion.res.js @@ -0,0 +1 @@ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/src/apis/Style.res b/src/apis/Style.res index 3d4ad22a..e2455c4e 100644 --- a/src/apis/Style.res +++ b/src/apis/Style.res @@ -41,7 +41,7 @@ type transform @obj external translateY: (~translateY: size) => transform = "" @obj external skewX: (~skewX: angle) => transform = "" @obj external skewY: (~skewY: angle) => transform = "" -// @todo matrix +@obj external matrix: (~matrix: array) => transform = "" external unsafeTransform: {..} => transform = "%identity" @@ -120,19 +120,40 @@ type fontStyle = [#normal | #italic] type fontWeight = [#normal | #bold | #100 | #200 | #300 | #400 | #500 | #600 | #700 | #800 | #900] -// @todo in 0.71.0 -// Apparently there are more `fontVariant` options IOS specific -// (`stylistic-one` ... `stylistic-twenty`) but they are not documented. -// Found in the 0.71.0 changelog: -// https://github.com/facebook/react-native/blob/main/CHANGELOG.md#ios-specific-4 -// and found in code: -// https://github.com/facebook/react-native/blob/4e117cb09d208ca02f513d2101592d0ac10d4739/Libraries/StyleSheet/StyleSheetTypes.js#L784 type fontVariant = [ | #"small-caps" | #"oldstyle-nums" | #"lining-nums" | #"tabular-nums" + | #"common-ligatures" + | #"no-common-ligatures" + | #"discretionary-ligatures" + | #"no-discretionary-ligatures" + | #"historical-ligatures" + | #"no-historical-ligatures" + | #contextual + | #"no-contextual" | #"proportional-nums" + | #"stylistic-one" + | #"stylistic-two" + | #"stylistic-three" + | #"stylistic-four" + | #"stylistic-five" + | #"stylistic-six" + | #"stylistic-seven" + | #"stylistic-eight" + | #"stylistic-nine" + | #"stylistic-ten" + | #"stylistic-eleven" + | #"stylistic-twelve" + | #"stylistic-thirteen" + | #"stylistic-fourteen" + | #"stylistic-fifteen" + | #"stylistic-sixteen" + | #"stylistic-seventeen" + | #"stylistic-eighteen" + | #"stylistic-nineteen" + | #"stylistic-twenty" ] type textAlign = [#auto | #left | #right | #center | #justify] diff --git a/src/apis/Style.resi b/src/apis/Style.resi index 354db9af..b171eed0 100644 --- a/src/apis/Style.resi +++ b/src/apis/Style.resi @@ -37,7 +37,7 @@ type transform @obj external translateY: (~translateY: size) => transform = "" @obj external skewX: (~skewX: angle) => transform = "" @obj external skewY: (~skewY: angle) => transform = "" -// @todo matrix +@obj external matrix: (~matrix: array) => transform = "" external unsafeTransform: {..} => transform = "%identity" @@ -121,7 +121,35 @@ type fontVariant = [ | #"oldstyle-nums" | #"lining-nums" | #"tabular-nums" + | #"common-ligatures" + | #"no-common-ligatures" + | #"discretionary-ligatures" + | #"no-discretionary-ligatures" + | #"historical-ligatures" + | #"no-historical-ligatures" + | #contextual + | #"no-contextual" | #"proportional-nums" + | #"stylistic-one" + | #"stylistic-two" + | #"stylistic-three" + | #"stylistic-four" + | #"stylistic-five" + | #"stylistic-six" + | #"stylistic-seven" + | #"stylistic-eight" + | #"stylistic-nine" + | #"stylistic-ten" + | #"stylistic-eleven" + | #"stylistic-twelve" + | #"stylistic-thirteen" + | #"stylistic-fourteen" + | #"stylistic-fifteen" + | #"stylistic-sixteen" + | #"stylistic-seventeen" + | #"stylistic-eighteen" + | #"stylistic-nineteen" + | #"stylistic-twenty" ] type textAlign = [#auto | #left | #right | #center | #justify] diff --git a/src/apis/StyleSheet.res b/src/apis/StyleSheet.res index 58ae818e..294a8077 100644 --- a/src/apis/StyleSheet.res +++ b/src/apis/StyleSheet.res @@ -2,8 +2,6 @@ external hairlineWidth: float = "hairlineWidth" @module("react-native") @scope("StyleSheet") external absoluteFill: Style.t = "absoluteFill" -@module("react-native") @scope("StyleSheet") -external absoluteFillObject: Style.t = "absoluteFillObject" @module("react-native") @scope("StyleSheet") external create: ({..} as 'a) => ({..} as 'a) = "create" diff --git a/src/components/Button.res b/src/components/Button.res index dc56458c..f82f125e 100644 --- a/src/components/Button.res +++ b/src/components/Button.res @@ -11,7 +11,7 @@ type props = { accessible?: bool, color?: Color.t, disabled?: bool, - hasTVPreferredFocus?: bool, + @deprecated("Use `focusable` instead.") hasTVPreferredFocus?: bool, nextFocusDown?: int, nextFocusForward?: int, nextFocusLeft?: int, diff --git a/src/components/Image.res b/src/components/Image.res index 3f2e02f0..aeb403f2 100644 --- a/src/components/Image.res +++ b/src/components/Image.res @@ -108,7 +108,9 @@ type imageProps = { onLoadStart?: unit => unit, referrerPolicy?: referrerPolicy, resizeMode?: Style.resizeMode, - source: Source.t, + // `source`, `src` or `srcSet` + source?: Source.t, + src?: string, srcSet?: string, tintColor?: Color.t, width?: float, diff --git a/src/components/Pressable.res b/src/components/Pressable.res index bd60fcb3..737de5ed 100644 --- a/src/components/Pressable.res +++ b/src/components/Pressable.res @@ -36,6 +36,7 @@ type props = { ref?: ref, android_disableSound?: bool, android_ripple?: rippleConfig, + cancelable?: bool, children?: interactionState => React.element, delayLongPress?: int, disabled?: bool, @@ -47,6 +48,7 @@ type props = { onLongPress?: Event.pressEvent => unit, onPress?: Event.pressEvent => unit, onPressIn?: Event.pressEvent => unit, + onPressMove?: Event.pressEvent => unit, onPressOut?: Event.pressEvent => unit, pressRetentionOffset?: Rect.t, style?: interactionState => Style.t, diff --git a/src/components/ProgressBarAndroid.res b/src/components/ProgressBarAndroid.res index f6aa3a1f..f5c99766 100644 --- a/src/components/ProgressBarAndroid.res +++ b/src/components/ProgressBarAndroid.res @@ -22,5 +22,8 @@ type props = { styleAttr?: styleAttr, } +@deprecated( + "ProgressBarAndroid has been extracted from react-native core and will be removed in a future release, use @react-native-community/progress-bar-android instead." +) @module("react-native") external make: React.component = "ProgressBarAndroid" diff --git a/src/components/ScrollView.res b/src/components/ScrollView.res index d6e2667b..15f18551 100644 --- a/src/components/ScrollView.res +++ b/src/components/ScrollView.res @@ -25,6 +25,22 @@ type overScrollMode = [#always | #never | #auto] type snapToAlignment = [#start | #center | #end] +// an `Animated.Value`, see `Animated.Value.fromStickyHeaderScrollValue` +type stickyHeaderScrollAnimatedValue + +// These are only received by the component and not created by the user. +// Therefore prefer option<...> to optional fields for easier matching. +type stickyHeaderProps = { + children: option, + nextHeaderLayoutY: option, + onLayout: Event.layoutEvent => unit, + scrollAnimatedValue: stickyHeaderScrollAnimatedValue, + inverted: option, + scrollViewHeight: option, + nativeID: option, + hiddenOnScroll: option, +} + type maintainVisibleContentPosition = { autoscrollToTopThreshold?: float, minIndexForVisible: int, @@ -65,6 +81,7 @@ type androidProps = { nestedScrollEnabled?: bool, fadingEdgeLength?: float, persistentScrollbar?: bool, + scrollsChildToFocus?: bool, } type scrollViewPropsWithoutListConflict = { @@ -96,7 +113,7 @@ type scrollViewPropsWithoutListConflict = { stickyHeaderIndices?: array, disableIntervalMomentum?: bool, disableScrollViewPanResponder?: bool, - \"StickyHeaderComponent"?: React.element, + \"StickyHeaderComponent"?: React.component, } type scrollViewProps = { diff --git a/src/components/StatusBar.res b/src/components/StatusBar.res index 67556669..00ce3152 100644 --- a/src/components/StatusBar.res +++ b/src/components/StatusBar.res @@ -25,7 +25,7 @@ external setHidden: (bool, showHideTransition) => unit = "setHidden" @module("react-native") @scope("StatusBar") external setBarStyle: (barStyle, bool) => unit = "setBarStyle" -@module("react-native") @scope("StatusBar") +@deprecated("Deprecated by React Native.") @module("react-native") @scope("StatusBar") external setNetworkActivityIndicatorVisible: bool => unit = "setNetworkActivityIndicatorVisible" @module("react-native") @scope("StatusBar") diff --git a/src/components/TextInput.res b/src/components/TextInput.res index b9950562..afa258a9 100644 --- a/src/components/TextInput.res +++ b/src/components/TextInput.res @@ -1,9 +1,18 @@ include TextInputElement + +type selection = { + start: int, + end: int, +} + module ChangeEvent = { type payload = { eventCount: int, target: int, text: string, + // This is usually only used as a callback param and not created by the user. + // Therefore prefer option<...> to an optional field for easier matching. + selection: option, } include Event.SyntheticEvent({type _payload = payload}) @@ -42,11 +51,6 @@ module ScrollEvent = { type scrollEvent = ScrollEvent.t -type selection = { - start: int, - end: int, -} - module SelectionChangeEvent = { type payload = { selection: selection, @@ -264,7 +268,7 @@ type props = { autoComplete?: autoComplete, autoCorrect?: bool, autoFocus?: bool, - blurOnSubmit?: bool, + @deprecated("Use `submitBehavior` instead.") blurOnSubmit?: bool, submitBehavior?: submitBehavior, caretHidden?: bool, clearButtonMode?: clearButtonMode, @@ -282,6 +286,7 @@ type props = { importantForAutofill?: importantForAutofill, inlineImageLeft?: string, inlineImagePadding?: float, + inputAccessoryViewButtonLabel?: string, inputAccessoryViewID?: string, // `inputMode` has precedence over `keyboardType` inputMode?: inputMode, diff --git a/src/components/TouchableHighlight.res b/src/components/TouchableHighlight.res index c02336db..aab8a7c6 100644 --- a/src/components/TouchableHighlight.res +++ b/src/components/TouchableHighlight.res @@ -6,7 +6,7 @@ type props = { ref?: ref, ...TouchableWithoutFeedback.coreProps, activeOpacity?: float, - hasTVPreferredFocus?: bool, + @deprecated("Use `focusable` instead.") hasTVPreferredFocus?: bool, onHideUnderlay?: unit => unit, onShowUnderlay?: unit => unit, style?: Style.t, diff --git a/src/components/TouchableOpacity.res b/src/components/TouchableOpacity.res index d77ebd78..7ee41875 100644 --- a/src/components/TouchableOpacity.res +++ b/src/components/TouchableOpacity.res @@ -9,7 +9,7 @@ type props = { nextFocusLeft?: float, nextFocusRight?: float, nextFocusUp?: float, - hasTVPreferredFocus?: bool, + @deprecated("Use `focusable` instead.") hasTVPreferredFocus?: bool, style?: Style.t, tvParallaxProperties?: TV.parallax, } diff --git a/src/components/TouchableWithoutFeedback.res b/src/components/TouchableWithoutFeedback.res index dad06e27..d6929fc4 100644 --- a/src/components/TouchableWithoutFeedback.res +++ b/src/components/TouchableWithoutFeedback.res @@ -17,6 +17,7 @@ type coreProps = { onPressIn?: Event.pressEvent => unit, onPressOut?: Event.pressEvent => unit, pressRetentionOffset?: Rect.t, + rejectResponderTermination?: bool, testID?: string, touchSoundDisabled?: bool, children?: React.element, diff --git a/src/components/View.res b/src/components/View.res index 2e2f3d8d..5960921c 100644 --- a/src/components/View.res +++ b/src/components/View.res @@ -2,9 +2,6 @@ type nativeElement include NativeElement.Impl({type t = nativeElement}) -// @todo in 0.71.0 -// after adding `aria-*` props, make sure `aria-checked` can be true, false or "mixed" - type importantForAccessibility = Accessibility.importantForAccessibility type pointerEvents = [ @@ -29,6 +26,17 @@ type gestureResponderHandlersProps = { onStartShouldSetResponderCapture?: Event.pressEvent => bool, } +type touchEventProps = { + onTouchCancel?: Event.pressEvent => unit, + onTouchCancelCapture?: Event.pressEvent => unit, + onTouchEnd?: Event.pressEvent => unit, + onTouchEndCapture?: Event.pressEvent => unit, + onTouchMove?: Event.pressEvent => unit, + onTouchMoveCapture?: Event.pressEvent => unit, + onTouchStart?: Event.pressEvent => unit, + onTouchStartCapture?: Event.pressEvent => unit, +} + // W3C pointer handlers (excludes onClick — covered by webClickProps). type pointerEventProps = { onGotPointerCapture?: Event.pointerEvent => unit, @@ -55,8 +63,11 @@ type pointerEventProps = { type accessibilityProps = Accessibility.viewProps - -type iosProps = {shouldRasterizeIOS?: bool} +type iosProps = { + shouldRasterizeIOS?: bool, + // nativeID values of descendants, in accessibility focus order + experimental_accessibilityOrder?: array, +} @unboxed type tabIndex = | @as(0) Focusable | @as(-1) NotFocusable @@ -65,6 +76,12 @@ type androidProps = { renderToHardwareTextureAndroid?: bool, focusable?: bool, tabIndex?: tabIndex, + // native view tags (see `NativeMethods`) of the next view to focus + nextFocusDown?: int, + nextFocusForward?: int, + nextFocusLeft?: int, + nextFocusRight?: int, + nextFocusUp?: int, } type webLinkProps = { @@ -80,7 +97,9 @@ type webClickProps = { type webFocusProps = { onFocus?: ReactEvent.Focus.t => unit, + onFocusCapture?: ReactEvent.Focus.t => unit, onBlur?: ReactEvent.Focus.t => unit, + onBlurCapture?: ReactEvent.Focus.t => unit, } type webKeyboardProps = { @@ -129,6 +148,7 @@ type coreProps = { type viewPropsWithoutChildren = { ...gestureResponderHandlersProps, + ...touchEventProps, ...pointerEventProps, ...accessibilityProps, ...iosProps, diff --git a/src/components/VirtualizedList.res b/src/components/VirtualizedList.res index 913ecdbd..30f7253b 100644 --- a/src/components/VirtualizedList.res +++ b/src/components/VirtualizedList.res @@ -18,8 +18,17 @@ type renderItemProps<'item> = { type renderItemCallback<'item> = renderItemProps<'item> => React.element -// TODO -type cellRendererComponentProps<'item> = {.} +// These are only received by the component and not created by the user. +// Therefore prefer option<...> to optional fields for easier matching. +type cellRendererComponentProps<'item> = { + cellKey: string, + children: React.element, + index: int, + item: 'item, + onFocusCapture: option unit>, + onLayout: option unit>, + style: Style.t, +} type cellRendererComponent<'item> = React.component> type viewableItem<'item> = { diff --git a/src/types/Accessibility.res b/src/types/Accessibility.res index e30b3218..011e34b7 100644 --- a/src/types/Accessibility.res +++ b/src/types/Accessibility.res @@ -27,6 +27,8 @@ type value type liveRegion = [#none | #polite | #assertive] +type ariaLive = [#polite | #assertive | #off] + type role = [ | #adjustable | #alert @@ -87,6 +89,18 @@ type props = { accessibilityState?: state, accessibilityValue?: value, onAccessibilityAction?: actionEvent => unit, + // `aria-*` props have precedence over the matching `accessibility*` props + @as("aria-busy") ariaBusy?: bool, + @as("aria-checked") ariaChecked?: checked, + @as("aria-disabled") ariaDisabled?: bool, + @as("aria-expanded") ariaExpanded?: bool, + @as("aria-hidden") ariaHidden?: bool, + @as("aria-label") ariaLabel?: string, + @as("aria-selected") ariaSelected?: bool, + @as("aria-valuemax") ariaValuemax?: float, + @as("aria-valuemin") ariaValuemin?: float, + @as("aria-valuenow") ariaValuenow?: float, + @as("aria-valuetext") ariaValuetext?: string, } type iosProps = { @@ -94,6 +108,7 @@ type iosProps = { accessibilityIgnoresInvertColors?: bool, accessibilityLanguage?: string, accessibilityViewIsModal?: bool, + @as("aria-modal") ariaModal?: bool, onAccessibilityEscape?: unit => unit, onAccessibilityTap?: unit => unit, onMagicTap?: unit => unit, @@ -102,6 +117,8 @@ type iosProps = { type androidProps = { accessibilityLabelledBy?: array, accessibilityLiveRegion?: liveRegion, + @as("aria-labelledby") ariaLabelledby?: string, + @as("aria-live") ariaLive?: ariaLive, importantForAccessibility?: importantForAccessibility, } diff --git a/src/types/Accessibility.resi b/src/types/Accessibility.resi index ba25ed12..6bba3208 100644 --- a/src/types/Accessibility.resi +++ b/src/types/Accessibility.resi @@ -27,6 +27,8 @@ type value type liveRegion = [#none | #polite | #assertive] +type ariaLive = [#polite | #assertive | #off] + // `accessibilityRole` communicates the purpose of a component to the user of an assistive technology. // roles that are specific for react-native-web are also included: // article, banner, complementary, contentinfo, form, list, listItem, main, navigation, region @@ -90,6 +92,18 @@ type props = { accessibilityState?: state, accessibilityValue?: value, onAccessibilityAction?: actionEvent => unit, + // `aria-*` props have precedence over the matching `accessibility*` props + @as("aria-busy") ariaBusy?: bool, + @as("aria-checked") ariaChecked?: checked, + @as("aria-disabled") ariaDisabled?: bool, + @as("aria-expanded") ariaExpanded?: bool, + @as("aria-hidden") ariaHidden?: bool, + @as("aria-label") ariaLabel?: string, + @as("aria-selected") ariaSelected?: bool, + @as("aria-valuemax") ariaValuemax?: float, + @as("aria-valuemin") ariaValuemin?: float, + @as("aria-valuenow") ariaValuenow?: float, + @as("aria-valuetext") ariaValuetext?: string, } type iosProps = { @@ -97,6 +111,7 @@ type iosProps = { accessibilityIgnoresInvertColors?: bool, accessibilityLanguage?: string, accessibilityViewIsModal?: bool, + @as("aria-modal") ariaModal?: bool, onAccessibilityEscape?: unit => unit, onAccessibilityTap?: unit => unit, onMagicTap?: unit => unit, @@ -105,6 +120,8 @@ type iosProps = { type androidProps = { accessibilityLabelledBy?: array, accessibilityLiveRegion?: liveRegion, + @as("aria-labelledby") ariaLabelledby?: string, + @as("aria-live") ariaLive?: ariaLive, importantForAccessibility?: importantForAccessibility, }