From 66039cf2a0f0c6f4940387c57eb5624fa797b5f6 Mon Sep 17 00:00:00 2001 From: Christoph Purrer Date: Tue, 1 Mar 2022 12:17:12 -0800 Subject: [PATCH] Add placeholder support for Windows This change brings parity with the react-native-windows 0.63 Picker implementation of not setting a default index for the picker: https://github.com/microsoft/react-native-windows/blob/0.63-stable/vnext/Microsoft.ReactNative/Views/PickerViewManager.cpp#L40 If we don't set the index to -1 (or default to 0) we the place holder text won't appear https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.combobox.placeholdertext?view=winrt-22000#remarks This change also adds placeholder text support for Windows only + an example to use it --- example/src/App.tsx | 11 +++++++++ example/src/PickerWindowsExamples.js | 23 +++++++++++++++++++ js/Picker.js | 6 +++++ js/PickerWindows.windows.js | 2 ++ typings/Picker.d.ts | 5 ++++ windows/ReactNativePicker/ReactPickerView.cpp | 8 +++++++ windows/ReactNativePicker/ReactPickerView.h | 2 +- .../ReactPickerViewManager.cpp | 1 + 8 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 example/src/PickerWindowsExamples.js diff --git a/example/src/App.tsx b/example/src/App.tsx index 076b9fba8d..f7bbc43482 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -12,6 +12,7 @@ import { import * as PickerExamples from './PickerExample'; import * as PickerIOSExamples from './PickerIOSExample'; +import * as PickerWindowsExamples from './PickerWindowsExamples'; export default function App() { const [isRTL, setIsRTL] = React.useState(I18nManager.isRTL); @@ -49,6 +50,16 @@ export default function App() { {element.render()} ))} + {Platform.OS === 'windows' && ( + PickerWindows Examples + )} + {Platform.OS === 'windows' && + PickerWindowsExamples.examples.map((element) => ( + + {element.title} + {element.render()} + + ))} diff --git a/example/src/PickerWindowsExamples.js b/example/src/PickerWindowsExamples.js new file mode 100644 index 0000000000..aaea87776c --- /dev/null +++ b/example/src/PickerWindowsExamples.js @@ -0,0 +1,23 @@ +import * as React from 'react'; +import {Text, View, StyleSheet, Button} from 'react-native'; +import {Picker} from '../../js'; + +const Item: any = Picker.Item; + +function PlaceholderPickerExample() { + return ( + + + + + + + ); +} + +export const examples = [ + { + title: 'Picker with placeholder', + render: PlaceholderPickerExample, + }, +]; diff --git a/js/Picker.js b/js/Picker.js index 6cdcf657e7..b78e36ca3f 100644 --- a/js/Picker.js +++ b/js/Picker.js @@ -103,6 +103,12 @@ type PickerProps = $ReadOnly<{| * @platform android */ prompt?: ?string, + + /** + * Placeholder string for this picker, used on Windows if no item has been selected. + * @platform windows + */ + placeholder?: ?string, /** * Used to locate this view in end-to-end tests. diff --git a/js/PickerWindows.windows.js b/js/PickerWindows.windows.js index 3254b72ba4..7d1d161d79 100644 --- a/js/PickerWindows.windows.js +++ b/js/PickerWindows.windows.js @@ -31,6 +31,7 @@ type PickerWindowsProps = $ReadOnly<{| selectedValue?: any, enabled?: boolean, prompt?: string, + placeholder?: ?string, testID?: string, onChange?: (event: IPickerChangeEvent) => void, onValueChange?: (value: any, itemIndex: number, text: string) => void, @@ -87,6 +88,7 @@ class PickerWindows extends React.Component< enabled: this.props.enabled, items: this.state.items, onChange: this._onChange, + placeholder: this.props.placeholder, selectedIndex: this.state.selectedIndex, testID: this.props.testID, style: [styles.pickerWindows, this.props.style, this.props.itemStyle], diff --git a/typings/Picker.d.ts b/typings/Picker.d.ts index f1044ac304..e62cdf2f42 100644 --- a/typings/Picker.d.ts +++ b/typings/Picker.d.ts @@ -98,6 +98,11 @@ export interface PickerProps extends ViewProps { * The string used for the accessibility label. Will be read once focused on the picker but not on change. */ accessibilityLabel?: string; + /** + * Placeholder string for this picker, used on Windows if no item has been selected. + * @platform windows + */ + placeholder?: string; /** * Called when picker is focused * @platform android diff --git a/windows/ReactNativePicker/ReactPickerView.cpp b/windows/ReactNativePicker/ReactPickerView.cpp index 4b7c0f33c3..0716c48a54 100644 --- a/windows/ReactNativePicker/ReactPickerView.cpp +++ b/windows/ReactNativePicker/ReactPickerView.cpp @@ -100,6 +100,14 @@ namespace winrt::ReactNativePicker::implementation { else if (propertyName == "items") { RepopulateItems(propertyValue.AsArray()); } + else if (propertyName == "placeholder") { + if (propertyValue.IsNull()) { + this->ClearValue(winrt::ComboBox::PlaceholderTextProperty()); + } + else { + this->PlaceholderText(to_hstring(propertyValue.AsString())); + } + } else if (propertyName == "backgroundColor") { auto const color = propertyValue.To(); auto res = this->Resources(); diff --git a/windows/ReactNativePicker/ReactPickerView.h b/windows/ReactNativePicker/ReactPickerView.h index c39e9a543f..96c19fa130 100644 --- a/windows/ReactNativePicker/ReactPickerView.h +++ b/windows/ReactNativePicker/ReactPickerView.h @@ -20,7 +20,7 @@ namespace winrt::ReactNativePicker::implementation { Microsoft::ReactNative::IReactContext m_reactContext{ nullptr }; bool m_updating{ false }; // FUTURE: remove when we can require RS5+ - int32_t m_selectedIndex{ 0 }; + int32_t m_selectedIndex{ -1 }; std::vector m_itemValues; xaml::Media::Brush m_comboBoxColor{ nullptr }; xaml::Controls::ComboBox::SelectionChanged_revoker m_selectionChangedRevoker{}; diff --git a/windows/ReactNativePicker/ReactPickerViewManager.cpp b/windows/ReactNativePicker/ReactPickerViewManager.cpp index eaefe6ff75..4e62f5b8b1 100644 --- a/windows/ReactNativePicker/ReactPickerViewManager.cpp +++ b/windows/ReactNativePicker/ReactPickerViewManager.cpp @@ -40,6 +40,7 @@ namespace winrt::ReactNativePicker::implementation { nativeProps.Insert(L"editable", ViewManagerPropertyType::Boolean); nativeProps.Insert(L"enabled", ViewManagerPropertyType::Boolean); nativeProps.Insert(L"items", ViewManagerPropertyType::Array); + nativeProps.Insert(L"placeholder", ViewManagerPropertyType::String); nativeProps.Insert(L"selectedIndex", ViewManagerPropertyType::Number); nativeProps.Insert(L"text", ViewManagerPropertyType::String); return nativeProps.GetView();