feat: Refactor utility and component exports, update dependencies, and add Knip for unused code detection.

This commit is contained in:
2025-12-04 11:58:04 +01:00
parent c3375b714d
commit 2ea74816fb
65 changed files with 624 additions and 707 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
import React, { ElementType, ReactNode } from 'react';
import composeClassName from './classNames';
import { composeClassName } from './classNames';
type TitleProps = Record<string, unknown>;
+1 -1
View File
@@ -49,7 +49,7 @@ interface FloatingMenuState {
type CSSVarStyle = CSSProperties & Record<string, string>;
export interface QuickAddMenuProps {
interface QuickAddMenuProps {
onSelectOption?: (value: QuickAddOption, normalized: NormalizedOption) => Promise<void> | void;
onCreate?: (value: string) => Promise<void> | void;
options?: QuickAddOption[];
-2
View File
@@ -1,4 +1,2 @@
export const composeClassName = (base: string, extra?: string | null): string =>
extra ? `${base} ${extra}` : base;
export default composeClassName;
+1 -92
View File
@@ -12,15 +12,11 @@ import {
IconLayoutList,
IconLayoutGrid,
IconArrowLeft,
IconArrowRight,
IconArrowUp,
IconAnalyze,
IconUpload,
IconWindowMaximize,
IconTextScan2,
IconFolderPlus,
IconFolder,
IconFolderUp,
IconFolders,
IconFoldersOff,
IconRefresh,
@@ -37,10 +33,8 @@ import {
IconDeviceLaptop,
IconLayoutSidebarLeftCollapse,
IconLayoutSidebarLeftExpand,
IconLayoutSidebarRightCollapse,
IconLayoutBottombarCollapse,
IconLayoutBottombarExpand,
IconClearAll,
IconInfoCircle,
IconCircleDashedCheck,
IconFile,
@@ -56,7 +50,7 @@ import {
import FolderSvg from '../assets/folder.svg';
const logoWebp = new URL('../assets/logo.webp', import.meta.url).toString();
const logoSmallWebp = new URL('../assets/logo_small.webp', import.meta.url).toString();
import composeClassName from './classNames';
import { composeClassName } from './classNames';
type TablerIconComponent = (props: TablerIconProps) => JSX.Element;
@@ -223,16 +217,6 @@ export const ArrowLeftIcon: TablerIconComponent = ({ className, size = '1em', st
{...rest}
/>
);
export const ArrowRightIcon: TablerIconComponent = ({ className, size = '1em', stroke = 1.6, ...rest }) => (
<IconArrowRight
className={composeClassName('icon', className)}
size={size}
stroke={stroke}
{...rest}
/>
);
export const SidebarCollapseIcon: TablerIconComponent = ({ className, size = '1em', stroke = 1.6, ...rest }) => (
<IconLayoutSidebarLeftCollapse
className={composeClassName('icon', className)}
@@ -268,16 +252,6 @@ export const FileInfoIcon: TablerIconComponent = ({ className, size = '1em', str
{...rest}
/>
);
export const DetailPanelCollapseIcon: TablerIconComponent = ({ className, size = '1em', stroke = 1.6, ...rest }) => (
<IconLayoutSidebarRightCollapse
className={composeClassName('icon', className)}
size={size}
stroke={stroke}
{...rest}
/>
);
export const BottombarCollapseIcon: TablerIconComponent = ({ className, size = '1em', stroke = 1.6, ...rest }) => (
<IconLayoutBottombarCollapse
className={composeClassName('icon', className)}
@@ -295,16 +269,6 @@ export const BottombarExpandIcon: TablerIconComponent = ({ className, size = '1e
{...rest}
/>
);
export const ClearAllIcon: TablerIconComponent = ({ className, size = '1em', stroke = 1.6, ...rest }) => (
<IconClearAll
className={composeClassName('icon', className)}
size={size}
stroke={stroke}
{...rest}
/>
);
export const FolderPlusIcon: TablerIconComponent = ({ className, size = '1em', stroke = 1.6, ...rest }) => (
<IconFolderPlus
className={composeClassName('icon', className)}
@@ -349,16 +313,6 @@ export const RestoreIcon: TablerIconComponent = ({ className, size = '1em', stro
{...rest}
/>
);
export const ArrowUpIcon: TablerIconComponent = ({ className, size = '1em', stroke = 1.6, ...rest }) => (
<IconArrowUp
className={composeClassName('icon', className)}
size={size}
stroke={stroke}
{...rest}
/>
);
export const MinusVerticalIcon: TablerIconComponent = ({ className, size = '1em', stroke = 1.6, ...rest }) => (
<IconMinusVertical
className={composeClassName('icon', className)}
@@ -567,16 +521,6 @@ export const ChevronDownIcon: TablerIconComponent = ({ className, size = '1em',
{...rest}
/>
);
export const FolderUpIcon: TablerIconComponent = ({ className, size = '1em', stroke = 1.6, ...rest }) => (
<IconFolderUp
className={composeClassName('icon', className)}
size={size}
stroke={stroke}
{...rest}
/>
);
export const FolderMoveIcon: TablerIconComponent = ({ className, size = '1em', stroke = 1.6, ...rest }) => (
<svg
xmlns="http://www.w3.org/2000/svg"
@@ -601,38 +545,3 @@ export const FolderMoveIcon: TablerIconComponent = ({ className, size = '1em', s
</g>
</svg>
);
export default {
ChevronIcon,
TrashIcon,
EditIcon,
FolderIcon,
TagIcon,
CorrespondentIcon,
DownloadIcon,
ViewListIcon,
ViewGridIcon,
SidebarCollapseIcon,
SidebarExpandIcon,
DetailPanelCollapseIcon,
AnalyzeIcon,
LoaderIcon,
WindowMaximizeIcon,
FolderPlusIcon,
RefreshIcon,
ArrowUpIcon,
MinusVerticalIcon,
LogoutIcon,
ChevronDownIcon,
FolderUpIcon,
FolderMoveIcon,
};
export const TextScanIcon: TablerIconComponent = ({ className, size = '1em', stroke = 1.6, ...rest }) => (
<IconTextScan2
className={composeClassName('icon', className)}
size={size}
stroke={stroke}
{...rest}
/>
);
-94
View File
@@ -1,94 +0,0 @@
import { useCallback, useEffect, useRef } from 'react';
import type { PointerEvent as ReactPointerEvent } from 'react';
export interface PointerTapContext<T = unknown> {
clientX: number;
clientY: number;
pointerType: string;
event: PointerEventWithPersist;
data?: T;
}
type PointerEventWithPersist = (PointerEvent | ReactPointerEvent) & { persist?: () => void };
type PointerTapFilter = (event?: PointerEventWithPersist | null) => boolean;
export interface UsePointerTapOptions<T = unknown> {
onSingle?: (context: PointerTapContext<T>) => void;
onDouble?: (context: PointerTapContext<T>) => void;
delay?: number;
filter?: PointerTapFilter;
}
const defaultFilter: PointerTapFilter = (event) => {
if (!event) {
return false;
}
const { type, button, pointerType, isPrimary } = event;
const isPointerUp = type === 'pointerup';
const buttonValid =
button == null || button === 0 || (isPointerUp && (button === -1 || button === 0));
if (!buttonValid) {
return false;
}
if (pointerType === 'touch' && isPrimary === false) {
return false;
}
return true;
};
const usePointerTap = <T,>({
onSingle,
onDouble,
delay = 240,
filter = defaultFilter,
}: UsePointerTapOptions<T> = {}) => {
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
useEffect(
() => () => {
if (timerRef.current) {
clearTimeout(timerRef.current);
timerRef.current = null;
}
},
[],
);
return useCallback(
(event?: PointerEventWithPersist | null, metadata?: T) => {
if (!filter(event)) {
return;
}
if (!event) {
return;
}
event.persist?.();
const context: PointerTapContext<T> = {
clientX: event.clientX ?? 0,
clientY: event.clientY ?? 0,
pointerType: event.pointerType ?? 'mouse',
event,
data: metadata,
};
if (timerRef.current) {
clearTimeout(timerRef.current);
timerRef.current = null;
onDouble?.(context);
return;
}
timerRef.current = setTimeout(() => {
timerRef.current = null;
onSingle?.(context);
}, delay);
},
[delay, filter, onDouble, onSingle],
);
};
export default usePointerTap;