Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Alert: implementation #1026

Open
necolas opened this issue Jul 7, 2018 · 30 comments
Open

Alert: implementation #1026

necolas opened this issue Jul 7, 2018 · 30 comments
Labels
project:react-native-web Issue associated with react-native-web

Comments

@necolas
Copy link
Owner

necolas commented Jul 7, 2018

https://facebook.github.io/react-native/docs/alert

@piranna
Copy link

piranna commented Jul 7, 2018

https://github.com/piranna/react-native-web-extended/blob/master/src/apis/Alert/index.js

@Kif11
Copy link

Kif11 commented Oct 12, 2018

@necolas can you please merge this changes.

@RichardLindhout
Copy link
Contributor

RichardLindhout commented Jan 18, 2019

For now I do something like this to workaround this.

const alertTitle = 'Foutmelding'
const alertText = 'Geen toegang tot locatiedata'
if (Platform.OS === 'web') {
   alert(alertText)
} else {
    Alert.alert(alertTitle, alertText)
}

@piranna
Copy link

piranna commented Jan 18, 2019

Browser alert() is blocking, so it's not recomended to use. Not sure why it's not deprecated yet...

@vlimag
Copy link

vlimag commented Feb 1, 2019

Does react-native-web supports Alert already?

@steida
Copy link

steida commented Feb 2, 2019

@vlimag Check readme https://github.com/necolas/react-native-web#modules

@arqex
Copy link

arqex commented May 21, 2019

What do you think about implementing it using react portals? We can inject the node in the dom and use a portal to show/hide.

We can ship simple styling for it and create a way to let the developer customize the appearance and the appearing/hiding transition.

@vlimag
Copy link

vlimag commented May 21, 2019

What I've done so far.
one file for default react native alert, and one file for react web alert.
Alert. js

import { Alert } from 'react-native'

export const StdAlert = (title, desc, onPress = () => { }) => {
  Alert.alert(
    title,
    desc,
    [
      { text: 'OK', onPress: () => onPress() }
    ],
    { cancelable: false }
  )
}

export const BinaryAlert = (title, desc, onPositivePress = () => {}, onNegativePress = () => {}) => {
  Alert.alert(
    title,
    desc,
    [
      { text: 'Sim', onPress: () => onPositivePress() },
      { text: 'Não', onPress: () => onNegativePress() }
    ],
    { cancelable: false }
  )
}

and for web, Alert.web.js

export const StdAlert = (title, desc, onPress = () => {}) => {
  alert(`${title}\n${desc}`)
  if (onPress) onPress()
}

export const BinaryAlert = (title, desc, onPositivePress = () => {}, onNegativePress = () => {}) => {
  const res = window.confirm(`${title}\n${desc}`)
  if (res) onPositivePress()
  else onNegativePress()
}

Then use it as following:

import {StdAlert, BinaryAlert} from ...

StdAlert('title', 'desc', ()=>action())
BinaryAlert('title', 'desc', ()=>positiveAction(), ()=>negativeAction())

@arqex arqex mentioned this issue Jun 10, 2019
@joan-saum
Copy link

