Skip to content

Commit c93a164

Browse files
committed
Allow custom title/message, fixed touch events
1 parent 00b3fc3 commit c93a164

3 files changed

Lines changed: 63 additions & 87 deletions

File tree

src/react-notification.js

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,7 @@ export default class ReactNotification extends React.Component {
5050

5151
componentDidMount() {
5252
const { notification, count } = this.props;
53-
const {
54-
dismiss: { duration, onScreen }
55-
} = notification;
53+
const { dismiss: { duration, onScreen } } = notification;
5654
const { scrollHeight } = this.rootElementRef.current;
5755
const willSlide = shouldNotificationHaveSliding(notification, count);
5856

@@ -140,10 +138,14 @@ export default class ReactNotification extends React.Component {
140138

141139
onTouchStart({ touches }) {
142140
const [{ pageX }] = touches;
143-
this.setState({
141+
this.setState(({ parentStyle }) => ({
144142
startX: pageX,
145-
currentX: pageX
146-
});
143+
currentX: pageX,
144+
parentStyle: {
145+
...parentStyle,
146+
position: 'relative'
147+
}
148+
}));
147149
}
148150

149151
onTouchMove({ touches }) {
@@ -249,7 +251,6 @@ export default class ReactNotification extends React.Component {
249251
};
250252

251253
const onAnimationEnd = () => this.removeNotification(REMOVAL.TIMEOUT);
252-
253254
return (
254255
<div className="timer">
255256
<div className="timer-filler" onAnimationEnd={onAnimationEnd} style={style}></div>
@@ -260,11 +261,21 @@ export default class ReactNotification extends React.Component {
260261
renderCustomContent() {
261262
const { htmlClassList } = this.state;
262263
const {
263-
notification: { id, content: CustomContent }
264+
notification: {
265+
id,
266+
content: CustomContent,
267+
dismiss: { duration, pauseOnHover }
268+
}
264269
} = this.props;
265270

271+
const hasMouseEvents = duration > 0 && pauseOnHover;
272+
266273
return (
267-
<div className={`${[...htmlClassList, 'n-child'].join(' ')}`}>
274+
<div
275+
className={`${[...htmlClassList, 'n-child'].join(' ')}`}
276+
onMouseEnter={hasMouseEvents ? this.onMouseEnter : null}
277+
onMouseLeave={hasMouseEvents ? this.onMouseLeave : null}
278+
>
268279
{React.isValidElement(CustomContent) ? CustomContent : <CustomContent {...{ id }} />}
269280
</div>
270281
);
@@ -289,8 +300,8 @@ export default class ReactNotification extends React.Component {
289300
>
290301
<div className="notification-content">
291302
{showIcon && <div className="notification-close" onClick={this.onClick}></div>}
292-
{title && <p className="notification-title">{title}</p>}
293-
{<p className="notification-message">{message}</p>}
303+
{title && <div className="notification-title">{title}</div>}
304+
<div className="notification-message">{message}</div>
294305
{this.renderTimer()}
295306
</div>
296307
</div>

src/utils/constants.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export const REMOVAL = {
3232
export const ERROR = {
3333
ANIMATION_IN: 'Validation error. `animationIn` option must be an array',
3434
ANIMATION_OUT: 'Validation error. `animationOut` option must be an array',
35+
3536
DISMISS_REQUIRED: 'Validation error. `duration` property of `dismiss` option is required',
3637
DISMISS_NUMBER: 'Validation error. `duration` property of `dismiss` option must be a Number',
3738
DISMISS_POSITIVE:
@@ -45,24 +46,33 @@ export const ERROR = {
4546
DISMISS_ONSCREEN_BOOL:
4647
'Validation error. `onScreen` property of `dismiss` option must be a Boolean',
4748
DISMISS_ICON: 'Validation error. `showIcon` property of `dismiss` option must be a Boolean',
48-
TITLE_STRING: 'Validation error. `title` option must be a String.',
49+
50+
TITLE_STRING: 'Validation error. `title` option must be a String',
51+
TITLE_ELEMENT: 'Validation error. `title` option must be a valid React element/function',
52+
4953
MESSAGE_REQUIRED: 'Validation error. `message` option is required',
5054
MESSAGE_STRING: 'Validation error. `message` option must be a String',
55+
MESSAGE_ELEMENT: 'Validation error. `message` option must be a valid React element/function',
56+
5157
TYPE_REQUIRED: 'Validation error. `type` option is required',
5258
TYPE_STRING: 'Validation error. `type` option must be a String',
5359
TYPE_NOT_EXISTENT: 'Validation error. `type` option not found',
60+
5461
CONTAINER_REQUIRED: 'Validation error. `container` option is required',
5562
CONTAINER_STRING: 'Validation error. `container` option must be a String',
5663
CONTENT_INVALID:
5764
'Validation error. `content` option must be a valid React component/function/element',
65+
5866
WIDTH_NUMBER: 'Validation error. `width` option must be a Number',
5967
INSERT_STRING: 'Validation error. `insert` option must be a String',
68+
6069
TRANSITION_DURATION_NUMBER:
6170
'Validation error. `duration` property of `transition` option must be a Number',
6271
TRANSITION_TIMING_FUNCTION:
6372
'Validation error. `timingFunction` property of `transition` option must be a String',
6473
TRANSITION_DELAY_NUMBER:
6574
'Validation error. `delay` property of `transition` option must be a Number',
75+
6676
TYPE_NOT_FOUND: 'Validation error. Custom type not found',
6777
REMOVAL_FUNC: 'Validation error. `onRemoval` must be a function'
6878
};

src/utils/validators.js

Lines changed: 30 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,18 @@ function isFunctionComponent(component) {
1616
return typeof component === 'function';
1717
}
1818

19+
const isReactElement = value => isFunctionComponent(value) || React.isValidElement(value);
20+
1921
export function validateTransition(notification, transition) {
2022
const { TRANSITION_DURATION_NUMBER, TRANSITION_TIMING_FUNCTION, TRANSITION_DELAY_NUMBER } = ERROR;
21-
2223
const { duration, timingFunction, delay } = notification[transition] || {};
2324

2425
if (!isNull(duration) && !isNumber(duration)) {
2526
throw new Error(TRANSITION_DURATION_NUMBER.replace('transition', transition));
2627
}
27-
2828
if (!isNull(timingFunction) && !isString(timingFunction)) {
2929
throw new Error(TRANSITION_TIMING_FUNCTION.replace('transition', transition));
3030
}
31-
3231
if (!isNull(delay) && !isNumber(delay)) {
3332
throw new Error(TRANSITION_DELAY_NUMBER.replace('transition', transition));
3433
}
@@ -38,9 +37,11 @@ export const validators = [
3837
function title({ content, title }) {
3938
if (content) return;
4039
if (isNull(title)) return;
41-
if (typeof title !== 'string') {
42-
throw new Error(ERROR.TITLE_STRING);
43-
}
40+
41+
const isReactEl = isReactElement(title);
42+
if (isReactEl || typeof title === 'string') return;
43+
if (!isReactEl) throw new Error(ERROR.TITLE_ELEMENT);
44+
if (typeof title !== 'string') throw new Error(ERROR.TITLE_STRING);
4445
},
4546

4647
function message({ content, message }) {
@@ -50,21 +51,16 @@ export const validators = [
5051
throw new Error(ERROR.MESSAGE_REQUIRED);
5152
}
5253

53-
if (!isString(message)) {
54-
throw new Error(ERROR.MESSAGE_STRING);
55-
}
54+
const isReactEl = isReactElement(message);
55+
if (isString(message) || isReactEl) return;
56+
if (!isString(message)) throw new Error(ERROR.MESSAGE_STRING);
57+
if (!isReactEl) throw new Error(ERROR.MESSAGE_ELEMENT);
5658
},
5759

5860
function type({ content, type }, userDefinedTypes) {
5961
if (content) return;
60-
61-
if (!type) {
62-
throw new Error(ERROR.TYPE_REQUIRED);
63-
}
64-
65-
if (!isString(type)) {
66-
throw new Error(ERROR.TYPE_STRING);
67-
}
62+
if (!type) throw new Error(ERROR.TYPE_REQUIRED);
63+
if (!isString(type)) throw new Error(ERROR.TYPE_STRING);
6864

6965
if (
7066
!userDefinedTypes &&
@@ -79,27 +75,18 @@ export const validators = [
7975
},
8076

8177
function container({ container }) {
82-
if (isNull(container)) {
83-
throw new Error(ERROR.CONTAINER_REQUIRED);
84-
}
85-
86-
if (!isString(container)) {
87-
throw new Error(ERROR.CONTAINER_STRING);
88-
}
78+
if (isNull(container)) throw new Error(ERROR.CONTAINER_REQUIRED);
79+
if (!isString(container)) throw new Error(ERROR.CONTAINER_STRING);
8980
},
9081

9182
function insert({ insert }) {
9283
if (isNull(insert)) return;
93-
if (!isString(insert)) {
94-
throw new Error(ERROR.INSERT_STRING);
95-
}
84+
if (!isString(insert)) throw new Error(ERROR.INSERT_STRING);
9685
},
9786

9887
function width({ width }) {
9988
if (isNull(width)) return;
100-
if (!isNumber(width)) {
101-
throw new Error(ERROR.WIDTH_NUMBER);
102-
}
89+
if (!isNumber(width)) throw new Error(ERROR.WIDTH_NUMBER);
10390
},
10491

10592
function userDefinedTypes({ type, content }, userDefinedTypes) {
@@ -125,30 +112,22 @@ export const validators = [
125112
const isClass = isClassComponent(content);
126113
const isFunction = isFunctionComponent(content);
127114
const isElem = React.isValidElement(content);
128-
if (!isClass && !isFunction && !isElem) {
129-
throw new Error(ERROR.CONTENT_INVALID);
130-
}
115+
if (!isClass && !isFunction && !isElem) throw new Error(ERROR.CONTENT_INVALID);
131116
},
132117

133118
function animationIn({ animationIn }) {
134119
if (isNull(animationIn)) return;
135-
if (!isArray(animationIn)) {
136-
throw new Error(ERROR.ANIMATION_IN);
137-
}
120+
if (!isArray(animationIn)) throw new Error(ERROR.ANIMATION_IN);
138121
},
139122

140123
function animationOut({ animationOut }) {
141124
if (isNull(animationOut)) return;
142-
if (!isArray(animationOut)) {
143-
throw new Error(ERROR.ANIMATION_OUT);
144-
}
125+
if (!isArray(animationOut)) throw new Error(ERROR.ANIMATION_OUT);
145126
},
146127

147128
function onRemoval({ onRemoval }) {
148129
if (!onRemoval) return;
149-
if (!isFunction(onRemoval)) {
150-
throw new Error(ERROR.REMOVAL_FUNC);
151-
}
130+
if (!isFunction(onRemoval)) throw new Error(ERROR.REMOVAL_FUNC);
152131
},
153132

154133
function dismiss({ dismiss }) {
@@ -164,39 +143,15 @@ export const validators = [
164143
touch
165144
} = dismiss;
166145

167-
if (isNull(duration)) {
168-
throw new Error(ERROR.DISMISS_REQUIRED);
169-
}
170-
171-
if (!isNumber(duration)) {
172-
throw new Error(ERROR.DISMISS_NUMBER);
173-
}
174-
if (duration < 0) {
175-
throw new Error(ERROR.DISMISS_POSITIVE);
176-
}
177-
178-
if (!isNull(onScreen) && !isBoolean(onScreen)) {
179-
throw new Error(ERROR.DISMISS_ONSCREEN_BOOL);
180-
}
181-
182-
if (!isNull(pauseOnHover) && !isBoolean(pauseOnHover)) {
146+
if (isNull(duration)) throw new Error(ERROR.DISMISS_REQUIRED);
147+
if (!isNumber(duration)) throw new Error(ERROR.DISMISS_NUMBER);
148+
if (duration < 0) throw new Error(ERROR.DISMISS_POSITIVE);
149+
if (!isNull(onScreen) && !isBoolean(onScreen)) throw new Error(ERROR.DISMISS_ONSCREEN_BOOL);
150+
if (!isNull(pauseOnHover) && !isBoolean(pauseOnHover))
183151
throw new Error(ERROR.DISMISS_PAUSE_BOOL);
184-
}
185-
186-
if (!isNull(click) && !isBoolean(click)) {
187-
throw new Error(ERROR.DISMISS_CLICK_BOOL);
188-
}
189-
190-
if (!isNull(touch) && !isBoolean(touch)) {
191-
throw new Error(ERROR.DISMISS_TOUCH_BOOL);
192-
}
193-
194-
if (!isNull(showIcon) && !isBoolean(showIcon)) {
195-
throw new Error(ERROR.DISMISS_ICON);
196-
}
197-
198-
if (!isNull(wait) && !isBoolean(wait)) {
199-
throw new Error(ERROR.DISMISS_WAIT);
200-
}
152+
if (!isNull(click) && !isBoolean(click)) throw new Error(ERROR.DISMISS_CLICK_BOOL);
153+
if (!isNull(touch) && !isBoolean(touch)) throw new Error(ERROR.DISMISS_TOUCH_BOOL);
154+
if (!isNull(showIcon) && !isBoolean(showIcon)) throw new Error(ERROR.DISMISS_ICON);
155+
if (!isNull(wait) && !isBoolean(wait)) throw new Error(ERROR.DISMISS_WAIT);
201156
}
202157
];

0 commit comments

Comments
 (0)