Skip to content

Commit

Permalink
Merge defc664 into ea8f068
Browse files Browse the repository at this point in the history
  • Loading branch information
mukiienko committed Aug 1, 2019
2 parents ea8f068 + defc664 commit 3fa1f93
Show file tree
Hide file tree
Showing 6 changed files with 663 additions and 535 deletions.
933 changes: 471 additions & 462 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
"@babel/plugin-proposal-decorators": "7.1.0",
"@babel/preset-env": "7.1.0",
"@babel/preset-react": "7.0.0",
"@sambego/storybook-state": "1.3.6",
"@storybook/addon-actions": "^5.1.8",
"@storybook/addon-console": "^1.1.0",
"@storybook/addon-info": "^5.1.8",
Expand Down
55 changes: 55 additions & 0 deletions src/packages/storybook/withStore/__tests__/withStore.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { StoreInjector } from '../withStore';

jest.mock('@storybook/addons', () => ({
getChannel: () => ({
on: () => {},
emit: () => {},
}),
}));

let withStore;

describe('Storybook|injectStore decorator', () => {
beforeEach(() => {
withStore = injectedStore => new StoreInjector().withStore(injectedStore);
});

it('should expos the puplic API', () => {
const instance = withStore();
expect(typeof instance.getStore).toBe('function');
expect(typeof instance.resetStore).toBe('function');
});

it('should return stored values', () => {
const instance = withStore({
string: 'test',
object: { a: 1 },
array: [1, 2, 3],
});
expect(instance.getStore().get('string')).toBe('test');
expect(instance.getStore().get('object')).toEqual({ a: 1 });
expect(instance.getStore().get('array')).toEqual([1, 2, 3]);
});

it('should change just changed values', () => {
const instance = withStore({
string: 'test',
number: 1,
});
instance.getStore().set({ string: 'new value' });
expect(instance.getStore().get('string')).toBe('new value');
expect(instance.getStore().get('number')).toBe(1);
});

it('should reset store to initialValues', () => {
const instance = withStore({
string: 'test',
number: 1,
});
instance.getStore().set({ string: 'new value' });
instance.getStore().set({ number: 2 });
instance.resetStore();
expect(instance.getStore().get('string')).toBe('test');
expect(instance.getStore().get('number')).toBe(1);
});
});
1 change: 1 addition & 0 deletions src/packages/storybook/withStore/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default, StoreInjector } from './withStore';
60 changes: 60 additions & 0 deletions src/packages/storybook/withStore/withStore.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import addons from '@storybook/addons'; // eslint-disable-line import/no-extraneous-dependencies
import { STORY_CHANGED, FORCE_RE_RENDER } from '@storybook/core-events'; // eslint-disable-line import/no-extraneous-dependencies
import { Store } from '@sambego/storybook-state'; // eslint-disable-line import/no-extraneous-dependencies

/**
* This decorator allows you to add store in Storybook
* For inject store use Storybook API `addParameters`
* Example: `.addParameters(injectStore({ param: 'one' }))`
*/
class StoreInjector {
/**
* Used for keep store
*/
globalStore = {};

/**
* Used for keep initial store
*/
initialStore = {};

constructor() {
const channel = addons.getChannel();
// Fired when page changed
channel.on(STORY_CHANGED, () => {
this.createStore(this.initialStore);
});
}

/**
* Used for create store
*/
createStore(injectedStore) {
this.globalStore = new Store(injectedStore);
this.globalStore.subscribe(state => {
// Enforce rerender stories when store was changed
addons.getChannel().emit(FORCE_RE_RENDER);
return state;
});
addons.getChannel().emit(FORCE_RE_RENDER);
}

/**
* Used for injected store in Storybook
*/
withStore(injectedStore) {
this.initialStore = injectedStore;
this.createStore(injectedStore);
return {
getStore: () => this.globalStore,
resetStore: () => this.createStore(injectedStore),
};
}
}

const storeInjector = new StoreInjector();

export { StoreInjector };
export default function(injectedStore) {
return storeInjector.withStore(injectedStore);
}
148 changes: 75 additions & 73 deletions stories/Autosuggest.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,20 @@ import React from 'react';
import { storiesOf } from '@storybook/react';
import { text, boolean, withKnobs } from '@storybook/addon-knobs';
import { Autosuggest, IconMatch } from '@textkernel/oneui';
import withStore from '../src/packages/storybook/withStore';
import {
SUGGESTIONS,
SUGGESTION_TO_STRING,
} from '../src/components/Autosuggest/__mocks__/suggestions';