@vlimag , how about dependencies which use the Alert from react native ? (#1366)

@vlimag
Copy link

vlimag commented Jun 12, 2019

@joan-saum As a provisory solution you should probably fork the dependency, change as necessary - following the example above - and publish to npm to use it.
Hopefully React native alert will be available at some time on React Native Web

@tonypee
Copy link

tonypee commented Jul 1, 2019

I just created my own alert popup for web, using native-base - works pretty well

https://gist.github.com/tonypee/f3ebb3a6f89e6d73255a5823092b24c6

it needs to be instantiated in the root of the app too

@joshbalfour
Copy link

joshbalfour commented Aug 24, 2020

very quick and dirty polyfill I whipped up if anyone else got super stuck by this:

import { Alert, Platform } from 'react-native'

const alertPolyfill = (title, description, options, extra) => {
    const result = window.confirm([title, description].filter(Boolean).join('\n'))

    if (result) {
        const confirmOption = options.find(({ style }) => style !== 'cancel')
        confirmOption && confirmOption.onPress()
    } else {
        const cancelOption = options.find(({ style }) => style === 'cancel')
        cancelOption && cancelOption.onPress()
    }
}

const alert = Platform.OS === 'web' ? alertPolyfill : Alert.alert

export default alert

Usage:

Before:

import { Alert } from 'react-native'
Alert.alert(
    ...
)

After:

import alert from './alert'
alert(
    ...
)

@benceg
Copy link

benceg commented Sep 5, 2020

Thank you @joshbalfour.

Here's roughly the same in TypeScript for those who need it. Written as a singleton in order to be able to implement AlertStatic symmetrically from React Native and call it via Alert.alert.

// Alert.web.ts
import { AlertButton, AlertStatic } from 'react-native';

class WebAlert implements Pick<AlertStatic, 'alert'> {
  public alert(title: string, message?: string, buttons?: AlertButton[]): void {
    if (buttons === undefined || buttons.length === 0) {
      window.alert([title, message].filter(Boolean).join('\n'));
      return;
    }

    const result = window.confirm([title, message].filter(Boolean).join('\n'));

    if (result === true) {
      const confirm = buttons.find(({ style }) => style !== 'cancel');
      confirm?.onPress?.();
      return;
    }

    const cancel = buttons.find(({ style }) => style === 'cancel');
    cancel?.onPress?.();
  }
}

export const Alert = new WebAlert();
// Alert.ts
export { Alert } from 'react-native';

Several things to note:

  1. Providing no buttons argument manifests a basic alert. Providing buttons presents a dialogue.
  2. The fourth options argument is not implemented as it pertains to Android cancellation behaviour only, which has no browser analogue.
  3. The AlertStatic interface implies an additional prompt method, but the React Native docs suggest that it hasn't yet been implemented (or that it's just undocumented, for now).

EDIT: Added Alert.ts to indicate how it should be imported.

@blueturtle13g
Copy link

Browser alert() is blocking, so it's not recomended to use. Not sure why it's not deprecated yet...

It's meant to block on purpose!

@RichardLindhout
Copy link
Contributor

The Modal PR is merged in react-native-web, that means the Alert implementation will be a lot easier to implement. I'll see if I can find some time to make a PR for this

@RichardLindhout
Copy link
Contributor

I just did an experiment with the Modal in the canary version to implement a the Alert API on the web: https://codesandbox.io/s/alert-implementation-z4eoq?file=/src/App.js.
This would require the React DOM to be available before Alert.alert can be called.

I'm not sure how we could handle this better
ezgif-5-b66429171338

@necolas Is it a requirement of the web version of the Alert.api to be available before React is mounted?

@necolas
Copy link
Owner Author

necolas commented Sep 25, 2020

Before React is mounted? What does that mean?

@RichardLindhout
Copy link
Contributor

RichardLindhout commented Sep 25, 2020

In my implementation the would have to be included somewhere in the three, I don't know if that's possible in the AppRegistry.

So if you would could Alert.alert() before the <AlertRoot /> has rendered it would fail, I presume we should implement the Alert.alert outside of the component tree but that would be hard since <Modal> would not be available.

@RichardLindhout
Copy link
Contributor

RichardLindhout commented Sep 25, 2020

I think I can workaround the issue I described above, but is it possible to add extra components in the root of a react-native-web app, like an <AlertRoot /> or extra Context providers?

@RichardLindhout
Copy link
Contributor

RichardLindhout commented Sep 25, 2020

I now have rewritten the Alert proposal to add support for Alerts outside components.
https://codesandbox.io/s/alert-implementation-z4eoq?file=/src/Alert.js

It would still need something like ReactDOM.render(<AlertRoot />) when react-native-web registers the app

update: fixed a bug where multiple Alerts would open

@RichardLindhout
Copy link
Contributor

Do you think the Codesandbox will be good enough for a PR if I

@arnavzek
Copy link

I went with, https://callstack.github.io/react-native-paper/dialog.html It looks pretty

@necolas
Copy link
Owner Author

necolas commented Nov 30, 2020

@RichardLindhout yeah something like that would be a good start

@kevinrodriguez-io

This comment has been minimized.

@ezekiel747
Copy link

ezekiel747 commented Apr 25, 2021

Hi, is there any update on this?
Would love to see a web version for the Alert.alert / .prompt in the same imperative approach.

