From 1994c98063c27a41797dec01f2ca9fcbe33ceab0 Mon Sep 17 00:00:00 2001 From: Israel Lavi Date: Mon, 21 May 2018 17:42:00 +0300 Subject: init commit onap ui Change-Id: I1dace78817dbba752c550c182dfea118b4a38646 Issue-ID: SDC-1350 Signed-off-by: Israel Lavi --- stories/react/Accordion.stories.js | 16 +++ stories/react/Checkbox.stories.js | 33 ++++++ stories/react/Checklist.stories.js | 65 +++++++++++ stories/react/Colors.stories.js | 53 +++++++++ stories/react/Input.stories.js | 51 +++++++++ stories/react/Modal.stories.js | 133 ++++++++++++++++++++++ stories/react/Panel.stories.js | 22 ++++ stories/react/PopupMenu.stories.js | 37 ++++++ stories/react/Radio.stories.js | 33 ++++++ stories/react/RadioGroup.stories.js | 34 ++++++ stories/react/SVGIcon.stories.js | 103 +++++++++++++++++ stories/react/Tabs.stories.js | 48 ++++++++ stories/react/Tiles.stories.js | 89 +++++++++++++++ stories/react/Typography.stories.js | 62 ++++++++++ stories/react/buttons/LinkButtons.stories.js | 49 ++++++++ stories/react/buttons/PrimaryButtons.stories.js | 49 ++++++++ stories/react/buttons/SecondaryButtons.stories.js | 49 ++++++++ stories/react/index.js | 66 +++++++++++ stories/react/utils/BeautifyHTML.js | 33 ++++++ stories/react/utils/Examples.js | 23 ++++ stories/react/utils/InsertSVGIcons.js | 15 +++ stories/react/utils/SourceToggle.js | 73 ++++++++++++ stories/react/utils/components/DropdownMenu.js | 14 +++ stories/react/utils/jsxToString.js | 74 ++++++++++++ 24 files changed, 1224 insertions(+) create mode 100644 stories/react/Accordion.stories.js create mode 100644 stories/react/Checkbox.stories.js create mode 100644 stories/react/Checklist.stories.js create mode 100644 stories/react/Colors.stories.js create mode 100644 stories/react/Input.stories.js create mode 100644 stories/react/Modal.stories.js create mode 100644 stories/react/Panel.stories.js create mode 100644 stories/react/PopupMenu.stories.js create mode 100644 stories/react/Radio.stories.js create mode 100644 stories/react/RadioGroup.stories.js create mode 100644 stories/react/SVGIcon.stories.js create mode 100644 stories/react/Tabs.stories.js create mode 100644 stories/react/Tiles.stories.js create mode 100644 stories/react/Typography.stories.js create mode 100644 stories/react/buttons/LinkButtons.stories.js create mode 100644 stories/react/buttons/PrimaryButtons.stories.js create mode 100644 stories/react/buttons/SecondaryButtons.stories.js create mode 100644 stories/react/index.js create mode 100644 stories/react/utils/BeautifyHTML.js create mode 100644 stories/react/utils/Examples.js create mode 100644 stories/react/utils/InsertSVGIcons.js create mode 100644 stories/react/utils/SourceToggle.js create mode 100644 stories/react/utils/components/DropdownMenu.js create mode 100644 stories/react/utils/jsxToString.js (limited to 'stories/react') diff --git a/stories/react/Accordion.stories.js b/stories/react/Accordion.stories.js new file mode 100644 index 0000000..85fdae3 --- /dev/null +++ b/stories/react/Accordion.stories.js @@ -0,0 +1,16 @@ +import React from 'react'; +import Examples from './utils/Examples.js'; +import Accordion from '../../src/react/Accordion.js'; +import HTMLBasic from '../../components/accordion/accordion-basic.html'; +let examples = { + Basic: { + jsx:
Accordion body
, + html: HTMLBasic + } +}; + +const Checkboxes = () => ( + +); + +export default Checkboxes; diff --git a/stories/react/Checkbox.stories.js b/stories/react/Checkbox.stories.js new file mode 100644 index 0000000..3fb3ad1 --- /dev/null +++ b/stories/react/Checkbox.stories.js @@ -0,0 +1,33 @@ +import React from 'react'; +import Examples from './utils/Examples.js'; + +import Checkbox from '../../src/react/Checkbox'; +import HTMLCheckboxChecked from '../../components/checkbox/checkbox-checked.html'; +import HTMLCheckboxUnchecked from '../../components/checkbox/checkbox-unchecked.html'; +import HTMLCheckboxDisabled from '../../components/checkbox/checkbox-disabled.html'; +import HTMLCheckboxDisabledChecked from '../../components/checkbox/checkbox-disabled-checked.html'; + +let examples = { + Checked: { + jsx: {}} data-test-id='mycheckbox-1' inputRef={() => {} } />, + html: HTMLCheckboxChecked + }, + Unchecked: { + jsx: {}} data-test-id='mycheckbox-2' inputRef={() => {} } />, + html: HTMLCheckboxUnchecked + }, + Disabled: { + jsx: {}} data-test-id='mycheckbox-4' inputRef={() => {} } />, + html: HTMLCheckboxDisabled + }, + 'Disabled and Checked': { + jsx: {}} data-test-id='mycheckbox-4' inputRef={() => {} } />, + html: HTMLCheckboxDisabledChecked + } +}; + +const Checkboxes = () => ( + +); + +export default Checkboxes; diff --git a/stories/react/Checklist.stories.js b/stories/react/Checklist.stories.js new file mode 100644 index 0000000..0fd089b --- /dev/null +++ b/stories/react/Checklist.stories.js @@ -0,0 +1,65 @@ +import React from 'react'; +import Examples from './utils/Examples.js'; +import Checklist from '../../src/react/Checklist.js'; +import HTMLListChecked from '../../components/checklist/checklist-with-checked-items.html'; +import HTMLListDisabled from '../../components/checklist/checklist-with-disabled-items.html'; +const items = [ + { + label: 'apple', + value: 'apple', + dataTestId: 'apple', + checked: true + }, + { + label: 'banana', + value: 'banana', + dataTestId: 'banana', + checked: false + }, + { + label: 'orange', + value: 'orange', + dataTestId: 'orange', + checked: true + } +]; + +const itemsDisabled = [ + { + label: 'apple', + value: 'apple', + dataTestId: 'apple', + checked: true, + disabled: true + }, + { + label: 'banana', + value: 'banana', + dataTestId: 'banana', + checked: false, + disabled: true + }, + { + label: 'orange', + value: 'orange', + dataTestId: 'orange', + checked: false + } +]; + +let examples = { + Basic: { + jsx: { }} />, + html: HTMLListChecked + }, + Disabled: { + jsx: { }} />, + html: HTMLListDisabled + } +}; + +const ChecklistStory = () => ( + +); + +export default ChecklistStory; \ No newline at end of file diff --git a/stories/react/Colors.stories.js b/stories/react/Colors.stories.js new file mode 100644 index 0000000..d6758ce --- /dev/null +++ b/stories/react/Colors.stories.js @@ -0,0 +1,53 @@ +import React, {Component} from 'react'; + +const colorMap = { + '$white': '#ffffff', + '$blue': '#009fdb', + '$light-blue': '#1eb9f3', + '$lighter-blue': '#e6f6fb', + '$blue-disabled': '#9dd9ef', + '$dark-blue': '#0568ae', + '$black': '#000000', + '$rich-black': '#323943', + '$text-black': '#191919', + '$dark-gray': '#5a5a5a', + '$gray': '#959595', + '$light-gray': '#d2d2d2', + '$silver': '#eaeaea', + '$light-silver': '#f2f2f2', + '$green': '#4ca90c', + '$functional-red': '#cf2a2a', + '$yellow': '#ffb81c', + '$dark-purple': '#702f8a', + '$purple': '#9063cd', + '$light-purple': '#caa2dd' +}; + +function Color({colorName, colorValue}) { + return ( +
+
+
{colorName.replace('$', '')}
+
{colorValue}
+
+ ); +} + +class Colors extends Component { + + render() { + return ( +
+

Colors Palette

+
+ { + Object.keys(colorMap).map(colorName => ) + } +
+
+ ); + } + +} + +export default Colors; diff --git a/stories/react/Input.stories.js b/stories/react/Input.stories.js new file mode 100644 index 0000000..869bafa --- /dev/null +++ b/stories/react/Input.stories.js @@ -0,0 +1,51 @@ +import React from 'react'; +import { action } from '@storybook/addon-actions'; +import Examples from './utils/Examples.js'; + +import ReactInput from '../../src/react/Input.js'; + +import InputDefaultHtml from '../../components/input/input.html'; +import InputRequiredHtml from '../../components/input/input-required.html'; +import InputNumberHtml from '../../components/input/input-number.html'; +import InputViewOnlyHtml from '../../components/input/input-view-only.html'; +import InputDisabledHtml from '../../components/input/input-disabled.html'; +import InputPlaceholderHtml from '../../components/input/input-placeholder.html'; +import InputErrorHtml from '../../components/input/input-error.html'; + +let examples = { + 'Input Default': { + jsx: , + html: InputDefaultHtml + }, + 'Input Required': { + jsx: , + html: InputRequiredHtml + }, + 'Input Number': { + jsx: , + html: InputNumberHtml + }, + 'Input View Only': { + jsx: , + html: InputViewOnlyHtml + }, + 'Input Disabled': { + jsx: , + html: InputDisabledHtml + }, + 'Input Placeholder': { + jsx: , + html: InputPlaceholderHtml + }, + 'Input Error': { + jsx: , + html: InputErrorHtml + } + +} + +const Inputs = () => ( + +); + +export default Inputs; diff --git a/stories/react/Modal.stories.js b/stories/react/Modal.stories.js new file mode 100644 index 0000000..29ff7a5 --- /dev/null +++ b/stories/react/Modal.stories.js @@ -0,0 +1,133 @@ +import React from 'react'; +import Examples from './utils/Examples.js'; +import Button from '../../src/react/Button.js'; +import Modal from '../../src/react/Modal.js'; +import Input from '../../src/react/Input.js'; +import HTMLStandardModal from '../../components/modal/standard-modal.html'; +import HTMLAlertModal from '../../components/modal/alert-modal.html'; +import HTMLErrorModal from '../../components/modal/error-modal.html'; +import HTMLCustomModal from '../../components/modal/custom-modal.html'; + +class Example extends React.Component { + constructor(props) { + super(props); + this.state = { + show: false + }; + } + render() { + const { children } = this.props; + const { show } = this.state; + var childrenWithProps = React.Children.map(children, child => { + let childChildrenWithProps = []; + if (child.props.children) { + let childChildren = child.props.children; + childChildrenWithProps = React.Children.map(childChildren, child => + React.cloneElement(child, { onClose: ()=>this.setState({show: !show}) })); + + } + return React.cloneElement(child, { show: this.state.show, onClose: ()=>this.setState({show: !show}), children: childChildrenWithProps}); + } + ); + + return ( +
+ + {childrenWithProps} +
+ ); + } +} + +const ModalBody = () => { + return ( +
+ + + + +
); +}; + +const BODY_TEXT = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed risus nisl, egestas vitae erat non,' + + 'pulvinar lacinia libero. Integer pulvinar pellentesque accumsan. Sed hendrerit lacus eu tempus pharetra'; + +const isShown = false; + +let examples = { + Standard: { + jsx: + isShown()} size='small'> + Standard Modal + + {BODY_TEXT} + + {}}/> + + , + html: HTMLStandardModal, + exclude: 'Example', + renderFromJsx: true + }, + Alert: { + jsx: + isShown()} type='alert' size='small'> + Title + + {BODY_TEXT} + + + + , + html: HTMLAlertModal, + exclude: 'Example', + renderFromJsx: true + }, + Error: { + jsx: + isShown()} size='small' type='error'> + isShown(false)} type='error'>Title + + {BODY_TEXT} + + isShown(false)} closeButtonText='Ok'/> + + , + html: HTMLErrorModal, + exclude: 'Example', + renderFromJsx: true + }, + + Custom: { + jsx: + isShown()} type='custom'> + Title + + + + {}}/> + + , + html: HTMLCustomModal, + exclude: 'Example', + renderFromJsx: true + } +}; + +const Modals = () => ( + +); + +export default Modals; \ No newline at end of file diff --git a/stories/react/Panel.stories.js b/stories/react/Panel.stories.js new file mode 100644 index 0000000..f87eefb --- /dev/null +++ b/stories/react/Panel.stories.js @@ -0,0 +1,22 @@ +import React from 'react'; +import Examples from './utils/Examples.js'; +import Panel from '../../src/react/Panel.js'; +import Checkbox from '../../src/react/Checkbox.js'; +import HTMLBasic from '../../components/panel/basic-panel.html'; +let examples = { + Basic: { + jsx: + +

