From 257a24166eaf94aa96192c48a5ce7ba12ab02282 Mon Sep 17 00:00:00 2001
From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com>
Date: Sun, 8 Jan 2023 04:22:41 -0800
Subject: [PATCH] Chore: Mobile: Migrate action button to `react-native-paper`
(#7477)
---
.eslintignore | 3 +
.gitignore | 3 +
.../net/cozic/joplin/MainApplication.java | 1 +
packages/app-mobile/android/settings.gradle | 2 +
.../app-mobile/components/ActionButton.tsx | 73 ++++++++
.../app-mobile/components/action-button.js | 169 ------------------
.../app-mobile/components/screens/Note.tsx | 12 +-
.../app-mobile/components/screens/notes.js | 45 ++++-
packages/app-mobile/ios/Podfile.lock | 14 +-
packages/app-mobile/package.json | 2 +
packages/app-mobile/root.tsx | 24 ++-
packages/lib/reducer.ts | 3 +-
yarn.lock | 51 +++++-
13 files changed, 218 insertions(+), 184 deletions(-)
create mode 100644 packages/app-mobile/components/ActionButton.tsx
delete mode 100644 packages/app-mobile/components/action-button.js
diff --git a/.eslintignore b/.eslintignore
index 1ab0d68eeb..29aed09957 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -864,6 +864,9 @@ packages/app-desktop/utils/markupLanguageUtils.js.map
packages/app-mobile/PluginAssetsLoader.d.ts
packages/app-mobile/PluginAssetsLoader.js
packages/app-mobile/PluginAssetsLoader.js.map
+packages/app-mobile/components/ActionButton.d.ts
+packages/app-mobile/components/ActionButton.js
+packages/app-mobile/components/ActionButton.js.map
packages/app-mobile/components/BackButtonDialogBox.d.ts
packages/app-mobile/components/BackButtonDialogBox.js
packages/app-mobile/components/BackButtonDialogBox.js.map
diff --git a/.gitignore b/.gitignore
index b28b45df3c..0e23f6a993 100644
--- a/.gitignore
+++ b/.gitignore
@@ -852,6 +852,9 @@ packages/app-desktop/utils/markupLanguageUtils.js.map
packages/app-mobile/PluginAssetsLoader.d.ts
packages/app-mobile/PluginAssetsLoader.js
packages/app-mobile/PluginAssetsLoader.js.map
+packages/app-mobile/components/ActionButton.d.ts
+packages/app-mobile/components/ActionButton.js
+packages/app-mobile/components/ActionButton.js.map
packages/app-mobile/components/BackButtonDialogBox.d.ts
packages/app-mobile/components/BackButtonDialogBox.js
packages/app-mobile/components/BackButtonDialogBox.js.map
diff --git a/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/MainApplication.java b/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/MainApplication.java
index e5740b5868..b421afe7e6 100644
--- a/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/MainApplication.java
+++ b/packages/app-mobile/android/app/src/main/java/net/cozic/joplin/MainApplication.java
@@ -9,6 +9,7 @@ import androidx.multidex.MultiDex;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
+import com.oblador.vectoricons.VectorIconsPackage;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
diff --git a/packages/app-mobile/android/settings.gradle b/packages/app-mobile/android/settings.gradle
index 060030b35b..c36bb7a80d 100644
--- a/packages/app-mobile/android/settings.gradle
+++ b/packages/app-mobile/android/settings.gradle
@@ -1,4 +1,6 @@
rootProject.name = 'Joplin'
+include ':react-native-vector-icons'
+project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android')
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
include ':app'
includeBuild('../node_modules/react-native-gradle-plugin')
diff --git a/packages/app-mobile/components/ActionButton.tsx b/packages/app-mobile/components/ActionButton.tsx
new file mode 100644
index 0000000000..d687ca3b89
--- /dev/null
+++ b/packages/app-mobile/components/ActionButton.tsx
@@ -0,0 +1,73 @@
+const React = require('react');
+import { useState, useCallback, useMemo } from 'react';
+
+const Icon = require('react-native-vector-icons/Ionicons').default;
+import { FAB, Portal } from 'react-native-paper';
+import { _ } from '@joplin/lib/locale';
+
+
+type OnButtonPress = ()=> void;
+interface ButtonSpec {
+ icon: string;
+ label: string;
+ color?: string;
+ onPress?: OnButtonPress;
+}
+
+interface ActionButtonProps {
+ buttons?: ButtonSpec[];
+
+ // If not given, an "add" button will be used.
+ mainButton?: ButtonSpec;
+}
+
+const defaultOnPress = () => {};
+
+// Returns a render function compatible with React Native Paper.
+const getIconRenderFunction = (iconName: string) => {
+ return (props: any) => ;
+};
+
+const useIcon = (iconName: string) => {
+ return useMemo(() => {
+ return getIconRenderFunction(iconName);
+ }, [iconName]);
+};
+
+const ActionButton = (props: ActionButtonProps) => {
+ const [open, setOpen] = useState(false);
+ const onMenuToggled = useCallback(
+ (state: { open: boolean }) => setOpen(state.open)
+ , [setOpen]);
+
+
+ const actions = useMemo(() => (props.buttons ?? []).map(button => {
+ return {
+ ...button,
+ icon: getIconRenderFunction(button.icon),
+ onPress: button.onPress ?? defaultOnPress,
+ };
+ }), [props.buttons]);
+
+ const closedIcon = useIcon(props.mainButton?.icon ?? 'md-add');
+ const openIcon = useIcon('close');
+
+ return (
+
+
+
+ );
+};
+
+export default ActionButton;
diff --git a/packages/app-mobile/components/action-button.js b/packages/app-mobile/components/action-button.js
deleted file mode 100644
index ca2f804cba..0000000000
--- a/packages/app-mobile/components/action-button.js
+++ /dev/null
@@ -1,169 +0,0 @@
-const React = require('react');
-
-const { StyleSheet } = require('react-native');
-const Note = require('@joplin/lib/models/Note').default;
-const Icon = require('react-native-vector-icons/Ionicons').default;
-const ReactNativeActionButton = require('react-native-action-button').default;
-const { connect } = require('react-redux');
-const { _ } = require('@joplin/lib/locale');
-
-// We need this to suppress the useless warning
-// https://github.com/oblador/react-native-vector-icons/issues/1465
-Icon.loadFont().catch((error) => { console.info(error); });
-
-const styles = StyleSheet.create({
- actionButtonIcon: {
- fontSize: 20,
- height: 22,
- color: 'white',
- },
- itemText: {
- // fontSize: 14, // Cannot currently set fontsize since the bow surrounding the label has a fixed size
- },
-});
-
-class ActionButtonComponent extends React.Component {
- constructor() {
- super();
- this.state = {
- buttonIndex: 0,
- };
-
- this.renderIconMultiStates = this.renderIconMultiStates.bind(this);
- this.renderIcon = this.renderIcon.bind(this);
- }
-
- UNSAFE_componentWillReceiveProps(newProps) {
- if ('buttonIndex' in newProps) {
- this.setState({ buttonIndex: newProps.buttonIndex });
- }
- }
-
- async newNoteNavigate(folderId, isTodo) {
- const newNote = await Note.save({
- parent_id: folderId,
- is_todo: isTodo ? 1 : 0,
- }, { provisional: true });
-
- this.props.dispatch({
- type: 'NAV_GO',
- routeName: 'Note',
- noteId: newNote.id,
- });
- }
-
- newTodo_press() {
- this.newNoteNavigate(this.props.parentFolderId, true);
- }
-
- newNote_press() {
- this.newNoteNavigate(this.props.parentFolderId, false);
- }
-
- renderIconMultiStates() {
- const button = this.props.buttons[this.state.buttonIndex];
-
- return ;
- }
-
- renderIcon() {
- const mainButton = this.props.mainButton ? this.props.mainButton : {};
- const iconName = mainButton.icon ?? 'md-add';
-
- // Icons don't have alt text by default. We need to add it:
- const iconTitle = mainButton.title ?? _('Add new');
-
- // TODO: If the button toggles a sub-menu, state whether the submenu is open
- // or closed.
-
- return (
-
- );
- }
-
- render() {
- const buttons = this.props.buttons ? this.props.buttons : [];
-
- if (this.props.addFolderNoteButtons) {
- if (this.props.folders.length) {
- buttons.push({
- title: _('New to-do'),
- onPress: () => {
- this.newTodo_press();
- },
- color: '#9b59b6',
- icon: 'md-checkbox-outline',
- });
-
- buttons.push({
- title: _('New note'),
- onPress: () => {
- this.newNote_press();
- },
- color: '#9b59b6',
- icon: 'md-document',
- });
- }
- }
-
- const buttonComps = [];
- for (let i = 0; i < buttons.length; i++) {
- const button = buttons[i];
- const buttonTitle = button.title ? button.title : '';
- const key = `${buttonTitle.replace(/\s/g, '_')}_${button.icon}`;
- buttonComps.push(
- // TODO: By default, ReactNativeActionButton also adds a title, which is focusable
- // by the screen reader. As such, each item currently is double-focusable
-
-
-
- );
- }
-
- if (!buttonComps.length && !this.props.mainButton) {
- return null;
- }
-
- if (this.props.multiStates) {
- if (!this.props.buttons || !this.props.buttons.length) throw new Error('Multi-state button requires at least one state');
- if (this.state.buttonIndex < 0 || this.state.buttonIndex >= this.props.buttons.length) throw new Error(`Button index out of bounds: ${this.state.buttonIndex}/${this.props.buttons.length}`);
- const button = this.props.buttons[this.state.buttonIndex];
- return (
- {
- button.onPress();
- }}
- />
- );
- } else {
- return (
-
- {buttonComps}
-
- );
- }
- }
-}
-
-const ActionButton = connect(state => {
- return {
- folders: state.folders,
- locale: state.settings.locale,
- };
-})(ActionButtonComponent);
-
-module.exports = { ActionButton };
diff --git a/packages/app-mobile/components/screens/Note.tsx b/packages/app-mobile/components/screens/Note.tsx
index 2d9eb17179..8552bd5e63 100644
--- a/packages/app-mobile/components/screens/Note.tsx
+++ b/packages/app-mobile/components/screens/Note.tsx
@@ -22,7 +22,7 @@ const md5 = require('md5');
const { BackButtonService } = require('../../services/back-button.js');
import NavService from '@joplin/lib/services/NavService';
import BaseModel from '@joplin/lib/BaseModel';
-const { ActionButton } = require('../action-button.js');
+import ActionButton from '../ActionButton';
const { fileExtension, safeFileExtension } = require('@joplin/lib/path-utils');
const mimeUtils = require('@joplin/lib/mime-utils.js').mime;
import ScreenHeader from '../ScreenHeader';
@@ -1145,21 +1145,19 @@ class NoteScreenComponent extends BaseScreenComponent {
}
const renderActionButton = () => {
- const buttons = [];
-
- buttons.push({
- title: _('Edit'),
+ const editButton = {
+ label: _('Edit'),
icon: 'md-create',
onPress: () => {
this.setState({ mode: 'edit' });
this.doFocusUpdate_ = true;
},
- });
+ };
if (this.state.mode === 'edit') return null;
- return ;
+ return ;
};
const actionButtonComp = renderActionButton();
diff --git a/packages/app-mobile/components/screens/notes.js b/packages/app-mobile/components/screens/notes.js
index bc4c6d747d..5ce6926952 100644
--- a/packages/app-mobile/components/screens/notes.js
+++ b/packages/app-mobile/components/screens/notes.js
@@ -11,7 +11,7 @@ const Setting = require('@joplin/lib/models/Setting').default;
const { themeStyle } = require('../global-style.js');
const { ScreenHeader } = require('../ScreenHeader');
const { _ } = require('@joplin/lib/locale');
-const { ActionButton } = require('../action-button.js');
+const ActionButton = require('../ActionButton').default;
const { dialogs } = require('../../utils/dialogs.js');
const DialogBox = require('react-native-dialogbox').default;
const { BaseScreenComponent } = require('../base-screen.js');
@@ -179,6 +179,19 @@ class NotesScreenComponent extends BaseScreenComponent {
});
}
+ newNoteNavigate = async (folderId, isTodo) => {
+ const newNote = await Note.save({
+ parent_id: folderId,
+ is_todo: isTodo ? 1 : 0,
+ }, { provisional: true });
+
+ this.props.dispatch({
+ type: 'NAV_GO',
+ routeName: 'Note',
+ noteId: newNote.id,
+ });
+ };
+
parentItem(props = null) {
if (!props) props = this.props;
@@ -238,7 +251,35 @@ class NotesScreenComponent extends BaseScreenComponent {
const addFolderNoteButtons = !!buttonFolderId;
const thisComp = this;
- const actionButtonComp = this.props.noteSelectionEnabled || !this.props.visible ? null : ;
+
+ const makeActionButtonComp = () => {
+ if (addFolderNoteButtons && this.props.folders.length > 0) {
+ const buttons = [];
+ buttons.push({
+ label: _('New to-do'),
+ onPress: () => {
+ const isTodo = true;
+ this.newNoteNavigate(buttonFolderId, isTodo);
+ },
+ color: '#9b59b6',
+ icon: 'md-checkbox-outline',
+ });
+
+ buttons.push({
+ label: _('New note'),
+ onPress: () => {
+ const isTodo = false;
+ this.newNoteNavigate(buttonFolderId, isTodo);
+ },
+ color: '#9b59b6',
+ icon: 'md-document',
+ });
+ return ;
+ }
+ return null;
+ };
+
+ const actionButtonComp = this.props.noteSelectionEnabled || !this.props.visible ? null : makeActionButtonComp();
return (
diff --git a/packages/app-mobile/ios/Podfile.lock b/packages/app-mobile/ios/Podfile.lock
index c75249dbaf..0d9a423a31 100644
--- a/packages/app-mobile/ios/Podfile.lock
+++ b/packages/app-mobile/ios/Podfile.lock
@@ -248,6 +248,12 @@ PODS:
- React-Core
- react-native-rsa-native (2.0.5):
- React
+ - react-native-safe-area-context (4.4.1):
+ - RCT-Folly
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - ReactCommon/turbomodule/core
- react-native-slider (4.4.0):
- React-Core
- react-native-sqlite-storage (6.0.1):
@@ -376,6 +382,7 @@ DEPENDENCIES:
- react-native-image-resizer (from `../node_modules/react-native-image-resizer`)
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
- react-native-rsa-native (from `../node_modules/react-native-rsa-native`)
+ - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
- "react-native-slider (from `../node_modules/@react-native-community/slider`)"
- react-native-sqlite-storage (from `../node_modules/react-native-sqlite-storage`)
- react-native-version-info (from `../node_modules/react-native-version-info`)
@@ -469,6 +476,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/@react-native-community/netinfo"
react-native-rsa-native:
:path: "../node_modules/react-native-rsa-native"
+ react-native-safe-area-context:
+ :path: "../node_modules/react-native-safe-area-context"
react-native-slider:
:path: "../node_modules/@react-native-community/slider"
react-native-sqlite-storage:
@@ -530,10 +539,10 @@ SPEC CHECKSUMS:
FBLazyVector: 2b47ff52037bd9ae07cc9b051c9975797814b736
FBReactNativeSpec: 0e0d384ef17a33b385f13f0c7f97702c7cd17858
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
- glog: 476ee3e89abb49e07f822b48323c51c57124b572
+ glog: 5337263514dd6f09803962437687240c5dc39aa4
JoplinCommonShareExtension: a8b60b02704d85a7305627912c0240e94af78db7
JoplinRNShareExtension: 485f3e6dad83b7b77f1572eabc249f869ee55c02
- RCT-Folly: 4d8508a426467c48885f1151029bc15fa5d7b3b8
+ RCT-Folly: a21c126816d8025b547704b777a2ba552f3d9fa9
RCTRequired: 0f06b6068f530932d10e1a01a5352fad4eaacb74
RCTTypeSafety: b0ee81f10ef1b7d977605a2b266823dabd565e65
React: 3becd12bd51ea8a43bdde7e09d0f40fba7820e03
@@ -556,6 +565,7 @@ SPEC CHECKSUMS:
react-native-image-resizer: d9fb629a867335bdc13230ac2a58702bb8c8828f
react-native-netinfo: 2517ad504b3d303e90d7a431b0fcaef76d207983
react-native-rsa-native: 12132eb627797529fdb1f0d22fd0f8f9678df64a
+ react-native-safe-area-context: 99b24a0c5acd0d5dcac2b1a7f18c49ea317be99a
react-native-slider: d2938a12c4e439a227c70eec65d119136eb4aeb5
react-native-sqlite-storage: f6d515e1c446d1e6d026aa5352908a25d4de3261
react-native-version-info: a106f23009ac0db4ee00de39574eb546682579b9
diff --git a/packages/app-mobile/package.json b/packages/app-mobile/package.json
index 21ac09686c..4e7af138ad 100644
--- a/packages/app-mobile/package.json
+++ b/packages/app-mobile/package.json
@@ -51,9 +51,11 @@
"react-native-image-picker": "4.10.3",
"react-native-image-resizer": "1.4.5",
"react-native-modal-datetime-picker": "14.0.1",
+ "react-native-paper": "5.0.2",
"react-native-popup-menu": "0.16.1",
"react-native-quick-actions": "0.3.13",
"react-native-rsa-native": "2.0.5",
+ "react-native-safe-area-context": "4.4.1",
"react-native-securerandom": "1.0.1",
"react-native-share": "8.1.0",
"react-native-side-menu-updated": "1.3.2",
diff --git a/packages/app-mobile/root.tsx b/packages/app-mobile/root.tsx
index 34b08872e8..fdc5423966 100644
--- a/packages/app-mobile/root.tsx
+++ b/packages/app-mobile/root.tsx
@@ -36,6 +36,7 @@ const DropdownAlert = require('react-native-dropdownalert').default;
const AlarmServiceDriver = require('./services/AlarmServiceDriver').default;
const SafeAreaView = require('./components/SafeAreaView');
const { connect, Provider } = require('react-redux');
+import { Provider as PaperProvider, MD2DarkTheme as PaperDarkTheme, MD2LightTheme as PaperLightTheme } from 'react-native-paper';
const { BackButtonService } = require('./services/back-button.js');
import NavService from '@joplin/lib/services/NavService';
import { createStore, applyMiddleware } from 'redux';
@@ -108,6 +109,7 @@ import SyncTargetNone from '@joplin/lib/SyncTargetNone';
import { setRSA } from '@joplin/lib/services/e2ee/ppk';
import RSA from './services/e2ee/RSA.react-native';
import { runIntegrationTests } from '@joplin/lib/services/e2ee/ppkTestUtils';
+import { Theme, ThemeAppearance } from '@joplin/lib/themes/type';
import { AppState } from './utils/types';
import sensorInfo from './components/biometrics/sensorInfo';
@@ -881,7 +883,7 @@ class AppComponent extends React.Component {
public render() {
if (this.props.appState !== 'ready') return null;
- const theme = themeStyle(this.props.themeId);
+ const theme: Theme = themeStyle(this.props.themeId);
let sideMenuContent = null;
let menuPosition = 'left';
@@ -912,7 +914,7 @@ class AppComponent extends React.Component {
// const statusBarStyle = theme.appearance === 'light-content';
const statusBarStyle = 'light-content';
- return (
+ const mainContent = (
);
+
+
+ const paperTheme = theme.appearance === ThemeAppearance.Dark ? PaperDarkTheme : PaperLightTheme;
+
+ // Wrap everything in a PaperProvider -- this allows using components from react-native-paper
+ return (
+
+ {mainContent}
+
+ );
}
}
diff --git a/packages/lib/reducer.ts b/packages/lib/reducer.ts
index 7d3214ba9a..01017cf2fe 100644
--- a/packages/lib/reducer.ts
+++ b/packages/lib/reducer.ts
@@ -7,6 +7,7 @@ import BaseModel from './BaseModel';
import { Store } from 'redux';
import { ProfileConfig } from './services/profileConfig/types';
import * as ArrayUtils from './ArrayUtils';
+import { FolderEntity } from './services/database/types';
const fastDeepEqual = require('fast-deep-equal');
const { ALL_NOTES_FILTER_ID } = require('./reserved-ids');
const { createSelectorCreator, defaultMemoize } = require('reselect');
@@ -55,7 +56,7 @@ export interface State {
noteSelectionEnabled?: boolean;
notesSource: string;
notesParentType: string;
- folders: any[];
+ folders: FolderEntity[];
tags: any[];
masterKeys: any[];
notLoadedMasterKeys: string[];
diff --git a/yarn.lock b/yarn.lock
index f225ef5b98..d5b820e987 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3150,6 +3150,18 @@ __metadata:
languageName: node
linkType: hard
+"@callstack/react-theme-provider@npm:^3.0.8":
+ version: 3.0.8
+ resolution: "@callstack/react-theme-provider@npm:3.0.8"
+ dependencies:
+ deepmerge: ^3.2.0
+ hoist-non-react-statics: ^3.3.0
+ peerDependencies:
+ react: ">=16.3.0"
+ checksum: 6077a4795aea4eb06a2a2ffe5cf299c3fdcba56530aa68eba5c3ac0728ce02be2f6e9e71278be303065cb7fbe252c35639538477d5d05ee14f6325d550c8c696
+ languageName: node
+ linkType: hard
+
"@cloudcmd/create-element@npm:^2.0.0":
version: 2.0.2
resolution: "@cloudcmd/create-element@npm:2.0.2"
@@ -4732,9 +4744,11 @@ __metadata:
react-native-image-picker: 4.10.3
react-native-image-resizer: 1.4.5
react-native-modal-datetime-picker: 14.0.1
+ react-native-paper: 5.0.2
react-native-popup-menu: 0.16.1
react-native-quick-actions: 0.3.13
react-native-rsa-native: 2.0.5
+ react-native-safe-area-context: 4.4.1
react-native-securerandom: 1.0.1
react-native-share: 8.1.0
react-native-side-menu-updated: 1.3.2
@@ -11994,7 +12008,7 @@ __metadata:
languageName: node
linkType: hard
-"color@npm:3.2.1":
+"color@npm:3.2.1, color@npm:^3.1.2":
version: 3.2.1
resolution: "color@npm:3.2.1"
dependencies:
@@ -27687,6 +27701,22 @@ __metadata:
languageName: node
linkType: hard
+"react-native-paper@npm:5.0.2":
+ version: 5.0.2
+ resolution: "react-native-paper@npm:5.0.2"
+ dependencies:
+ "@callstack/react-theme-provider": ^3.0.8
+ color: ^3.1.2
+ use-event-callback: ^0.1.0
+ peerDependencies:
+ react: "*"
+ react-native: "*"
+ react-native-safe-area-context: "*"
+ react-native-vector-icons: "*"
+ checksum: 46481e3db2b297f2f02d1d05710d7ab329f901acc5a663e4c81fb7db83534e5d63067e9287bb396703e50d955ddfb8c41d7546cbd1ea2825a6888fd2e0fa80de
+ languageName: node
+ linkType: hard
+
"react-native-popup-menu@npm:0.16.1":
version: 0.16.1
resolution: "react-native-popup-menu@npm:0.16.1"
@@ -27708,6 +27738,16 @@ __metadata:
languageName: node
linkType: hard
+"react-native-safe-area-context@npm:4.4.1":
+ version: 4.4.1
+ resolution: "react-native-safe-area-context@npm:4.4.1"
+ peerDependencies:
+ react: "*"
+ react-native: "*"
+ checksum: ef7c41ea59a34b114c6481fb130e66ef85e8d5b88acb46279131367761ca9fbf22cd310fe613f49b6c9b56dbd83e044be640f0532eda1d3856bf708e96335a35
+ languageName: node
+ linkType: hard
+
"react-native-securerandom@npm:1.0.1":
version: 1.0.1
resolution: "react-native-securerandom@npm:1.0.1"
@@ -33141,6 +33181,15 @@ __metadata:
languageName: node
linkType: hard
+"use-event-callback@npm:^0.1.0":
+ version: 0.1.0
+ resolution: "use-event-callback@npm:0.1.0"
+ peerDependencies:
+ react: ">=16.8"
+ checksum: 1e15fb21306c74f877e9d57686546c363165429412dcb9260254d2dd8f56692cb01ba2162f9169e6fc15b01cf3921b9cd8a9c60cf777d0143afcee92c1a7976a
+ languageName: node
+ linkType: hard
+
"use-isomorphic-layout-effect@npm:^1.1.2":
version: 1.1.2
resolution: "use-isomorphic-layout-effect@npm:1.1.2"