refactor: rewrite some components to TS for better lint

This commit is contained in:
Tim 2025-01-06 10:45:59 +01:00
parent 003881d06d
commit 510f91e031
17 changed files with 125 additions and 119 deletions

View file

@ -4,7 +4,7 @@ const React = require('react');
const PropTypes = require('prop-types');
const classnames = require('classnames');
const { default: Icon } = require('@stremio/stremio-icons/react');
const Image = require('stremio/components/Image');
const { default: Image } = require('stremio/components/Image');
const styles = require('./styles');
const AddonDetails = ({ className, id, name, version, logo, description, types, transportUrl, official }) => {

View file

@ -1,65 +0,0 @@
// Copyright (C) 2017-2023 Smart code 203358507
const React = require('react');
const PropTypes = require('prop-types');
const classnames = require('classnames');
const styles = require('./styles');
const { useLongPress } = require('use-long-press');
const Button = React.forwardRef(({ className, href, disabled, children, onLongPress, onDoubleClick, ...props }, ref) => {
const longPress = useLongPress(onLongPress, { detect: 'pointer' });
const onKeyDown = React.useCallback((event) => {
if (typeof props.onKeyDown === 'function') {
props.onKeyDown(event);
}
if (event.key === 'Enter') {
event.preventDefault();
if (!event.nativeEvent.buttonClickPrevented) {
event.currentTarget.click();
}
}
}, [props.onKeyDown]);
const onMouseDown = React.useCallback((event) => {
if (typeof props.onMouseDown === 'function') {
props.onMouseDown(event);
}
if (!event.nativeEvent.buttonBlurPrevented) {
event.preventDefault();
if (document.activeElement instanceof HTMLElement) {
document.activeElement.blur();
}
}
}, [props.onMouseDown]);
return React.createElement(
typeof href === 'string' && href.length > 0 ? 'a' : 'div',
{
tabIndex: 0,
...props,
ref,
className: classnames(className, styles['button-container'], { 'disabled': disabled }),
href,
onKeyDown,
onMouseDown,
onDoubleClick,
...longPress()
},
children
);
});
Button.displayName = 'Button';
Button.propTypes = {
className: PropTypes.string,
href: PropTypes.string,
disabled: PropTypes.bool,
children: PropTypes.node,
onKeyDown: PropTypes.func,
onMouseDown: PropTypes.func,
onLongPress: PropTypes.func,
onDoubleClick: PropTypes.func
};
module.exports = Button;

View file

@ -0,0 +1,71 @@
// Copyright (C) 2017-2023 Smart code 203358507
import { createElement, forwardRef, useCallback } from 'react';
import classNames from 'classnames';
import { LongPressEventType, useLongPress } from 'use-long-press';
import styles from './Button.less';
type Props = {
className?: string,
href?: string,
title?: string,
disabled?: boolean,
tabIndex?: number,
children: React.ReactNode,
onKeyDown?: (event: React.KeyboardEvent) => void,
onMouseDown?: (event: React.MouseEvent) => void,
onLongPress?: () => void,
onClick?: (event: React.MouseEvent<HTMLDivElement>) => void,
onDoubleClick?: () => void,
};
const Button = forwardRef(({ className, href, disabled, children, onLongPress, onDoubleClick, ...props }: Props, ref) => {
const longPress = useLongPress(onLongPress!, { detect: LongPressEventType.Pointer });
const onKeyDown = useCallback((event: React.KeyboardEvent<HTMLDivElement>) => {
if (typeof props.onKeyDown === 'function') {
props.onKeyDown(event);
}
if (event.key === 'Enter') {
event.preventDefault();
// @ts-expect-error: Property 'buttonClickPrevented' does not exist on type 'KeyboardEvent'.
if (!event.nativeEvent.buttonClickPrevented) {
event.currentTarget.click();
}
}
}, [props.onKeyDown]);
const onMouseDown = useCallback((event: React.MouseEvent<HTMLDivElement>) => {
if (typeof props.onMouseDown === 'function') {
props.onMouseDown(event);
}
// @ts-expect-error: Property 'buttonBlurPrevented' does not exist on type 'MouseEvent'.
if (!event.nativeEvent.buttonBlurPrevented) {
event.preventDefault();
if (document.activeElement instanceof HTMLElement) {
document.activeElement.blur();
}
}
}, [props.onMouseDown]);
return createElement(
typeof href === 'string' && href.length > 0 ? 'a' : 'div',
{
tabIndex: 0,
...props,
ref,
className: classNames(className, styles['button-container'], { 'disabled': disabled }),
href,
onKeyDown,
onMouseDown,
onDoubleClick,
...longPress()
},
children
);
});
export default Button;

View file

@ -1,5 +0,0 @@
// Copyright (C) 2017-2023 Smart code 203358507
const Button = require('./Button');
module.exports = Button;

View file

@ -0,0 +1,6 @@
// Copyright (C) 2017-2023 Smart code 203358507
import Button from './Button';
export default Button;

View file

@ -1,20 +1,30 @@
// Copyright (C) 2017-2023 Smart code 203358507
const React = require('react');
const PropTypes = require('prop-types');
import React, { useCallback, useLayoutEffect, useState } from 'react';
const Image = ({ className, src, alt, fallbackSrc, renderFallback, ...props }) => {
const [broken, setBroken] = React.useState(false);
const onError = React.useCallback((event) => {
type Props = {
className: string,
src: string,
alt: string,
fallbackSrc: string,
renderFallback: () => void,
onError: (event: React.SyntheticEvent<HTMLImageElement>) => void,
};
const Image = ({ className, src, alt, fallbackSrc, renderFallback, ...props }: Props) => {
const [broken, setBroken] = useState(false);
const onError = useCallback((event: React.SyntheticEvent<HTMLImageElement>) => {
if (typeof props.onError === 'function') {
props.onError(event);
}
setBroken(true);
}, [props.onError]);
React.useLayoutEffect(() => {
useLayoutEffect(() => {
setBroken(false);
}, [src]);
return (broken || typeof src !== 'string' || src.length === 0) && (typeof renderFallback === 'function' || typeof fallbackSrc === 'string') ?
typeof renderFallback === 'function' ?
renderFallback()
@ -24,13 +34,4 @@ const Image = ({ className, src, alt, fallbackSrc, renderFallback, ...props }) =
<img {...props} className={className} src={src} alt={alt} loading='lazy' onError={onError} />;
};
Image.propTypes = {
className: PropTypes.string,
src: PropTypes.string,
alt: PropTypes.string,
fallbackSrc: PropTypes.string,
renderFallback: PropTypes.func,
onError: PropTypes.func
};
module.exports = Image;
export default Image;

View file

@ -1,5 +0,0 @@
// Copyright (C) 2017-2023 Smart code 203358507
const Image = require('./Image');
module.exports = Image;

View file

@ -0,0 +1,5 @@
// Copyright (C) 2017-2023 Smart code 203358507
import Image from './Image';
export default Image;

View file

@ -1,10 +1,9 @@
// Copyright (C) 2017-2023 Smart code 203358507
const React = require('react');
const PropTypes = require('prop-types');
const classnames = require('classnames');
const { VerticalNavBar, HorizontalNavBar } = require('stremio/components/NavBar');
const styles = require('./styles');
import React, { memo } from 'react';
import classnames from 'classnames';
import { VerticalNavBar, HorizontalNavBar } from 'stremio/components/NavBar';
import styles from './MainNavBars.less';
const TABS = [
{ id: 'board', label: 'Board', icon: 'home', href: '#/' },
@ -15,7 +14,14 @@ const TABS = [
{ id: 'settings', label: 'SETTINGS', icon: 'settings', href: '#/settings' },
];
const MainNavBars = React.memo(({ className, route, query, children }) => {
type Props = {
className: string,
route?: string,
query?: string,
children?: React.ReactNode,
};
const MainNavBars = memo(({ className, route, query, children }: Props) => {
return (
<div className={classnames(className, styles['main-nav-bars-container'])}>
<HorizontalNavBar
@ -37,13 +43,5 @@ const MainNavBars = React.memo(({ className, route, query, children }) => {
);
});
MainNavBars.displayName = 'MainNavBars';
export default MainNavBars;
MainNavBars.propTypes = {
className: PropTypes.string,
route: PropTypes.string,
query: PropTypes.string,
children: PropTypes.node
};
module.exports = MainNavBars;

View file

@ -1,5 +0,0 @@
// Copyright (C) 2017-2023 Smart code 203358507
const MainNavBars = require('./MainNavBars');
module.exports = MainNavBars;

View file

@ -0,0 +1,6 @@
// Copyright (C) 2017-2023 Smart code 203358507
import MainNavBars from './MainNavBars';
export default MainNavBars;

View file

@ -6,8 +6,8 @@ const classnames = require('classnames');
const { useTranslation } = require('react-i18next');
const filterInvalidDOMProps = require('filter-invalid-dom-props').default;
const { default: Icon } = require('@stremio/stremio-icons/react');
const Button = require('stremio/components/Button');
const Image = require('stremio/components/Image');
const { default: Button } = require('stremio/components/Button');
const { default: Image } = require('stremio/components/Image');
const Multiselect = require('stremio/components/Multiselect');
const useBinaryState = require('stremio/common/useBinaryState');
const { ICON_FOR_TYPE } = require('stremio/common/CONSTANTS');

View file

@ -6,8 +6,8 @@ const classnames = require('classnames');
const UrlUtils = require('url');
const { useTranslation } = require('react-i18next');
const { default: Icon } = require('@stremio/stremio-icons/react');
const Button = require('stremio/components/Button');
const Image = require('stremio/components/Image');
const { default: Button } = require('stremio/components/Button');
const { default: Image } = require('stremio/components/Image');
const ModalDialog = require('stremio/components/ModalDialog');
const SharePrompt = require('stremio/components/SharePrompt');
const CONSTANTS = require('stremio/common/CONSTANTS');

View file

@ -4,7 +4,7 @@ const React = require('react');
const PropTypes = require('prop-types');
const classnames = require('classnames');
const { useRouteFocused, useModalsContainer } = require('stremio-router');
const Button = require('stremio/components/Button');
const { default: Button } = require('stremio/components/Button');
const { default: Icon } = require('@stremio/stremio-icons/react');
const { Modal } = require('stremio-router');
const styles = require('./styles');

3
src/modules.d.ts vendored
View file

@ -3,5 +3,4 @@ declare module '*.less' {
export = resource;
}
declare module 'stremio/common';
declare module 'stremio/components/Button';
declare module 'stremio/components/NavBar';