Panel

+ + +
, + html: HTMLBasic + } +}; + +const PanelStory = () => ( + +); + +export default PanelStory; diff --git a/stories/react/PopupMenu.stories.js b/stories/react/PopupMenu.stories.js new file mode 100644 index 0000000..9d94522 --- /dev/null +++ b/stories/react/PopupMenu.stories.js @@ -0,0 +1,37 @@ + +import React from 'react'; +import Examples from './utils/Examples.js'; +import PopupMenu from '../../src/react/PopupMenu.js'; +import PopupMenuItem from '../../src/react/PopupMenuItem.js'; +import HTMLPopupMenu from '../../components/menu/popup-menu.html'; +import HTMLPopupMenuRelative from '../../components/menu/relative-popup-menu.html'; + +let examples = { + 'Basic popup menu (static)': { + jsx: {}}> + + + + + + , + html: HTMLPopupMenu + }, + 'Basic popup menu (relative)': { + jsx:
+ {}} position={{x: 10, y: 10}} relative> + + + + + +
, + html: HTMLPopupMenuRelative + } +}; + +const PopupMenuReactComponent = () => ( + +); + +export default PopupMenuReactComponent; \ No newline at end of file diff --git a/stories/react/Radio.stories.js b/stories/react/Radio.stories.js new file mode 100644 index 0000000..151f947 --- /dev/null +++ b/stories/react/Radio.stories.js @@ -0,0 +1,33 @@ +import React from 'react'; +import Examples from './utils/Examples.js'; + +import Radio from '../../src/react/Radio'; +import HTMLRadioChecked from '../../components/radio/radio-checked.html'; +import HTMLRadioUnchecked from '../../components/radio/radio-unchecked.html'; +import HTMLRadioDisabled from '../../components/radio/radio-disabled.html'; +import HTMLRadioDisabledChecked from '../../components/radio/radio-disabled-checked.html'; + +let examples = { + Checked: { + jsx: {}} data-test-id='myradio-1' inputRef={() => {} } />, + html: HTMLRadioChecked + }, + Unchecked: { + jsx: {}} data-test-id='myradio-2' inputRef={() => {} } />, + html: HTMLRadioUnchecked + }, + Disabled: { + jsx: {}} data-test-id='myradio-4' inputRef={() => {} } />, + html: HTMLRadioDisabled + }, + 'Disabled and Checked': { + jsx: {}} data-test-id='myradio-4' inputRef={() => {} } />, + html: HTMLRadioDisabledChecked + } +}; + +const Radios = () => ( + +); + +export default Radios; diff --git a/stories/react/RadioGroup.stories.js b/stories/react/RadioGroup.stories.js new file mode 100644 index 0000000..912f9b9 --- /dev/null +++ b/stories/react/RadioGroup.stories.js @@ -0,0 +1,34 @@ +import React from 'react'; +import Examples from './utils/Examples.js'; + +import RadioGroup from '../../src/react/RadioGroup'; +import HTMLRadioGroup from '../../components/radioGroup/radio-group.html'; +import HTMLRadioGroupValue from '../../components/radioGroup/radio-group-value.html'; +import HTMLRadioGroupDisabled from '../../components/radioGroup/radio-group-disabled.html'; +import HTMLRadioGroupNoTitle from '../../components/radioGroup/radio-group-no-title.html'; + +let examples = { + 'Value': { + jsx: {}} data-test-id='grp2' options={[{value: '1', label: 'option 1'}, {value: '2', label: 'option 2'}]} />, + html: HTMLRadioGroupValue + }, + 'No Value': { + jsx: {}} data-test-id='grp3' options={[{value: '1', label: 'option 1'}, {value: '2', label: 'option 2'}]} />, + html: HTMLRadioGroup + }, + 'Disabled': { + jsx: {}} data-test-id='grp4' options={[{value: '1', label: 'option 1'}, {value: '2', label: 'option 2'}]} />, + html: HTMLRadioGroupDisabled + }, + 'No title': { + jsx: {}} data-test-id='grp4' options={[{value: '1', label: 'option 1'}, {value: '2', label: 'option 2'}]} />, + html: HTMLRadioGroupNoTitle + } + +}; + +const RadioGroups = () => ( + +); + +export default RadioGroups; diff --git a/stories/react/SVGIcon.stories.js b/stories/react/SVGIcon.stories.js new file mode 100644 index 0000000..2c2ffc2 --- /dev/null +++ b/stories/react/SVGIcon.stories.js @@ -0,0 +1,103 @@ +import React from 'react'; +import Examples from './utils/Examples.js'; +import DropdownMenu from './utils/components/DropdownMenu.js'; +import SVGIcon from '../../src/react/SVGIcon.js'; + +const iconLabelPositions = [ + '', 'bottom', 'top', 'left', 'right' +]; + +const iconColors = [ + '', + 'primary', + 'secondary', + 'positive', + 'negative', + 'warning' +]; + +const disabledStates = ['false', 'true']; + +function buildExamples({iconName, iconLabel, labelPosition, color, disabled}) { + return { + Example: { + jsx: + } + }; +} + +const IconTable = ({onClick}) => ( +
+ {ICON_NAMES.map(icon => ( +
+ onClick(icon)} + label={icon} + iconClassName='storybook-small' + name={icon} /> +
+ ))} +
+); + +class Icons extends React.Component { + constructor(props) { + super(props); + this.state = { + iconName: ICON_NAMES[0], + iconLabel: '', + labelPosition: iconLabelPositions[0], + color : iconColors[0] + }; + } + + render() { + let {iconName, iconLabel, labelPosition, color, disabled} = this.state; + return ( +
+

Icons

+
+ this.setState({iconName: e.target.value})} + options={ICON_NAMES} /> +
+ + this.setState({iconLabel: e.target.value})}/> +
+ this.setState({labelPosition: e.target.value})} + options={iconLabelPositions} /> + this.setState({color: e.target.value})} + options={iconColors} /> + this.setState({disabled: e.target.value})} + options={disabledStates} /> +
+ + this.setState({iconName: icon})} /> +
+
You will see the following if the icon name you used is not found:
+ {}} + name='MissingIcon' /> +
+
+ ); + }; +} + +export default Icons; diff --git a/stories/react/Tabs.stories.js b/stories/react/Tabs.stories.js new file mode 100644 index 0000000..74f163c --- /dev/null +++ b/stories/react/Tabs.stories.js @@ -0,0 +1,48 @@ +import React from 'react'; +import Examples from './utils/Examples.js'; +import {default as TabsComp} from '../../src/react/Tabs.js'; +import Tab from '../../src/react/Tab.js'; +import HTMLTabsHeader from '../../components/tabs/tabs-header.html'; +import HTMLTabsDisabled from '../../components/tabs/tabs-disabled.html'; +import HTMLTabsMenu from '../../components/tabs/tabs-menu.html'; + +let examples = { + 'Menu Tabs': { + jsx: {console.log(tabId);}}> + +
This is the active tab content
+
+ + +
, + html: HTMLTabsMenu + }, + 'Header Tabs': { + jsx: {console.log(tabId);}}> + +
This is the active tab content
+
+ + +
, + html: HTMLTabsHeader + }, + 'Disabled Tabs': { + jsx: ( + {console.log(tabId);}}> + +
This is the active tab content
+
+ + +
+ ), + html: HTMLTabsDisabled + } +}; + +const Tabs = () => ( + +); + +export default Tabs; diff --git a/stories/react/Tiles.stories.js b/stories/react/Tiles.stories.js new file mode 100644 index 0000000..04a6fb5 --- /dev/null +++ b/stories/react/Tiles.stories.js @@ -0,0 +1,89 @@ +import React from 'react'; + +import Examples from './utils/Examples.js'; +import SVGIcon from '../../src/react/SVGIcon.js'; +import Button from '../../src/react/Button.js'; + +import Tile from '../../src/react/Tile.js'; +import TileInfo from '../../src/react/TileInfo.js'; +import TileInfoLine from '../../src/react/TileInfoLine.js'; +import TileFooter from '../../src/react/TileFooter.js'; +import TileFooterCell from '../../src/react/TileFooterCell.js'; + +import HTMLTileWithoutFooter from '../../components/tile/tile-without-footer.html'; +import HTMLVspTile from '../../components/tile/vsp-tile.html'; +import HTMLVlmTile from '../../components/tile/vlm-tile.html'; +import HTMLVendorTile from '../../components/tile/vendor-tile.html'; +import HTMLVfcTile from '../../components/tile/vfc-tile.html'; + +let examples = { + 'Without footer': { + jsx: + + Supertitle + Title + + , + html: HTMLTileWithoutFooter + }, + VFC: { + jsx: + + Title + V 1.0 + + + Certified + + , + html: HTMLVfcTile + }, + VSP: { + jsx: + + VLM + VSP name + + + Draft + + , + html: HTMLVspTile + }, + VLM: { + jsx: + + VLM name + + + Certified + + + + + , + html: HTMLVlmTile + }, + Vendor: { + jsx: + + Vendor name + + + + + + + + + + , + html: HTMLVendorTile + }, +}; + +const Tiles = () => ( + +); + +export default Tiles; diff --git a/stories/react/Typography.stories.js b/stories/react/Typography.stories.js new file mode 100644 index 0000000..f1475c6 --- /dev/null +++ b/stories/react/Typography.stories.js @@ -0,0 +1,62 @@ +import React, {Component} from 'react'; + +const typos = [ + {className: 'heading-1', size: 28, text: 'Major Section Heading'}, + {className: 'heading-2', size: 24, text: 'Sub-Section Heading'}, + {className: 'heading-3', size: 20, text: 'Small Heading'}, + {className: 'heading-4', size: 16, text: 'Small Heading'}, + {className: 'heading-4-emphasis', size: 16, text: 'Small Heading'}, + {className: 'heading-5', size: 14, text: 'Small Heading'}, + {className: 'body-1', size: 14, text: 'Body (Standard) Text'}, + {className: 'body-1-italic', size: 14, text: 'Body (Standard) Text'}, + {className: 'body-2', size: 13, text: 'Text in Tables'}, + {className: 'body-2-emphasis', size: 13, text: 'Text in Tables'}, + {className: 'body-3', size: 12, text: 'Input Labels, Table Titles'}, + {className: 'body-3-emphasis', size: 12, text: 'Even Smaller Text'}, + {className: 'body-4', size: 10, text: 'Even Much Smaller Text'} +]; + +const fontWeights = ['OpenSans Regular 400', 'OpenSans Semibold 600']; + +function TextRow({className, size, text}) { + return ( +
+
{className}
+
{size}px
+
{text}
+
+ ); +} + +class Typography extends Component { + + render() { + return ( +
+

Typography

+
+

Font Family

+
    +
  • OpenSans
  • +
  • Arial
  • +
  • sans-serif
  • +
+
+
+

Font Weights

+
    {fontWeights.map(font =>
  • {font}
  • )}
+
+
+

Font Size

+
+ + {typos.map(typo => )} +
+
+
+ ); + } + +} + +export default Typography; diff --git a/stories/react/buttons/LinkButtons.stories.js b/stories/react/buttons/LinkButtons.stories.js new file mode 100644 index 0000000..ef32a22 --- /dev/null +++ b/stories/react/buttons/LinkButtons.stories.js @@ -0,0 +1,49 @@ +import React from 'react'; +import Examples from '../utils/Examples.js'; + +import ReactButton from '../../../src/react/Button.js'; + +import LinkButton from '../../../components/button/button-link.html'; +import LinkButtonDisabled from '../../../components/button/button-link-disabled.html'; +import ExtraSmall from '../../../components/button/button-link-extra-small.html'; +import Small from '../../../components/button/button-link-small.html'; +import Medium from '../../../components/button/button-link-medium.html'; +import Large from '../../../components/button/button-link-large.html'; +import Auto from '../../../components/button/button-link-auto.html'; + +let examples = { + 'Link Default': { + jsx: {}}>Click Me, + html: LinkButton + }, + 'Link Disabled': { + jsx: {}} disabled>Click Me, + html: LinkButtonDisabled, + }, + 'Extra Small': { + jsx: {}}>Click Me, + html: ExtraSmall + }, + 'Small': { + jsx: {}}>Click Me, + html: Small, + }, + 'Medium': { + jsx: {}}>Click Me, + html: Medium + }, + 'Large': { + jsx: {}}>Click Me, + html: Large, + }, + 'Auto Sizing': { + jsx: {}}>Click Me, + html: Auto, + } +}; + +const DefaultButtons = () => ( + +); + +export default DefaultButtons; diff --git a/stories/react/buttons/PrimaryButtons.stories.js b/stories/react/buttons/PrimaryButtons.stories.js new file mode 100644 index 0000000..db732b9 --- /dev/null +++ b/stories/react/buttons/PrimaryButtons.stories.js @@ -0,0 +1,49 @@ +import React from 'react'; +import Examples from '../utils/Examples.js'; + +import ReactButton from '../../../src/react/Button.js'; + +import PrimaryButton from '../../../components/button/button-primary.html'; +import PrimaryButtonDisabled from '../../../components/button/button-primary-disabled.html'; +import ExtraSmall from '../../../components/button/button-primary-extra-small.html'; +import Small from '../../../components/button/button-primary-small.html'; +import Medium from '../../../components/button/button-primary-medium.html'; +import Large from '../../../components/button/button-primary-large.html'; +import Auto from '../../../components/button/button-primary-auto.html'; + +let examples = { + 'Primary Default': { + jsx: {}}>Click Me, + html: PrimaryButton + }, + 'Primary Disabled': { + jsx: {}} disabled>Click Me, + html: PrimaryButtonDisabled, + }, + 'Extra Small': { + jsx: {}}>Click Me, + html: ExtraSmall + }, + 'Small': { + jsx: {}}>Click Me, + html: Small, + }, + 'Medium': { + jsx: {}}>Click Me, + html: Medium + }, + 'Large': { + jsx: {}}>Click Me, + html: Large, + }, + 'Auto Sizing': { + jsx: {}}>Click Me, + html: Auto, + } +}; + +const DefaultButtons = () => ( + +); + +export default DefaultButtons; diff --git a/stories/react/buttons/SecondaryButtons.stories.js b/stories/react/buttons/SecondaryButtons.stories.js new file mode 100644 index 0000000..75f9d54 --- /dev/null +++ b/stories/react/buttons/SecondaryButtons.stories.js @@ -0,0 +1,49 @@ +import React from 'react'; +import Examples from '../utils/Examples.js'; + +import ReactButton from '../../../src/react/Button.js'; + +import SecondaryButton from '../../../components/button/button-secondary.html'; +import SecondaryButtonDisabled from '../../../components/button/button-secondary-disabled.html'; +import ExtraSmall from '../../../components/button/button-secondary-extra-small.html'; +import Small from '../../../components/button/button-secondary-small.html'; +import Medium from '../../../components/button/button-secondary-medium.html'; +import Large from '../../../components/button/button-secondary-large.html'; +import Auto from '../../../components/button/button-secondary-auto.html'; + +let examples = { + 'Secondary Default': { + jsx: {}}>Click Me, + html: SecondaryButton + }, + 'Secondary Disabled': { + jsx: {}} disabled>Click Me, + html: SecondaryButtonDisabled, + }, + 'Extra Small': { + jsx: {}}>Click Me, + html: ExtraSmall + }, + 'Small': { + jsx: {}}>Click Me, + html: Small, + }, + 'Medium': { + jsx: {}}>Click Me, + html: Medium + }, + 'Large': { + jsx: {}}>Click Me, + html: Large, + }, + 'Auto Sizing': { + jsx: {}}>Click Me, + html: Auto, + } +}; + +const DefaultButtons = () => ( + +); + +export default DefaultButtons; diff --git a/stories/react/index.js b/stories/react/index.js new file mode 100644 index 0000000..6d425ba --- /dev/null +++ b/stories/react/index.js @@ -0,0 +1,66 @@ +import React from 'react'; +import { storiesOf } from '@storybook/react'; + +import PrimaryButtons from './buttons/PrimaryButtons.stories.js'; +import SecondaryButtons from './buttons/SecondaryButtons.stories.js'; +import LinkButtons from './buttons/LinkButtons.stories.js'; + +import Colors from './Colors.stories.js'; +import Typography from './Typography.stories.js'; +import Checkboxes from './Checkbox.stories.js'; +import Checklist from './Checklist.stories.js'; +import Input from './Input.stories.js'; +import Icons from './SVGIcon.stories.js'; +import Tiles from './Tiles.stories.js'; +import Tabs from './Tabs.stories.js'; +import Radios from './Radio.stories.js'; +import RadioGroups from './RadioGroup.stories.js'; +import Modals from './Modal.stories.js'; +import PopupMenu from './PopupMenu.stories.js'; +import Accordion from './Accordion.stories.js'; +import Panel from './Panel.stories.js'; + +storiesOf('Colors', module) + .add('Color Palette', () => ); + +storiesOf('Typography', module) + .add('Typography', () => ); + +storiesOf('Accordion', module) + .add('Accordion', () => ); + +storiesOf('Buttons', module) + .add('Primary', () => ) + .add('Secondary', () => ) + .add('Link', () => ); + +storiesOf('Checkboxes', module) + .add('Checkboxes', () => ); + +storiesOf('Checklist', module) + .add('Checklist', () => ); + +storiesOf('Input Fields', module) + .add('Input Text', () => ); + +storiesOf('Icons', module) + .add('SVG Icons', () => ); + +storiesOf('Menu', module) + .add('Popup Menu', () => ); + +storiesOf('Modals', module) + .add('Modal examples', () => ); + +storiesOf('Radios', module) + .add('Radio Buttons', () => ) + .add('Radio Button Groups', () => ); + +storiesOf('Panel', module) + .add('Panel', () => ); + +storiesOf('Tabs', module) + .add('Tabs', () => ); + +storiesOf('Tiles', module) + .add('Tiles', () => ); diff --git a/stories/react/utils/BeautifyHTML.js b/stories/react/utils/BeautifyHTML.js new file mode 100644 index 0000000..1a29b00 --- /dev/null +++ b/stories/react/utils/BeautifyHTML.js @@ -0,0 +1,33 @@ +export default function beautifyHTML({html, indentChar = ' ', startingIndentCount = 0}) { + html = html.replace(/[ ]{2,}/g, ' '); + + let result = '', indentCount = startingIndentCount, parsingText = false; + for (let i = 0; i < html.length; i++) { + + let startOfTag, endOfTag, closingTag, upcomingTag, afterTag, numTabs; + if (html[i] === '<') { startOfTag = true; } + else if (html[i] === '>') { endOfTag = true; } + else if (html[i - 1] === '>') { afterTag = true; } + if (html[i + 1] === '/') { closingTag = true; } + else if (html[i + 1 ] === '<') { upcomingTag = true; } + + if (startOfTag) { + if (closingTag) { numTabs = --indentCount; } + else { numTabs = indentCount++; } + } + + if (parsingText && afterTag) { + numTabs = indentCount; + } + + result += indentChar.repeat(numTabs) + html[i]; + + if (endOfTag || parsingText && upcomingTag) { + result += '\n'; + parsingText = false; + if (!upcomingTag) { parsingText = true; } + } + } + + return result.slice(0, -1); +} diff --git a/stories/react/utils/Examples.js b/stories/react/utils/Examples.js new file mode 100644 index 0000000..5948b68 --- /dev/null +++ b/stories/react/utils/Examples.js @@ -0,0 +1,23 @@ +import React from 'react'; +import {renderToStaticMarkup} from 'react-dom/server'; +import SourceToggle from './SourceToggle.js'; +import beautifyHTML from './BeautifyHTML.js'; +import insertSVGIcons from './InsertSVGIcons.js'; + +const Examples = ({examples}) => ( +
+ {Object.keys(examples).map(key => { + let title = key; + let {jsx, html, displayTitle = true, exclude, renderFromJsx = false} = examples[key]; + if (!html) { + html = renderToStaticMarkup(jsx); + html = beautifyHTML({html, indentChar: ' '}); + } else { + html = insertSVGIcons({html, jsx}); + } + return ; + })} +
+); + +export default Examples; diff --git a/stories/react/utils/InsertSVGIcons.js b/stories/react/utils/InsertSVGIcons.js new file mode 100644 index 0000000..5a5e390 --- /dev/null +++ b/stories/react/utils/InsertSVGIcons.js @@ -0,0 +1,15 @@ +import {renderToStaticMarkup} from 'react-dom/server'; +import beautifyHTML from './BeautifyHTML.js'; + +const insertSVGIcons = ({html, jsx, indentChar = ' '}) => { + let svgCode = renderToStaticMarkup(jsx).match(/(]*>)[\s\S]*?(<\/svg>)/g); + let newHTML = html.replace(/\s*/g, str => { + let html = '\n' + svgCode.shift(); + let indentRegExp = new RegExp(`[${indentChar}]*`); + let startingIndentCount = str.slice(2).match(indentRegExp)[0].length / indentChar.length; + return beautifyHTML({html, startingIndentCount, indentChar}); + }); + return newHTML; +}; + +export default insertSVGIcons; diff --git a/stories/react/utils/SourceToggle.js b/stories/react/utils/SourceToggle.js new file mode 100644 index 0000000..a05c8d0 --- /dev/null +++ b/stories/react/utils/SourceToggle.js @@ -0,0 +1,73 @@ +/* eslint-disable react/no-danger */ +import React from 'react'; +import jsxToString from './jsxToString.js'; + +import Prism from 'prismjs'; + +import PrismJsx from 'prismjs/components/prism-jsx.js'; // eslint-disable-line no-unused-vars + +const sources = { + React: 'React', + HTML: 'HTML' +}; + +export default class SourceToggle extends React.Component { + constructor(props) { + super(props); + this.state = { + source: sources.React + }; + } + + renderFromSource() { + let {jsx, html, renderFromJsx} = this.props; + let {source} = this.state; + let classname = 'source-toggle-example'; + switch (source) { + case sources.HTML: + return renderFromJsx ?
{jsx}
:
; + case sources.React: + default: + return
{jsx}
; + } + } + + renderMarkdown() { + let {jsx, html, exclude} = this.props; + let {source} = this.state; + switch (source) { + case sources.HTML: + return {__html: Prism.highlight(html, Prism.languages.html)}; + case sources.React: + default: + return {__html: Prism.highlight(jsxToString({jsx, exclude}), Prism.languages.jsx)}; + } + } + + render() { + let {title} = this.props; + return ( +
+ {title &&
{title}
} +
+ {this.renderFromSource()} +
+
+ {Object.keys(sources).map((source, i) => ( +
this.setState({source})}> + {source} +
+ ))} +
+
+							
+						
+
+
+
+ ); + } +} diff --git a/stories/react/utils/components/DropdownMenu.js b/stories/react/utils/components/DropdownMenu.js new file mode 100644 index 0000000..4a69463 --- /dev/null +++ b/stories/react/utils/components/DropdownMenu.js @@ -0,0 +1,14 @@ +import React from 'react'; + +const DropdownMenu = ({title, value, onChange, options}) => ( +
+ + +
+); + +export default DropdownMenu; diff --git a/stories/react/utils/jsxToString.js b/stories/react/utils/jsxToString.js new file mode 100644 index 0000000..8b799ad --- /dev/null +++ b/stories/react/utils/jsxToString.js @@ -0,0 +1,74 @@ +import React, {Children} from 'react'; + +const INDENT = ' '; + +function stringRepresentationForJsx(item) { + if (typeof item === 'string') { + return `'${item}'`; + } else if (typeof item === 'number') { + return item.toString(); + } else if (Array.isArray(item)) { + return `[${item.map(val => stringRepresentationForJsx(val)).toString()}]`; + } + else if (typeof item === 'boolean') { + return item.toString(); + } + else if (typeof item === 'function') { + return item.toString().replace(/\s{2,}/g, ' '); + } else if (typeof item === 'object') { + let repr = '{'; + for (let key in item) { + if (item.hasOwnProperty(key)) { + repr += `${key}: ${stringRepresentationForJsx(item[key])}, `; + } + } + repr = repr.slice(0, -2); + repr += '}'; + return repr; + } +} + +function parseProps(jsx, indentCount) { + let result = ''; + for (let prop in jsx.props) { + let value = jsx.props[prop]; + if (prop !== 'children' && value) { + let repr = stringRepresentationForJsx(value); + let isString = repr.startsWith("'"); + result += `\n${INDENT.repeat(indentCount)}${prop}`; + if (value !== true) { + result += `=${isString ? '' : '{ '}${stringRepresentationForJsx(value)}${isString ? '' : ' }'}`; + } + } + } + return result; +} + +function jsxToString({jsx, indentCount=0, exclude}) { + if (typeof jsx === 'string'){ + return jsx; + } + + let name = typeof jsx.type === 'string' ? jsx.type : jsx.type.name; + let result = name === exclude ? '' + : `${INDENT.repeat(indentCount)}<${name}${parseProps(jsx, indentCount + 1)}`; + + if (jsx.props.hasOwnProperty('children')) { + let {children} = jsx.props; + let childrenArr = Children.toArray(children); + if (name !== exclude) { result += '>\n';} + if (typeof children === 'string') { + result += `${INDENT.repeat(indentCount + 1)}${children}\n`; + } else { + let newIndentCount = name === exclude ? indentCount : indentCount + 1; + childrenArr.forEach(child => result += `${jsxToString({jsx: child, indentCount: newIndentCount})}\n`); + } + const closingTag = name === exclude ? '' + : `${INDENT.repeat(indentCount)}`; + return result + closingTag; + } + + return result + ' />'; +} + +export default jsxToString; -- cgit 1.2.3-korg