mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Update to React 18
This commit is contained in:
parent
b5d6e37fb3
commit
be891c3a98
36 changed files with 339 additions and 311 deletions
|
@ -1,8 +1,27 @@
|
|||
import escapeHTML from 'escape-html';
|
||||
import React, { FunctionComponent } from 'react';
|
||||
import React, { type FC } from 'react';
|
||||
import globalize from '../scripts/globalize';
|
||||
|
||||
const createCheckBoxElement = ({ labelClassName, className, id, dataFilter, dataItemType, dataId, checkedAttribute, renderContent }: { labelClassName?: string, type?: string, className?: string, id?: string, dataFilter?: string, dataItemType?: string, dataId?: string, checkedAttribute?: string, renderContent?: string }) => ({
|
||||
const createCheckBoxElement = ({
|
||||
labelClassName,
|
||||
className,
|
||||
id,
|
||||
dataFilter,
|
||||
dataItemType,
|
||||
dataId,
|
||||
checkedAttribute,
|
||||
renderContent
|
||||
}: {
|
||||
labelClassName?: string;
|
||||
type?: string;
|
||||
className?: string;
|
||||
id?: string;
|
||||
dataFilter?: string;
|
||||
dataItemType?: string;
|
||||
dataId?: string;
|
||||
checkedAttribute?: string;
|
||||
renderContent?: string;
|
||||
}) => ({
|
||||
__html: `<label ${labelClassName}>
|
||||
<input
|
||||
is="emby-checkbox"
|
||||
|
@ -18,20 +37,31 @@ const createCheckBoxElement = ({ labelClassName, className, id, dataFilter, data
|
|||
</label>`
|
||||
});
|
||||
|
||||
type IProps = {
|
||||
interface CheckBoxElementProps {
|
||||
labelClassName?: string;
|
||||
className?: string;
|
||||
elementId?: string;
|
||||
dataFilter?: string;
|
||||
itemType?: string;
|
||||
itemId?: string;
|
||||
itemAppName?: string;
|
||||
itemId?: string | null;
|
||||
itemAppName?: string | null;
|
||||
itemCheckedAttribute?: string;
|
||||
itemName?: string
|
||||
title?: string
|
||||
};
|
||||
itemName?: string | null;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
const CheckBoxElement: FunctionComponent<IProps> = ({ labelClassName, className, elementId, dataFilter, itemType, itemId, itemAppName, itemCheckedAttribute, itemName, title }: IProps) => {
|
||||
const CheckBoxElement: FC<CheckBoxElementProps> = ({
|
||||
labelClassName,
|
||||
className,
|
||||
elementId,
|
||||
dataFilter,
|
||||
itemType,
|
||||
itemId,
|
||||
itemAppName,
|
||||
itemCheckedAttribute,
|
||||
itemName,
|
||||
title
|
||||
}) => {
|
||||
const appName = itemAppName ? `- ${itemAppName}` : '';
|
||||
const renderContent = itemName ?
|
||||
`<span>${escapeHTML(itemName || '')} ${appName}</span>` :
|
||||
|
@ -41,13 +71,17 @@ const CheckBoxElement: FunctionComponent<IProps> = ({ labelClassName, className,
|
|||
<div
|
||||
className='sectioncheckbox'
|
||||
dangerouslySetInnerHTML={createCheckBoxElement({
|
||||
labelClassName: labelClassName ? `class='${labelClassName}'` : '',
|
||||
labelClassName: labelClassName ?
|
||||
`class='${labelClassName}'` :
|
||||
'',
|
||||
className: className,
|
||||
id: elementId ? `id='${elementId}'` : '',
|
||||
dataFilter: dataFilter ? `data-filter='${dataFilter}'` : '',
|
||||
dataItemType: itemType ? `data-itemtype='${itemType}'` : '',
|
||||
dataId: itemId ? `data-id='${itemId}'` : '',
|
||||
checkedAttribute: itemCheckedAttribute ? itemCheckedAttribute : '',
|
||||
checkedAttribute: itemCheckedAttribute ?
|
||||
itemCheckedAttribute :
|
||||
'',
|
||||
renderContent: renderContent
|
||||
})}
|
||||
/>
|
||||
|
|
|
@ -1,11 +1,21 @@
|
|||
import classNames from 'classnames';
|
||||
import React, { type DetailedHTMLProps, type InputHTMLAttributes, useState, useCallback, forwardRef } from 'react';
|
||||
import React, {
|
||||
type DetailedHTMLProps,
|
||||
type InputHTMLAttributes,
|
||||
useState,
|
||||
useCallback,
|
||||
forwardRef
|
||||
} from 'react';
|
||||
|
||||
import './emby-input.scss';
|
||||
|
||||
interface InputProps extends DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement> {
|
||||
id: string,
|
||||
label?: string
|
||||
interface InputProps
|
||||
extends DetailedHTMLProps<
|
||||
InputHTMLAttributes<HTMLInputElement>,
|
||||
HTMLInputElement
|
||||
> {
|
||||
id: string;
|
||||
label?: string;
|
||||
}
|
||||
|
||||
const Input = forwardRef<HTMLInputElement, InputProps>(
|
||||
|
@ -13,7 +23,7 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
|
|||
const [isFocused, setIsFocused] = useState(false);
|
||||
|
||||
const onBlurInternal = useCallback(
|
||||
(e) => {
|
||||
(e: React.FocusEvent<HTMLInputElement, Element>) => {
|
||||
setIsFocused(false);
|
||||
onBlur?.(e);
|
||||
},
|
||||
|
@ -21,7 +31,7 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
|
|||
);
|
||||
|
||||
const onFocusInternal = useCallback(
|
||||
(e) => {
|
||||
(e: React.FocusEvent<HTMLInputElement, Element>) => {
|
||||
setIsFocused(true);
|
||||
onFocus?.(e);
|
||||
},
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { ApiClient } from 'jellyfin-apiclient';
|
||||
import React, { type FC, useCallback, useEffect, useState } from 'react';
|
||||
import Events, { Event } from 'utils/events';
|
||||
import serverNotifications from 'scripts/serverNotifications';
|
||||
|
@ -50,7 +51,7 @@ interface RefreshIndicatorProps {
|
|||
const RefreshIndicator: FC<RefreshIndicatorProps> = ({ item, className }) => {
|
||||
const [progress, setProgress] = useState(item.RefreshProgress || 0);
|
||||
|
||||
const onRefreshProgress = useCallback((_e: Event, apiClient, info) => {
|
||||
const onRefreshProgress = useCallback((_e: Event, _apiClient: ApiClient, info: { ItemId: string | null | undefined; Progress: string; }) => {
|
||||
if (info.ItemId === item?.Id) {
|
||||
setProgress(parseFloat(info.Progress));
|
||||
}
|
||||
|
|
|
@ -3,13 +3,13 @@ import {
|
|||
type LibraryUpdateInfo
|
||||
} from '@jellyfin/sdk/lib/generated-client';
|
||||
import { ApiClient } from 'jellyfin-apiclient';
|
||||
import React, { type FC, useCallback, useEffect, useRef } from 'react';
|
||||
import React, { type FC, type PropsWithChildren, useCallback, useEffect, useRef } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import Box from '@mui/material/Box';
|
||||
import Sortable from 'sortablejs';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { usePlaylistsMoveItemMutation } from 'hooks/useFetchItems';
|
||||
import Events, { Event } from 'utils/events';
|
||||
import Events, { type Event } from 'utils/events';
|
||||
import serverNotifications from 'scripts/serverNotifications';
|
||||
import inputManager from 'scripts/inputManager';
|
||||
import dom from 'scripts/dom';
|
||||
|
@ -48,7 +48,7 @@ interface ItemsContainerProps {
|
|||
queryKey?: string[]
|
||||
}
|
||||
|
||||
const ItemsContainer: FC<ItemsContainerProps> = ({
|
||||
const ItemsContainer: FC<PropsWithChildren<ItemsContainerProps>> = ({
|
||||
className,
|
||||
isContextMenuEnabled,
|
||||
isMultiSelectEnabled,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React, { type FC, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import React, { type FC, type PropsWithChildren, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import useElementSize from 'hooks/useElementSize';
|
||||
import layoutManager from '../../components/layoutManager';
|
||||
|
@ -21,7 +21,7 @@ interface ScrollerProps {
|
|||
isAllowNativeSmoothScrollEnabled?: boolean;
|
||||
}
|
||||
|
||||
const Scroller: FC<ScrollerProps> = ({
|
||||
const Scroller: FC<PropsWithChildren<ScrollerProps>> = ({
|
||||
className,
|
||||
isHorizontalEnabled,
|
||||
isMouseWheelEnabled,
|
||||
|
@ -126,7 +126,7 @@ const Scroller: FC<ScrollerProps> = ({
|
|||
});
|
||||
}, [getScrollPosition, getScrollSize, getScrollWidth]);
|
||||
|
||||
const initCenterFocus = useCallback((elem, scrollerInstance: ScrollerFactory) => {
|
||||
const initCenterFocus = useCallback((elem: HTMLElement, scrollerInstance: ScrollerFactory) => {
|
||||
dom.addEventListener(elem, 'focus', function (e: FocusEvent) {
|
||||
const focused = focusManager.focusableParent(e.target);
|
||||
if (focused) {
|
||||
|
@ -138,19 +138,26 @@ const Scroller: FC<ScrollerProps> = ({
|
|||
});
|
||||
}, []);
|
||||
|
||||
const addScrollEventListener = useCallback((fn, options) => {
|
||||
const addScrollEventListener = useCallback((fn: () => void, options: AddEventListenerOptions | undefined) => {
|
||||
if (scrollerFactoryRef.current) {
|
||||
dom.addEventListener(scrollerFactoryRef.current.getScrollFrame(), scrollerFactoryRef.current.getScrollEventName(), fn, options);
|
||||
}
|
||||
}, [scrollerFactoryRef]);
|
||||
|
||||
const removeScrollEventListener = useCallback((fn, options) => {
|
||||
const removeScrollEventListener = useCallback((fn: () => void, options: AddEventListenerOptions | undefined) => {
|
||||
if (scrollerFactoryRef.current) {
|
||||
dom.removeEventListener(scrollerFactoryRef.current.getScrollFrame(), scrollerFactoryRef.current.getScrollEventName(), fn, options);
|
||||
}
|
||||
}, [scrollerFactoryRef]);
|
||||
|
||||
useEffect(() => {
|
||||
const frame = scrollRef.current;
|
||||
|
||||
if (!frame) {
|
||||
console.error('Unexpected null reference');
|
||||
return;
|
||||
}
|
||||
|
||||
const horizontal = isHorizontalEnabled !== false;
|
||||
const scrollbuttons = isScrollButtonsEnabled !== false;
|
||||
const mousewheel = isMouseWheelEnabled !== false;
|
||||
|
@ -179,12 +186,12 @@ const Scroller: FC<ScrollerProps> = ({
|
|||
};
|
||||
|
||||
// If just inserted it might not have any height yet - yes this is a hack
|
||||
scrollerFactoryRef.current = new ScrollerFactory(scrollRef.current, options);
|
||||
scrollerFactoryRef.current = new ScrollerFactory(frame, options);
|
||||
scrollerFactoryRef.current.init();
|
||||
scrollerFactoryRef.current.reload();
|
||||
|
||||
if (layoutManager.tv && isCenterFocusEnabled) {
|
||||
initCenterFocus(scrollRef.current, scrollerFactoryRef.current);
|
||||
initCenterFocus(frame, scrollerFactoryRef.current);
|
||||
}
|
||||
|
||||
if (enableScrollButtons) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue