From 6fbf5d6493d0f057402ee5dbc986707877305f88 Mon Sep 17 00:00:00 2001 From: georgewrmarshall Date: Wed, 22 Apr 2026 14:44:28 -0700 Subject: [PATCH 1/4] chore: migrating icon to union and centralized types --- eslint.config.mjs | 3 +- package.json | 4 +- .../design-system-react-native/package.json | 3 +- .../create-component/create-component.ts | 2 - .../scripts/generate-icons.ts | 154 ----- .../src/components/Icon/Icon.assets.ts | 566 +++++++++--------- .../src/components/Icon/Icon.constants.ts | 2 +- .../src/components/Icon/Icon.stories.tsx | 4 +- .../src/components/Icon/Icon.test.tsx | 4 +- .../src/components/Icon/Icon.tsx | 3 +- .../src/components/Icon/Icon.types.ts | 22 +- .../src/components/Icon/README.md | 2 + .../src/components/Icon/index.ts | 2 +- .../src/types/index.ts | 357 +---------- packages/design-system-react/package.json | 5 +- .../create-component/create-component.ts | 2 - .../scripts/generate-icons-index.test.ts | 147 ----- .../scripts/generate-icons-index.ts | 88 --- .../src/components/Icon/.svgrrc.js | 29 - .../src/components/Icon/Icon.constants.ts | 2 +- .../src/components/Icon/Icon.stories.tsx | 3 +- .../src/components/Icon/Icon.test.tsx | 4 +- .../src/components/Icon/Icon.tsx | 2 +- .../src/components/Icon/Icon.types.ts | 53 +- .../src/components/Icon/README.mdx | 2 + .../src/components/Icon/icons/index.ts | 155 ++--- .../src/components/Icon/index.ts | 2 +- .../src/components/Icon/template.d.ts | 20 - .../src/components/Icon/template.js | 52 -- .../src/components/Icon/template.test.ts | 30 - .../design-system-react/src/types/index.ts | 343 ----------- packages/design-system-shared/package.json | 7 +- .../scripts/generate-icons.ts | 341 +++++++++++ .../src/assets/icons/after-hours.svg | 2 +- packages/design-system-shared/src/index.ts | 8 + .../src/types/Icon/Icon.types.ts | 380 ++++++++++++ .../src/types/Icon/index.ts | 6 + .../scripts/testUtils.ts | 2 - yarn.lock | 232 +++---- 39 files changed, 1264 insertions(+), 1781 deletions(-) delete mode 100644 packages/design-system-react-native/scripts/generate-icons.ts delete mode 100644 packages/design-system-react/scripts/generate-icons-index.test.ts delete mode 100644 packages/design-system-react/scripts/generate-icons-index.ts delete mode 100644 packages/design-system-react/src/components/Icon/.svgrrc.js delete mode 100644 packages/design-system-react/src/components/Icon/template.d.ts delete mode 100644 packages/design-system-react/src/components/Icon/template.js delete mode 100644 packages/design-system-react/src/components/Icon/template.test.ts create mode 100644 packages/design-system-shared/scripts/generate-icons.ts create mode 100644 packages/design-system-shared/src/types/Icon/Icon.types.ts create mode 100644 packages/design-system-shared/src/types/Icon/index.ts diff --git a/eslint.config.mjs b/eslint.config.mjs index e2763ac08..24b0f96d1 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -74,6 +74,7 @@ const config = createConfig([ '**/tests/**/*.{js,ts}', 'scripts/*.ts', 'scripts/create-package/**/*.ts', + 'packages/*/scripts/**/*.ts', ], extends: [nodejs], rules: { @@ -189,7 +190,7 @@ const config = createConfig([ }, }, { - files: ['scripts/*.ts'], + files: ['scripts/*.ts', 'packages/*/scripts/**/*.ts'], rules: { // Scripts may be self-executable and thus have hashbangs. 'n/hashbang': 'off', diff --git a/package.json b/package.json index 421de84d4..b42ee64b6 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ ], "scripts": { "build": "yarn workspaces foreach --all --topological-dev run build", + "generate:icons": "yarn workspace @metamask/design-system-shared generate-icons", "build:clean": "rimraf 'packages/*/dist' '**/*.tsbuildinfo' && yarn build", "build:types": "tsc --build tsconfig.build.json --verbose", "changelog:update": "yarn workspaces foreach --all --no-private --parallel --interlaced --verbose run changelog:update", @@ -32,9 +33,6 @@ "figma:connect:unpublish": "yarn figma:connect:unpublish:react && yarn figma:connect:unpublish:react-native", "figma:connect:unpublish:react": "figma connect unpublish --config packages/design-system-react/figma.config.json", "figma:connect:unpublish:react-native": "figma connect unpublish --config packages/design-system-react-native/figma.config.json", - "generate-icons": "yarn generate-icons:react && yarn generate-icons:react-native", - "generate-icons:react": "yarn workspace @metamask/design-system-react generate-icons", - "generate-icons:react-native": "yarn workspace @metamask/design-system-react-native generate-icons", "lint": "yarn lint:eslint && yarn lint:misc --check && yarn constraints && yarn lint:dependencies", "lint:clear-cache": "rimraf .eslintcache", "lint:dependencies": "depcheck && yarn dedupe --check", diff --git a/packages/design-system-react-native/package.json b/packages/design-system-react-native/package.json index 8ac0d4911..88c5667bb 100644 --- a/packages/design-system-react-native/package.json +++ b/packages/design-system-react-native/package.json @@ -35,11 +35,10 @@ "dist/" ], "scripts": { - "build": "yarn generate-icons && ts-bridge --project tsconfig.build.json --verbose --clean --no-references && cp -r src/components/Icon/assets dist/components/Icon/", + "build": "ts-bridge --project tsconfig.build.json --verbose --clean --no-references && cp -r src/components/Icon/assets dist/components/Icon/", "changelog:update": "../../scripts/update-changelog.sh @metamask/design-system-react-native", "changelog:validate": "../../scripts/validate-changelog.sh @metamask/design-system-react-native", "create-component:react-native": "tsx scripts/create-component", - "generate-icons": "tsx scripts/generate-icons.ts", "publish:preview": "yarn npm publish --tag preview", "since-latest-release": "../../scripts/since-latest-release.sh", "test": "NODE_OPTIONS=--experimental-vm-modules jest --reporters=jest-silent-reporter", diff --git a/packages/design-system-react-native/scripts/create-component/create-component.ts b/packages/design-system-react-native/scripts/create-component/create-component.ts index 79e8df31b..a7628d191 100644 --- a/packages/design-system-react-native/scripts/create-component/create-component.ts +++ b/packages/design-system-react-native/scripts/create-component/create-component.ts @@ -1,7 +1,5 @@ -/* eslint-disable import-x/no-nodejs-modules */ import { promises as fs } from 'fs'; import * as path from 'path'; -/* eslint-enable import-x/no-nodejs-modules */ type CreateComponentArgs = { name: string; diff --git a/packages/design-system-react-native/scripts/generate-icons.ts b/packages/design-system-react-native/scripts/generate-icons.ts deleted file mode 100644 index 841f16cde..000000000 --- a/packages/design-system-react-native/scripts/generate-icons.ts +++ /dev/null @@ -1,154 +0,0 @@ -/* eslint-disable import-x/no-nodejs-modules */ -import fs from 'fs'; -import path from 'path'; -/* eslint-enable import-x/no-nodejs-modules */ - -const ASSETS_FOLDER = 'assets'; -const GENERATED_ASSETS_FILE = 'Icon.assets.ts'; -const TYPES_FILE = 'index.ts'; -const ASSET_EXT = '.svg'; -const TYPES_CONTENT_TO_DETECT = '// DO NOT EDIT - Use generate-assets.js'; - -/** Single source of truth for SVG assets — shared across React and React Native */ -const REPO_ROOT = path.join(__dirname, '../../..'); -const SHARED_ASSETS_DIR = path.join( - REPO_ROOT, - 'packages/design-system-shared/src/assets/icons', -); - -/** - * Gets an icon name in TitleCase from the given file name. - * - * @param fileName - The name of the file (including extension) to process. - * @returns The formatted icon name in TitleCase. - */ -function getIconNameInTitleCase(fileName: string): string { - return path - .basename(fileName, ASSET_EXT) - .split('-') - .map( - (section: string) => `${section[0].toUpperCase()}${section.substring(1)}`, - ) - .join(''); -} - -/** - * Main entry point for the script. - * Reads SVG files, transforms them, generates asset and type files. - * Throws an error if anything goes wrong. - */ -export async function main(): Promise { - const localAssetsFolderPath = path.join( - __dirname, - `../src/components/Icon/${ASSETS_FOLDER}`, - ); - const assetsModulePath = path.join( - __dirname, - `../src/components/Icon/${GENERATED_ASSETS_FILE}`, - ); - const typesFilePath = path.join(__dirname, `../src/types/${TYPES_FILE}`); - - // Read SVGs from the shared source of truth - const fileList = await fs.promises.readdir(SHARED_ASSETS_DIR); - const assetFileList = fileList - .filter((fileName: string) => path.extname(fileName) === ASSET_EXT) - .sort(); - - // Process SVGs: replace hardcoded black fill with currentColor so icons - // inherit color from context, then copy to the local RN assets folder. - for (const fileName of assetFileList) { - const srcPath = path.join(SHARED_ASSETS_DIR, fileName); - const destPath = path.join(localAssetsFolderPath, fileName); - const fileContent = await fs.promises.readFile(srcPath, { - encoding: 'utf-8', - }); - const formattedFileContent = fileContent.replace(/black/gu, 'currentColor'); - await fs.promises.writeFile(destPath, formattedFileContent); - } - - await fs.promises.writeFile(assetsModulePath, ''); - - await fs.promises.appendFile( - assetsModulePath, - `// /////////////////////////////////////////////////////\n// This is a generated file\n// DO NOT EDIT - Use generate-icons.js\n// /////////////////////////////////////////////////////`, - ); - - await fs.promises.appendFile( - assetsModulePath, - `\nimport { IconName } from '../../types';`, - ); - - await fs.promises.appendFile(assetsModulePath, '\n'); - - for (const fileName of assetFileList) { - const iconName = getIconNameInTitleCase(fileName); - await fs.promises.appendFile( - assetsModulePath, - `\nimport ${iconName}SVG from './${ASSETS_FOLDER}/${fileName}';`, - ); - } - - await fs.promises.appendFile( - assetsModulePath, - `\nimport type { AssetByIconName } from './Icon.types';`, - ); - - await fs.promises.appendFile( - assetsModulePath, - `\n\n/**\n * Asset stored by icon name\n */`, - ); - - await fs.promises.appendFile( - assetsModulePath, - `\nexport const assetByIconName: AssetByIconName = {`, - ); - - for (const fileName of assetFileList) { - const iconName = getIconNameInTitleCase(fileName); - await fs.promises.appendFile( - assetsModulePath, - `\n [IconName.${iconName}]: ${iconName}SVG,`, - ); - } - - await fs.promises.appendFile(assetsModulePath, '\n};\n'); - - const typesFileContent = await fs.promises.readFile(typesFilePath, { - encoding: 'utf8', - }); - const indexToRemove = typesFileContent.indexOf(TYPES_CONTENT_TO_DETECT); - const baseTypesFileContent = typesFileContent.substring(0, indexToRemove); - - let typesContentToWrite = `${ - baseTypesFileContent + TYPES_CONTENT_TO_DETECT - }\n// /////////////////////////////////////////////////////`; - - typesContentToWrite += - '\n\n/**\n * Icon - name\n */\n/* eslint-disable @typescript-eslint/no-shadow */\nexport enum IconName {'; - - for (const fileName of assetFileList) { - const iconName = path - .basename(fileName, ASSET_EXT) - .split('-') - .map( - (section: string) => - `${section[0].toUpperCase()}${section.substring(1, section.length)}`, - ) - .join(''); - typesContentToWrite += `\n ${iconName} = '${iconName}',`; - } - - typesContentToWrite += - '\n}\n/* eslint-enable @typescript-eslint/no-shadow */\n'; - - await fs.promises.writeFile(typesFilePath, typesContentToWrite); - - console.log(`Finished generating icons!`); -} - -if (require.main === module) { - main().catch((error) => { - console.error(error); - throw error; // Throw instead of process.exit(1) - }); -} diff --git a/packages/design-system-react-native/src/components/Icon/Icon.assets.ts b/packages/design-system-react-native/src/components/Icon/Icon.assets.ts index e618ff9e5..f8143ffb4 100644 --- a/packages/design-system-react-native/src/components/Icon/Icon.assets.ts +++ b/packages/design-system-react-native/src/components/Icon/Icon.assets.ts @@ -1,9 +1,7 @@ // ///////////////////////////////////////////////////// // This is a generated file -// DO NOT EDIT - Use generate-icons.js +// DO NOT EDIT — run `yarn generate:icons` from the repo root // ///////////////////////////////////////////////////// -import { IconName } from '../../types'; - import AccessibilitySVG from './assets/accessibility.svg'; import ActivitySVG from './assets/activity.svg'; import AddCardSVG from './assets/add-card.svg'; @@ -291,285 +289,285 @@ import type { AssetByIconName } from './Icon.types'; * Asset stored by icon name */ export const assetByIconName: AssetByIconName = { - [IconName.Accessibility]: AccessibilitySVG, - [IconName.Activity]: ActivitySVG, - [IconName.AddCard]: AddCardSVG, - [IconName.AddCircle]: AddCircleSVG, - [IconName.AddSquare]: AddSquareSVG, - [IconName.Add]: AddSVG, - [IconName.AfterHours]: AfterHoursSVG, - [IconName.Ai]: AiSVG, - [IconName.AlternateEmail]: AlternateEmailSVG, - [IconName.AppleLogo]: AppleLogoSVG, - [IconName.Apps]: AppsSVG, - [IconName.Arrow2Down]: Arrow2DownSVG, - [IconName.Arrow2Left]: Arrow2LeftSVG, - [IconName.Arrow2Right]: Arrow2RightSVG, - [IconName.Arrow2UpRight]: Arrow2UpRightSVG, - [IconName.Arrow2Up]: Arrow2UpSVG, - [IconName.ArrowCircleDown]: ArrowCircleDownSVG, - [IconName.ArrowCircleUp]: ArrowCircleUpSVG, - [IconName.ArrowDoubleLeft]: ArrowDoubleLeftSVG, - [IconName.ArrowDoubleRight]: ArrowDoubleRightSVG, - [IconName.ArrowDown]: ArrowDownSVG, - [IconName.ArrowDropDownCircle]: ArrowDropDownCircleSVG, - [IconName.ArrowLeft]: ArrowLeftSVG, - [IconName.ArrowRight]: ArrowRightSVG, - [IconName.ArrowUp]: ArrowUpSVG, - [IconName.AttachMoney]: AttachMoneySVG, - [IconName.Attachment]: AttachmentSVG, - [IconName.Backspace]: BackspaceSVG, - [IconName.Ban]: BanSVG, - [IconName.BankAssured]: BankAssuredSVG, - [IconName.Bank]: BankSVG, - [IconName.Bold]: BoldSVG, - [IconName.Book]: BookSVG, - [IconName.Bookmark]: BookmarkSVG, - [IconName.Bridge]: BridgeSVG, - [IconName.Briefcase]: BriefcaseSVG, - [IconName.Bulb]: BulbSVG, - [IconName.BuySell]: BuySellSVG, - [IconName.Cake]: CakeSVG, - [IconName.Calculator]: CalculatorSVG, - [IconName.Calendar]: CalendarSVG, - [IconName.Call]: CallSVG, - [IconName.Camera]: CameraSVG, - [IconName.Campaign]: CampaignSVG, - [IconName.Candlestick]: CandlestickSVG, - [IconName.CardPos]: CardPosSVG, - [IconName.Card]: CardSVG, - [IconName.Cash]: CashSVG, - [IconName.Category]: CategorySVG, - [IconName.Chart]: ChartSVG, - [IconName.CheckBold]: CheckBoldSVG, - [IconName.Check]: CheckSVG, - [IconName.CircleX]: CircleXSVG, - [IconName.Clear]: ClearSVG, - [IconName.ClockFilled]: ClockFilledSVG, - [IconName.Clock]: ClockSVG, - [IconName.Close]: CloseSVG, - [IconName.CloudDownload]: CloudDownloadSVG, - [IconName.CloudUpload]: CloudUploadSVG, - [IconName.Cloud]: CloudSVG, - [IconName.CodeCircle]: CodeCircleSVG, - [IconName.Code]: CodeSVG, - [IconName.Coin]: CoinSVG, - [IconName.Collapse]: CollapseSVG, - [IconName.Confirmation]: ConfirmationSVG, - [IconName.Connect]: ConnectSVG, - [IconName.CopySuccess]: CopySuccessSVG, - [IconName.Copy]: CopySVG, - [IconName.CorporateFare]: CorporateFareSVG, - [IconName.CreditCheck]: CreditCheckSVG, - [IconName.CurrencyFranc]: CurrencyFrancSVG, - [IconName.CurrencyLira]: CurrencyLiraSVG, - [IconName.CurrencyPound]: CurrencyPoundSVG, - [IconName.CurrencyYuan]: CurrencyYuanSVG, - [IconName.Customize]: CustomizeSVG, - [IconName.Danger]: DangerSVG, - [IconName.DarkFilled]: DarkFilledSVG, - [IconName.Dark]: DarkSVG, - [IconName.Data]: DataSVG, - [IconName.Description]: DescriptionSVG, - [IconName.Details]: DetailsSVG, - [IconName.Diagram]: DiagramSVG, - [IconName.DocumentCode]: DocumentCodeSVG, - [IconName.Download]: DownloadSVG, - [IconName.Draft]: DraftSVG, - [IconName.EcoLeaf]: EcoLeafSVG, - [IconName.EditSquare]: EditSquareSVG, - [IconName.Edit]: EditSVG, - [IconName.EncryptedAdd]: EncryptedAddSVG, - [IconName.Eraser]: EraserSVG, - [IconName.Error]: ErrorSVG, - [IconName.Ethereum]: EthereumSVG, - [IconName.Exchange]: ExchangeSVG, - [IconName.ExpandVertical]: ExpandVerticalSVG, - [IconName.Expand]: ExpandSVG, - [IconName.ExploreFilled]: ExploreFilledSVG, - [IconName.Explore]: ExploreSVG, - [IconName.Export]: ExportSVG, - [IconName.Extension]: ExtensionSVG, - [IconName.EyeSlash]: EyeSlashSVG, - [IconName.Eye]: EyeSVG, - [IconName.FaceId]: FaceIdSVG, - [IconName.Feedback]: FeedbackSVG, - [IconName.File]: FileSVG, - [IconName.Filter]: FilterSVG, - [IconName.Fingerprint]: FingerprintSVG, - [IconName.Fire]: FireSVG, - [IconName.FirstPage]: FirstPageSVG, - [IconName.Flag]: FlagSVG, - [IconName.FlashSlash]: FlashSlashSVG, - [IconName.Flash]: FlashSVG, - [IconName.Flask]: FlaskSVG, - [IconName.Flower]: FlowerSVG, - [IconName.Folder]: FolderSVG, - [IconName.Forest]: ForestSVG, - [IconName.FullCircle]: FullCircleSVG, - [IconName.Gas]: GasSVG, - [IconName.Gift]: GiftSVG, - [IconName.GlobalSearch]: GlobalSearchSVG, - [IconName.Global]: GlobalSVG, - [IconName.Graph]: GraphSVG, - [IconName.Hardware]: HardwareSVG, - [IconName.HashTag]: HashTagSVG, - [IconName.HeartFilled]: HeartFilledSVG, - [IconName.Heart]: HeartSVG, - [IconName.Hierarchy]: HierarchySVG, - [IconName.HomeFilled]: HomeFilledSVG, - [IconName.Home]: HomeSVG, - [IconName.Image]: ImageSVG, - [IconName.Info]: InfoSVG, - [IconName.Inventory]: InventorySVG, - [IconName.Joystick]: JoystickSVG, - [IconName.KeepFilled]: KeepFilledSVG, - [IconName.Keep]: KeepSVG, - [IconName.Key]: KeySVG, - [IconName.LastPage]: LastPageSVG, - [IconName.LightFilled]: LightFilledSVG, - [IconName.Light]: LightSVG, - [IconName.Link]: LinkSVG, - [IconName.Loading]: LoadingSVG, - [IconName.Location]: LocationSVG, - [IconName.LockSlash]: LockSlashSVG, - [IconName.Lock]: LockSVG, - [IconName.LockedFilled]: LockedFilledSVG, - [IconName.Login]: LoginSVG, - [IconName.Logout]: LogoutSVG, - [IconName.Mail]: MailSVG, - [IconName.Map]: MapSVG, - [IconName.Menu]: MenuSVG, - [IconName.MessageQuestion]: MessageQuestionSVG, - [IconName.Messages]: MessagesSVG, - [IconName.MetamaskFoxOutline]: MetamaskFoxOutlineSVG, - [IconName.Mic]: MicSVG, - [IconName.MinusBold]: MinusBoldSVG, - [IconName.MinusSquare]: MinusSquareSVG, - [IconName.Minus]: MinusSVG, - [IconName.Mobile]: MobileSVG, - [IconName.MoneyBag]: MoneyBagSVG, - [IconName.Money]: MoneySVG, - [IconName.Monitor]: MonitorSVG, - [IconName.MoreHorizontal]: MoreHorizontalSVG, - [IconName.MoreVertical]: MoreVerticalSVG, - [IconName.MountainFlag]: MountainFlagSVG, - [IconName.MusicNote]: MusicNoteSVG, - [IconName.NoPhotography]: NoPhotographySVG, - [IconName.Notification]: NotificationSVG, - [IconName.PageInfo]: PageInfoSVG, - [IconName.Palette]: PaletteSVG, - [IconName.PasswordCheck]: PasswordCheckSVG, - [IconName.Pending]: PendingSVG, - [IconName.People]: PeopleSVG, - [IconName.PersonCancel]: PersonCancelSVG, - [IconName.Pin]: PinSVG, - [IconName.Plant]: PlantSVG, - [IconName.Plug]: PlugSVG, - [IconName.PlusAndMinus]: PlusAndMinusSVG, - [IconName.PolicyAlert]: PolicyAlertSVG, - [IconName.PopUp]: PopUpSVG, - [IconName.Print]: PrintSVG, - [IconName.PriorityHigh]: PriorityHighSVG, - [IconName.PrivacyTip]: PrivacyTipSVG, - [IconName.ProgrammingArrows]: ProgrammingArrowsSVG, - [IconName.Publish]: PublishSVG, - [IconName.QrCode]: QrCodeSVG, - [IconName.Question]: QuestionSVG, - [IconName.Receive]: ReceiveSVG, - [IconName.Received]: ReceivedSVG, - [IconName.Refresh]: RefreshSVG, - [IconName.RemoveMinus]: RemoveMinusSVG, - [IconName.Report]: ReportSVG, - [IconName.Rocket]: RocketSVG, - [IconName.SaveFilled]: SaveFilledSVG, - [IconName.Save]: SaveSVG, - [IconName.Saving]: SavingSVG, - [IconName.ScanBarcode]: ScanBarcodeSVG, - [IconName.ScanFocus]: ScanFocusSVG, - [IconName.Scan]: ScanSVG, - [IconName.Search]: SearchSVG, - [IconName.SecurityAlert]: SecurityAlertSVG, - [IconName.SecurityCross]: SecurityCrossSVG, - [IconName.SecurityKey]: SecurityKeySVG, - [IconName.SecuritySearch]: SecuritySearchSVG, - [IconName.SecuritySlash]: SecuritySlashSVG, - [IconName.SecurityTick]: SecurityTickSVG, - [IconName.SecurityTime]: SecurityTimeSVG, - [IconName.SecurityUser]: SecurityUserSVG, - [IconName.Security]: SecuritySVG, - [IconName.Send]: SendSVG, - [IconName.SentimentDissatisfied]: SentimentDissatisfiedSVG, - [IconName.SentimentNeutral]: SentimentNeutralSVG, - [IconName.SentimentSatisfied]: SentimentSatisfiedSVG, - [IconName.SentimentVerySatisfied]: SentimentVerySatisfiedSVG, - [IconName.SettingFilled]: SettingFilledSVG, - [IconName.Setting]: SettingSVG, - [IconName.Share]: ShareSVG, - [IconName.ShieldLock]: ShieldLockSVG, - [IconName.ShoppingBag]: ShoppingBagSVG, - [IconName.ShoppingCart]: ShoppingCartSVG, - [IconName.SidePanel]: SidePanelSVG, - [IconName.SignalCellular]: SignalCellularSVG, - [IconName.Slash]: SlashSVG, - [IconName.Sms]: SmsSVG, - [IconName.SnapsMobile]: SnapsMobileSVG, - [IconName.SnapsPlus]: SnapsPlusSVG, - [IconName.SnapsRound]: SnapsRoundSVG, - [IconName.Snaps]: SnapsSVG, - [IconName.SortByAlpha]: SortByAlphaSVG, - [IconName.Sort]: SortSVG, - [IconName.Sparkle]: SparkleSVG, - [IconName.Speed]: SpeedSVG, - [IconName.Speedometer]: SpeedometerSVG, - [IconName.Square]: SquareSVG, - [IconName.Stake]: StakeSVG, - [IconName.StarFilled]: StarFilledSVG, - [IconName.Star]: StarSVG, - [IconName.Start]: StartSVG, - [IconName.Storefront]: StorefrontSVG, - [IconName.Student]: StudentSVG, - [IconName.SwapHorizontal]: SwapHorizontalSVG, - [IconName.SwapVertical]: SwapVerticalSVG, - [IconName.TabClose]: TabCloseSVG, - [IconName.TableRow]: TableRowSVG, - [IconName.Tablet]: TabletSVG, - [IconName.Tag]: TagSVG, - [IconName.ThumbDownFilled]: ThumbDownFilledSVG, - [IconName.ThumbDown]: ThumbDownSVG, - [IconName.ThumbUpFilled]: ThumbUpFilledSVG, - [IconName.ThumbUp]: ThumbUpSVG, - [IconName.Tint]: TintSVG, - [IconName.Tooltip]: TooltipSVG, - [IconName.Translate]: TranslateSVG, - [IconName.Trash]: TrashSVG, - [IconName.TrendDown]: TrendDownSVG, - [IconName.TrendUp]: TrendUpSVG, - [IconName.Undo]: UndoSVG, - [IconName.Unfold]: UnfoldSVG, - [IconName.UnlockedFilled]: UnlockedFilledSVG, - [IconName.Unpin]: UnpinSVG, - [IconName.UploadFile]: UploadFileSVG, - [IconName.Upload]: UploadSVG, - [IconName.Usb]: UsbSVG, - [IconName.UserCheck]: UserCheckSVG, - [IconName.UserCircleAdd]: UserCircleAddSVG, - [IconName.UserCircleRemove]: UserCircleRemoveSVG, - [IconName.UserCircle]: UserCircleSVG, - [IconName.User]: UserSVG, - [IconName.VerifiedFilled]: VerifiedFilledSVG, - [IconName.Verified]: VerifiedSVG, - [IconName.Videocam]: VideocamSVG, - [IconName.ViewColumn]: ViewColumnSVG, - [IconName.ViewInAr]: ViewInArSVG, - [IconName.VolumeOff]: VolumeOffSVG, - [IconName.VolumeUp]: VolumeUpSVG, - [IconName.WalletFilled]: WalletFilledSVG, - [IconName.Wallet]: WalletSVG, - [IconName.Warning]: WarningSVG, - [IconName.WebTraffic]: WebTrafficSVG, - [IconName.Widgets]: WidgetsSVG, - [IconName.WifiOff]: WifiOffSVG, - [IconName.Wifi]: WifiSVG, - [IconName.X]: XSVG, + Accessibility: AccessibilitySVG, + Activity: ActivitySVG, + AddCard: AddCardSVG, + AddCircle: AddCircleSVG, + AddSquare: AddSquareSVG, + Add: AddSVG, + AfterHours: AfterHoursSVG, + Ai: AiSVG, + AlternateEmail: AlternateEmailSVG, + AppleLogo: AppleLogoSVG, + Apps: AppsSVG, + Arrow2Down: Arrow2DownSVG, + Arrow2Left: Arrow2LeftSVG, + Arrow2Right: Arrow2RightSVG, + Arrow2UpRight: Arrow2UpRightSVG, + Arrow2Up: Arrow2UpSVG, + ArrowCircleDown: ArrowCircleDownSVG, + ArrowCircleUp: ArrowCircleUpSVG, + ArrowDoubleLeft: ArrowDoubleLeftSVG, + ArrowDoubleRight: ArrowDoubleRightSVG, + ArrowDown: ArrowDownSVG, + ArrowDropDownCircle: ArrowDropDownCircleSVG, + ArrowLeft: ArrowLeftSVG, + ArrowRight: ArrowRightSVG, + ArrowUp: ArrowUpSVG, + AttachMoney: AttachMoneySVG, + Attachment: AttachmentSVG, + Backspace: BackspaceSVG, + Ban: BanSVG, + BankAssured: BankAssuredSVG, + Bank: BankSVG, + Bold: BoldSVG, + Book: BookSVG, + Bookmark: BookmarkSVG, + Bridge: BridgeSVG, + Briefcase: BriefcaseSVG, + Bulb: BulbSVG, + BuySell: BuySellSVG, + Cake: CakeSVG, + Calculator: CalculatorSVG, + Calendar: CalendarSVG, + Call: CallSVG, + Camera: CameraSVG, + Campaign: CampaignSVG, + Candlestick: CandlestickSVG, + CardPos: CardPosSVG, + Card: CardSVG, + Cash: CashSVG, + Category: CategorySVG, + Chart: ChartSVG, + CheckBold: CheckBoldSVG, + Check: CheckSVG, + CircleX: CircleXSVG, + Clear: ClearSVG, + ClockFilled: ClockFilledSVG, + Clock: ClockSVG, + Close: CloseSVG, + CloudDownload: CloudDownloadSVG, + CloudUpload: CloudUploadSVG, + Cloud: CloudSVG, + CodeCircle: CodeCircleSVG, + Code: CodeSVG, + Coin: CoinSVG, + Collapse: CollapseSVG, + Confirmation: ConfirmationSVG, + Connect: ConnectSVG, + CopySuccess: CopySuccessSVG, + Copy: CopySVG, + CorporateFare: CorporateFareSVG, + CreditCheck: CreditCheckSVG, + CurrencyFranc: CurrencyFrancSVG, + CurrencyLira: CurrencyLiraSVG, + CurrencyPound: CurrencyPoundSVG, + CurrencyYuan: CurrencyYuanSVG, + Customize: CustomizeSVG, + Danger: DangerSVG, + DarkFilled: DarkFilledSVG, + Dark: DarkSVG, + Data: DataSVG, + Description: DescriptionSVG, + Details: DetailsSVG, + Diagram: DiagramSVG, + DocumentCode: DocumentCodeSVG, + Download: DownloadSVG, + Draft: DraftSVG, + EcoLeaf: EcoLeafSVG, + EditSquare: EditSquareSVG, + Edit: EditSVG, + EncryptedAdd: EncryptedAddSVG, + Eraser: EraserSVG, + Error: ErrorSVG, + Ethereum: EthereumSVG, + Exchange: ExchangeSVG, + ExpandVertical: ExpandVerticalSVG, + Expand: ExpandSVG, + ExploreFilled: ExploreFilledSVG, + Explore: ExploreSVG, + Export: ExportSVG, + Extension: ExtensionSVG, + EyeSlash: EyeSlashSVG, + Eye: EyeSVG, + FaceId: FaceIdSVG, + Feedback: FeedbackSVG, + File: FileSVG, + Filter: FilterSVG, + Fingerprint: FingerprintSVG, + Fire: FireSVG, + FirstPage: FirstPageSVG, + Flag: FlagSVG, + FlashSlash: FlashSlashSVG, + Flash: FlashSVG, + Flask: FlaskSVG, + Flower: FlowerSVG, + Folder: FolderSVG, + Forest: ForestSVG, + FullCircle: FullCircleSVG, + Gas: GasSVG, + Gift: GiftSVG, + GlobalSearch: GlobalSearchSVG, + Global: GlobalSVG, + Graph: GraphSVG, + Hardware: HardwareSVG, + HashTag: HashTagSVG, + HeartFilled: HeartFilledSVG, + Heart: HeartSVG, + Hierarchy: HierarchySVG, + HomeFilled: HomeFilledSVG, + Home: HomeSVG, + Image: ImageSVG, + Info: InfoSVG, + Inventory: InventorySVG, + Joystick: JoystickSVG, + KeepFilled: KeepFilledSVG, + Keep: KeepSVG, + Key: KeySVG, + LastPage: LastPageSVG, + LightFilled: LightFilledSVG, + Light: LightSVG, + Link: LinkSVG, + Loading: LoadingSVG, + Location: LocationSVG, + LockSlash: LockSlashSVG, + Lock: LockSVG, + LockedFilled: LockedFilledSVG, + Login: LoginSVG, + Logout: LogoutSVG, + Mail: MailSVG, + Map: MapSVG, + Menu: MenuSVG, + MessageQuestion: MessageQuestionSVG, + Messages: MessagesSVG, + MetamaskFoxOutline: MetamaskFoxOutlineSVG, + Mic: MicSVG, + MinusBold: MinusBoldSVG, + MinusSquare: MinusSquareSVG, + Minus: MinusSVG, + Mobile: MobileSVG, + MoneyBag: MoneyBagSVG, + Money: MoneySVG, + Monitor: MonitorSVG, + MoreHorizontal: MoreHorizontalSVG, + MoreVertical: MoreVerticalSVG, + MountainFlag: MountainFlagSVG, + MusicNote: MusicNoteSVG, + NoPhotography: NoPhotographySVG, + Notification: NotificationSVG, + PageInfo: PageInfoSVG, + Palette: PaletteSVG, + PasswordCheck: PasswordCheckSVG, + Pending: PendingSVG, + People: PeopleSVG, + PersonCancel: PersonCancelSVG, + Pin: PinSVG, + Plant: PlantSVG, + Plug: PlugSVG, + PlusAndMinus: PlusAndMinusSVG, + PolicyAlert: PolicyAlertSVG, + PopUp: PopUpSVG, + Print: PrintSVG, + PriorityHigh: PriorityHighSVG, + PrivacyTip: PrivacyTipSVG, + ProgrammingArrows: ProgrammingArrowsSVG, + Publish: PublishSVG, + QrCode: QrCodeSVG, + Question: QuestionSVG, + Receive: ReceiveSVG, + Received: ReceivedSVG, + Refresh: RefreshSVG, + RemoveMinus: RemoveMinusSVG, + Report: ReportSVG, + Rocket: RocketSVG, + SaveFilled: SaveFilledSVG, + Save: SaveSVG, + Saving: SavingSVG, + ScanBarcode: ScanBarcodeSVG, + ScanFocus: ScanFocusSVG, + Scan: ScanSVG, + Search: SearchSVG, + SecurityAlert: SecurityAlertSVG, + SecurityCross: SecurityCrossSVG, + SecurityKey: SecurityKeySVG, + SecuritySearch: SecuritySearchSVG, + SecuritySlash: SecuritySlashSVG, + SecurityTick: SecurityTickSVG, + SecurityTime: SecurityTimeSVG, + SecurityUser: SecurityUserSVG, + Security: SecuritySVG, + Send: SendSVG, + SentimentDissatisfied: SentimentDissatisfiedSVG, + SentimentNeutral: SentimentNeutralSVG, + SentimentSatisfied: SentimentSatisfiedSVG, + SentimentVerySatisfied: SentimentVerySatisfiedSVG, + SettingFilled: SettingFilledSVG, + Setting: SettingSVG, + Share: ShareSVG, + ShieldLock: ShieldLockSVG, + ShoppingBag: ShoppingBagSVG, + ShoppingCart: ShoppingCartSVG, + SidePanel: SidePanelSVG, + SignalCellular: SignalCellularSVG, + Slash: SlashSVG, + Sms: SmsSVG, + SnapsMobile: SnapsMobileSVG, + SnapsPlus: SnapsPlusSVG, + SnapsRound: SnapsRoundSVG, + Snaps: SnapsSVG, + SortByAlpha: SortByAlphaSVG, + Sort: SortSVG, + Sparkle: SparkleSVG, + Speed: SpeedSVG, + Speedometer: SpeedometerSVG, + Square: SquareSVG, + Stake: StakeSVG, + StarFilled: StarFilledSVG, + Star: StarSVG, + Start: StartSVG, + Storefront: StorefrontSVG, + Student: StudentSVG, + SwapHorizontal: SwapHorizontalSVG, + SwapVertical: SwapVerticalSVG, + TabClose: TabCloseSVG, + TableRow: TableRowSVG, + Tablet: TabletSVG, + Tag: TagSVG, + ThumbDownFilled: ThumbDownFilledSVG, + ThumbDown: ThumbDownSVG, + ThumbUpFilled: ThumbUpFilledSVG, + ThumbUp: ThumbUpSVG, + Tint: TintSVG, + Tooltip: TooltipSVG, + Translate: TranslateSVG, + Trash: TrashSVG, + TrendDown: TrendDownSVG, + TrendUp: TrendUpSVG, + Undo: UndoSVG, + Unfold: UnfoldSVG, + UnlockedFilled: UnlockedFilledSVG, + Unpin: UnpinSVG, + UploadFile: UploadFileSVG, + Upload: UploadSVG, + Usb: UsbSVG, + UserCheck: UserCheckSVG, + UserCircleAdd: UserCircleAddSVG, + UserCircleRemove: UserCircleRemoveSVG, + UserCircle: UserCircleSVG, + User: UserSVG, + VerifiedFilled: VerifiedFilledSVG, + Verified: VerifiedSVG, + Videocam: VideocamSVG, + ViewColumn: ViewColumnSVG, + ViewInAr: ViewInArSVG, + VolumeOff: VolumeOffSVG, + VolumeUp: VolumeUpSVG, + WalletFilled: WalletFilledSVG, + Wallet: WalletSVG, + Warning: WarningSVG, + WebTraffic: WebTrafficSVG, + Widgets: WidgetsSVG, + WifiOff: WifiOffSVG, + Wifi: WifiSVG, + X: XSVG, }; diff --git a/packages/design-system-react-native/src/components/Icon/Icon.constants.ts b/packages/design-system-react-native/src/components/Icon/Icon.constants.ts index 899c98fa8..6157ddd27 100644 --- a/packages/design-system-react-native/src/components/Icon/Icon.constants.ts +++ b/packages/design-system-react-native/src/components/Icon/Icon.constants.ts @@ -1,4 +1,4 @@ -import { IconSize } from '../../types'; +import { IconSize } from '@metamask/design-system-shared'; export const TWCLASSMAP_ICON_SIZE_DIMENSION: Record = { [IconSize.Xs]: 'w-3 h-3', // 12px diff --git a/packages/design-system-react-native/src/components/Icon/Icon.stories.tsx b/packages/design-system-react-native/src/components/Icon/Icon.stories.tsx index 91804f439..df908f0d6 100644 --- a/packages/design-system-react-native/src/components/Icon/Icon.stories.tsx +++ b/packages/design-system-react-native/src/components/Icon/Icon.stories.tsx @@ -3,11 +3,11 @@ import type { Meta, StoryObj } from '@storybook/react-native'; import React from 'react'; import { ScrollView, View } from 'react-native'; -import { IconColor, IconName, IconSize } from '../../types'; - import { Icon } from './Icon'; import type { IconProps } from './Icon.types'; +import { IconColor, IconName, IconSize } from '.'; + const meta: Meta = { title: 'Components/Icon', component: Icon, diff --git a/packages/design-system-react-native/src/components/Icon/Icon.test.tsx b/packages/design-system-react-native/src/components/Icon/Icon.test.tsx index bf08c649b..56dcf53f2 100644 --- a/packages/design-system-react-native/src/components/Icon/Icon.test.tsx +++ b/packages/design-system-react-native/src/components/Icon/Icon.test.tsx @@ -2,11 +2,11 @@ import { useTailwind } from '@metamask/design-system-twrnc-preset'; import { render } from '@testing-library/react-native'; import React from 'react'; -import { IconColor, IconName, IconSize } from '../../types'; - import { Icon } from './Icon'; import { TWCLASSMAP_ICON_SIZE_DIMENSION } from './Icon.constants'; +import { IconColor, IconName, IconSize } from '.'; + describe('Icon', () => { describe('Icon Component', () => { it('renders the specified icon', () => { diff --git a/packages/design-system-react-native/src/components/Icon/Icon.tsx b/packages/design-system-react-native/src/components/Icon/Icon.tsx index e943a701e..66ef4c943 100644 --- a/packages/design-system-react-native/src/components/Icon/Icon.tsx +++ b/packages/design-system-react-native/src/components/Icon/Icon.tsx @@ -1,8 +1,7 @@ +import { IconColor, IconSize } from '@metamask/design-system-shared'; import { useTailwind } from '@metamask/design-system-twrnc-preset'; import React from 'react'; -import { IconColor, IconSize } from '../../types'; - import { assetByIconName } from './Icon.assets'; import { TWCLASSMAP_ICON_SIZE_DIMENSION } from './Icon.constants'; import type { IconProps } from './Icon.types'; diff --git a/packages/design-system-react-native/src/components/Icon/Icon.types.ts b/packages/design-system-react-native/src/components/Icon/Icon.types.ts index f66e083fc..70d0350e9 100644 --- a/packages/design-system-react-native/src/components/Icon/Icon.types.ts +++ b/packages/design-system-react-native/src/components/Icon/Icon.types.ts @@ -1,29 +1,11 @@ +import type { IconName, IconPropsShared } from '@metamask/design-system-shared'; import type React from 'react'; import type { SvgProps } from 'react-native-svg'; -import type { IconColor, IconName, IconSize } from '../../types'; - /** * Icon component props. */ -export type IconProps = { - /** - * Required prop to specify which icon to render from the icon set - */ - name: IconName; - /** - * Optional prop to control the size of the icon - * Different sizes map to specific pixel dimensions - * - * @default IconSize.Md - */ - size?: IconSize; - /** - * Optional prop that sets the color of the icon using predefined theme colors - * - * @default IconColor.IconDefault - */ - color?: IconColor; +export type IconProps = IconPropsShared & { /** * Optional prop to add twrnc overriding classNames. */ diff --git a/packages/design-system-react-native/src/components/Icon/README.md b/packages/design-system-react-native/src/components/Icon/README.md index 7ba3941bc..345617679 100644 --- a/packages/design-system-react-native/src/components/Icon/README.md +++ b/packages/design-system-react-native/src/components/Icon/README.md @@ -2,6 +2,8 @@ Icons are read-only symbols that represent ideas or objects, offered in standard sizes. +> **Note:** The `assets/` folder in this directory is auto-generated. The source of truth for all SVG assets is `packages/design-system-shared/src/assets/icons/`. Run `yarn generate:icons` from the repo root to regenerate. + ```tsx import { Icon } from '@metamask/design-system-react-native'; diff --git a/packages/design-system-react-native/src/components/Icon/index.ts b/packages/design-system-react-native/src/components/Icon/index.ts index 31cab1b35..85b384935 100644 --- a/packages/design-system-react-native/src/components/Icon/index.ts +++ b/packages/design-system-react-native/src/components/Icon/index.ts @@ -1,3 +1,3 @@ -export { IconColor, IconName, IconSize } from '../../types'; +export { IconColor, IconName, IconSize } from '@metamask/design-system-shared'; export { Icon } from './Icon'; export type { IconProps } from './Icon.types'; diff --git a/packages/design-system-react-native/src/types/index.ts b/packages/design-system-react-native/src/types/index.ts index d52bce6cd..5b90f5f35 100644 --- a/packages/design-system-react-native/src/types/index.ts +++ b/packages/design-system-react-native/src/types/index.ts @@ -2,6 +2,7 @@ export { AvatarBaseSize, AvatarBaseShape, } from '@metamask/design-system-shared'; +export { IconColor } from '@metamask/design-system-shared'; export { AvatarBaseSize as AvatarGroupSize } from '@metamask/design-system-shared'; export { AvatarBaseSize as AvatarIconSize } from '@metamask/design-system-shared'; export { AvatarBaseSize as AvatarNetworkSize } from '@metamask/design-system-shared'; @@ -87,359 +88,3 @@ export enum ButtonIconVariant { Filled = 'filled', Floating = 'floating', } - -/** - * Icon - color - */ -export enum IconColor { - /** For default neutral icons */ - IconDefault = 'text-icon-default', - /** For softer neutral icons */ - IconAlternative = 'text-icon-alternative', - /** For the weakest contrast neutral icons (not accessible) */ - IconMuted = 'text-icon-muted', - /** For elements used on top of overlay/alternative. Used for text, icon, or border */ - OverlayInverse = 'text-overlay-inverse', - /** For interactive, active, and selected semantics. Used for text, background, icon, or border */ - PrimaryDefault = 'text-primary-default', - /** For softer variants of primary interactive elements */ - PrimaryAlternative = 'text-primary-alternative', - /** For elements used on top of primary/default. Used for text, icon, or border */ - PrimaryInverse = 'text-primary-inverse', - /** For primary interactive elements in a pressed state */ - PrimaryDefaultPressed = 'text-primary-default-pressed', - /** For critical alert semantic elements. Used for text, background, icon, or border */ - ErrorDefault = 'text-error-default', - /** For softer variants of error elements */ - ErrorAlternative = 'text-error-alternative', - /** For elements used on top of error/default. Used for text, icon, or border */ - ErrorInverse = 'text-error-inverse', - /** For critical alert semantic elements in a pressed state */ - ErrorDefaultPressed = 'text-error-default-pressed', - /** For caution alert semantic elements. Used for text, background, icon, or border */ - WarningDefault = 'text-warning-default', - /** For elements used on top of warning/default. Used for text, icon, or border */ - WarningInverse = 'text-warning-inverse', - /** For caution alert semantic elements in a pressed state */ - WarningDefaultPressed = 'text-warning-default-pressed', - /** For positive semantic elements. Used for text, background, icon, or border */ - SuccessDefault = 'text-success-default', - /** For elements used on top of success/default. Used for text, icon, or border */ - SuccessInverse = 'text-success-inverse', - /** For positive semantic elements in a pressed state */ - SuccessDefaultPressed = 'text-success-default-pressed', - /** For informational read-only elements. Used for text, background, icon, or border */ - InfoDefault = 'text-info-default', - /** For elements used on top of info/default. Used for text, icon, or border */ - InfoInverse = 'text-info-inverse', -} - -/** - * Icon - size - */ -export enum IconSize { - /** Extra small - 12px */ - Xs = 'xs', - /** Small - 16px */ - Sm = 'sm', - /** Medium - 20px (Default) */ - Md = 'md', - /** Large - 24px */ - Lg = 'lg', - /** Extra large - 32px */ - Xl = 'xl', -} - -// ///////////////////////////////////////////////////// -// This is generated code - Manually add types above -// DO NOT EDIT - Use generate-assets.js -// ///////////////////////////////////////////////////// - -/** - * Icon - name - */ -/* eslint-disable @typescript-eslint/no-shadow */ -export enum IconName { - Accessibility = 'Accessibility', - Activity = 'Activity', - AddCard = 'AddCard', - AddCircle = 'AddCircle', - AddSquare = 'AddSquare', - Add = 'Add', - AfterHours = 'AfterHours', - Ai = 'Ai', - AlternateEmail = 'AlternateEmail', - AppleLogo = 'AppleLogo', - Apps = 'Apps', - Arrow2Down = 'Arrow2Down', - Arrow2Left = 'Arrow2Left', - Arrow2Right = 'Arrow2Right', - Arrow2UpRight = 'Arrow2UpRight', - Arrow2Up = 'Arrow2Up', - ArrowCircleDown = 'ArrowCircleDown', - ArrowCircleUp = 'ArrowCircleUp', - ArrowDoubleLeft = 'ArrowDoubleLeft', - ArrowDoubleRight = 'ArrowDoubleRight', - ArrowDown = 'ArrowDown', - ArrowDropDownCircle = 'ArrowDropDownCircle', - ArrowLeft = 'ArrowLeft', - ArrowRight = 'ArrowRight', - ArrowUp = 'ArrowUp', - AttachMoney = 'AttachMoney', - Attachment = 'Attachment', - Backspace = 'Backspace', - Ban = 'Ban', - BankAssured = 'BankAssured', - Bank = 'Bank', - Bold = 'Bold', - Book = 'Book', - Bookmark = 'Bookmark', - Bridge = 'Bridge', - Briefcase = 'Briefcase', - Bulb = 'Bulb', - BuySell = 'BuySell', - Cake = 'Cake', - Calculator = 'Calculator', - Calendar = 'Calendar', - Call = 'Call', - Camera = 'Camera', - Campaign = 'Campaign', - Candlestick = 'Candlestick', - CardPos = 'CardPos', - Card = 'Card', - Cash = 'Cash', - Category = 'Category', - Chart = 'Chart', - CheckBold = 'CheckBold', - Check = 'Check', - CircleX = 'CircleX', - Clear = 'Clear', - ClockFilled = 'ClockFilled', - Clock = 'Clock', - Close = 'Close', - CloudDownload = 'CloudDownload', - CloudUpload = 'CloudUpload', - Cloud = 'Cloud', - CodeCircle = 'CodeCircle', - Code = 'Code', - Coin = 'Coin', - Collapse = 'Collapse', - Confirmation = 'Confirmation', - Connect = 'Connect', - CopySuccess = 'CopySuccess', - Copy = 'Copy', - CorporateFare = 'CorporateFare', - CreditCheck = 'CreditCheck', - CurrencyFranc = 'CurrencyFranc', - CurrencyLira = 'CurrencyLira', - CurrencyPound = 'CurrencyPound', - CurrencyYuan = 'CurrencyYuan', - Customize = 'Customize', - Danger = 'Danger', - DarkFilled = 'DarkFilled', - Dark = 'Dark', - Data = 'Data', - Description = 'Description', - Details = 'Details', - Diagram = 'Diagram', - DocumentCode = 'DocumentCode', - Download = 'Download', - Draft = 'Draft', - EcoLeaf = 'EcoLeaf', - EditSquare = 'EditSquare', - Edit = 'Edit', - EncryptedAdd = 'EncryptedAdd', - Eraser = 'Eraser', - Error = 'Error', - Ethereum = 'Ethereum', - Exchange = 'Exchange', - ExpandVertical = 'ExpandVertical', - Expand = 'Expand', - ExploreFilled = 'ExploreFilled', - Explore = 'Explore', - Export = 'Export', - Extension = 'Extension', - EyeSlash = 'EyeSlash', - Eye = 'Eye', - FaceId = 'FaceId', - Feedback = 'Feedback', - File = 'File', - Filter = 'Filter', - Fingerprint = 'Fingerprint', - Fire = 'Fire', - FirstPage = 'FirstPage', - Flag = 'Flag', - FlashSlash = 'FlashSlash', - Flash = 'Flash', - Flask = 'Flask', - Flower = 'Flower', - Folder = 'Folder', - Forest = 'Forest', - FullCircle = 'FullCircle', - Gas = 'Gas', - Gift = 'Gift', - GlobalSearch = 'GlobalSearch', - Global = 'Global', - Graph = 'Graph', - Hardware = 'Hardware', - HashTag = 'HashTag', - HeartFilled = 'HeartFilled', - Heart = 'Heart', - Hierarchy = 'Hierarchy', - HomeFilled = 'HomeFilled', - Home = 'Home', - Image = 'Image', - Info = 'Info', - Inventory = 'Inventory', - Joystick = 'Joystick', - KeepFilled = 'KeepFilled', - Keep = 'Keep', - Key = 'Key', - LastPage = 'LastPage', - LightFilled = 'LightFilled', - Light = 'Light', - Link = 'Link', - Loading = 'Loading', - Location = 'Location', - LockSlash = 'LockSlash', - Lock = 'Lock', - LockedFilled = 'LockedFilled', - Login = 'Login', - Logout = 'Logout', - Mail = 'Mail', - Map = 'Map', - Menu = 'Menu', - MessageQuestion = 'MessageQuestion', - Messages = 'Messages', - MetamaskFoxOutline = 'MetamaskFoxOutline', - Mic = 'Mic', - MinusBold = 'MinusBold', - MinusSquare = 'MinusSquare', - Minus = 'Minus', - Mobile = 'Mobile', - MoneyBag = 'MoneyBag', - Money = 'Money', - Monitor = 'Monitor', - MoreHorizontal = 'MoreHorizontal', - MoreVertical = 'MoreVertical', - MountainFlag = 'MountainFlag', - MusicNote = 'MusicNote', - NoPhotography = 'NoPhotography', - Notification = 'Notification', - PageInfo = 'PageInfo', - Palette = 'Palette', - PasswordCheck = 'PasswordCheck', - Pending = 'Pending', - People = 'People', - PersonCancel = 'PersonCancel', - Pin = 'Pin', - Plant = 'Plant', - Plug = 'Plug', - PlusAndMinus = 'PlusAndMinus', - PolicyAlert = 'PolicyAlert', - PopUp = 'PopUp', - Print = 'Print', - PriorityHigh = 'PriorityHigh', - PrivacyTip = 'PrivacyTip', - ProgrammingArrows = 'ProgrammingArrows', - Publish = 'Publish', - QrCode = 'QrCode', - Question = 'Question', - Receive = 'Receive', - Received = 'Received', - Refresh = 'Refresh', - RemoveMinus = 'RemoveMinus', - Report = 'Report', - Rocket = 'Rocket', - SaveFilled = 'SaveFilled', - Save = 'Save', - Saving = 'Saving', - ScanBarcode = 'ScanBarcode', - ScanFocus = 'ScanFocus', - Scan = 'Scan', - Search = 'Search', - SecurityAlert = 'SecurityAlert', - SecurityCross = 'SecurityCross', - SecurityKey = 'SecurityKey', - SecuritySearch = 'SecuritySearch', - SecuritySlash = 'SecuritySlash', - SecurityTick = 'SecurityTick', - SecurityTime = 'SecurityTime', - SecurityUser = 'SecurityUser', - Security = 'Security', - Send = 'Send', - SentimentDissatisfied = 'SentimentDissatisfied', - SentimentNeutral = 'SentimentNeutral', - SentimentSatisfied = 'SentimentSatisfied', - SentimentVerySatisfied = 'SentimentVerySatisfied', - SettingFilled = 'SettingFilled', - Setting = 'Setting', - Share = 'Share', - ShieldLock = 'ShieldLock', - ShoppingBag = 'ShoppingBag', - ShoppingCart = 'ShoppingCart', - SidePanel = 'SidePanel', - SignalCellular = 'SignalCellular', - Slash = 'Slash', - Sms = 'Sms', - SnapsMobile = 'SnapsMobile', - SnapsPlus = 'SnapsPlus', - SnapsRound = 'SnapsRound', - Snaps = 'Snaps', - SortByAlpha = 'SortByAlpha', - Sort = 'Sort', - Sparkle = 'Sparkle', - Speed = 'Speed', - Speedometer = 'Speedometer', - Square = 'Square', - Stake = 'Stake', - StarFilled = 'StarFilled', - Star = 'Star', - Start = 'Start', - Storefront = 'Storefront', - Student = 'Student', - SwapHorizontal = 'SwapHorizontal', - SwapVertical = 'SwapVertical', - TabClose = 'TabClose', - TableRow = 'TableRow', - Tablet = 'Tablet', - Tag = 'Tag', - ThumbDownFilled = 'ThumbDownFilled', - ThumbDown = 'ThumbDown', - ThumbUpFilled = 'ThumbUpFilled', - ThumbUp = 'ThumbUp', - Tint = 'Tint', - Tooltip = 'Tooltip', - Translate = 'Translate', - Trash = 'Trash', - TrendDown = 'TrendDown', - TrendUp = 'TrendUp', - Undo = 'Undo', - Unfold = 'Unfold', - UnlockedFilled = 'UnlockedFilled', - Unpin = 'Unpin', - UploadFile = 'UploadFile', - Upload = 'Upload', - Usb = 'Usb', - UserCheck = 'UserCheck', - UserCircleAdd = 'UserCircleAdd', - UserCircleRemove = 'UserCircleRemove', - UserCircle = 'UserCircle', - User = 'User', - VerifiedFilled = 'VerifiedFilled', - Verified = 'Verified', - Videocam = 'Videocam', - ViewColumn = 'ViewColumn', - ViewInAr = 'ViewInAr', - VolumeOff = 'VolumeOff', - VolumeUp = 'VolumeUp', - WalletFilled = 'WalletFilled', - Wallet = 'Wallet', - Warning = 'Warning', - WebTraffic = 'WebTraffic', - Widgets = 'Widgets', - WifiOff = 'WifiOff', - Wifi = 'Wifi', - X = 'X', -} -/* eslint-enable @typescript-eslint/no-shadow */ diff --git a/packages/design-system-react/package.json b/packages/design-system-react/package.json index 0c32dc869..ddbe998fd 100644 --- a/packages/design-system-react/package.json +++ b/packages/design-system-react/package.json @@ -35,13 +35,10 @@ "dist/" ], "scripts": { - "build": "yarn generate-icons && ts-bridge --project tsconfig.build.json --verbose --clean --no-references", + "build": "ts-bridge --project tsconfig.build.json --verbose --clean --no-references", "changelog:update": "../../scripts/update-changelog.sh @metamask/design-system-react", "changelog:validate": "../../scripts/validate-changelog.sh @metamask/design-system-react", - "clean:icons": "rimraf src/components/Icon/icons", "create-component": "tsx scripts/create-component", - "generate-icons": "yarn clean:icons && svgr --config-file src/components/Icon/.svgrrc.js -d src/components/Icon/icons ../design-system-shared/src/assets/icons/*.svg && yarn generate-icons:index", - "generate-icons:index": "tsx scripts/generate-icons-index.ts", "publish:preview": "yarn npm publish --tag preview", "since-latest-release": "../../scripts/since-latest-release.sh", "test": "NODE_OPTIONS=--experimental-vm-modules jest --reporters=jest-silent-reporter", diff --git a/packages/design-system-react/scripts/create-component/create-component.ts b/packages/design-system-react/scripts/create-component/create-component.ts index 8c7a24182..499e4b18d 100644 --- a/packages/design-system-react/scripts/create-component/create-component.ts +++ b/packages/design-system-react/scripts/create-component/create-component.ts @@ -1,7 +1,5 @@ -/* eslint-disable import-x/no-nodejs-modules */ import { promises as fs } from 'fs'; import * as path from 'path'; -/* eslint-enable import-x/no-nodejs-modules */ type CreateComponentArgs = { name: string; diff --git a/packages/design-system-react/scripts/generate-icons-index.test.ts b/packages/design-system-react/scripts/generate-icons-index.test.ts deleted file mode 100644 index 83cb20169..000000000 --- a/packages/design-system-react/scripts/generate-icons-index.test.ts +++ /dev/null @@ -1,147 +0,0 @@ -// eslint-disable-next-line @typescript-eslint/no-shadow -import { jest } from '@jest/globals'; -import type { Dirent } from 'fs'; -import * as fs from 'fs/promises'; - -import { generateIconsIndex } from './generate-icons-index'; - -// Mock fs/promises -jest.mock('fs/promises'); -const mockedFs = jest.mocked(fs); - -describe('generateIconsIndex', () => { - // Add interface for better type handling - type MockFiles = { - 'types-index.ts': string; - 'icons-index.ts': string; - }; - - const mockFiles: MockFiles = { - 'types-index.ts': ` - // Other content - export enum IconName { - OldIcon = 'OldIcon', - } - // More content - `, - 'icons-index.ts': '', - }; - - beforeEach(() => { - jest.clearAllMocks(); - - // Improve mock setup with type safety - mockedFs.readdir.mockResolvedValue([ - 'Icon1.tsx', - 'Icon2.tsx', - 'Icon3.tsx', - ] as unknown as Dirent[]); - - // Use mockFiles object for consistent file content - // @ts-expect-error - Mocking the function with a string parameter - mockedFs.readFile.mockImplementation(async (filePath: string) => { - if (filePath.includes('/src/types/index.ts')) { - return mockFiles['types-index.ts']; - } - throw new Error(`Unexpected file read: ${filePath}`); - }); - - mockedFs.writeFile.mockImplementation( - // @ts-expect-error - Mocking the function with a string parameter - async (path: string, content: string) => { - const filePath = path.toString(); - if (filePath.includes('/src/types/index.ts')) { - mockFiles['types-index.ts'] = content; - } else if (filePath.includes('/src/components/Icon/icons/index.ts')) { - mockFiles['icons-index.ts'] = content; - } - return undefined; - }, - ); - }); - - it('should generate index.ts with correct content', async () => { - await generateIconsIndex(); - - const expectedIndexContent = `// This file is auto-generated. Do not edit manually -import type { ForwardRefExoticComponent, RefAttributes, SVGProps } from 'react'; - -import Icon1 from './Icon1'; -import Icon2 from './Icon2'; -import Icon3 from './Icon3'; - -export const Icons = { - Icon1, - Icon2, - Icon3, -} as const; - -export type IconComponentType = ForwardRefExoticComponent< - SVGProps & RefAttributes ->; - -export type IconsType = typeof Icons; -`; - - expect(mockedFs.writeFile).toHaveBeenCalledWith( - expect.stringContaining('/src/components/Icon/icons/index.ts'), - expectedIndexContent, - ); - }); - - it('should update Icon.types.ts with new enum values', async () => { - await generateIconsIndex(); - - const expectedEnumContent = `export enum IconName { - Icon1 = 'Icon1', - Icon2 = 'Icon2', - Icon3 = 'Icon3', -}`; - - expect(mockedFs.writeFile).toHaveBeenCalledWith( - expect.stringContaining('/src/types/index.ts'), - expect.stringContaining(expectedEnumContent), - ); - }); - - it('should filter out non-tsx files', async () => { - mockedFs.readdir.mockResolvedValue([ - 'Icon1.tsx', - 'README.md', - 'Icon2.tsx', - '.DS_Store', - ] as unknown as Dirent[]); - - await generateIconsIndex(); - - const writeFileCalls = mockedFs.writeFile.mock.calls; - const iconsIndexFileCall = writeFileCalls.find((call) => - // eslint-disable-next-line @typescript-eslint/no-base-to-string - call[0].toString().includes('/src/components/Icon/icons/index.ts'), - ); - const iconsIndexFileContent = iconsIndexFileCall?.[1] as string; - - expect(iconsIndexFileContent).toContain('import Icon1'); - expect(iconsIndexFileContent).toContain('import Icon2'); - expect(iconsIndexFileContent).not.toContain('README'); - expect(iconsIndexFileContent).not.toContain('.DS_Store'); - }); - - it('should throw error when file operations fail', async () => { - mockedFs.readdir.mockRejectedValue(new Error('Failed to read directory')); - - await expect(generateIconsIndex()).rejects.toThrow( - /Failed to (generate icons index|read directory)/u, - ); - }); - - it('should throw error when directory is empty', async () => { - mockedFs.readdir.mockResolvedValue([] as unknown as Dirent[]); - - await expect(generateIconsIndex()).rejects.toThrow( - 'Failed to generate icons index: No icon files found in icons directory', - ); - - expect(mockedFs.writeFile).not.toHaveBeenCalled(); - }); -}); diff --git a/packages/design-system-react/scripts/generate-icons-index.ts b/packages/design-system-react/scripts/generate-icons-index.ts deleted file mode 100644 index e02800bdf..000000000 --- a/packages/design-system-react/scripts/generate-icons-index.ts +++ /dev/null @@ -1,88 +0,0 @@ -/* eslint-disable import-x/no-nodejs-modules */ -import * as fs from 'fs/promises'; -import * as path from 'path'; -/* eslint-enable import-x/no-nodejs-modules */ - -/** Path to the directory containing icon components */ -const ICONS_DIR = path.join(__dirname, '../src/components/Icon/icons'); -/** Path to the Icon types definition file */ -const TYPES_FILE = path.join(__dirname, '../src/types/index.ts'); - -/** - * Generates the index file for icon components and updates the IconName enum. - * - * This script: - * 1. Creates an index.ts file that exports all icon components - * 2. Updates the IconName enum in Icon.types.ts to match available icons - * - * The generated files are used to: - * - Provide a central export point for all icon components - * - Maintain type safety when using icons throughout the application - * - * @throws {Error} If file operations fail or icon generation encounters an error - * @returns Promise that resolves when the files are generated - */ -export const generateIconsIndex = async (): Promise => { - try { - // First check if directory exists - try { - await fs.access(ICONS_DIR); - } catch { - throw new Error(`Icons directory not found: ${ICONS_DIR}`); - } - - const files = (await fs.readdir(ICONS_DIR)) - .filter((file: string) => file.endsWith('.tsx')) - .map((file: string) => file.replace('.tsx', '')); - - // Throw error if no icon files are found - if (files.length === 0) { - throw new Error('No icon files found in icons directory'); - } - - // Generate index content with proper import ordering and newlines - const indexContent = `// This file is auto-generated. Do not edit manually -import type { ForwardRefExoticComponent, RefAttributes, SVGProps } from 'react'; - -${files.map((name) => `import ${name} from './${name}';`).join('\n')} - -export const Icons = { -${files.map((name) => ` ${name},`).join('\n')} -} as const; - -export type IconComponentType = ForwardRefExoticComponent< - SVGProps & RefAttributes ->; - -export type IconsType = typeof Icons; -`; - - await fs.writeFile(path.join(ICONS_DIR, 'index.ts'), indexContent); - - // Update IconName enum with trailing commas - const enumContent = files - .map((name: string) => ` ${name} = '${name}',`) - .join('\n'); - - const typesContent = await fs.readFile(TYPES_FILE, 'utf8'); - const updatedTypesContent = typesContent.replace( - /(\/\*\*?\s*eslint-disable @typescript-eslint\/no-shadow \*\/\n)?export enum IconName \{[\s\S]*?\}(\n\/\* eslint-enable @typescript-eslint\/no-shadow \*\/)?/u, - `/* eslint-disable @typescript-eslint/no-shadow */\nexport enum IconName {\n${enumContent}\n}\n/* eslint-enable @typescript-eslint/no-shadow */`, - ); - - await fs.writeFile(TYPES_FILE, updatedTypesContent); - } catch (error) { - // Improve error handling with more context - const errorMessage = - error instanceof Error ? error.message : 'Unknown error'; - throw new Error(`Failed to generate icons index: ${errorMessage}`); - } -}; - -// Improve the error handling in the execution -if (require.main === module) { - generateIconsIndex().catch((error) => { - console.error('Error details:', error); - throw error; - }); -} diff --git a/packages/design-system-react/src/components/Icon/.svgrrc.js b/packages/design-system-react/src/components/Icon/.svgrrc.js deleted file mode 100644 index d1964a40a..000000000 --- a/packages/design-system-react/src/components/Icon/.svgrrc.js +++ /dev/null @@ -1,29 +0,0 @@ -module.exports = { - typescript: true, - dimensions: false, - ref: true, - svgProps: { - fill: 'currentColor', - }, - // eslint-disable-next-line n/global-require - template: require('./template').default, - prettier: false, - svgoConfig: { - plugins: [ - { - name: 'preset-default', - params: { - overrides: { - removeViewBox: false, - }, - }, - }, - { - name: 'addAttributesToSVGElement', - params: { - attributes: [{ fill: 'currentColor' }], - }, - }, - ], - }, -}; diff --git a/packages/design-system-react/src/components/Icon/Icon.constants.ts b/packages/design-system-react/src/components/Icon/Icon.constants.ts index 899c98fa8..6157ddd27 100644 --- a/packages/design-system-react/src/components/Icon/Icon.constants.ts +++ b/packages/design-system-react/src/components/Icon/Icon.constants.ts @@ -1,4 +1,4 @@ -import { IconSize } from '../../types'; +import { IconSize } from '@metamask/design-system-shared'; export const TWCLASSMAP_ICON_SIZE_DIMENSION: Record = { [IconSize.Xs]: 'w-3 h-3', // 12px diff --git a/packages/design-system-react/src/components/Icon/Icon.stories.tsx b/packages/design-system-react/src/components/Icon/Icon.stories.tsx index a83735150..d335b5e10 100644 --- a/packages/design-system-react/src/components/Icon/Icon.stories.tsx +++ b/packages/design-system-react/src/components/Icon/Icon.stories.tsx @@ -2,12 +2,13 @@ import { TextVariant } from '@metamask/design-system-shared'; import type { StoryObj } from '@storybook/react-vite'; import React, { useState } from 'react'; -import { IconName, IconSize, IconColor } from '../../types'; import { Text } from '../Text/Text'; import { Icon } from './Icon'; import README from './README.mdx'; +import { IconName, IconSize, IconColor } from '.'; + const meta = { title: 'React Components/Icon', component: Icon, diff --git a/packages/design-system-react/src/components/Icon/Icon.test.tsx b/packages/design-system-react/src/components/Icon/Icon.test.tsx index 70aca7cec..6b7897f8a 100644 --- a/packages/design-system-react/src/components/Icon/Icon.test.tsx +++ b/packages/design-system-react/src/components/Icon/Icon.test.tsx @@ -1,12 +1,12 @@ import { render, screen } from '@testing-library/react'; import React from 'react'; -import { IconName, IconSize, IconColor } from '../../types'; - import { Icon } from './Icon'; import { TWCLASSMAP_ICON_SIZE_DIMENSION } from './Icon.constants'; import type { IconProps } from './Icon.types'; +import { IconName, IconSize, IconColor } from '.'; + describe('Icon', () => { it('should render correctly', () => { render(); diff --git a/packages/design-system-react/src/components/Icon/Icon.tsx b/packages/design-system-react/src/components/Icon/Icon.tsx index a0b15b125..d4845f0d2 100644 --- a/packages/design-system-react/src/components/Icon/Icon.tsx +++ b/packages/design-system-react/src/components/Icon/Icon.tsx @@ -1,6 +1,6 @@ +import { IconSize, IconColor } from '@metamask/design-system-shared'; import React from 'react'; -import { IconSize, IconColor } from '../../types'; import { twMerge } from '../../utils/tw-merge'; import { TWCLASSMAP_ICON_SIZE_DIMENSION } from './Icon.constants'; diff --git a/packages/design-system-react/src/components/Icon/Icon.types.ts b/packages/design-system-react/src/components/Icon/Icon.types.ts index ade91f75b..aebfb4729 100644 --- a/packages/design-system-react/src/components/Icon/Icon.types.ts +++ b/packages/design-system-react/src/components/Icon/Icon.types.ts @@ -1,40 +1,23 @@ +import type { IconPropsShared } from '@metamask/design-system-shared'; import type { SVGProps, ComponentPropsWithoutRef } from 'react'; -import type { IconName, IconSize, IconColor } from '../../types'; - // Use ComponentPropsWithoutRef to get SVG element props without relying on global SVGElement type SVGElementProps = ComponentPropsWithoutRef<'svg'>; -export type IconProps = SVGProps & { - /** - * Required prop to specify which icon to render from the icon set - */ - name: IconName; - /** - * Optional prop to control the size of the icon - * Different sizes map to specific pixel dimensions - * - * @default IconSize.Md - */ - size?: IconSize; - /** - * Optional prop that sets the color of the icon using predefined theme colors - * - * @default IconColor.IconDefault - */ - color?: IconColor; - /** - * Additional CSS classes to be added to the component. - * These classes will be merged with the component's default classes using twMerge. - */ - className?: string; - /** - * Optional CSS styles to be applied to the component. - * Should be used sparingly and only for dynamic styles that can't be achieved with className. - */ - style?: React.CSSProperties; - /** - * Optional prop to add a test id to the icon - */ - 'data-testid'?: string; -}; +export type IconProps = SVGProps & + IconPropsShared & { + /** + * Additional CSS classes to be added to the component. + * These classes will be merged with the component's default classes using twMerge. + */ + className?: string; + /** + * Optional CSS styles to be applied to the component. + * Should be used sparingly and only for dynamic styles that can't be achieved with className. + */ + style?: React.CSSProperties; + /** + * Optional prop to add a test id to the icon + */ + 'data-testid'?: string; + }; diff --git a/packages/design-system-react/src/components/Icon/README.mdx b/packages/design-system-react/src/components/Icon/README.mdx index 63c2415e0..386ddaa0f 100644 --- a/packages/design-system-react/src/components/Icon/README.mdx +++ b/packages/design-system-react/src/components/Icon/README.mdx @@ -5,6 +5,8 @@ import * as IconStories from './Icon.stories'; Icons are read-only symbols that represent ideas or objects, offered in standard sizes. +> **Note:** The `icons/` folder in this directory is auto-generated. The source of truth for all SVG assets is `packages/design-system-shared/src/assets/icons/`. Run `yarn generate:icons` from the repo root to regenerate. + ```tsx import { Icon, IconName } from '@metamask/design-system-react'; diff --git a/packages/design-system-react/src/components/Icon/icons/index.ts b/packages/design-system-react/src/components/Icon/icons/index.ts index 274318fc9..f8eb4c7b4 100644 --- a/packages/design-system-react/src/components/Icon/icons/index.ts +++ b/packages/design-system-react/src/components/Icon/icons/index.ts @@ -1,12 +1,13 @@ -// This file is auto-generated. Do not edit manually +// This file is auto-generated — do not edit manually +// Run `yarn generate:icons` from the repo root to regenerate import type { ForwardRefExoticComponent, RefAttributes, SVGProps } from 'react'; import Accessibility from './Accessibility'; import Activity from './Activity'; -import Add from './Add'; import AddCard from './AddCard'; import AddCircle from './AddCircle'; import AddSquare from './AddSquare'; +import Add from './Add'; import AfterHours from './AfterHours'; import Ai from './Ai'; import AlternateEmail from './AlternateEmail'; @@ -15,8 +16,8 @@ import Apps from './Apps'; import Arrow2Down from './Arrow2Down'; import Arrow2Left from './Arrow2Left'; import Arrow2Right from './Arrow2Right'; -import Arrow2Up from './Arrow2Up'; import Arrow2UpRight from './Arrow2UpRight'; +import Arrow2Up from './Arrow2Up'; import ArrowCircleDown from './ArrowCircleDown'; import ArrowCircleUp from './ArrowCircleUp'; import ArrowDoubleLeft from './ArrowDoubleLeft'; @@ -30,8 +31,8 @@ import AttachMoney from './AttachMoney'; import Attachment from './Attachment'; import Backspace from './Backspace'; import Ban from './Ban'; -import Bank from './Bank'; import BankAssured from './BankAssured'; +import Bank from './Bank'; import Bold from './Bold'; import Book from './Book'; import Bookmark from './Bookmark'; @@ -46,29 +47,29 @@ import Call from './Call'; import Camera from './Camera'; import Campaign from './Campaign'; import Candlestick from './Candlestick'; -import Card from './Card'; import CardPos from './CardPos'; +import Card from './Card'; import Cash from './Cash'; import Category from './Category'; import Chart from './Chart'; -import Check from './Check'; import CheckBold from './CheckBold'; +import Check from './Check'; import CircleX from './CircleX'; import Clear from './Clear'; -import Clock from './Clock'; import ClockFilled from './ClockFilled'; +import Clock from './Clock'; import Close from './Close'; -import Cloud from './Cloud'; import CloudDownload from './CloudDownload'; import CloudUpload from './CloudUpload'; -import Code from './Code'; +import Cloud from './Cloud'; import CodeCircle from './CodeCircle'; +import Code from './Code'; import Coin from './Coin'; import Collapse from './Collapse'; import Confirmation from './Confirmation'; import Connect from './Connect'; -import Copy from './Copy'; import CopySuccess from './CopySuccess'; +import Copy from './Copy'; import CorporateFare from './CorporateFare'; import CreditCheck from './CreditCheck'; import CurrencyFranc from './CurrencyFranc'; @@ -77,8 +78,8 @@ import CurrencyPound from './CurrencyPound'; import CurrencyYuan from './CurrencyYuan'; import Customize from './Customize'; import Danger from './Danger'; -import Dark from './Dark'; import DarkFilled from './DarkFilled'; +import Dark from './Dark'; import Data from './Data'; import Description from './Description'; import Details from './Details'; @@ -87,21 +88,21 @@ import DocumentCode from './DocumentCode'; import Download from './Download'; import Draft from './Draft'; import EcoLeaf from './EcoLeaf'; -import Edit from './Edit'; import EditSquare from './EditSquare'; +import Edit from './Edit'; import EncryptedAdd from './EncryptedAdd'; import Eraser from './Eraser'; import Error from './Error'; import Ethereum from './Ethereum'; import Exchange from './Exchange'; -import Expand from './Expand'; import ExpandVertical from './ExpandVertical'; -import Explore from './Explore'; +import Expand from './Expand'; import ExploreFilled from './ExploreFilled'; +import Explore from './Explore'; import Export from './Export'; import Extension from './Extension'; -import Eye from './Eye'; import EyeSlash from './EyeSlash'; +import Eye from './Eye'; import FaceId from './FaceId'; import Feedback from './Feedback'; import File from './File'; @@ -110,8 +111,8 @@ import Fingerprint from './Fingerprint'; import Fire from './Fire'; import FirstPage from './FirstPage'; import Flag from './Flag'; -import Flash from './Flash'; import FlashSlash from './FlashSlash'; +import Flash from './Flash'; import Flask from './Flask'; import Flower from './Flower'; import Folder from './Folder'; @@ -119,31 +120,31 @@ import Forest from './Forest'; import FullCircle from './FullCircle'; import Gas from './Gas'; import Gift from './Gift'; -import Global from './Global'; import GlobalSearch from './GlobalSearch'; +import Global from './Global'; import Graph from './Graph'; import Hardware from './Hardware'; import HashTag from './HashTag'; -import Heart from './Heart'; import HeartFilled from './HeartFilled'; +import Heart from './Heart'; import Hierarchy from './Hierarchy'; -import Home from './Home'; import HomeFilled from './HomeFilled'; +import Home from './Home'; import Image from './Image'; import Info from './Info'; import Inventory from './Inventory'; import Joystick from './Joystick'; -import Keep from './Keep'; import KeepFilled from './KeepFilled'; +import Keep from './Keep'; import Key from './Key'; import LastPage from './LastPage'; -import Light from './Light'; import LightFilled from './LightFilled'; +import Light from './Light'; import Link from './Link'; import Loading from './Loading'; import Location from './Location'; -import Lock from './Lock'; import LockSlash from './LockSlash'; +import Lock from './Lock'; import LockedFilled from './LockedFilled'; import Login from './Login'; import Logout from './Logout'; @@ -154,12 +155,12 @@ import MessageQuestion from './MessageQuestion'; import Messages from './Messages'; import MetamaskFoxOutline from './MetamaskFoxOutline'; import Mic from './Mic'; -import Minus from './Minus'; import MinusBold from './MinusBold'; import MinusSquare from './MinusSquare'; +import Minus from './Minus'; import Mobile from './Mobile'; -import Money from './Money'; import MoneyBag from './MoneyBag'; +import Money from './Money'; import Monitor from './Monitor'; import MoreHorizontal from './MoreHorizontal'; import MoreVertical from './MoreVertical'; @@ -192,14 +193,13 @@ import Refresh from './Refresh'; import RemoveMinus from './RemoveMinus'; import Report from './Report'; import Rocket from './Rocket'; -import Save from './Save'; import SaveFilled from './SaveFilled'; +import Save from './Save'; import Saving from './Saving'; -import Scan from './Scan'; import ScanBarcode from './ScanBarcode'; import ScanFocus from './ScanFocus'; +import Scan from './Scan'; import Search from './Search'; -import Security from './Security'; import SecurityAlert from './SecurityAlert'; import SecurityCross from './SecurityCross'; import SecurityKey from './SecurityKey'; @@ -208,13 +208,14 @@ import SecuritySlash from './SecuritySlash'; import SecurityTick from './SecurityTick'; import SecurityTime from './SecurityTime'; import SecurityUser from './SecurityUser'; +import Security from './Security'; import Send from './Send'; import SentimentDissatisfied from './SentimentDissatisfied'; import SentimentNeutral from './SentimentNeutral'; import SentimentSatisfied from './SentimentSatisfied'; import SentimentVerySatisfied from './SentimentVerySatisfied'; -import Setting from './Setting'; import SettingFilled from './SettingFilled'; +import Setting from './Setting'; import Share from './Share'; import ShieldLock from './ShieldLock'; import ShoppingBag from './ShoppingBag'; @@ -223,19 +224,19 @@ import SidePanel from './SidePanel'; import SignalCellular from './SignalCellular'; import Slash from './Slash'; import Sms from './Sms'; -import Snaps from './Snaps'; import SnapsMobile from './SnapsMobile'; import SnapsPlus from './SnapsPlus'; import SnapsRound from './SnapsRound'; -import Sort from './Sort'; +import Snaps from './Snaps'; import SortByAlpha from './SortByAlpha'; +import Sort from './Sort'; import Sparkle from './Sparkle'; import Speed from './Speed'; import Speedometer from './Speedometer'; import Square from './Square'; import Stake from './Stake'; -import Star from './Star'; import StarFilled from './StarFilled'; +import Star from './Star'; import Start from './Start'; import Storefront from './Storefront'; import Student from './Student'; @@ -245,10 +246,10 @@ import TabClose from './TabClose'; import TableRow from './TableRow'; import Tablet from './Tablet'; import Tag from './Tag'; -import ThumbDown from './ThumbDown'; import ThumbDownFilled from './ThumbDownFilled'; -import ThumbUp from './ThumbUp'; +import ThumbDown from './ThumbDown'; import ThumbUpFilled from './ThumbUpFilled'; +import ThumbUp from './ThumbUp'; import Tint from './Tint'; import Tooltip from './Tooltip'; import Translate from './Translate'; @@ -259,37 +260,37 @@ import Undo from './Undo'; import Unfold from './Unfold'; import UnlockedFilled from './UnlockedFilled'; import Unpin from './Unpin'; -import Upload from './Upload'; import UploadFile from './UploadFile'; +import Upload from './Upload'; import Usb from './Usb'; -import User from './User'; import UserCheck from './UserCheck'; -import UserCircle from './UserCircle'; import UserCircleAdd from './UserCircleAdd'; import UserCircleRemove from './UserCircleRemove'; -import Verified from './Verified'; +import UserCircle from './UserCircle'; +import User from './User'; import VerifiedFilled from './VerifiedFilled'; +import Verified from './Verified'; import Videocam from './Videocam'; import ViewColumn from './ViewColumn'; import ViewInAr from './ViewInAr'; import VolumeOff from './VolumeOff'; import VolumeUp from './VolumeUp'; -import Wallet from './Wallet'; import WalletFilled from './WalletFilled'; +import Wallet from './Wallet'; import Warning from './Warning'; import WebTraffic from './WebTraffic'; import Widgets from './Widgets'; -import Wifi from './Wifi'; import WifiOff from './WifiOff'; +import Wifi from './Wifi'; import X from './X'; export const Icons = { Accessibility, Activity, - Add, AddCard, AddCircle, AddSquare, + Add, AfterHours, Ai, AlternateEmail, @@ -298,8 +299,8 @@ export const Icons = { Arrow2Down, Arrow2Left, Arrow2Right, - Arrow2Up, Arrow2UpRight, + Arrow2Up, ArrowCircleDown, ArrowCircleUp, ArrowDoubleLeft, @@ -313,8 +314,8 @@ export const Icons = { Attachment, Backspace, Ban, - Bank, BankAssured, + Bank, Bold, Book, Bookmark, @@ -329,29 +330,29 @@ export const Icons = { Camera, Campaign, Candlestick, - Card, CardPos, + Card, Cash, Category, Chart, - Check, CheckBold, + Check, CircleX, Clear, - Clock, ClockFilled, + Clock, Close, - Cloud, CloudDownload, CloudUpload, - Code, + Cloud, CodeCircle, + Code, Coin, Collapse, Confirmation, Connect, - Copy, CopySuccess, + Copy, CorporateFare, CreditCheck, CurrencyFranc, @@ -360,8 +361,8 @@ export const Icons = { CurrencyYuan, Customize, Danger, - Dark, DarkFilled, + Dark, Data, Description, Details, @@ -370,21 +371,21 @@ export const Icons = { Download, Draft, EcoLeaf, - Edit, EditSquare, + Edit, EncryptedAdd, Eraser, Error, Ethereum, Exchange, - Expand, ExpandVertical, - Explore, + Expand, ExploreFilled, + Explore, Export, Extension, - Eye, EyeSlash, + Eye, FaceId, Feedback, File, @@ -393,8 +394,8 @@ export const Icons = { Fire, FirstPage, Flag, - Flash, FlashSlash, + Flash, Flask, Flower, Folder, @@ -402,31 +403,31 @@ export const Icons = { FullCircle, Gas, Gift, - Global, GlobalSearch, + Global, Graph, Hardware, HashTag, - Heart, HeartFilled, + Heart, Hierarchy, - Home, HomeFilled, + Home, Image, Info, Inventory, Joystick, - Keep, KeepFilled, + Keep, Key, LastPage, - Light, LightFilled, + Light, Link, Loading, Location, - Lock, LockSlash, + Lock, LockedFilled, Login, Logout, @@ -437,12 +438,12 @@ export const Icons = { Messages, MetamaskFoxOutline, Mic, - Minus, MinusBold, MinusSquare, + Minus, Mobile, - Money, MoneyBag, + Money, Monitor, MoreHorizontal, MoreVertical, @@ -475,14 +476,13 @@ export const Icons = { RemoveMinus, Report, Rocket, - Save, SaveFilled, + Save, Saving, - Scan, ScanBarcode, ScanFocus, + Scan, Search, - Security, SecurityAlert, SecurityCross, SecurityKey, @@ -491,13 +491,14 @@ export const Icons = { SecurityTick, SecurityTime, SecurityUser, + Security, Send, SentimentDissatisfied, SentimentNeutral, SentimentSatisfied, SentimentVerySatisfied, - Setting, SettingFilled, + Setting, Share, ShieldLock, ShoppingBag, @@ -506,19 +507,19 @@ export const Icons = { SignalCellular, Slash, Sms, - Snaps, SnapsMobile, SnapsPlus, SnapsRound, - Sort, + Snaps, SortByAlpha, + Sort, Sparkle, Speed, Speedometer, Square, Stake, - Star, StarFilled, + Star, Start, Storefront, Student, @@ -528,10 +529,10 @@ export const Icons = { TableRow, Tablet, Tag, - ThumbDown, ThumbDownFilled, - ThumbUp, + ThumbDown, ThumbUpFilled, + ThumbUp, Tint, Tooltip, Translate, @@ -542,28 +543,28 @@ export const Icons = { Unfold, UnlockedFilled, Unpin, - Upload, UploadFile, + Upload, Usb, - User, UserCheck, - UserCircle, UserCircleAdd, UserCircleRemove, - Verified, + UserCircle, + User, VerifiedFilled, + Verified, Videocam, ViewColumn, ViewInAr, VolumeOff, VolumeUp, - Wallet, WalletFilled, + Wallet, Warning, WebTraffic, Widgets, - Wifi, WifiOff, + Wifi, X, } as const; diff --git a/packages/design-system-react/src/components/Icon/index.ts b/packages/design-system-react/src/components/Icon/index.ts index 6ac4bca1f..85b384935 100644 --- a/packages/design-system-react/src/components/Icon/index.ts +++ b/packages/design-system-react/src/components/Icon/index.ts @@ -1,3 +1,3 @@ -export { IconName, IconSize, IconColor } from '../../types'; +export { IconColor, IconName, IconSize } from '@metamask/design-system-shared'; export { Icon } from './Icon'; export type { IconProps } from './Icon.types'; diff --git a/packages/design-system-react/src/components/Icon/template.d.ts b/packages/design-system-react/src/components/Icon/template.d.ts deleted file mode 100644 index 65cbdd880..000000000 --- a/packages/design-system-react/src/components/Icon/template.d.ts +++ /dev/null @@ -1,20 +0,0 @@ -type TemplateVariables = { - imports: string; - interfaces: string; - componentName: string; - props: string; - jsx: string; - exports: string; -}; - -type TemplateContext = { - tpl: (strings: TemplateStringsArray, ...values: unknown[]) => string; - options?: Record; -}; - -declare const template: ( - variables: TemplateVariables, - context: TemplateContext, -) => string; - -export default template; diff --git a/packages/design-system-react/src/components/Icon/template.js b/packages/design-system-react/src/components/Icon/template.js deleted file mode 100644 index 2c616e637..000000000 --- a/packages/design-system-react/src/components/Icon/template.js +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Template for generating icon components. - * This template is used by SVGR to transform SVG files into React components. - * It provides consistent formatting and props handling for all icon components. - * - * @param {object} variables - The variables passed to the template - * @param {object} variables.imports - The component import statements - * @param {object} variables.interfaces - The component type interfaces - * @param {string} variables.componentName - The name of the component being generated - * @param {object} variables.props - The component props configuration - * @param {string} variables.jsx - The JSX code for the component - * @param {object} variables.exports - The component export statements - * @param {object} options - Template options - * @param {Function} options.tpl - Template literal tag function - * @returns {string} The formatted component code - */ - -/** - * Generates a React component from SVG template variables - * - * @param {object} variables - SVGR template variables - * @param {object} options - Template options containing tpl function - * @param {Function} options.tpl - Template literal tag function - * @returns {string} Generated component code - */ -function template(variables, { tpl }) { - return tpl` -import type { SVGProps, Ref } from 'react'; -import * as React from 'react'; -import { forwardRef } from 'react'; - -const ${variables.componentName} = ( - props: SVGProps, - ref: Ref, -) => ( - - ${variables.jsx} - -); - -const ForwardRef = forwardRef(${variables.componentName}); -export default ForwardRef; -`; -} - -module.exports = template; diff --git a/packages/design-system-react/src/components/Icon/template.test.ts b/packages/design-system-react/src/components/Icon/template.test.ts deleted file mode 100644 index 6d732fe3b..000000000 --- a/packages/design-system-react/src/components/Icon/template.test.ts +++ /dev/null @@ -1,30 +0,0 @@ -import template from './template'; - -describe('template', () => { - it('should generate correct SVG component template', () => { - const variables = { - componentName: 'string', - jsx: 'string', - imports: '', - interfaces: '', - props: '', - exports: '', - }; - - const mockTpl = (strings: TemplateStringsArray, ...values: unknown[]) => { - return strings.reduce((result, str, i) => { - // eslint-disable-next-line @typescript-eslint/no-base-to-string - return result + str + String(values[i] || ''); - }, ''); - }; - - const result = template(variables, { tpl: mockTpl }); - - // Verify the template contains essential parts - expect(result).toContain("import * as React from 'react'"); - expect(result).toContain('const string = ('); - expect(result).toContain('props: SVGProps'); - expect(result).toContain('const ForwardRef = forwardRef(string)'); - expect(result).toContain('export default ForwardRef'); - }); -}); diff --git a/packages/design-system-react/src/types/index.ts b/packages/design-system-react/src/types/index.ts index c48c48455..92c00ecb2 100644 --- a/packages/design-system-react/src/types/index.ts +++ b/packages/design-system-react/src/types/index.ts @@ -138,346 +138,3 @@ export enum TextButtonSize { BodySm = 'body-sm', BodyXs = 'body-xs', } - -/** - * Icon - size - */ -export enum IconSize { - /** Extra small - 12px */ - Xs = 'xs', - /** Small - 16px */ - Sm = 'sm', - /** Medium - 20px (Default) */ - Md = 'md', - /** Large - 24px */ - Lg = 'lg', - /** Extra large - 32px */ - Xl = 'xl', -} - -/** - * Icon - color - */ -export enum IconColor { - /** For default neutral icons */ - IconDefault = 'text-icon-default', - /** For softer neutral icons */ - IconAlternative = 'text-icon-alternative', - /** For the weakest contrast neutral icons (not accessible) */ - IconMuted = 'text-icon-muted', - /** For elements used on top of overlay/alternative. Used for text, icon or border */ - OverlayInverse = 'text-overlay-inverse', - /** For interactive, active, and selected semantics. Used for text, background, icon or border */ - PrimaryDefault = 'text-primary-default', - /** For elements used on top of primary/default. Used for text, icon or border */ - PrimaryInverse = 'text-primary-inverse', - /** For the critical alert semantic elements. Used for text, background, icon or border */ - ErrorDefault = 'text-error-default', - /** For elements used on top of error/default. Used for text, icon or border */ - ErrorInverse = 'text-error-inverse', - /** For the positive semantic elements. Used for text, background, icon or border */ - SuccessDefault = 'text-success-default', - /** For elements used on top of success/default. Used for text, icon or border */ - SuccessInverse = 'text-success-inverse', - /** For the caution alert semantic elements. Used for text, background, icon or border */ - WarningDefault = 'text-warning-default', - /** For elements used on top of warning/default. Used for text, icon or border */ - WarningInverse = 'text-warning-inverse', - /** For informational read-only elements. Used for text, background, icon or border */ - InfoDefault = 'text-info-default', - /** For elements used on top of info/default. Used for text, icon or border */ - InfoInverse = 'text-info-inverse', -} - -/** - * Autogenerated from the generate-icon-script.ts script. - * Please do not edit this enum directly. - */ -/** - * Icon - name - */ -/* eslint-disable @typescript-eslint/no-shadow */ -export enum IconName { - Accessibility = 'Accessibility', - Activity = 'Activity', - Add = 'Add', - AddCard = 'AddCard', - AddCircle = 'AddCircle', - AddSquare = 'AddSquare', - AfterHours = 'AfterHours', - Ai = 'Ai', - AlternateEmail = 'AlternateEmail', - AppleLogo = 'AppleLogo', - Apps = 'Apps', - Arrow2Down = 'Arrow2Down', - Arrow2Left = 'Arrow2Left', - Arrow2Right = 'Arrow2Right', - Arrow2Up = 'Arrow2Up', - Arrow2UpRight = 'Arrow2UpRight', - ArrowCircleDown = 'ArrowCircleDown', - ArrowCircleUp = 'ArrowCircleUp', - ArrowDoubleLeft = 'ArrowDoubleLeft', - ArrowDoubleRight = 'ArrowDoubleRight', - ArrowDown = 'ArrowDown', - ArrowDropDownCircle = 'ArrowDropDownCircle', - ArrowLeft = 'ArrowLeft', - ArrowRight = 'ArrowRight', - ArrowUp = 'ArrowUp', - AttachMoney = 'AttachMoney', - Attachment = 'Attachment', - Backspace = 'Backspace', - Ban = 'Ban', - Bank = 'Bank', - BankAssured = 'BankAssured', - Bold = 'Bold', - Book = 'Book', - Bookmark = 'Bookmark', - Bridge = 'Bridge', - Briefcase = 'Briefcase', - Bulb = 'Bulb', - BuySell = 'BuySell', - Cake = 'Cake', - Calculator = 'Calculator', - Calendar = 'Calendar', - Call = 'Call', - Camera = 'Camera', - Campaign = 'Campaign', - Candlestick = 'Candlestick', - Card = 'Card', - CardPos = 'CardPos', - Cash = 'Cash', - Category = 'Category', - Chart = 'Chart', - Check = 'Check', - CheckBold = 'CheckBold', - CircleX = 'CircleX', - Clear = 'Clear', - Clock = 'Clock', - ClockFilled = 'ClockFilled', - Close = 'Close', - Cloud = 'Cloud', - CloudDownload = 'CloudDownload', - CloudUpload = 'CloudUpload', - Code = 'Code', - CodeCircle = 'CodeCircle', - Coin = 'Coin', - Collapse = 'Collapse', - Confirmation = 'Confirmation', - Connect = 'Connect', - Copy = 'Copy', - CopySuccess = 'CopySuccess', - CorporateFare = 'CorporateFare', - CreditCheck = 'CreditCheck', - CurrencyFranc = 'CurrencyFranc', - CurrencyLira = 'CurrencyLira', - CurrencyPound = 'CurrencyPound', - CurrencyYuan = 'CurrencyYuan', - Customize = 'Customize', - Danger = 'Danger', - Dark = 'Dark', - DarkFilled = 'DarkFilled', - Data = 'Data', - Description = 'Description', - Details = 'Details', - Diagram = 'Diagram', - DocumentCode = 'DocumentCode', - Download = 'Download', - Draft = 'Draft', - EcoLeaf = 'EcoLeaf', - Edit = 'Edit', - EditSquare = 'EditSquare', - EncryptedAdd = 'EncryptedAdd', - Eraser = 'Eraser', - Error = 'Error', - Ethereum = 'Ethereum', - Exchange = 'Exchange', - Expand = 'Expand', - ExpandVertical = 'ExpandVertical', - Explore = 'Explore', - ExploreFilled = 'ExploreFilled', - Export = 'Export', - Extension = 'Extension', - Eye = 'Eye', - EyeSlash = 'EyeSlash', - FaceId = 'FaceId', - Feedback = 'Feedback', - File = 'File', - Filter = 'Filter', - Fingerprint = 'Fingerprint', - Fire = 'Fire', - FirstPage = 'FirstPage', - Flag = 'Flag', - Flash = 'Flash', - FlashSlash = 'FlashSlash', - Flask = 'Flask', - Flower = 'Flower', - Folder = 'Folder', - Forest = 'Forest', - FullCircle = 'FullCircle', - Gas = 'Gas', - Gift = 'Gift', - Global = 'Global', - GlobalSearch = 'GlobalSearch', - Graph = 'Graph', - Hardware = 'Hardware', - HashTag = 'HashTag', - Heart = 'Heart', - HeartFilled = 'HeartFilled', - Hierarchy = 'Hierarchy', - Home = 'Home', - HomeFilled = 'HomeFilled', - Image = 'Image', - Info = 'Info', - Inventory = 'Inventory', - Joystick = 'Joystick', - Keep = 'Keep', - KeepFilled = 'KeepFilled', - Key = 'Key', - LastPage = 'LastPage', - Light = 'Light', - LightFilled = 'LightFilled', - Link = 'Link', - Loading = 'Loading', - Location = 'Location', - Lock = 'Lock', - LockSlash = 'LockSlash', - LockedFilled = 'LockedFilled', - Login = 'Login', - Logout = 'Logout', - Mail = 'Mail', - Map = 'Map', - Menu = 'Menu', - MessageQuestion = 'MessageQuestion', - Messages = 'Messages', - MetamaskFoxOutline = 'MetamaskFoxOutline', - Mic = 'Mic', - Minus = 'Minus', - MinusBold = 'MinusBold', - MinusSquare = 'MinusSquare', - Mobile = 'Mobile', - Money = 'Money', - MoneyBag = 'MoneyBag', - Monitor = 'Monitor', - MoreHorizontal = 'MoreHorizontal', - MoreVertical = 'MoreVertical', - MountainFlag = 'MountainFlag', - MusicNote = 'MusicNote', - NoPhotography = 'NoPhotography', - Notification = 'Notification', - PageInfo = 'PageInfo', - Palette = 'Palette', - PasswordCheck = 'PasswordCheck', - Pending = 'Pending', - People = 'People', - PersonCancel = 'PersonCancel', - Pin = 'Pin', - Plant = 'Plant', - Plug = 'Plug', - PlusAndMinus = 'PlusAndMinus', - PolicyAlert = 'PolicyAlert', - PopUp = 'PopUp', - Print = 'Print', - PriorityHigh = 'PriorityHigh', - PrivacyTip = 'PrivacyTip', - ProgrammingArrows = 'ProgrammingArrows', - Publish = 'Publish', - QrCode = 'QrCode', - Question = 'Question', - Receive = 'Receive', - Received = 'Received', - Refresh = 'Refresh', - RemoveMinus = 'RemoveMinus', - Report = 'Report', - Rocket = 'Rocket', - Save = 'Save', - SaveFilled = 'SaveFilled', - Saving = 'Saving', - Scan = 'Scan', - ScanBarcode = 'ScanBarcode', - ScanFocus = 'ScanFocus', - Search = 'Search', - Security = 'Security', - SecurityAlert = 'SecurityAlert', - SecurityCross = 'SecurityCross', - SecurityKey = 'SecurityKey', - SecuritySearch = 'SecuritySearch', - SecuritySlash = 'SecuritySlash', - SecurityTick = 'SecurityTick', - SecurityTime = 'SecurityTime', - SecurityUser = 'SecurityUser', - Send = 'Send', - SentimentDissatisfied = 'SentimentDissatisfied', - SentimentNeutral = 'SentimentNeutral', - SentimentSatisfied = 'SentimentSatisfied', - SentimentVerySatisfied = 'SentimentVerySatisfied', - Setting = 'Setting', - SettingFilled = 'SettingFilled', - Share = 'Share', - ShieldLock = 'ShieldLock', - ShoppingBag = 'ShoppingBag', - ShoppingCart = 'ShoppingCart', - SidePanel = 'SidePanel', - SignalCellular = 'SignalCellular', - Slash = 'Slash', - Sms = 'Sms', - Snaps = 'Snaps', - SnapsMobile = 'SnapsMobile', - SnapsPlus = 'SnapsPlus', - SnapsRound = 'SnapsRound', - Sort = 'Sort', - SortByAlpha = 'SortByAlpha', - Sparkle = 'Sparkle', - Speed = 'Speed', - Speedometer = 'Speedometer', - Square = 'Square', - Stake = 'Stake', - Star = 'Star', - StarFilled = 'StarFilled', - Start = 'Start', - Storefront = 'Storefront', - Student = 'Student', - SwapHorizontal = 'SwapHorizontal', - SwapVertical = 'SwapVertical', - TabClose = 'TabClose', - TableRow = 'TableRow', - Tablet = 'Tablet', - Tag = 'Tag', - ThumbDown = 'ThumbDown', - ThumbDownFilled = 'ThumbDownFilled', - ThumbUp = 'ThumbUp', - ThumbUpFilled = 'ThumbUpFilled', - Tint = 'Tint', - Tooltip = 'Tooltip', - Translate = 'Translate', - Trash = 'Trash', - TrendDown = 'TrendDown', - TrendUp = 'TrendUp', - Undo = 'Undo', - Unfold = 'Unfold', - UnlockedFilled = 'UnlockedFilled', - Unpin = 'Unpin', - Upload = 'Upload', - UploadFile = 'UploadFile', - Usb = 'Usb', - User = 'User', - UserCheck = 'UserCheck', - UserCircle = 'UserCircle', - UserCircleAdd = 'UserCircleAdd', - UserCircleRemove = 'UserCircleRemove', - Verified = 'Verified', - VerifiedFilled = 'VerifiedFilled', - Videocam = 'Videocam', - ViewColumn = 'ViewColumn', - ViewInAr = 'ViewInAr', - VolumeOff = 'VolumeOff', - VolumeUp = 'VolumeUp', - Wallet = 'Wallet', - WalletFilled = 'WalletFilled', - Warning = 'Warning', - WebTraffic = 'WebTraffic', - Widgets = 'Widgets', - Wifi = 'Wifi', - WifiOff = 'WifiOff', - X = 'X', -} -/* eslint-enable @typescript-eslint/no-shadow */ diff --git a/packages/design-system-shared/package.json b/packages/design-system-shared/package.json index ebf51605d..f6c4ebf24 100644 --- a/packages/design-system-shared/package.json +++ b/packages/design-system-shared/package.json @@ -35,7 +35,7 @@ "dist/" ], "scripts": { - "build": "ts-bridge --project tsconfig.build.json --verbose --clean --no-references", + "build": "tsx scripts/generate-icons.ts && ts-bridge --project tsconfig.build.json --verbose --clean --no-references", "changelog:update": "../../scripts/update-changelog.sh @metamask/design-system-shared", "changelog:validate": "../../scripts/validate-changelog.sh @metamask/design-system-shared", "test": "NODE_OPTIONS=--experimental-vm-modules jest --reporters=jest-silent-reporter", @@ -43,6 +43,7 @@ "test:verbose": "NODE_OPTIONS=--experimental-vm-modules jest --verbose", "test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch", "since-latest-release": "../../scripts/since-latest-release.sh", + "generate-icons": "tsx scripts/generate-icons.ts", "publish:preview": "yarn npm publish --tag preview" }, "dependencies": { @@ -50,6 +51,9 @@ }, "devDependencies": { "@metamask/auto-changelog": "^6.1.0", + "@svgr/core": "^8.1.0", + "@svgr/plugin-jsx": "^8.1.0", + "@svgr/plugin-svgo": "^8.1.0", "@ts-bridge/cli": "^0.6.3", "@types/jest": "^27.4.1", "@types/react": "^18.2.0", @@ -57,6 +61,7 @@ "jest": "^29.7.0", "react": "18.3.1", "ts-jest": "^29.2.5", + "tsx": "^4.20.6", "typescript": "~5.2.2" }, "peerDependencies": { diff --git a/packages/design-system-shared/scripts/generate-icons.ts b/packages/design-system-shared/scripts/generate-icons.ts new file mode 100644 index 000000000..a78ea78ea --- /dev/null +++ b/packages/design-system-shared/scripts/generate-icons.ts @@ -0,0 +1,341 @@ +import { transform } from '@svgr/core'; +import jsxPlugin from '@svgr/plugin-jsx'; +import svgoPlugin from '@svgr/plugin-svgo'; +import * as fs from 'fs/promises'; +import * as path from 'path'; + +// ─── Paths ──────────────────────────────────────────────────────────────────── + +const REPO_ROOT = path.join(__dirname, '../../..'); + +/** Single source of truth for all icon SVG assets */ +const SHARED_ASSETS_DIR = path.join(__dirname, '../src/assets/icons'); + +/** Shared IconName const object lives here */ +const SHARED_TYPES_FILE = path.join( + __dirname, + '../src/types/Icon/Icon.types.ts', +); + +/** Sentinels that bracket the generated IconName block */ +const ICON_NAME_SENTINEL_START = + '// DO NOT EDIT - generated by generate-icons.ts'; +const ICON_NAME_SENTINEL_END = '// END generated IconName'; + +// React Native paths +const RN_ASSETS_DIR = path.join( + REPO_ROOT, + 'packages/design-system-react-native/src/components/Icon/assets', +); +const RN_ASSETS_FILE = path.join( + REPO_ROOT, + 'packages/design-system-react-native/src/components/Icon/Icon.assets.ts', +); + +// React paths +const REACT_ICONS_DIR = path.join( + REPO_ROOT, + 'packages/design-system-react/src/components/Icon/icons', +); +const REACT_ICONS_INDEX_FILE = path.join(REACT_ICONS_DIR, 'index.ts'); + +// ─── Helpers ────────────────────────────────────────────────────────────────── + +/** + * Converts a kebab-case SVG filename to a PascalCase icon name. + * e.g. "add-card.svg" → "AddCard", "pop-up.svg" → "PopUp" + * + * @param fileName - The SVG filename to convert (e.g. "add-card.svg"). + * @returns The PascalCase icon name (e.g. "AddCard"). + */ +function toPascalCase(fileName: string): string { + return path + .basename(fileName, '.svg') + .split('-') + .map((part) => `${part[0].toUpperCase()}${part.slice(1)}`) + .join(''); +} + +/** + * SVGR custom template — mirrors the existing React template.js so generated + * components are identical in format to what was produced before centralisation. + * + * @param variables - The template variables provided by SVGR. + * @param variables.componentName - The PascalCase component name (e.g. "SvgAddCard"). + * @param variables.jsx - The JSX markup generated from the SVG. + * @param options1 - Additional SVGR template options. + * @param options1.tpl - The tagged-template helper used to produce the output string. + * @returns The complete TSX source string for the icon component. + */ +function svgrTemplate( + variables: { componentName: string; jsx: string }, + { tpl }: { tpl: (...args: unknown[]) => string }, +) { + return tpl` +import * as React from "react"; +import type { SVGProps } from "react"; +import { Ref, forwardRef } from "react"; + +const ${variables.componentName} = ( + props: SVGProps, + ref: Ref, +) => ( + ${variables.jsx} +); + +const ForwardRef = forwardRef(${variables.componentName}); +export default ForwardRef; +`; +} + +// ─── Step 1: Read & process SVG files ──────────────────────────────────────── + +async function readSvgFiles(): Promise { + const files = await fs.readdir(SHARED_ASSETS_DIR); + return files.filter((f) => f.endsWith('.svg')).sort(); +} + +async function processSvgs(svgFiles: string[]): Promise { + for (const file of svgFiles) { + const filePath = path.join(SHARED_ASSETS_DIR, file); + const content = await fs.readFile(filePath, 'utf-8'); + // Replace hardcoded black fill with currentColor so icons inherit color + const processed = content.replace(/black/gu, 'currentColor'); + await fs.writeFile(filePath, processed); + } +} + +// ─── Step 2: Update shared IconName ────────────────────────────────────────── + +async function updateSharedIconName(svgFiles: string[]): Promise { + const typesContent = await fs.readFile(SHARED_TYPES_FILE, 'utf-8'); + + const startIndex = typesContent.indexOf(ICON_NAME_SENTINEL_START); + if (startIndex === -1) { + throw new Error( + `Start sentinel "${ICON_NAME_SENTINEL_START}" not found in ${SHARED_TYPES_FILE}.`, + ); + } + + const endIndex = typesContent.indexOf(ICON_NAME_SENTINEL_END); + if (endIndex === -1) { + throw new Error( + `End sentinel "${ICON_NAME_SENTINEL_END}" not found in ${SHARED_TYPES_FILE}.`, + ); + } + + const beforeBlock = typesContent.slice(0, startIndex); + // Preserve everything after the end sentinel line (including the sentinel itself). + // Guard against the sentinel being the very last line (no trailing newline): if + // indexOf returns -1, slice from the end of the file so afterBlock is empty. + const newlineIndex = typesContent.indexOf('\n', endIndex); + const afterBlockStart = + newlineIndex === -1 ? typesContent.length : newlineIndex + 1; + const afterBlock = typesContent.slice(afterBlockStart); + + const iconEntries = svgFiles + .map((file) => { + const name = toPascalCase(file); + return ` ${name}: '${name}',`; + }) + .join('\n'); + + const generatedBlock = [ + ICON_NAME_SENTINEL_START, + `// /////////////////////////////////////////////////////`, + ``, + `/**`, + ` * Icon - name`, + ` * All icon names shared across React and React Native platforms.`, + ` * This block is auto-generated — do not edit directly.`, + ` * Run \`yarn generate:icons\` from the repo root to regenerate.`, + ` */`, + `export const IconName = {`, + iconEntries, + `} as const;`, + ``, + `export type IconName = (typeof IconName)[keyof typeof IconName];`, + ``, + ICON_NAME_SENTINEL_END, + ``, + ].join('\n'); + + await fs.writeFile( + SHARED_TYPES_FILE, + beforeBlock + generatedBlock + afterBlock, + ); +} + +// ─── Step 3: React Native — copy SVGs + generate Icon.assets.ts ────────────── + +async function generateReactNativeAssets(svgFiles: string[]): Promise { + // Ensure RN assets directory exists and clear previous output so stale SVGs + // (removed from the shared source) don't persist in the published package. + await fs.mkdir(RN_ASSETS_DIR, { recursive: true }); + const existingAssets = await fs.readdir(RN_ASSETS_DIR); + await Promise.all( + existingAssets.map((f) => fs.rm(path.join(RN_ASSETS_DIR, f))), + ); + + // Copy each processed SVG to RN assets folder + for (const file of svgFiles) { + const src = path.join(SHARED_ASSETS_DIR, file); + const dest = path.join(RN_ASSETS_DIR, file); + await fs.copyFile(src, dest); + } + + // Generate Icon.assets.ts + // Note: keys use PascalCase identifiers directly (e.g. `Add: AddSVG`) rather + // than computed `[IconName.Add]` to avoid importing IconName from + // @metamask/design-system-shared. That import gets regenerated during the + // shared-package build step, which runs after prepare-preview-builds.sh has + // already rewritten the scope in committed source files — causing TS2307 in + // the preview publish workflow. The AssetByIconName type annotation provides + // the same compile-time exhaustiveness check without the cross-package import. + const lines: string[] = [ + `// /////////////////////////////////////////////////////`, + `// This is a generated file`, + `// DO NOT EDIT — run \`yarn generate:icons\` from the repo root`, + `// /////////////////////////////////////////////////////`, + ]; + + for (const file of svgFiles) { + const name = toPascalCase(file); + lines.push(`import ${name}SVG from './assets/${file}';`); + } + + lines.push( + `import type { AssetByIconName } from './Icon.types';`, + ``, + `/**`, + ` * Asset stored by icon name`, + ` */`, + `export const assetByIconName: AssetByIconName = {`, + ); + + for (const file of svgFiles) { + const name = toPascalCase(file); + lines.push(` ${name}: ${name}SVG,`); + } + + lines.push(`};`, ``); + + await fs.writeFile(RN_ASSETS_FILE, lines.join('\n')); +} + +// ─── Step 4: React — generate TSX components + icons/index.ts ──────────────── + +async function generateReactIcons(svgFiles: string[]): Promise { + // Ensure icons directory exists and clear previous output + await fs.mkdir(REACT_ICONS_DIR, { recursive: true }); + const existing = await fs.readdir(REACT_ICONS_DIR); + await Promise.all(existing.map((f) => fs.rm(path.join(REACT_ICONS_DIR, f)))); + + const svgoConfig = { + plugins: [ + { + name: 'preset-default', + params: { + overrides: { removeViewBox: false }, + }, + }, + { + name: 'addAttributesToSVGElement', + params: { + attributes: [{ fill: 'currentColor' }], + }, + }, + ], + }; + + const iconNames: string[] = []; + + for (const file of svgFiles) { + const pascalName = toPascalCase(file); + const componentName = `Svg${pascalName}`; + iconNames.push(pascalName); + + const svgContent = await fs.readFile( + path.join(SHARED_ASSETS_DIR, file), + 'utf-8', + ); + + const tsxCode = await transform( + svgContent, + { + plugins: [svgoPlugin, jsxPlugin], + typescript: true, + dimensions: false, + ref: true, + svgProps: { fill: 'currentColor' }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + template: svgrTemplate as any, + prettier: false, + svgoConfig, + }, + { componentName }, + ); + + await fs.writeFile( + path.join(REACT_ICONS_DIR, `${pascalName}.tsx`), + tsxCode, + ); + } + + // Generate icons/index.ts barrel export + const indexLines: string[] = [ + `// This file is auto-generated — do not edit manually`, + `// Run \`yarn generate:icons\` from the repo root to regenerate`, + `import type { ForwardRefExoticComponent, RefAttributes, SVGProps } from 'react';`, + ``, + ...iconNames.map((name) => `import ${name} from './${name}';`), + ``, + `export const Icons = {`, + ...iconNames.map((name) => ` ${name},`), + `} as const;`, + ``, + `export type IconComponentType = ForwardRefExoticComponent<`, + ` SVGProps & RefAttributes`, + `>;`, + ``, + `export type IconsType = typeof Icons;`, + ``, + ]; + + await fs.writeFile(REACT_ICONS_INDEX_FILE, indexLines.join('\n')); +} + +// ─── Main ───────────────────────────────────────────────────────────────────── + +export async function main(): Promise { + console.log('🎨 Generating icons...\n'); + + const svgFiles = await readSvgFiles(); + console.log(` Found ${svgFiles.length} SVG assets in shared package`); + + console.log(' Step 1/4: Processing SVGs (black → currentColor)...'); + await processSvgs(svgFiles); + + console.log(' Step 2/4: Updating shared IconName...'); + await updateSharedIconName(svgFiles); + + console.log(' Step 3/4: Generating React Native assets...'); + await generateReactNativeAssets(svgFiles); + + console.log(' Step 4/4: Generating React TSX components...'); + await generateReactIcons(svgFiles); + + console.log(` +✅ Done! + • Shared: ${SHARED_TYPES_FILE.replace(`${REPO_ROOT}/`, '')} + • React Native: ${RN_ASSETS_FILE.replace(`${REPO_ROOT}/`, '')} + ${svgFiles.length} SVG assets + • React: ${svgFiles.length} TSX components + icons/index.ts +`); +} + +if (require.main === module) { + main().catch((error: unknown) => { + console.error(error); + throw error; + }); +} diff --git a/packages/design-system-shared/src/assets/icons/after-hours.svg b/packages/design-system-shared/src/assets/icons/after-hours.svg index 654390447..886720c7c 100644 --- a/packages/design-system-shared/src/assets/icons/after-hours.svg +++ b/packages/design-system-shared/src/assets/icons/after-hours.svg @@ -1 +1 @@ - + diff --git a/packages/design-system-shared/src/index.ts b/packages/design-system-shared/src/index.ts index 03ffc1c8f..1d163e618 100644 --- a/packages/design-system-shared/src/index.ts +++ b/packages/design-system-shared/src/index.ts @@ -130,3 +130,11 @@ export { type BoxBorderWidth, type BoxPropsShared, } from './types/Box'; + +// Icon types (ADR-0003 + ADR-0004) +export { + IconColor, + IconName, + IconSize, + type IconPropsShared, +} from './types/Icon'; diff --git a/packages/design-system-shared/src/types/Icon/Icon.types.ts b/packages/design-system-shared/src/types/Icon/Icon.types.ts new file mode 100644 index 000000000..1180e9d70 --- /dev/null +++ b/packages/design-system-shared/src/types/Icon/Icon.types.ts @@ -0,0 +1,380 @@ +/** + * Icon - color (ADR-0003) + * All icon color values shared across React and React Native platforms. + */ +export const IconColor = { + /** For default neutral icons */ + IconDefault: 'text-icon-default', + /** For softer neutral icons */ + IconAlternative: 'text-icon-alternative', + /** For the weakest contrast neutral icons (not accessible) */ + IconMuted: 'text-icon-muted', + /** For elements used on top of overlay/alternative. Used for text, icon, or border */ + OverlayInverse: 'text-overlay-inverse', + /** For interactive, active, and selected semantics. Used for text, background, icon, or border */ + PrimaryDefault: 'text-primary-default', + /** For softer variants of primary interactive elements */ + PrimaryAlternative: 'text-primary-alternative', + /** For elements used on top of primary/default. Used for text, icon, or border */ + PrimaryInverse: 'text-primary-inverse', + /** For critical alert semantic elements. Used for text, background, icon, or border */ + ErrorDefault: 'text-error-default', + /** For softer variants of error elements */ + ErrorAlternative: 'text-error-alternative', + /** For elements used on top of error/default. Used for text, icon, or border */ + ErrorInverse: 'text-error-inverse', + /** For caution alert semantic elements. Used for text, background, icon, or border */ + WarningDefault: 'text-warning-default', + /** For elements used on top of warning/default. Used for text, icon, or border */ + WarningInverse: 'text-warning-inverse', + /** For positive semantic elements. Used for text, background, icon, or border */ + SuccessDefault: 'text-success-default', + /** For elements used on top of success/default. Used for text, icon, or border */ + SuccessInverse: 'text-success-inverse', + /** For informational read-only elements. Used for text, background, icon, or border */ + InfoDefault: 'text-info-default', + /** For elements used on top of info/default. Used for text, icon, or border */ + InfoInverse: 'text-info-inverse', +} as const; + +export type IconColor = (typeof IconColor)[keyof typeof IconColor]; + +// ///////////////////////////////////////////////////// +// DO NOT EDIT - generated by generate-icons.ts +// ///////////////////////////////////////////////////// + +/** + * Icon - name + * All icon names shared across React and React Native platforms. + * This block is auto-generated — do not edit directly. + * Run `yarn generate:icons` from the repo root to regenerate. + */ +export const IconName = { + Accessibility: 'Accessibility', + Activity: 'Activity', + AddCard: 'AddCard', + AddCircle: 'AddCircle', + AddSquare: 'AddSquare', + Add: 'Add', + AfterHours: 'AfterHours', + Ai: 'Ai', + AlternateEmail: 'AlternateEmail', + AppleLogo: 'AppleLogo', + Apps: 'Apps', + Arrow2Down: 'Arrow2Down', + Arrow2Left: 'Arrow2Left', + Arrow2Right: 'Arrow2Right', + Arrow2UpRight: 'Arrow2UpRight', + Arrow2Up: 'Arrow2Up', + ArrowCircleDown: 'ArrowCircleDown', + ArrowCircleUp: 'ArrowCircleUp', + ArrowDoubleLeft: 'ArrowDoubleLeft', + ArrowDoubleRight: 'ArrowDoubleRight', + ArrowDown: 'ArrowDown', + ArrowDropDownCircle: 'ArrowDropDownCircle', + ArrowLeft: 'ArrowLeft', + ArrowRight: 'ArrowRight', + ArrowUp: 'ArrowUp', + AttachMoney: 'AttachMoney', + Attachment: 'Attachment', + Backspace: 'Backspace', + Ban: 'Ban', + BankAssured: 'BankAssured', + Bank: 'Bank', + Bold: 'Bold', + Book: 'Book', + Bookmark: 'Bookmark', + Bridge: 'Bridge', + Briefcase: 'Briefcase', + Bulb: 'Bulb', + BuySell: 'BuySell', + Cake: 'Cake', + Calculator: 'Calculator', + Calendar: 'Calendar', + Call: 'Call', + Camera: 'Camera', + Campaign: 'Campaign', + Candlestick: 'Candlestick', + CardPos: 'CardPos', + Card: 'Card', + Cash: 'Cash', + Category: 'Category', + Chart: 'Chart', + CheckBold: 'CheckBold', + Check: 'Check', + CircleX: 'CircleX', + Clear: 'Clear', + ClockFilled: 'ClockFilled', + Clock: 'Clock', + Close: 'Close', + CloudDownload: 'CloudDownload', + CloudUpload: 'CloudUpload', + Cloud: 'Cloud', + CodeCircle: 'CodeCircle', + Code: 'Code', + Coin: 'Coin', + Collapse: 'Collapse', + Confirmation: 'Confirmation', + Connect: 'Connect', + CopySuccess: 'CopySuccess', + Copy: 'Copy', + CorporateFare: 'CorporateFare', + CreditCheck: 'CreditCheck', + CurrencyFranc: 'CurrencyFranc', + CurrencyLira: 'CurrencyLira', + CurrencyPound: 'CurrencyPound', + CurrencyYuan: 'CurrencyYuan', + Customize: 'Customize', + Danger: 'Danger', + DarkFilled: 'DarkFilled', + Dark: 'Dark', + Data: 'Data', + Description: 'Description', + Details: 'Details', + Diagram: 'Diagram', + DocumentCode: 'DocumentCode', + Download: 'Download', + Draft: 'Draft', + EcoLeaf: 'EcoLeaf', + EditSquare: 'EditSquare', + Edit: 'Edit', + EncryptedAdd: 'EncryptedAdd', + Eraser: 'Eraser', + Error: 'Error', + Ethereum: 'Ethereum', + Exchange: 'Exchange', + ExpandVertical: 'ExpandVertical', + Expand: 'Expand', + ExploreFilled: 'ExploreFilled', + Explore: 'Explore', + Export: 'Export', + Extension: 'Extension', + EyeSlash: 'EyeSlash', + Eye: 'Eye', + FaceId: 'FaceId', + Feedback: 'Feedback', + File: 'File', + Filter: 'Filter', + Fingerprint: 'Fingerprint', + Fire: 'Fire', + FirstPage: 'FirstPage', + Flag: 'Flag', + FlashSlash: 'FlashSlash', + Flash: 'Flash', + Flask: 'Flask', + Flower: 'Flower', + Folder: 'Folder', + Forest: 'Forest', + FullCircle: 'FullCircle', + Gas: 'Gas', + Gift: 'Gift', + GlobalSearch: 'GlobalSearch', + Global: 'Global', + Graph: 'Graph', + Hardware: 'Hardware', + HashTag: 'HashTag', + HeartFilled: 'HeartFilled', + Heart: 'Heart', + Hierarchy: 'Hierarchy', + HomeFilled: 'HomeFilled', + Home: 'Home', + Image: 'Image', + Info: 'Info', + Inventory: 'Inventory', + Joystick: 'Joystick', + KeepFilled: 'KeepFilled', + Keep: 'Keep', + Key: 'Key', + LastPage: 'LastPage', + LightFilled: 'LightFilled', + Light: 'Light', + Link: 'Link', + Loading: 'Loading', + Location: 'Location', + LockSlash: 'LockSlash', + Lock: 'Lock', + LockedFilled: 'LockedFilled', + Login: 'Login', + Logout: 'Logout', + Mail: 'Mail', + Map: 'Map', + Menu: 'Menu', + MessageQuestion: 'MessageQuestion', + Messages: 'Messages', + MetamaskFoxOutline: 'MetamaskFoxOutline', + Mic: 'Mic', + MinusBold: 'MinusBold', + MinusSquare: 'MinusSquare', + Minus: 'Minus', + Mobile: 'Mobile', + MoneyBag: 'MoneyBag', + Money: 'Money', + Monitor: 'Monitor', + MoreHorizontal: 'MoreHorizontal', + MoreVertical: 'MoreVertical', + MountainFlag: 'MountainFlag', + MusicNote: 'MusicNote', + NoPhotography: 'NoPhotography', + Notification: 'Notification', + PageInfo: 'PageInfo', + Palette: 'Palette', + PasswordCheck: 'PasswordCheck', + Pending: 'Pending', + People: 'People', + PersonCancel: 'PersonCancel', + Pin: 'Pin', + Plant: 'Plant', + Plug: 'Plug', + PlusAndMinus: 'PlusAndMinus', + PolicyAlert: 'PolicyAlert', + PopUp: 'PopUp', + Print: 'Print', + PriorityHigh: 'PriorityHigh', + PrivacyTip: 'PrivacyTip', + ProgrammingArrows: 'ProgrammingArrows', + Publish: 'Publish', + QrCode: 'QrCode', + Question: 'Question', + Receive: 'Receive', + Received: 'Received', + Refresh: 'Refresh', + RemoveMinus: 'RemoveMinus', + Report: 'Report', + Rocket: 'Rocket', + SaveFilled: 'SaveFilled', + Save: 'Save', + Saving: 'Saving', + ScanBarcode: 'ScanBarcode', + ScanFocus: 'ScanFocus', + Scan: 'Scan', + Search: 'Search', + SecurityAlert: 'SecurityAlert', + SecurityCross: 'SecurityCross', + SecurityKey: 'SecurityKey', + SecuritySearch: 'SecuritySearch', + SecuritySlash: 'SecuritySlash', + SecurityTick: 'SecurityTick', + SecurityTime: 'SecurityTime', + SecurityUser: 'SecurityUser', + Security: 'Security', + Send: 'Send', + SentimentDissatisfied: 'SentimentDissatisfied', + SentimentNeutral: 'SentimentNeutral', + SentimentSatisfied: 'SentimentSatisfied', + SentimentVerySatisfied: 'SentimentVerySatisfied', + SettingFilled: 'SettingFilled', + Setting: 'Setting', + Share: 'Share', + ShieldLock: 'ShieldLock', + ShoppingBag: 'ShoppingBag', + ShoppingCart: 'ShoppingCart', + SidePanel: 'SidePanel', + SignalCellular: 'SignalCellular', + Slash: 'Slash', + Sms: 'Sms', + SnapsMobile: 'SnapsMobile', + SnapsPlus: 'SnapsPlus', + SnapsRound: 'SnapsRound', + Snaps: 'Snaps', + SortByAlpha: 'SortByAlpha', + Sort: 'Sort', + Sparkle: 'Sparkle', + Speed: 'Speed', + Speedometer: 'Speedometer', + Square: 'Square', + Stake: 'Stake', + StarFilled: 'StarFilled', + Star: 'Star', + Start: 'Start', + Storefront: 'Storefront', + Student: 'Student', + SwapHorizontal: 'SwapHorizontal', + SwapVertical: 'SwapVertical', + TabClose: 'TabClose', + TableRow: 'TableRow', + Tablet: 'Tablet', + Tag: 'Tag', + ThumbDownFilled: 'ThumbDownFilled', + ThumbDown: 'ThumbDown', + ThumbUpFilled: 'ThumbUpFilled', + ThumbUp: 'ThumbUp', + Tint: 'Tint', + Tooltip: 'Tooltip', + Translate: 'Translate', + Trash: 'Trash', + TrendDown: 'TrendDown', + TrendUp: 'TrendUp', + Undo: 'Undo', + Unfold: 'Unfold', + UnlockedFilled: 'UnlockedFilled', + Unpin: 'Unpin', + UploadFile: 'UploadFile', + Upload: 'Upload', + Usb: 'Usb', + UserCheck: 'UserCheck', + UserCircleAdd: 'UserCircleAdd', + UserCircleRemove: 'UserCircleRemove', + UserCircle: 'UserCircle', + User: 'User', + VerifiedFilled: 'VerifiedFilled', + Verified: 'Verified', + Videocam: 'Videocam', + ViewColumn: 'ViewColumn', + ViewInAr: 'ViewInAr', + VolumeOff: 'VolumeOff', + VolumeUp: 'VolumeUp', + WalletFilled: 'WalletFilled', + Wallet: 'Wallet', + Warning: 'Warning', + WebTraffic: 'WebTraffic', + Widgets: 'Widgets', + WifiOff: 'WifiOff', + Wifi: 'Wifi', + X: 'X', +} as const; + +export type IconName = (typeof IconName)[keyof typeof IconName]; + +// END generated IconName + +/** + * Icon - size + * Common icon sizes shared across React and React Native platforms. + */ +export const IconSize = { + /** Extra small - 12px */ + Xs: 'xs', + /** Small - 16px */ + Sm: 'sm', + /** Medium - 20px (Default) */ + Md: 'md', + /** Large - 24px */ + Lg: 'lg', + /** Extra large - 32px */ + Xl: 'xl', +} as const; + +export type IconSize = (typeof IconSize)[keyof typeof IconSize]; + +/** + * Icon component shared props (ADR-0004). + */ +export type IconPropsShared = { + /** + * Required prop to specify which icon to render from the icon set. + */ + name: IconName; + /** + * Optional prop that sets the color of the icon using predefined theme colors. + * + * @default IconColor.IconDefault + */ + color?: IconColor; + /** + * Optional prop to control the size of the icon. + * Different sizes map to specific pixel dimensions. + * + * @default IconSize.Md + */ + size?: IconSize; +}; diff --git a/packages/design-system-shared/src/types/Icon/index.ts b/packages/design-system-shared/src/types/Icon/index.ts new file mode 100644 index 000000000..9ac2dca4d --- /dev/null +++ b/packages/design-system-shared/src/types/Icon/index.ts @@ -0,0 +1,6 @@ +export { + IconColor, + IconName, + IconSize, + type IconPropsShared, +} from './Icon.types'; diff --git a/packages/design-system-tailwind-preset/scripts/testUtils.ts b/packages/design-system-tailwind-preset/scripts/testUtils.ts index 5da23fe74..f58a8d7b6 100644 --- a/packages/design-system-tailwind-preset/scripts/testUtils.ts +++ b/packages/design-system-tailwind-preset/scripts/testUtils.ts @@ -1,7 +1,5 @@ -/* eslint-disable import-x/no-nodejs-modules */ import { promises as fs } from 'fs'; import * as path from 'path'; -/* eslint-enable import-x/no-nodejs-modules */ import { parse } from 'postcss'; /** diff --git a/yarn.lock b/yarn.lock index 7a74e4350..e77e020e7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1800,9 +1800,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/aix-ppc64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/aix-ppc64@npm:0.27.2" +"@esbuild/aix-ppc64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/aix-ppc64@npm:0.27.7" conditions: os=aix & cpu=ppc64 languageName: node linkType: hard @@ -1814,9 +1814,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-arm64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/android-arm64@npm:0.27.2" +"@esbuild/android-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/android-arm64@npm:0.27.7" conditions: os=android & cpu=arm64 languageName: node linkType: hard @@ -1828,9 +1828,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-arm@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/android-arm@npm:0.27.2" +"@esbuild/android-arm@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/android-arm@npm:0.27.7" conditions: os=android & cpu=arm languageName: node linkType: hard @@ -1842,9 +1842,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-x64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/android-x64@npm:0.27.2" +"@esbuild/android-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/android-x64@npm:0.27.7" conditions: os=android & cpu=x64 languageName: node linkType: hard @@ -1856,9 +1856,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/darwin-arm64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/darwin-arm64@npm:0.27.2" +"@esbuild/darwin-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/darwin-arm64@npm:0.27.7" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard @@ -1870,9 +1870,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/darwin-x64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/darwin-x64@npm:0.27.2" +"@esbuild/darwin-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/darwin-x64@npm:0.27.7" conditions: os=darwin & cpu=x64 languageName: node linkType: hard @@ -1884,9 +1884,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/freebsd-arm64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/freebsd-arm64@npm:0.27.2" +"@esbuild/freebsd-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/freebsd-arm64@npm:0.27.7" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard @@ -1898,9 +1898,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/freebsd-x64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/freebsd-x64@npm:0.27.2" +"@esbuild/freebsd-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/freebsd-x64@npm:0.27.7" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard @@ -1912,9 +1912,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-arm64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/linux-arm64@npm:0.27.2" +"@esbuild/linux-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-arm64@npm:0.27.7" conditions: os=linux & cpu=arm64 languageName: node linkType: hard @@ -1926,9 +1926,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-arm@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/linux-arm@npm:0.27.2" +"@esbuild/linux-arm@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-arm@npm:0.27.7" conditions: os=linux & cpu=arm languageName: node linkType: hard @@ -1940,9 +1940,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-ia32@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/linux-ia32@npm:0.27.2" +"@esbuild/linux-ia32@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-ia32@npm:0.27.7" conditions: os=linux & cpu=ia32 languageName: node linkType: hard @@ -1954,9 +1954,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-loong64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/linux-loong64@npm:0.27.2" +"@esbuild/linux-loong64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-loong64@npm:0.27.7" conditions: os=linux & cpu=loong64 languageName: node linkType: hard @@ -1968,9 +1968,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-mips64el@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/linux-mips64el@npm:0.27.2" +"@esbuild/linux-mips64el@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-mips64el@npm:0.27.7" conditions: os=linux & cpu=mips64el languageName: node linkType: hard @@ -1982,9 +1982,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-ppc64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/linux-ppc64@npm:0.27.2" +"@esbuild/linux-ppc64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-ppc64@npm:0.27.7" conditions: os=linux & cpu=ppc64 languageName: node linkType: hard @@ -1996,9 +1996,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-riscv64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/linux-riscv64@npm:0.27.2" +"@esbuild/linux-riscv64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-riscv64@npm:0.27.7" conditions: os=linux & cpu=riscv64 languageName: node linkType: hard @@ -2010,9 +2010,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-s390x@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/linux-s390x@npm:0.27.2" +"@esbuild/linux-s390x@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-s390x@npm:0.27.7" conditions: os=linux & cpu=s390x languageName: node linkType: hard @@ -2024,9 +2024,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-x64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/linux-x64@npm:0.27.2" +"@esbuild/linux-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-x64@npm:0.27.7" conditions: os=linux & cpu=x64 languageName: node linkType: hard @@ -2038,9 +2038,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/netbsd-arm64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/netbsd-arm64@npm:0.27.2" +"@esbuild/netbsd-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/netbsd-arm64@npm:0.27.7" conditions: os=netbsd & cpu=arm64 languageName: node linkType: hard @@ -2052,9 +2052,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/netbsd-x64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/netbsd-x64@npm:0.27.2" +"@esbuild/netbsd-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/netbsd-x64@npm:0.27.7" conditions: os=netbsd & cpu=x64 languageName: node linkType: hard @@ -2066,9 +2066,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/openbsd-arm64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/openbsd-arm64@npm:0.27.2" +"@esbuild/openbsd-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/openbsd-arm64@npm:0.27.7" conditions: os=openbsd & cpu=arm64 languageName: node linkType: hard @@ -2080,9 +2080,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/openbsd-x64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/openbsd-x64@npm:0.27.2" +"@esbuild/openbsd-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/openbsd-x64@npm:0.27.7" conditions: os=openbsd & cpu=x64 languageName: node linkType: hard @@ -2094,9 +2094,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/openharmony-arm64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/openharmony-arm64@npm:0.27.2" +"@esbuild/openharmony-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/openharmony-arm64@npm:0.27.7" conditions: os=openharmony & cpu=arm64 languageName: node linkType: hard @@ -2108,9 +2108,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/sunos-x64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/sunos-x64@npm:0.27.2" +"@esbuild/sunos-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/sunos-x64@npm:0.27.7" conditions: os=sunos & cpu=x64 languageName: node linkType: hard @@ -2122,9 +2122,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-arm64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/win32-arm64@npm:0.27.2" +"@esbuild/win32-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/win32-arm64@npm:0.27.7" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard @@ -2136,9 +2136,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-ia32@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/win32-ia32@npm:0.27.2" +"@esbuild/win32-ia32@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/win32-ia32@npm:0.27.7" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard @@ -2150,9 +2150,9 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-x64@npm:0.27.2": - version: 0.27.2 - resolution: "@esbuild/win32-x64@npm:0.27.2" +"@esbuild/win32-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/win32-x64@npm:0.27.7" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -3391,6 +3391,9 @@ __metadata: dependencies: "@metamask/auto-changelog": "npm:^6.1.0" "@metamask/utils": "npm:^11.11.0" + "@svgr/core": "npm:^8.1.0" + "@svgr/plugin-jsx": "npm:^8.1.0" + "@svgr/plugin-svgo": "npm:^8.1.0" "@ts-bridge/cli": "npm:^0.6.3" "@types/jest": "npm:^27.4.1" "@types/react": "npm:^18.2.0" @@ -3398,6 +3401,7 @@ __metadata: jest: "npm:^29.7.0" react: "npm:18.3.1" ts-jest: "npm:^29.2.5" + tsx: "npm:^4.20.6" typescript: "npm:~5.2.2" peerDependencies: react: ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -8665,36 +8669,36 @@ __metadata: languageName: node linkType: hard -"esbuild@npm:^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.26.0 || ^0.27.0": - version: 0.27.2 - resolution: "esbuild@npm:0.27.2" - dependencies: - "@esbuild/aix-ppc64": "npm:0.27.2" - "@esbuild/android-arm": "npm:0.27.2" - "@esbuild/android-arm64": "npm:0.27.2" - "@esbuild/android-x64": "npm:0.27.2" - "@esbuild/darwin-arm64": "npm:0.27.2" - "@esbuild/darwin-x64": "npm:0.27.2" - "@esbuild/freebsd-arm64": "npm:0.27.2" - "@esbuild/freebsd-x64": "npm:0.27.2" - "@esbuild/linux-arm": "npm:0.27.2" - "@esbuild/linux-arm64": "npm:0.27.2" - "@esbuild/linux-ia32": "npm:0.27.2" - "@esbuild/linux-loong64": "npm:0.27.2" - "@esbuild/linux-mips64el": "npm:0.27.2" - "@esbuild/linux-ppc64": "npm:0.27.2" - "@esbuild/linux-riscv64": "npm:0.27.2" - "@esbuild/linux-s390x": "npm:0.27.2" - "@esbuild/linux-x64": "npm:0.27.2" - "@esbuild/netbsd-arm64": "npm:0.27.2" - "@esbuild/netbsd-x64": "npm:0.27.2" - "@esbuild/openbsd-arm64": "npm:0.27.2" - "@esbuild/openbsd-x64": "npm:0.27.2" - "@esbuild/openharmony-arm64": "npm:0.27.2" - "@esbuild/sunos-x64": "npm:0.27.2" - "@esbuild/win32-arm64": "npm:0.27.2" - "@esbuild/win32-ia32": "npm:0.27.2" - "@esbuild/win32-x64": "npm:0.27.2" +"esbuild@npm:^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.26.0 || ^0.27.0, esbuild@npm:~0.27.0": + version: 0.27.7 + resolution: "esbuild@npm:0.27.7" + dependencies: + "@esbuild/aix-ppc64": "npm:0.27.7" + "@esbuild/android-arm": "npm:0.27.7" + "@esbuild/android-arm64": "npm:0.27.7" + "@esbuild/android-x64": "npm:0.27.7" + "@esbuild/darwin-arm64": "npm:0.27.7" + "@esbuild/darwin-x64": "npm:0.27.7" + "@esbuild/freebsd-arm64": "npm:0.27.7" + "@esbuild/freebsd-x64": "npm:0.27.7" + "@esbuild/linux-arm": "npm:0.27.7" + "@esbuild/linux-arm64": "npm:0.27.7" + "@esbuild/linux-ia32": "npm:0.27.7" + "@esbuild/linux-loong64": "npm:0.27.7" + "@esbuild/linux-mips64el": "npm:0.27.7" + "@esbuild/linux-ppc64": "npm:0.27.7" + "@esbuild/linux-riscv64": "npm:0.27.7" + "@esbuild/linux-s390x": "npm:0.27.7" + "@esbuild/linux-x64": "npm:0.27.7" + "@esbuild/netbsd-arm64": "npm:0.27.7" + "@esbuild/netbsd-x64": "npm:0.27.7" + "@esbuild/openbsd-arm64": "npm:0.27.7" + "@esbuild/openbsd-x64": "npm:0.27.7" + "@esbuild/openharmony-arm64": "npm:0.27.7" + "@esbuild/sunos-x64": "npm:0.27.7" + "@esbuild/win32-arm64": "npm:0.27.7" + "@esbuild/win32-ia32": "npm:0.27.7" + "@esbuild/win32-x64": "npm:0.27.7" dependenciesMeta: "@esbuild/aix-ppc64": optional: true @@ -8750,11 +8754,11 @@ __metadata: optional: true bin: esbuild: bin/esbuild - checksum: 10/7f1229328b0efc63c4184a61a7eb303df1e99818cc1d9e309fb92600703008e69821e8e984e9e9f54a627da14e0960d561db3a93029482ef96dc82dd267a60c2 + checksum: 10/262b16c4a33cb70e9f054759a7ce420541649315eef7b064172c795021ccce322e56c3f5fd52e8842873f1c23745f3ab62311a24860950bd5406ba77b36b8529 languageName: node linkType: hard -"esbuild@npm:^0.25.0, esbuild@npm:~0.25.0": +"esbuild@npm:^0.25.0": version: 0.25.11 resolution: "esbuild@npm:0.25.11" dependencies: @@ -16616,10 +16620,10 @@ __metadata: linkType: hard "tsx@npm:^4.20.6": - version: 4.20.6 - resolution: "tsx@npm:4.20.6" + version: 4.21.0 + resolution: "tsx@npm:4.21.0" dependencies: - esbuild: "npm:~0.25.0" + esbuild: "npm:~0.27.0" fsevents: "npm:~2.3.3" get-tsconfig: "npm:^4.7.5" dependenciesMeta: @@ -16627,7 +16631,7 @@ __metadata: optional: true bin: tsx: dist/cli.mjs - checksum: 10/16396df25c474d7526f7adf9cd0c1f0b71a8c42f70bb93c2399c561eae3998abc015e8fe36a1e149fd289472919fb02816c5b46d72cf9f4335932419ecf2de8b + checksum: 10/7afedeff855ba98c47dc28b33d7e8e253c4dc1f791938db402d79c174bdf806b897c1a5f91e5b1259c112520c816f826b4c5d98f0bad7e95b02dec66fedb64d2 languageName: node linkType: hard From 61d3f6bf3fbf567ee4e01fb410a7cc444c7c0dd7 Mon Sep 17 00:00:00 2001 From: georgewrmarshall Date: Wed, 22 Apr 2026 14:47:36 -0700 Subject: [PATCH 2/4] chore: updating types index and adding missing icon --- .../src/components/Icon/assets/after-hours.svg | 2 +- packages/design-system-react-native/src/types/index.ts | 5 ++++- packages/design-system-react/src/types/index.ts | 4 ++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/design-system-react-native/src/components/Icon/assets/after-hours.svg b/packages/design-system-react-native/src/components/Icon/assets/after-hours.svg index 654390447..886720c7c 100644 --- a/packages/design-system-react-native/src/components/Icon/assets/after-hours.svg +++ b/packages/design-system-react-native/src/components/Icon/assets/after-hours.svg @@ -1 +1 @@ - + diff --git a/packages/design-system-react-native/src/types/index.ts b/packages/design-system-react-native/src/types/index.ts index 5b90f5f35..d635cca3c 100644 --- a/packages/design-system-react-native/src/types/index.ts +++ b/packages/design-system-react-native/src/types/index.ts @@ -2,7 +2,10 @@ export { AvatarBaseSize, AvatarBaseShape, } from '@metamask/design-system-shared'; -export { IconColor } from '@metamask/design-system-shared'; +/** + * TODO: Remove the following exports and update imports in components to import directly from `@metamask/design-system-shared` once all components have been migrated to React Native. + */ +export { IconColor, IconName, IconSize } from '@metamask/design-system-shared'; export { AvatarBaseSize as AvatarGroupSize } from '@metamask/design-system-shared'; export { AvatarBaseSize as AvatarIconSize } from '@metamask/design-system-shared'; export { AvatarBaseSize as AvatarNetworkSize } from '@metamask/design-system-shared'; diff --git a/packages/design-system-react/src/types/index.ts b/packages/design-system-react/src/types/index.ts index 92c00ecb2..45262b23b 100644 --- a/packages/design-system-react/src/types/index.ts +++ b/packages/design-system-react/src/types/index.ts @@ -2,6 +2,10 @@ export { AvatarBaseSize, AvatarBaseShape, } from '@metamask/design-system-shared'; +/** + * TODO: Remove the following exports and update imports in components to import directly from `@metamask/design-system-shared` once all components have been migrated to React Native. + */ +export { IconColor, IconName, IconSize } from '@metamask/design-system-shared'; export { AvatarBaseSize as AvatarGroupSize } from '@metamask/design-system-shared'; export { AvatarBaseSize as AvatarIconSize } from '@metamask/design-system-shared'; export { AvatarBaseSize as AvatarNetworkSize } from '@metamask/design-system-shared'; From 87a24989395c6b4d8a8790eaffd0498f4c9b02a1 Mon Sep 17 00:00:00 2001 From: georgewrmarshall Date: Wed, 22 Apr 2026 14:53:48 -0700 Subject: [PATCH 3/4] chore: reverting imports to reduce file changes --- .../src/components/Icon/Icon.constants.ts | 2 +- .../src/components/Icon/Icon.stories.tsx | 4 ++-- .../src/components/Icon/Icon.test.tsx | 4 ++-- .../design-system-react-native/src/components/Icon/Icon.tsx | 3 ++- .../design-system-react-native/src/components/Icon/index.ts | 2 +- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/design-system-react-native/src/components/Icon/Icon.constants.ts b/packages/design-system-react-native/src/components/Icon/Icon.constants.ts index 6157ddd27..899c98fa8 100644 --- a/packages/design-system-react-native/src/components/Icon/Icon.constants.ts +++ b/packages/design-system-react-native/src/components/Icon/Icon.constants.ts @@ -1,4 +1,4 @@ -import { IconSize } from '@metamask/design-system-shared'; +import { IconSize } from '../../types'; export const TWCLASSMAP_ICON_SIZE_DIMENSION: Record = { [IconSize.Xs]: 'w-3 h-3', // 12px diff --git a/packages/design-system-react-native/src/components/Icon/Icon.stories.tsx b/packages/design-system-react-native/src/components/Icon/Icon.stories.tsx index df908f0d6..91804f439 100644 --- a/packages/design-system-react-native/src/components/Icon/Icon.stories.tsx +++ b/packages/design-system-react-native/src/components/Icon/Icon.stories.tsx @@ -3,11 +3,11 @@ import type { Meta, StoryObj } from '@storybook/react-native'; import React from 'react'; import { ScrollView, View } from 'react-native'; +import { IconColor, IconName, IconSize } from '../../types'; + import { Icon } from './Icon'; import type { IconProps } from './Icon.types'; -import { IconColor, IconName, IconSize } from '.'; - const meta: Meta = { title: 'Components/Icon', component: Icon, diff --git a/packages/design-system-react-native/src/components/Icon/Icon.test.tsx b/packages/design-system-react-native/src/components/Icon/Icon.test.tsx index 56dcf53f2..bf08c649b 100644 --- a/packages/design-system-react-native/src/components/Icon/Icon.test.tsx +++ b/packages/design-system-react-native/src/components/Icon/Icon.test.tsx @@ -2,11 +2,11 @@ import { useTailwind } from '@metamask/design-system-twrnc-preset'; import { render } from '@testing-library/react-native'; import React from 'react'; +import { IconColor, IconName, IconSize } from '../../types'; + import { Icon } from './Icon'; import { TWCLASSMAP_ICON_SIZE_DIMENSION } from './Icon.constants'; -import { IconColor, IconName, IconSize } from '.'; - describe('Icon', () => { describe('Icon Component', () => { it('renders the specified icon', () => { diff --git a/packages/design-system-react-native/src/components/Icon/Icon.tsx b/packages/design-system-react-native/src/components/Icon/Icon.tsx index 66ef4c943..e943a701e 100644 --- a/packages/design-system-react-native/src/components/Icon/Icon.tsx +++ b/packages/design-system-react-native/src/components/Icon/Icon.tsx @@ -1,7 +1,8 @@ -import { IconColor, IconSize } from '@metamask/design-system-shared'; import { useTailwind } from '@metamask/design-system-twrnc-preset'; import React from 'react'; +import { IconColor, IconSize } from '../../types'; + import { assetByIconName } from './Icon.assets'; import { TWCLASSMAP_ICON_SIZE_DIMENSION } from './Icon.constants'; import type { IconProps } from './Icon.types'; diff --git a/packages/design-system-react-native/src/components/Icon/index.ts b/packages/design-system-react-native/src/components/Icon/index.ts index 85b384935..31cab1b35 100644 --- a/packages/design-system-react-native/src/components/Icon/index.ts +++ b/packages/design-system-react-native/src/components/Icon/index.ts @@ -1,3 +1,3 @@ -export { IconColor, IconName, IconSize } from '@metamask/design-system-shared'; +export { IconColor, IconName, IconSize } from '../../types'; export { Icon } from './Icon'; export type { IconProps } from './Icon.types'; From f254bdc46569aa50f222a8cab295564c5cb34f89 Mon Sep 17 00:00:00 2001 From: georgewrmarshall Date: Wed, 22 Apr 2026 14:57:26 -0700 Subject: [PATCH 4/4] chore: reverting imports to reduce file changes --- .../scripts/create-component/create-component.ts | 2 ++ .../scripts/create-component/create-component.ts | 2 ++ .../design-system-react/src/components/Icon/Icon.constants.ts | 2 +- .../design-system-react/src/components/Icon/Icon.stories.tsx | 3 +-- .../design-system-react/src/components/Icon/Icon.test.tsx | 4 ++-- packages/design-system-react/src/components/Icon/Icon.tsx | 2 +- packages/design-system-react/src/components/Icon/index.ts | 2 +- 7 files changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/design-system-react-native/scripts/create-component/create-component.ts b/packages/design-system-react-native/scripts/create-component/create-component.ts index a7628d191..79e8df31b 100644 --- a/packages/design-system-react-native/scripts/create-component/create-component.ts +++ b/packages/design-system-react-native/scripts/create-component/create-component.ts @@ -1,5 +1,7 @@ +/* eslint-disable import-x/no-nodejs-modules */ import { promises as fs } from 'fs'; import * as path from 'path'; +/* eslint-enable import-x/no-nodejs-modules */ type CreateComponentArgs = { name: string; diff --git a/packages/design-system-react/scripts/create-component/create-component.ts b/packages/design-system-react/scripts/create-component/create-component.ts index 499e4b18d..8c7a24182 100644 --- a/packages/design-system-react/scripts/create-component/create-component.ts +++ b/packages/design-system-react/scripts/create-component/create-component.ts @@ -1,5 +1,7 @@ +/* eslint-disable import-x/no-nodejs-modules */ import { promises as fs } from 'fs'; import * as path from 'path'; +/* eslint-enable import-x/no-nodejs-modules */ type CreateComponentArgs = { name: string; diff --git a/packages/design-system-react/src/components/Icon/Icon.constants.ts b/packages/design-system-react/src/components/Icon/Icon.constants.ts index 6157ddd27..899c98fa8 100644 --- a/packages/design-system-react/src/components/Icon/Icon.constants.ts +++ b/packages/design-system-react/src/components/Icon/Icon.constants.ts @@ -1,4 +1,4 @@ -import { IconSize } from '@metamask/design-system-shared'; +import { IconSize } from '../../types'; export const TWCLASSMAP_ICON_SIZE_DIMENSION: Record = { [IconSize.Xs]: 'w-3 h-3', // 12px diff --git a/packages/design-system-react/src/components/Icon/Icon.stories.tsx b/packages/design-system-react/src/components/Icon/Icon.stories.tsx index d335b5e10..a83735150 100644 --- a/packages/design-system-react/src/components/Icon/Icon.stories.tsx +++ b/packages/design-system-react/src/components/Icon/Icon.stories.tsx @@ -2,13 +2,12 @@ import { TextVariant } from '@metamask/design-system-shared'; import type { StoryObj } from '@storybook/react-vite'; import React, { useState } from 'react'; +import { IconName, IconSize, IconColor } from '../../types'; import { Text } from '../Text/Text'; import { Icon } from './Icon'; import README from './README.mdx'; -import { IconName, IconSize, IconColor } from '.'; - const meta = { title: 'React Components/Icon', component: Icon, diff --git a/packages/design-system-react/src/components/Icon/Icon.test.tsx b/packages/design-system-react/src/components/Icon/Icon.test.tsx index 6b7897f8a..70aca7cec 100644 --- a/packages/design-system-react/src/components/Icon/Icon.test.tsx +++ b/packages/design-system-react/src/components/Icon/Icon.test.tsx @@ -1,12 +1,12 @@ import { render, screen } from '@testing-library/react'; import React from 'react'; +import { IconName, IconSize, IconColor } from '../../types'; + import { Icon } from './Icon'; import { TWCLASSMAP_ICON_SIZE_DIMENSION } from './Icon.constants'; import type { IconProps } from './Icon.types'; -import { IconName, IconSize, IconColor } from '.'; - describe('Icon', () => { it('should render correctly', () => { render(); diff --git a/packages/design-system-react/src/components/Icon/Icon.tsx b/packages/design-system-react/src/components/Icon/Icon.tsx index d4845f0d2..a0b15b125 100644 --- a/packages/design-system-react/src/components/Icon/Icon.tsx +++ b/packages/design-system-react/src/components/Icon/Icon.tsx @@ -1,6 +1,6 @@ -import { IconSize, IconColor } from '@metamask/design-system-shared'; import React from 'react'; +import { IconSize, IconColor } from '../../types'; import { twMerge } from '../../utils/tw-merge'; import { TWCLASSMAP_ICON_SIZE_DIMENSION } from './Icon.constants'; diff --git a/packages/design-system-react/src/components/Icon/index.ts b/packages/design-system-react/src/components/Icon/index.ts index 85b384935..6ac4bca1f 100644 --- a/packages/design-system-react/src/components/Icon/index.ts +++ b/packages/design-system-react/src/components/Icon/index.ts @@ -1,3 +1,3 @@ -export { IconColor, IconName, IconSize } from '@metamask/design-system-shared'; +export { IconName, IconSize, IconColor } from '../../types'; export { Icon } from './Icon'; export type { IconProps } from './Icon.types';