Skip to content

Commit

Permalink
Feature fix : Make floating label always fixed if
Browse files Browse the repository at this point in the history
both hintText AND floatingLabel are specified.
  • Loading branch information
Sharlaan committed Jun 30, 2018
1 parent 0941e4a commit 32f3170
Show file tree
Hide file tree
Showing 7 changed files with 1,266 additions and 1,375 deletions.
39 changes: 26 additions & 13 deletions demo/src/CodeExample1.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,13 @@ class CodeExample extends Component {

handleDisable = (event, isDisabled) => this.setState({ isDisabled });

handlePlaceholder = (event, withPlaceholder) => this.setState({ withPlaceholder });

render () {
const { state11, state12, floatingLabelState, isDisabled } = this.state;
console.debug('state11', state11, '\nstate12', state12, '\nfloatingLabelState', floatingLabelState); // eslint-disable-line no-console
const { state11, state12, floatingLabelState, isDisabled, withPlaceholder } = this.state;

// eslint-disable-next-line no-console
console.debug('state11', state11, '\nstate12', state12, '\nfloatingLabelState', floatingLabelState);

return (
<section style={containerStyle}>
Expand Down Expand Up @@ -83,17 +87,26 @@ class CodeExample extends Component {
marginTop: 40,
}}
>
<SuperSelectField
name='floatingLabelState'
floatingLabel='Floating label'
value={floatingLabelState}
onChange={this.handleSelection}
style={{ minWidth: 150, margin: 10 }}
>
<div value='A'>Option A</div>
<div value='B'>Option B</div>
<div value='C'>Option C</div>
</SuperSelectField>
<article style={{ marginRight: 20 }}>
<SuperSelectField
name='floatingLabelState'
floatingLabel='Floating label'
hintText={`${withPlaceholder ? 'Some hint text' : ''}`}
value={floatingLabelState}
onChange={this.handleSelection}
style={{ minWidth: 150, margin: 10 }}
>
<div value='A'>Option A</div>
<div value='B'>Option B</div>
<div value='C'>Option C</div>
</SuperSelectField>
<Toggle
label='with Hint Text'
toggled={withPlaceholder}
onToggle={this.handlePlaceholder}
style={{ margin: 10 }}
/>
</article>

<article>
<SuperSelectField
Expand Down
20 changes: 10 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,21 +58,21 @@
},
"peerDependencies": {
"material-ui": ">= 0.17 < 1",
"react": "15.x || 16.x",
"react-dom": "15.x || 16.x"
"react": ">= 15 < 16.3",
"react-dom": ">= 15 < 16.3"
},
"devDependencies": {
"enzyme": "^3.3.0",
"enzyme-adapter-react-16": "^1.1.1",
"eslint-config-sharlaan": "^2.3.1",
"eslint-config-sharlaan": "^2.3.6",
"husky": "^0.14.3",
"lint-staged": "^7.0.4",
"material-ui": "^0.20.0",
"lint-staged": "^7.2.0",
"material-ui": "^0.20.1",
"nwb": "^0.22.0",
"prop-types": "^15.6.1",
"react": "^16.3.2",
"react-dom": "^16.3.2",
"react-router": "^4.2.0",
"react-router-dom": "^4.2.2"
"prop-types": "^15.6.2",
"react": "16.2.0",
"react-dom": "16.2.0",
"react-router": "^4.3.1",
"react-router-dom": "^4.3.1"
}
}
7 changes: 5 additions & 2 deletions src/SelectionsPresenter.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,19 @@ export default function SelectionsPresenter ({
underlineFocusStyle,
underlineStyle,
}) {
const { textField: { borderColor, floatingLabelColor, focusColor } } = muiTheme;
const {
textField: { borderColor, floatingLabelColor, focusColor },
} = muiTheme;

const isValidObject = (obj) =>
obj &&
Object.prototype.toString.call(obj) === '[object Object]' &&
Object.keys(obj).includes('value') &&
obj.value !== null;

// Condition for shrinking the floating Label
// Conditions for shrinking the floating Label
const isShrunk =
(hintText && hintText.length) ||
(Array.isArray(selectedValues) && (!!selectedValues.length || isFocused)) ||
(!Array.isArray(selectedValues) && (isValidObject(selectedValues) || (selectedValues === null && isFocused))) ||
isOpen;
Expand Down
35 changes: 22 additions & 13 deletions src/SuperSelectField.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ export default class SelectField extends Component {

static defaultProps = selectFieldDefaultProps;

componentWillReceiveProps (nextProps) {
// eslint-disable-next-line camelcase
UNSAFE_componentWillReceiveProps (nextProps) {
if (!areEqual(nextProps.value, this.state.selectedItems)) {
this.setState({ selectedItems: nextProps.value });
}
Expand Down Expand Up @@ -147,7 +148,10 @@ export default class SelectField extends Component {
const { children, autocompleteFilter } = this.props;
const fixedChildren = Array.isArray(children) ? children : [children];
const selectedItems = fixedChildren.reduce((nodes, child) => {
const { type, props: { value, label } } = child;
const {
type,
props: { value, label },
} = child;
const passesFilter = (label, value) => autocompleteFilter(this.state.searchText, label || value);
if (type !== 'optgroup' && passesFilter(label, value)) {
return nodes.concat({ value, label });
Expand Down Expand Up @@ -283,7 +287,10 @@ export default class SelectField extends Component {
} = this.props;

// Default style depending on Material-UI context (muiTheme)
const { baseTheme: { palette }, menuItem } = this.context.muiTheme;
const {
baseTheme: { palette },
menuItem,
} = this.context.muiTheme;

const mergedSelectedMenuItemStyle = {
color: menuItem.selectedTextColor,
Expand All @@ -309,7 +316,9 @@ export default class SelectField extends Component {
}
const isSelected = Array.isArray(selectedItems)
? selectedItems.some((obj) => areEqual(obj.value, childValue))
: selectedItems ? selectedItems.value === childValue : false;
: selectedItems
? selectedItems.value === childValue
: false;
const leftCheckbox = (multiple && checkPosition === 'left' && (isSelected ? checkedIcon : unCheckedIcon)) || null;
const rightCheckbox =
(multiple && checkPosition === 'right' && (isSelected ? checkedIcon : unCheckedIcon)) || null;
Expand Down Expand Up @@ -457,15 +466,15 @@ export default class SelectField extends Component {

{multiple &&
withResetSelectAllButtons && (
<header style={{ display: 'flex', alignItems: 'center' }}>
<div onClick={this.selectAll} style={{ flex: '50%' }}>
{selectAllButton}
</div>
<div onClick={this.reset} style={{ flex: '50%' }}>
{resetButton}
</div>
</header>
)}
<header style={{ display: 'flex', alignItems: 'center' }}>
<div onClick={this.selectAll} style={{ flex: '50%' }}>
{selectAllButton}
</div>
<div onClick={this.reset} style={{ flex: '50%' }}>
{resetButton}
</div>
</header>
)}

<div ref={(ref) => (this.menu = ref)} onKeyDown={this.handleMenuKeyDown} style={menuStyle}>
{menuItems.length ? (
Expand Down
79 changes: 54 additions & 25 deletions src/SuperSelectField.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,18 @@ const mountWithContext = node => mount(node, {
})
*/
const testChildren = [
<div key='0' value='1'>
<div key="0" value="1">
Test Child
</div>,
<div key='1' value='2'>
<div key="1" value="2">
Test Child
</div>,
</div>
]

const testChild = [
<div key='0' value='1'>
<div key="0" value="1">
Test Child
</div>,
</div>
]

describe('Default states, styles, and behaviors', () => {
Expand All @@ -64,26 +64,34 @@ describe('Default states, styles, and behaviors', () => {
})

it('expects the menu to open when clicked', () => {
const wrapper = shallowWithContext(<SuperSelectField>{testChildren}</SuperSelectField>)
const wrapper = shallowWithContext(
<SuperSelectField>{testChildren}</SuperSelectField>
)
wrapper.simulate('click')
expect(wrapper.find('Popover').props().open).toBe(true)
})

it('expects the menu to open when clicked even with one child', () => {
const wrapper = shallowWithContext(<SuperSelectField>{testChild}</SuperSelectField>)
const wrapper = shallowWithContext(
<SuperSelectField>{testChild}</SuperSelectField>
)
wrapper.simulate('click')
expect(wrapper.find('Popover').props().open).toBe(true)
})

it('expects the menu to render children', () => {
const wrapper = shallowWithContext(<SuperSelectField>{testChildren}</SuperSelectField>)
const wrapper = shallowWithContext(
<SuperSelectField>{testChildren}</SuperSelectField>
)
wrapper.simulate('click') // opens menu
const firstChild = wrapper.find('ListItem').first()
expect(firstChild.props().primaryText).toBe(testChildren[0])
})

it('expects the menu to render even with one child', () => {
const wrapper = shallowWithContext(<SuperSelectField>{testChild}</SuperSelectField>)
const wrapper = shallowWithContext(
<SuperSelectField>{testChild}</SuperSelectField>
)
wrapper.simulate('click') // opens menu
const firstChild = wrapper.find('ListItem').first()
expect(firstChild.props().primaryText).toBe(testChild[0])
Expand Down Expand Up @@ -130,59 +138,78 @@ describe('Children composition', () => {
describe('Autocomplete usage', () => {
it('should show if [showAutocompleteThreshold] is less than children', () => {
const wrapper = shallowWithContext(
<SuperSelectField showAutocompleteThreshold={1}>{testChildren}</SuperSelectField>
<SuperSelectField showAutocompleteThreshold={1}>
{testChildren}
</SuperSelectField>
)
wrapper.simulate('click')
const firstChild = wrapper.find('TextField')
expect(firstChild.exists()).toBe(true)
})
it('should NOT show if [showAutocompleteThreshold] is greater than children', () => {
const wrapper = shallowWithContext(
<SuperSelectField showAutocompleteThreshold={4}>{testChildren}</SuperSelectField>
<SuperSelectField showAutocompleteThreshold={4}>
{testChildren}
</SuperSelectField>
)
wrapper.simulate('click')
const firstChild = wrapper.find('TextField')
expect(firstChild.exists()).toBe(false)
})
it('should show regardless of children with [showAutocompleteThreshold="always"]', () => {
const wrapper = shallowWithContext(
<SuperSelectField showAutocompleteThreshold='always'>{testChildren}</SuperSelectField>
<SuperSelectField showAutocompleteThreshold="always">
{testChildren}
</SuperSelectField>
)
wrapper.simulate('click')
const firstChild = wrapper.find('TextField')
expect(firstChild.exists()).toBe(true)
})
it('should open Menu and Autocomplete even if no children with [showAutocompleteThreshold="always"]', () => {
const wrapper = shallowWithContext(<SuperSelectField showAutocompleteThreshold='always'>{[]}</SuperSelectField>)
const wrapper = shallowWithContext(
<SuperSelectField showAutocompleteThreshold="always">
{[]}
</SuperSelectField>
)
wrapper.simulate('click')
const firstChild = wrapper.find('Popover')
expect(firstChild.props().open).toBe(true)
})
it('should NOT open Menu if no children and [showAutocompleteThreshold={0}]', () => {
const wrapper = shallowWithContext(<SuperSelectField showAutocompleteThreshold={0}>{[]}</SuperSelectField>)
const wrapper = shallowWithContext(
<SuperSelectField showAutocompleteThreshold={0}>{[]}</SuperSelectField>
)
wrapper.simulate('click')
const firstChild = wrapper.find('Popover')
expect(firstChild.props().open).toBe(false)
})
it('should NOT show if [showAutocompleteThreshold="never"] regardless of children', () => {
const wrapper = shallowWithContext(
<SuperSelectField showAutocompleteThreshold='never'>{testChildren}</SuperSelectField>
<SuperSelectField showAutocompleteThreshold="never">
{testChildren}
</SuperSelectField>
)
wrapper.simulate('click')
const firstChild = wrapper.find('TextField')
expect(firstChild.exists()).toBe(false)
})
it('should display the default [hintTextAutocomplete]', () => {
const wrapper = shallowWithContext(
<SuperSelectField showAutocompleteThreshold='always'>{testChildren}</SuperSelectField>
<SuperSelectField showAutocompleteThreshold="always">
{testChildren}
</SuperSelectField>
)
wrapper.simulate('click')
const firstChild = wrapper.find('TextField')
expect(firstChild.props().hintText).toMatch('Type something')
})
it('should display the custom [hintTextAutocomplete]', () => {
const wrapper = shallowWithContext(
<SuperSelectField showAutocompleteThreshold='always' hintTextAutocomplete='Custom'>
<SuperSelectField
showAutocompleteThreshold="always"
hintTextAutocomplete="Custom"
>
{testChildren}
</SuperSelectField>
)
Expand All @@ -199,33 +226,35 @@ describe('Autocomplete usage', () => {
})

describe('Selections presenter', () => {
it('should display the default [hintText]', () => {
it('should display custom [hintText] properly', () => {
const wrapper = shallowWithContext(
<SuperSelectField showAutocompleteThreshold='always'>{testChildren}</SuperSelectField>
<SuperSelectField hintText="Hello There..">
{testChildren}
</SuperSelectField>
)
const selectionsPresenter = wrapper.find('SelectionsPresenter')
expect(selectionsPresenter.props().hintText).toMatch('Click me')
expect(selectionsPresenter.props().hintText).toMatch('Hello There..')
})
it('should display custom [hintText] properly', () => {
it('should always display the [hintText] when both placeholder and label are defined', () => {
const wrapper = shallowWithContext(
<SuperSelectField showAutocompleteThreshold='always' hintText='Hello There..'>
<SuperSelectField hintText="Placeholder ..." floatingLabel="Fixed Label">
{testChildren}
</SuperSelectField>
)
const selectionsPresenter = wrapper.find('SelectionsPresenter')
expect(selectionsPresenter.props().hintText).toMatch('Hello There..')
expect(selectionsPresenter.props().hintText).toMatch('Placeholder ...')
})
it('should display the default [DropDownIcon]', () => {
const wrapper = shallowWithContext(
<SuperSelectField showAutocompleteThreshold='always'>{testChildren}</SuperSelectField>
<SuperSelectField>{testChildren}</SuperSelectField>
)
const SelectionsPresenter = wrapper.find('SelectionsPresenter').dive()
const ArrowDownIcon = SelectionsPresenter.find('ArrowDownIcon').dive()
expect(ArrowDownIcon.find('NavigationArrowDropDown').length).toBe(1)
})
it('should display the custom [DropDownIcon]', () => {
const wrapper = shallowWithContext(
<SuperSelectField showAutocompleteThreshold='always' dropDownIcon={<span id='customDropDown'>></span>}>
<SuperSelectField dropDownIcon={<span id="customDropDown">></span>}>
{testChildren}
</SuperSelectField>
)
Expand Down
2 changes: 1 addition & 1 deletion src/defaultProps/selectionsPresenter.defaultProps.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export default {
errorStyle: {},
errorText: '',
hintText: 'Click me',
hintText: '',
selectionsRenderer: (values, hintText) => {
if (!values) return hintText;
const { value, label } = values;
Expand Down
Loading

0 comments on commit 32f3170

Please sign in to comment.