Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[List] Deprecate the valueLink property #3936

Merged
merged 2 commits into from
Apr 18, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions docs/src/app/components/AppNavDrawer.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const AppNavDrawer = React.createClass({
propTypes: {
docked: React.PropTypes.bool.isRequired,
location: React.PropTypes.object.isRequired,
onRequestChangeList: React.PropTypes.func.isRequired,
onChangeList: React.PropTypes.func.isRequired,
onRequestChangeNavDrawer: React.PropTypes.func.isRequired,
open: React.PropTypes.bool.isRequired,
style: React.PropTypes.object,
Expand Down Expand Up @@ -110,7 +110,7 @@ const AppNavDrawer = React.createClass({
location,
docked,
onRequestChangeNavDrawer,
onRequestChangeList,
onChangeList,
open,
style,
} = this.props;
Expand All @@ -126,7 +126,6 @@ const AppNavDrawer = React.createClass({
<div style={this.styles.logo} onTouchTap={this.handleTouchTapHeader}>
Material-UI
</div>

<span style={this.styles.version}>Version:</span>
<DropDownMenu
value={this.currentVersion()}
Expand All @@ -142,9 +141,9 @@ const AppNavDrawer = React.createClass({
/>
))}
</DropDownMenu>

<SelectableList
valueLink={{value: location.pathname, requestChange: onRequestChangeList}}
value={location.pathname}
onChange={onChangeList}
>
<ListItem
primaryText="Get Started"
Expand Down Expand Up @@ -253,7 +252,8 @@ const AppNavDrawer = React.createClass({
</SelectableList>
<Divider />
<SelectableList
valueLink={{value: '', requestChange: this.handleRequestChangeLink}}
value=""
onChange={this.handleRequestChangeLink}
>
<Subheader>Resources</Subheader>
<ListItem primaryText="GitHub" value="https://github.com/callemall/material-ui" />
Expand Down
4 changes: 2 additions & 2 deletions docs/src/app/components/Master.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ const Master = React.createClass({
});
},

handleRequestChangeList(event, value) {
handleChangeList(event, value) {
this.context.router.push(value);
this.setState({
navDrawerOpen: false,
Expand Down Expand Up @@ -194,7 +194,7 @@ const Master = React.createClass({
location={location}
docked={docked}
onRequestChangeNavDrawer={this.handleChangeRequestNavDrawer}
onRequestChangeList={this.handleRequestChangeList}
onChangeList={this.handleChangeList}
open={navDrawerOpen}
/>
<FullWidthSection style={styles.footer}>
Expand Down
37 changes: 23 additions & 14 deletions docs/src/app/components/pages/components/List/ExampleSelectable.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,42 @@ import Subheader from 'material-ui/Subheader';
let SelectableList = MakeSelectable(List);

function wrapState(ComposedComponent) {
const StateWrapper = React.createClass({
getInitialState() {
return {selectedIndex: 1};
},
handleUpdateSelectedIndex(event, index) {
return class SelectableList extends React.Component {
static propTypes = {
children: React.PropTypes.node.isRequired,
defaultValue: React.PropTypes.number.isRequired,
};

componentWillMount() {
this.setState({
selectedIndex: this.props.defaultValue,
});
}

handleRequestChange = (event, index) => {
this.setState({
selectedIndex: index,
});
},
};

render() {
return (
<ComposedComponent
{...this.props}
{...this.state}
valueLink={{value: this.state.selectedIndex, requestChange: this.handleUpdateSelectedIndex}}
/>
value={this.state.selectedIndex}
onChange={this.handleRequestChange}
>
{this.props.children}
</ComposedComponent>
);
},
});
return StateWrapper;
}
};
}

SelectableList = wrapState(SelectableList);

const ListExampleSelectable = () => (
<MobileTearSheet>
<SelectableList value={3}>
<SelectableList defaultValue={3}>
<Subheader>Selectable Contacts</Subheader>
<ListItem
value={1}
Expand Down
4 changes: 1 addition & 3 deletions docs/src/app/components/pages/components/List/Page.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import ListExamplePhone from './ExamplePhone';
import listExampleMessagesCode from '!raw!./ExampleMessages';
import ListExampleMessages from './ExampleMessages';
import listExampleSelectableCode from '!raw!./ExampleSelectable';
import selectableHelpText from './SelectableHelp';
import ListExampleSelectable from './ExampleSelectable';
import listCode from '!raw!material-ui/lib/List/List';
import listItemCode from '!raw!material-ui/lib/List/ListItem';
Expand All @@ -39,7 +38,7 @@ const descriptions = {
phone: '',
messages: 'Two examples showing formatted secondary text. The second example demonstrates an ' +
'[IconButton](/#/components/icon-button) with `tooltip`.',
selectable: 'The selectable list wraps List in a Higher Order Component. See below for further details.',
selectable: 'The selectable list wraps List in a Higher Order Component.',
};

const ListPage = () => (
Expand Down Expand Up @@ -109,7 +108,6 @@ const ListPage = () => (
>
<ListExampleSelectable />
</CodeExample>
<MarkdownElement text={selectableHelpText} />
<PropTypeDescription header="### List Properties" code={listCode} />
<PropTypeDescription header="### ListItem Properties" code={listItemCode} />
</div>
Expand Down
41 changes: 0 additions & 41 deletions docs/src/app/components/pages/components/List/SelectableHelp.md

This file was deleted.

72 changes: 34 additions & 38 deletions src/List/MakeSelectable.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
import React from 'react';
import {fade} from '../utils/colorManipulator';
import deprecated from '../utils/deprecatedPropType';

export const MakeSelectable = (Component) => {
const composed = React.createClass({

displayName: `Selectable${Component.displayName || Component.muiName || Component.name}`,

propTypes: {
return class extends React.Component {
static propTypes = {
children: React.PropTypes.node,
onChange: React.PropTypes.func,
selectedItemStyle: React.PropTypes.object,
valueLink: React.PropTypes.shape({
value: React.PropTypes.any,
valueLink: deprecated(React.PropTypes.shape({
value: React.PropTypes.any,
requestChange: React.PropTypes.func,
}).isRequired,
},
}), 'This property is deprecated due to his low popularity. Use the value and onChange property.'),
};

contextTypes: {
static contextTypes = {
muiTheme: React.PropTypes.object.isRequired,
},
};

getValueLink: function(props) {
getValueLink(props) {
return props.valueLink || {
value: props.value,
requestChange: props.onChange,
};
},
}

extendChild(child, styles, selectedItemStyle) {
if (child && child.type && child.type.muiName === 'ListItem') {
Expand Down Expand Up @@ -53,62 +53,58 @@ export const MakeSelectable = (Component) => {
} else {
return child;
}
},
}

isInitiallyOpen(child) {
if (child.props.initiallyOpen) {
return child.props.initiallyOpen;
}
return this.hasSelectedDescendant(false, child);
},
}

hasSelectedDescendant(previousValue, child) {
hasSelectedDescendant = (previousValue, child) => {
if (React.isValidElement(child) && child.props.nestedItems && child.props.nestedItems.length > 0) {
return child.props.nestedItems.reduce(this.hasSelectedDescendant, previousValue);
}
return previousValue || this.isChildSelected(child, this.props);
},
};

isChildSelected(child, props) {
const itemValue = this.getValueLink(props).value;
const childValue = child.props.value;
return this.getValueLink(props).value === child.props.value;
}

return (itemValue === childValue);
},

handleItemTouchTap(event, item) {
handleItemTouchTap = (event, item) => {
const valueLink = this.getValueLink(this.props);
const itemValue = item.props.value;
const menuValue = valueLink.value;
if ( itemValue !== menuValue) {

if (itemValue !== valueLink.value) {
valueLink.requestChange(event, itemValue);
}
},
};

render() {
const {children, selectedItemStyle} = this.props;
const {
children,
selectedItemStyle,
} = this.props;

this.keyIndex = 0;
let styles = {};
const styles = {};

if (!selectedItemStyle) {
const textColor = this.context.muiTheme.baseTheme.palette.textColor;
const selectedColor = fade(textColor, 0.2);
styles = {
backgroundColor: selectedColor,
};
styles.backgroundColor = fade(textColor, 0.2);
}

const newChildren = React.Children.map(children, (child) => this.extendChild(child, styles, selectedItemStyle));

return (
<Component {...this.props} {...this.state}>
{newChildren}
{React.Children.map(children, (child) => (
this.extendChild(child, styles, selectedItemStyle))
)}
</Component>
);
},
});

return composed;
}
};
};

export default MakeSelectable;
62 changes: 62 additions & 0 deletions test/browser/lists/MakeSelectable-spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/* global assert */
import React from 'react';
import List from 'List/List';
import ListItem from 'List/ListItem';
import MakeSelectable from 'List/MakeSelectable';
import injectTheme from '../fixtures/inject-theme';
import TestUtils from 'react-addons-test-utils';

describe('MakeSelectable', () => {
const testChildren = [
<ListItem
key={1}
value={1}
primaryText="Brendan Lim"
nestedItems={[
<ListItem
value={2}
primaryText="Grace Ng"
/>,
]}
/>,
<ListItem
key={3}
value={3}
primaryText="Kerem Suer"
/>,
];

it('should display the children', () => {
const SelectableList = injectTheme(MakeSelectable(List));

const render = TestUtils.renderIntoDocument(
<SelectableList>
{testChildren}
</SelectableList>
);

const nodeTree = TestUtils.scryRenderedDOMComponentsWithTag(render, 'div');
assert.equal(
nodeTree[0].innerText,
'Brendan LimGrace NgKerem Suer',
'Render the primaryText'
);
});

it('should select the right item', () => {
const SelectableList = injectTheme(MakeSelectable(List));

const render = TestUtils.renderIntoDocument(
<SelectableList value={2}>
{testChildren}
</SelectableList>
);

const nodeTree = TestUtils.scryRenderedDOMComponentsWithTag(render, 'div');
assert.equal(
nodeTree[0].firstChild.lastChild.querySelector('span').style.backgroundColor,
'rgba(0, 0, 0, 0.2)',
'Change the backgroundColor of the selected item'
);
});
});
1 change: 1 addition & 0 deletions test/karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ module.exports = function(config) {
'react/lib/ExecutionEnvironment': true,
'react/lib/ReactContext': 'window',
'text-encoding': 'window',
'react/addons': true, // For enzyme
},
},
webpackServer: {
Expand Down