And more user-friendly / good looking than plain old browsers' window.alert / window.prompt.

@zhigang1992
Copy link
Contributor

@ezekiel747 there is react-native-paper-alerts that looks pretty good on web.

@mikehardy
Copy link

@zhigang1992 react-native-paper-alerts is a reasonable solution, thanks for that pointer. I just looked it over and went ahead with an integration of it in https://github.com/invertase/react-native-firebase-authentication-example

If you're not using react-native-paper then it probably isn't attractive, but if you are - definitely worth a look - mind the styles applied in public/index.html to avoid a keyboard hiding issue if you use prompts with TextInput in the Alerts, but if you're just doing text and buttons, zero issues.

@p4bl1t0
Copy link

p4bl1t0 commented Jan 5, 2023

hi there! is there any update on this?

can I help on something? are there any pull request with this working progress?

@pjk5
Copy link

pjk5 commented Mar 7, 2023

While not an actual solution for this issue, I was able to make React Native's Alert work on multiple platforms by utilizing the sweetalert2 library for the web.

I've included my code below for anyone who might find it useful. Native Alert API is called for the native platforms and the code falls back to sweetalert2 for the web. The API is almost identical to the native Alert, with one addition to the AlertButton type to enable button type props for sweetalert2.

It seems that the prompt method could also be implemented with sweetalert2 quite easily, but I didn't have the need for that yet.

You can test it out on Snack.


Install sweetalert2:
npm install sweetalert2

Alert.web.ts:

import {
  type AlertType,
  type AlertButton,
  type AlertOptions,
} from 'react-native'

import Swal from 'sweetalert2'

export type CustomAlertButton = AlertButton & {
  swalType?: 'deny' | 'cancel' | 'confirm'
}

class Alert {
  static alert(
    title: string,
    message?: string,
    buttons?: CustomAlertButton[],
    options?: AlertOptions
  ): void {
    const confirmButton = buttons
      ? buttons.find((button) => button.swalType === 'confirm')
      : undefined
    const denyButton = buttons
      ? buttons.find((button) => button.swalType === 'deny')
      : undefined
    const cancelButton = buttons
      ? buttons.find((button) => button.swalType === 'cancel')
      : undefined

    Swal.fire({
      title: title,
      text: message,
      showConfirmButton: !!confirmButton,
      showDenyButton: !!denyButton,
      showCancelButton: !!cancelButton,
      confirmButtonText: confirmButton?.text,
      denyButtonText: denyButton?.text,
      cancelButtonText: cancelButton?.text,
    }).then((result) => {
      if (result.isConfirmed) {
        if (confirmButton?.onPress !== undefined) {
          confirmButton.onPress()
        }
      } else if (result.isDenied) {
        if (denyButton?.onPress !== undefined) {
          denyButton.onPress()
        }
      } else if (result.isDismissed) {
        if (cancelButton?.onPress !== undefined) {
          cancelButton.onPress()
        }
      }
    })
  }

  static prompt(
    title: string,
    message?: string,
    callbackOrButtons?: ((text: string) => void) | CustomAlertButton[],
    type?: AlertType,
    defaultValue?: string,
    keyboardType?: string
  ): void {
    throw new Error('Not implemented.')
  }
}

export default Alert

Alert.ts

import {
  Alert as RNAlert,
  type AlertOptions,
  type AlertButton,
  type AlertType,
} from 'react-native'

type CustomAlertButton = AlertButton & {
  swalType?: 'deny' | 'cancel' | 'confirm'
}

export interface ExtendedAlertStatic {
  alert: (
    title: string,
    message?: string,
    buttons?: CustomAlertButton[],
    options?: AlertOptions
  ) => void
  prompt: (
    title: string,
    message?: string,
    callbackOrButtons?: ((text: string) => void) | CustomAlertButton[],
    type?: AlertType,
    defaultValue?: string,
    keyboardType?: string
  ) => void
}

const Alert: ExtendedAlertStatic = RNAlert as ExtendedAlertStatic

export default Alert

@mensonones
Copy link

I'm creating a multiplatform. simple for now

https://github.com/mensonones/AnywhereAlertConfirm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
project:react-native-web Issue associated with react-native-web
Projects
None yet
Development

No branches or pull requests