Skip to content
This repository has been archived by the owner on Mar 30, 2018. It is now read-only.

Commit

Permalink
React select fork WIP (#122)
Browse files Browse the repository at this point in the history
* update storybook

* update readme and add logo

* initial work on react-select fork

* initial import of react-select code

* fix tabs versus spaces madness

* refactor in progress

* refactoring fork

* refactoring select

* convert Select/Value to es6 class

* convert Select/Option to es6 class

* refactoring to uikit

* refactoring creation of options

* refactor styling

* wip
  • Loading branch information
stipsan committed Aug 7, 2016
1 parent 9b2e71c commit 078abf0
Show file tree
Hide file tree
Showing 14 changed files with 1,536 additions and 31 deletions.
30 changes: 10 additions & 20 deletions .eslintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,13 @@ rules:
semi:
- error
- never
react/no-danger:
- error
react/no-comment-textnodes:
- error
react/no-direct-mutation-state:
- error
react/no-string-refs:
- error
react/jsx-handler-names:
- error
react/react-in-jsx-scope:
- off
react/jsx-uses-react:
- off
react/jsx-filename-extension:
- off
import/no-extraneous-dependencies:
- off
global-require:
- off
react/no-danger: error
react/no-comment-textnodes: error
react/no-direct-mutation-state: error
react/no-string-refs: error
react/jsx-handler-names: error
react/react-in-jsx-scope: off
react/jsx-uses-react: off
react/jsx-filename-extension: off
import/no-extraneous-dependencies: off
global-require: off
1 change: 1 addition & 0 deletions .storybook/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ addDecorator(story => (
function loadStories() {
require('../src/stories/button')
require('../src/stories/dropdown')
require('../src/stories/Select')
}

configure(loadStories, module)
24 changes: 24 additions & 0 deletions .storybook/static/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions .storybook/uikit.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@ $icon-font-path: "~uikit/dist/fonts";
@import "~uikit/dist/scss/uikit-mixins.scss";
@import "~uikit/dist/scss/uikit-variables.scss";
@import "~uikit/dist/scss/uikit.scss";
@import "~uikit/dist/scss/components/autocomplete.scss";
@import "~uikit/dist/scss/components/form-advanced.scss";

@import "~uikit-react/scss/Select.scss";
9 changes: 6 additions & 3 deletions .storybook/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@ module.exports = {
},
module: {
loaders: [
{ test: /\.scss$/, loader: ExtractTextPlugin.extract(
'style-loader', 'css!postcss!sass?sourceMap'
) },
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract(
'style-loader', 'css!postcss!sass?sourceMap'
),
},
{ test: /\.css$/, loaders: ['style', 'css'] },
{ test: /\.svg$/, loader: 'url-loader?limit=10000&mimetype=image/svg+xml' },
{
Expand Down
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ uikit-react
[![Build Status](https://travis-ci.org/stipsan/uikit-react.svg)](https://travis-ci.org/stipsan/uikit-react)
[![Coverage Status](https://coveralls.io/repos/github/stipsan/uikit-react/badge.svg)](https://coveralls.io/github/stipsan/uikit-react)

<img src="https://uikit-react.firebaseapp.com/images/logo.svg" width="300"/>

# Be warned, this is barely even alpha atm!
<img src="https://uikit-react.io/logo.svg" width="256"/>

React UI component built on top of the UIkit CSS.
The docs folder shows how easy it is to setup a project that compiles the UIkit less and puts it all together using Browserify.
This library makes no assumptions how you provide the CSS, load it any way you like.
The minimum required css for components can function can be seen in the [SCSS file](.storybook/uikit.scss) we use to compile UIkit for our [Storybook](http://uikit-react.io).

Check our [Storybook](http://uikit-react.io) to see docs and usage examples on each component in the library.

A changelog.md will be started up as soon as we reach 0.1.0. Versions in the 0.0.x range is not at all meant to be used in production.
We use GitHub Releases as our [Changelog](https://github.com/stipsan/uikit-react/releases).

Inspired by
* [material ui](http://material-ui.com/)
Expand Down
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@
},
"homepage": "https://github.com/stipsan/uikit-react",
"devDependencies": {
"@kadira/react-storybook-addon-info": "3.1.1",
"@kadira/storybook": "2.0.0",
"@kadira/react-storybook-addon-info": "3.1.2",
"@kadira/storybook": "2.2.0",
"@kadira/storybook-deployer": "1.0.0",
"autoprefixer": "6.4.0",
"babel-cli": "6.11.4",
Expand Down Expand Up @@ -92,7 +92,8 @@
"url-loader": "0.5.7"
},
"dependencies": {
"classnames": "2.2.5"
"classnames": "2.2.5",
"react-input-autosize": "1.1.0"
},
"contributors": [
{
Expand Down
21 changes: 21 additions & 0 deletions src/Select/CreateOption.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import classNames from 'classnames'
import { PropTypes } from 'react'

const CreateOption = ({ isFocused, addLabelText, children }) => (
<li className={classNames({ 'uk-active': isFocused })}>
<a>
{addLabelText}&nbsp;
<span className="uk-text-bold">
{children}
</span>
</a>
</li>
)

CreateOption.propTypes = {
isFocused: PropTypes.bool.isRequired,
addLabelText: PropTypes.node.isRequired,
children: PropTypes.node.isRequired,
}

export default CreateOption
100 changes: 100 additions & 0 deletions src/Select/Option.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import classNames from 'classnames'
import { Component, PropTypes } from 'react'

export default class Option extends Component {
static propTypes = {
addLabelText: PropTypes.string, // text to display with value while creating
children: PropTypes.node,
className: PropTypes.string, // className (based on mouse position)
instancePrefix: PropTypes.string.isRequired, // unique prefix for the ids (used for aria)
isDisabled: PropTypes.bool, // the option is disabled
isFocused: PropTypes.bool, // the option is focused
isSelected: PropTypes.bool, // the option is selected
onFocus: PropTypes.func, // method to handle mouseEnter on option
onSelect: PropTypes.func, // method to handle click on option element
onUnfocus: PropTypes.func, // method to handle mouseLeave on option
option: PropTypes.object.isRequired, // object that is base for that option
optionIndex: PropTypes.number, // index of the option, used to generate
}

onFocus = (event) => {
if (!this.props.isFocused) {
this.props.onFocus(this.props.option, event)
}
}

handleBlockEvent = event => {
event.preventDefault()
event.stopPropagation()
}

handleMouseDown = (event) => {
event.preventDefault()
event.stopPropagation()
this.props.onSelect(this.props.option, event)
}

handleMouseEnter = (event) => {
this.onFocus(event)
}

handleMouseMove = (event) => {
this.onFocus(event)
}

handleTouchEnd= (event) => {
// Check if the view is being dragged, In this case
// we don't want to fire the click event (because the user only wants to scroll)
if (this.dragging) return

this.handleMouseDown(event)
}

handleTouchMove = () => {
// Set a flag that the view is being dragged
this.dragging = true
}

handleTouchStart = () => {
// Set a flag that the view is not being dragged
this.dragging = false
}

render() {
const { option, instancePrefix, optionIndex } = this.props
let className = classNames(this.props.className, option.className)
return option.disabled ? (
<li
className={className}
onMouseDown={this.handleBlockEvent}
onClick={this.handleBlockEvent}
>
<a>
{this.props.children}
</a>
</li>
) : (
<li
className={className}
style={option.style}
role="option"
onMouseDown={this.handleMouseDown}
onMouseEnter={this.handleMouseEnter}
onMouseMove={this.handleMouseMove}
onTouchStart={this.handleTouchStart}
onTouchMove={this.handleTouchMove}
onTouchEnd={this.handleTouchEnd}
id={`${instancePrefix}-option-${optionIndex}`}
title={option.title}
>
<a>
{
option.create ?
this.props.addLabelText.replace('{label}', option.label) :
this.props.children
}
</a>
</li>
)
}
}
104 changes: 104 additions & 0 deletions src/Select/Value.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import classNames from 'classnames'
import { Component, PropTypes } from 'react'

export default class Value extends Component {

static propTypes = {
children: PropTypes.node,
disabled: PropTypes.bool, // disabled prop passed to ReactSelect
id: PropTypes.string, // Unique id for the value - used for aria
onClick: PropTypes.func, // method to handle click on value label
onRemove: PropTypes.func, // method to handle removal of the value
value: PropTypes.object.isRequired, // the option object for this value
}

handleRemove = event => {
event.preventDefault()
event.stopPropagation()
this.props.onRemove(this.props.value)
}

handleMouseDown = event => {
if (event.type === 'mousedown' && event.button !== 0) {
return
}
if (this.props.onClick) {
event.stopPropagation()
this.props.onClick(this.props.value, event)
return
}
if (this.props.value.href) {
event.stopPropagation()
}
}

handleTouchEndRemove = event => {
// Check if the view is being dragged, In this case
// we don't want to fire the click event (because the user only wants to scroll)
if (this.dragging) return

// Fire the mouse events
this.onRemove(event)
}

handleTouchMove = () => {
// Set a flag that the view is being dragged
this.dragging = true
}

handleTouchStart = () => {
// Set a flag that the view is not being dragged
this.dragging = false
}

renderRemoveIcon() {
if (this.props.disabled || !this.props.onRemove) {
return false
}
return (
<span
className="Select-value-icon"
aria-hidden="true"
onMouseDown={this.handleRemove}
onTouchEnd={this.handleTouchEndRemove}
onTouchStart={this.handleTouchStart}
onTouchMove={this.handleTouchMove}
>
&times;
</span>
)
}

renderLabel() {
let className = 'Select-value-label'
return this.props.onClick || this.props.value.href ? (
<a
className={className}
href={this.props.value.href}
target={this.props.value.target}
onMouseDown={this.handleMouseDown}
onTouchEnd={this.handleMouseDown}
>
{this.props.children}
</a>
) : (
<span className={className} role="option" aria-selected="true" id={this.props.id}>
{this.props.children}
</span>
)
}

render() {
return (
<div
className={classNames('uk-component-select__value', this.props.value.className)}
style={this.props.value.style}
title={this.props.value.title}
>
{this.renderRemoveIcon()}
{this.renderLabel()}
</div>
)
}

}
Loading

0 comments on commit 078abf0

Please sign in to comment.