Move Icon and LoadingIcon to shared package

This commit is contained in:
Gregory Schier
2026-03-07 08:00:14 -08:00
parent d99898f39b
commit 3586c8fe24
62 changed files with 64 additions and 90 deletions

View File

@@ -4,8 +4,7 @@ import type { HTMLAttributes, ReactNode } from 'react';
import { forwardRef, useImperativeHandle, useRef } from 'react';
import type { HotkeyAction } from '../../hooks/useHotKey';
import { useFormattedHotkey, useHotKey } from '../../hooks/useHotKey';
import { Icon } from './Icon';
import { LoadingIcon } from './LoadingIcon';
import { Icon, LoadingIcon } from '@yaakapp-internal/ui';
export type ButtonProps = Omit<HTMLAttributes<HTMLButtonElement>, 'color' | 'onChange'> & {
innerClassName?: string;

View File

@@ -1,6 +1,6 @@
import classNames from 'classnames';
import type { ReactNode } from 'react';
import { Icon } from './Icon';
import { Icon } from '@yaakapp-internal/ui';
import { IconTooltip } from './IconTooltip';
import { HStack } from './Stacks';

View File

@@ -2,7 +2,7 @@ import classNames from 'classnames';
import { useState } from 'react';
import { HexColorPicker } from 'react-colorful';
import { useRandomKey } from '../../hooks/useRandomKey';
import { Icon } from './Icon';
import { Icon } from '@yaakapp-internal/ui';
import { PlainInput } from './PlainInput';
interface Props {

View File

@@ -35,8 +35,7 @@ import { ErrorBoundary } from '../ErrorBoundary';
import { Overlay } from '../Overlay';
import { Button } from './Button';
import { Hotkey } from './Hotkey';
import { Icon, type IconProps } from './Icon';
import { LoadingIcon } from './LoadingIcon';
import { Icon, LoadingIcon, type IconProps } from '@yaakapp-internal/ui';
import { Separator } from './Separator';
import { HStack, VStack } from './Stacks';

View File

@@ -1,326 +0,0 @@
import type { Color } from '@yaakapp-internal/plugins';
import classNames from 'classnames';
import {
AlarmClockIcon,
AlertTriangleIcon,
ArchiveIcon,
ArrowBigDownDashIcon,
ArrowBigLeftDashIcon,
ArrowBigRightDashIcon,
ArrowBigRightIcon,
ArrowBigUpDashIcon,
ArrowDownIcon,
ArrowDownToDotIcon,
ArrowDownToLineIcon,
ArrowLeftIcon,
ArrowRightCircleIcon,
ArrowRightIcon,
ArrowUpDownIcon,
ArrowUpFromDotIcon,
ArrowUpFromLineIcon,
ArrowUpIcon,
BadgeCheckIcon,
BookOpenText,
BoxIcon,
CakeIcon,
CheckCircleIcon,
CheckIcon,
ChevronDownIcon,
ChevronLeftIcon,
ChevronRightIcon,
ChevronsDownUpIcon,
ChevronsUpDownIcon,
CircleAlertIcon,
CircleDashedIcon,
CircleDollarSignIcon,
CircleFadingArrowUpIcon,
CircleHelpIcon,
CircleOffIcon,
ClipboardPasteIcon,
ClockIcon,
CodeIcon,
Columns2Icon,
CommandIcon,
CookieIcon,
CopyCheck,
CopyIcon,
CornerRightDownIcon,
CornerRightUpIcon,
CreditCardIcon,
CrosshairIcon,
DotIcon,
DownloadIcon,
EllipsisIcon,
EllipsisVerticalIcon,
ExpandIcon,
ExternalLinkIcon,
EyeIcon,
EyeOffIcon,
FileCodeIcon,
FileIcon,
FileTextIcon,
FilterIcon,
FlameIcon,
FlaskConicalIcon,
FolderCodeIcon,
FolderCogIcon,
FolderDownIcon,
FolderGitIcon,
FolderIcon,
FolderInputIcon,
FolderOpenIcon,
FolderOutputIcon,
FolderSymlinkIcon,
FolderSyncIcon,
FolderUpIcon,
GiftIcon,
GitBranchIcon,
GitBranchPlusIcon,
GitCommitIcon,
GitCommitVerticalIcon,
GitForkIcon,
GitPullRequestIcon,
GlobeIcon,
GripVerticalIcon,
HandIcon,
HardDriveDownloadIcon,
HistoryIcon,
HomeIcon,
ImportIcon,
InfoIcon,
KeyboardIcon,
KeyRoundIcon,
LockIcon,
LockOpenIcon,
MergeIcon,
MessageSquare,
MinusCircleIcon,
MinusIcon,
MoonIcon,
MoreVerticalIcon,
PaletteIcon,
PanelLeftCloseIcon,
PanelLeftOpenIcon,
PencilIcon,
PinIcon,
PinOffIcon,
Plug,
PlusCircleIcon,
PlusIcon,
PuzzleIcon,
RefreshCcwIcon,
RefreshCwIcon,
RocketIcon,
RotateCcwIcon,
Rows2Icon,
SaveIcon,
SearchIcon,
SendHorizontalIcon,
SettingsIcon,
ShieldAlertIcon,
ShieldCheckIcon,
ShieldIcon,
ShieldOffIcon,
SparklesIcon,
SquareCheckIcon,
SquareIcon,
SquareTerminalIcon,
SunIcon,
TableIcon,
Trash2Icon,
UploadIcon,
VariableIcon,
Wand2Icon,
WifiIcon,
WrenchIcon,
XIcon,
} from 'lucide-react';
import type { CSSProperties, HTMLAttributes } from 'react';
import { memo } from 'react';
const icons = {
alarm_clock: AlarmClockIcon,
alert_triangle: AlertTriangleIcon,
archive: ArchiveIcon,
arrow_big_down_dash: ArrowBigDownDashIcon,
arrow_big_left_dash: ArrowBigLeftDashIcon,
arrow_big_right: ArrowBigRightIcon,
arrow_big_right_dash: ArrowBigRightDashIcon,
arrow_big_up_dash: ArrowBigUpDashIcon,
arrow_down: ArrowDownIcon,
arrow_down_to_dot: ArrowDownToDotIcon,
arrow_down_to_line: ArrowDownToLineIcon,
arrow_left: ArrowLeftIcon,
arrow_right: ArrowRightIcon,
arrow_right_circle: ArrowRightCircleIcon,
arrow_up: ArrowUpIcon,
arrow_up_down: ArrowUpDownIcon,
arrow_up_from_dot: ArrowUpFromDotIcon,
arrow_up_from_line: ArrowUpFromLineIcon,
badge_check: BadgeCheckIcon,
book_open_text: BookOpenText,
box: BoxIcon,
cake: CakeIcon,
chat: MessageSquare,
check: CheckIcon,
check_circle: CheckCircleIcon,
check_square_checked: SquareCheckIcon,
check_square_unchecked: SquareIcon,
chevron_down: ChevronDownIcon,
chevron_left: ChevronLeftIcon,
chevrons_up_down: ChevronsUpDownIcon,
chevrons_down_up: ChevronsDownUpIcon,
chevron_right: ChevronRightIcon,
circle_alert: CircleAlertIcon,
circle_dashed: CircleDashedIcon,
circle_dollar_sign: CircleDollarSignIcon,
circle_fading_arrow_up: CircleFadingArrowUpIcon,
clock: ClockIcon,
code: CodeIcon,
columns_2: Columns2Icon,
command: CommandIcon,
cookie: CookieIcon,
copy: CopyIcon,
copy_check: CopyCheck,
corner_right_down: CornerRightDownIcon,
corner_right_up: CornerRightUpIcon,
credit_card: CreditCardIcon,
crosshair: CrosshairIcon,
dot: DotIcon,
download: DownloadIcon,
ellipsis: EllipsisIcon,
ellipsis_vertical: EllipsisVerticalIcon,
expand: ExpandIcon,
external_link: ExternalLinkIcon,
eye: EyeIcon,
eye_closed: EyeOffIcon,
file: FileIcon,
file_code: FileCodeIcon,
file_text: FileTextIcon,
filter: FilterIcon,
flame: FlameIcon,
flask: FlaskConicalIcon,
folder: FolderIcon,
folder_code: FolderCodeIcon,
folder_cog: FolderCogIcon,
folder_git: FolderGitIcon,
folder_input: FolderInputIcon,
folder_open: FolderOpenIcon,
folder_output: FolderOutputIcon,
folder_symlink: FolderSymlinkIcon,
folder_sync: FolderSyncIcon,
folder_down: FolderDownIcon,
folder_up: FolderUpIcon,
gift: GiftIcon,
git_branch: GitBranchIcon,
git_branch_plus: GitBranchPlusIcon,
git_commit: GitCommitIcon,
git_commit_vertical: GitCommitVerticalIcon,
git_fork: GitForkIcon,
git_pull_request: GitPullRequestIcon,
globe: GlobeIcon,
grip_vertical: GripVerticalIcon,
circle_off: CircleOffIcon,
hand: HandIcon,
hard_drive_download: HardDriveDownloadIcon,
help: CircleHelpIcon,
history: HistoryIcon,
house: HomeIcon,
import: ImportIcon,
info: InfoIcon,
key_round: KeyRoundIcon,
keyboard: KeyboardIcon,
left_panel_hidden: PanelLeftOpenIcon,
left_panel_visible: PanelLeftCloseIcon,
lock: LockIcon,
lock_open: LockOpenIcon,
magic_wand: Wand2Icon,
merge: MergeIcon,
minus: MinusIcon,
minus_circle: MinusCircleIcon,
moon: MoonIcon,
more_vertical: MoreVerticalIcon,
palette: PaletteIcon,
paste: ClipboardPasteIcon,
pencil: PencilIcon,
pin: PinIcon,
plug: Plug,
plus: PlusIcon,
plus_circle: PlusCircleIcon,
puzzle: PuzzleIcon,
refresh: RefreshCwIcon,
rocket: RocketIcon,
rotate_ccw: RotateCcwIcon,
rows_2: Rows2Icon,
save: SaveIcon,
search: SearchIcon,
send_horizontal: SendHorizontalIcon,
settings: SettingsIcon,
shield: ShieldIcon,
shield_check: ShieldCheckIcon,
shield_off: ShieldOffIcon,
sparkles: SparklesIcon,
square_terminal: SquareTerminalIcon,
sun: SunIcon,
table: TableIcon,
text: FileTextIcon,
trash: Trash2Icon,
unpin: PinOffIcon,
update: RefreshCcwIcon,
upload: UploadIcon,
variable: VariableIcon,
wifi: WifiIcon,
wrench: WrenchIcon,
x: XIcon,
_unknown: ShieldAlertIcon,
empty: (props: HTMLAttributes<HTMLSpanElement>) => <div {...props} />,
};
export interface IconProps {
icon: keyof typeof icons;
className?: string;
style?: CSSProperties;
size?: '2xs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';
spin?: boolean;
title?: string;
color?: Color | 'custom' | 'default';
}
export const Icon = memo(function Icon({
icon,
color = 'default',
spin,
size = 'md',
style,
className,
title,
}: IconProps) {
const Component = icons[icon] ?? icons._unknown;
return (
<Component
style={style}
title={title}
className={classNames(
className,
!spin && 'transform-gpu',
spin && 'animate-spin',
'flex-shrink-0',
size === 'xl' && 'h-6 w-6',
size === 'lg' && 'h-5 w-5',
size === 'md' && 'h-4 w-4',
size === 'sm' && 'h-3.5 w-3.5',
size === 'xs' && 'h-3 w-3',
size === '2xs' && 'h-2.5 w-2.5',
color === 'default' && 'inherit',
color === 'danger' && 'text-danger',
color === 'warning' && 'text-warning',
color === 'notice' && 'text-notice',
color === 'info' && 'text-info',
color === 'success' && 'text-success',
color === 'primary' && 'text-primary',
color === 'secondary' && 'text-secondary',
)}
/>
);
});

View File

@@ -4,9 +4,7 @@ import { forwardRef, useCallback } from 'react';
import { useTimedBoolean } from '../../hooks/useTimedBoolean';
import type { ButtonProps } from './Button';
import { Button } from './Button';
import type { IconProps } from './Icon';
import { Icon } from './Icon';
import { LoadingIcon } from './LoadingIcon';
import { Icon, LoadingIcon, type IconProps } from '@yaakapp-internal/ui';
export type IconButtonProps = IconProps &
ButtonProps & {

View File

@@ -1,5 +1,4 @@
import type { IconProps } from './Icon';
import { Icon } from './Icon';
import { Icon, type IconProps } from '@yaakapp-internal/ui';
import type { TooltipProps } from './Tooltip';
import { Tooltip } from './Tooltip';

View File

@@ -22,8 +22,7 @@ import type { DropdownItem } from './Dropdown';
import { Dropdown } from './Dropdown';
import type { EditorProps } from './Editor/Editor';
import { Editor } from './Editor/LazyEditor';
import type { IconProps } from './Icon';
import { Icon } from './Icon';
import { Icon, type IconProps } from '@yaakapp-internal/ui';
import { IconButton } from './IconButton';
import { IconTooltip } from './IconTooltip';
import { Label } from './Label';

View File

@@ -1,7 +1,7 @@
import classNames from 'classnames';
import type { ReactNode } from 'react';
import { useMemo, useState } from 'react';
import { Icon } from './Icon';
import { Icon } from '@yaakapp-internal/ui';
interface Props {
depth?: number;

View File

@@ -2,7 +2,7 @@ import { Link as RouterLink } from '@tanstack/react-router';
import classNames from 'classnames';
import type { HTMLAttributes } from 'react';
import { appInfo } from '../../lib/appInfo';
import { Icon } from './Icon';
import { Icon } from '@yaakapp-internal/ui';
interface Props extends HTMLAttributes<HTMLAnchorElement> {
href: string;

View File

@@ -1,35 +0,0 @@
import classNames from 'classnames';
interface Props {
size?: '2xs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';
className?: string;
}
export function LoadingIcon({ size = 'md', className }: Props) {
const classes = classNames(
className,
'text-inherit flex-shrink-0',
size === 'xl' && 'h-6 w-6',
size === 'lg' && 'h-5 w-5',
size === 'md' && 'h-4 w-4',
size === 'sm' && 'h-3.5 w-3.5',
size === 'xs' && 'h-3 w-3',
size === '2xs' && 'h-2.5 w-2.5',
'animate-spin',
);
return (
<div
className={classNames(
classes,
'border-[currentColor] border-b-transparent rounded-full',
size === 'xl' && 'border-[0.2rem]',
size === 'lg' && 'border-[0.16rem]',
size === 'md' && 'border-[0.13rem]',
size === 'sm' && 'border-[0.1rem]',
size === 'xs' && 'border-[0.08rem]',
size === '2xs' && 'border-[0.06rem]',
)}
/>
);
}

View File

@@ -28,7 +28,7 @@ import { Dropdown } from './Dropdown';
import type { EditorProps } from './Editor/Editor';
import type { GenericCompletionConfig } from './Editor/genericCompletion';
import { Editor } from './Editor/LazyEditor';
import { Icon } from './Icon';
import { Icon } from '@yaakapp-internal/ui';
import { IconButton } from './IconButton';
import type { InputHandle, InputProps } from './Input';
import { Input } from './Input';

View File

@@ -2,7 +2,7 @@ import type { ReactNode } from 'react';
import { useMemo } from 'react';
import type { DropdownItem, DropdownItemSeparator, DropdownProps } from './Dropdown';
import { Dropdown } from './Dropdown';
import { Icon } from './Icon';
import { Icon } from '@yaakapp-internal/ui';
export type RadioDropdownItem<T = string | null> =
| {

View File

@@ -3,7 +3,7 @@ import { type ReactNode, useRef } from 'react';
import { useStateWithDeps } from '../../hooks/useStateWithDeps';
import { generateId } from '../../lib/generateId';
import { Button } from './Button';
import type { IconProps } from './Icon';
import type { IconProps } from '@yaakapp-internal/ui';
import { IconButton, type IconButtonProps } from './IconButton';
import { Label } from './Label';
import { HStack } from './Stacks';

View File

@@ -27,7 +27,7 @@ import { DropMarker } from '../../DropMarker';
import { ErrorBoundary } from '../../ErrorBoundary';
import type { ButtonProps } from '../Button';
import { Button } from '../Button';
import { Icon } from '../Icon';
import { Icon } from '@yaakapp-internal/ui';
import type { RadioDropdownProps } from '../RadioDropdown';
import { RadioDropdown } from '../RadioDropdown';

View File

@@ -4,8 +4,7 @@ import * as m from 'motion/react-m';
import type { ReactNode } from 'react';
import { useKey } from 'react-use';
import type { IconProps } from './Icon';
import { Icon } from './Icon';
import { Icon, type IconProps } from '@yaakapp-internal/ui';
import { IconButton } from './IconButton';
import { VStack } from './Stacks';

View File

@@ -14,7 +14,7 @@ import { computeSideForDragMove } from '../../../lib/dnd';
import { jotaiStore } from '../../../lib/jotai';
import type { ContextMenuProps, DropdownItem } from '../Dropdown';
import { ContextMenu } from '../Dropdown';
import { Icon } from '../Icon';
import { Icon } from '@yaakapp-internal/ui';
import { collapsedFamily, isCollapsedFamily, isLastFocusedFamily, isSelectedFamily } from './atoms';
import type { TreeNode } from './common';
import { getNodeKey } from './common';