From c6bcefdf17ae3dac4a652bbd1ab7643ec8081ae9 Mon Sep 17 00:00:00 2001 From: Scott Cazan Date: Thu, 5 Mar 2026 23:20:42 +0100 Subject: [PATCH 1/5] Normalize icon stroke widths to 1px --- packages/ui/src/components/CommentButton.tsx | 2 +- packages/ui/src/components/icons/CheckIcon.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ui/src/components/CommentButton.tsx b/packages/ui/src/components/CommentButton.tsx index 64f87e8fb..265a08557 100644 --- a/packages/ui/src/components/CommentButton.tsx +++ b/packages/ui/src/components/CommentButton.tsx @@ -24,7 +24,7 @@ const MessageCircleIcon = ({ className }: { className?: string }) => ( ( From 9351e9f610e5437e9335228e09ba8b3d8dc50e44 Mon Sep 17 00:00:00 2001 From: Scott Cazan Date: Thu, 5 Mar 2026 23:43:16 +0100 Subject: [PATCH 2/5] Use non-scaling strokes --- apps/app/src/components/IconProvider.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/app/src/components/IconProvider.tsx b/apps/app/src/components/IconProvider.tsx index be438eccc..8a3616624 100644 --- a/apps/app/src/components/IconProvider.tsx +++ b/apps/app/src/components/IconProvider.tsx @@ -4,7 +4,9 @@ import { IconContext } from 'react-icons'; export const IconProvider = ({ children }: { children: React.ReactNode }) => { return ( - + {children} ); From 24bb70fdc1118c9200c120dadb2c4ff4e2232a55 Mon Sep 17 00:00:00 2001 From: Scott Cazan Date: Thu, 5 Mar 2026 23:57:32 +0100 Subject: [PATCH 3/5] Use react-icons/lu for provider --- .../RichTextEditorFloatingToolbar.tsx | 64 +++++++------- .../RichTextEditor/RichTextEditorToolbar.tsx | 84 +++++++++---------- .../ProposalCard/ProposalCardActions.tsx | 9 +- .../ProposalCard/ProposalCardComponents.tsx | 7 +- .../ProposalCard/ProposalCardMenu.tsx | 4 +- .../src/components/decisions/ProposalView.tsx | 7 +- .../decisions/ProposalViewLayout.tsx | 7 +- .../components/decisions/ProposalsList.tsx | 4 +- .../components/decisions/SlashCommands.tsx | 44 +++++----- packages/ui/src/components/AvatarUploader.tsx | 4 +- packages/ui/src/components/BannerUploader.tsx | 4 +- packages/ui/src/components/Breadcrumbs.tsx | 4 +- packages/ui/src/components/Calendar.tsx | 10 +-- packages/ui/src/components/Checkbox.tsx | 12 ++- packages/ui/src/components/ComboBox.tsx | 4 +- packages/ui/src/components/DatePicker.tsx | 4 +- packages/ui/src/components/ListBox.tsx | 4 +- packages/ui/src/components/Menu.tsx | 6 +- packages/ui/src/components/Pagination.tsx | 6 +- packages/ui/src/components/PhaseStepper.tsx | 4 +- .../ui/src/components/ReactionsButton.tsx | 4 +- packages/ui/src/components/SearchField.tsx | 6 +- packages/ui/src/components/Select.tsx | 7 +- packages/ui/src/components/TagGroup.tsx | 4 +- .../ui/src/components/TranslateBanner.tsx | 6 +- packages/ui/stories/Menu.stories.tsx | 8 +- packages/ui/stories/Popover.stories.tsx | 4 +- packages/ui/stories/Tooltip.stories.tsx | 6 +- 28 files changed, 171 insertions(+), 166 deletions(-) diff --git a/apps/app/src/components/RichTextEditor/RichTextEditorFloatingToolbar.tsx b/apps/app/src/components/RichTextEditor/RichTextEditorFloatingToolbar.tsx index 650a7b991..11586f7f7 100644 --- a/apps/app/src/components/RichTextEditor/RichTextEditorFloatingToolbar.tsx +++ b/apps/app/src/components/RichTextEditor/RichTextEditorFloatingToolbar.tsx @@ -1,24 +1,24 @@ 'use client'; import type { Editor } from '@tiptap/react'; -import { - AlignCenter, - AlignLeft, - AlignRight, - Bold, - Code, - Heading1, - Heading2, - Heading3, - Italic, - Link as LinkIcon, - List, - ListOrdered, - Quote, - Strikethrough, - Underline as UnderlineIcon, -} from 'lucide-react'; import { useCallback } from 'react'; +import { + LuAlignCenter, + LuAlignLeft, + LuAlignRight, + LuBold, + LuCode, + LuHeading1, + LuHeading2, + LuHeading3, + LuItalic, + LuLink, + LuList, + LuListOrdered, + LuQuote, + LuStrikethrough, + LuUnderline, +} from 'react-icons/lu'; import { useTranslations } from '@/lib/i18n'; @@ -81,7 +81,7 @@ export function RichTextEditorFloatingToolbar({ className={`rounded p-1.5 hover:bg-gray-100 ${editor.isActive('heading', { level: 1 }) ? 'bg-gray-200 text-neutral-black' : 'text-neutral-charcoal'}`} title={t('Heading 1')} > - +
@@ -115,7 +115,7 @@ export function RichTextEditorFloatingToolbar({ className={`rounded p-1.5 hover:bg-gray-100 ${editor.isActive('bold') ? 'bg-gray-200 text-neutral-black' : 'text-neutral-charcoal'}`} title={t('Bold')} > - +
@@ -169,7 +169,7 @@ export function RichTextEditorFloatingToolbar({ className={`rounded p-1.5 hover:bg-gray-100 ${editor.isActive('bulletList') ? 'bg-gray-200 text-neutral-black' : 'text-neutral-charcoal'}`} title={t('Bullet List')} > - +
@@ -203,7 +203,7 @@ export function RichTextEditorFloatingToolbar({ className={`rounded p-1.5 hover:bg-gray-100 ${editor.isActive({ textAlign: 'left' }) ? 'bg-gray-200 text-neutral-black' : 'text-neutral-charcoal'}`} title={t('Align Left')} > - +
@@ -237,7 +237,7 @@ export function RichTextEditorFloatingToolbar({ className={`rounded p-1.5 hover:bg-gray-100 ${editor.isActive('link') ? 'bg-gray-200 text-neutral-black' : 'text-neutral-charcoal'}`} title={t('Add Link')} > - +
); diff --git a/apps/app/src/components/RichTextEditor/RichTextEditorToolbar.tsx b/apps/app/src/components/RichTextEditor/RichTextEditorToolbar.tsx index df7894cd4..bed1d9241 100644 --- a/apps/app/src/components/RichTextEditor/RichTextEditorToolbar.tsx +++ b/apps/app/src/components/RichTextEditor/RichTextEditorToolbar.tsx @@ -3,29 +3,29 @@ import { useFileUpload } from '@/hooks/useFileUpload'; import { cn } from '@op/ui/utils'; import type { Editor } from '@tiptap/react'; -import { - AlignCenter, - AlignLeft, - AlignRight, - Bold, - Code, - Heading1, - Heading2, - Heading3, - Image as ImageIcon, - Italic, - Link2, - Link as LinkIcon, - List, - ListOrdered, - Minus, - Quote, - Redo, - Strikethrough, - Underline as UnderlineIcon, - Undo, -} from 'lucide-react'; import { useCallback, useRef } from 'react'; +import { + LuAlignCenter, + LuAlignLeft, + LuAlignRight, + LuBold, + LuCode, + LuHeading1, + LuHeading2, + LuHeading3, + LuImage, + LuItalic, + LuLink, + LuLink2, + LuList, + LuListOrdered, + LuMinus, + LuQuote, + LuRedo, + LuStrikethrough, + LuUnderline, + LuUndo, +} from 'react-icons/lu'; import { useTranslations } from '@/lib/i18n'; @@ -125,7 +125,7 @@ export function RichTextEditorToolbar({ className="shrink-0 rounded p-2 hover:bg-gray-100" title={t('Undo')} > - +
@@ -149,7 +149,7 @@ export function RichTextEditorToolbar({ )} title={t('Heading 1')} > - +
@@ -185,7 +185,7 @@ export function RichTextEditorToolbar({ className={btnClass(editor?.isActive('bold') ?? false)} title={t('Bold')} > - +
@@ -229,7 +229,7 @@ export function RichTextEditorToolbar({ className={btnClass(editor?.isActive('bulletList') ?? false)} title={t('Bullet List')} > - +
@@ -257,7 +257,7 @@ export function RichTextEditorToolbar({ className={btnClass(editor?.isActive({ textAlign: 'left' }) ?? false)} title={t('Align Left')} > - +
@@ -289,7 +289,7 @@ export function RichTextEditorToolbar({ className={btnClass(editor?.isActive('link') ?? false)} title={t('Add Link')} > - +
diff --git a/apps/app/src/components/decisions/ProposalCard/ProposalCardActions.tsx b/apps/app/src/components/decisions/ProposalCard/ProposalCardActions.tsx index 133128145..a4752fee9 100644 --- a/apps/app/src/components/decisions/ProposalCard/ProposalCardActions.tsx +++ b/apps/app/src/components/decisions/ProposalCard/ProposalCardActions.tsx @@ -7,9 +7,8 @@ import { Button, ButtonLink } from '@op/ui/Button'; import { DialogTrigger } from '@op/ui/Dialog'; import { Modal, ModalBody, ModalFooter, ModalHeader } from '@op/ui/Modal'; import { toast } from '@op/ui/Toast'; -import { Heart, Pencil, Trash2 } from 'lucide-react'; import { useState } from 'react'; -import { LuBookmark } from 'react-icons/lu'; +import { LuBookmark, LuHeart, LuPencil, LuTrash2 } from 'react-icons/lu'; import type { z } from 'zod'; import { useTranslations } from '@/lib/i18n'; @@ -61,7 +60,7 @@ export function ProposalCardActions({ className="w-full text-nowrap" isDisabled={isLoading} > - + {isLikedByUser ? t('Liked') : t('Like')} diff --git a/apps/app/src/components/decisions/ProposalCard/ProposalCardComponents.tsx b/apps/app/src/components/decisions/ProposalCard/ProposalCardComponents.tsx index d9d36d26a..2257369b7 100644 --- a/apps/app/src/components/decisions/ProposalCard/ProposalCardComponents.tsx +++ b/apps/app/src/components/decisions/ProposalCard/ProposalCardComponents.tsx @@ -16,10 +16,9 @@ import { Avatar } from '@op/ui/Avatar'; import { Chip } from '@op/ui/Chip'; import { Surface } from '@op/ui/Surface'; import { cn } from '@op/ui/utils'; -import { Heart, MessageCircle } from 'lucide-react'; import Image from 'next/image'; import type { HTMLAttributes, ReactNode } from 'react'; -import { LuBookmark } from 'react-icons/lu'; +import { LuBookmark, LuHeart, LuMessageCircle } from 'react-icons/lu'; import type { z } from 'zod'; import { useTranslations } from '@/lib/i18n'; @@ -409,11 +408,11 @@ export function ProposalCardMetrics({ )} > - + {proposal.likesCount || 0} {t('Likes')} - + {proposal.commentsCount || 0} {t('Comments')} diff --git a/apps/app/src/components/decisions/ProposalCard/ProposalCardMenu.tsx b/apps/app/src/components/decisions/ProposalCard/ProposalCardMenu.tsx index b17f30ef4..1efdd9165 100644 --- a/apps/app/src/components/decisions/ProposalCard/ProposalCardMenu.tsx +++ b/apps/app/src/components/decisions/ProposalCard/ProposalCardMenu.tsx @@ -14,8 +14,8 @@ import { Menu, MenuItem, MenuTrigger } from '@op/ui/Menu'; import { Modal, ModalBody, ModalFooter, ModalHeader } from '@op/ui/Modal'; import { Popover } from '@op/ui/Popover'; import { toast } from '@op/ui/Toast'; -import { Trash2 } from 'lucide-react'; import { useState } from 'react'; +import { LuTrash2 } from 'react-icons/lu'; import { LuCheck, LuEllipsis, LuEye, LuEyeOff, LuX } from 'react-icons/lu'; import type { z } from 'zod'; @@ -254,7 +254,7 @@ export function ProposalCardMenu({ if (proposal.isEditable) { items.push({ key: 'delete', - icon: , + icon: , label: t('Delete'), onAction: () => { setIsMenuSheetOpen(false); diff --git a/apps/app/src/components/decisions/ProposalView.tsx b/apps/app/src/components/decisions/ProposalView.tsx index 092eaf587..98ffbeb5a 100644 --- a/apps/app/src/components/decisions/ProposalView.tsx +++ b/apps/app/src/components/decisions/ProposalView.tsx @@ -14,11 +14,10 @@ import { Header1 } from '@op/ui/Header'; import { Link } from '@op/ui/Link'; import { Surface } from '@op/ui/Surface'; import { Tag, TagGroup } from '@op/ui/TagGroup'; -import { Heart, MessageCircle } from 'lucide-react'; import { useLocale } from 'next-intl'; import Image from 'next/image'; import { useCallback, useMemo, useRef, useState } from 'react'; -import { LuBookmark } from 'react-icons/lu'; +import { LuBookmark, LuHeart, LuMessageCircle } from 'react-icons/lu'; import { useTranslations } from '@/lib/i18n'; @@ -283,13 +282,13 @@ export function ProposalView({ {/* Engagement Stats */}
- + {currentProposal.likesCount || 0} {t('Likes')}
- + {currentProposal.commentsCount || 0}{' '} {(currentProposal.commentsCount || 0) !== 1 diff --git a/apps/app/src/components/decisions/ProposalViewLayout.tsx b/apps/app/src/components/decisions/ProposalViewLayout.tsx index 297b50776..d82a9f3a7 100644 --- a/apps/app/src/components/decisions/ProposalViewLayout.tsx +++ b/apps/app/src/components/decisions/ProposalViewLayout.tsx @@ -1,9 +1,8 @@ 'use client'; import { Button } from '@op/ui/Button'; -import { Edit, Heart } from 'lucide-react'; import { ReactNode } from 'react'; -import { LuArrowLeft, LuBookmark } from 'react-icons/lu'; +import { LuArrowLeft, LuBookmark, LuHeart, LuPencil } from 'react-icons/lu'; import { useTranslations } from '@/lib/i18n'; import { useRouter } from '@/lib/i18n/routing'; @@ -62,7 +61,7 @@ export function ProposalViewLayout({ onPress={() => router.push(editHref)} className="px-4 py-2" > - + {t('Edit')} )} @@ -73,7 +72,7 @@ export function ProposalViewLayout({ onPress={onLike} isDisabled={isLoading} > - + {isLiked ? t('Liked') : t('Like')} ) diff --git a/apps/app/src/components/decisions/SlashCommands.tsx b/apps/app/src/components/decisions/SlashCommands.tsx index a00252895..a8c5be3c7 100644 --- a/apps/app/src/components/decisions/SlashCommands.tsx +++ b/apps/app/src/components/decisions/SlashCommands.tsx @@ -3,18 +3,6 @@ import { Extension } from '@tiptap/core'; import { PluginKey } from '@tiptap/pm/state'; import { Suggestion, SuggestionOptions } from '@tiptap/suggestion'; -import { - Code, - Heading1, - Heading2, - Heading3, - Link2, - List, - ListOrdered, - Minus, - Quote, - Type, -} from 'lucide-react'; import React, { forwardRef, useEffect, @@ -22,6 +10,18 @@ import React, { useState, } from 'react'; import { createRoot } from 'react-dom/client'; +import { + LuCode, + LuHeading1, + LuHeading2, + LuHeading3, + LuLink2, + LuList, + LuListOrdered, + LuMinus, + LuQuote, + LuType, +} from 'react-icons/lu'; import { useTranslations } from '@/lib/i18n'; @@ -125,7 +125,7 @@ const suggestionOptions: Partial = { title: 'Text', description: 'Just start typing with plain text.', searchTerms: ['p', 'paragraph'], - icon: Type, + icon: LuType, command: ({ editor, range }) => { editor .chain() @@ -139,7 +139,7 @@ const suggestionOptions: Partial = { title: 'Heading 1', description: 'Big section heading.', searchTerms: ['title', 'big', 'large'], - icon: Heading1, + icon: LuHeading1, command: ({ editor, range }) => { editor .chain() @@ -153,7 +153,7 @@ const suggestionOptions: Partial = { title: 'Heading 2', description: 'Medium section heading.', searchTerms: ['subtitle', 'medium'], - icon: Heading2, + icon: LuHeading2, command: ({ editor, range }) => { editor .chain() @@ -167,7 +167,7 @@ const suggestionOptions: Partial = { title: 'Heading 3', description: 'Small section heading.', searchTerms: ['subtitle', 'small'], - icon: Heading3, + icon: LuHeading3, command: ({ editor, range }) => { editor .chain() @@ -181,7 +181,7 @@ const suggestionOptions: Partial = { title: 'Bullet List', description: 'Create a simple bullet list.', searchTerms: ['unordered', 'point'], - icon: List, + icon: LuList, command: ({ editor, range }) => { editor.chain().focus().deleteRange(range).toggleBulletList().run(); }, @@ -190,7 +190,7 @@ const suggestionOptions: Partial = { title: 'Numbered List', description: 'Create a list with numbering.', searchTerms: ['ordered'], - icon: ListOrdered, + icon: LuListOrdered, command: ({ editor, range }) => { editor.chain().focus().deleteRange(range).toggleOrderedList().run(); }, @@ -199,7 +199,7 @@ const suggestionOptions: Partial = { title: 'Quote', description: 'Capture a quote.', searchTerms: ['blockquote'], - icon: Quote, + icon: LuQuote, command: ({ editor, range }) => { editor .chain() @@ -214,7 +214,7 @@ const suggestionOptions: Partial = { title: 'Code', description: 'Capture a code snippet.', searchTerms: ['codeblock'], - icon: Code, + icon: LuCode, command: ({ editor, range }) => { editor.chain().focus().deleteRange(range).toggleCodeBlock().run(); }, @@ -223,7 +223,7 @@ const suggestionOptions: Partial = { title: 'Divider', description: 'Visually divide blocks.', searchTerms: ['horizontal', 'rule', 'hr'], - icon: Minus, + icon: LuMinus, command: ({ editor, range }) => { editor.chain().focus().deleteRange(range).setHorizontalRule().run(); }, @@ -232,7 +232,7 @@ const suggestionOptions: Partial = { title: 'Link Embed', description: 'Embed a link with preview.', searchTerms: ['embed', 'preview', 'iframely', 'url'], - icon: Link2, + icon: LuLink2, command: ({ editor, range }) => { const url = window.prompt('Enter the URL to embed:'); if (url && url.trim()) { diff --git a/packages/ui/src/components/AvatarUploader.tsx b/packages/ui/src/components/AvatarUploader.tsx index eed725373..7f5aec631 100644 --- a/packages/ui/src/components/AvatarUploader.tsx +++ b/packages/ui/src/components/AvatarUploader.tsx @@ -1,6 +1,6 @@ -import { Camera } from 'lucide-react'; import { useRef } from 'react'; import { useButton } from 'react-aria'; +import { LuCamera } from 'react-icons/lu'; import { cn } from '../lib/utils'; import { LoadingSpinner } from './LoadingSpinner'; @@ -66,7 +66,7 @@ export const AvatarUploader = ({ {uploading ? ( ) : ( - + )}
diff --git a/packages/ui/src/components/BannerUploader.tsx b/packages/ui/src/components/BannerUploader.tsx index 2aa20b8ef..4f0918fe2 100644 --- a/packages/ui/src/components/BannerUploader.tsx +++ b/packages/ui/src/components/BannerUploader.tsx @@ -1,6 +1,6 @@ -import { Camera } from 'lucide-react'; import { useRef } from 'react'; import { useButton } from 'react-aria'; +import { LuCamera } from 'react-icons/lu'; import { cn } from '../lib/utils'; import { LoadingSpinner } from './LoadingSpinner'; @@ -60,7 +60,7 @@ export const BannerUploader = ({ {uploading ? ( ) : ( - + )}
diff --git a/packages/ui/src/components/Breadcrumbs.tsx b/packages/ui/src/components/Breadcrumbs.tsx index f42cb4610..b06760f6c 100644 --- a/packages/ui/src/components/Breadcrumbs.tsx +++ b/packages/ui/src/components/Breadcrumbs.tsx @@ -1,6 +1,5 @@ 'use client'; -import { ChevronRight } from 'lucide-react'; import { Breadcrumb as AriaBreadcrumb, Breadcrumbs as AriaBreadcrumbs, @@ -10,6 +9,7 @@ import type { BreadcrumbsProps, LinkProps, } from 'react-aria-components'; +import { LuChevronRight } from 'react-icons/lu'; import { twMerge } from 'tailwind-merge'; import { composeTailwindRenderProps } from '../utils'; @@ -36,7 +36,7 @@ export const Breadcrumb = ( )} > - {props.href && } + {props.href && } ); }; diff --git a/packages/ui/src/components/Calendar.tsx b/packages/ui/src/components/Calendar.tsx index 620877501..0d2709381 100644 --- a/packages/ui/src/components/Calendar.tsx +++ b/packages/ui/src/components/Calendar.tsx @@ -1,7 +1,6 @@ 'use client'; import { getLocalTimeZone, isToday } from '@internationalized/date'; -import { ChevronLeft, ChevronRight } from 'lucide-react'; import { Calendar as AriaCalendar, CalendarGridHeader as AriaCalendarGridHeader, @@ -17,6 +16,7 @@ import type { CalendarProps as AriaCalendarProps, DateValue, } from 'react-aria-components'; +import { LuChevronLeft, LuChevronRight } from 'react-icons/lu'; import { tv } from 'tailwind-variants'; import { focusRing } from '../utils'; @@ -55,9 +55,9 @@ export const CalendarHeader = () => { className="h-8 w-8 rounded-none bg-white p-0 text-neutral-charcoal shadow-none hover:bg-neutral-offWhite pressed:bg-neutral-offWhite pressed:shadow-none" > {direction === 'rtl' ? ( - + ) : ( - + )} @@ -67,9 +67,9 @@ export const CalendarHeader = () => { className="h-8 w-8 rounded-none bg-white p-0 text-neutral-charcoal shadow-none hover:bg-neutral-offWhite pressed:bg-neutral-offWhite pressed:shadow-none" > {direction === 'rtl' ? ( - + ) : ( - + )} diff --git a/packages/ui/src/components/Checkbox.tsx b/packages/ui/src/components/Checkbox.tsx index adda07a7b..89ad06e2b 100644 --- a/packages/ui/src/components/Checkbox.tsx +++ b/packages/ui/src/components/Checkbox.tsx @@ -1,6 +1,5 @@ 'use client'; -import { Check, Minus } from 'lucide-react'; import type { ReactNode } from 'react'; import { Checkbox as AriaCheckbox, @@ -12,6 +11,7 @@ import type { CheckboxProps, ValidationResult, } from 'react-aria-components'; +import { LuCheck, LuMinus } from 'react-icons/lu'; import { VariantProps, tv } from 'tailwind-variants'; import { composeTailwindRenderProps, focusRing } from '../utils'; @@ -124,9 +124,15 @@ export const Checkbox = (props: CheckboxProps & CheckboxVariants) => { })} > {isIndeterminate ? ( - + ) : isSelected ? ( - + ) : null}
{props.children} diff --git a/packages/ui/src/components/ComboBox.tsx b/packages/ui/src/components/ComboBox.tsx index 38e149339..74e86eb0b 100644 --- a/packages/ui/src/components/ComboBox.tsx +++ b/packages/ui/src/components/ComboBox.tsx @@ -1,12 +1,12 @@ 'use client'; -import { ChevronDown } from 'lucide-react'; import { ComboBox as AriaComboBox, ListBox } from 'react-aria-components'; import type { ComboBoxProps as AriaComboBoxProps, ListBoxItemProps, ValidationResult, } from 'react-aria-components'; +import { LuChevronDown } from 'react-icons/lu'; import { cn } from '../lib/utils'; import { composeTailwindRenderProps } from '../utils'; @@ -60,7 +60,7 @@ export const ComboBox = ({ props.buttonProps?.className, )} > - + {description && {description}} diff --git a/packages/ui/src/components/DatePicker.tsx b/packages/ui/src/components/DatePicker.tsx index b3735c24d..fbe24f8a4 100644 --- a/packages/ui/src/components/DatePicker.tsx +++ b/packages/ui/src/components/DatePicker.tsx @@ -1,10 +1,10 @@ 'use client'; import { parseDate } from '@internationalized/date'; -import { CalendarIcon } from 'lucide-react'; import { useCallback, useEffect, useMemo, useState } from 'react'; import type { DateValue } from 'react-aria-components'; import { Button as AriaButton, DialogTrigger } from 'react-aria-components'; +import { LuCalendar } from 'react-icons/lu'; import { cn } from '../lib/utils'; import { Calendar } from './Calendar'; @@ -210,7 +210,7 @@ export const DatePicker = ({ props.isDisabled && 'cursor-not-allowed text-lightGray', )} > - + diff --git a/packages/ui/src/components/ListBox.tsx b/packages/ui/src/components/ListBox.tsx index d5f23e843..8a3875729 100644 --- a/packages/ui/src/components/ListBox.tsx +++ b/packages/ui/src/components/ListBox.tsx @@ -1,6 +1,5 @@ 'use client'; -import { Check } from 'lucide-react'; import { ListBox as AriaListBox, ListBoxItem as AriaListBoxItem, @@ -14,6 +13,7 @@ import type { ListBoxItemProps as RACListBoxItemProps, SectionProps, } from 'react-aria-components'; +import { LuCheck } from 'react-icons/lu'; import { tv } from 'tailwind-variants'; import type { VariantProps } from 'tailwind-variants'; @@ -139,7 +139,7 @@ export const DropdownItem = ( {children} - {isSelected && } + {isSelected && } ))} diff --git a/packages/ui/src/components/Menu.tsx b/packages/ui/src/components/Menu.tsx index cc1e117f3..d09d972b1 100644 --- a/packages/ui/src/components/Menu.tsx +++ b/packages/ui/src/components/Menu.tsx @@ -1,6 +1,5 @@ 'use client'; -import { Check, ChevronRight } from 'lucide-react'; import { Menu as AriaMenu, MenuItem as AriaMenuItem, @@ -13,6 +12,7 @@ import type { MenuItemProps, SeparatorProps, } from 'react-aria-components'; +import { LuCheck, LuChevronRight } from 'react-icons/lu'; import { VariantProps, cn, tv } from '../lib/utils'; import { DropdownSection, dropdownItemStyles } from './ListBox'; @@ -89,14 +89,14 @@ export const MenuItem = ( <> {selectionMode !== 'none' && ( - {isSelected && } + {isSelected && } )} {children} {hasSubmenu && ( - + )} ), diff --git a/packages/ui/src/components/Pagination.tsx b/packages/ui/src/components/Pagination.tsx index 746087815..7f639da62 100644 --- a/packages/ui/src/components/Pagination.tsx +++ b/packages/ui/src/components/Pagination.tsx @@ -1,9 +1,9 @@ 'use client'; import clsx from 'clsx'; -import { ChevronLeft, ChevronRight } from 'lucide-react'; import * as React from 'react'; import { type ContextValue, useContextProps } from 'react-aria-components'; +import { LuChevronLeft, LuChevronRight } from 'react-icons/lu'; import { Button } from './Button'; @@ -85,7 +85,7 @@ const PaginationNavigation = React.forwardRef< } }} > - + Previous ); diff --git a/packages/ui/src/components/PhaseStepper.tsx b/packages/ui/src/components/PhaseStepper.tsx index fd46a35ca..c9d6013df 100644 --- a/packages/ui/src/components/PhaseStepper.tsx +++ b/packages/ui/src/components/PhaseStepper.tsx @@ -1,6 +1,6 @@ 'use client'; -import { Check } from 'lucide-react'; +import { LuCheck } from 'react-icons/lu'; import { cn } from '../lib/utils'; import { formatDateRange } from '../utils/formatting'; @@ -42,7 +42,7 @@ const Step = ({ 'border border-neutral-charcoal bg-transparent text-neutral-charcoal', )} > - {stepState === 'completed' ? : index + 1} + {stepState === 'completed' ? : index + 1}
{phase.name}
diff --git a/packages/ui/src/components/ReactionsButton.tsx b/packages/ui/src/components/ReactionsButton.tsx index d42e50fec..e9723f235 100644 --- a/packages/ui/src/components/ReactionsButton.tsx +++ b/packages/ui/src/components/ReactionsButton.tsx @@ -1,7 +1,7 @@ 'use client'; -import { SmilePlus } from 'lucide-react'; import { Button as RACButton } from 'react-aria-components'; +import { LuSmilePlus } from 'react-icons/lu'; import { tv } from 'tailwind-variants'; import type { VariantProps } from 'tailwind-variants'; @@ -88,7 +88,7 @@ export const ReactionButton = ({ {...props} className={reactionButtonStyle({ size, active, className })} > - + ); } diff --git a/packages/ui/src/components/SearchField.tsx b/packages/ui/src/components/SearchField.tsx index 5473a7ca9..a1f9c1c76 100644 --- a/packages/ui/src/components/SearchField.tsx +++ b/packages/ui/src/components/SearchField.tsx @@ -1,11 +1,11 @@ 'use client'; -import { SearchIcon, XIcon } from 'lucide-react'; import { SearchField as AriaSearchField } from 'react-aria-components'; import type { SearchFieldProps as AriaSearchFieldProps, ValidationResult, } from 'react-aria-components'; +import { LuSearch, LuX } from 'react-icons/lu'; import { composeTailwindRenderProps } from '../utils'; import { Button } from './Button'; @@ -37,7 +37,7 @@ export const SearchField = ({ > {label && } - @@ -51,7 +51,7 @@ export const SearchField = ({ color="ghost" className="absolute top-1/2 right-1 aspect-square w-6 -translate-y-1/2 p-0 group-empty:invisible" > - + {description && {description}} diff --git a/packages/ui/src/components/Select.tsx b/packages/ui/src/components/Select.tsx index 6266289e0..a7ce328d4 100644 --- a/packages/ui/src/components/Select.tsx +++ b/packages/ui/src/components/Select.tsx @@ -1,6 +1,5 @@ 'use client'; -import { ChevronDown } from 'lucide-react'; import { ReactNode } from 'react'; import { Select as AriaSelect, @@ -13,6 +12,7 @@ import type { ListBoxItemProps, ValidationResult, } from 'react-aria-components'; +import { LuChevronDown } from 'react-icons/lu'; import { VariantProps, tv } from 'tailwind-variants'; import { cn } from '../lib/utils'; @@ -125,7 +125,10 @@ export const Select = ({ )} /> {icon ?? ( - + )} diff --git a/packages/ui/src/components/TagGroup.tsx b/packages/ui/src/components/TagGroup.tsx index 5a6572055..d526b6b60 100644 --- a/packages/ui/src/components/TagGroup.tsx +++ b/packages/ui/src/components/TagGroup.tsx @@ -1,6 +1,5 @@ 'use client'; -import { XIcon } from 'lucide-react'; import { createContext, useContext } from 'react'; import { Tag as AriaTag, @@ -15,6 +14,7 @@ import type { TagProps as AriaTagProps, TagListProps, } from 'react-aria-components'; +import { LuX } from 'react-icons/lu'; import { twMerge } from 'tailwind-merge'; import { tv } from 'tailwind-variants'; @@ -136,7 +136,7 @@ export const Tag = ({ children, color, ...props }: TagProps) => { {children} {allowsRemoving && ( )} diff --git a/packages/ui/src/components/TranslateBanner.tsx b/packages/ui/src/components/TranslateBanner.tsx index 774f241ab..086bd7673 100644 --- a/packages/ui/src/components/TranslateBanner.tsx +++ b/packages/ui/src/components/TranslateBanner.tsx @@ -1,4 +1,4 @@ -import { Languages, X } from 'lucide-react'; +import { LuLanguages, LuX } from 'react-icons/lu'; import { cn } from '../lib/utils'; import { Button } from './Button'; @@ -45,7 +45,7 @@ export const TranslateBanner = ({ className="group flex min-w-0 flex-1 cursor-pointer items-center gap-2 rounded-full text-left text-primary-teal outline-hidden transition-opacity focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-data-blue disabled:cursor-not-allowed disabled:opacity-60" > - + {label} @@ -56,7 +56,7 @@ export const TranslateBanner = ({ unstyled className="flex size-8 shrink-0 cursor-pointer items-center justify-center rounded-full text-neutral-gray4 outline-hidden transition-colors hover:bg-neutral-gray1 hover:text-neutral-charcoal focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-data-blue" > - +
); diff --git a/packages/ui/stories/Menu.stories.tsx b/packages/ui/stories/Menu.stories.tsx index 9ed9ecf6a..0b79e7b43 100644 --- a/packages/ui/stories/Menu.stories.tsx +++ b/packages/ui/stories/Menu.stories.tsx @@ -1,6 +1,6 @@ import type { Meta } from '@storybook/react-vite'; -import { MoreHorizontal } from 'lucide-react'; import { MenuTrigger, SubmenuTrigger } from 'react-aria-components'; +import { LuEllipsis } from 'react-icons/lu'; import { Button } from '../src/components/Button'; import { @@ -23,7 +23,7 @@ export default meta; export const Example = (args: any) => ( New… @@ -45,7 +45,7 @@ DisabledItems.args = { export const Sections = (args: any) => ( @@ -67,7 +67,7 @@ export const Sections = (args: any) => ( export const Submenu = (args: any) => ( New… diff --git a/packages/ui/stories/Popover.stories.tsx b/packages/ui/stories/Popover.stories.tsx index de22d1230..102712ce8 100644 --- a/packages/ui/stories/Popover.stories.tsx +++ b/packages/ui/stories/Popover.stories.tsx @@ -1,6 +1,6 @@ import type { Meta } from '@storybook/react-vite'; -import { HelpCircle } from 'lucide-react'; import { DialogTrigger, Heading } from 'react-aria-components'; +import { LuCircleHelp } from 'react-icons/lu'; import { Button } from '../src/components/Button'; import { Dialog } from '../src/components/Dialog'; @@ -22,7 +22,7 @@ export default meta; export const Example = (args: any) => ( diff --git a/packages/ui/stories/Tooltip.stories.tsx b/packages/ui/stories/Tooltip.stories.tsx index fea77f11b..8f0cdda83 100644 --- a/packages/ui/stories/Tooltip.stories.tsx +++ b/packages/ui/stories/Tooltip.stories.tsx @@ -1,6 +1,6 @@ import type { Meta } from '@storybook/react-vite'; -import { PrinterIcon, SaveIcon } from 'lucide-react'; import { TooltipTrigger } from 'react-aria-components'; +import { LuPrinter, LuSave } from 'react-icons/lu'; import { Button } from '../src/components/Button'; import { Tooltip } from '../src/components/Tooltip'; @@ -19,13 +19,13 @@ export const Example = (args: any) => (
Save Print From 6544ace1fb3305433f8a393bcaae0ae3bfb55a4e Mon Sep 17 00:00:00 2001 From: Scott Cazan Date: Fri, 6 Mar 2026 00:00:10 +0100 Subject: [PATCH 4/5] Add non-scaling-stroke to custom SVGs --- packages/ui/src/components/CommentButton.tsx | 1 + packages/ui/src/components/icons/CheckIcon.tsx | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/ui/src/components/CommentButton.tsx b/packages/ui/src/components/CommentButton.tsx index 265a08557..6ac3d806f 100644 --- a/packages/ui/src/components/CommentButton.tsx +++ b/packages/ui/src/components/CommentButton.tsx @@ -27,6 +27,7 @@ const MessageCircleIcon = ({ className }: { className?: string }) => ( strokeWidth="1" strokeLinecap="round" strokeLinejoin="round" + vectorEffect="non-scaling-stroke" fill="none" /> diff --git a/packages/ui/src/components/icons/CheckIcon.tsx b/packages/ui/src/components/icons/CheckIcon.tsx index bac6b064e..eb120cad6 100644 --- a/packages/ui/src/components/icons/CheckIcon.tsx +++ b/packages/ui/src/components/icons/CheckIcon.tsx @@ -17,6 +17,7 @@ export const CheckIcon = ({ className }: { className?: string }) => ( strokeWidth="1" strokeLinecap="round" strokeLinejoin="round" + vectorEffect="non-scaling-stroke" /> ); From 14860be7d4ca7c3898f23dfd85f5243d3f0adca3 Mon Sep 17 00:00:00 2001 From: Scott Cazan Date: Fri, 6 Mar 2026 11:29:10 +0100 Subject: [PATCH 5/5] Remove dependency --- package.json | 2 -- packages/ui/package.json | 1 - packages/ui/stories/AllComponents.stories.tsx | 6 ------ pnpm-lock.yaml | 16 ---------------- 4 files changed, 25 deletions(-) diff --git a/package.json b/package.json index 2df124f89..e4f96aa75 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,6 @@ "immer": "^10.1.1", "js-yaml": "^4.1.0", "lodash": "^4.17.21", - "lucide-react": "^0.476.0", "motion": "12.4.7", "nanoid": "5.1.2", "next": "catalog:", @@ -148,7 +147,6 @@ "immer": "$immer", "js-yaml": "$js-yaml", "lodash": "$lodash", - "lucide-react": "$lucide-react", "motion": "$motion", "postcss": "$postcss", "postgres": "$postgres", diff --git a/packages/ui/package.json b/packages/ui/package.json index 17717e9d5..9129d7824 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -109,7 +109,6 @@ "cmdk": "^1.0.4", "framer-motion": "^12.7.4", "lodash": "^4.17.21", - "lucide-react": "^0.476.0", "react": "^19.0.1", "react-aria": "^3.37.0", "react-aria-components": "^1.6.0", diff --git a/packages/ui/stories/AllComponents.stories.tsx b/packages/ui/stories/AllComponents.stories.tsx index 26287687d..c83731532 100644 --- a/packages/ui/stories/AllComponents.stories.tsx +++ b/packages/ui/stories/AllComponents.stories.tsx @@ -1,11 +1,5 @@ // @ts-nocheck // TODO: commenting for a demo -// import { -// BoldIcon, -// ItalicIcon, -// MoreHorizontal, -// UnderlineIcon, -// } from 'lucide-react'; // import { DialogTrigger, Group, MenuTrigger } from 'react-aria-components'; // import { TimeField } from '../src/components/TimeField'; // import { ToggleButton } from '../src/components/ToggleButton'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e5fdd7aa9..03978965d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -128,7 +128,6 @@ overrides: immer: ^10.1.1 js-yaml: ^4.1.0 lodash: ^4.17.21 - lucide-react: ^0.476.0 motion: 12.4.7 postcss: ^8.5.3 postgres: ^3.4.5 @@ -280,9 +279,6 @@ importers: lodash: specifier: ^4.17.21 version: 4.17.21 - lucide-react: - specifier: ^0.476.0 - version: 0.476.0(react@19.2.1) motion: specifier: 12.4.7 version: 12.4.7(react-dom@19.2.1(react@19.2.1))(react@19.2.1) @@ -1067,9 +1063,6 @@ importers: lodash: specifier: ^4.17.21 version: 4.17.21 - lucide-react: - specifier: ^0.476.0 - version: 0.476.0(react@19.2.1) react: specifier: ^19.0.1 version: 19.2.1 @@ -7637,11 +7630,6 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - lucide-react@0.476.0: - resolution: {integrity: sha512-x6cLTk8gahdUPje0hSgLN1/MgiJH+Xl90Xoxy9bkPAsMPOUiyRSKR4JCDPGVCEpyqnZXH3exFWNItcvra9WzUQ==} - peerDependencies: - react: ^19.0.1 - lz-string@1.5.0: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true @@ -16552,10 +16540,6 @@ snapshots: dependencies: yallist: 3.1.1 - lucide-react@0.476.0(react@19.2.1): - dependencies: - react: 19.2.1 - lz-string@1.5.0: {} maath@0.10.8(@types/three@0.174.0)(three@0.174.0):