commit
648604282e
@ -0,0 +1,44 @@ |
|||||||
|
import { Plugin } from '@remixproject/engine' |
||||||
|
import { LibraryProfile, MethodApi, StatusEvents } from '@remixproject/plugin-utils' |
||||||
|
import { AppModal } from '@remix-ui/app' |
||||||
|
import { AlertModal } from 'libs/remix-ui/app/src/lib/remix-app/interface' |
||||||
|
import { dispatchModalInterface } from 'libs/remix-ui/app/src/lib/remix-app/context/context' |
||||||
|
|
||||||
|
interface IModalApi { |
||||||
|
events: StatusEvents, |
||||||
|
methods: { |
||||||
|
modal: (args: AppModal) => void |
||||||
|
alert: (args: AlertModal) => void |
||||||
|
toast: (message: string) => void |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const profile:LibraryProfile<IModalApi> = { |
||||||
|
name: 'modal', |
||||||
|
displayName: 'Modal', |
||||||
|
description: 'Modal', |
||||||
|
methods: ['modal', 'alert', 'toast'] |
||||||
|
} |
||||||
|
|
||||||
|
export class ModalPlugin extends Plugin implements MethodApi<IModalApi> { |
||||||
|
dispatcher: dispatchModalInterface |
||||||
|
constructor () { |
||||||
|
super(profile) |
||||||
|
} |
||||||
|
|
||||||
|
setDispatcher (dispatcher: dispatchModalInterface) { |
||||||
|
this.dispatcher = dispatcher |
||||||
|
} |
||||||
|
|
||||||
|
async modal (args: AppModal) { |
||||||
|
this.dispatcher.modal(args) |
||||||
|
} |
||||||
|
|
||||||
|
async alert (args: AlertModal) { |
||||||
|
this.dispatcher.alert(args) |
||||||
|
} |
||||||
|
|
||||||
|
async toast (message: string) { |
||||||
|
this.dispatcher.toast(message) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,53 @@ |
|||||||
|
import { Plugin } from '@remixproject/engine' |
||||||
|
import { Profile } from '@remixproject/plugin-utils' |
||||||
|
import { AlertModal } from 'libs/remix-ui/app/src/lib/remix-app/interface' |
||||||
|
import { ModalTypes } from 'libs/remix-ui/app/src/lib/remix-app/types' |
||||||
|
import { AppModal } from '../../../../../libs/remix-ui/app/src' |
||||||
|
|
||||||
|
const profile:Profile = { |
||||||
|
name: 'testerplugin', |
||||||
|
displayName: 'testerplugin', |
||||||
|
description: 'testerplugin', |
||||||
|
methods: [] |
||||||
|
} |
||||||
|
|
||||||
|
export class ModalPluginTester extends Plugin { |
||||||
|
constructor () { |
||||||
|
super(profile) |
||||||
|
} |
||||||
|
|
||||||
|
handleMessage (message: any): void { |
||||||
|
console.log(message) |
||||||
|
} |
||||||
|
|
||||||
|
onActivation (): void { |
||||||
|
// just a modal
|
||||||
|
let mod:AppModal = { |
||||||
|
id: 'modal1', |
||||||
|
title: 'test', |
||||||
|
message: 'test', |
||||||
|
okFn: this.handleMessage, |
||||||
|
okLabel: 'yes', |
||||||
|
cancelFn: null, |
||||||
|
cancelLabel: 'no' |
||||||
|
} |
||||||
|
// this.call('modal', 'modal', mod)
|
||||||
|
|
||||||
|
// modal with callback
|
||||||
|
mod = { ...mod, message: 'gist url', modalType: ModalTypes.prompt, defaultValue: 'prompting' } |
||||||
|
// this.call('modal', 'modal', mod)
|
||||||
|
|
||||||
|
// modal with password
|
||||||
|
mod = { ...mod, message: 'enter password to give me eth', modalType: ModalTypes.password, defaultValue: 'pass' } |
||||||
|
// this.call('modal', 'modal', mod)
|
||||||
|
|
||||||
|
const al:AlertModal = { |
||||||
|
id: 'myalert', |
||||||
|
message: 'alert message' |
||||||
|
} |
||||||
|
// this.call('modal', 'alert', al)
|
||||||
|
|
||||||
|
// set toaster
|
||||||
|
// this.call('modal', 'toast', 'toast message')
|
||||||
|
} |
||||||
|
} |
@ -1 +1,4 @@ |
|||||||
export { default as RemixApp } from './lib/remix-app/remix-app' |
export { default as RemixApp } from './lib/remix-app/remix-app' |
||||||
|
export { dispatchModalContext } from './lib/remix-app/context/context' |
||||||
|
export { ModalProvider } from './lib/remix-app/context/provider' |
||||||
|
export { AppModal } from './lib/remix-app/interface/index' |
||||||
|
@ -0,0 +1,30 @@ |
|||||||
|
import { AppModal } from '../interface' |
||||||
|
|
||||||
|
type ActionMap<M extends { [index: string]: any }> = { |
||||||
|
[Key in keyof M]: M[Key] extends undefined |
||||||
|
? { |
||||||
|
type: Key; |
||||||
|
} |
||||||
|
: { |
||||||
|
type: Key; |
||||||
|
payload: M[Key]; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export const enum modalActionTypes { |
||||||
|
setModal = 'SET_MODAL', |
||||||
|
setToast = 'SET_TOAST', |
||||||
|
handleHideModal = 'HANDLE_HIDE_MODAL', |
||||||
|
handleToaster = 'HANDLE_HIDE_TOAST' |
||||||
|
} |
||||||
|
|
||||||
|
type ModalPayload = { |
||||||
|
[modalActionTypes.setModal]: AppModal |
||||||
|
[modalActionTypes.handleHideModal]: any |
||||||
|
[modalActionTypes.setToast]: string |
||||||
|
[modalActionTypes.handleToaster]: any |
||||||
|
} |
||||||
|
|
||||||
|
export type ModalAction = ActionMap<ModalPayload>[keyof ActionMap< |
||||||
|
ModalPayload |
||||||
|
>] |
@ -0,0 +1,16 @@ |
|||||||
|
import React, { useContext, useEffect } from 'react' |
||||||
|
import { AppContext } from '../../context/context' |
||||||
|
import { useDialogDispatchers } from '../../context/provider' |
||||||
|
|
||||||
|
const DialogViewPlugin = () => { |
||||||
|
const { modal, alert, toast } = useDialogDispatchers() |
||||||
|
const app = useContext(AppContext) |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
console.log(modal, app) |
||||||
|
app.modal.setDispatcher({ modal, alert, toast }) |
||||||
|
}, []) |
||||||
|
return <></> |
||||||
|
} |
||||||
|
|
||||||
|
export default DialogViewPlugin |
@ -0,0 +1,16 @@ |
|||||||
|
import React from 'react' |
||||||
|
import { useDialogDispatchers, useDialogs } from '../../context/provider' |
||||||
|
import { Toaster } from '@remix-ui/toaster' |
||||||
|
import ModalWrapper from './modal-wrapper' |
||||||
|
|
||||||
|
const AppDialogs = () => { |
||||||
|
const { handleHideModal, handleToaster } = useDialogDispatchers() |
||||||
|
const { focusModal, focusToaster } = useDialogs() |
||||||
|
|
||||||
|
return ( |
||||||
|
<> |
||||||
|
<ModalWrapper {...focusModal} handleHide={handleHideModal}></ModalWrapper> |
||||||
|
<Toaster message={focusToaster} handleHide={handleToaster} /> |
||||||
|
</>) |
||||||
|
} |
||||||
|
export default AppDialogs |
@ -0,0 +1,45 @@ |
|||||||
|
import React, { useContext, useEffect, useState } from 'react' |
||||||
|
import { AppContext } from '../../context/context' |
||||||
|
import { useDialogDispatchers } from '../../context/provider' |
||||||
|
const _paq = window._paq = window._paq || [] |
||||||
|
|
||||||
|
const MatomoDialog = (props) => { |
||||||
|
const { settings, showMatamo, appManager } = useContext(AppContext) |
||||||
|
const { modal } = useDialogDispatchers() |
||||||
|
const [visible, setVisible] = useState<boolean>(props.hide) |
||||||
|
|
||||||
|
const message = () => { |
||||||
|
return (<><p>An Opt-in version of <a href="https://matomo.org" target="_blank" rel="noreferrer">Matomo</a>, an open source data analytics platform is being used to improve Remix IDE.</p> |
||||||
|
<p>We realize that our users have sensitive information in their code and that their privacy - your privacy - must be protected.</p> |
||||||
|
<p>All data collected through Matomo is stored on our own server - no data is ever given to third parties. Our analytics reports are public: <a href="https://matomo.ethereum.org/index.php?module=MultiSites&action=index&idSite=23&period=day&date=yesterday" target="_blank" rel="noreferrer">take a look</a>.</p> |
||||||
|
<p>We do not collect nor store any personally identifiable information (PII).</p> |
||||||
|
<p>For more info, see: <a href="https://medium.com/p/66ef69e14931/" target="_blank" rel="noreferrer">Matomo Analyitcs on Remix iDE</a>.</p> |
||||||
|
<p>You can change your choice in the Settings panel anytime.</p></>) |
||||||
|
} |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
if (visible && showMatamo) { |
||||||
|
modal({ id: 'matomoModal', title: 'Help us to improve Remix IDE', message: message(), okLabel: 'Accept', okFn: handleModalOkClick, cancelLabel: 'Decline', cancelFn: declineModal }) |
||||||
|
} |
||||||
|
}, [visible]) |
||||||
|
|
||||||
|
const declineModal = async () => { |
||||||
|
settings.updateMatomoAnalyticsChoice(false) |
||||||
|
_paq.push(['optUserOut']) |
||||||
|
appManager.call('walkthrough', 'start') |
||||||
|
setVisible(false) |
||||||
|
} |
||||||
|
|
||||||
|
const handleModalOkClick = async () => { |
||||||
|
_paq.push(['forgetUserOptOut']) |
||||||
|
// @TODO remove next line when https://github.com/matomo-org/matomo/commit/9e10a150585522ca30ecdd275007a882a70c6df5 is used
|
||||||
|
document.cookie = 'mtm_consent_removed=; expires=Thu, 01 Jan 1970 00:00:01 GMT;' |
||||||
|
settings.updateMatomoAnalyticsChoice(true) |
||||||
|
appManager.call('walkthrough', 'start') |
||||||
|
setVisible(false) |
||||||
|
} |
||||||
|
|
||||||
|
return (<></>) |
||||||
|
} |
||||||
|
|
||||||
|
export default MatomoDialog |
@ -0,0 +1,56 @@ |
|||||||
|
import React, { useEffect, useRef, useState } from 'react' |
||||||
|
import { ModalDialog } from '@remix-ui/modal-dialog' |
||||||
|
import { ModalDialogProps } from 'libs/remix-ui/modal-dialog/src/lib/types' |
||||||
|
import { ModalTypes } from '../../types' |
||||||
|
|
||||||
|
interface ModalWrapperProps extends ModalDialogProps { |
||||||
|
modalType?: ModalTypes |
||||||
|
defaultValue?: string |
||||||
|
} |
||||||
|
|
||||||
|
const ModalWrapper = (props: ModalWrapperProps) => { |
||||||
|
const [state, setState] = useState<ModalDialogProps>() |
||||||
|
const ref = useRef() |
||||||
|
|
||||||
|
const onFinishPrompt = async () => { |
||||||
|
if (ref.current === undefined) { |
||||||
|
props.okFn() |
||||||
|
} else { |
||||||
|
// @ts-ignore: Object is possibly 'null'.
|
||||||
|
props.okFn(ref.current.value) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const createModalMessage = (defaultValue: string) => { |
||||||
|
return ( |
||||||
|
<> |
||||||
|
{props.message} |
||||||
|
<input type={props.modalType === ModalTypes.password ? 'password' : 'text'} defaultValue={defaultValue} data-id="modalDialogCustomPromp" ref={ref} className="form-control" /></> |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
if (props.modalType) { |
||||||
|
switch (props.modalType) { |
||||||
|
case ModalTypes.prompt: |
||||||
|
case ModalTypes.password: |
||||||
|
setState({ |
||||||
|
...props, |
||||||
|
okFn: onFinishPrompt, |
||||||
|
message: createModalMessage(props.defaultValue) |
||||||
|
}) |
||||||
|
break |
||||||
|
default: |
||||||
|
setState({ ...props }) |
||||||
|
break |
||||||
|
} |
||||||
|
} else { |
||||||
|
setState({ ...props }) |
||||||
|
} |
||||||
|
}, [props]) |
||||||
|
|
||||||
|
return ( |
||||||
|
<ModalDialog id={props.id} {...state} handleHide={props.handleHide} /> |
||||||
|
) |
||||||
|
} |
||||||
|
export default ModalWrapper |
@ -1,5 +1,24 @@ |
|||||||
import React from 'react' |
import React from 'react' |
||||||
|
import { AlertModal, AppModal } from '../interface' |
||||||
|
import { ModalInitialState } from '../state/modals' |
||||||
|
import { ModalTypes } from '../types' |
||||||
|
|
||||||
const AppContext = React.createContext(null) |
export const AppContext = React.createContext<any>(null) |
||||||
|
|
||||||
export default AppContext |
export interface dispatchModalInterface { |
||||||
|
modal: (data: AppModal) => void |
||||||
|
toast: (message: string) => void |
||||||
|
alert: (data: AlertModal) => void |
||||||
|
handleHideModal: () => void, |
||||||
|
handleToaster: () => void |
||||||
|
} |
||||||
|
|
||||||
|
export const dispatchModalContext = React.createContext<dispatchModalInterface>({ |
||||||
|
modal: (data: AppModal) => { }, |
||||||
|
toast: (message: string) => {}, |
||||||
|
alert: (data: AlertModal) => {}, |
||||||
|
handleHideModal: () => {}, |
||||||
|
handleToaster: () => {} |
||||||
|
}) |
||||||
|
|
||||||
|
export const modalContext = React.createContext(ModalInitialState) |
||||||
|
@ -0,0 +1,64 @@ |
|||||||
|
import React, { useReducer } from 'react' |
||||||
|
import { modalActionTypes } from '../actions/modals' |
||||||
|
import { AlertModal, AppModal } from '../interface' |
||||||
|
import { modalReducer } from '../reducer/modals' |
||||||
|
import { ModalInitialState } from '../state/modals' |
||||||
|
import { ModalTypes } from '../types' |
||||||
|
import { AppContext, dispatchModalContext, modalContext } from './context' |
||||||
|
|
||||||
|
export const ModalProvider = ({ children = [], reducer = modalReducer, initialState = ModalInitialState } = {}) => { |
||||||
|
const [{ modals, toasters, focusModal, focusToaster }, dispatch] = useReducer(reducer, initialState) |
||||||
|
|
||||||
|
const modal = (data: AppModal) => { |
||||||
|
const { id, title, message, okLabel, okFn, cancelLabel, cancelFn, modalType, defaultValue } = data |
||||||
|
dispatch({ |
||||||
|
type: modalActionTypes.setModal, |
||||||
|
payload: { id, title, message, okLabel, okFn, cancelLabel, cancelFn, modalType: modalType || ModalTypes.default, defaultValue: defaultValue } |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
const alert = (data: AlertModal) => { |
||||||
|
modal({ id: data.id, title: data.title || 'Alert', message: data.message || data.title, okLabel: 'OK', okFn: (value?:any) => {}, cancelLabel: '', cancelFn: () => {} }) |
||||||
|
} |
||||||
|
|
||||||
|
const handleHideModal = () => { |
||||||
|
dispatch({ |
||||||
|
type: modalActionTypes.handleHideModal, |
||||||
|
payload: null |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
const toast = (message: string) => { |
||||||
|
dispatch({ |
||||||
|
type: modalActionTypes.setToast, |
||||||
|
payload: message |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
const handleToaster = () => { |
||||||
|
dispatch({ |
||||||
|
type: modalActionTypes.handleToaster, |
||||||
|
payload: null |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
return (<dispatchModalContext.Provider value={{ modal, toast, alert, handleHideModal, handleToaster }}> |
||||||
|
<modalContext.Provider value={{ modals, toasters, focusModal, focusToaster }}> |
||||||
|
{children} |
||||||
|
</modalContext.Provider> |
||||||
|
</dispatchModalContext.Provider>) |
||||||
|
} |
||||||
|
|
||||||
|
export const AppProvider = ({ children = [], value = {} } = {}) => { |
||||||
|
return <AppContext.Provider value={value}> |
||||||
|
<ModalProvider>{children}</ModalProvider> |
||||||
|
</AppContext.Provider> |
||||||
|
} |
||||||
|
|
||||||
|
export const useDialogs = () => { |
||||||
|
return React.useContext(modalContext) |
||||||
|
} |
||||||
|
|
||||||
|
export const useDialogDispatchers = () => { |
||||||
|
return React.useContext(dispatchModalContext) |
||||||
|
} |
@ -0,0 +1,28 @@ |
|||||||
|
import { ModalTypes } from '../types' |
||||||
|
|
||||||
|
export interface AppModal { |
||||||
|
id: string |
||||||
|
hide?: boolean |
||||||
|
title: string |
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
message: string | JSX.Element |
||||||
|
okLabel: string |
||||||
|
okFn: (value?:any) => void |
||||||
|
cancelLabel: string |
||||||
|
cancelFn: () => void, |
||||||
|
modalType?: ModalTypes, |
||||||
|
defaultValue?: string |
||||||
|
} |
||||||
|
|
||||||
|
export interface AlertModal { |
||||||
|
id: string |
||||||
|
title?: string, |
||||||
|
message: string | JSX.Element, |
||||||
|
} |
||||||
|
|
||||||
|
export interface ModalState { |
||||||
|
modals: AppModal[], |
||||||
|
toasters: string[], |
||||||
|
focusModal: AppModal, |
||||||
|
focusToaster: string |
||||||
|
} |
@ -1,51 +0,0 @@ |
|||||||
import React, { useContext, useEffect, useState } from 'react' |
|
||||||
import { ModalDialog } from '@remix-ui/modal-dialog' |
|
||||||
import AppContext from '../context/context' |
|
||||||
const _paq = window._paq = window._paq || [] |
|
||||||
|
|
||||||
const MatomoDialog = (props) => { |
|
||||||
const { settings, showMatamo, appManager } = useContext(AppContext) |
|
||||||
const [visible, setVisible] = useState<boolean>(props.hide) |
|
||||||
useEffect(() => { |
|
||||||
if (showMatamo) { |
|
||||||
setVisible(true) |
|
||||||
} else { |
|
||||||
setVisible(false) |
|
||||||
} |
|
||||||
}, []) |
|
||||||
const declineModal = async () => { |
|
||||||
settings.updateMatomoAnalyticsChoice(false) |
|
||||||
_paq.push(['optUserOut']) |
|
||||||
appManager.call('walkthrough', 'start') |
|
||||||
setVisible(false) |
|
||||||
} |
|
||||||
const hideModal = async () => { |
|
||||||
setVisible(false) |
|
||||||
} |
|
||||||
const handleModalOkClick = async () => { |
|
||||||
_paq.push(['forgetUserOptOut']) |
|
||||||
// @TODO remove next line when https://github.com/matomo-org/matomo/commit/9e10a150585522ca30ecdd275007a882a70c6df5 is used
|
|
||||||
document.cookie = 'mtm_consent_removed=; expires=Thu, 01 Jan 1970 00:00:01 GMT;' |
|
||||||
settings.updateMatomoAnalyticsChoice(true) |
|
||||||
appManager.call('walkthrough', 'start') |
|
||||||
setVisible(false) |
|
||||||
} |
|
||||||
return (<ModalDialog |
|
||||||
handleHide={hideModal} |
|
||||||
id="matomoDialog" |
|
||||||
hide={!visible} |
|
||||||
title="Help us to improve Remix IDE" |
|
||||||
okLabel="Accept" |
|
||||||
okFn={ handleModalOkClick } |
|
||||||
cancelLabel="Decline" |
|
||||||
cancelFn={declineModal}> |
|
||||||
<p>An Opt-in version of <a href="https://matomo.org" target="_blank" rel="noreferrer">Matomo</a>, an open source data analytics platform is being used to improve Remix IDE.</p> |
|
||||||
<p>We realize that our users have sensitive information in their code and that their privacy - your privacy - must be protected.</p> |
|
||||||
<p>All data collected through Matomo is stored on our own server - no data is ever given to third parties. Our analytics reports are public: <a href="https://matomo.ethereum.org/index.php?module=MultiSites&action=index&idSite=23&period=day&date=yesterday" target="_blank" rel="noreferrer">take a look</a>.</p> |
|
||||||
<p>We do not collect nor store any personally identifiable information (PII).</p> |
|
||||||
<p>For more info, see: <a href="https://medium.com/p/66ef69e14931/" target="_blank" rel="noreferrer">Matomo Analyitcs on Remix iDE</a>.</p> |
|
||||||
<p>You can change your choice in the Settings panel anytime.</p> |
|
||||||
</ModalDialog>) |
|
||||||
} |
|
||||||
|
|
||||||
export default MatomoDialog |
|
@ -0,0 +1,46 @@ |
|||||||
|
import { modalActionTypes, ModalAction } from '../actions/modals' |
||||||
|
import { ModalInitialState } from '../state/modals' |
||||||
|
import { AppModal, ModalState } from '../interface' |
||||||
|
|
||||||
|
export const modalReducer = (state: ModalState = ModalInitialState, action: ModalAction) => { |
||||||
|
switch (action.type) { |
||||||
|
case modalActionTypes.setModal: { |
||||||
|
let modalList:AppModal[] = state.modals |
||||||
|
modalList.push(action.payload) |
||||||
|
if (state.modals.length === 1 && state.focusModal.hide === true) { // if it's the first one show it
|
||||||
|
const focusModal: AppModal = { |
||||||
|
id: modalList[0].id, |
||||||
|
hide: false, |
||||||
|
title: modalList[0].title, |
||||||
|
message: modalList[0].message, |
||||||
|
okLabel: modalList[0].okLabel, |
||||||
|
okFn: modalList[0].okFn, |
||||||
|
cancelLabel: modalList[0].cancelLabel, |
||||||
|
cancelFn: modalList[0].cancelFn, |
||||||
|
modalType: modalList[0].modalType, |
||||||
|
defaultValue: modalList[0].defaultValue |
||||||
|
} |
||||||
|
|
||||||
|
modalList = modalList.slice() |
||||||
|
modalList.shift() |
||||||
|
return { ...state, modals: modalList, focusModal: focusModal } |
||||||
|
} |
||||||
|
return { ...state, modals: modalList } |
||||||
|
} |
||||||
|
case modalActionTypes.handleHideModal: |
||||||
|
state.focusModal = { ...state.focusModal, hide: true, message: null } |
||||||
|
return { ...state } |
||||||
|
|
||||||
|
case modalActionTypes.setToast: |
||||||
|
state.toasters.push(action.payload) |
||||||
|
if (state.toasters.length > 0) { |
||||||
|
const focus = state.toasters[0] |
||||||
|
state.toasters.shift() |
||||||
|
return { ...state, focusToaster: focus } |
||||||
|
} |
||||||
|
return { ...state } |
||||||
|
|
||||||
|
case modalActionTypes.handleToaster: |
||||||
|
return { ...state, focusToaster: '' } |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,17 @@ |
|||||||
|
import { ModalState } from '../interface' |
||||||
|
|
||||||
|
export const ModalInitialState: ModalState = { |
||||||
|
modals: [], |
||||||
|
toasters: [], |
||||||
|
focusModal: { |
||||||
|
id: '', |
||||||
|
hide: true, |
||||||
|
title: '', |
||||||
|
message: '', |
||||||
|
okLabel: '', |
||||||
|
okFn: () => { }, |
||||||
|
cancelLabel: '', |
||||||
|
cancelFn: () => { } |
||||||
|
}, |
||||||
|
focusToaster: '' |
||||||
|
} |
@ -0,0 +1,7 @@ |
|||||||
|
export const enum ModalTypes { |
||||||
|
alert = 'alert', |
||||||
|
confirm = 'confirm', |
||||||
|
prompt = 'prompt', |
||||||
|
password = 'password', |
||||||
|
default = 'default', |
||||||
|
} |
Loading…
Reference in new issue