react#ElementType TypeScript Examples
The following examples show how to use
react#ElementType.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: classed.ts From apps with GNU Affero General Public License v3.0 | 7 votes |
function classed<T, P extends Record<string, unknown>>(
type: ElementType,
...className: string[]
): ForwardRefExoticComponent<PropsWithoutRef<P> & RefAttributes<T>> {
return forwardRef<T, P>(function Classed(props, ref) {
return React.createElement(type, {
...props,
className: classNames(
// eslint-disable-next-line react/prop-types
props?.className,
...className,
),
ref,
});
});
}
Example #2
Source File: ChangeLanguage.tsx From hamagen-react-native with MIT License | 6 votes |
ChangeLanguage: ElementType = ({ locale, strings: { languages: { title } }, languages: { long }, changeLocale, toggleChangeLanguage }: Props) => {
const onButtonPress = (selectedLocale: string) => {
selectedLocale !== locale && changeLocale(selectedLocale);
toggleChangeLanguage(false);
};
return (
<>
<View style={styles.titleWrapper}>
<Text style={styles.title} bold>{title}</Text>
</View>
<ScrollView
contentContainerStyle={{ alignItems: 'center' }}
showsVerticalScrollIndicator={false}
>
{
Object.keys(long).map((key: string, index: number) => (
<TouchableOpacity key={index} onPress={() => onButtonPress(key)}>
<View style={[styles.languageButton, key === locale && { backgroundColor: MAIN_COLOR }]}>
<Text style={[styles.text, key === locale && { color: '#fff' }]} black>{long[key]}</Text>
</View>
</TouchableOpacity>
))
}
</ScrollView>
</>
);
}
Example #3
Source File: ChangeLanguageButton.tsx From hamagen-react-native with MIT License | 6 votes |
ChangeLanguageButton: ElementType = ({ locale, strings: { languages: { title } }, languages: { short, long }, toggleChangeLanguage }: Props) => {
return (
<TouchableOpacity
onPress={() => toggleChangeLanguage(true)}
importantForAccessibility="no-hide-descendants"
accessibilityElementsHidden
accessibilityHint={long[locale]}
accessibilityLabel={title}
>
<View style={styles.container}>
<Text style={styles.text}>{short[locale]}</Text>
<Icon source={require('../../assets/onboarding/lang.png')} width={20} />
</View>
</TouchableOpacity>
);
}
Example #4
Source File: JoyTokenIcon.tsx From atlas with GNU General Public License v3.0 | 6 votes |
VARIANT_SIZE_COMPONENT_MAPPING: Record<JoyTokenIconVariant, Record<JoyTokenIconSize, ElementType>> = { primary: { 16: SvgJoyTokenPrimary16, 24: SvgJoyTokenPrimary24, 32: SvgJoyTokenPrimary32, 48: SvgJoyTokenPrimary48, }, silver: { 16: SvgJoyTokenSilver16, 24: SvgJoyTokenSilver24, 32: SvgJoyTokenSilver32, 48: SvgJoyTokenSilver48, }, regular: { 16: SvgJoyTokenMonochrome16, 24: SvgJoyTokenMonochrome24, 32: SvgJoyTokenMonochrome32, 48: SvgJoyTokenMonochrome48, }, gray: { 16: SvgJoyTokenMonochrome16, 24: SvgJoyTokenMonochrome24, 32: SvgJoyTokenMonochrome32, 48: SvgJoyTokenMonochrome48, }, }
Example #5
Source File: CodeEditor.tsx From hub with Apache License 2.0 | 6 votes |
CodeEditor: ElementType = (props: Props) => {
const { ctx } = useContext(AppCtx);
const { effective } = ctx.prefs.theme;
const isDisabled = !isUndefined(props.disabled) && props.disabled;
return (
<CodeMirror
className={classnames('border position-relative h-100', styles.code, { [styles.disabled]: isDisabled })}
value={props.value}
options={{
mode: {
name: props.mode,
json: true,
statementIndent: 2,
},
theme: effective === 'dark' ? 'material-darker' : 'elegant',
lineNumbers: true,
inputStyle: 'contenteditable',
viewportMargin: Infinity,
readOnly: isDisabled ? 'nocursor' : false,
tabindex: 0,
}}
editorDidMount={(editor) => {
editor.setSize('', '100%');
}}
onBeforeChange={(editor: any, data: any, value: string) => {
props.onChange(value);
}}
/>
);
}
Example #6
Source File: Button.tsx From pancake-toolkit with GNU General Public License v3.0 | 6 votes |
Button = <E extends ElementType = "button">(props: ButtonProps<E>): JSX.Element => { const { startIcon, endIcon, external, className, isLoading, disabled, children, ...rest } = props; const internalProps = external ? getExternalLinkProps() : {}; const isDisabled = isLoading || disabled; const classNames = className ? [className] : []; if (isLoading) { classNames.push("pancake-button--loading"); } if (isDisabled && !isLoading) { classNames.push("pancake-button--disabled"); } return ( <StyledButton $isLoading={isLoading} className={classNames.join(" ")} disabled={isDisabled} {...internalProps} {...rest} > <> {isValidElement(startIcon) && cloneElement(startIcon, { mr: "0.5rem", })} {children} {isValidElement(endIcon) && cloneElement(endIcon, { ml: "0.5rem", })} </> </StyledButton> ); }
Example #7
Source File: ParamInfo.tsx From hub with Apache License 2.0 | 6 votes |
Link: ElementType = (data: LinkProps) => {
const linkIcon =
data.children && isArray(data.children) && data.children[0] === 'iconLink' ? (
<FiExternalLink className={`position-relative ${styles.linkIcon}`} />
) : undefined;
return (
<a href={data.href} target={data.target} rel="noopener noreferrer" className="d-inline-block text-dark">
{linkIcon || data.children}
</a>
);
}
Example #8
Source File: index.tsx From engine with MIT License | 6 votes |
join = (...args: ProducersAndViews[]) => {
//@ts-ignore
const elements = flattenDeep(args);
const views = extractViews(args);
const producers = extractProducers(args);
const components = elements.filter(
(x: unknown) => !isView(x) && isValidElementType(x)
) as ElementType[];
if (views.length === 0 && components.length === 0 && producers.length === 0) {
console.error(
"Component creation failed using join. Please provide at least view, producer or react component"
);
return <></>;
}
if (views.length === 1 && components.length === 0) {
const view = views[0];
if (producers.length > 0) {
//@ts-ignore
view.producers(producers);
}
return view;
} else {
const list: (ElementType | View)[] = [...components, ...views];
const Component: view = ({ _props }: { _props: unknown }) => {
return (
<>
{list.map((X, i) => (
<X {..._props} key={i} />
))}
</>
);
};
Component.producers(producers);
return Component;
}
}
Example #9
Source File: Button.tsx From ui with MIT License | 6 votes |
export function Button<T extends ElementType = "button">({
as,
intent = "secondary",
size = "standard",
fluid,
children,
className,
...rest
}: ButtonProps<T>) {
const Element: ElementType = as;
const classNames = cx(
"button",
objectToClassnames({ intent, size }),
{ fluid },
className,
);
if (children !== undefined) {
return (
<Element className={classNames} {...rest}>
{children}
</Element>
);
}
return null;
}
Example #10
Source File: Field.tsx From ke with MIT License | 6 votes |
Field = makeWithLayout(
({ name, as, validator, label, isRequired, ...other }: FieldProps<unknown, ControlProps<unknown>>) => {
const controlRef = useRef<ControlRefProps>(null)
const { value, onChange } = useField(name, controlRef)
const { errors, validate } = useFieldValidation(name, value, validator)
const handleChange = useCallback(
async (v: unknown) => {
await validate(v)
onChange(v)
},
[onChange, validate]
)
// Don't found why, but type declaration necessary here https://github.com/microsoft/TypeScript/issues/28631#issuecomment-477240245
const Component: ElementType = as
return {
// Ðто обёртка
// eslint-disable-next-line react/jsx-props-no-spreading
Control: <Component ref={controlRef} value={value} onChange={handleChange} name={name} {...other} />,
Errors: errors && errors.length ? errors[0].message : '',
Label: label && (
<Label isRequired={isRequired} mb={2} display="inline-block">
{label}
</Label>
),
}
},
Simple
) as <T, P extends ControlProps<T>>(
props: PropsWithDefaultLayout<FieldProps<T, P>, { Control: JSX.Element }>
) => JSX.Element
Example #11
Source File: withPasswordProtect.tsx From next-password-protect with MIT License | 5 votes |
withPasswordProtect = (
App: any,
options?: PasswordProtectHOCOptions,
) => {
const ProtectedApp = ({ Component, pageProps, ...props }: AppProps) => {
const isAmp = useAmp();
const [isAuthenticated, setAuthenticated] = useState<undefined | boolean>(
undefined,
);
const checkIfLoggedIn = async () => {
try {
const res = await fetch(options?.checkApiUrl || '/api/passwordCheck', {
credentials: 'include',
});
if (res.status === 200) {
setAuthenticated(true);
} else {
setAuthenticated(false);
}
} catch (e) {
setAuthenticated(false);
}
};
useEffect(() => {
checkIfLoggedIn();
}, []);
if (isAuthenticated === undefined) {
return null;
}
if (isAuthenticated) {
return <App Component={Component} pageProps={pageProps} {...props} />;
}
// AMP is not yet supported
if (isAmp) {
return null;
}
const LoginComponent: ElementType =
options?.loginComponent || DefaultLoginComponent;
return (
<LoginComponent
apiUrl={options?.loginApiUrl}
{...(options?.loginComponentProps || {})}
/>
);
};
return ProtectedApp;
}
Example #12
Source File: context.ts From pancake-toolkit with GNU General Public License v3.0 | 5 votes |
MenuContext = createContext<{ linkComponent: ElementType }>({ linkComponent: "a" })
Example #13
Source File: index.tsx From fower with MIT License | 5 votes |
/**
* style any Component
* @param component tag name or React Component
* @param args
*
* @example
*
* ```jsx
* styled(Button)
*
* styled(Button, ['textXL', 'fontBold', 'textCenter'])
*
* styled(Button, {
* p: 8,
* color: 'red'
* })
*
* styled(Button, ['textXL', 'fontBold', 'textCenter'], { color: 'red' })
*
* ```
*/
export function styled<C extends keyof JSX.IntrinsicElements | ElementType>(
component: C,
...args: StyledArgs
): StyledComponent<
JSX.LibraryManagedAttributes<C, ComponentProps<C>> & AtomicProps & InjectedProps
> {
if (!component) return null as any
const StyledComponent = forwardRef((props = {}, ref) => {
const { inline } = store.config
const prepareProps = { ...argsToProps(args, store.config?.objectPropKeys?.[0]), ...props }
const parsedProps = inline
? getInLineParsedProps(prepareProps)
: getCssParsedProps(prepareProps)
return createElement(component, { ref, ...parsedProps })
})
StyledComponent.displayName =
typeof component === 'string' ? `Styled${upFirst(component as string)}` : 'StyledComponent'
hoistNonReactStatics(StyledComponent, component as any)
return StyledComponent
}
Example #14
Source File: Tag.tsx From webapis-playground with MIT License | 5 votes |
Tag = <Element extends ElementType = 'span'>({ children, as, className, leftIcon, rightIcon, ...props }: TagProps<Element> & ComponentPropsWithoutRef<Element>) => { let Component = as || 'span'; return ( <Component className={cx( ` tw-inline-flex tw-items-center tw-justify-center tw-py-1 tw-px-2 tw-text-xs tw-font-bold tw-text-white tw-whitespace-nowrap tw-uppercase tw-rounded-md tw-bg-gray-500 tw-transition tw-duration-100 tw-ease-in tw-appearance-none tw-select-none tw-align-middle active:tw-bg-gray-800 hover:tw-bg-gray-600 `, className )} {...filterDOMProps(props)} > {leftIcon && ( <span className="tw-inline-flex tw-self-center tw-flex-shrink-0 tw-mr-1"> {leftIcon} </span> )} {children} {rightIcon && ( <span className="tw-inline-flex tw-self-center tw-flex-shrink-0 tw-ml-1"> {rightIcon} </span> )} </Component> ); }
Example #15
Source File: IconButton.tsx From webapis-playground with MIT License | 5 votes |
IconButton = <Element extends ElementType = 'button'>({ children, icon, as, className, ...props }: IconButtonProps<Element> & ComponentPropsWithoutRef<Element>) => { let element = children || icon; const child = React.isValidElement(element) ? React.cloneElement(element as any, { 'aria-hidden': true, focusable: false, }) : null; let Component = as || 'button'; return ( <Component className={cx( ` tw-inline-flex tw-items-center tw-justify-center tw-px-3 tw-h-10 tw-text-base tw-font-semibold tw-text-gray-500 tw-whitespace-nowrap tw-rounded-md tw-bg-transparent tw-transition tw-duration-200 tw-ease-in tw-appearance-none tw-select-none tw-align-middle focus:tw-ring-4 focus:tw-ring-blue-200 focus:tw-outline-none active:tw-bg-gray-200 hover:tw-bg-gray-100 disabled:tw-opacity-50 disabled:tw-pointer-events-none disabled:tw-select-none `, className )} {...filterDOMProps(props)} > <span className="tw-inline-flex tw-self-center tw-flex-shrink-0"> {child} </span> </Component> ); }
Example #16
Source File: Button.tsx From webapis-playground with MIT License | 5 votes |
Button = <Element extends ElementType = 'button'>({ children, as, className, leftIcon, rightIcon, ...props }: ButtonProps<Element> & ComponentPropsWithoutRef<Element>) => { let Component = as || 'button'; return ( <Component className={cx( ` tw-inline-flex tw-items-center tw-justify-center tw-px-4 tw-h-10 tw-text-base tw-font-semibold tw-text-white tw-whitespace-nowrap tw-rounded-md tw-bg-blue-500 tw-transition tw-duration-100 tw-ease-in tw-appearance-none tw-select-none tw-align-middle focus:tw-ring-4 focus:tw-ring-blue-300 focus:tw-outline-none active:tw-bg-blue-800 hover:tw-bg-blue-600 disabled:tw-opacity-50 disabled:tw-pointer-events-none disabled:tw-select-none `, className )} {...filterDOMProps(props)} > {leftIcon && ( <span className="tw-inline-flex tw-self-center tw-flex-shrink-0 tw-mr-2"> {leftIcon} </span> )} {children} {rightIcon && ( <span className="tw-inline-flex tw-self-center tw-flex-shrink-0 tw-ml-2"> {rightIcon} </span> )} </Component> ); }
Example #17
Source File: ParamInfo.tsx From hub with Apache License 2.0 | 5 votes |
Heading: ElementType = (data: HeadingProps) => {
const Tag = `h${data.level}` as 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
return <Tag className={`text-dark lh-1 fw-bold ${styles.header}`}>{data.children}</Tag>;
}
Example #18
Source File: index.tsx From hub with Apache License 2.0 | 5 votes |
Heading: ElementType = (data: HeadingProps) => {
const Tag = `h${data.level}` as 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
return <Tag className={`text-dark lh-1 fw-bold ${styles.header}`}>{data.children}</Tag>;
}
Example #19
Source File: AnchorHeader.tsx From hub with Apache License 2.0 | 5 votes |
AnchorHeader: ElementType = (props: Props) => {
let value = props.title;
if (isUndefined(value) && props.children && props.children.length > 0) {
const allContentValues = props.children.map((n: any) => {
if (isString(n)) {
return [n];
} else if (isObject(n)) {
return String((n as any).props.children);
} else {
return '';
}
});
value = allContentValues.join('');
}
if (isUndefined(value)) return null;
const Tag = `h${props.level}` as 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
const anchor = props.anchorName || getAnchorValue(value);
return (
<span className={styles.header}>
<Tag className={`position-relative anchorHeader ${styles.headingWrapper} ${props.className}`}>
<div data-testid="anchor" className={`position-absolute ${styles.headerAnchor}`} id={anchor} />
<a
href={`${history.location.pathname}#${anchor}`}
onClick={(e: ReactMouseEvent<HTMLAnchorElement, MouseEvent>) => {
e.preventDefault();
e.stopPropagation();
props.scrollIntoView(`#${anchor}`);
}}
role="button"
className={`text-reset text-center d-none d-md-block lh-1 float-start ${styles.headingLink}`}
aria-label={value}
>
<GoLink />
</a>
{props.title || props.children}
</Tag>
</span>
);
}
Example #20
Source File: Alert.tsx From hub with Apache License 2.0 | 5 votes |
Alert: ElementType = (props: Props) => {
const [errorMessage, setErrorMessage] = useState<string | null>(null);
const errorWrapper = useRef<HTMLDivElement>(null);
const [isVisible, setIsVisible] = useState<boolean>(false);
useEffect(() => {
let timeout: NodeJS.Timeout;
if (isNull(props.message)) {
if (!isNull(errorMessage)) {
setIsVisible(false);
timeout = setTimeout(() => {
setErrorMessage(null);
}, 1000);
}
} else {
if (props.message !== errorMessage) {
setErrorMessage(props.message);
setIsVisible(true);
errorWrapper.current!.scrollIntoView({ block: 'start', inline: 'nearest', behavior: 'smooth' });
}
}
return () => {
if (!isUndefined(timeout)) {
clearTimeout(timeout);
}
};
}, [props.message]); /* eslint-disable-line react-hooks/exhaustive-deps */
return (
<div
data-testid="alertWrapper"
className={classnames('overflow-hidden', styles.alertWrapper, { [styles.isAlertActive]: isVisible })}
ref={errorWrapper}
>
{isVisible && (
<div className={`alert alert-${props.type || DEFAULT_ALERT_TYPE} mt-3 mb-0`} role="alert">
<div className="d-flex flex-row align-items-start justify-content-between">
<div>{errorMessage || ''}</div>
{!isUndefined(props.onClose) && (
<button
data-testid="closeAlertBtn"
type="button"
className="btn-close ms-3"
onClick={props.onClose}
aria-label="Close alert"
></button>
)}
</div>
</div>
)}
</div>
);
}
Example #21
Source File: Readme.tsx From hub with Apache License 2.0 | 4 votes |
Readme = (props: Props) => {
const Code: ElementType = ({ inline, className, children }: CodeProps) => {
const match = /language-(\w+)/.exec(className || '');
if (inline) {
return <code className={className}>{children}</code>;
} else {
return (
<SyntaxHighlighter language={checkCodeLanguage(match ? match[1] : 'bash')} style={github}>
{String(children).replace(/\n$/, '')}
</SyntaxHighlighter>
);
}
};
const Image: ElementType = (data: ImageProps) => {
const img = useRef<HTMLImageElement>(null);
const [error, setError] = useState<boolean>(false);
const [isBigImage, setIsBigImage] = useState<boolean>(false);
const point = useBreakpointDetect();
const checkImageInBreakpoint = useCallback(() => {
if (!isNull(img) && img.current && point && ['md', 'lg', 'xl'].includes(point) && img.current!.width > 410) {
setIsBigImage(true);
}
}, [point]);
useEffect(() => {
checkImageInBreakpoint();
}, [point, checkImageInBreakpoint]);
return /^https?:/.test(data.src) ? (
<span className={classnames({ 'overflow-hidden d-table-cell': isBigImage })}>
<img
ref={img}
src={data.src}
alt={data.alt || ''}
className={classnames({ 'd-none': error })}
onError={() => setError(true)}
onLoad={checkImageInBreakpoint}
/>
</span>
) : null;
};
// Only for external links and anchors
const Link: ElementType = (data: LinkProps) => {
const isContentImage =
data.children && isArray(data.children) && data.children.length > 0 && !isUndefined(data.children[0].props)
? !isUndefined(data.children[0].props.src)
: false;
if (/^https?:/.test(data.href)) {
return (
// We need to force display inline when content is not an image due to
// .paragraph a:only-child {
// display: table-cell;
// }
<a
href={data.href}
target={data.target}
rel="noopener noreferrer"
className={classnames('text-primary', { 'd-inline': !isContentImage })}
>
{data.children}
</a>
);
// We only displays anchors when title is on the Readme
} else if (data.href.startsWith('#') && isElementInView(data.href)) {
return (
<button
className={classnames('btn btn-link text-primary text-start border-0 p-0', styles.btnLink)}
onClick={() => props.scrollIntoView(data.href)}
aria-label="Go to element"
>
{data.children}
</button>
);
} else {
return <>{data.children}</>;
}
};
const Table: ElementType = (data: BasicProps) => (
<div className="mw-100 overflow-auto">
<table>{data.children}</table>
</div>
);
const Paragraph: ElementType = (data: BasicProps) => {
const isOneChild = data.children && isArray(data.children) && data.children.length === 1;
if (isUndefined(data.children)) return null;
return <p className={classnames({ 'd-block w-100 h-100': isOneChild }, styles.paragraph)}>{data.children}</p>;
};
const Blockquote: ElementType = (data: BasicProps) => {
return <blockquote className={`text-muted position-relative ${styles.quote}`}>{data.children}</blockquote>;
};
const Heading: ElementType = (data: any) => <AnchorHeader {...data} scrollIntoView={props.scrollIntoView} />;
const isElementInView = (id: string) => {
try {
const item = document.querySelector(id);
return !isNull(item);
} catch {
return false;
}
};
const Pre: ElementType = (props: CodeProps) => {
return <>{props.children}</>;
};
return (
<ReactMarkdown
className={`mt-3 mb-5 position-relative ${styles.md}`}
children={props.readme}
linkTarget="_blank"
skipHtml
remarkPlugins={[[remarkGfm, { tableCellPadding: false }]]}
components={{
pre: Pre,
code: Code,
image: Image,
img: Image,
a: Link,
table: Table,
h1: Heading,
h2: Heading,
h3: Heading,
h4: Heading,
h5: Heading,
h6: Heading,
p: Paragraph,
blockquote: Blockquote,
}}
/>
);
}
Example #22
Source File: PublisherInstructionsInstall.tsx From hub with Apache License 2.0 | 4 votes |
PublisherInstructionsInstall = (props: Props) => {
const Code: ElementType = (props: CodeProps) => {
if (props.inline) {
return <code className={`border ${styles.inlineCode}`}>{props.children}</code>;
}
if (props.children) {
const content = String(props.children).replace(/\n$/, '');
return <CommandBlock command={content} />;
} else {
return null;
}
};
const Pre: ElementType = (props: CodeProps) => {
return <>{props.children}</>;
};
const Heading: ElementType = (props: HeadingProps) => (
<div className="my-2">
<div className={`h${props.level} text-muted pt-2 pb-1`}>
<div className={styles.mdHeader}>{props.children}</div>
</div>
</div>
);
const Table: ElementType = (data: TableProps) => (
<div className="w-100 overflow-auto">
<table>{data.children}</table>
</div>
);
const Image: ElementType = (data: ImageProps) => {
const [error, setError] = useState<boolean>(false);
// Only absolute path
return /^https?:/.test(data.src) ? (
<img
src={data.src}
alt={data.alt || ''}
className={classnames('mw-100', { 'd-none': error })}
onError={() => setError(true)}
/>
) : null;
};
// Only for external links and anchors
const Link: ElementType = (data: LinkProps) => {
// Only absolute link
return /^https?:/.test(data.href) ? (
<a href={data.href} target={data.target} rel="noopener noreferrer" className="text-primary">
{data.children}
</a>
) : null;
};
return (
<ErrorBoundary message="Something went wrong rendering the install instructions of this package.">
<span data-testid="readme">
<ReactMarkdown
className={`mt-3 mb-5 ${styles.md}`}
children={props.install}
linkTarget="_blank"
remarkPlugins={[[remarkGfm, { singleTilde: false }]]}
skipHtml
components={{
pre: Pre,
code: Code,
img: Image,
a: Link,
h1: Heading,
h2: Heading,
h3: Heading,
h4: Heading,
h5: Heading,
h6: Heading,
table: Table,
}}
/>
</span>
</ErrorBoundary>
);
}
Example #23
Source File: index.tsx From hub with Apache License 2.0 | 4 votes |
UserNotificationsController: ElementType = () => {
const { dispatch, ctx } = useContext(AppCtx);
const [notification, setNotification] = useState<UserNotification | null>(null);
const [isVisible, setIsVisible] = useState<boolean>(false);
const [addNotificationTimeout, setAddNotificationTimeout] = useState<NodeJS.Timeout | undefined>(undefined);
const [dismissNotificationTimeout, setDismissNotificationTimeout] = useState<NodeJS.Timeout | undefined>(undefined);
const point = useBreakpointDetect();
notificationsDispatcher.subscribe({
updateUserNotificationsWrapper: (notif: UserNotification | null) => {
if (!isNull(notif)) {
setNotification(notif);
setIsVisible(true);
setAddNotificationTimeout(
setTimeout(() => {
dispatch(addNewDisplayedNotification(notif.id));
}, ANIMATION_TIME)
);
} else {
setIsVisible(false);
setDismissNotificationTimeout(
setTimeout(() => {
if (!isNull(notification)) {
setNotification(null);
}
}, ANIMATION_TIME)
);
}
},
});
const onClose = () => {
notificationsDispatcher.dismissNotification();
};
const onChangeNotificationsPrefs = () => {
notificationsDispatcher.dismissNotification();
// Change user prefs
dispatch(enabledDisplayedNotifications(false));
};
useEffect(() => {
if (!isUndefined(ctx.user)) {
notificationsDispatcher.start(ctx.prefs.notifications, point);
}
return () => {
notificationsDispatcher.close();
};
}, [ctx.user]); /* eslint-disable-line react-hooks/exhaustive-deps */
useEffect(() => {
if (!isUndefined(ctx.user)) {
notificationsDispatcher.updateSettings(ctx.prefs.notifications);
}
}, [ctx.prefs.notifications]); /* eslint-disable-line react-hooks/exhaustive-deps */
useEffect(() => {
return () => {
if (addNotificationTimeout) {
clearTimeout(addNotificationTimeout);
}
if (dismissNotificationTimeout) {
clearTimeout(dismissNotificationTimeout);
}
};
}, [addNotificationTimeout, dismissNotificationTimeout]);
return (
<div className="d-none d-md-flex justify-content-center align-items-center w-100">
<div
className={classnames(
'position-fixed toast fade border border-3 bg-white opacity-0',
styles.toast,
{
[`show opacity-100 ${styles.isVisible}`]: !isNull(notification) && isVisible,
},
'notificationCard'
)}
role="alert"
aria-live="assertive"
aria-atomic="true"
>
{!isNull(notification) && (
<div className="toast-body" data-testid="notificationContent">
<div>
<div className={`float-end ${styles.btnsWrapper}`}>
<div className="d-flex flex-row align-items-center">
<button
type="button"
className={`btn btn-link text-dark py-0 ${styles.btn}`}
onClick={onChangeNotificationsPrefs}
aria-label="Disable usage tips"
>
Don't show me more again
</button>
<button
type="button"
className={`btn-close ${styles.closeBtn}`}
onClick={onClose}
aria-label="Close"
></button>
</div>
</div>
<span>
<ReactMarkdown
className={styles.content}
children={notification.body}
components={{
h1: Heading,
h2: Heading,
h3: Heading,
h4: Heading,
h5: Heading,
h6: Heading,
}}
linkTarget="_blank"
skipHtml
/>
</span>
</div>
</div>
)}
</div>
</div>
);
}