diff --git a/NewArch/src/RNGalleryList.ts b/NewArch/src/RNGalleryList.ts index b8995674..450d8533 100644 --- a/NewArch/src/RNGalleryList.ts +++ b/NewArch/src/RNGalleryList.ts @@ -41,6 +41,7 @@ import { ModalExamplePage } from './examples/ModalExamplePage'; // Fabric only import {VirtualizedListExamplePage} from './examples/VirtualizedListExamplePage'; // import {LinearGradientExamplePage} from './examples/LinearGradientExamplePage'; // import {NetworkExamplePage} from './examples/NetworkExamplePage'; +import {PlatformColorExamplePage} from './examples/PlatformColorExamplePage'; // import {SvgExamplePage} from './examples/SvgExamplePage'; // import {LottieAnimationsExamplePage} from './examples/LottieAnimationsExamplePage'; @@ -207,6 +208,14 @@ export const RNGalleryList: Array = [ // subtitle: 'Displays content on top of existing content.', // type: 'Dialogs & flyouts', // }, + { + key: 'PlatformColor', + component: PlatformColorExamplePage, + textIcon: '\uE790', + subtitle: 'Reference platform-specific colors that adapt to user themes and accessibility settings.', + type: 'System', + new: true, + }, { key: 'Pressable', component: PressableExamplePage, diff --git a/NewArch/src/examples/PlatformColorExamplePage.tsx b/NewArch/src/examples/PlatformColorExamplePage.tsx new file mode 100644 index 00000000..2faf16b0 --- /dev/null +++ b/NewArch/src/examples/PlatformColorExamplePage.tsx @@ -0,0 +1,346 @@ +'use strict'; +import {View, Text, PlatformColor, ScrollView, StyleSheet, Switch, Button} from 'react-native'; +import React, { useState, createContext, useContext } from 'react'; +import {Example} from '../components/Example'; +import {Page} from '../components/Page'; + +type ThemeContextType = { + isDarkMode: boolean; +}; + +const ThemeContext = createContext({ isDarkMode: false }); + + +type ColorGroup = 'background' | 'border' | 'text'; +type PlatformColorType = { key: string; group?: ColorGroup }; +function PlatformColorVisualizer({ color }: { color: PlatformColorType }) { + const { isDarkMode } = useContext(ThemeContext); + let backgroundStyle; + let textStyle; + if (color.group === 'border') { + backgroundStyle = { borderWidth: 2, borderColor: PlatformColor(color.key), backgroundColor: 'transparent' }; + } else if (color.group === 'text') { + backgroundStyle = { backgroundColor: PlatformColor(color.key) }; + textStyle = { color: 'transparent' }; + } else { + backgroundStyle = { backgroundColor: PlatformColor(color.key) }; + } + return ( + + + O + + + {color.key} + + + ); +} + +// Source for these is here: https://github.com/microsoft/react-native-windows/blob/63e9eaaa2249c3f7b46200203cb69c006c5770a9/vnext/Microsoft.ReactNative/Fabric/Composition/Theme.cpp +// Grouping done in alignment with WinUI Gallery's Design->Color section +const platformColorGroups: { header: string; group?: string; colors: PlatformColorType[] }[] = [ + { + header: 'Control Fill', + colors: [ + { key: 'ControlFillColorDefault' }, + { key: 'ControlFillColorSecondary' }, + { key: 'ControlFillColorTertiary' }, + { key: 'ControlFillColorDisabled' }, + { key: 'ControlFillColorTransparent' }, + ], + }, + { + header: 'Strong Fill', + colors: [ + { key: 'ControlStrongFillColorDefault' }, + { key: 'ControlStrongFillColorDisabled' }, + ], + }, + { + header: 'Control Alt Fill', + colors: [ + { key: 'ControlAltFillColorSecondary' }, + { key: 'ControlAltFillColorTertiary' }, + { key: 'ControlAltFillColorQuarternary' }, + { key: 'ControlAltFillColorDisabled' }, + ], + }, + { + header: 'Subtle Fill', + colors: [ + { key: 'SubtleFillColorTransparent' }, + { key: 'SubtleFillColorSecondary' }, + ], + }, + { + header: 'Accent Fill', + colors: [ + { key: 'AccentFillColorDefault' }, + { key: 'AccentFillColorSecondary' }, + { key: 'AccentFillColorTertiary' }, + { key: 'AccentFillColorDisabled' }, + ], + }, + { + header: 'Accent', + group: 'system', + colors: [ + { key: 'Accent' }, + { key: 'AccentDark1' }, + { key: 'AccentDark2' }, + { key: 'AccentDark3' }, + { key: 'AccentLight1' }, + { key: 'AccentLight2' }, + { key: 'AccentLight3' }, + //{ key: 'Complement' }, + { key: 'Foreground' }, + ], + }, + { + header: 'Text', + colors: [ + { key: 'TextFillColorPrimary', group: 'text' }, + { key: 'TextFillColorSecondary', group: 'text' }, + { key: 'TextFillColorDisabled', group: 'text' }, + ], + }, + { + header: 'Text On Accent', + colors: [ + { key: 'TextOnAccentFillColorPrimary', group: 'text' }, + { key: 'TextOnAccentFillColorDisabled', group: 'text' }, + ], + }, + { + header: 'Control Stroke', + colors: [ + { key: 'ControlStrokeColorDefault', group: 'border' }, + { key: 'ControlStrokeColorSecondary', group: 'border' }, + { key: 'ControlStrokeColorOnAccentSecondary', group: 'border' }, + { key: 'ControlStrongStrokeColorDefault', group: 'border' }, + { key: 'ControlStrongStrokeColorDisabled', group: 'border' }, + ], + }, + { + header: 'Other', + colors: [ + { key: 'SolidBackgroundFillColorBase' }, + { key: 'CircleElevationBorder', group: 'border' }, + { key: 'ProgressRingForegroundTheme' }, + { key: 'TextControlForeground' }, + { key: 'ScrollBarButtonBackground' }, + { key: 'ScrollBarButtonBackgroundPointerOver' }, + { key: 'ScrollBarButtonBackgroundPressed' }, + { key: 'ScrollBarButtonBackgroundDisabled' }, + { key: 'ScrollBarButtonArrowForeground' }, + { key: 'ScrollBarButtonArrowForegroundPointerOver' }, + { key: 'ScrollBarButtonArrowForegroundPressed' }, + { key: 'ScrollBarButtonArrowForegroundDisabled' }, + { key: 'ScrollBarThumbFill' }, + { key: 'ScrollBarThumbFillPointerOver' }, + { key: 'ScrollBarThumbFillPressed' }, + { key: 'ScrollBarThumbFillDisabled' }, + { key: 'ScrollBarTrackFill' }, + { key: 'ToolTipBackground' }, + { key: 'ToolTipForeground' }, + { key: 'ToolTipBorderBrush', group: 'border' }, + { key: 'SystemChromeMediumLowColor' }, + { key: 'SystemControlForegroundBaseHighColor' }, + { key: 'SystemControlTransientBorderColor', group: 'border' }, + { key: 'FocusVisualPrimary', group: 'border' }, + { key: 'FocusVisualSecondary', group: 'border' }, + ], + }, + { + header: 'System', + group: 'system', + colors: [ + { key: 'AccentColor' }, + { key: 'ActiveCaption' }, + { key: 'Background' }, + { key: 'ButtonFace' }, + { key: 'ButtonText' }, + { key: 'CaptionText' }, + { key: 'GrayText' }, + { key: 'Highlight' }, + { key: 'HighlightText' }, + { key: 'Hotlight' }, + { key: 'InactiveCaption' }, + { key: 'InactiveCaptionText' }, + { key: 'NonTextHigh' }, + { key: 'NonTextLow' }, + { key: 'NonTextMedium' }, + { key: 'NonTextMediumHigh' }, + { key: 'NonTextMediumLow' }, + { key: 'OverlayOutsidePopup' }, + { key: 'PageBackground' }, + { key: 'PopupBackground' }, + { key: 'TextContrastWithHigh' }, + { key: 'TextHigh' }, + { key: 'TextLow' }, + { key: 'TextMedium' }, + { key: 'Window' }, + { key: 'WindowText' }, + ], + }, +]; + + +const groupLabels: { group: ColorGroup | 'fill' | 'system'; label: string }[] = [ + { group: 'background', label: 'Fill' }, + { group: 'border', label: 'Stroke' }, + { group: 'text', label: 'Text' }, + { group: 'system', label: 'System' }, +]; + +function PlatformColorList({ groupFilter }: { groupFilter: ColorGroup | 'fill' | 'system' }) { + const { isDarkMode } = useContext(ThemeContext); + const scrollChildren = []; + const stickyHeaderIndices = []; + let childIndex = 0; + for (const group of platformColorGroups) { + // Filter colors by group + const filteredColors = group.colors.filter(color => { + if (groupFilter === 'system') { + return group.header === 'System' || group.header === 'Accent'; + } + if (groupFilter === 'background') { + // Exclude System and Accent groups from background filter + if (group.header === 'System' || group.header === 'Accent') { + return false; + } + return !color.group || color.group === 'background'; + } + return color.group === groupFilter; + }); + if (filteredColors.length === 0) continue; + stickyHeaderIndices.push(childIndex); + scrollChildren.push( + {group.header} + ); + childIndex++; + for (const color of filteredColors) { + scrollChildren.push( + + ); + childIndex++; + } + } + + return ( + + {scrollChildren} + + ); +} + +function PlatformColorValueList() { + const [isDarkMode, setIsDarkMode] = useState(false); + const [groupFilter, setGroupFilter] = useState('background'); + + return ( + + + Dark Background + + + + {groupLabels.map(({ group, label }) => ( + +