From b0358fab49bb060e8944dfcb20451629dfc2263f Mon Sep 17 00:00:00 2001 From: Dominik Danielewicz Date: Tue, 31 Oct 2023 09:24:19 +0100 Subject: [PATCH] feat: notification width and position (#220) * feature: notification width and position * closes #216 && #218 Co-authored-by: PdoubleU --- .../intro/animations/changing-transitions.md | 2 +- docs/docs/intro/basics/basic-configuration.md | 2 +- .../global-notifications-settings.md | 17 +-- .../order-of-settings-overwriting.md | 3 + .../intro/default-variants-config/position.md | 11 +- .../intro/default-variants-config/width.md | 113 ++++++++++++++++++ docs/docs/intro/examples/custom-examples.md | 2 +- .../examples/notification-in-modal-example.md | 2 +- .../intro/types/custom-components-examples.md | 2 +- example/yarn.lock | 2 +- src/core/hooks/useNotificationsStates.ts | 9 +- src/core/renderers/GestureHandler.tsx | 24 +++- src/core/utils/pickers.ts | 38 ++++-- src/types.ts | 1 + src/types/config.ts | 9 +- yarn.lock | 2 +- 16 files changed, 202 insertions(+), 37 deletions(-) create mode 100644 docs/docs/intro/default-variants-config/width.md diff --git a/docs/docs/intro/animations/changing-transitions.md b/docs/docs/intro/animations/changing-transitions.md index 0b4ef903..407a42c2 100644 --- a/docs/docs/intro/animations/changing-transitions.md +++ b/docs/docs/intro/animations/changing-transitions.md @@ -2,7 +2,7 @@ sidebar_position: 1 --- -# 🊄 Transitions +# 🔄 Transitions ### 🎛 Changing transitions diff --git a/docs/docs/intro/basics/basic-configuration.md b/docs/docs/intro/basics/basic-configuration.md index 36bfc297..72f302d4 100644 --- a/docs/docs/intro/basics/basic-configuration.md +++ b/docs/docs/intro/basics/basic-configuration.md @@ -2,7 +2,7 @@ sidebar_position: 2 --- -# 🊛 Basic configuration +# 🛠 Basic configuration ### Create Notifications diff --git a/docs/docs/intro/comprehensive-configuration/global-notifications-settings.md b/docs/docs/intro/comprehensive-configuration/global-notifications-settings.md index 0901af85..dd0886c0 100644 --- a/docs/docs/intro/comprehensive-configuration/global-notifications-settings.md +++ b/docs/docs/intro/comprehensive-configuration/global-notifications-settings.md @@ -12,14 +12,15 @@ In the beginning, you can set the configuration for all the notifications used i Let's take a look at what exactly can we set globally: -| Name | Type | Default | Description | -| --------------------- | :-------------------------: | :----------------------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| duration | Number | 3000 | Use this property to set how long the notifications should be displayed on the screen. Value expressed in milliseconds | -| notificationPosition | 'top' / 'center' / 'bottom' | 'top' | Set where the notifications should appear on the screen. You can choose one of three default options: top / center / bottom. To read more about the notification position please go to the [NOTIFICATION POSITION](../default-variants-config/position) section. | -| animationConfig | Object | SlideInLeftSlideOutRight | Property responsible for the notification animation. You can set one of the animations prepared by us, or make your own config. To read more about the animation settings please go to the [ANIMATIONS SETTINGS](../animations/changing-transitions) section. | -| isNotch | Boolean | false | Property responsible for read if the device has notch. You can use one of the libraries (for example 'react-native-device-info') to read if the specific device has Notch and pass the value here. | -| gestureConfig | Object | iOS: 'y' / android: 'x' | Object responsible for setting gesture direction that triggers swipe-dismiss of notification. To read more about gesture config, please go to the [GESTURE CONFIG](../default-variants-config/props-config) section. | -| defaultStylesSettings | Object | - | Object responsible for setting global styles for the notifications. You can also set here styles, for all the notifications of the specific type. For example for the error notifications. To read more about global style settings please go to the [GLOBAL STYLES SETTINGS](../default-variants-config/global-config) section. | +| Name | Type | Default | Description | +| --------------------- | :-------------------------------------------------------------------------------------: | :----------------------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| duration | Number | 3000 | Use this property to set how long the notifications should be displayed on the screen. Value expressed in milliseconds. | +| notificationPosition | 'top' / 'top-right' / 'top-left' / 'center' / 'bottom' / 'bottom-right' / 'bottom-left' | 'top' | Set where the notifications should appear on the screen. You can choose one of seven default options: top / top-right / top-left / center / bottom / bottom-right / bottom-left. To read more about the notification position please go to the [NOTIFICATION POSITION](../default-variants-config/position) section. | +| notificationWidth | Number | 343 | Use this property to set the width, in pixels, of the notifications that will be displayed on the screen. | +| animationConfig | Object | SlideInLeftSlideOutRight | Property responsible for the notification animation. You can set one of the animations prepared by us, or make your own config. To read more about the animation settings please go to the [ANIMATIONS SETTINGS](../animations/changing-transitions) section. | +| isNotch | Boolean | false | Property responsible for read if the device has notch. You can use one of the libraries (for example 'react-native-device-info') to read if the specific device has Notch and pass the value here. | +| gestureConfig | Object | iOS: 'y' / android: 'x' | Object responsible for setting gesture direction that triggers swipe-dismiss of notification. To read more about gesture config, please go to the [GESTURE CONFIG](../default-variants-config/props-config) section. | +| defaultStylesSettings | Object | - | Object responsible for setting global styles for the notifications. You can also set here styles, for all the notifications of the specific type. For example for the error notifications. To read more about global style settings please go to the [GLOBAL STYLES SETTINGS](../default-variants-config/global-config) section. |
diff --git a/docs/docs/intro/comprehensive-configuration/order-of-settings-overwriting.md b/docs/docs/intro/comprehensive-configuration/order-of-settings-overwriting.md index 077bea7c..5c818987 100644 --- a/docs/docs/intro/comprehensive-configuration/order-of-settings-overwriting.md +++ b/docs/docs/intro/comprehensive-configuration/order-of-settings-overwriting.md @@ -113,6 +113,7 @@ const { useNotifications, NotificationsProvider } = createNotifications({ isNotch: true, duration: 30, notificationPosition: 'top', + notificationWidth: 400, animationConfig: SlideInLeftSlideOutRight, defaultStylesSettings: { darkMode: false, @@ -139,6 +140,7 @@ All those properties: - isNotch - duration - notificationPosition +- notificationWidth - animationConfig (defaultStylesSettings) @@ -238,6 +240,7 @@ All those properties: (config) - notificationPosition +- notificationWidth - animationConfig - duration diff --git a/docs/docs/intro/default-variants-config/position.md b/docs/docs/intro/default-variants-config/position.md index 6ae1e0fc..4cc721c9 100644 --- a/docs/docs/intro/default-variants-config/position.md +++ b/docs/docs/intro/default-variants-config/position.md @@ -2,17 +2,22 @@ sidebar_position: 2 --- -# 🊄 Notification position +# 📌 Notification position + #### ## 🎛 Changing position You can change the position of the notifications displayed on the screen.
-There are three possible options to choose from: +There are seven possible options to choose from: - `top` - at the top of the screen +- `top-right` - at the top right of the screen +- `top-left` - at the top left of the screen - `center` - at the middle of the screen (y-axis) - `bottom`- at the bottom of the screen +- `bottom-right` - at the bottom right of the screen +- `bottom-left` - at the bottom left of the screen The default setting for the `notificationPosition` is the `top` value. @@ -52,7 +57,6 @@ export const ExampleNotification = () => { ) } - ``` Now all the notifications in the app will be displayed in the middle of the screen (y-axis) because we have set the `notificationPosition` value for the `center`. @@ -60,7 +64,6 @@ Now all the notifications in the app will be displayed in the middle of the scre

- ### Set the position locally inside config object in a single notification instance: ```jsx diff --git a/docs/docs/intro/default-variants-config/width.md b/docs/docs/intro/default-variants-config/width.md new file mode 100644 index 00000000..ecc7baca --- /dev/null +++ b/docs/docs/intro/default-variants-config/width.md @@ -0,0 +1,113 @@ +--- +sidebar_position: 2 +--- + +# 📏 Notification width + +#### + +## 🎛 Changing width + +You can change the width of the notifications displayed on the screen.
+ +By default, the `notificationWidth` is set to 343 pixels. If you don't specify a value for `notificationWidth`, notifications will default to this width. + +If the value you provide for `notificationWidth` exceeds the device's width, the notification's width will be adjusted to the device width minus the margin value. + +Depending on whether you want to change the notification width for the whole app or only change it for a certain notification, you can either: + +
+ +### Set the width for all notifications in the global config object: + +```jsx +import React from 'react' +import { SafeAreaView, Text } from 'react-native' +import { createNotifications } from 'react-native-notificated' +import { styles } from './styles' + +const { NotificationsProvider, useNotifications } = createNotifications({ + notificationWidth: 400, +}) + +export const ExampleNotification = () => { + const { notify } = useNotifications() + + return ( + + + + notify('error', { + params: { + description: 'This is where the toast text goes. ', + title: 'Error', + }, + }) + }> + Emit error + + + ) +} +``` + +"Now, all notifications in the application will be 400 pixels wide because we've set the `notificationWidth` value to 400." + +
+
+ +### Set the position locally inside config object in a single notification instance: + +```jsx +import React from 'react' +import { SafeAreaView, Text } from 'react-native' +import { createNotifications } from 'react-native-notificated' +import { styles } from './styles' + +const { NotificationsProvider, useNotifications } = createNotifications({ + notificationWidth: 400, +}) + +export const ExampleNotification = () => { + const { notify } = useNotifications() + + return ( + + + + notify('error', { + params: { + description: 'This is where the toast text goes', + title: 'Error', + }, + config: { + notificationWidth: 500, + }, + }) + }> + Emit error + + + ) +} +``` + +Now, all notifications in the app will be displayed with a width of 400 pixels, except for the `error` notification mentioned in the previous example.
+That `error` notification will have a width of 500 pixels because local configuration overrides the global setting.
+Of course, if you prefer, you can set the width locally without adjusting the global setting.
+(You can read more about props overwriting in the [ORDER OF SETTINGS OVERWRITING](../comprehensive-configuration/order-of-settings-overwriting) section) + +
+
+ +## ðŸ”Ķ Width config priority + +For each subsequent notification, the library looks for a notification width in the following order: + +1. First, it looks for a config defined in `notify` payload +2. Secondly, it looks for a global config from `createNotification` +3. At last, when no config is found, it uses the default behavior, which is 343 pixels + +
diff --git a/docs/docs/intro/examples/custom-examples.md b/docs/docs/intro/examples/custom-examples.md index ea45a5d8..6c2d67f5 100644 --- a/docs/docs/intro/examples/custom-examples.md +++ b/docs/docs/intro/examples/custom-examples.md @@ -2,7 +2,7 @@ sidebar_position: 5 --- -# ðŸŠķ Custom examples +# 🧭 Custom examples
diff --git a/docs/docs/intro/examples/notification-in-modal-example.md b/docs/docs/intro/examples/notification-in-modal-example.md index 5e13375d..f8c7b13c 100644 --- a/docs/docs/intro/examples/notification-in-modal-example.md +++ b/docs/docs/intro/examples/notification-in-modal-example.md @@ -2,7 +2,7 @@ sidebar_position: 8 --- -# ðŸŠķ Notifcation In Modal Example +# 🔔 Notifcation In Modal Example
diff --git a/docs/docs/intro/types/custom-components-examples.md b/docs/docs/intro/types/custom-components-examples.md index eb333c02..14c61892 100644 --- a/docs/docs/intro/types/custom-components-examples.md +++ b/docs/docs/intro/types/custom-components-examples.md @@ -2,7 +2,7 @@ sidebar_position: 1 --- -# 🊎 Specifying default types +# 🔧 Specifying default types
diff --git a/example/yarn.lock b/example/yarn.lock index 09b3c55d..449e4ee7 100644 --- a/example/yarn.lock +++ b/example/yarn.lock @@ -7651,4 +7651,4 @@ yargs@^15.1.0, yargs@^15.3.1, yargs@^15.4.1: string-width "^4.2.0" which-module "^2.0.0" y18n "^4.0.0" - yargs-parser "^18.1.2" + yargs-parser "^18.1.2" \ No newline at end of file diff --git a/src/core/hooks/useNotificationsStates.ts b/src/core/hooks/useNotificationsStates.ts index 3d3fa2de..bfed2487 100644 --- a/src/core/hooks/useNotificationsStates.ts +++ b/src/core/hooks/useNotificationsStates.ts @@ -1,7 +1,7 @@ import { useReducer, useRef, useState } from 'react' import { useWindowDimensions } from 'react-native' import { useNotificationConfig } from './useNotificationConfig' -import { getTopOffset, mergeConfigs } from '../utils/pickers' +import { getNotificationOffset, mergeConfigs } from '../utils/pickers' import { queueReducer } from '../utils/queueReducer' import { useStatusBarHeightDetector } from './useStatusBarHeightDetector' @@ -18,7 +18,7 @@ export const useNotificationsStates = () => { const notificationEvent = notificationsQueue[0] const config = mergeConfigs(globalConfig, notificationEvent) - const topOffset = getTopOffset({ + const notificationOffset = getNotificationOffset({ globalConfig: config, notificationHeight, isPortraitMode, @@ -29,13 +29,14 @@ export const useNotificationsStates = () => { return { config, dispatch, - topOffset, + notificationOffset, panHandlerRef, notificationEvent, notificationsQueue, longPressHandlerRef, setNotificationHeight, - isPortaitMode: isPortraitMode, + isPortrait: isPortraitMode, + notificationWidth: config.notificationWidth, } } diff --git a/src/core/renderers/GestureHandler.tsx b/src/core/renderers/GestureHandler.tsx index cf977955..00e36199 100644 --- a/src/core/renderers/GestureHandler.tsx +++ b/src/core/renderers/GestureHandler.tsx @@ -14,8 +14,9 @@ type Props = { | 'longPressHandlerRef' | 'panHandlerRef' | 'setNotificationHeight' - | 'topOffset' - | 'isPortaitMode' + | 'notificationOffset' + | 'isPortrait' + | 'notificationWidth' > animationAPI: Pick notificationTopPosition?: number @@ -28,14 +29,23 @@ export const GestureHandler = ({ notificationTopPosition, }: Props) => { const { width } = useWindowDimensions() - const notificationWidth = state.isPortaitMode - ? width - Constants.notificationSideMargin * 2 - : Constants.maxNotificationWidth + + const fullWidth = width - Constants.notificationSideMargin * 2 + + const initialNotificationWidth = state?.notificationWidth || Constants.maxNotificationWidth + + const isWidthWithinBounds = initialNotificationWidth <= fullWidth + + const notificationWidth = isWidthWithinBounds ? initialNotificationWidth : fullWidth const top = notificationTopPosition || notificationTopPosition === 0 ? notificationTopPosition - : state.topOffset + : state.notificationOffset.top + + const left = state.notificationOffset.left + + const right = state.notificationOffset.right return ( diff --git a/src/core/utils/pickers.ts b/src/core/utils/pickers.ts index a8baad41..cfee4d15 100644 --- a/src/core/utils/pickers.ts +++ b/src/core/utils/pickers.ts @@ -4,7 +4,7 @@ import type { DefaultKeys, DefaultStylesConfigs } from '../../defaultConfig/type import type { KeyType } from '../../types/misc' import { Constants } from '../config' -type GetOffsetTopProps = { +type GetNotificationOffsetProps = { globalConfig: NotificationsConfig notificationHeight: number isPortraitMode: boolean @@ -12,13 +12,13 @@ type GetOffsetTopProps = { statusBarHeight: number } -export const getTopOffset = ({ +export const getNotificationOffset = ({ globalConfig, notificationHeight, isPortraitMode, windowHeight, statusBarHeight, -}: GetOffsetTopProps) => { +}: GetNotificationOffsetProps) => { const isNotch = globalConfig.isNotch const extraSpace = statusBarHeight + 10 @@ -26,16 +26,40 @@ export const getTopOffset = ({ const topPosition = shouldRenderExtraSpace ? extraSpace : 10 const notificationPosition = globalConfig.notificationPosition + let topOffset, leftOffset, rightOffset + switch (notificationPosition) { case 'top': - return topPosition + topOffset = topPosition + break + case 'top-left': + topOffset = topPosition + leftOffset = Constants.notificationSideMargin + break + case 'top-right': + topOffset = topPosition + rightOffset = Constants.notificationSideMargin + break case 'center': - return windowHeight / 2 - (notificationHeight ? notificationHeight / 2 : 75) + topOffset = windowHeight / 2 - (notificationHeight ? notificationHeight / 2 + 10 : 75) + break case 'bottom': - return windowHeight - (notificationHeight ? notificationHeight + extraSpace : 150) + topOffset = windowHeight - (notificationHeight ? notificationHeight + extraSpace : 150) + break + case 'bottom-left': + topOffset = windowHeight - (notificationHeight ? notificationHeight + extraSpace : 150) + leftOffset = Constants.notificationSideMargin + break + case 'bottom-right': + topOffset = windowHeight - (notificationHeight ? notificationHeight + extraSpace : 150) + rightOffset = Constants.notificationSideMargin + break default: - return topPosition + topOffset = topPosition + break } + + return { top: topOffset, left: leftOffset, right: rightOffset } } export const pickVariant = ( diff --git a/src/types.ts b/src/types.ts index 172264b2..c0e1243f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -33,6 +33,7 @@ export type NotificationConfigBase = { animationConfig: AnimationBuilder | CustomAnimationConfig gestureConfig: GestureConfig isNotch?: boolean + notificationWidth?: number onClose?: () => void } diff --git a/src/types/config.ts b/src/types/config.ts index 3c6dbd21..b0e82e1e 100644 --- a/src/types/config.ts +++ b/src/types/config.ts @@ -1,5 +1,12 @@ export type NotificationsType = 'default' | 'success' | 'warning' | 'error' -export type NotificationPosition = 'top' | 'center' | 'bottom' +export type NotificationPosition = + | 'top' + | 'center' + | 'bottom' + | 'top-left' + | 'top-right' + | 'bottom-left' + | 'bottom-right' export type NotificationConfig = { type: NotificationsType diff --git a/yarn.lock b/yarn.lock index 4f790635..0d92dac0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10498,4 +10498,4 @@ yargs@^16.2.0: yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== \ No newline at end of file