mirror of
https://github.com/zhigang1992/react-native-web.git
synced 2026-01-12 22:51:09 +08:00
committed by
Nicolas Gallagher
parent
02e62ad5d6
commit
b7e970f4e6
113
docs/storybook/1-components/Picker/PickerScreen.js
Normal file
113
docs/storybook/1-components/Picker/PickerScreen.js
Normal file
@@ -0,0 +1,113 @@
|
||||
/* eslint-disable react/jsx-sort-props, react/jsx-no-bind, no-alert */
|
||||
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PickerExample from './examples/PickerExample';
|
||||
import UIExplorer, {
|
||||
AppText,
|
||||
Description,
|
||||
DocItem,
|
||||
Section,
|
||||
StyleList,
|
||||
storiesOf
|
||||
} from '../../ui-explorer';
|
||||
import { View } from 'react-native';
|
||||
|
||||
const PickerScreen = () => (
|
||||
<View>
|
||||
<UIExplorer title="Picker">
|
||||
<Description>
|
||||
<AppText>Renders the native <select> component.</AppText>
|
||||
</Description>
|
||||
<Section title="Props">
|
||||
<DocItem
|
||||
name="children"
|
||||
typeInfo="?Array<Picker.Item>"
|
||||
description="The items to display in the picker."
|
||||
example={{
|
||||
code: `<Picker>
|
||||
<Picker.Item label="Goblet of Fire" />
|
||||
<Picker.Item label="Order of the Phoenix" />
|
||||
</Picker>`
|
||||
}}
|
||||
/>
|
||||
|
||||
<DocItem
|
||||
name="enabled"
|
||||
typeInfo="?boolean"
|
||||
description="If set to false, the picker will be disabled, i.e., the user will not be able to make a selection."
|
||||
example={{
|
||||
render: () => <PickerExample enabled={false} />
|
||||
}}
|
||||
/>
|
||||
|
||||
<DocItem
|
||||
name="onValueChange"
|
||||
typeInfo="?(itemValue, itemIndex) => void"
|
||||
description="Callback for when an item is selected. This is called with the value and index prop of the item that was selected."
|
||||
example={{
|
||||
render: () => (
|
||||
<PickerExample
|
||||
onValueChange={(itemValue, itemPosition) => {
|
||||
window.alert(`itemValue: ${itemValue}, itemPosition: ${itemPosition}`);
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
|
||||
<DocItem
|
||||
name="selectedValue"
|
||||
typeInfo="?string"
|
||||
description="Select the item with the matching value."
|
||||
example={{
|
||||
render: () => <PickerExample selectedValue="book-3" />
|
||||
}}
|
||||
/>
|
||||
|
||||
<DocItem
|
||||
name="style"
|
||||
typeInfo="?style"
|
||||
description={
|
||||
<StyleList
|
||||
stylePropTypes={[
|
||||
{
|
||||
name: '…View#style'
|
||||
},
|
||||
{
|
||||
name: 'color',
|
||||
typeInfo: 'color'
|
||||
}
|
||||
]}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<DocItem
|
||||
name="testID"
|
||||
typeInfo="?string"
|
||||
description="Used to locate this view in end-to-end tests."
|
||||
/>
|
||||
</Section>
|
||||
</UIExplorer>
|
||||
|
||||
<UIExplorer title="Picker.Item" url="1-components/Picker">
|
||||
<Description>Individual selectable item in a Picker.</Description>
|
||||
|
||||
<Section title="Props">
|
||||
<DocItem name="label" typeInfo="string" description="Text to display for this item" />
|
||||
<DocItem name="testID" typeInfo="?string" />
|
||||
<DocItem
|
||||
name="value"
|
||||
typeInfo="?number | string"
|
||||
description="The value to be passed to the picker's 'onValueChange' callback when this item is selected."
|
||||
/>
|
||||
</Section>
|
||||
</UIExplorer>
|
||||
</View>
|
||||
);
|
||||
|
||||
storiesOf('Components', module).add('Picker', PickerScreen);
|
||||
28
docs/storybook/1-components/Picker/examples/PickerExample.js
Normal file
28
docs/storybook/1-components/Picker/examples/PickerExample.js
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Picker, StyleSheet, View } from 'react-native';
|
||||
|
||||
const PickerExample = props => (
|
||||
<View style={styles.root}>
|
||||
<Picker {...props}>
|
||||
<Picker.Item label="Sourcerer's Stone" value="book-1" />
|
||||
<Picker.Item label="Chamber of Secrets" value="book-2" />
|
||||
<Picker.Item label="Prisoner of Azkaban" value="book-3" />
|
||||
<Picker.Item label="Goblet of Fire" value="book-4" />
|
||||
<Picker.Item label="Order of the Phoenix" value="book-5" />
|
||||
<Picker.Item label="Half-Blood Prince" value="book-6" />
|
||||
<Picker.Item label="Deathly Hallows" value="book-7" />
|
||||
</Picker>
|
||||
</View>
|
||||
);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
rootl: {
|
||||
alignItems: 'flex-start'
|
||||
}
|
||||
});
|
||||
|
||||
export default PickerExample;
|
||||
26
src/components/Picker/PickerItemPropType.js
Normal file
26
src/components/Picker/PickerItemPropType.js
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) 2017-present, Nicolas Gallagher.
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import Picker from './';
|
||||
|
||||
const PickerItemPropType = (props: Object, propName: string, componentName: string) => {
|
||||
const prop = props[propName];
|
||||
let error = null;
|
||||
React.Children.forEach(prop, function(child) {
|
||||
if (child.type !== Picker.Item) {
|
||||
error = new Error('`Picker` children must be of type `Picker.Item`.');
|
||||
}
|
||||
});
|
||||
return error;
|
||||
};
|
||||
|
||||
export default PickerItemPropType;
|
||||
20
src/components/Picker/PickerStylePropTypes.js
Normal file
20
src/components/Picker/PickerStylePropTypes.js
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Copyright (c) 2017-present, Nicolas Gallagher.
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import ColorPropType from '../../propTypes/ColorPropType';
|
||||
import ViewStylePropTypes from '../View/ViewStylePropTypes';
|
||||
|
||||
const PickerStylePropTypes = {
|
||||
...ViewStylePropTypes,
|
||||
color: ColorPropType
|
||||
};
|
||||
|
||||
export default PickerStylePropTypes;
|
||||
@@ -0,0 +1,17 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`components/Picker prop "children" renders items 1`] = `
|
||||
<select
|
||||
className="rn-fontFamily-poiln3 rn-fontSize-7cikom rn-marginTop-1mnahxq rn-marginRight-61z16t rn-marginBottom-p1pxzi rn-marginLeft-11wrixw"
|
||||
onChange={[Function]}
|
||||
>
|
||||
<PickerItem
|
||||
label="label-1"
|
||||
value="value-1"
|
||||
/>
|
||||
<PickerItem
|
||||
label="label-2"
|
||||
value="value-2"
|
||||
/>
|
||||
</select>
|
||||
`;
|
||||
74
src/components/Picker/__tests__/index-test.js
Normal file
74
src/components/Picker/__tests__/index-test.js
Normal file
@@ -0,0 +1,74 @@
|
||||
/* eslint-env jasmine, jest */
|
||||
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import Picker from '..';
|
||||
|
||||
describe('components/Picker', () => {
|
||||
describe('prop "children"', () => {
|
||||
test('renders items', () => {
|
||||
const picker = (
|
||||
<Picker>
|
||||
<Picker.Item label="label-1" value="value-1" />
|
||||
<Picker.Item label="label-2" value="value-2" />
|
||||
</Picker>
|
||||
);
|
||||
const component = shallow(picker);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('prop "enabled"', () => {
|
||||
test('picker is disabled if false', () => {
|
||||
const picker = (
|
||||
<Picker enabled={false}>
|
||||
<Picker.Item label="label-1" value="value-1" />
|
||||
<Picker.Item label="label-2" value="value-2" />
|
||||
</Picker>
|
||||
);
|
||||
const component = shallow(picker);
|
||||
expect(component.find('select').props().disabled).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('prop "onValueChange"', () => {
|
||||
test('is called with (value, index)', () => {
|
||||
const onValueChange = jest.fn();
|
||||
const picker = (
|
||||
<Picker onValueChange={onValueChange} selectedValue="value-1">
|
||||
<Picker.Item label="label-1" value="value-1" />
|
||||
<Picker.Item label="label-2" value="value-2" />
|
||||
</Picker>
|
||||
);
|
||||
const component = shallow(picker);
|
||||
component.find('select').simulate('change', {
|
||||
target: { selectedIndex: '1', value: 'value-2' }
|
||||
});
|
||||
expect(onValueChange).toHaveBeenCalledWith('value-2', '1');
|
||||
});
|
||||
});
|
||||
|
||||
describe('prop "selectedValue"', () => {
|
||||
test('selects the correct item (string)', () => {
|
||||
const picker = (
|
||||
<Picker selectedValue="value-2">
|
||||
<Picker.Item label="label-1" value="value-1" />
|
||||
<Picker.Item label="label-2" value="value-2" />
|
||||
</Picker>
|
||||
);
|
||||
const component = shallow(picker);
|
||||
expect(component.find('select').prop('value')).toBe('value-2');
|
||||
});
|
||||
|
||||
test('selects the correct item (number)', () => {
|
||||
const picker = (
|
||||
<Picker selectedValue={22}>
|
||||
<Picker.Item label="label-1" value={11} />
|
||||
<Picker.Item label="label-2" value={22} />
|
||||
</Picker>
|
||||
);
|
||||
const component = shallow(picker);
|
||||
expect(component.find('select').prop('value')).toBe(22);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,114 @@
|
||||
import UnimplementedView from '../UnimplementedView';
|
||||
const Picker = UnimplementedView;
|
||||
Picker.Item = UnimplementedView;
|
||||
export default Picker;
|
||||
/**
|
||||
* Copyright (c) 2017-present, Nicolas Gallagher.
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule Picker
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import applyNativeMethods from '../../modules/applyNativeMethods';
|
||||
import { Component } from 'react';
|
||||
import ColorPropType from '../../propTypes/ColorPropType';
|
||||
import createElement from '../../modules/createElement';
|
||||
import PickerItemPropType from './PickerItemPropType';
|
||||
import PickerStylePropTypes from './PickerStylePropTypes';
|
||||
import StyleSheetPropType from '../../propTypes/StyleSheetPropType';
|
||||
import StyleSheet from '../../apis/StyleSheet';
|
||||
import TextStylePropTypes from '../Text/TextStylePropTypes';
|
||||
import { arrayOf, bool, func, number, oneOfType, string } from 'prop-types';
|
||||
|
||||
const pickerStyleType = StyleSheetPropType(PickerStylePropTypes);
|
||||
const itemStylePropType = StyleSheetPropType(TextStylePropTypes);
|
||||
|
||||
type ItemProps = {
|
||||
color?: ColorPropType,
|
||||
label: string,
|
||||
testID?: string,
|
||||
value?: number | string
|
||||
};
|
||||
|
||||
class PickerItem extends Component<ItemProps> {
|
||||
static propTypes = {
|
||||
color: ColorPropType,
|
||||
label: string.isRequired,
|
||||
testID: string,
|
||||
value: oneOfType([number, string])
|
||||
};
|
||||
|
||||
render() {
|
||||
const { label, testID, value } = this.props;
|
||||
return createElement('option', { label, testID, value });
|
||||
}
|
||||
}
|
||||
|
||||
type Props = {
|
||||
children?: Array<typeof PickerItem>,
|
||||
enabled?: boolean,
|
||||
onValueChange?: Function,
|
||||
selectedValue?: number | string,
|
||||
style?: pickerStyleType,
|
||||
testID?: string,
|
||||
/* compat */
|
||||
itemStyle?: itemStylePropType,
|
||||
mode?: string,
|
||||
prompt?: string
|
||||
};
|
||||
|
||||
class Picker extends Component<Props> {
|
||||
static propTypes = {
|
||||
children: arrayOf(PickerItemPropType),
|
||||
enabled: bool,
|
||||
onValueChange: func,
|
||||
selectedValue: oneOfType([number, string]),
|
||||
style: pickerStyleType,
|
||||
testID: string
|
||||
};
|
||||
|
||||
static Item = PickerItem;
|
||||
|
||||
render() {
|
||||
const {
|
||||
children,
|
||||
enabled,
|
||||
selectedValue,
|
||||
style,
|
||||
testID,
|
||||
/* eslint-disable */
|
||||
itemStyle,
|
||||
mode,
|
||||
prompt
|
||||
/* eslint-enable */
|
||||
} = this.props;
|
||||
|
||||
return createElement('select', {
|
||||
children,
|
||||
disabled: enabled === false ? true : undefined,
|
||||
onChange: this._handleChange,
|
||||
style: [styles.initial, style],
|
||||
testID,
|
||||
value: selectedValue
|
||||
});
|
||||
}
|
||||
|
||||
_handleChange = (e: Object) => {
|
||||
const { onValueChange } = this.props;
|
||||
const { selectedIndex, value } = e.target;
|
||||
if (onValueChange) {
|
||||
onValueChange(value, selectedIndex);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
initial: {
|
||||
fontFamily: 'inherit',
|
||||
fontSize: 'inherit',
|
||||
margin: 0
|
||||
}
|
||||
});
|
||||
|
||||
export default applyNativeMethods(Picker);
|
||||
|
||||
Reference in New Issue
Block a user