Copy react-notification's source code directly into the project

react-query-api
Alex Gleason 2022-07-25 22:58:09 -05:00
rodzic 5916041fec
commit 83329d0887
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 7211D1F99744FBB7
12 zmienionych plików z 464 dodań i 10 usunięć

Wyświetl plik

@ -5,7 +5,7 @@ import { httpErrorMessages } from 'soapbox/utils/errors';
import type { SnackbarActionSeverity } from './snackbar'; import type { SnackbarActionSeverity } from './snackbar';
import type { AnyAction } from '@reduxjs/toolkit'; import type { AnyAction } from '@reduxjs/toolkit';
import type { AxiosError } from 'axios'; import type { AxiosError } from 'axios';
import type { NotificationObject } from 'react-notification'; import type { NotificationObject } from 'soapbox/react-notification';
const messages = defineMessages({ const messages = defineMessages({
unexpectedTitle: { id: 'alert.unexpected.title', defaultMessage: 'Oops!' }, unexpectedTitle: { id: 'alert.unexpected.title', defaultMessage: 'Oops!' },

Wyświetl plik

@ -1,11 +1,11 @@
import React from 'react'; import React from 'react';
import { useIntl, MessageDescriptor } from 'react-intl'; import { useIntl, MessageDescriptor } from 'react-intl';
import { NotificationStack, NotificationObject, StyleFactoryFn } from 'react-notification';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import { dismissAlert } from 'soapbox/actions/alerts'; import { dismissAlert } from 'soapbox/actions/alerts';
import { Button } from 'soapbox/components/ui'; import { Button } from 'soapbox/components/ui';
import { useAppSelector, useAppDispatch } from 'soapbox/hooks'; import { useAppSelector, useAppDispatch } from 'soapbox/hooks';
import { NotificationStack, NotificationObject, StyleFactoryFn } from 'soapbox/react-notification';
import type { Alert } from 'soapbox/reducers/alerts'; import type { Alert } from 'soapbox/reducers/alerts';

Wyświetl plik

@ -11,6 +11,7 @@ const hasGdpr = !!localStorage.getItem('soapbox:gdpr');
const messages = defineMessages({ const messages = defineMessages({
accept: { id: 'gdpr.accept', defaultMessage: 'Accept' }, accept: { id: 'gdpr.accept', defaultMessage: 'Accept' },
learnMore: { id: 'gdpr.learn_more', defaultMessage: 'Learn more' },
body: { id: 'gdpr.message', defaultMessage: '{siteTitle} uses session cookies, which are essential to the website\'s functioning.' }, body: { id: 'gdpr.message', defaultMessage: '{siteTitle} uses session cookies, which are essential to the website\'s functioning.' },
}); });

Wyświetl plik

@ -90,6 +90,7 @@ export const SoapboxConfigRecord = ImmutableRecord({
defaultSettings: ImmutableMap<string, any>(), defaultSettings: ImmutableMap<string, any>(),
extensions: ImmutableMap(), extensions: ImmutableMap(),
gdpr: false, gdpr: false,
gdprUrl: '',
greentext: false, greentext: false,
promoPanel: PromoPanelRecord(), promoPanel: PromoPanelRecord(),
navlinks: ImmutableMap({ navlinks: ImmutableMap({

Wyświetl plik

@ -0,0 +1,31 @@
import PropTypes from 'prop-types';
export default {
message: PropTypes.oneOfType([
PropTypes.string,
PropTypes.element,
]).isRequired,
action: PropTypes.oneOfType([
PropTypes.bool,
PropTypes.string,
PropTypes.node,
]),
onClick: PropTypes.func,
style: PropTypes.bool,
actionStyle: PropTypes.object,
titleStyle: PropTypes.object,
barStyle: PropTypes.object,
activeBarStyle: PropTypes.object,
dismissAfter: PropTypes.oneOfType([
PropTypes.bool,
PropTypes.number,
]),
onDismiss: PropTypes.func,
className: PropTypes.string,
activeClassName: PropTypes.string,
isActive: PropTypes.bool,
title: PropTypes.oneOfType([
PropTypes.string,
PropTypes.node,
]),
};

Wyświetl plik

@ -0,0 +1,88 @@
declare module 'soapbox/react-notification' {
import { Component, ReactElement } from 'react';
interface StyleFactoryFn {
(index: number, style: object | void, notification: NotificationProps): object;
}
interface OnClickNotificationProps {
/**
* Callback function to run when the action is clicked.
* @param notification Notification currently being clicked
* @param deactivate Function that can be called to set the notification to inactive.
* Used to activate notification exit animation on click.
*/
onClick?(notification: NotificationProps, deactivate: () => void): void;
}
interface NotificationProps extends OnClickNotificationProps {
/** The name of the action, e.g., "close" or "undo". */
action?: string;
/** Custom action styles. */
actionStyle?: object;
/** Custom snackbar styles when the bar is active. */
activeBarStyle?: object;
/**
* Custom class to apply to the top-level component when active.
* @default 'notification-bar-active'
*/
activeClassName?: string;
/** Custom snackbar styles. */
barStyle?: object;
/** Custom class to apply to the top-level component. */
className?: string;
/**
* Timeout for onDismiss event.
* @default 2000
*/
dismissAfter?: boolean | number;
/**
* If true, the notification is visible.
* @default false
*/
isActive?: boolean;
/** The message or component for the notification. */
message: string | ReactElement<NotificationProps>;
/** Setting this prop to `false` will disable all inline styles. */
style?: boolean;
/** The title for the notification. */
title?: string | ReactElement<any>;
/** Custom title styles. */
titleStyle?: object;
/**
* Callback function to run when dismissAfter timer runs out
* @param notification Notification currently being dismissed.
*/
onDismiss?(notification: NotificationProps): void;
}
interface NotificationStackProps extends OnClickNotificationProps {
/** Create the style of the actions. */
actionStyleFactory?: StyleFactoryFn;
/** Create the style of the active notification. */
activeBarStyleFactory?: StyleFactoryFn;
/** Create the style of the notification. */
barStyleFactory?: StyleFactoryFn;
/**
* If false, notification dismiss timers start immediately.
* @default true
*/
dismissInOrder?: boolean;
/** Array of notifications to render. */
notifications: NotificationObject[];
/**
* Callback function to run when dismissAfter timer runs out
* @param notification Notification currently being dismissed.
*/
onDismiss?(notification: NotificationObject): void;
}
export interface NotificationObject extends NotificationProps {
key: number | string;
}
export class Notification extends Component<NotificationProps, {}> {}
export class NotificationStack extends Component<NotificationStackProps, {}> {}
}

Wyświetl plik

@ -0,0 +1,2 @@
export { default as Notification } from './notification';
export { default as NotificationStack } from './notificationStack';

Wyświetl plik

@ -0,0 +1,175 @@
/* linting temp disabled while working on updates */
/* eslint-disable */
import React, { Component } from 'react';
import defaultPropTypes from './defaultPropTypes';
class Notification extends Component {
constructor(props) {
super(props);
this.getBarStyle = this.getBarStyle.bind(this);
this.getActionStyle = this.getActionStyle.bind(this);
this.getTitleStyle = this.getTitleStyle.bind(this);
this.handleClick = this.handleClick.bind(this);
if (props.onDismiss && props.isActive) {
this.dismissTimeout = setTimeout(
props.onDismiss,
props.dismissAfter
);
}
}
componentWillReceiveProps(nextProps) {
if (nextProps.dismissAfter === false) return;
// See http://eslint.org/docs/rules/no-prototype-builtins
if (!{}.hasOwnProperty.call(nextProps, 'isLast')) {
clearTimeout(this.dismissTimeout);
}
if (nextProps.onDismiss) {
if (
(nextProps.isActive && !this.props.isActive) ||
(nextProps.dismissAfter && this.props.dismissAfter === false)
) {
this.dismissTimeout = setTimeout(
nextProps.onDismiss,
nextProps.dismissAfter
);
}
}
}
componentWillUnmount() {
if (this.props.dismissAfter) clearTimeout(this.dismissTimeout);
}
/*
* @description Dynamically get the styles for the bar.
* @returns {object} result The style.
*/
getBarStyle() {
if (this.props.style === false) return {};
const { isActive, barStyle, activeBarStyle } = this.props;
const baseStyle = {
position: 'fixed',
bottom: '2rem',
left: '-100%',
width: 'auto',
padding: '1rem',
margin: 0,
color: '#fafafa',
font: '1rem normal Roboto, sans-serif',
borderRadius: '5px',
background: '#212121',
borderSizing: 'border-box',
boxShadow: '0 0 1px 1px rgba(10, 10, 11, .125)',
cursor: 'default',
WebKitTransition: '.5s cubic-bezier(0.89, 0.01, 0.5, 1.1)',
MozTransition: '.5s cubic-bezier(0.89, 0.01, 0.5, 1.1)',
msTransition: '.5s cubic-bezier(0.89, 0.01, 0.5, 1.1)',
OTransition: '.5s cubic-bezier(0.89, 0.01, 0.5, 1.1)',
transition: '.5s cubic-bezier(0.89, 0.01, 0.5, 1.1)',
WebkitTransform: 'translatez(0)',
MozTransform: 'translatez(0)',
msTransform: 'translatez(0)',
OTransform: 'translatez(0)',
transform: 'translatez(0)'
};
return isActive ?
Object.assign({}, baseStyle, { left: '1rem' }, barStyle, activeBarStyle) :
Object.assign({}, baseStyle, barStyle);
}
/*
* @function getActionStyle
* @description Dynamically get the styles for the action text.
* @returns {object} result The style.
*/
getActionStyle() {
return this.props.style !== false ? Object.assign({}, {
padding: '0.125rem',
marginLeft: '1rem',
color: '#f44336',
font: '.75rem normal Roboto, sans-serif',
lineHeight: '1rem',
letterSpacing: '.125ex',
textTransform: 'uppercase',
borderRadius: '5px',
cursor: 'pointer'
}, this.props.actionStyle) : {};
}
/*
* @function getTitleStyle
* @description Dynamically get the styles for the title.
* @returns {object} result The style.
*/
getTitleStyle() {
return this.props.style !== false ? Object.assign({}, {
fontWeight: '700',
marginRight: '.5rem'
}, this.props.titleStyle) : {};
}
/*
* @function handleClick
* @description Handle click events on the action button.
*/
handleClick() {
if (this.props.onClick && typeof this.props.onClick === 'function') {
return this.props.onClick();
}
}
render() {
let className = 'notification-bar';
if (this.props.isActive) className += ` ${this.props.activeClassName}`;
if (this.props.className) className += ` ${this.props.className}`;
return (
<div className={className} style={this.getBarStyle()}>
<div className="notification-bar-wrapper">
{this.props.title ? (
<span
className="notification-bar-title"
style={this.getTitleStyle()}
>
{this.props.title}
</span>
) : null}
{/* eslint-disable */}
<span className="notification-bar-message">
{this.props.message}
</span>
{this.props.action ? (
<span
className="notification-bar-action"
onClick={this.handleClick}
style={this.getActionStyle()}
>
{this.props.action}
</span>
) : null}
</div>
</div>
);
}
}
Notification.propTypes = defaultPropTypes;
Notification.defaultProps = {
isActive: false,
dismissAfter: 2000,
activeClassName: 'notification-bar-active'
};
export default Notification;

Wyświetl plik

@ -0,0 +1,95 @@
/* linting temp disabled while working on updates */
/* eslint-disable */
import React from 'react';
import PropTypes from 'prop-types';
import StackedNotification from './stackedNotification';
import defaultPropTypes from './defaultPropTypes';
function defaultBarStyleFactory(index, style) {
return Object.assign(
{},
style,
{ bottom: `${2 + (index * 4)}rem` }
);
}
function defaultActionStyleFactory(index, style) {
return Object.assign(
{},
style,
{}
);
}
/**
* The notification list does not have any state, so use a
* pure function here. It just needs to return the stacked array
* of notification components.
*/
const NotificationStack = props => (
<div className="notification-list">
{props.notifications.map((notification, index) => {
const isLast = index === 0 && props.notifications.length === 1;
const dismissNow = isLast || !props.dismissInOrder;
// Handle styles
const barStyle = props.barStyleFactory(index, notification.barStyle, notification);
const actionStyle = props.actionStyleFactory(index, notification.actionStyle, notification);
const activeBarStyle = props.activeBarStyleFactory(
index,
notification.activeBarStyle,
notification
);
// Allow onClick from notification stack or individual notifications
const onClick = notification.onClick || props.onClick;
const onDismiss = props.onDismiss;
let { dismissAfter } = notification;
if (dismissAfter !== false) {
if (dismissAfter == null) dismissAfter = props.dismissAfter;
if (!dismissNow) dismissAfter += index * 1000;
}
return (
<StackedNotification
{...notification}
key={notification.key}
isLast={isLast}
action={notification.action || props.action}
dismissAfter={dismissAfter}
onDismiss={onDismiss.bind(this, notification)}
onClick={onClick.bind(this, notification)}
activeBarStyle={activeBarStyle}
barStyle={barStyle}
actionStyle={actionStyle}
/>
);
})}
</div>
);
/* eslint-disable react/no-unused-prop-types, react/forbid-prop-types */
NotificationStack.propTypes = {
activeBarStyleFactory: PropTypes.func,
barStyleFactory: PropTypes.func,
actionStyleFactory: PropTypes.func,
dismissInOrder: PropTypes.bool,
notifications: PropTypes.array.isRequired,
onDismiss: PropTypes.func.isRequired,
onClick: PropTypes.func,
action: defaultPropTypes.action
};
NotificationStack.defaultProps = {
activeBarStyleFactory: defaultBarStyleFactory,
barStyleFactory: defaultBarStyleFactory,
actionStyleFactory: defaultActionStyleFactory,
dismissInOrder: true,
dismissAfter: 1000,
onClick: () => {}
};
/* eslint-enable no-alert, no-console */
export default NotificationStack;

Wyświetl plik

@ -0,0 +1,69 @@
/* linting temp disabled while working on updates */
/* eslint-disable */
import React, { Component } from 'react';
import defaultPropTypes from './defaultPropTypes';
import Notification from './notification';
class StackedNotification extends Component {
constructor(props) {
super(props);
this.state = {
isActive: false
};
this.handleClick = this.handleClick.bind(this);
}
componentDidMount() {
this.activeTimeout = setTimeout(this.setState.bind(this, {
isActive: true
}), 1);
this.dismiss(this.props.dismissAfter);
}
componentWillReceiveProps(nextProps) {
if (nextProps.dismissAfter !== this.props.dismissAfter) {
this.dismiss(nextProps.dismissAfter);
}
}
componentWillUnmount() {
clearTimeout(this.activeTimeout);
clearTimeout(this.dismissTimeout);
}
dismiss(dismissAfter) {
if (dismissAfter === false) return;
this.dismissTimeout = setTimeout(this.setState.bind(this, {
isActive: false
}), dismissAfter);
}
/*
* @function handleClick
* @description Bind deactivate Notification function to Notification click handler
*/
handleClick() {
if (this.props.onClick && typeof this.props.onClick === 'function') {
return this.props.onClick(this.setState.bind(this, { isActive: false }));
}
}
render() {
return (
<Notification
{...this.props}
onClick={this.handleClick}
onDismiss={() => setTimeout(this.props.onDismiss, 300)}
isActive={this.state.isActive}
/>
);
}
}
StackedNotification.propTypes = defaultPropTypes;
export default StackedNotification;

Wyświetl plik

@ -162,7 +162,6 @@
"react-inlinesvg": "^3.0.0", "react-inlinesvg": "^3.0.0",
"react-intl": "^5.0.0", "react-intl": "^5.0.0",
"react-motion": "^0.5.2", "react-motion": "^0.5.2",
"react-notification": "^6.8.5",
"react-otp-input": "^2.4.0", "react-otp-input": "^2.4.0",
"react-overlays": "^0.9.0", "react-overlays": "^0.9.0",
"react-popper": "^2.3.0", "react-popper": "^2.3.0",

Wyświetl plik

@ -9749,13 +9749,6 @@ react-motion@^0.5.2:
prop-types "^15.5.8" prop-types "^15.5.8"
raf "^3.1.0" raf "^3.1.0"
react-notification@^6.8.5:
version "6.8.5"
resolved "https://registry.yarnpkg.com/react-notification/-/react-notification-6.8.5.tgz#7ea90a633bb2a280d899e30c93cf372265cce4f0"
integrity sha512-3pJPhSsWNYizpyeMeWuC+jVthqE9WKqQ6rHq2naiiP4fLGN4irwL2Xp2Q8Qn7agW/e4BIDxarab6fJOUp1cKUw==
dependencies:
prop-types "^15.6.2"
react-onclickoutside@^6.12.0: react-onclickoutside@^6.12.0:
version "6.12.1" version "6.12.1"
resolved "https://registry.yarnpkg.com/react-onclickoutside/-/react-onclickoutside-6.12.1.tgz#92dddd28f55e483a1838c5c2930e051168c1e96b" resolved "https://registry.yarnpkg.com/react-onclickoutside/-/react-onclickoutside-6.12.1.tgz#92dddd28f55e483a1838c5c2930e051168c1e96b"