| ... | @@ -4,11 +4,14 @@ import type { Icon } from "@tabler/icons-react-native/types"; | ... | @@ -4,11 +4,14 @@ import type { Icon } from "@tabler/icons-react-native/types"; |
| 4 | * the entire Tabler icon set in Metro. | 4 | * the entire Tabler icon set in Metro. |
| 5 | */ | 5 | */ |
| 6 | import IconAdjustmentsHorizontal from "@tabler/icons-react-native/IconAdjustmentsHorizontal"; | 6 | import IconAdjustmentsHorizontal from "@tabler/icons-react-native/IconAdjustmentsHorizontal"; |
| | 7 | import IconAlignLeft from "@tabler/icons-react-native/IconAlignLeft"; |
| 7 | import IconAlertCircle from "@tabler/icons-react-native/IconAlertCircle"; | 8 | import IconAlertCircle from "@tabler/icons-react-native/IconAlertCircle"; |
| 8 | import IconAlertTriangle from "@tabler/icons-react-native/IconAlertTriangle"; | 9 | import IconAlertTriangle from "@tabler/icons-react-native/IconAlertTriangle"; |
| 9 | import IconApps from "@tabler/icons-react-native/IconApps"; | 10 | import IconApps from "@tabler/icons-react-native/IconApps"; |
| 10 | import IconArchive from "@tabler/icons-react-native/IconArchive"; | 11 | import IconArchive from "@tabler/icons-react-native/IconArchive"; |
| 11 | import IconArrowBackUp from "@tabler/icons-react-native/IconArrowBackUp"; | 12 | import IconArrowBackUp from "@tabler/icons-react-native/IconArrowBackUp"; |
| | 13 | import IconArrowDown from "@tabler/icons-react-native/IconArrowDown"; |
| | 14 | import IconArrowForwardUp from "@tabler/icons-react-native/IconArrowForwardUp"; |
| 12 | import IconArrowLeft from "@tabler/icons-react-native/IconArrowLeft"; | 15 | import IconArrowLeft from "@tabler/icons-react-native/IconArrowLeft"; |
| 13 | import IconArrowDownCircle from "@tabler/icons-react-native/IconArrowDownCircle"; | 16 | import IconArrowDownCircle from "@tabler/icons-react-native/IconArrowDownCircle"; |
| 14 | import IconArrowRightCircle from "@tabler/icons-react-native/IconArrowRightCircle"; | 17 | import IconArrowRightCircle from "@tabler/icons-react-native/IconArrowRightCircle"; |
| ... | @@ -30,15 +33,17 @@ import IconChevronDown from "@tabler/icons-react-native/IconChevronDown"; | ... | @@ -30,15 +33,17 @@ import IconChevronDown from "@tabler/icons-react-native/IconChevronDown"; |
| 30 | import IconChevronLeft from "@tabler/icons-react-native/IconChevronLeft"; | 33 | import IconChevronLeft from "@tabler/icons-react-native/IconChevronLeft"; |
| 31 | import IconChevronRight from "@tabler/icons-react-native/IconChevronRight"; | 34 | import IconChevronRight from "@tabler/icons-react-native/IconChevronRight"; |
| 32 | import IconChevronUp from "@tabler/icons-react-native/IconChevronUp"; | 35 | import IconChevronUp from "@tabler/icons-react-native/IconChevronUp"; |
| | 36 | import IconCircle from "@tabler/icons-react-native/IconCircle"; |
| 33 | import IconCircleCheck from "@tabler/icons-react-native/IconCircleCheck"; | 37 | import IconCircleCheck from "@tabler/icons-react-native/IconCircleCheck"; |
| 34 | import IconCircleXFilled from "@tabler/icons-react-native/IconCircleXFilled"; | 38 | import IconCircleXFilled from "@tabler/icons-react-native/IconCircleXFilled"; |
| 35 | import IconTicket from "@tabler/icons-react-native/IconTicket"; | 39 | import IconTicket from "@tabler/icons-react-native/IconTicket"; |
| 36 | import IconClock from "@tabler/icons-react-native/IconClock"; | 40 | import IconClock from "@tabler/icons-react-native/IconClock"; |
| 37 | import IconCode from "@tabler/icons-react-native/IconCode"; | 41 | import IconCode from "@tabler/icons-react-native/IconCode"; |
| 38 | import IconCopy from "@tabler/icons-react-native/IconCopy"; | 42 | import IconCopy from "@tabler/icons-react-native/IconCopy"; |
| 39 | import IconDeviceDesktop from "@tabler/icons-react-native/IconDeviceDesktop"; | | |
| 40 | import IconDatabase from "@tabler/icons-react-native/IconDatabase"; | 43 | import IconDatabase from "@tabler/icons-react-native/IconDatabase"; |
| | 44 | import IconDeviceDesktop from "@tabler/icons-react-native/IconDeviceDesktop"; |
| 41 | import IconDeviceLaptop from "@tabler/icons-react-native/IconDeviceLaptop"; | 45 | import IconDeviceLaptop from "@tabler/icons-react-native/IconDeviceLaptop"; |
| | 46 | import IconDeviceMobile from "@tabler/icons-react-native/IconDeviceMobile"; |
| 42 | import IconDots from "@tabler/icons-react-native/IconDots"; | 47 | import IconDots from "@tabler/icons-react-native/IconDots"; |
| 43 | import IconDotsVertical from "@tabler/icons-react-native/IconDotsVertical"; | 48 | import IconDotsVertical from "@tabler/icons-react-native/IconDotsVertical"; |
| 44 | import IconDotsCircleHorizontal from "@tabler/icons-react-native/IconDotsCircleHorizontal"; | 49 | import IconDotsCircleHorizontal from "@tabler/icons-react-native/IconDotsCircleHorizontal"; |
| ... | @@ -62,13 +67,15 @@ import IconLayoutColumns from "@tabler/icons-react-native/IconLayoutColumns"; | ... | @@ -62,13 +67,15 @@ import IconLayoutColumns from "@tabler/icons-react-native/IconLayoutColumns"; |
| 62 | import IconLayoutSidebar from "@tabler/icons-react-native/IconLayoutSidebar"; | 67 | import IconLayoutSidebar from "@tabler/icons-react-native/IconLayoutSidebar"; |
| 63 | import IconLayoutSidebarRight from "@tabler/icons-react-native/IconLayoutSidebarRight"; | 68 | import IconLayoutSidebarRight from "@tabler/icons-react-native/IconLayoutSidebarRight"; |
| 64 | import IconLetterSpacing from "@tabler/icons-react-native/IconLetterSpacing"; | 69 | import IconLetterSpacing from "@tabler/icons-react-native/IconLetterSpacing"; |
| 65 | import IconMenu2 from "@tabler/icons-react-native/IconMenu2"; | 70 | import IconMicrophone from "@tabler/icons-react-native/IconMicrophone"; |
| 66 | import IconLink from "@tabler/icons-react-native/IconLink"; | 71 | import IconLink from "@tabler/icons-react-native/IconLink"; |
| | 72 | import IconMenu2 from "@tabler/icons-react-native/IconMenu2"; |
| 67 | import IconMessage from "@tabler/icons-react-native/IconMessage"; | 73 | import IconMessage from "@tabler/icons-react-native/IconMessage"; |
| 68 | import IconMinus from "@tabler/icons-react-native/IconMinus"; | 74 | import IconMinus from "@tabler/icons-react-native/IconMinus"; |
| 69 | import IconMoon from "@tabler/icons-react-native/IconMoon"; | 75 | import IconMoon from "@tabler/icons-react-native/IconMoon"; |
| 70 | import IconNetwork from "@tabler/icons-react-native/IconNetwork"; | 76 | import IconNetwork from "@tabler/icons-react-native/IconNetwork"; |
| 71 | import IconPalette from "@tabler/icons-react-native/IconPalette"; | 77 | import IconPalette from "@tabler/icons-react-native/IconPalette"; |
| | 78 | import IconPencil from "@tabler/icons-react-native/IconPencil"; |
| 72 | import IconPhoto from "@tabler/icons-react-native/IconPhoto"; | 79 | import IconPhoto from "@tabler/icons-react-native/IconPhoto"; |
| 73 | import IconPin from "@tabler/icons-react-native/IconPin"; | 80 | import IconPin from "@tabler/icons-react-native/IconPin"; |
| 74 | import IconPinnedOff from "@tabler/icons-react-native/IconPinnedOff"; | 81 | import IconPinnedOff from "@tabler/icons-react-native/IconPinnedOff"; |
| ... | @@ -97,13 +104,14 @@ import IconUserCircle from "@tabler/icons-react-native/IconUserCircle"; | ... | @@ -97,13 +104,14 @@ import IconUserCircle from "@tabler/icons-react-native/IconUserCircle"; |
| 97 | import IconWifiOff from "@tabler/icons-react-native/IconWifiOff"; | 104 | import IconWifiOff from "@tabler/icons-react-native/IconWifiOff"; |
| 98 | import IconWorld from "@tabler/icons-react-native/IconWorld"; | 105 | import IconWorld from "@tabler/icons-react-native/IconWorld"; |
| 99 | import IconX from "@tabler/icons-react-native/IconX"; | 106 | import IconX from "@tabler/icons-react-native/IconX"; |
| 100 | import type { SFSymbol, SymbolViewProps } from "expo-symbols"; | 107 | import type { AndroidSymbol, SFSymbol, SymbolViewProps } from "expo-symbols"; |
| 101 | import { withUniwind } from "uniwind"; | 108 | import { withUniwind } from "uniwind"; |
| 102 | | 109 | |
| 103 | const ANDROID_ICON_BY_SF_SYMBOL: Partial<Record<SFSymbol, Icon>> = { | 110 | const ANDROID_ICON_BY_SF_SYMBOL = { |
| 104 | "arrow.branch": IconGitBranch, | 111 | "arrow.branch": IconGitBranch, |
| 105 | "arrow.left": IconArrowLeft, | 112 | "arrow.left": IconArrowLeft, |
| 106 | "arrow.clockwise": IconRefresh, | 113 | "arrow.clockwise": IconRefresh, |
| | 114 | "arrow.down": IconArrowDown, |
| 107 | "arrow.down.circle": IconArrowDownCircle, | 115 | "arrow.down.circle": IconArrowDownCircle, |
| 108 | "arrow.right.circle": IconArrowRightCircle, | 116 | "arrow.right.circle": IconArrowRightCircle, |
| 109 | "arrow.triangle.branch": IconGitBranch, | 117 | "arrow.triangle.branch": IconGitBranch, |
| ... | @@ -117,6 +125,7 @@ const ANDROID_ICON_BY_SF_SYMBOL: Partial<Record<SFSymbol, Icon>> = { | ... | @@ -117,6 +125,7 @@ const ANDROID_ICON_BY_SF_SYMBOL: Partial<Record<SFSymbol, Icon>> = { |
| 117 | "arrow.up.right": IconArrowUpRight, | 125 | "arrow.up.right": IconArrowUpRight, |
| 118 | "arrow.up.right.circle": IconArrowUpRightCircle, | 126 | "arrow.up.right.circle": IconArrowUpRightCircle, |
| 119 | "arrow.uturn.backward": IconArrowBackUp, | 127 | "arrow.uturn.backward": IconArrowBackUp, |
| | 128 | "arrow.uturn.forward": IconArrowForwardUp, |
| 120 | archivebox: IconArchive, | 129 | archivebox: IconArchive, |
| 121 | "archivebox.fill": IconArchive, | 130 | "archivebox.fill": IconArchive, |
| 122 | "bell.badge": IconBellRinging, | 131 | "bell.badge": IconBellRinging, |
| ... | @@ -127,6 +136,7 @@ const ANDROID_ICON_BY_SF_SYMBOL: Partial<Record<SFSymbol, Icon>> = { | ... | @@ -127,6 +136,7 @@ const ANDROID_ICON_BY_SF_SYMBOL: Partial<Record<SFSymbol, Icon>> = { |
| 127 | "chart.bar.xaxis": IconChartBar, | 136 | "chart.bar.xaxis": IconChartBar, |
| 128 | checkmark: IconCheck, | 137 | checkmark: IconCheck, |
| 129 | "checkmark.circle": IconCircleCheck, | 138 | "checkmark.circle": IconCircleCheck, |
| | 139 | circle: IconCircle, |
| 130 | clock: IconClock, | 140 | clock: IconClock, |
| 131 | ticket: IconTicket, | 141 | ticket: IconTicket, |
| 132 | cloud: IconCloud, | 142 | cloud: IconCloud, |
| ... | @@ -143,11 +153,13 @@ const ANDROID_ICON_BY_SF_SYMBOL: Partial<Record<SFSymbol, Icon>> = { | ... | @@ -143,11 +153,13 @@ const ANDROID_ICON_BY_SF_SYMBOL: Partial<Record<SFSymbol, Icon>> = { |
| 143 | moon: IconMoon, | 153 | moon: IconMoon, |
| 144 | "ellipsis.circle": IconDotsCircleHorizontal, | 154 | "ellipsis.circle": IconDotsCircleHorizontal, |
| 145 | "exclamationmark.triangle": IconAlertTriangle, | 155 | "exclamationmark.triangle": IconAlertTriangle, |
| | 156 | "exclamationmark.circle": IconAlertCircle, |
| 146 | eye: IconEye, | 157 | eye: IconEye, |
| 147 | folder: IconFolder, | 158 | folder: IconFolder, |
| 148 | "folder.badge.plus": IconFolderPlus, | 159 | "folder.badge.plus": IconFolderPlus, |
| 149 | "folder.fill": IconFolder, | 160 | "folder.fill": IconFolder, |
| 150 | gearshape: IconSettings, | 161 | gearshape: IconSettings, |
| | 162 | globe: IconWorld, |
| 151 | hammer: IconHammer, | 163 | hammer: IconHammer, |
| 152 | "info.circle": IconInfoCircle, | 164 | "info.circle": IconInfoCircle, |
| 153 | internaldrive: IconDatabase, | 165 | internaldrive: IconDatabase, |
| ... | @@ -162,7 +174,9 @@ const ANDROID_ICON_BY_SF_SYMBOL: Partial<Record<SFSymbol, Icon>> = { | ... | @@ -162,7 +174,9 @@ const ANDROID_ICON_BY_SF_SYMBOL: Partial<Record<SFSymbol, Icon>> = { |
| 162 | macmini: IconServer, | 174 | macmini: IconServer, |
| 163 | macstudio: IconDeviceDesktop, | 175 | macstudio: IconDeviceDesktop, |
| 164 | magnifyingglass: IconSearch, | 176 | magnifyingglass: IconSearch, |
| | 177 | mic: IconMicrophone, |
| 165 | paintbrush: IconPalette, | 178 | paintbrush: IconPalette, |
| | 179 | pencil: IconPencil, |
| 166 | "person.crop.circle": IconUserCircle, | 180 | "person.crop.circle": IconUserCircle, |
| 167 | photo: IconPhoto, | 181 | photo: IconPhoto, |
| 168 | pin: IconPin, | 182 | pin: IconPin, |
| ... | @@ -187,6 +201,7 @@ const ANDROID_ICON_BY_SF_SYMBOL: Partial<Record<SFSymbol, Icon>> = { | ... | @@ -187,6 +201,7 @@ const ANDROID_ICON_BY_SF_SYMBOL: Partial<Record<SFSymbol, Icon>> = { |
| 187 | "sun.max": IconSun, | 201 | "sun.max": IconSun, |
| 188 | "stop.fill": IconPlayerStopFilled, | 202 | "stop.fill": IconPlayerStopFilled, |
| 189 | terminal: IconTerminal2, | 203 | terminal: IconTerminal2, |
| | 204 | "text.alignleft": IconAlignLeft, |
| 190 | "text.bubble": IconMessage, | 205 | "text.bubble": IconMessage, |
| 191 | "text.word.spacing": IconLetterSpacing, | 206 | "text.word.spacing": IconLetterSpacing, |
| 192 | "textformat.size": IconTypography, | 207 | "textformat.size": IconTypography, |
| ... | @@ -197,13 +212,14 @@ const ANDROID_ICON_BY_SF_SYMBOL: Partial<Record<SFSymbol, Icon>> = { | ... | @@ -197,13 +212,14 @@ const ANDROID_ICON_BY_SF_SYMBOL: Partial<Record<SFSymbol, Icon>> = { |
| 197 | "wifi.slash": IconWifiOff, | 212 | "wifi.slash": IconWifiOff, |
| 198 | xmark: IconX, | 213 | xmark: IconX, |
| 199 | "xmark.circle.fill": IconCircleXFilled, | 214 | "xmark.circle.fill": IconCircleXFilled, |
| 200 | }; | 215 | } satisfies Partial<Record<SFSymbol, Icon>>; |
| | 216 | const SF_ICON_LOOKUP: Partial<Record<SFSymbol, Icon>> = ANDROID_ICON_BY_SF_SYMBOL; |
| 201 | | 217 | |
| 202 | // Callers can pass `{ ios, android }` names where `android` is a Material | 218 | // Callers can pass `{ ios, android }` names where `android` is a Material |
| 203 | // icon name (the raw expo-symbols contract). Resolve those here too so the | 219 | // icon name (the raw expo-symbols contract). Resolve those here too so the |
| 204 | // android key keeps working through this wrapper — it wins over the SF map | 220 | // android key keeps working through this wrapper — it wins over the SF map |
| 205 | // when both match (e.g. folder vs folder_open for expanded project groups). | 221 | // when both match (e.g. folder vs folder_open for expanded project groups). |
| 206 | const ANDROID_ICON_BY_MATERIAL_NAME: Record<string, Icon> = { | 222 | const ANDROID_ICON_BY_MATERIAL_NAME = { |
| 207 | auto_awesome: IconSparkles, | 223 | auto_awesome: IconSparkles, |
| 208 | bolt: IconBolt, | 224 | bolt: IconBolt, |
| 209 | build: IconTool, | 225 | build: IconTool, |
| ... | @@ -222,21 +238,34 @@ const ANDROID_ICON_BY_MATERIAL_NAME: Record<string, Icon> = { | ... | @@ -222,21 +238,34 @@ const ANDROID_ICON_BY_MATERIAL_NAME: Record<string, Icon> = { |
| 222 | keyboard_arrow_up: IconChevronUp, | 238 | keyboard_arrow_up: IconChevronUp, |
| 223 | keyboard_hide: IconKeyboardHide, | 239 | keyboard_hide: IconKeyboardHide, |
| 224 | more_vert: IconDotsVertical, | 240 | more_vert: IconDotsVertical, |
| | 241 | merge: IconGitMerge, |
| 225 | public: IconWorld, | 242 | public: IconWorld, |
| 226 | remove: IconMinus, | 243 | remove: IconMinus, |
| | 244 | smartphone: IconDeviceMobile, |
| 227 | terminal: IconTerminal2, | 245 | terminal: IconTerminal2, |
| 228 | visibility: IconEye, | 246 | visibility: IconEye, |
| 229 | }; | 247 | } satisfies Partial<Record<AndroidSymbol, Icon>>; |
| 230 | | 248 | |
| 231 | export type { SFSymbol } from "expo-symbols"; | 249 | export type { SFSymbol } from "expo-symbols"; |
| 232 | export type AppSymbolName = SymbolViewProps["name"]; | 250 | export type AppSymbolName = |
| | 251 | | keyof typeof ANDROID_ICON_BY_SF_SYMBOL |
| | 252 | | { |
| | 253 | ios: SFSymbol; |
| | 254 | android: keyof typeof ANDROID_ICON_BY_MATERIAL_NAME; |
| | 255 | }; |
| | 256 | |
| | 257 | export type AppSymbolViewProps = Omit<SymbolViewProps, "name"> & { name: AppSymbolName }; |
| | 258 | |
| | 259 | export function isAppSymbolName(name: string): name is Extract<AppSymbolName, string> { |
| | 260 | return Object.prototype.hasOwnProperty.call(ANDROID_ICON_BY_SF_SYMBOL, name); |
| | 261 | } |
| 233 | | 262 | |
| 234 | function AppSymbolView(props: SymbolViewProps) { | 263 | function AppSymbolView(props: AppSymbolViewProps) { |
| 235 | const materialName = typeof props.name === "string" ? undefined : props.name.android; | 264 | const materialName = typeof props.name === "string" ? undefined : props.name.android; |
| 236 | const sfSymbol = typeof props.name === "string" ? props.name : props.name.ios; | 265 | const sfSymbol = typeof props.name === "string" ? props.name : props.name.ios; |
| 237 | const AndroidIcon = | 266 | const AndroidIcon = |
| 238 | (materialName ? ANDROID_ICON_BY_MATERIAL_NAME[materialName] : undefined) ?? | 267 | (materialName ? ANDROID_ICON_BY_MATERIAL_NAME[materialName] : undefined) ?? |
| 239 | (sfSymbol ? ANDROID_ICON_BY_SF_SYMBOL[sfSymbol] : undefined); | 268 | (sfSymbol ? SF_ICON_LOOKUP[sfSymbol] : undefined); |
| 240 | | 269 | |
| 241 | if (!AndroidIcon) { | 270 | if (!AndroidIcon) { |
| 242 | return props.fallback ?? null; | 271 | return props.fallback ?? null; |