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

Add a search bar to filter components #91

Merged
merged 2 commits into from
Apr 11, 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
63 changes: 57 additions & 6 deletions dist/client/ui/controls.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,29 +28,55 @@ var _react = require('react');

var _react2 = _interopRequireDefault(_react);

var _text_filter = require('./text_filter');

var _text_filter2 = _interopRequireDefault(_text_filter);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var StorybookControls = function (_React$Component) {
(0, _inherits3.default)(StorybookControls, _React$Component);

function StorybookControls() {
function StorybookControls(props) {
(0, _classCallCheck3.default)(this, StorybookControls);
return (0, _possibleConstructorReturn3.default)(this, (0, _getPrototypeOf2.default)(StorybookControls).apply(this, arguments));

var _this = (0, _possibleConstructorReturn3.default)(this, (0, _getPrototypeOf2.default)(StorybookControls).call(this, props));

_this.state = {
filterText: ''
};
return _this;
}

(0, _createClass3.default)(StorybookControls, [{
key: 'getKindNames',
value: function getKindNames() {
var _this2 = this;

var storyStore = this.props.storyStore;

if (!storyStore) {
return [];
}

return storyStore.map(function (_ref) {
var kindNames = storyStore.map(function (_ref) {
var kind = _ref.kind;
return kind;
});

var filterdKindNames = kindNames.filter(function (kind) {
var selectedKind = _this2.props.selectedKind;
var filterText = _this2.state.filterText;


if (kind === selectedKind) {
// Always keep the selected kind name
return true;
}

return kind.toLowerCase().indexOf(filterText.toLowerCase()) > -1;
});

return filterdKindNames;
}
}, {
key: 'getStories',
Expand Down Expand Up @@ -80,6 +106,16 @@ var StorybookControls = function (_React$Component) {

if (onStory) onStory(story);
}
}, {
key: 'filterStoryList',
value: function filterStoryList(filterText) {
this.setState({ filterText: filterText });
}
}, {
key: 'clearFilterText',
value: function clearFilterText() {
this.setState({ filterText: '' });
}
}, {
key: 'renderStory',
value: function renderStory(story) {
Expand Down Expand Up @@ -159,7 +195,6 @@ var StorybookControls = function (_React$Component) {

var h1WrapStyle = {
background: '#F7F7F7',
borderBottom: '1px solid #EEE',
paddingBottom: '20px',
position: 'absolute',
top: '20px',
Expand All @@ -181,10 +216,17 @@ var StorybookControls = function (_React$Component) {
margin: 0
};

var filterTextWrapStyle = {
position: 'absolute',
top: '68px',
right: '10px',
left: '20px'
};

var listStyle = {
overflowY: 'auto',
position: 'absolute',
top: '68px',
top: '108px',
right: '10px',
bottom: 0,
left: '20px'
Expand All @@ -202,6 +244,15 @@ var StorybookControls = function (_React$Component) {
'React Storybook'
)
),
_react2.default.createElement(
'div',
{ style: filterTextWrapStyle },
_react2.default.createElement(_text_filter2.default, {
filterText: this.state.filterText,
onChange: this.filterStoryList.bind(this),
onClear: this.clearFilterText.bind(this)
})
),
_react2.default.createElement(
'div',
{ style: listStyle },
Expand Down
120 changes: 120 additions & 0 deletions dist/client/ui/text_filter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
'use strict';

Object.defineProperty(exports, "__esModule", {
value: true
});

var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');

var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);

var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');

var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);

var _createClass2 = require('babel-runtime/helpers/createClass');

var _createClass3 = _interopRequireDefault(_createClass2);

var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');

var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);

var _inherits2 = require('babel-runtime/helpers/inherits');

var _inherits3 = _interopRequireDefault(_inherits2);

var _react = require('react');

var _react2 = _interopRequireDefault(_react);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var TextFilter = function (_React$Component) {
(0, _inherits3.default)(TextFilter, _React$Component);

function TextFilter() {
(0, _classCallCheck3.default)(this, TextFilter);
return (0, _possibleConstructorReturn3.default)(this, (0, _getPrototypeOf2.default)(TextFilter).apply(this, arguments));
}

(0, _createClass3.default)(TextFilter, [{
key: 'onChange',
value: function onChange(event) {
var filterText = event.target.value;
this.props.onChange(filterText);
}
}, {
key: 'render',
value: function render() {
var mainStyle = {
border: '1px solid #ECECEC',
borderRadius: 2
};

var filterTextWrapStyle = {
background: '#F7F7F7',
paddingRight: 25
};

var filterTextStyle = {
fontSize: 12,
color: '#828282',
border: 'none',
padding: 5,
display: 'block',
width: '100%',
boxSizing: 'border-box',
outline: 'none'
};

var clearButtonStyle = {
position: 'absolute',
color: '#B1B1B1',
border: 'none',
padding: 3,
width: 25,
right: 0,
top: 0,
textAlign: 'center',
boxSizing: 'border-box',
cursor: 'pointer'
};

return _react2.default.createElement(
'div',
{ style: mainStyle },
_react2.default.createElement(
'div',
{ style: filterTextWrapStyle },
_react2.default.createElement('input', {
style: filterTextStyle,
type: 'text',
placeholder: 'Filter',
name: 'filter-text',
value: this.props.filterText,
onChange: this.onChange.bind(this)
})
),
_react2.default.createElement(
'div',
{
style: clearButtonStyle,
onClick: this.props.onClear
},
'x'
)
);
}
}]);
return TextFilter;
}(_react2.default.Component);

exports.default = TextFilter;


TextFilter.propTypes = {
filterText: _react2.default.PropTypes.string,
onChange: _react2.default.PropTypes.func,
onClear: _react2.default.PropTypes.func
};
48 changes: 45 additions & 3 deletions src/client/ui/controls.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,34 @@
import React from 'react';
import TextFilter from './text_filter';

export default class StorybookControls extends React.Component {
constructor(props) {
super(props);
this.state = {
filterText: '',
};
}

getKindNames() {
const { storyStore } = this.props;
if (!storyStore) {
return [];
}
const kindNames = storyStore.map(({ kind }) => kind);

const filterdKindNames = kindNames.filter(kind => {
const { selectedKind } = this.props;
const { filterText } = this.state;

if (kind === selectedKind) {
// Always keep the selected kind name
return true;
}

return storyStore.map(({ kind }) => kind);
return kind.toLowerCase().indexOf(filterText.toLowerCase()) > -1;
});

return filterdKindNames;
}

getStories(kind) {
Expand All @@ -30,6 +51,14 @@ export default class StorybookControls extends React.Component {
if (onStory) onStory(story);
}

filterStoryList(filterText) {
this.setState({ filterText });
}

clearFilterText() {
this.setState({ filterText: '' });
}

renderStory(story) {
const { selectedStory } = this.props;
const storyStyle = {
Expand Down Expand Up @@ -102,7 +131,6 @@ export default class StorybookControls extends React.Component {

const h1WrapStyle = {
background: '#F7F7F7',
borderBottom: '1px solid #EEE',
paddingBottom: '20px',
position: 'absolute',
top: '20px',
Expand All @@ -124,10 +152,17 @@ export default class StorybookControls extends React.Component {
margin: 0,
};

const filterTextWrapStyle = {
position: 'absolute',
top: '68px',
right: '10px',
left: '20px',
};

const listStyle = {
overflowY: 'auto',
position: 'absolute',
top: '68px',
top: '108px',
right: '10px',
bottom: 0,
left: '20px',
Expand All @@ -138,6 +173,13 @@ export default class StorybookControls extends React.Component {
<div style={h1WrapStyle}>
<h3 style={h1Style}>React Storybook</h3>
</div>
<div style={filterTextWrapStyle}>
<TextFilter
filterText={this.state.filterText}
onChange={this.filterStoryList.bind(this)}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accept these events via props in the component you create as mentioned above.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do this.filterStoryList=this.filterStoryList.bind(this) in the constructor . Here it will create a different listener on every re-render.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, that's fine for specially this kind of apps since we won't render items in often. (Often means few times a sec)

And js.bind is pretty fast and React does a lot more costly stuff for virtual DOM diffing.

onClear={this.clearFilterText.bind(this)}
/>
</div>
<div style={listStyle}>
{kindNames.map(this.renderKind.bind(this))}
</div>
Expand Down
Loading