refactor: migrate UI components and remove chakra

migrate pin page
migrate copy tag
migrate pin input
migrate dropdown menus
migrate radio buttons
migrate switch
migrate select
migrate textarea
migrate colour picker
migrate select
migrate context menu
migrate viewparams
remove chakra
This commit is contained in:
Carlos Valente
2025-07-08 20:50:49 +02:00
committed by Carlos Valente
parent 4d359445a7
commit e1e8410ba4
100 changed files with 1222 additions and 1990 deletions
@@ -1,7 +1,6 @@
import { memo } from 'react';
import { useSessionStorage } from '@mantine/hooks';
import { ContextMenu } from '../../common/components/context-menu/ContextMenu';
import { Corner } from '../../common/components/editor-utils/EditorUtils';
import ErrorBoundary from '../../common/components/error-boundary/ErrorBoundary';
import ViewNavigationMenu from '../../common/components/navigation-menu/ViewNavigationMenu';
@@ -13,6 +12,7 @@ import { AppMode, sessionKeys } from '../../ontimeConfig';
import RundownEntryEditor from './entry-editor/RundownEntryEditor';
import FinderPlacement from './placements/FinderPlacement';
import { RundownContextMenu } from './rundown-context-menu/RundownContextMenu';
import RundownWrapper from './RundownWrapper';
import style from './RundownExport.module.scss';
@@ -39,9 +39,9 @@ function RundownExport() {
<ViewNavigationMenu suppressSettings />
<div className={style.content}>
<ErrorBoundary>
<ContextMenu>
<RundownContextMenu>
<RundownWrapper isSmallDevice />
</ContextMenu>
</RundownContextMenu>
</ErrorBoundary>
</div>
</div>
@@ -59,9 +59,9 @@ function RundownExport() {
<div className={style.list}>
<ErrorBoundary>
<Corner onClick={(event) => handleLinks('rundown', event)} />
<ContextMenu>
<RundownContextMenu>
<RundownWrapper />
</ContextMenu>
</RundownContextMenu>
</ErrorBoundary>
</div>
{!hideSideBar && (
@@ -16,12 +16,8 @@ function EventEditorFooter({ id, cue }: EventEditorFooterProps) {
return (
<div className={style.footer}>
<CopyTag copyValue={loadById} label='OSC trigger by ID'>
{loadById}
</CopyTag>
<CopyTag copyValue={loadByCue} label='OSC trigger by cue'>
{loadByCue}
</CopyTag>
<CopyTag copyValue={loadById}>{loadById}</CopyTag>
<CopyTag copyValue={loadByCue}>{loadByCue}</CopyTag>
</div>
);
}
@@ -1,7 +1,7 @@
import { type CSSProperties, useCallback, useRef } from 'react';
import * as Editor from '../../../../common/components/editor-utils/EditorUtils';
import { AutoTextArea } from '../../../../common/components/input/auto-text-area/AutoTextArea';
import { AutoTextarea } from '../../../../common/components/input/auto-textarea/AutoTextarea';
import useReactiveTextInput from '../../../../common/components/input/text-input/useReactiveTextInput';
import { EventEditorUpdateFields } from '../EventEditor';
@@ -22,7 +22,7 @@ export default function EventTextArea({
style: givenStyles,
submitHandler,
}: CountedTextAreaProps) {
const ref = useRef<HTMLInputElement | null>(null);
const ref = useRef<HTMLTextAreaElement | null>(null);
const submitCallback = useCallback((newValue: string) => submitHandler(field, newValue), [field, submitHandler]);
const { value, onChange, onBlur, onKeyDown } = useReactiveTextInput(initialValue, submitCallback, ref, {
@@ -34,14 +34,12 @@ export default function EventTextArea({
<Editor.Label className={className} htmlFor={field} style={givenStyles}>
{label}
</Editor.Label>
<AutoTextArea
<AutoTextarea
id={field}
inputref={ref}
rows={1}
size='sm'
resize='none'
variant='ontime-filled'
data-testid='input-textarea'
fluid
value={value}
onChange={onChange}
onBlur={onBlur}
@@ -67,10 +67,10 @@ function QuickAddInline({ previousEventId, parentBlock }: QuickAddInlineProps) {
<div className={style.quickAdd} data-testid='quick-add-inline'>
<DropdownMenu
items={[
{ type: 'item', icon: <IoAdd />, label: 'Add Event', onClick: addEvent },
{ type: 'item', icon: <IoAdd />, label: 'Add Delay', onClick: addDelay },
{ type: 'item', icon: <IoAdd />, label: 'Add Milestone', onClick: addMilestone },
{ type: 'item', icon: <IoAdd />, label: 'Add Group', onClick: addBlock, disabled: parentBlock !== null },
{ type: 'item', icon: IoAdd, label: 'Add Event', onClick: addEvent },
{ type: 'item', icon: IoAdd, label: 'Add Delay', onClick: addDelay },
{ type: 'item', icon: IoAdd, label: 'Add Milestone', onClick: addMilestone },
{ type: 'item', icon: IoAdd, label: 'Add Group', onClick: addBlock, disabled: parentBlock !== null },
]}
render={<IconButton size='small' variant='primary' className={style.addButton} />}
>
@@ -36,21 +36,26 @@ export default function RundownBlock({ data, hasCursor, collapsed, onCollapse }:
const [onContextMenu] = useContextMenu<HTMLDivElement>([
{
type: 'item',
label: 'Clone Group',
icon: IoDuplicateOutline,
onClick: () => clone(data.id),
},
{
type: 'item',
label: 'Ungroup',
icon: IoFolderOpenOutline,
onClick: () => ungroup(data.id),
isDisabled: data.entries.length === 0,
disabled: data.entries.length === 0,
},
{ type: 'divider' },
{
type: 'item',
label: 'Delete Group',
icon: IoTrash,
onClick: () => deleteEntry([data.id]),
withDivider: true,
disabled: true,
},
]);
@@ -0,0 +1,44 @@
import type { PropsWithChildren } from 'react';
import { create } from 'zustand';
import { DropdownMenuOption, PositionedDropdownMenu } from '../../../common/components/dropdown-menu/DropdownMenu';
type Position = {
x: number;
y: number;
};
type ContextMenuStore = {
position: Position;
options: DropdownMenuOption[];
isOpen: boolean;
setContextMenu: (position: Position, options: DropdownMenuOption[]) => void;
setIsOpen: (newIsOpen: boolean) => void;
};
export const useContextMenuStore = create<ContextMenuStore>((set) => ({
position: { x: 0, y: 0 },
options: [],
isOpen: false,
setContextMenu: (position, options) => set(() => ({ position, options, isOpen: true })),
setIsOpen: (newIsOpen) => set(() => ({ isOpen: newIsOpen })),
}));
export function RundownContextMenu({ children }: PropsWithChildren) {
const { position, options, isOpen, setIsOpen } = useContextMenuStore();
const onClose = () => {
return setIsOpen(false);
};
if (!isOpen) {
return children;
}
return (
<>
{children}
<PositionedDropdownMenu isOpen position={position} onClose={onClose} items={options} />
</>
);
}
@@ -107,6 +107,7 @@ export default function RundownEvent({
selectedEvents.size > 1
? [
{
type: 'item',
label: 'Link to previous',
icon: IoLink,
onClick: () =>
@@ -116,6 +117,8 @@ export default function RundownEvent({
}),
},
{
type: 'item',
label: 'Unlink from previous',
icon: IoUnlink,
onClick: () =>
@@ -124,11 +127,15 @@ export default function RundownEvent({
value: null,
}),
},
{ withDivider: true, label: 'Group', icon: IoFolder, onClick: () => actionHandler('group') },
{ withDivider: true, label: 'Delete', icon: IoTrash, onClick: () => actionHandler('delete') },
{ type: 'divider' },
{ type: 'item', label: 'Group', icon: IoFolder, onClick: () => actionHandler('group') },
{ type: 'divider' },
{ type: 'item', label: 'Delete', icon: IoTrash, onClick: () => actionHandler('delete') },
]
: [
{
type: 'item',
label: 'Toggle link to previous',
icon: IoLink,
onClick: () =>
@@ -137,23 +144,34 @@ export default function RundownEvent({
value: linkStart,
}),
},
{ type: 'divider' },
{
type: 'item',
label: 'Add to swap',
icon: IoAdd,
onClick: () => setSelectedEventId(eventId),
withDivider: true,
},
{
type: 'item',
label: `Swap this event with ${selectedEventId ?? ''}`,
icon: IoSwapVertical,
onClick: () => {
actionHandler('swap', { field: 'id', value: selectedEventId });
clearSelectedEventId();
},
isDisabled: selectedEventId == null || selectedEventId === eventId,
disabled: selectedEventId == null || selectedEventId === eventId,
},
{ withDivider: false, label: 'Clone', icon: IoDuplicateOutline, onClick: () => actionHandler('clone') },
{ withDivider: true, label: 'Delete', icon: IoTrash, onClick: () => actionHandler('delete') },
{
type: 'item',
label: 'Clone',
icon: IoDuplicateOutline,
onClick: () => actionHandler('clone'),
},
{ type: 'divider' },
{ type: 'item', label: 'Delete', icon: IoTrash, onClick: () => actionHandler('delete') },
],
);