storiesOf('Organisms|Autosuggest', module)
.addDecorator(withKnobs)
.addParameters(
withStore({
selectedSuggestions: [],
inputValue: '',
})
)
.add('Single select with icon', () => (
<Autosuggest
getSuggestions={() => SUGGESTIONS}
Expand Down Expand Up @@ -51,86 +58,81 @@ storiesOf('Organisms|Autosuggest', module)
style={{ width: '650px' }}
/>
))
.add('Example implementation', () => {
// eslint-disable-next-line react/prop-types
const Implementation = ({ style }) => {
const [selectedSuggestions, setSelectedSuggestions] = React.useState([]);
const [inputValue, setInputValue] = React.useState('');

const getSuggestions = () => {
if (!inputValue.length) return [];
return SUGGESTIONS.filter(item => !selectedSuggestions.includes(item)).filter(
item => item.name.toLocaleLowerCase().includes(inputValue.toLocaleLowerCase())
);
};

const onInputValueChange = value => {
console.log(`onInputValueChange was called with ${value}`);
setInputValue(value);
};

const getSelectedPlaceholder = () => {
const numOfItems = selectedSuggestions.length;
if (!numOfItems) {
return '';
}
.add('Example implementation', ({ parameters }) => {
const store = parameters.getStore();
const getSuggestions = () => {
if (!store.get('inputValue').length) return [];
return SUGGESTIONS.filter(
item => !store.get('selectedSuggestions').includes(item)
).filter(item =>
item.name.toLocaleLowerCase().includes(store.get('inputValue').toLocaleLowerCase())
);
};

if (numOfItems === 1) {
return SUGGESTION_TO_STRING(selectedSuggestions[0]);
}
const onInputValueChange = value => {
console.log(`onInputValueChange was called with ${value}`);
store.set({ inputValue: value });
};

return `${SUGGESTION_TO_STRING(selectedSuggestions[0])} + ${numOfItems - 1} more`;
};
const getSelectedPlaceholder = () => {
const numOfItems = store.get('selectedSuggestions').length;
if (!numOfItems) {
return '';
}

const onSelectionChange = item => {
console.log(`onSelectionChange was called with {name: ${item.name}}`);
if (selectedSuggestions.includes(item)) {
const newSelection = selectedSuggestions.filter(el => el.name !== item.name);
setSelectedSuggestions(newSelection);
} else {
setSelectedSuggestions([...selectedSuggestions, item]);
}
};
if (numOfItems === 1) {
return SUGGESTION_TO_STRING(store.get('selectedSuggestions')[0]);
}

const onBlur = () => {
console.log('onBlur was called');
setInputValue('');
};
return `${SUGGESTION_TO_STRING(store.get('selectedSuggestions')[0])} + ${numOfItems -
1} more`;
};

const onClearAllSelected = () => {
console.log('onClearAllSelected was called');
setSelectedSuggestions([]);
};
const onSelectionChange = item => {
console.log(`onSelectionChange was called with {name: ${item.name}}`);
if (store.get('selectedSuggestions').includes(item)) {
const newSelection = store
.get('selectedSuggestions')
.filter(el => el.name !== item.name);
store.set({ selectedSuggestions: newSelection });
} else {
store.set({ selectedSuggestions: [...store.get('selectedSuggestions'), item] });
}
};

return (
<Autosuggest
selectedSuggestions={
boolean('Add selectedSuggestions', true) ? selectedSuggestions : undefined
}
selectedPlaceholder={
boolean('Add selectionPlaceholder', true)
? getSelectedPlaceholder()
: undefined
}
isLoading={boolean('Loading', false)}
showClearButton={boolean('Show clear button', true)}
isMultiselect={boolean('Multiselect', true)}
isProminent={boolean('Use prominent styling', true)}
inputPlaceholder={text('Input placeholder', 'Select something...')}
noSuggestionsPlaceholder={text('No suggestions', 'No suggestions found...')}
clearTitle={text('Remove button label', 'Clear')}
getSuggestions={getSuggestions}
suggestionToString={SUGGESTION_TO_STRING}
onBlur={onBlur}
onSelectionChange={onSelectionChange}
onClearAllSelected={onClearAllSelected}
onInputValueChange={onInputValueChange}
style={style}
/>
);
const onBlur = () => {
console.log('onBlur was called');
store.set({ inputValue: '' });
};

Implementation.displayName = 'Implementation';
const onClearAllSelected = () => {
console.log('onClearAllSelected was called');
store.set({ selectedSuggestions: [] });
};

return <Implementation style={{ width: '650px' }} />;
return (
<Autosuggest
selectedSuggestions={
boolean('Add selectedSuggestions', true)
? store.get('selectedSuggestions')
: undefined
}
selectedPlaceholder={
boolean('Add selectionPlaceholder', true) ? getSelectedPlaceholder() : undefined
}
isLoading={boolean('Loading', false)}
showClearButton={boolean('Show clear button', true)}
isMultiselect={boolean('Multiselect', true)}
isProminent={boolean('Use prominent styling', true)}
inputPlaceholder={text('Input placeholder', 'Select something...')}
noSuggestionsPlaceholder={text('No suggestions', 'No suggestions found...')}
clearTitle={text('Remove button label', 'Clear')}
getSuggestions={getSuggestions}
suggestionToString={SUGGESTION_TO_STRING}
onBlur={onBlur}
onSelectionChange={onSelectionChange}
onClearAllSelected={onClearAllSelected}
onInputValueChange={onInputValueChange}
/>
);
});

0 comments on commit 3fa1f93

Please sign in to comment.