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 theming capability #487

Merged
merged 32 commits into from
May 3, 2019
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
ab5f8e9
Add custom theme and provider and begin implementation on components
kaytcat Apr 8, 2019
82c9354
Update autocomplete and clean up shared styles and add docs
kaytcat Apr 10, 2019
0870d1b
Update choice and combobox
kaytcat Apr 10, 2019
001427c
Update more components with theme
kaytcat Apr 15, 2019
09e7f61
Add theming to more components
kaytcat Apr 16, 2019
dc51363
Update even more components with theming
kaytcat Apr 16, 2019
60fc05a
Update the remaining components
kaytcat Apr 16, 2019
2bdd3b9
Merge branch 'master' into add-theming
kaytcat Apr 19, 2019
fc56091
Merge branch 'master' into add-theming
kaytcat Apr 19, 2019
0e03d30
Fix button and autocomplete tests
kaytcat Apr 23, 2019
25df270
Fix tests for more components
kaytcat Apr 23, 2019
0920d48
Return classname if not found
kaytcat Apr 23, 2019
70f58a7
Fix remaining tests and update final snapshots
kaytcat Apr 23, 2019
469e52e
Add test for themeProvider
kaytcat Apr 23, 2019
9258f57
Fixes
kaytcat Apr 23, 2019
d6020a4
Remove old test
kaytcat Apr 23, 2019
df2cfae
Fix linting
kaytcat Apr 23, 2019
c225255
Sonar fixes
kaytcat Apr 23, 2019
5403a85
Fix mistake
kaytcat Apr 23, 2019
78d20f6
More sonar fixes
kaytcat Apr 23, 2019
bbf3cb7
Fix linting
kaytcat Apr 23, 2019
7f7ae93
More sonar fixes
kaytcat Apr 24, 2019
9be241f
Fixes
kaytcat Apr 24, 2019
6c47738
Update snapshots
kaytcat Apr 24, 2019
c8717ee
Fix changes to combobox styles which were a mistake
kaytcat Apr 24, 2019
c62e4d8
Remove empty styles from label
kaytcat Apr 24, 2019
1d79d92
Fixes
kaytcat Apr 24, 2019
2602380
Fix linting and update snapshot
kaytcat Apr 24, 2019
987802e
Merge branch 'master' into add-theming
kaytcat May 3, 2019
57654eb
Bump major version due to major feature
kaytcat May 3, 2019
4c68953
Fix babel/storybook issues when running and building
kaytcat May 3, 2019
e3c9efe
Build docs
kaytcat May 3, 2019
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
8 changes: 8 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@
"original": "utils/params",
"replacement": "../../utils/params",
},
{
"original": "utils/theming",
"replacement": "../../utils/theming",
},
{
"original": "utils/themeContext",
"replacement": "../../utils/themeContext",
},
{
"original": "./index.scss",
"replacement": "./index.css"
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Welcome to [kununu's](https://wwww.kununu.com) collection of [React](https://fac
* Over 80% code coverage
* Frequently updated
* Wide range of form and UI components
* Themeable

<br />

Expand Down
58 changes: 58 additions & 0 deletions src/components/Autocomplete/customTheme.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
@import '~@kununu/kununu-theme-v2/scss/base/variables';

.suggestionInfo {
color: black;
font-size: 12px;
display: inline-block;
border: 1px solid black;
}

.suggestionsContainer {
box-shadow: 0 2px 10px rgba($black, .2);
font-size: 12px;
width: 80%;

@media (max-width: $screen-xs-max) {
width: auto;
border-radius: 0;
}

ul {
list-style-type: none;
margin: 0;
padding: 0;
}
}

.formControl {
box-sizing: border-box;
width: 100%;
min-height: 50px;
padding: 5px;

&:focus {
border: 1px solid $green;
box-shadow: inset 0 0 0 1px $green, inset 0 2px 1px rgba($black, .075);
outline: none;
}
}

.suggestionHighlighted {
background: black;
color: white;
cursor: pointer;

.suggestionInfo {
color: white;
}
}

.suggestionsFooter {
border-top: 1px solid $gray-base-03;
padding: 8px 12px;
}

.autocompleteContainer {
position: relative;
width: 100%;
}
193 changes: 99 additions & 94 deletions src/components/Autocomplete/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ import Autosuggest from 'react-autosuggest';
import Scroll from 'react-scroll';
import debounce from 'debounce';

import ThemeContext from 'utils/themeContext';
import themeable from 'utils/theming';
import getElementPositionY from 'utils/elementPosition';
import {queryParamsToObject} from 'utils/params';
import isMobile from 'utils/mobileDetection';


import Error from '../Error';
import sharedStyles from '../index.scss';

import styles from './index.scss';


export default class Autocomplete extends React.Component {
static propTypes = {
autoFocus: PropTypes.bool,
Expand Down Expand Up @@ -181,21 +181,6 @@ export default class Autocomplete extends React.Component {
}
}

/**
* determines which classNames should be added to the container div of
* the component
*
* @return {string} [list of classNames split by space]
*/
get containerClassNames () {
const {inputStyle, requiredLabel} = this.props;
const classNames = [sharedStyles.formGroup, sharedStyles[inputStyle]];

if (requiredLabel) classNames.push(styles.paddingTop);

return classNames.join(' ');
}

/**
* determines which classNames should be added to the label of
* the component
Expand All @@ -204,13 +189,13 @@ export default class Autocomplete extends React.Component {
*/
get labelClassNames () {
const {labelHidden} = this.props;
const classNames = [sharedStyles.controlLabel];
const classNames = ['controlLabel'];

if (labelHidden) classNames.push(sharedStyles.hidden);
if (labelHidden) classNames.push('hidden');

if (this.hasError()) classNames.push(sharedStyles.controlLabelError);
if (this.hasError()) classNames.push('controlLabelError');

return classNames.join(' ');
return classNames;
}

getSuggestions = (value) => {
Expand Down Expand Up @@ -332,7 +317,6 @@ export default class Autocomplete extends React.Component {
return (
kaytcat marked this conversation as resolved.
Show resolved Hide resolved
<div
{...containerProps}
className={styles.suggestionsContainer}
>
{children}
</div>
Expand All @@ -355,6 +339,7 @@ export default class Autocomplete extends React.Component {
label,
labelHidden,
id,
inputStyle,
isRequired,
name,
noSuggestionText,
Expand All @@ -369,83 +354,103 @@ export default class Autocomplete extends React.Component {
value,
} = this.state;

const inputProps = {
autoFocus,
className: `${sharedStyles.formControl} ${this.hasError() ? sharedStyles.formControlError : ''}`,
disabled,
id,
name,
onBlur: this.onBlur,
onChange: this.onChange,
onFocus: this.onFocus,
placeholder,
required: isRequired,
value,
};

return (
<div
ref={(node) => { this.node = node; }}
className={this.containerClassNames}
id={`${name}-container`}
>

{requiredLabel && (
<span className={`${sharedStyles.controlNote} ${sharedStyles.controlLabelRequired}`}>
{requiredLabel}
</span>
)}
<ThemeContext.Consumer>
{(context) => {
const allStyles = {
...sharedStyles,
...styles,
...context,
};

{labelHidden && (
<span className={sharedStyles.srOnly}>
{label}
</span>
)}
const theme = themeable(allStyles);

<label
className={this.labelClassNames}
htmlFor={id}
>
{label}
</label>

<div className={styles.autoCompleteContainer}>
<Autosuggest
id={id}
focusFirstSuggestion
focusInputOnSuggestionClick={!isMobile}
getSuggestionValue={this.getSuggestionValue}
inputProps={inputProps}
onSuggestionSelected={this.onSuggestionSelected}
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
renderSuggestion={this.renderSuggestion}
renderSuggestionsContainer={this.renderSuggestionsContainer}
suggestions={suggestions}
theme={styles}
/>

{isFetching && this.getSpinner()}

{hasInitialized && showNoSuggestionsText && !isFetching && !suggestions.length && value ? (
<div className={styles.suggestionsContainer}>
<ul>
<li className={styles.suggestion}>
{noSuggestionText}
</li>
</ul>
</div>
) : ''
const classNames = ['formControl'];

if (this.hasError()) {
classNames.push('formControlError');
}

{this.hasError() && (
<Error
info={error}
subInfo={errorSubInfo}
/>
)}
</div>
</div>
const inputProps = {
autoFocus,
className: theme(classNames),
disabled,
id,
name,
onBlur: this.onBlur,
onChange: this.onChange,
onFocus: this.onFocus,
placeholder,
required: isRequired,
value,
};

return (
<div
ref={(node) => { this.node = node; }}
className={theme('formGroup', inputStyle)}
id={`${name}-container`}
>

{requiredLabel && (
<span className={theme('controlNote', 'controlLabelRequired')}>
{requiredLabel}
</span>
)}

{labelHidden && (
<span className={theme('srOnly')}>
{label}
</span>
)}

<label
className={theme(...this.labelClassNames)}
htmlFor={id}
>
{label}
</label>

<div className={theme('autocompleteContainer')}>
<Autosuggest
id={id}
focusFirstSuggestion
focusInputOnSuggestionClick={!isMobile}
getSuggestionValue={this.getSuggestionValue}
inputProps={inputProps}
onSuggestionSelected={this.onSuggestionSelected}
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
renderSuggestion={this.renderSuggestion}
renderSuggestionsContainer={this.renderSuggestionsContainer}
suggestions={suggestions}
theme={allStyles}
/>

{isFetching && this.getSpinner()}

{hasInitialized && showNoSuggestionsText && !isFetching && !suggestions.length && value ? (
<div className={theme('suggestionsContainer')}>
<ul>
<li className={theme('suggestion')}>
{noSuggestionText}
</li>
</ul>
</div>
) : ''
}

{this.hasError() && (
<Error
info={error}
subInfo={errorSubInfo}
/>
)}
</div>
</div>
);
}}
</ThemeContext.Consumer>
);
}
}
Loading