React Native Modalfy

repository·main·Indexed 23 days ago

https://github.com/colorfy-software/react-native-modalfy

A logic-only library for managing complex modal stacks in React Native. It provides global access to trigger modals from anywhere, supports nested modal stacking, and offers full control over UI and animations. Key features include the useModal hook, withModal HOC, ModalProvider, and a configurable ModalOptions interface for managing transitions, back behavior, and backdrop styling.

Tokens
2.2K
Snippets
2
Records
14
Agent score
80%

What's inside react-native-modalfy

  1. Overview of React Native Modalfy

    main

    React Native Modalfy is a library designed to manage modal stacks in React Native applications. It provides the logic for managing modal lifecycles and stacks, while leaving the UI implementation and styling entirely to the developer.

    Key capabilities include:

    • Global Access: Write modal components once and trigger them from anywhere in your application.
    • Modal Stacking: Display multiple modals simultaneously, allowing for complex, nested modal stacks.
    • Animation Control: Complete control over animations and transitions between different modals in the stack.
  2. Define custom parameters with `ModalfyParams`

    main

    To ensure type safety when opening modals and retrieving parameters, you should extend ModalfyParams. This allows you to define the shape of the params object for each modal in your stack.

    By implementing ModalfyCustomParams, you can provide a mapping of modal names to their specific parameter types, which getParam will then respect.

  3. Configure ModalOptions for rendering and animation

    main

    The ModalOptions interface defines how a modal is rendered and animated. You can use these options globally in your stack configuration or locally on specific modal components.

    Key properties include:

    • animateInConfig / animateOutConfig: Configuration for Animated.timing() (e.g., { duration: 450, easing: Easing.inOut(Easing.exp) }).
    • animationIn / animationOut: Custom animation functions. animationOut must call the provided callback when the animation finishes.
    • backBehavior: Determines behavior for backdrop presses or Android back button. Options: 'pop', 'clear', or 'none' (default: 'pop').
    • backdropColor / backdropOpacity / backdropPosition: Controls the appearance and placement of the stack backdrop.
    • position: Vertical positioning of the modal. Options: 'center', 'top', or 'bottom' (default: 'center').
    • transitionOptions: A function that returns a style object using an Animated.Value for interpolations.
    • pointerEventsBehavior: Controls touch response. Options: 'auto', 'none', 'current-modal-only', or 'current-modal-none' (default: 'auto').
    // Example of custom animationIn
    const animationIn = (modalAnimatedValue, modalToValue, callback) => {
      Animated.timing(modalAnimatedValue, {
        toValue: modalToValue,
        duration: 300,
        easing: Easing.inOut(Easing.exp),
        useNativeDriver: true,
      }).start(() => callback?.());
    };
  4. Configure Metro for monorepo peer dependency resolution

    main

    When using react-native-modalfy in a monorepo or an example project structure, you may need to configure metro.config.js to prevent multiple versions of peer dependencies from being loaded. This is achieved by:

    1. Adding the root node_modules paths for peer dependencies to the resolver.blacklistRE (or resolver.blockList in newer Metro versions) to prevent Metro from watching/loading them from the root.
    2. Using resolver.extraNodeModules to alias those same peer dependencies to the specific versions located within the local example/node_modules folder.

    This ensures that only one version of each peer dependency is active in the bundler.

    const path = require('path')
    const exclusionList = require('metro-config/src/defaults/exclusionList')
    const escape = require('escape-string-regexp')
    const pak = require('../package.json')
    
    const root = path.resolve(__dirname, '..')
    
    const modules = Object.keys({
      ...pak.peerDependencies,
    })
    
    module.exports = {
      projectRoot: __dirname,
      watchFolders: [root],
    
      resolver: {
        // Exclude peer dependencies from the root node_modules
        blacklistRE: exclusionList(modules.map(m => new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`))),
    
        // Alias peer dependencies to the local example/node_modules
        extraNodeModules: modules.reduce((acc, name) => {
          acc[name] = path.join(__dirname, 'node_modules', name)
          return acc
        }, {}),
      },
    
      transformer: {
        getTransformOptions: async () => ({
          transform: {
            experimentalImportSupport: false,
            inlineRequires: true,
          },
        }),
      },
    }
  5. Use the `modal` prop in regular components

    main

    When using ModalProp, the modal object provides methods to control the modal stack from anywhere in your application.

    Available methods:

    • openModal(modalName, params, callback): Opens a modal by name with optional parameters.
    • closeModal(modalName, callback): Closes the specified modal (or the current one if no name is provided).
    • closeModals(modalName, callback): Closes all instances of a specific modal name.
    • closeAllModals(callback): Closes every open modal in the stack.
    • currentModal: Returns the name of the currently active modal, or null.
  6. Listen to modal events with `addListener`

    main

    You can attach listeners to a modal component to respond to its lifecycle events. Supported event names are 'onAnimate' and 'onClose'.

    • 'onAnimate': Triggered during the animation phase. The callback receives the current animation value.
    • 'onClose': Triggered when the modal is closing. The callback receives a ModalClosingAction object containing the type (e.g., 'closeModal') and the origin (e.g., 'default', 'fling', or 'backdrop').

    Always remember to call .remove() on the returned ModalEventListener to prevent memory leaks.

  7. Use the `modal` prop in modal components

    main

    Modal components (those defined in your createModalStack config) receive a specialized UsableModalComponentProp. This allows the component to interact with its own lifecycle and parameters.

    Available properties/methods:

    • getParam(paramName, defaultValue): Retrieves a value from the params passed during openModal.
    • addListener(eventName, handler): Hooks into 'onAnimate' or 'onClose' events.
    • setModalOptions(modalOptions): Dynamically updates the options for the current modal instance.
    • closeModal(modalName, callback): Closes the current modal.
    • params: The parameters passed to this specific modal instance.
    • removeAllListeners(): Cleans up all registered event listeners.