diff options
author | Israel Lavi <israel.lavi@intl.att.com> | 2018-05-21 17:42:00 +0300 |
---|---|---|
committer | Israel Lavi <il0695@att.com> | 2018-05-21 17:52:01 +0300 |
commit | 1994c98063c27a41797dec01f2ca9fcbe33ceab0 (patch) | |
tree | f30beeaf15a8358f6da78fdd74bcbda74bd334f8 /stories | |
parent | 4749f4631426fcbe29ed98cef8f24cab18b501d0 (diff) |
init commit onap ui
Change-Id: I1dace78817dbba752c550c182dfea118b4a38646
Issue-ID: SDC-1350
Signed-off-by: Israel Lavi <il0695@att.com>
Diffstat (limited to 'stories')
55 files changed, 4006 insertions, 0 deletions
diff --git a/stories/README.md b/stories/README.md new file mode 100644 index 0000000..7ed8e9d --- /dev/null +++ b/stories/README.md @@ -0,0 +1,9 @@ +# Storybook + +This is the part of the repo that is responsible for defining and building the stories for storybook. Take a look at the following guides for your assistance: + +## Adding a new component to storybook +See [wiki page](https://github.com/onap-sdc/sdc-ui/wiki/Adding-a-new-component-to-storybook). + +## Deploying storybook to a fork's github pages +See [wiki page](https://github.com/onap-sdc/sdc-ui/wiki/Deploying-storybook-to-a-fork's-github-pages). diff --git a/stories/ng2-component-lab/accordion.component.exp.ts b/stories/ng2-component-lab/accordion.component.exp.ts new file mode 100644 index 0000000..480a011 --- /dev/null +++ b/stories/ng2-component-lab/accordion.component.exp.ts @@ -0,0 +1,146 @@ +import { experimentOn } from '@islavi/ng2-component-lab'; +import {Placement} from "../../src/angular/common/enums"; + + +/************************************************** + * Adding custom styles for example + *************************************************/ +const style = document.createElement('style'); +style.innerHTML = ` +.sdc-accordion-custom-class .sdc-accordion-header, +.sdc-accordion-custom-class .sdc-accordion-body.open { + padding: 10px; + border-radius: 3px; +} +.sdc-accordion-custom-class .sdc-accordion-header { + background-color: #d2d2d2; +} +.sdc-accordion-custom-class .sdc-accordion-body.open { + border: 1px solid #d2d2d2; + margin-top: 1px; + } +`; +const head = document.getElementsByTagName('head'); +head[0].appendChild(style); + +export default experimentOn('Accordion').group('Accordion', + [ + { + id: 'simpleAccodion', + title: 'Simple accordion', + description: 'Example of accordion with default left arrow', + showSource: true, + template: ` + <sdc-accordion title="Accordion header"> + <p> + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce consequat dictum porttitor. + Nam facilisis, dui nec maximus facilisis, nisl eros mattis arcu, nec pharetra nisl nisi vitae metus. + Vestibulum urna nunc, fringilla nec imperdiet a, varius hendrerit neque. Aliquam pulvinar turpis enim, ac hendrerit dui blandit eu. + Curabitur ut mollis arcu, ac iaculis turpis. Pellentesque lobortis leo justo. Morbi commodo cursus dignissim. + Nam orci diam, mattis eget leo vel, tincidunt interdum dui. + Donec dapibus mauris non sapien ornare, non pharetra mi commodo. + </p> + </sdc-accordion> + ` + }, + { + id: 'accordionRightArrow', + title: 'Accordion with right arrow', + description: 'Example of accordion with right arrow', + showSource: true, + context: { + arrowDirection: Placement.right, + }, + template: ` + + + + <sdc-accordion + title="Accordion header" + [arrow-direction]="arrowDirection"> + <p> + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce consequat dictum porttitor. + Nam facilisis, dui nec maximus facilisis, nisl eros mattis arcu, nec pharetra nisl nisi vitae metus. + Vestibulum urna nunc, fringilla nec imperdiet a, varius hendrerit neque. Aliquam pulvinar turpis enim, ac hendrerit dui blandit eu. + Curabitur ut mollis arcu, ac iaculis turpis. Pellentesque lobortis leo justo. Morbi commodo cursus dignissim. + Nam orci diam, mattis eget leo vel, tincidunt interdum dui. + Donec dapibus mauris non sapien ornare, non pharetra mi commodo. + </p> + </sdc-accordion> + ` + }, + { + id: 'accordionRightArrowStyle', + title: 'Accordion with right arrow and custom style', + description: 'Example of accordion with right arrow and custom style', + showSource: true, + context: { + arrowDirection: Placement.right, + }, + template: ` + <sdc-accordion + title="Accordion header" + css-class="sdc-accordion-custom-class" + [arrow-direction]="arrowDirection"> + <p> + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce consequat dictum porttitor. + Nam facilisis, dui nec maximus facilisis, nisl eros mattis arcu, nec pharetra nisl nisi vitae metus. + Vestibulum urna nunc, fringilla nec imperdiet a, varius hendrerit neque. Aliquam pulvinar turpis enim, ac hendrerit dui blandit eu. + Curabitur ut mollis arcu, ac iaculis turpis. Pellentesque lobortis leo justo. Morbi commodo cursus dignissim. + Nam orci diam, mattis eget leo vel, tincidunt interdum dui. + Donec dapibus mauris non sapien ornare, non pharetra mi commodo. + </p> + </sdc-accordion> + ` + } + , + { + id: 'accordionLeftArrowStyle', + title: 'Accordion with left arrow and custom style', + description: 'Example of accordion with left arrow and custom style', + showSource: true, + context: { + arrowDirection: Placement.left, + }, + template: ` + <sdc-accordion + title="Accordion header" + css-class="sdc-accordion-custom-class" + [arrow-direction]="arrowDirection"> + <p> + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce consequat dictum porttitor. + Nam facilisis, dui nec maximus facilisis, nisl eros mattis arcu, nec pharetra nisl nisi vitae metus. + Vestibulum urna nunc, fringilla nec imperdiet a, varius hendrerit neque. Aliquam pulvinar turpis enim, ac hendrerit dui blandit eu. + Curabitur ut mollis arcu, ac iaculis turpis. Pellentesque lobortis leo justo. Morbi commodo cursus dignissim. + Nam orci diam, mattis eget leo vel, tincidunt interdum dui. + Donec dapibus mauris non sapien ornare, non pharetra mi commodo. + </p> + </sdc-accordion> + ` + }, + { + id: 'accordionLeftArrowStyleOpen', + title: 'Open accordion with left arrow and custom style', + description: 'Example of open accordion with left arrow and custom style', + showSource: true, + context: { + arrowDirection: Placement.left, + }, + template: ` + <sdc-accordion + title="Accordion header" + css-class="sdc-accordion-custom-class" + [open]="true" + [arrow-direction]="arrowDirection"> + <p> + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce consequat dictum porttitor. + Nam facilisis, dui nec maximus facilisis, nisl eros mattis arcu, nec pharetra nisl nisi vitae metus. + Vestibulum urna nunc, fringilla nec imperdiet a, varius hendrerit neque. Aliquam pulvinar turpis enim, ac hendrerit dui blandit eu. + Curabitur ut mollis arcu, ac iaculis turpis. Pellentesque lobortis leo justo. Morbi commodo cursus dignissim. + Nam orci diam, mattis eget leo vel, tincidunt interdum dui. + Donec dapibus mauris non sapien ornare, non pharetra mi commodo. + </p> + </sdc-accordion> + ` + } + ]); diff --git a/stories/ng2-component-lab/autocomplete.component.exp.ts b/stories/ng2-component-lab/autocomplete.component.exp.ts new file mode 100644 index 0000000..a1fa3dd --- /dev/null +++ b/stories/ng2-component-lab/autocomplete.component.exp.ts @@ -0,0 +1,77 @@ +import { experimentOn } from '@islavi/ng2-component-lab'; + +export default experimentOn('Autocomplete').group('Autocomplete', +[ + { + id: 'simpleAutocomplete', + title: 'Simple autocomplete data', + description: 'Example of auto complete with simple data', + showSource: true, + context: { + data: ['red', 'yellow', 'orange', 'green', 'white', 'black'], + selectedOption: '', + showSelectedItem: ((value: string) => { + alert(value); + }) + }, + template: ` + <sdc-autocomplete + placeholder="search text" + label="search by color:" + [data]="data" + (itemSelected)="showSelectedItem($event)" + > + </sdc-autocomplete> + ` + }, + { + id: 'complexAutocomplete', + title: 'Complex autocomplete data', + description: 'Example of auto complete with complex data', + showSource: true, + context: { + data: [ + {id: 'redId', color: 'red'}, + {id: 'yellowId', color: 'yellow'}, + {id: 'orangeId', color: 'orange'}, + {id: 'greenId', color: 'green'}, + {id: 'whiteId', color: 'white'}, + {id: 'blackId', color: 'black'} + ], + showSelectedItem: ((value: string) => { + alert(value); + }) + }, + template: ` + <sdc-autocomplete + placeholder="search text" + label="search by color:" + [data]="data" + [dataSchema]="{key: 'id', value: 'color'}" + (itemSelected)="showSelectedItem($event)" + > + </sdc-autocomplete> + ` + }, + { + id: 'complexAutocompleteWithBeData', + title: 'Complex autocomplete data from server', + description: 'Example of auto complete with complex data from server. (In this example the data is not really filtered, because it is from mock data)', + showSource: true, + context: { + showSelectedItem: ((value: string) => { + alert(value); + }) + }, + template: ` + <sdc-autocomplete + placeholder="search text" + label="search by color:" + dataUrl="../../../stories/ng2-component-lab/utils/mock.json" + [dataSchema]="{key: 'id', value: 'color'}" + (itemSelected)="showSelectedItem($event)" + > + </sdc-autocomplete> + ` + } +]); diff --git a/stories/ng2-component-lab/button.component.exp.ts b/stories/ng2-component-lab/button.component.exp.ts new file mode 100644 index 0000000..6c5fb04 --- /dev/null +++ b/stories/ng2-component-lab/button.component.exp.ts @@ -0,0 +1,164 @@ +import { experimentOn } from '@islavi/ng2-component-lab'; + +const buttonTypes = ['primary', 'secondary', 'link', 'alert']; +const buttonSizes = ['large', 'medium', 'small', 'x-small', 'default']; +const experiment = experimentOn('Button'); + +experiment.group("Default button", [ + { + id: "defaultButton", + showSource: true, + description: `Default button, does not need to supply type or size. + <br>The size of the button set to 'default' so it will shrink or expand according to the content. + `, + context: { + buttonClicked: ():void => { + window.alert("OK"); + } + }, + title: "Default button", + template: ` + <sdc-button + text="Default button long text" + testId="longButton" + (click)="buttonClicked()"> + </sdc-button> + <sdc-button + text="Sample button" + (click)="buttonClicked()" + [testId]="'defaultButtonTestId'" + > + </sdc-button> + + + ` + } +]); + +buttonTypes.forEach((buttonType) => { + [false, true].forEach((buttonDisabled) => { + experiment.group(`Button ${buttonType} ${buttonDisabled ? ' disabled' : ''}`, [ { + id: `Button ${buttonType}${buttonDisabled ? ' disabled' : ''}`, + showSource: true, + context: { + buttonClicked: ():void => { + window.alert("OK"); + } + }, + title: `Button ${buttonType}${buttonDisabled ? ' disabled' : ''}`, + template: buttonSizes.map((buttonSize) => + ` + <span style="display: inline-block;"> + <div>${buttonSize}</div><br> + <sdc-button + text="Sample" + type="${buttonType}" + size="${buttonSize}" + (click)="buttonClicked()" + ${buttonDisabled ? ' [disabled]="true"' : ''}> + </sdc-button> + </span> + `).join('\n') + } + ]); + }); +}); + +experiment.group("Buttons with icons", [ + { + id: "buttonsWithIcons", + showSource: true, + description: `Buttons with icons forward`, + context: { + buttonClicked: (): void => { + window.alert("OK"); + } + }, + title: "Button with icons", + template: ` + <sdc-button + text="Default button long text" + (click)="buttonClicked()" + icon_name="settings-o" + icon_position="left" + > + </sdc-button> + + <sdc-button + text="Sample button" + (click)="buttonClicked()" + icon_name="plus-circle-o" + icon_position="left" + > + </sdc-button> + + <sdc-button + text="Sample button" + type="secondary" + (click)="buttonClicked()" + icon_name="plus-circle" + icon_position="right" + > + </sdc-button> + + <sdc-button + text="Sample button" + type="secondary" + (click)="buttonClicked()" + icon_name="caret2-right-circle-o" + icon_position="right" + > + </sdc-button> + + ` + } +]); + +experiment.group("Buttons with spinners", [ + { + id: "buttonsWithSpinnersRight", + showSource: true, + description: `Click the button to see the spinner shows for 2 seconds`, + context: { + buttonClicked: (button): void => { + button.show_spinner = true; + setTimeout(() => {button.show_spinner = false},2000); + }, + }, + title: "Button with spinner on the right", + template: ` + <sdc-button + text="Click to show spinner" + (click)="buttonClicked(button)" + [show_spinner]="false" + spinner_position="right" + #button + > + </sdc-button> + + ` + }, + { + id: "buttonsWithSpinnersLeft", + showSource: true, + description: `Click the button to see the spinner shows for 2 seconds`, + context: { + buttonClicked: (button): void => { + button.show_spinner = true; + setTimeout(() => {button.show_spinner = false},2000); + }, + }, + title: "Button with spinner on the left", + template: ` + <sdc-button + text="Click to show spinner" + (click)="buttonClicked(button)" + spinner_position="left" + #button + > + </sdc-button> + + ` + } +]); +export default experiment; diff --git a/stories/ng2-component-lab/checkbox.component.exp.ts b/stories/ng2-component-lab/checkbox.component.exp.ts new file mode 100644 index 0000000..7ac53c9 --- /dev/null +++ b/stories/ng2-component-lab/checkbox.component.exp.ts @@ -0,0 +1,33 @@ +import { experimentOn } from '@islavi/ng2-component-lab'; + +export default experimentOn('Checkbox') + .group("Checkbox",[ + { + id: 'checkbox', + showSource: true, + title: 'Regular Checkbox', + description: 'Simple checkbox', + template: `<sdc-checkbox label="Simple"></sdc-checkbox>`, + }, + { + id: 'checkboxChecked', + showSource: true, + title: 'Regular Checked Checkbox', + description: 'Simple checked checkbox', + template: `<sdc-checkbox label="Checked" [checked]="true"></sdc-checkbox>`, + }, + { + id: 'disabledCheckbox', + showSource: true, + title: 'Disabled checkbox', + description: 'Simple disabled checkbox', + template: `<sdc-checkbox label="Disabled"[disabled]="true"></sdc-checkbox>`, + }, + { + id: 'disabledCheckboxChecked', + showSource: true, + title: 'Disabled checked checkbox', + description: 'Simple disabled checked checkbox', + template: `<sdc-checkbox label="Disabled" [checked]="true" [disabled]="true"></sdc-checkbox>`, + } + ]); diff --git a/stories/ng2-component-lab/checklist.component.exp.ts b/stories/ng2-component-lab/checklist.component.exp.ts new file mode 100644 index 0000000..4700a74 --- /dev/null +++ b/stories/ng2-component-lab/checklist.component.exp.ts @@ -0,0 +1,213 @@ +import { experimentOn } from '@islavi/ng2-component-lab'; +import { ChecklistItemModel } from "../../src/angular/checklist/models/ChecklistItem"; +import { ChecklistModel } from "../../src/angular/checklist/models/Checklist"; + +const styleCode = 'h5{color:red;} pre{background-color: #d1d1d1; padding: 10px;}'; +const checklistValuesExample1 = []; + +const checkListExample1: ChecklistModel = new ChecklistModel(checklistValuesExample1, + [new ChecklistItemModel('apple'), + new ChecklistItemModel('banana'), + new ChecklistItemModel('orange')]); + +const checklistValuesExample2 = []; +const checkListExample2: ChecklistModel = new ChecklistModel(checklistValuesExample2, + [new ChecklistItemModel('apple', false, false, null, 0), + new ChecklistItemModel('banana', false, false, null, 1), + new ChecklistItemModel('orange', false, false, null, 2)]); + +const checklistValuesExample3 = []; +const checkListExample3: ChecklistModel = new ChecklistModel(checklistValuesExample3, + [new ChecklistItemModel('apple', false, true), + new ChecklistItemModel('banana'), + new ChecklistItemModel('orange', false, true)]); + +const checklistValuesExample4 = []; +const checkListExample4: ChecklistModel = new ChecklistModel(checklistValuesExample4, + [new ChecklistItemModel('apple', true, true), + new ChecklistItemModel('banana', true), + new ChecklistItemModel('orange')]); + +const checklistValuesExample5 = []; +const innerChecklistValues = []; +const checkListExample5: ChecklistModel = new ChecklistModel(checklistValuesExample5, + [new ChecklistItemModel('apple', false, false, + new ChecklistModel(innerChecklistValues, + [new ChecklistItemModel('red'), new ChecklistItemModel('green'), new ChecklistItemModel('yellow')])), + new ChecklistItemModel('banana'), + new ChecklistItemModel('orange')]); + +const checklistFirstLevelValuesExample6 = []; +const checklistSecondLevelValuesExample6 = []; +const checklistThirdLevelValuesExample6 = []; +const checkListExample6: ChecklistModel = new ChecklistModel(checklistFirstLevelValuesExample6, + [new ChecklistItemModel('1', false, false, + new ChecklistModel(checklistSecondLevelValuesExample6, [new ChecklistItemModel('1.1'), + new ChecklistItemModel('1.2', false, false, new ChecklistModel(checklistThirdLevelValuesExample6, [new ChecklistItemModel('1.2.1'), + new ChecklistItemModel('1.2.2'), + new ChecklistItemModel('1.2.3')])), + new ChecklistItemModel('1.3')])), + new ChecklistItemModel('2'), + new ChecklistItemModel('3')]); + +export default experimentOn('Checklist') + .group("Checklist",[ + { + id: 'checklist', + showSource: true, + context: { + checklistModel: checkListExample1, + checklistValues: checklistValuesExample1 + }, + styles: [styleCode], + title: 'Checklist', + description: ` + <pre> + <h5>The checklistModel parameter:</h5> + const checklistValues = []; + const checklistModel: ChecklistModel = + new ChecklistModel(checklistValues, + [new ChecklistItemModel('apple'), + new ChecklistItemModel('banana'), + new ChecklistItemModel('orange')]); + </pre> + `, + template: ` + <span>Selected values: {{checklistValues.toString()}}</span> + <sdc-checklist [checklistModel]="checklistModel"></sdc-checklist> + `, + }, + { + id: 'checklistWithValues', + showSource: true, + context: { + checklistModel: checkListExample2, + checklistValues: checklistValuesExample2 + }, + styles: [styleCode], + title: 'Checklist with values', + description: ` + <pre> + <h5>The checklistModel parameter:</h5> + const checklistValues = []; + const checklistModel: ChecklistModel = new ChecklistModel(checklistValues, + [new ChecklistItemModel('apple', false, false, null, 0), + new ChecklistItemModel('banana', false, false, null, 1), + new ChecklistItemModel('orange', false, false, null, 2)]); + </pre> + `, + template: ` + <span>Selected values: {{checklistValues.toString()}}</span> + <sdc-checklist [checklistModel]="checklistModel"></sdc-checklist> + ` + }, + { + id: 'checklistWithSomeCheckedItems', + title: 'Checklist with some checked items', + showSource: true, + context: { + checklistModel: checkListExample3, + checklistValues: checklistValuesExample3 + }, + styles: [styleCode], + description: ` + <pre><h5>The checklistModel parameter:</h5> + const checklistValues = []; + const checklistModel: ChecklistModel = new ChecklistModel(checklistValues, + [new ChecklistItemModel('apple', false, true), + new ChecklistItemModel('banana'), + new ChecklistItemModel('orange', false, true)]); + </pre> + `, + template: ` + <span>Selected values: {{checklistValues.toString()}}</span> + <sdc-checklist [checklistModel]="checklistModel"></sdc-checklist> + ` + }, + { + id: 'checklistWithSomeDisabledItems', + title: 'Checklist with some disabled items', + showSource: true, + context: { + checklistModel: checkListExample4, + checklistValues: checklistValuesExample4 + }, + styles: [styleCode], + description: ` + <pre><h5>The checklistModel parameter:</h5> + const checklistValues = []; + const checklistModel: ChecklistModel = new ChecklistModel(checklistValues, + [new ChecklistItemModel('apple', true, true), + new ChecklistItemModel('banana', true), + new ChecklistItemModel('orange')]); + </pre> + `, + template: ` + <span>Selected values: {{checklistValues.toString()}}</span> + <sdc-checklist [checklistModel]="checklistModel"></sdc-checklist> + ` + }, + { + id: 'twoLevelsChecklist', + title: 'Multi-levels checklist', + showSource: true, + context: { + checklistModel: checkListExample5, + checklistValues: checklistValuesExample5, + innerChecklistValues: innerChecklistValues + }, + styles: [styleCode], + description: ` + <pre> + <h5>The checklistModel parameter:</h5> + const checklistValues = []; + const innerChecklistValues = []; + const checklistModel: ChecklistModel = new ChecklistModel(checklistValues, + [new ChecklistItemModel('apple', false, false,new ChecklistModel(innerChecklistValues,[new ChecklistItemModel('red'), + new ChecklistItemModel('green'), + new ChecklistItemModel('yellow')])), + new ChecklistItemModel('banana'), + new ChecklistItemModel('orange')]);</pre> + `, + template: ` + <div>Selected values: {{checklistValues.toString()}}</div> + <div>Inner checklist selected values: {{innerChecklistValues.toString()}}</div> + <sdc-checklist [checklistModel]="checklistModel"></sdc-checklist> + ` + }, + { + id: 'multiLevelsChecklist', + title: 'Multi-levels checklist', + showSource: true, + context: { + checklistModel: checkListExample6, + checklistFirstLevelValues: checklistFirstLevelValuesExample6, + checklistSecondLevelValues: checklistSecondLevelValuesExample6, + checklistThirdLevelValues: checklistThirdLevelValuesExample6 + }, + styles: [styleCode], + description: ` + <pre><h5>The checklistModel parameter:</h5> + const checklistFirstLevelValues = []; + const checklistSecondLevelValues = []; + const checklistThirdLevelValues = []; + const checklistModel: ChecklistModel = new ChecklistModel(checklistFirstLevelValues, + [new ChecklistItemModel('1', false, false, + new ChecklistModel(checklistSecondLevelValues, [new ChecklistItemModel('1.1'), + new ChecklistItemModel('1.2', false, false, + new ChecklistModel(checklistThirdLevelValues, [new ChecklistItemModel('1.2.1'), + new ChecklistItemModel('1.2.2'), + new ChecklistItemModel('1.2.3')])), + new ChecklistItemModel('1.3')])), + new ChecklistItemModel('2'), + new ChecklistItemModel('3')]); + </pre> + `, + template: ` + <div>Selected values: {{checklistFirstLevelValues.toString()}}</div> + <div>Second level checklist selected values: {{checklistSecondLevelValues.toString()}}</div> + <div>Third level checklist selected values: {{checklistThirdLevelValues.toString()}}</div> + <sdc-checklist [checklistModel]="checklistModel"></sdc-checklist> + ` + } + ]); diff --git a/stories/ng2-component-lab/colors.component.exp.ts b/stories/ng2-component-lab/colors.component.exp.ts new file mode 100644 index 0000000..f082d90 --- /dev/null +++ b/stories/ng2-component-lab/colors.component.exp.ts @@ -0,0 +1,42 @@ +import { experimentOn } from '@islavi/ng2-component-lab'; + +const colorMap = { + 'white': '#ffffff', + 'dark-blue': '#0568ae', + 'blue': '#009fdb', + 'light-blue': '#1eb9f3', + 'blue-disabled': '#9dd9ef', + 'lighter-blue': '#e6f6fb', + 'black': '#000000', + 'text-black': '#191919', + 'rich-black': '#323943', + 'dark-gray': '#5a5a5a', + 'gray': '#959595', + 'light-gray': '#d2d2d2', + 'silver': '#eaeaea', + 'light-silver': '#f2f2f2', + 'lighter-silver':'#f8f8f8', + 'green': '#4ca90c', + 'red': '#cf2a2a', + 'light-red':'#ed4141', + 'disabled-red':'#f4adad', + 'yellow': '#ffb81c', + 'dark-purple': '#702f8a', + 'purple': '#9063cd', + 'light-purple': '#caa2dd' +}; + +export default experimentOn('Colors', 1) + .group("Color palette", [ + { + id: 'colorPalette', + showSource: true, + context: { + colorMap + }, + title: 'Color palette', + description: 'Supported design colors', + template: `<colors-table [tableTitle]="'Colors'" [tableMapColors]="colorMap"></colors-table>`, + } + ] + ); diff --git a/stories/ng2-component-lab/components.module.ts b/stories/ng2-component-lab/components.module.ts new file mode 100644 index 0000000..266f047 --- /dev/null +++ b/stories/ng2-component-lab/components.module.ts @@ -0,0 +1,45 @@ +import { NgModule } from "@angular/core"; +import { CommonModule } from "@angular/common"; +import { FormsModule } from "@angular/forms"; +import { SdcUiComponentsModule } from "../../src/angular"; +import { KeysPipe } from "./utils/pipes/keys.pipe"; +import { SearchFilterPipe } from "./pipes/search-filter-pipe"; +import { ColorsTable } from "./components/colors-table.component"; +import { ModalInnerContent } from "./components/modal-inner-content-example.component"; +import { ModalConsumer } from "./components/modal-consumer.component"; +import { SvgIconsTableComponent } from "./components/svg-icons-table.component"; +import { NotificationsExample } from "./components/notifications-example.component"; +import { Mode, Placement, Size } from "./../../src/angular/common/enums"; + +@NgModule({ + declarations: [ + ColorsTable, + KeysPipe, + ModalInnerContent, + ModalConsumer, + SearchFilterPipe, + SvgIconsTableComponent, + NotificationsExample + ], + imports: [ + CommonModule, + FormsModule, + SdcUiComponentsModule + ], + exports: [ + CommonModule, + SdcUiComponentsModule, + ModalInnerContent, + NotificationsExample, + ColorsTable, + SvgIconsTableComponent, + ModalConsumer, + SearchFilterPipe + ], + entryComponents: [ + ModalInnerContent + ], + providers: [KeysPipe] +}) +export class ComponentsModule { +} diff --git a/stories/ng2-component-lab/components/colors-table.component.ts b/stories/ng2-component-lab/components/colors-table.component.ts new file mode 100644 index 0000000..fc7bd2f --- /dev/null +++ b/stories/ng2-component-lab/components/colors-table.component.ts @@ -0,0 +1,26 @@ +import { Component, Input } from "@angular/core"; + +@Component({ + selector: "colors-table", + template: ` + + <h1>{{tableTitle}}</h1> + <div class="colors-table"> + <div class="color-section" *ngFor="let color of tableMapColors | keys"> + <div class='sdc-bc-{{color}} color-circle'></div> + <div>{{color}}</div> + <div>{{tableMapColors[color]}}</div> + </div> + </div> +` +}) +export class ColorsTable { + + @Input() tableTitle:string; + @Input() tableMapColors: Object; + + constructor() { + + } + +} diff --git a/stories/ng2-component-lab/components/modal-consumer.component.ts b/stories/ng2-component-lab/components/modal-consumer.component.ts new file mode 100644 index 0000000..e4a3977 --- /dev/null +++ b/stories/ng2-component-lab/components/modal-consumer.component.ts @@ -0,0 +1,106 @@ +import { Component, Input, Output, EventEmitter } from "@angular/core"; +import { ModalService } from "../../../src/angular/modals/modal.service"; +import { IModalConfig, ModalType, ModalSize } from "../../../src/angular/modals/models/modal-config"; +import { ModalInnerContent } from "./modal-inner-content-example.component"; +import { ButtonComponent } from "../../../src/angular/buttons/button.component"; +import { ModalButtonComponent } from './../../../src/angular/modals/modal-button.component'; +import { Placement } from "../../../src/angular/common/enums"; +import { ModalComponent } from "../../../src/angular/components"; + +const MODAL_CONTENT = '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'; + +@Component({ + selector: 'modal-consumer', + template: `<sdc-button [text]="'View Modal'" (click)="openModal()"></sdc-button>` +}) +export class ModalConsumer { + @Input() action: string; + + constructor(private modalService: ModalService) { + } + + private openModal = (): void => { + if (this[this.action]) { + this[this.action](); + } + } + + private openErrorModal = (): void => { + this.modalService.openErrorModal(MODAL_CONTENT, "sampleTestId"); + } + + private openAlertModal = (): void => { + this.modalService.openAlertModal("Alert Title", MODAL_CONTENT, 'Continue', this.onConfirmAction, 'sampleTestId'); + } + + private openActionModal = (): void => { + this.modalService.openActionModal('Standard Modal', MODAL_CONTENT, "OK", this.onConfirmAction, "sampleTestId"); + } + + private onConfirmAction = (): void => { + alert("Action has been confirmed"); + } + + private openCustomModal1 = (): void => { + const modalConfig = { + size: ModalSize.medium, + title: 'Title', + type: ModalType.custom, + testId: 'sampleTestIdModal1', + buttons: [ + {id: "saveButton", text: "Save", callback: this.customModalOnSave1, closeModal: false}, + {id: "cancelButton", text: "Cancel", size: 'x-small', type: 'secondary', closeModal: true} + ] as ModalButtonComponent[] + } as IModalConfig; + this.modalService.openCustomModal(modalConfig, ModalInnerContent, {name: "Sample Content"}); + } + + private customModalOnSave1 = (): void => { + const currentInstance: ModalComponent = this.modalService.getCurrentInstance(); + const saveButton: ModalButtonComponent = currentInstance.getButtonById("saveButton"); + saveButton.show_spinner = true; + saveButton.spinner_position = Placement.right; + + // Show spinner for 2 seconds + console.log('Saving example, please wait ...'); + window.setTimeout((button: ModalButtonComponent) => { + button.show_spinner = false; + console.log('Finish saving'); + }, 2000, saveButton); + } + + private openCustomModal2 = (): void => { + const modalConfig = { + size: ModalSize.medium, + title: 'Title', + type: ModalType.custom, + testId: 'sampleTestIdModal2', + buttons: [ + {text: "Change title", callback: this.customModalChangeTitle2, closeModal: false}, + {text: "Change buttons", callback: this.customModalUpdateButtons2, closeModal: false}, + {text: "Disable close", callback: this.customModalUDisableClose2, closeModal: false} + ] + } as IModalConfig; + this.modalService.openCustomModal(modalConfig, ModalInnerContent, {name: "Sample Content"}); + } + + private customModalUDisableClose2 = (): void => { + const currentInstance: ModalComponent = this.modalService.getCurrentInstance(); + currentInstance.getCloseButton().disabled = true; + } + + private customModalChangeTitle2 = (): void => { + const currentInstance: ModalComponent = this.modalService.getCurrentInstance(); + currentInstance.setTitle('New title'); + } + + private customModalUpdateButtons2 = (): void => { + const currentInstance: ModalComponent = this.modalService.getCurrentInstance(); + const newButtons = [ + {text: "Change title", callback: this.customModalChangeTitle2, closeModal: false}, + {text: "Do nothing", closeModal: false} + ] as ModalButtonComponent[]; + currentInstance.setButtons(newButtons); + } +} diff --git a/stories/ng2-component-lab/components/modal-inner-content-example.component.ts b/stories/ng2-component-lab/components/modal-inner-content-example.component.ts new file mode 100644 index 0000000..1b6bed0 --- /dev/null +++ b/stories/ng2-component-lab/components/modal-inner-content-example.component.ts @@ -0,0 +1,16 @@ +import { Component, Input } from "@angular/core"; + +@Component({ + selector: "inner-content", + template: ` + <div> + <sdc-input [label]="'Enter value'" [(value)]="name"> </sdc-input> + <sdc-input [label]="'Enter value'" [(value)]="name"> </sdc-input> + <sdc-input [label]="'Enter value'" [(value)]="name"> </sdc-input> + </div> +` +}) +export class ModalInnerContent { + + @Input() name:string; +} diff --git a/stories/ng2-component-lab/components/notifications-example.component.ts b/stories/ng2-component-lab/components/notifications-example.component.ts new file mode 100644 index 0000000..91dd95e --- /dev/null +++ b/stories/ng2-component-lab/components/notifications-example.component.ts @@ -0,0 +1,57 @@ +import { Component, Input, ViewChild } from "@angular/core"; +import { NotificationsService } from "../../../src/angular/notifications/services/notifications.service"; +import { NotificationSettings } from "../../../src/angular/notifications/utilities/notification.config"; +import { InnerNotifContent } from "../../../src/angular/notifications/notification-inner-content-example.component"; + +@Component({ + selector: "notifications-example", + template: ` + <div> + <span>Send Success Notification</span> + <sdc-button (click)="sendSuccessNotif()" text="Click Me!"></sdc-button> + </div> + <div> + <span>Send Warning Notification</span> + <sdc-button (click)="sendWarnNotif()" text="Click Me!"></sdc-button> + </div> + <div> + <span>Send Info Notification</span> + <sdc-button (click)="sendInfoNotif()" text="Click Me!"></sdc-button> + </div> + <div> + <span>Send Success MultipleLine Notification</span> + <sdc-button (click)="sendMultipleLinesSuceessNotif()" text="Click Me!"></sdc-button> + </div> + <div> + <span>Send Success Custom Notification</span> + <sdc-button (click)="sendSuccessCustomNotif()" text="Click Me!"></sdc-button> + </div> + <sdc-notification-container> + </sdc-notification-container> +` +}) +export class NotificationsExample { + + constructor(private notifsService : NotificationsService) { + } + + sendSuccessNotif() { + this.notifsService.push(new NotificationSettings("success", 'notif success message test', 'Notif Title Success')); + } + + sendMultipleLinesSuceessNotif() { + this.notifsService.push(new NotificationSettings("success", 'notif success message test with a lot of test so we can test multiple line case lets just add blabla bcdesfg hijklmnop qrstuvw xyz abcdesfg hijklmnop qrstuvw xyz', 'Notif Title Success')); + } + + sendWarnNotif() { + this.notifsService.push(new NotificationSettings("warn", 'notif warn message test', 'Notif Title Warn')); + } + + sendInfoNotif() { + this.notifsService.push(new NotificationSettings("info", 'notif info message test', 'Notif Title Info')); + } + + sendSuccessCustomNotif() { + this.notifsService.push(new NotificationSettings( "info", 'notif XYZ', 'Notif Custom XYZ', 10000, false, true, InnerNotifContent, { notifyText : "notif info custom inner message test", notifyTitle : "Notif Custom Inner Title Info"})); + } +} diff --git a/stories/ng2-component-lab/components/svg-icons-table.component.ts b/stories/ng2-component-lab/components/svg-icons-table.component.ts new file mode 100644 index 0000000..732650d --- /dev/null +++ b/stories/ng2-component-lab/components/svg-icons-table.component.ts @@ -0,0 +1,189 @@ +import { Component } from "@angular/core"; +import { Mode, Placement, Size } from "../../../src/angular/common/enums"; +import { SvgIconComponent } from "../../../src/angular/svg-icon/svg-icon.component"; +import { IDropDownOption, DropDownOptionType, DropDownTypes } from "../../../src/angular/form-elements/dropdown/dropdown-models"; + +const options1: IDropDownOption[] = [ + { + label: 'First Option', + value: 'First Option', + }, + { + label: 'Second Option', + value: 'Second Option', + }, + { + label: 'Third Option', + value: 'Third Option', + type: DropDownOptionType.Simple + } +]; + +@Component({ + selector: "svg-icons-table", + template: ` + <div class="icon-showcase"> + <div> + <svg-icon [name]="selectedIcon" [mode]="defaultIconSettings.mode" [size]="defaultIconSettings.size"></svg-icon> + Selected icon: <b *ngIf="selectedIcon">{{selectedIcon}}</b><i *ngIf="!selectedIcon">None</i> + </div> + + <div class="icon-options-wrapper"> + + <div class="icon-options"> + <div class="icon-options-dropdowns"> + <sdc-dropdown label="Mode" [selectedOption]="{'value': mode, 'label': mode}" [options]="modeOptions" (changed)="mode = $event.value"></sdc-dropdown> + <sdc-dropdown label="Label Placement" [selectedOption]="{'value': labelPlacement, 'label': labelPlacement}" [options]="labelPlacementOptions" [selectedOption]="labelPlacement" (changed)="labelPlacement = $event.value"></sdc-dropdown> + <sdc-dropdown label="Size" [selectedOption]="{'value': size, 'label': size}" [options]="sizeOptions" [selectedOption]="size" (changed)="size = $event.value"></sdc-dropdown> + </div> + <div class="icon-options-checkboxes-wrapper"> + <div class="icon-options-checkboxes"> + <sdc-checkbox label="Clickable" [checked]="clickable" (checkedChange)="clickable = $event"></sdc-checkbox> + <sdc-checkbox label="Disabled" [checked]="disabled" (checkedChange)="disabled = $event"></sdc-checkbox> + </div> + <div class="icon-options-label"> + <sdc-input label="Label" [(value)]="label"></sdc-input> + </div> + <svg-icon-label [name]="selectedIcon" [mode]="mode" [size]="size" [clickable]="clickable" [disabled]="disabled" [label]="label" [labelPlacement]="labelPlacement"></svg-icon-label> + </div> + </div> + + <div class="icon-code"> + <pre> + <svg-icon-label + [name]="{{selectedIcon}}" + [mode]="{{mode}}" + [size]="{{size}}" + [clickable]="{{clickable}}" + [disabled]="{{disabled}}" + [label]="{{label}}" + [labelPlacement]="{{labelPlacement}}"> + </svg-icon-label> + </pre> + </div> + </div> + + </div> + <div class="svg-icons-table"> + <div *ngFor="let iconName of iconsNames" class="svg-icon-cell" [ngClass]="{'selected': selectedIcon === iconName}" (click)="selectIcon(iconName)"> + <svg-icon-label [name]="iconName" [label]="iconName" labelPlacement="right"></svg-icon-label> + </div> + </div> +`, + styles: [` + .svg-icons-table { + display: flex; + flex-flow: row wrap; + justify-content: flex-start; + align-items: stretch; + overflow-y: auto; + } + .svg-icons-table .svg-icon-cell { + border: 1px solid #999; + padding: 5px; + margin: 5px; + width: 250px; + overflow: hidden; + display: flex; + align-items: center; + cursor: pointer; + } + .svg-icons-table .svg-icon-cell.selected { + border-color: #1eb9f3; + background-color: #1eb9f3; + } + .icon-showcase { + margin: 20px 10px; + padding: 10px; + border: 1px solid #999; + background: #eee; + } + .icon-options-wrapper { + display: flex; + flex-flow: row wrap; + justify-content: flex-start; + margin-top: 10px; + } + + .icon-options-checkboxes-wrapper { + display: flex; + flex-flow: row; + margin-top: 10px; + } + + .icon-options-checkboxes { + margin-top: 27px; + margin-right: 30px; + } + + .icon-options-label { + margin-right: 30px; + } + + .icon-code pre { + user-select: text; + } + + sdc-dropdown { + display: inline-block; + min-width: 160px; + } + + sdc-dropdown .sdc-dropdown { + } +`] +}) +export class SvgIconsTableComponent { + public iconsNames: string[]; + public selectedIcon: string; + + public modeOptions; + public sizeOptions; + public labelPlacementOptions; + + private mode: Mode; + private size: Size; + private labelPlacement: Placement; + private clickable: boolean; + private disabled: boolean; + private label: string; + + private defaultIconSettings: {mode: Mode, size: Size}; + + constructor() { + this.iconsNames = Object.keys(SvgIconComponent.Icons); + this.mode = null; + this.size = Size.medium; + this.clickable = false; + this.disabled = false; + this.defaultIconSettings = { mode: Mode.info, size: Size.small }; + + this.modeOptions = [{value: null, label: 'NONE'}].concat(Object.keys(Mode).map((modeKey) => ({ + value: modeKey, + label: Mode[modeKey] + }))); + + this.sizeOptions = Object.keys(Size).map((sizeKey) => ({ + value: sizeKey, + label: Size[sizeKey] + })); + + this.labelPlacementOptions = Object.keys(Placement).map((placementKey) => ({ + value: placementKey, + label: Placement[placementKey] + })); + + this.setDefaults(); + } + + private setDefaults = (): void => { + this.label = 'Some label'; + this.selectedIcon = "attachment"; + this.mode = Mode.primary; + this.labelPlacement = Placement.right; + } + + public selectIcon(iconName) { + this.selectedIcon = iconName; + } +} diff --git a/stories/ng2-component-lab/dropdown.component.exp.ts b/stories/ng2-component-lab/dropdown.component.exp.ts new file mode 100644 index 0000000..025409e --- /dev/null +++ b/stories/ng2-component-lab/dropdown.component.exp.ts @@ -0,0 +1,195 @@ +import { experimentOn } from '@islavi/ng2-component-lab'; +import { IDropDownOption, DropDownOptionType, DropDownTypes } from "../../src/angular/form-elements/dropdown/dropdown-models"; + +const options1: IDropDownOption[] = [ + { + label: 'First Option Label', + value: 'firstOptionValue', + }, + { + label: 'Second Option Label', + value: 'secondOptionValue', + }, + { + label: 'Third Option Label', + value: 'thirdOptionValue', + type: DropDownOptionType.Simple + } +]; + +const options2: IDropDownOption[] = [ + { + label: 'Header Label', + value: 'headerValue', + type: DropDownOptionType.Header + }, + { + label: 'First Option Label', + value: 'firstOptionValue', + type: DropDownOptionType.Simple + }, + { + label: 'Disabled Option Label', + value: 'headerValue', + type: DropDownOptionType.Disable + }, + { + label: 'Second Option Label', + value: 'secondOptionValue', + type: DropDownOptionType.Simple + }, + { + label: 'Ruler Label', + value: 'rulerValue', + type: DropDownOptionType.HorizontalLine + }, + { + label: 'Third Option Label', + value: 'thirdOptionValue', + type: DropDownOptionType.Simple + }, + { + label: 'Fourth Option Label', + value: 'FourthOptionValue', + type: DropDownOptionType.Simple + }, + { + label: 'Fifth Option Label', + value: 'fifthOptionValue', + type: DropDownOptionType.Simple + }, + { + label: 'Ruler Label', + value: 'rulerValue', + type: DropDownOptionType.HorizontalLine + }, + { + label: 'Third Option Label', + value: 'thirdOptionValue', + type: DropDownOptionType.Simple + }, + { + label: 'Fourth Option Label', + value: 'FourthOptionValue', + type: DropDownOptionType.Simple + }, + { + label: 'Fifth Option Label', + value: 'fifthOptionValue', + type: DropDownOptionType.Simple + } +]; + +export default experimentOn('DropDown') + .group("DropDown", [ + { + id: 'normalDropDown', + showSource: true, + context: { + options: options1, + onChange: function(option) { + this.valueSelected = option.value; + } + }, + title: 'Normal DropDown', + description: 'Normal DropDown', + template: ` + <sdc-dropdown label="Hi I am a label" placeHolder="Please choose option" [options]="options" (changed)="onChange($event)"></sdc-dropdown> + <div style="margin: 10px 0 30px 0px; font-size:18px">Selected value:<strong style="font-weight: 700">{{valueSelected}}</strong></div> + ` + }, { + id: 'groupDropDown', + showSource: true, + context: { + options: options2, + onChange: function(option) { + this.valueSelected = option.value; + } + }, + title: 'DropDown with groups', + description: 'DropDown with groups', + template: ` + <sdc-dropdown label="Hi I am a label" placeHolder="Please choose option" [options]="options" (changed)="onChange($event)"></sdc-dropdown> + <div style="margin: 10px 0 30px 0px; font-size:18px">Selected value:<strong style="font-weight: 900">{{valueSelected}}</strong></div> + ` + }, + { + id: 'groupDropDownPreSelect', + showSource: true, + context: { + options: options2, + onChange: function(option) { + this.valueSelected = option.value; + } + }, + title: 'DropDown with groups and pre-selected value', + description: 'DropDown with groups and pre-selected value', + template: ` + <sdc-dropdown label="Hi I am a label" + placeHolder="Please choose option" + [options]="options" + [selectedOption]="{label: 'does not matter', value: 'firstOptionValue'}" + (changed)="onChange($event)"></sdc-dropdown> + <div style="margin: 10px 0 30px 0px; font-size:18px">Selected value:<strong style="font-weight: 900">{{valueSelected}}</strong></div> + ` + }, + { + id: 'headlesspDropDown', + showSource: true, + context: { + options: options2, + dropDownHedlessType: DropDownTypes.Headless, + onChange: function(option) { + this.valueSelected = option.value; + } + }, + title: 'Headless and Labeless DropDown', + description: 'Headless and labeless DropDown', + template: ` + <button style="margin-bottom: 10px;" SdcDropdownTrigger [dropDown]="dropDown1">Click to toggle!</button> + <sdc-dropdown #dropDown1 [options]="options" [type]="dropDownHedlessType" (changed)="onChange($event)"></sdc-dropdown> + <div style="margin: 10px 0 30px 0px; font-size:18px">Selected value:<strong style="font-weight: 900">{{valueSelected}}</strong></div> + ` + }, + { + id: 'disabledDropDown', + showSource: true, + context: { + options: options2, + onChange: function(option) { + this.valueSelected = option.value; + } + }, + title: 'Disabled DropDown', + description: 'Disabled DropDown', + template: ` + <sdc-dropdown label="Hi I am a label" + placeHolder="Please choose option" + disabled="true" + [options]="options" + (changed)="onChange($event)"></sdc-dropdown> + <div style="margin: 10px 0 30px 0px; font-size:18px">Selected value:<strong style="font-weight: 900">{{valueSelected}}</strong></div> + ` + }, + { + id: 'normalAutoDropDown', + showSource: true, + context: { + options: options1, + dropDownAutoType: DropDownTypes.Auto, + onChange: function(option) { + this.valueSelected = option.value; + } + }, + title: 'Normal Auto DropDown', + description: 'Normal Auto DropDown', + template: ` + <sdc-dropdown label="Hi I am a label" + placeHolder="Please choose option" + [type]="dropDownAutoType" + [options]="options" + (changed)="onChange($event)"></sdc-dropdown> + <div style="margin: 10px 0 30px 0px; font-size:18px">Selected value:<strong style="font-weight: 900">{{valueSelected}}</strong></div> + ` + } + ]); diff --git a/stories/ng2-component-lab/filter-bar.component.exp.ts b/stories/ng2-component-lab/filter-bar.component.exp.ts new file mode 100644 index 0000000..12a287d --- /dev/null +++ b/stories/ng2-component-lab/filter-bar.component.exp.ts @@ -0,0 +1,56 @@ +import { experimentOn } from '@islavi/ng2-component-lab'; +import { SearchFilterPipe } from './pipes/search-filter-pipe'; + +const action = (e): void => { + console.log("The search query was changed to: ", e); +}; + +export default experimentOn('Filter Bar').group('FilterBar', [ + { + id: 'filterBar', + title: 'Filter bar', + description: ` + The filter bar component text is updated (after debounce time, + default 200 miliseconds) while user write something. + In this example the event on search query changed: + const action = (e): void => { + console.log("The search query was changed to: ", e); + }; + `, + context: { + onChange: action + }, + showSource: true, + template: ` + <sdc-filter-bar placeholder="filter text" + label="filter example:" + [(searchQuery)]="searchText" + (searchQueryChange)="onChange($event)"> + </sdc-filter-bar> + <br> + Text to search: {{searchText}} + ` + }, + { + id: 'filterBarWithData', + title: 'Filter bar with data', + description: ` + Example of filter bar component with debounce 100 miliseconds, + and with example pipe for filterring. + `, + context: { + data: ['apple', 'banana', 'orange', 'peach'] + }, + showSource: true, + template: ` + <sdc-filter-bar placeholder="filter text" + label="filter example:" + [debounceTime]="100" + [(searchQuery)]="searchText"> + </sdc-filter-bar> + <ul style="height: 100px; background-color: #eeeeee;"> + <li *ngFor="let item of data | PipeSearchFilter:searchText">{{item}}</li> + </ul> + ` + } +]); diff --git a/stories/ng2-component-lab/infinite-scroll.component.exp.ts b/stories/ng2-component-lab/infinite-scroll.component.exp.ts new file mode 100644 index 0000000..bd20be5 --- /dev/null +++ b/stories/ng2-component-lab/infinite-scroll.component.exp.ts @@ -0,0 +1,166 @@ +import { experimentOn } from '@islavi/ng2-component-lab'; + +const basicContext = { + scrollContainerId: 'scrollContainer', + numLines: Array(20).fill(null), + hitBottomCount: 0, + pageCount: 0, + isPageLoading: false, + insertPageImmediately: function(pageNum) { + const scrollContainerElem: HTMLElement = document.getElementById(this.scrollContainerId); + scrollContainerElem.appendChild(document.createElement('hr')); + Array(10).fill(null).forEach((_, i) => { + const lineElem = document.createElement('div'); + lineElem.innerHTML = `Page ${pageNum} - line ${i + 1}`; + scrollContainerElem.appendChild(lineElem); + }); + }, + loadPageAsync: function(pageNum, timeout) { + return new Promise((resolve) => { + setTimeout(() => { + this.insertPageImmediately(pageNum); + resolve(); + }, timeout); + }); + }, + onScrollHitBottom: function() { + this.hitBottomCount++; + } +}; + +const basicStyle = ` + .scroll-container { + margin: 12px; + border: none; + padding: 5px; + width: 200px; + height: 100px; + overflow: auto; + font-size: 20px !important; + box-shadow: #666 1px 1px 10px; + } + + .example-source { + background: #eeeeee; + padding: 10px; + border: 1px solid #999999; + } + .example-source pre { + overflow: hidden; + background: #dddddd; + margin-top: 5px; + padding: 5px; + user-select: text; + } +`; +const makeBasicStyleDistance = (distance: number) => ` + .scroll-container::after { + display: block; + content: ''; + height: ${distance}px; + background: red; + } +`; + +export default experimentOn('Infinite-Scroll') + .group("Infinite Scroll",[ + { + id: 'infiniteScrollUsage', + showSource: true, + context: Object.assign({}, basicContext), + title: 'Infinite scroll usage', + description: 'Infinite scroll usage', + styles: [basicStyle], + template: ` + <div (infiniteScroll)="onScrollHitBottom()" class="scroll-container"> + <div *ngFor="let _i of numLines; let i=index"> + Line {{i + 1}} + </div> + </div> + Hit bottom for <b>{{hitBottomCount}}</b> times! + <div class="example-source"> + <b>onScrollHitBottom declaration:</b> + <pre>{{onScrollHitBottom}}</pre> + </div> + ` + }, + { + id: 'infiniteScrollUsageWithDistance', + showSource: true, + title: 'Infinite scroll usage with distance', + context: Object.assign({}, basicContext), + styles: [basicStyle, makeBasicStyleDistance(50)], + description: '', + template: ` + <div (infiniteScroll)="onScrollHitBottom()" [infiniteScrollDistance]="50" class="scroll-container"> + <div *ngFor="let _i of numLines; let i=index"> + Line {{i + 1}} + </div> + </div> + Hit bottom for <b>{{hitBottomCount}}</b> times! + <div class="example-source"> + <b>onScrollHitBottom declaration:</b> + <pre>{{onScrollHitBottom}}</pre> + </div> + ` + }, + { + id: 'infiniteScrollUsageWithExpandingContent', + title: 'Infinite scroll usage with expanding content', + showSource: true, + context: Object.assign({}, basicContext, { + scrollContainerId: 'scrollContainer1', + onScrollHitBottom: function() { + this.hitBottomCount++; + this.insertPageImmediately(this.pageCount + 1); + this.pageCount++; + } + }), + styles: [basicStyle, makeBasicStyleDistance(20)], + template: ` + <div (infiniteScroll)="onScrollHitBottom()" [infiniteScrollDistance]="20" class="scroll-container" id="{{scrollContainerId}}"> + <div *ngFor="let _i of numLines; let i=index"> + Line {{i + 1}} + </div> + </div> + Hit bottom for <b>{{hitBottomCount}}</b> times!<br/> + Loaded {{pageCount}} pages! + <div class="example-source"> + <b>onScrollHitBottom declaration:</b> + <pre>{{onScrollHitBottom}}</pre> + </div> + ` + }, + { + id: 'infiniteScrollUsageWithExpandingContentAsynchronous', + title: 'Infinite scroll usage with expanding content asynchronous', + showSource: true, + context: Object.assign({}, basicContext, { + scrollContainerId: 'scrollContainer2', + onScrollHitBottom: function() { + this.hitBottomCount++; + if (!this.isPageLoading) { + this.isPageLoading = true; + this.loadPageAsync(this.pageCount + 1, 5000).then(() => { + this.pageCount++; + this.isPageLoading = false; + }); + } + } + }), + styles: [basicStyle, makeBasicStyleDistance(20)], + template: ` + <div (infiniteScroll)="onScrollHitBottom()" [infiniteScrollDistance]="20" class="scroll-container" id="{{scrollContainerId}}"> + <div *ngFor="let _i of numLines; let i=index"> + Line {{i + 1}} + </div> + </div> + Hit bottom for <b>{{hitBottomCount}}</b> times!<br/> + Loaded {{pageCount}} pages! <span *ngIf="isPageLoading">LOADING page #{{this.pageCount + 1}} ...</span> + <div class="example-source"> + <b>onScrollHitBottom declaration:</b> + <pre>{{onScrollHitBottom}}</pre> + </div> + ` + } + ]); diff --git a/stories/ng2-component-lab/input.component.exp.ts b/stories/ng2-component-lab/input.component.exp.ts new file mode 100644 index 0000000..7e931d6 --- /dev/null +++ b/stories/ng2-component-lab/input.component.exp.ts @@ -0,0 +1,79 @@ +import { experimentOn } from '@islavi/ng2-component-lab'; + +const valueChange = (value: any): void => { + console.log('The value was changed! >>>>', value); +}; + +export default experimentOn('Input') + .group("Input",[ + { + id: 'normalInput', + showSource: true, + title: 'Normal input', + description: 'Normal input', + template: ` + <sdc-input label="Please Enter value" name="myValue" testId="myTestId"></sdc-input> + ` + }, + { + id: 'disabledInput', + showSource: true, + title: 'Disabled input', + description: 'Disabled input', + template: ` + <sdc-input [disabled]="true"></sdc-input> + ` + }, + { + id: 'InputTypeNumber', + showSource: true, + title: 'Input type number', + description: 'Input type number', + template: ` + <sdc-input type='number'></sdc-input> + ` + }, + { + id: 'Input required', + title: 'Input required', + description: 'Input required (this add red * to the label, but does not perform validation, use sdc-validation for validation)', + showSource: true, + template: ` + <sdc-input label="Please Enter Value" required="true" [maxLength]="5"></sdc-input> + ` + }, + { + id: 'inputWithMaxLength', + title: 'Input with max length', + description: 'Input with max length', + showSource: true, + template: ` + <sdc-input [maxLength]="5"></sdc-input> + ` + }, + { + id: 'inputWithPlaceholder', + title: 'Input with placeholder, custom class, and tests ID', + description: 'Input with placeholder', + showSource: true, + template: ` + <sdc-input placeHolder="Text..." [classNames]="'my-custom-class another-class'" [testId]="'customTestId'"></sdc-input> + ` + }, + { + id: 'inputWithDebounce', + title: 'Input with debounce time', + description: `<pre>On value change event code: + const valueChange = (value: any): void => { + console.log('The value was changed! >>>>', value); + }; + This event will happen 5 sec after the change + </pre>`, + showSource: true, + context: { + changeEvent: valueChange + }, + template: ` + <sdc-input [debounceTime]="5000" (valueChange)="changeEvent($event)"></sdc-input> + ` + }]); diff --git a/stories/ng2-component-lab/modals.component.exp.ts b/stories/ng2-component-lab/modals.component.exp.ts new file mode 100644 index 0000000..e7e38bc --- /dev/null +++ b/stories/ng2-component-lab/modals.component.exp.ts @@ -0,0 +1,126 @@ +import { experimentOn } from '@islavi/ng2-component-lab'; + +const sourceStyles:string =` + .example-source { + background: #eeeeee; + padding: 10px; + border: 1px solid #999999; + margin-top:30px; + } + .example-source pre { + overflow: hidden; + background: #dddddd; + margin-top: 5px; + padding: 5px; + user-select: text; + } + .example-source pre .comment{ + color:#666; + opacity:0.4; + font-style:italic; + transition: opacity 400ms ease-in; + } + .example-source pre:hover .comment { + opacity:1; + } +`; + +export default experimentOn('Modals') + .group("Modals", [ + { + id: 'standardModal', + showSource: false, + title: 'Standard modal', + description: 'Opens a modal with a custom title, message, and confirm button with a callback.', + template: ` + <modal-consumer [action]="'openActionModal'"></modal-consumer> + <div class="example-source">Source Code: + <pre> + const MODAL_CONTENT = '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'; + + this.modalService.openActionModal('Standard Modal', MODAL_CONTENT, "OK", this.onConfirmAction, "sampleTestId"); + + private onConfirmAction = ():void => {{ '{' }} + alert("Action has been confirmed"); + {{ '}' }}; + </pre></div>`, + styles: [sourceStyles] + }, + { + id: 'alertModal', + showSource: false, + title: 'Alert modal', + description: 'Opens a standard alert modal with a custom title and message.', + template: ` + + + <modal-consumer [action]="'openAlertModal'"></modal-consumer> + <div class="example-source">Source Code: + <pre> + const MODAL_CONTENT = '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'; + + this.modalService.openAlertModal("Alert Title", MODAL_CONTENT, "Continue", this.onConfirmAction, "sampleTestId"); + </pre></div>`, + styles: [sourceStyles] + }, + { + id: 'errorModal', + showSource: false, + title: 'Error modal', + description: `Opens a standard error modal with a custom message.`, + template: `<modal-consumer [action]="'openErrorModal'"></modal-consumer> + <div class="example-source">Source Code: + <pre> + + this.modalService.openErrorModal("An error has occurred!", "sampleTestId"); + </pre></div>`, + styles: [sourceStyles] + }, + { + id: 'customModal1', + showSource: false, + title: 'Custom modal 1', + description: 'Opens a modal with dynamic inner content and customizable title, buttons, and callbacks.', + template: ` + <modal-consumer [action]="'openCustomModal1'"></modal-consumer> + <div class="example-source">Source Code: + <pre> + + <span class="comment">//create modal config object </span> + let modalConfig:IModalConfig = {{ '{' }} + size: ModalSize.small, + title: 'Title', + type: ModalType.standard, + buttons: [ + {{ '{' }}text:"Save", size:"'x-small'", callback:this.customModalOnSave, closeModal:false{{ '}' }}, + {{ '{' }}text:"Cancel", size:"'x-small'", closeModal:true{{ '}' }}] + {{ '}' }}; + + <span class="comment">//open modal with dynamically created 'modalInnerContent' example component. Send data object with input 'name'. </span> + this.modalService.openCustomModal(modalConfig, ModalInnerContent, {{ '{' }}name: "Sample Content"{{ '}' }}); + + private customModalOnDone = ():void => {{ '{' }} + let currentInstance:any = this.modalService.getCurrentInstance(); + alert("Save with result: " + currentInstance.innerModalContent.instance.name); + {{ '}' }}; + + private customModalOnSave = ():void => {{ '{' }} + let currentInstance:any = this.modalService.getCurrentInstance(); + alert("Save with result: " + currentInstance.innerModalContent.instance.name); + {{ '}' }}; + </pre></div>`, + styles: [sourceStyles] + }, + { + id: 'customModal2', + showSource: false, + title: 'Custom modal 2', + description: 'Opens a modal with, and change his buttons and title', + template: ` + <modal-consumer [action]="'openCustomModal2'"></modal-consumer> + `, + styles: [sourceStyles] + } + ]); diff --git a/stories/ng2-component-lab/notification.component.exp.ts b/stories/ng2-component-lab/notification.component.exp.ts new file mode 100644 index 0000000..ba2ba24 --- /dev/null +++ b/stories/ng2-component-lab/notification.component.exp.ts @@ -0,0 +1,11 @@ +import { experimentOn } from '@islavi/ng2-component-lab'; + +export default experimentOn('Notification') + .group("Default Notification",[ + { + id: 'notificationContainer', + showSource: true, + title: 'Notification Container', + description: 'container example ...', + template: `<notifications-example></notifications-example>`, + }]); diff --git a/stories/ng2-component-lab/pipes/search-filter-pipe.ts b/stories/ng2-component-lab/pipes/search-filter-pipe.ts new file mode 100644 index 0000000..5469eb4 --- /dev/null +++ b/stories/ng2-component-lab/pipes/search-filter-pipe.ts @@ -0,0 +1,15 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe ({ + name: 'PipeSearchFilter', +}) +export class SearchFilterPipe implements PipeTransform { + public transform(value, text: string) { + if (!text || !text.length) { + return value; + } + return value.filter((item) => { + return item.toLowerCase().indexOf(text.toLowerCase()) > -1; + }); + } +} diff --git a/stories/ng2-component-lab/popup-menu.component.exp.ts b/stories/ng2-component-lab/popup-menu.component.exp.ts new file mode 100644 index 0000000..12da361 --- /dev/null +++ b/stories/ng2-component-lab/popup-menu.component.exp.ts @@ -0,0 +1,104 @@ +import { experimentOn } from '@islavi/ng2-component-lab'; + +export default experimentOn('Menu') + .group("Popups",[ + { + id: 'basicPopupMenuStatic', + showSource: true, + title: 'Basic popup menu (static)', + description: 'Basic popup menu (static)', + template: ` + <popup-menu-list [open]="true"> + <popup-menu-item> + <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="18" height="18" viewBox="0 0 24 24"> + <defs> + <path id="add-copy-a1" d="M11,0 C4.9,0 0,4.9 0,11 C0,17.1 4.9,22 11,22 C17.1,22 22,17.1 22,11 C22,4.9 17.1,0 11,0 M15,10 L12,10 L12,7 C12,6.4 11.6,6 11,6 C10.4,6 10,6.4 10,7 L10,10 L7,10 C6.4,10 6,10.4 6,11 C6,11.6 6.4,12 7,12 L10,12 L10,15 C10,15.6 10.4,16 11,16 C11.6,16 12,15.6 12,15 L12,12 L15,12 C15.6,12 16,11.6 16,11 C16,10.4 15.6,10 15,10"/> + </defs> + <g fill="none" fill-rule="evenodd" transform="translate(1 1)"> + <use xlink:href="#add-copy-a1"/> + </g> + </svg> + First + </popup-menu-item> + <popup-menu-item type="selected"> + <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="18" height="18" viewBox="0 0 24 24"> + <defs> + <path id="add-copy-a2" d="M11,0 C4.9,0 0,4.9 0,11 C0,17.1 4.9,22 11,22 C17.1,22 22,17.1 22,11 C22,4.9 17.1,0 11,0 M15,10 L12,10 L12,7 C12,6.4 11.6,6 11,6 C10.4,6 10,6.4 10,7 L10,10 L7,10 C6.4,10 6,10.4 6,11 C6,11.6 6.4,12 7,12 L10,12 L10,15 C10,15.6 10.4,16 11,16 C11.6,16 12,15.6 12,15 L12,12 L15,12 C15.6,12 16,11.6 16,11 C16,10.4 15.6,10 15,10"/> + </defs> + <g fill="none" fill-rule="evenodd" transform="translate(1 1)"> + <use xlink:href="#add-copy-a2"/> + </g> + </svg> + Selected + </popup-menu-item> + <popup-menu-item type="disabled"> + <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="18" height="18" viewBox="0 0 24 24"> + <defs> + <path id="add-copy-a3" d="M11,0 C4.9,0 0,4.9 0,11 C0,17.1 4.9,22 11,22 C17.1,22 22,17.1 22,11 C22,4.9 17.1,0 11,0 M15,10 L12,10 L12,7 C12,6.4 11.6,6 11,6 C10.4,6 10,6.4 10,7 L10,10 L7,10 C6.4,10 6,10.4 6,11 C6,11.6 6.4,12 7,12 L10,12 L10,15 C10,15.6 10.4,16 11,16 C11.6,16 12,15.6 12,15 L12,12 L15,12 C15.6,12 16,11.6 16,11 C16,10.4 15.6,10 15,10"/> + </defs> + <g fill="none" fill-rule="evenodd" transform="translate(1 1)"> + <use xlink:href="#add-copy-a3"/> + </g> + </svg> + Disabled + </popup-menu-item> + <popup-menu-item type="separator"></popup-menu-item> + <popup-menu-item> + <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="18" height="18" viewBox="0 0 24 24"> + <defs> + <path id="add-copy-a4" d="M11,0 C4.9,0 0,4.9 0,11 C0,17.1 4.9,22 11,22 C17.1,22 22,17.1 22,11 C22,4.9 17.1,0 11,0 M15,10 L12,10 L12,7 C12,6.4 11.6,6 11,6 C10.4,6 10,6.4 10,7 L10,10 L7,10 C6.4,10 6,10.4 6,11 C6,11.6 6.4,12 7,12 L10,12 L10,15 C10,15.6 10.4,16 11,16 C11.6,16 12,15.6 12,15 L12,12 L15,12 C15.6,12 16,11.6 16,11 C16,10.4 15.6,10 15,10"/> + </defs> + <g fill="none" fill-rule="evenodd" transform="translate(1 1)"> + <use xlink:href="#add-copy-a4"/> + </g> + </svg> + Second + </popup-menu-item> + </popup-menu-list> + ` + }, + { + id: 'basicMenuRelative', + title: 'Basic menu (relative)', + description: 'Basic menu (relative)', + showSource: true, + context: { + showSelectedItem: (msg, color) => { + const elm = document.getElementById('selectedItem'); + elm.style.color = color; + elm.innerHTML = msg; + } + }, + styles: [` + .message { + position: absolute; + top: 0; left: 0; + color: white; + } + .click-area { + position: absolute; + width: 100%; + height: 100%; + } + `], + template: + ` + <div style="position: relative; width: 400px; height: 200px; background: blue;"> + <span class="message">Click in the box...<br/> + (popup menu is {{menuStatus === undefined ? 'never opened' : (menuStatus ? 'open at '+menuPos.x+' , '+menuPos.y : 'closed')}})<br/> + selected: <span #selectedItem id="selectedItem"></span> + </span> + <div class="click-area" + (click)="menu.position = {x:$event.offsetX, y:$event.offsetY}; mopen=true;"> + <popup-menu-list [(open)]="mopen" (openChange)="menuStatus=$event" (positionChange)="menuPos=$event" [relative]="true" #menu> + <popup-menu-item (action)="showSelectedItem('First', 'red')">First</popup-menu-item> + <popup-menu-item type="disabled">Disabled</popup-menu-item> + <popup-menu-item type="separator"></popup-menu-item> + <popup-menu-item (action)="showSelectedItem('Second', 'green')">Second</popup-menu-item> + <popup-menu-item>Third (none)</popup-menu-item> + </popup-menu-list> + </div> + </div> + ` + } + ]); diff --git a/stories/ng2-component-lab/radio.component.exp.ts b/stories/ng2-component-lab/radio.component.exp.ts new file mode 100644 index 0000000..aa3959b --- /dev/null +++ b/stories/ng2-component-lab/radio.component.exp.ts @@ -0,0 +1,179 @@ +import { experimentOn } from '@islavi/ng2-component-lab'; + +export default experimentOn('Radios') + .group("Radios",[ + { + id: 'radioButtonsGroupTwoWaysBinding', + showSource: true, + context: { + selectedValue: "val2" + }, + title: 'Radio buttons group (two ways binding)', + description: 'Radio buttons group (two ways binding)', + template: + ` + <sdc-radio-group + [legend]="'Radio Buttons Group legend'" + [(value)]="selectedValue" + [options] = "{ + items: [ + { + value: 'val1', + name: 'radio5', + label: 'Label of Radio 1' + }, + { + value: 'val2', + name: 'radio5', + label: 'Label of Radio 2' + } + ]}" + ></sdc-radio-group> + <br><div>Selected Radio: {{selectedValue}}</div> + ` + }, + { + id: 'radioButtonsGroupDisabled', + title: 'Radio buttons group disabled', + description: 'Radio buttons group disabled', + showSource: true, + context: { + selectedValue: "val1" + }, + template: ` + <sdc-radio-group + [legend]="'Radio Buttons Group Disabled legend'" + [disabled]="true" + [value]="selectedValue" + [options] = "{ + items: [{ + value: 'val1', + name: 'radio6', + label: 'Label of Radio 1' + }, { + value: 'val2', + name: 'radio6', + label: 'Label of Radio 2' + }] + }"></sdc-radio-group> + <br><div>Selected Radio: {{selectedValue}}</div> + ` + }, + { + id: 'radioButtonsGroupPartiallyDisabled', + title: 'Radio buttons group partially disabled', + description: 'Radio buttons group partially disabled', + showSource: true, + context: { + selectedValue: "val2" + }, + template: ` + <sdc-radio-group + [legend]="'Radio Buttons Group partially disabled'" + [(value)]="selectedValue" + [options] = "{ + items: [{ + value: 'val1', + name: 'radio7', + label: 'Label of Radio 1' + }, { + value: 'val2', + disabled: 'true', + name: 'radio7', + label: 'Label of Radio 2' + }, { + value: 'val3', + name: 'radio7', + label: 'Label of Radio 3' + }] + }"></sdc-radio-group> + <br><div>Selected Radio: {{selectedValue}}</div> + ` + }, + { + id: 'radioButtonsGroupVertical', + title: 'Radio buttons group vertical', + description: 'Radio buttons group vertical', + showSource: true, + context: { + selectedValue: "val1" + }, + template: ` + <sdc-radio-group + [legend]="'Radio Buttons Group Vertical legend'" + [(value)]="selectedValue" + [direction]="'horizontal'" + [options]="{ + items: [{ + value:'val1', + name: 'radio8', + label: 'Label of Radio1' + }, { + value:'val2', + name: 'radio8', + label: 'Label of Radio2' + }] + }"></sdc-radio-group> + <br><div>Selected Radio: {{selectedValue}}</div> + ` + }, + { + id: 'radioButtonsGroupGetValue', + title: 'Radio buttons group get value', + description: 'Radio buttons group get value', + showSource: true, + context: { + selectedValue: "val1", + getSelectedValue: (val)=>{ + alert(val); + } + }, + template: ` + <sdc-radio-group + #myRadioGroup + [legend]="'Radio Buttons Group Vertical legend'" + [(value)]="selectedValue" + [options]="{ + items: [{ + value:'val1', + name: 'radio8', + label: 'Label of Radio1' + }, { + value:'val2', + name: 'radio8', + label: 'Label of Radio2' + }] + }"></sdc-radio-group> + <br><div>Selected Radio: {{selectedValue}}</div> + <br><button (click)="getSelectedValue(myRadioGroup.value)">Get selected value</button> + ` + }, + { + id: 'radioButtonsGroupSelectValue', + title: 'Radio buttons group select value', + description: 'Radio buttons group select value', + showSource: true, + context: { + selectedValue: "val1" + }, + template: ` + <sdc-radio-group + #myRadioGroup + [legend]="'Radio Buttons Group Vertical legend'" + [(value)]="selectedValue" + [options]="{ + items: [{ + value:'val1', + name: 'radio8', + label: 'Label of Radio1' + }, { + value:'val2', + name: 'radio8', + label: 'Label of Radio2' + }] + }"></sdc-radio-group> + <br><div>Selected Radio: {{selectedValue}}</div> + <br><button (click)="myRadioGroup.value='val2'">Set value to val2</button> + ` + } + ]); diff --git a/stories/ng2-component-lab/search-bar.component.exp.ts b/stories/ng2-component-lab/search-bar.component.exp.ts new file mode 100644 index 0000000..4a7e1fd --- /dev/null +++ b/stories/ng2-component-lab/search-bar.component.exp.ts @@ -0,0 +1,19 @@ +import { experimentOn } from '@islavi/ng2-component-lab'; + +export default experimentOn('Search Bar').group('SearchBar', [ + { + id: 'search-bar', + title: 'Search Bar', + description: "The search text is updated on click on the magnify", + showSource: true, + template: ` + The text to search: {{searchText}} + <sdc-search-bar placeholder="search text" + label="search example:" + [searchQuery]="searchText" + (searchQueryClick)="searchText = $event" + > + </sdc-search-bar> + ` + } +]); diff --git a/stories/ng2-component-lab/svg-icon.component.exp.ts b/stories/ng2-component-lab/svg-icon.component.exp.ts new file mode 100644 index 0000000..c87727d --- /dev/null +++ b/stories/ng2-component-lab/svg-icon.component.exp.ts @@ -0,0 +1,14 @@ +import { experimentOn } from '@islavi/ng2-component-lab'; +import { Mode, Size } from "../../src/angular/common/enums"; + +export default experimentOn('Icons') + .group('SvgIcons', [ + { + id: 'SvgIcons', + showSource: false, + title: 'SVG Icons', + template: ` + <svg-icons-table></svg-icons-table> + ` + } + ]); diff --git a/stories/ng2-component-lab/tabs.component.exp.ts b/stories/ng2-component-lab/tabs.component.exp.ts new file mode 100644 index 0000000..ff4c0c5 --- /dev/null +++ b/stories/ng2-component-lab/tabs.component.exp.ts @@ -0,0 +1,28 @@ +import { experimentOn } from '@islavi/ng2-component-lab'; + +export default experimentOn('Tabs').group('Tabs', [ + { + id: 'simpleTabs', + title: 'Simple tabs with text title', + description: "Simple tabs with text title", + showSource: true, + template: ` + <sdc-tabs> + <sdc-tab title="tab1">This is tab 1</sdc-tab> + <sdc-tab title="tab2">This is tab 2</sdc-tab> + </sdc-tabs> + ` + }, + { + id: 'simpleTabsWithIcons', + title: 'Simple tabs with icon title', + description: "Simple tabs with icon title", + showSource: true, + template: ` + <sdc-tabs> + <sdc-tab titleIcon="inputs-o">This is tab 1</sdc-tab> + <sdc-tab titleIcon="edit-file-o">This is tab 2</sdc-tab> + </sdc-tabs> + ` + } +]); diff --git a/stories/ng2-component-lab/tag-cloud.component.exp.ts b/stories/ng2-component-lab/tag-cloud.component.exp.ts new file mode 100644 index 0000000..83ad03c --- /dev/null +++ b/stories/ng2-component-lab/tag-cloud.component.exp.ts @@ -0,0 +1,61 @@ +import { experimentOn } from '@islavi/ng2-component-lab'; + +export default experimentOn('Tag Cloud').group('Tag Cloud', [ + { + id: 'list', + title: 'Simple tag-cloud', + description: 'Simple tag-cloud', + showSource: true, + template: ` + <sdc-tag-cloud label="Please Enter value" + placeholder="Type a value and then click enter or '+'" + [list]="['aaa', 'bbb']"> + + </sdc-tag-cloud> + ` + }, + { + id: 'unique-tag-cloud', + title: 'List with unique validation', + description: 'List with unique validation', + showSource: true, + template: ` + <sdc-tag-cloud label="Please Enter value" + placeholder="Type a value and then click enter or '+'" + [list]="['aaa', 'bbb']" + [isUniqueList]="true" + [uniqueErrorMessage]="'This value is already in the list'"> + + </sdc-tag-cloud> + ` + }, + { + id: 'disabled-tag-cloud', + title: 'Disabled tag-cloud', + description: 'When the parameter isViewOnly = true, the tag-cloud control is disabled', + showSource: true, + template: ` + <sdc-tag-cloud label="Please Enter value" + placeholder="Type a value and then click enter or '+'" + [list]="['aaa', 'bbb']" + [isViewOnly]="true"> + + </sdc-tag-cloud> + ` + }, + { + id: 'tag-cloud-with-disabled-items', + title: 'List with some readonly items', + description: 'The parameter isViewOnly can get an array of indexes of tag-cloud items.', + showSource: true, + template: ` + <sdc-tag-cloud label="Please Enter value" + placeholder="Type a value and then click enter or '+'" + [list]="['aaa', 'bbb', 'ccc', 'ddd']" + [isViewOnly]="[1,3]"> + + </sdc-tag-cloud> + ` + } +]); + diff --git a/stories/ng2-component-lab/tiles.component.exp.ts b/stories/ng2-component-lab/tiles.component.exp.ts new file mode 100644 index 0000000..572b6ca --- /dev/null +++ b/stories/ng2-component-lab/tiles.component.exp.ts @@ -0,0 +1,194 @@ +import { experimentOn } from '@islavi/ng2-component-lab'; + +const alert1 = window.alert; +const console1 = console.log; + +export default experimentOn('Tiles') + .group("Tiles",[ + { + id: 'tileSampleBlue', + showSource: true, + context: { + alert: alert1, + console: console1 + }, + title: 'Tile sample blue', + description: 'Tile sample blue', + template: ` + <sdc-tile> + <sdc-tile-header> + <div class="blue">P</div> + </sdc-tile-header> + <sdc-tile-content> + <div class="sdc-tile-content-icon blue"> + <div class="svg-icon-wrapper" > + <svg class="svg-icon __vsp" viewBox="0 0 59.5 40" id="vsp_icon"> + <title> + vsp_new_icon + </title> + <g id="Layer_2" data-name="Layer 2"> + <g id="vlm_icon" data-name="vlm icon"> + <path d="M58.28,30.74c-1.49-1.82-3-2.7-4.67-2.74a8.5,8.5,0,0,0-16.22-2.44,6.93,6.93,0,0,0-4.06.66A7.23,7.23,0,0,0,36.42,40H53.5a6,6,0,0,0,6-6A5.18,5.18,0,0,0,58.28,30.74ZM53.5,38H36.42a5.25,5.25,0,0,1-5.21-5.91,5.32,5.32,0,0,1,3-4.06,5,5,0,0,1,2.21-.53,5.25,5.25,0,0,1,1.35.18l.92.24L39,27A6.5,6.5,0,0,1,51.67,29v1.3l1.17-.2c1-.17,2.17-.17,3.91,2a3.18,3.18,0,0,1,.76,2A4,4,0,0,1,53.5,38Z"> + </path> + <path d="M49,0,4,.17A3.79,3.79,0,0,0,0,3.69V7.94H0v2H0V36.31C0,38.35,2,40,4.25,40l20.84-.08a1,1,0,0,0,0-1.92L4,38.08a1.89,1.89,0,0,1-2-1.76V10H51v7a1,1,0,0,0,2,0V3.53A3.79,3.79,0,0,0,49,0ZM2,8V3.76A1.89,1.89,0,0,1,4,2l45-.16a1.89,1.89,0,0,1,2,1.76V8Z"> + </path> + </g> + </g> + </svg> + </div> + </div> + <div class="sdc-tile-content-info"> + <div class="sdc-tile-info-line title">Router</div> + <div class="sdc-tile-info-line subtitle">test</div> + </div> + </sdc-tile-content> + <sdc-tile-footer> + <span class="sdc-tile-footer-cell">Footer</span> + </sdc-tile-footer> + </sdc-tile> + ` + }, + { + id: 'tileSamplePurple', + title: 'Tile sample purple', + description: 'Tile sample purple', + showSource: true, + template: ` + <sdc-tile> + <sdc-tile-header> + <div class="purple">P</div> + </sdc-tile-header> + <sdc-tile-content> + <div class="sdc-tile-content-icon purple"> + <div class="svg-icon-wrapper" > + <svg class="svg-icon __vsp" viewBox="0 0 59.5 40" id="vsp_icon"> + <title> + vsp_new_icon + </title> + <g id="Layer_2" data-name="Layer 2"> + <g id="vlm_icon" data-name="vlm icon"> + <path d="M58.28,30.74c-1.49-1.82-3-2.7-4.67-2.74a8.5,8.5,0,0,0-16.22-2.44,6.93,6.93,0,0,0-4.06.66A7.23,7.23,0,0,0,36.42,40H53.5a6,6,0,0,0,6-6A5.18,5.18,0,0,0,58.28,30.74ZM53.5,38H36.42a5.25,5.25,0,0,1-5.21-5.91,5.32,5.32,0,0,1,3-4.06,5,5,0,0,1,2.21-.53,5.25,5.25,0,0,1,1.35.18l.92.24L39,27A6.5,6.5,0,0,1,51.67,29v1.3l1.17-.2c1-.17,2.17-.17,3.91,2a3.18,3.18,0,0,1,.76,2A4,4,0,0,1,53.5,38Z"> + </path> + <path d="M49,0,4,.17A3.79,3.79,0,0,0,0,3.69V7.94H0v2H0V36.31C0,38.35,2,40,4.25,40l20.84-.08a1,1,0,0,0,0-1.92L4,38.08a1.89,1.89,0,0,1-2-1.76V10H51v7a1,1,0,0,0,2,0V3.53A3.79,3.79,0,0,0,49,0ZM2,8V3.76A1.89,1.89,0,0,1,4,2l45-.16a1.89,1.89,0,0,1,2,1.76V8Z"> + </path> + </g> + </g> + </svg> + </div> + </div> + <div class="sdc-tile-content-info"> + <span class="sdc-tile-info-line title">Router</span> + <div class="sdc-tile-info-line subtitle">test</div> + </div> + </sdc-tile-content> + <sdc-tile-footer> + <span class="sdc-tile-footer-cell"> Footer </span> + </sdc-tile-footer> + </sdc-tile> + ` + }, + { + id: 'tileSampleWithoutFooter', + title: 'Tile sample without footer', + description: 'Tile sample without footer', + showSource: true, + template: ` + <sdc-tile> + <sdc-tile-header> + <div class="purple">P</div> + </sdc-tile-header> + <sdc-tile-content> + <div class="sdc-tile-content-icon purple"> + <div class="svg-icon-wrapper" > + <svg class="svg-icon __vsp" viewBox="0 0 59.5 40" id="vsp_icon"> + <title> + vsp_new_icon + </title> + <g id="Layer_2" data-name="Layer 2"> + <g id="vlm_icon" data-name="vlm icon"> + <path d="M58.28,30.74c-1.49-1.82-3-2.7-4.67-2.74a8.5,8.5,0,0,0-16.22-2.44,6.93,6.93,0,0,0-4.06.66A7.23,7.23,0,0,0,36.42,40H53.5a6,6,0,0,0,6-6A5.18,5.18,0,0,0,58.28,30.74ZM53.5,38H36.42a5.25,5.25,0,0,1-5.21-5.91,5.32,5.32,0,0,1,3-4.06,5,5,0,0,1,2.21-.53,5.25,5.25,0,0,1,1.35.18l.92.24L39,27A6.5,6.5,0,0,1,51.67,29v1.3l1.17-.2c1-.17,2.17-.17,3.91,2a3.18,3.18,0,0,1,.76,2A4,4,0,0,1,53.5,38Z"> + </path> + <path d="M49,0,4,.17A3.79,3.79,0,0,0,0,3.69V7.94H0v2H0V36.31C0,38.35,2,40,4.25,40l20.84-.08a1,1,0,0,0,0-1.92L4,38.08a1.89,1.89,0,0,1-2-1.76V10H51v7a1,1,0,0,0,2,0V3.53A3.79,3.79,0,0,0,49,0ZM2,8V3.76A1.89,1.89,0,0,1,4,2l45-.16a1.89,1.89,0,0,1,2,1.76V8Z"> + </path> + </g> + </g> + </svg> + </div> + </div> + <div class="sdc-tile-content-info"> + <span class="sdc-tile-info-line title">Router</span> + <div class="sdc-tile-info-line subtitle">test</div> + </div> + </sdc-tile-content> + </sdc-tile> + ` + }, + { + id: 'tileSampleWithoutHeader', + title: 'Tile sample without header', + description: 'Tile sample without header', + showSource: true, + template: ` + <sdc-tile> + <sdc-tile-content> + <div class="sdc-tile-content-icon purple"> + <div class="svg-icon-wrapper" > + <svg class="svg-icon __vsp" viewBox="0 0 59.5 40" id="vsp_icon"> + <title> + vsp_new_icon + </title> + <g id="Layer_2" data-name="Layer 2"> + <g id="vlm_icon" data-name="vlm icon"> + <path d="M58.28,30.74c-1.49-1.82-3-2.7-4.67-2.74a8.5,8.5,0,0,0-16.22-2.44,6.93,6.93,0,0,0-4.06.66A7.23,7.23,0,0,0,36.42,40H53.5a6,6,0,0,0,6-6A5.18,5.18,0,0,0,58.28,30.74ZM53.5,38H36.42a5.25,5.25,0,0,1-5.21-5.91,5.32,5.32,0,0,1,3-4.06,5,5,0,0,1,2.21-.53,5.25,5.25,0,0,1,1.35.18l.92.24L39,27A6.5,6.5,0,0,1,51.67,29v1.3l1.17-.2c1-.17,2.17-.17,3.91,2a3.18,3.18,0,0,1,.76,2A4,4,0,0,1,53.5,38Z"> + </path> + <path d="M49,0,4,.17A3.79,3.79,0,0,0,0,3.69V7.94H0v2H0V36.31C0,38.35,2,40,4.25,40l20.84-.08a1,1,0,0,0,0-1.92L4,38.08a1.89,1.89,0,0,1-2-1.76V10H51v7a1,1,0,0,0,2,0V3.53A3.79,3.79,0,0,0,49,0ZM2,8V3.76A1.89,1.89,0,0,1,4,2l45-.16a1.89,1.89,0,0,1,2,1.76V8Z"> + </path> + </g> + </g> + </svg> + </div> + </div> + <div class="sdc-tile-content-info"> + <span class="sdc-tile-info-line title">Router</span> + <div class="sdc-tile-info-line subtitle">test</div> + </div> + </sdc-tile-content> + <sdc-tile-footer> + <span class="sdc-tile-footer-cell"> Footer </span> + </sdc-tile-footer> + </sdc-tile> + ` + }, + { + id: 'tileJustWithInfo', + title: 'Tile just with info', + description: 'Tile just with info', + showSource: true, + template: ` + <sdc-tile> + <sdc-tile-content> + <div class="sdc-tile-content-icon purple"> + <div class="svg-icon-wrapper" > + <svg class="svg-icon __vsp" viewBox="0 0 59.5 40" id="vsp_icon"> + <title> + vsp_new_icon + </title> + <g id="Layer_2" data-name="Layer 2"> + <g id="vlm_icon" data-name="vlm icon"> + <path d="M58.28,30.74c-1.49-1.82-3-2.7-4.67-2.74a8.5,8.5,0,0,0-16.22-2.44,6.93,6.93,0,0,0-4.06.66A7.23,7.23,0,0,0,36.42,40H53.5a6,6,0,0,0,6-6A5.18,5.18,0,0,0,58.28,30.74ZM53.5,38H36.42a5.25,5.25,0,0,1-5.21-5.91,5.32,5.32,0,0,1,3-4.06,5,5,0,0,1,2.21-.53,5.25,5.25,0,0,1,1.35.18l.92.24L39,27A6.5,6.5,0,0,1,51.67,29v1.3l1.17-.2c1-.17,2.17-.17,3.91,2a3.18,3.18,0,0,1,.76,2A4,4,0,0,1,53.5,38Z"> + </path> + <path d="M49,0,4,.17A3.79,3.79,0,0,0,0,3.69V7.94H0v2H0V36.31C0,38.35,2,40,4.25,40l20.84-.08a1,1,0,0,0,0-1.92L4,38.08a1.89,1.89,0,0,1-2-1.76V10H51v7a1,1,0,0,0,2,0V3.53A3.79,3.79,0,0,0,49,0ZM2,8V3.76A1.89,1.89,0,0,1,4,2l45-.16a1.89,1.89,0,0,1,2,1.76V8Z"> + </path> + </g> + </g> + </svg> + </div> + </div> + <div class="sdc-tile-content-info"> + <span class="sdc-tile-info-line title">Router</span> + <div class="sdc-tile-info-line subtitle">test</div> + </div> + </sdc-tile-content> + </sdc-tile>` + } + ]); diff --git a/stories/ng2-component-lab/tooltip.directive.exp.ts b/stories/ng2-component-lab/tooltip.directive.exp.ts new file mode 100644 index 0000000..9e1dd0b --- /dev/null +++ b/stories/ng2-component-lab/tooltip.directive.exp.ts @@ -0,0 +1,231 @@ +import { experimentOn } from '@islavi/ng2-component-lab'; +import { ArrowPlacement, TooltipPlacement } from '../../src/angular/tooltip/tooltip.directive'; + +const customTemplate = ` + .sdc-custom-tooltip-template-title { + font-size: 20px; + font-weight: bold; + background-color: $black; + color: $white; + text-align: center; + } + + .sdc-custom-tooltip-template-content { + background-color: $black; + color: $white; + display: inline-block; + text-align: center; + } + + .sdc-custom-tooltip-template-image { + width: 100%; + height:100%; + display: inline-block; + text-align: center; + background-color: #ffffff; + } +`; + +export default experimentOn('Tooltip') + .group("Tooltip",[ + { + id: 'leftAlignmentTextTooltip', + showSource: true, + title: 'Tooltip with short text (left placement)', + description: 'left placement', + context: { + placement: TooltipPlacement.Left, + arrowPlacement: ArrowPlacement.LeftTop + }, + template: ` + <div style="padding-bottom: 20px; width: 350px;">Lorem ipsum dolor sit amet, + <span style="color: #009fdb" + sdc-tooltip + tooltip-text = 'A short text name, short text' + [tooltip-placement]= 'placement' + [tooltip-arrow-placement] = 'arrowPlacement'>show tooltip + </span> + ,consectetur adipiscing elit. Sed risus nisl, egestas vitae erat non, pulvinar lacinia libero. + Integer pulvinar pellentesque accumsan. + <span style="color: #009fdb" + sdc-tooltip + tooltip-text = 'A short text name, short text' + [tooltip-placement]= 'placement' + [tooltip-arrow-placement] = 'arrowPlacement'>show tooltip + </span> + Sed hendrerit lacus eu tempus pharetra + </div> + ` + }, + { + id: 'leftAlignmentMultiLineTextTooltip', + showSource: true, + title: 'Tooltip with multi line text (left placement)', + description: 'left placement', + context: { + placement: TooltipPlacement.Left, + arrowPlacement: ArrowPlacement.LeftTop + }, + template: ` + <div style="padding-bottom: 20px;"> + The is text example, + <span style="color: #009fdb" + sdc-tooltip + tooltip-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' + [tooltip-placement]= 'placement' + [tooltip-arrow-placement] = 'arrowPlacement'>show tooltip + </span> + , more text + </div> + ` + }, + { + id: 'customStyleTooltip', + showSource: true, + title: 'Tooltip with custom style', + description: 'Tooltip with custom style, define your class and style it via css.', + context: { + 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' + }, + template: ` + <![CDATA[ + .sdc-custom-tooltip { + background-color: $dark-blue; + border-color: $dark-blue; + border-radius: 10px; + } + ]]> + <div style="padding-bottom: 20px;"> + Some text example, + <span style="color: #009fdb" sdc-tooltip [tooltip-text]=text tooltip-css-class='sdc-custom-tooltip'>show tooltip</span>, more text + </div> + ` + }, + { + id: 'rightAlignmentHtmlTooltip', + showSource: true, + title: 'Tooltip with HTML template (right placement)', + description: 'right placement', + context: { + placement: TooltipPlacement.Right, + arrowPlacement: ArrowPlacement.LeftTop + }, + styles: [customTemplate], + template: ` + Template Input: + <pre><![CDATA[ + <img src="../../../assets/images/logo_onap.png" class="sdc-custom-tooltip-template-image" /> + <p class="sdc-tooltip-template-content">A long text name, very long, long text ...</p> + ]]></pre> + + <div style="padding-bottom: 20px;"> + The is text example, + <span style="color: #009fdb" + sdc-tooltip + tooltip-text = 'This is the tooltip test' + [tooltip-placement]= 'placement' + [tooltip-arrow-placement] = 'arrowPlacement' + [tooltip-template]='template'>show tooltip + </span> + , more text + </div> + + <template #template> + <img src="../../../assets/images/logo_onap.png" class="sdc-custom-tooltip-template-image" /> + <p class="sdc-tooltip-template-content">A long text name, very long, long text ...</p> + </template> + ` + }, + { + id: 'rightAlignmentHtmlCustomStyleTooltip', + showSource: true, + title: 'Tooltip with HTML template and custom style (right placement)', + description: 'right placement', + context: { + placement: TooltipPlacement.Right, + arrowPlacement: ArrowPlacement.LeftTop + }, + styles: [customTemplate], + template: ` + Template Input: + <pre><![CDATA[ + <p class="sdc-custom-tooltip-template-title sdc-tooltip-template-big-title">Title... Title... Title... Title... Title...</p> + <img src="../../../assets/images/logo_onap.png" class="sdc-custom-tooltip-template-image" /> + <p class="sdc-custom-tooltip-template-content">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</p> + ]]></pre> + + <div style="padding-bottom: 20px;"> + The is text example, + <span style="color: #009fdb" + sdc-tooltip + tooltip-text = 'This is the tooltip test' + [tooltip-placement]= 'placement' + tooltip-css-class = 'sdc-custom-tooltip' + [tooltip-arrow-placement] = 'arrowPlacement' + [tooltip-template]='template'>show tooltip + </span> + , more text + </div> + + <template #template> + <p class="sdc-custom-tooltip-template-title sdc-tooltip-template-big-title">Title... Title... Title... Title... Title...</p> + <img src="../../../assets/images/logo_onap.png" class="sdc-custom-tooltip-template-image" /> + <p class="sdc-custom-tooltip-template-content">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</p> + </template> + ` + }, + { + id: 'topAlignmentTextTooltip', + showSource: true, + title: 'Tooltip with text (top placement)', + description: 'top placement', + context: { + placement: TooltipPlacement.Top, + arrowPlacement: ArrowPlacement.LeftTop + }, + template: ` + <div style="padding-bottom: 20px;"> + The is text example, + <span style="color: #009fdb" + sdc-tooltip + tooltip-text = 'A long text name, very long, long text' + [tooltip-placement]= 'placement' + [tooltip-arrow-placement] = 'arrowPlacement'>show tooltip + </span> + , more text + </div> + ` + }, + { + id: 'bottomAlignmentHtmlTooltip', + showSource: true, + title: 'Tooltip with HTML template (bottom placement)', + description: 'bottom placement', + context: { + placement: TooltipPlacement.Bottom, + arrowPlacement: ArrowPlacement.LeftTop + }, + template: ` + Template Input: + <pre><![CDATA[ + <div class="sdc-tooltip-template-content">A long text name,</div> + <div class="sdc-tooltip-template-content">very long, long text</div> + ]]></pre> + + <div style="width:30%; height: 30px; text-align: center;"> + The is text example, + <a style="color: #009fdb; font-size: small; cursor: pointer;" + sdc-tooltip + tooltip-text = 'This is the tooltip test' + [tooltip-placement]= 'placement' + [tooltip-arrow-placement] = 'arrowPlacement' + [tooltip-template]='template' >link example</a> + , more text + </div> + <template #template> + <div class="sdc-tooltip-template-content">A long text name,</div> + <div class="sdc-tooltip-template-content">very long, long text</div> + </template> + ` + }, + ]); diff --git a/stories/ng2-component-lab/utils/mock.json b/stories/ng2-component-lab/utils/mock.json new file mode 100644 index 0000000..6cdaf3b --- /dev/null +++ b/stories/ng2-component-lab/utils/mock.json @@ -0,0 +1,6 @@ +[{"id": "redId", "color": "red"}, +{"id": "yellowId", "color": "yellow"}, +{"id": "orangeId", "color": "orange"}, +{"id": "greenId", "color": "green"}, +{"id": "whiteId", "color": "white"}, +{"id": "blackId", "color": "black"}] diff --git a/stories/ng2-component-lab/utils/pipes/keys.pipe.ts b/stories/ng2-component-lab/utils/pipes/keys.pipe.ts new file mode 100644 index 0000000..2a58cd8 --- /dev/null +++ b/stories/ng2-component-lab/utils/pipes/keys.pipe.ts @@ -0,0 +1,13 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({name: 'keys'}) +export class KeysPipe implements PipeTransform { + transform(value, args:string[]) : any { + let keys = []; + for (let key in value) { + keys.push(key); + } + return keys; + } +} + diff --git a/stories/ng2-component-lab/validation.component.exp.ts b/stories/ng2-component-lab/validation.component.exp.ts new file mode 100644 index 0000000..7f18c93 --- /dev/null +++ b/stories/ng2-component-lab/validation.component.exp.ts @@ -0,0 +1,162 @@ +import { experimentOn } from '@islavi/ng2-component-lab'; +import { RegexPatterns } from '../../src/angular/common/enums'; +import { DropDownOptionType, IDropDownOption } from './../../src/angular/form-elements/dropdown/dropdown-models'; + +const options1: IDropDownOption[] = [ + { + label: 'First Option', + value: 'First Option', + }, + { + label: 'Second Option', + value: 'Second Option', + }, + { + label: 'Third Option', + value: 'Third Option', + type: DropDownOptionType.Simple + } +]; + +export default experimentOn('Validation') + .group("Validation", [ + { + id: 'validation1', + showSource: true, + title: 'Simple validation', + description: 'Simple validation (validating that email is valid and that user inserted something in the field). \ + By default the validation starts after first key press', + context: { + emailPattern: RegexPatterns.email + }, + template: ` + <sdc-input #email label="Please enter valid email address" [maxLength]="50" required="true"></sdc-input> + <sdc-validation [validateElement]="email"> + <sdc-required-validator message="Field is required!"></sdc-required-validator> + <sdc-regex-validator message="This is not a valid email!" [pattern]="emailPattern"></sdc-regex-validator> + </sdc-validation> + ` + }, + { + id: 'validation2', + showSource: true, + title: 'Simple validation', + description: 'Simple validation', + context: { + numbersPattern: RegexPatterns.numbers, + isValueHundred: (value: any) => { + return (Number(value) === 100) ? true : false; + } + }, + template: ` + <sdc-input #numberValidator label="Please enter some number" [maxLength]="10" required="true"></sdc-input> + <sdc-validation [validateElement]="numberValidator"> + <sdc-regex-validator message="This is not a number!" [pattern]="numbersPattern"></sdc-regex-validator> + <sdc-custom-validator message="The number should be 100" [callback]="isValueHundred"></sdc-custom-validator> + </sdc-validation> + ` + }, + { + id: 'validation3', + showSource: true, + title: 'Disabled validation', + description: 'Disabled validation', + context: { + emailPattern: RegexPatterns.email + }, + template: ` + <sdc-input #email label="Please enter valid email address" [maxLength]="50" required="true"></sdc-input> + <sdc-validation [validateElement]="email" disabled='true'> + <sdc-required-validator message="Field is required!"></sdc-required-validator> + <sdc-regex-validator message="This is not a valid email!" [pattern]="emailPattern"></sdc-regex-validator> + </sdc-validation> + ` + }, + { + id: 'validation4', + showSource: true, + title: 'Validation with value already entered', + description: 'Validation with value already entered', + context: { + emailPattern: RegexPatterns.email + }, + template: ` + <sdc-input #email label="Please enter valid email address" [maxLength]="50" required="true" value="notvalidemail@"></sdc-input> + <sdc-validation [validateElement]="email"> + <sdc-required-validator message="Field is required!"></sdc-required-validator> + <sdc-regex-validator message="This is not a valid email!" [pattern]="emailPattern"></sdc-regex-validator> + </sdc-validation> + ` + }, + { + id: 'validation5', + showSource: true, + title: 'Validation with validity changed callback', + description: 'Simple validation with alert when validity changes', + context: { + numbersPattern: RegexPatterns.numbers, + validityChanged: (newState: boolean) => { + alert("Validity has changed to " + newState); + } + }, + template: ` + <sdc-input #validatorWithCallback label="Please enter a number" [maxLength]="10" required="true"></sdc-input> + <sdc-validation [validateElement]="validatorWithCallback" (validityChanged)="validityChanged($event)"> + <sdc-regex-validator message="This is not a number!" [pattern]="numbersPattern"></sdc-regex-validator> + </sdc-validation> + ` + }, + { + id: 'dropdownWithValidation', + showSource: true, + context: { + options: options1, + isThirdOption: (value: any) => { + return value === 'Third Option'; + } + }, + title: 'DropDown with validation', + description: 'DropDown with validation', + template: ` + <sdc-dropdown #mydropdown label="Hi I am a label" placeHolder="Please choose option" [options]="options"></sdc-dropdown> + <sdc-validation [validateElement]="mydropdown"> + <sdc-required-validator message="Field is required!"></sdc-required-validator> + <sdc-custom-validator message="Please select the third option" [callback]="isThirdOption"></sdc-custom-validator> + </sdc-validation> + ` + }, + { + id: 'validationGroup', + showSource: true, + context: { + options: options1, + emailPattern: RegexPatterns.email, + isThirdOption: (value: any) => { + return value === 'Third Option'; + }, + validateGroup: (validationGroup) => { + validationGroup.validate(); + } + }, + title: 'Validation group', + description: 'Validation group (activating validation from code)', + template: ` + <sdc-validation-group #validationGroup> + + <sdc-input #email label="Please enter valid email address" [maxLength]="50" required="true"></sdc-input> + <sdc-validation [validateElement]="email"> + <sdc-required-validator message="Field is required!"></sdc-required-validator> + <sdc-regex-validator message="This is not a valid email!" [pattern]="emailPattern"></sdc-regex-validator> + </sdc-validation> + + <sdc-dropdown #mydropdown label="Hi I am a label" placeHolder="Please choose option" [options]="options"></sdc-dropdown> + <sdc-validation [validateElement]="mydropdown"> + <sdc-required-validator message="Field is required!"></sdc-required-validator> + <sdc-custom-validator message="Please select the third option" [callback]="isThirdOption"></sdc-custom-validator> + </sdc-validation> + + </sdc-validation-group> + <sdc-button text="validate group" (click)="validateGroup(validationGroup)"></sdc-button> + ` + } + ]); 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 title='Accordion Title'><div>Accordion body</div></Accordion>, + html: HTMLBasic + } +}; + +const Checkboxes = () => ( + <Examples examples={examples} /> +); + +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: <Checkbox checked={true} label='This is the checkbox label' value='myVal' onChange={()=>{}} data-test-id='mycheckbox-1' inputRef={() => {} } />, + html: HTMLCheckboxChecked + }, + Unchecked: { + jsx: <Checkbox label='This is the checkbox label' value='myVal' onChange={()=>{}} data-test-id='mycheckbox-2' inputRef={() => {} } />, + html: HTMLCheckboxUnchecked + }, + Disabled: { + jsx: <Checkbox label='This is the checkbox label' disabled={true} value='myVal' onChange={()=>{}} data-test-id='mycheckbox-4' inputRef={() => {} } />, + html: HTMLCheckboxDisabled + }, + 'Disabled and Checked': { + jsx: <Checkbox label='This is the checkbox label' disabled={true} checked={true} value='myVal' onChange={()=>{}} data-test-id='mycheckbox-4' inputRef={() => {} } />, + html: HTMLCheckboxDisabledChecked + } +}; + +const Checkboxes = () => ( + <Examples examples={examples} /> +); + +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: <Checklist items={items} onChange={() => { }} />, + html: HTMLListChecked + }, + Disabled: { + jsx: <Checklist items={itemsDisabled} onChange={() => { }} />, + html: HTMLListDisabled + } +}; + +const ChecklistStory = () => ( + <Examples examples={examples} /> +); + +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 ( + <div key={colorName} className='color-section'> + <div className='color-circle' style={{backgroundColor: colorValue}} /> + <div>{colorName.replace('$', '')}</div> + <div>{colorValue}</div> + </div> + ); +} + +class Colors extends Component { + + render() { + return ( + <div> + <h1>Colors Palette</h1> + <div className='colors-table'> + { + Object.keys(colorMap).map(colorName => <Color key={colorName} colorValue={colorMap[colorName]} colorName={colorName}/>) + } + </div> + </div> + ); + } + +} + +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: <ReactInput name='input1' value='Default' label='I am a label' onChange={ action('input-change')}/>, + html: InputDefaultHtml + }, + 'Input Required': { + jsx: <ReactInput name='input2' value='Default' label='I am a label' onChange={ action('input-change')} isRequired/>, + html: InputRequiredHtml + }, + 'Input Number': { + jsx: <ReactInput name='input3' value='3' label='I am a label' type="number" onChange={ action('input-change')}/>, + html: InputNumberHtml + }, + 'Input View Only': { + jsx: <ReactInput value='Read Only Text' label='I am a label' onChange={ action('input-change')} readOnly/>, + html: InputViewOnlyHtml + }, + 'Input Disabled': { + jsx: <ReactInput value='Default' label='I am a label' onChange={ action('input-change')} disabled/>, + html: InputDisabledHtml + }, + 'Input Placeholder': { + jsx: <ReactInput name='input5' placeholder='Write Here...' label='I am a label' onChange={ action('input-change')}/>, + html: InputPlaceholderHtml + }, + 'Input Error': { + jsx: <ReactInput value='Default' name='input6' label='I am a label' errorMessage='This is the error message' onChange={ action('input-change')}/>, + html: InputErrorHtml + } + +} + +const Inputs = () => ( + <Examples examples={examples} /> +); + +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 ( + <div> + <Button onClick={() => this.setState({show: !show})}>Modal</Button> + {childrenWithProps} + </div> + ); + } +} + +const ModalBody = () => { + return ( + <div> + <Input + name='input1' + value='Default' + label='I am a label' + type='text' /> + <Input + name='input1' + value='Default' + label='I am a label' + type='text' /> + <Input + name='input1' + value='Default' + label='I am a label' + type='text' /> + + </div>); +}; + +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: <Example> + <Modal show={() => isShown()} size='small'> + <Modal.Header><Modal.Title>Standard Modal</Modal.Title></Modal.Header> + <Modal.Body> + {BODY_TEXT} + </Modal.Body> + <Modal.Footer actionButtonText='Yes' actionButtonClick={()=>{}}/> + </Modal> + </Example>, + html: HTMLStandardModal, + exclude: 'Example', + renderFromJsx: true + }, + Alert: { + jsx: <Example> + <Modal show={() => isShown()} type='alert' size='small'> + <Modal.Header type='alert'><Modal.Title>Title</Modal.Title></Modal.Header> + <Modal.Body> + {BODY_TEXT} + </Modal.Body> + <Modal.Footer closeButtonText='Ok'/> + </Modal> + </Example>, + html: HTMLAlertModal, + exclude: 'Example', + renderFromJsx: true + }, + Error: { + jsx: <Example> + <Modal show={() => isShown()} size='small' type='error'> + <Modal.Header onClose={()=>isShown(false)} type='error'><Modal.Title>Title</Modal.Title></Modal.Header> + <Modal.Body> + {BODY_TEXT} + </Modal.Body> + <Modal.Footer onClose={()=>isShown(false)} closeButtonText='Ok'/> + </Modal> + </Example>, + html: HTMLErrorModal, + exclude: 'Example', + renderFromJsx: true + }, + + Custom: { + jsx: <Example> + <Modal show={() => isShown()} type='custom'> + <Modal.Header type='custom'><Modal.Title>Title</Modal.Title></Modal.Header> + <Modal.Body> + <ModalBody/> + </Modal.Body> + <Modal.Footer actionButtonText='Ok' actionButtonClick={()=>{}}/> + </Modal> + </Example>, + html: HTMLCustomModal, + exclude: 'Example', + renderFromJsx: true + } +}; + +const Modals = () => ( + <Examples examples={examples}/> +); + +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> + <h3>Panel</h3> + <Checkbox label='filter-item' /> + <Checkbox checked label='filter-item-checked' /> + </Panel>, + html: HTMLBasic + } +}; + +const PanelStory = () => ( + <Examples examples={examples} /> +); + +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: <PopupMenu onMenuItemClick={() => {}}> + <PopupMenuItem itemId='1' value='item 1 (selected)' selected/> + <PopupMenuItem itemId='2' value='item 2' disabled/> + <PopupMenu.Separator /> + <PopupMenuItem itemId='3' value='item 3'/> + <PopupMenuItem itemId='4' value='custom action' onClick={function customCallback() {}}/> + </PopupMenu>, + html: HTMLPopupMenu + }, + 'Basic popup menu (relative)': { + jsx: <div className='sdc-popup-menu'> + <PopupMenu onMenuItemClick={()=> {}} position={{x: 10, y: 10}} relative> + <PopupMenuItem itemId='1' value='item 1 (selected)' selected/> + <PopupMenuItem itemId='2' value='item 2' disabled/> + <PopupMenu.Separator /> + <PopupMenuItem itemId='3' value='item 3' onClick={function customCallback() {}}/> + </PopupMenu> + </div>, + html: HTMLPopupMenuRelative + } +}; + +const PopupMenuReactComponent = () => ( + <Examples examples={examples} /> +); + +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: <Radio name='grp1' checked={true} label='This is the radio label' value='myVal' onChange={()=>{}} data-test-id='myradio-1' inputRef={() => {} } />, + html: HTMLRadioChecked + }, + Unchecked: { + jsx: <Radio name='grp2' label='This is the radio label' value='myVal' onChange={()=>{}} data-test-id='myradio-2' inputRef={() => {} } />, + html: HTMLRadioUnchecked + }, + Disabled: { + jsx: <Radio name='grp3' label='This is the radio label' disabled={true} value='myVal' onChange={()=>{}} data-test-id='myradio-4' inputRef={() => {} } />, + html: HTMLRadioDisabled + }, + 'Disabled and Checked': { + jsx: <Radio name='grp4' label='This is the radio label' disabled={true} checked={true} value='myVal' onChange={()=>{}} data-test-id='myradio-4' inputRef={() => {} } />, + html: HTMLRadioDisabledChecked + } +}; + +const Radios = () => ( + <Examples examples={examples} /> +); + +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: <RadioGroup name='grp2' value='1' title='Group B' onChange={()=>{}} data-test-id='grp2' options={[{value: '1', label: 'option 1'}, {value: '2', label: 'option 2'}]} />, + html: HTMLRadioGroupValue + }, + 'No Value': { + jsx: <RadioGroup name='grp3' title='Group C' onChange={()=>{}} data-test-id='grp3' options={[{value: '1', label: 'option 1'}, {value: '2', label: 'option 2'}]} />, + html: HTMLRadioGroup + }, + 'Disabled': { + jsx: <RadioGroup name='grp4' disabled={true} title='Group D' onChange={()=>{}} data-test-id='grp4' options={[{value: '1', label: 'option 1'}, {value: '2', label: 'option 2'}]} />, + html: HTMLRadioGroupDisabled + }, + 'No title': { + jsx: <RadioGroup name='grp5' onChange={()=>{}} data-test-id='grp4' options={[{value: '1', label: 'option 1'}, {value: '2', label: 'option 2'}]} />, + html: HTMLRadioGroupNoTitle + } + +}; + +const RadioGroups = () => ( + <Examples examples={examples} /> +); + +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: <SVGIcon + label={iconLabel} + labelPosition={labelPosition} + color={color} + name={iconName} + disabled={disabled === 'true'} /> + } + }; +} + +const IconTable = ({onClick}) => ( + <div className='icons-table'> + {ICON_NAMES.map(icon => ( + <div key={icon} className='icon-section'> + <SVGIcon + onClick={() => onClick(icon)} + label={icon} + iconClassName='storybook-small' + name={icon} /> + </div> + ))} + </div> +); + +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 ( + <div className='icons-screen'> + <h1>Icons</h1> + <div className='icons-option-selector'> + <DropdownMenu + title='Icon name' + value={iconName} + onChange={e => this.setState({iconName: e.target.value})} + options={ICON_NAMES} /> + <div className='option-container'> + <label>Icon label</label> + <input value={iconLabel} onChange={e => this.setState({iconLabel: e.target.value})}/> + </div> + <DropdownMenu + title='Label position' + value={labelPosition} + onChange={e => this.setState({labelPosition: e.target.value})} + options={iconLabelPositions} /> + <DropdownMenu + title='Color' + value={color} + onChange={e => this.setState({color: e.target.value})} + options={iconColors} /> + <DropdownMenu + title='Disabled' + value={disabled} + onChange={e => this.setState({disabled: e.target.value})} + options={disabledStates} /> + </div> + <Examples examples={buildExamples({iconName, iconLabel, labelPosition, color, disabled})} /> + <IconTable onClick={icon => this.setState({iconName: icon})} /> + <div className='missing-icon-section'> + <div >You will see the following if the icon name you used is not found:</div> + <SVGIcon + onClick={() => {}} + name='MissingIcon' /> + </div> + </div> + ); + }; +} + +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: <TabsComp type='menu' activeTab='1' onTabClick={(tabId) => {console.log(tabId);}}> + <Tab title='tab 1' tabId='1'> + <div>This is the active tab content</div> + </Tab> + <Tab title='tab 2' tabId='2' /> + <Tab title='tab 3' tabId='3' /> + </TabsComp>, + html: HTMLTabsMenu + }, + 'Header Tabs': { + jsx: <TabsComp type='header' activeTab='1' onTabClick={(tabId) => {console.log(tabId);}}> + <Tab title='tab 1' tabId='1'> + <div>This is the active tab content</div> + </Tab> + <Tab title='tab 2' tabId='2' /> + <Tab title='tab 3' tabId='3' /> + </TabsComp>, + html: HTMLTabsHeader + }, + 'Disabled Tabs': { + jsx: ( + <TabsComp type='header' activeTab='1' onTabClick={(tabId) => {console.log(tabId);}}> + <Tab title='tab 1' tabId='1'> + <div>This is the active tab content</div> + </Tab> + <Tab title='tab 2' tabId='2' disabled/> + <Tab title='tab 3' tabId='3' disabled/> + </TabsComp> + ), + html: HTMLTabsDisabled + } +}; + +const Tabs = () => ( + <Examples examples={examples} /> +); + +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: <Tile headerText='header' headerColor='blue' iconName='vsp' iconColor='blue'> + <TileInfo> + <TileInfoLine type='supertitle'>Supertitle</TileInfoLine> + <TileInfoLine type='title'>Title</TileInfoLine> + </TileInfo> + </Tile>, + html: HTMLTileWithoutFooter + }, + VFC: { + jsx: <Tile headerText='vfc' headerColor='purple' iconName='network'> + <TileInfo> + <TileInfoLine type='title'>Title</TileInfoLine> + <TileInfoLine type='subtitle'>V 1.0</TileInfoLine> + </TileInfo> + <TileFooter> + <TileFooterCell>Certified</TileFooterCell> + </TileFooter> + </Tile>, + html: HTMLVfcTile + }, + VSP: { + jsx: <Tile headerText='vsp' headerColor='blue' iconName='vsp' iconColor='blue'> + <TileInfo> + <TileInfoLine type='supertitle'>VLM</TileInfoLine> + <TileInfoLine type='title'>VSP name</TileInfoLine> + </TileInfo> + <TileFooter> + <TileFooterCell>Draft</TileFooterCell> + </TileFooter> + </Tile>, + html: HTMLVspTile + }, + VLM: { + jsx: <Tile headerText='vlm' headerColor='purple' iconName='vlm' iconColor='purple'> + <TileInfo> + <TileInfoLine type='title'>VLM name</TileInfoLine> + </TileInfo> + <TileFooter> + <TileFooterCell>Certified</TileFooterCell> + <TileFooterCell> + <SVGIcon name='versionControllerPermissions' label='Owner' labelPosition='left' /> + </TileFooterCell> + </TileFooter> + </Tile>, + html: HTMLVlmTile + }, + Vendor: { + jsx: <Tile iconName='vendor' iconColor='dark-gray'> + <TileInfo align='center'> + <TileInfoLine type='title'>Vendor name</TileInfoLine> + <TileInfoLine> + <Button btnType='primary' onClick={() => {}}>100 VSPs</Button> + </TileInfoLine> + </TileInfo> + <TileFooter align='center'> + <TileFooterCell> + <Button btnType='link' color='primary' iconName='plusThin' onClick={() => {}}>Create new VSP</Button> + </TileFooterCell> + </TileFooter> + </Tile>, + html: HTMLVendorTile + }, +}; + +const Tiles = () => ( + <Examples examples={examples} /> +); + +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 ( + <div className={`typo-section ${className}`}> + <div>{className}</div> + <div>{size}px</div> + <div className='sample-text'>{text}</div> + </div> + ); +} + +class Typography extends Component { + + render() { + return ( + <div className='typography-screen'> + <h1>Typography</h1> + <div className='typography-section'> + <h3>Font Family</h3> + <ul> + <li>OpenSans</li> + <li style={{'fontFamily': 'Arial'}}>Arial</li> + <li style={{'fontFamily':'sans-serif'}}>sans-serif</li> + </ul> + </div> + <div className='typography-section'> + <h3>Font Weights</h3> + <ul>{fontWeights.map(font => <li key={font} className={font}>{font}</li>)}</ul> + </div> + <div className='typography-section'> + <h3>Font Size</h3> + <div className='typo-table'> + <TextRow className='SCSS mixin name (@include ....)' size='Size (in Pixels)' text='Sample Text'/> + {typos.map(typo => <TextRow key={typo.className} {...typo}/>)} + </div> + </div> + </div> + ); + } + +} + +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: <ReactButton btnType='link' onClick={() => {}}>Click Me</ReactButton>, + html: LinkButton + }, + 'Link Disabled': { + jsx: <ReactButton btnType='link' onClick={() => {}} disabled>Click Me</ReactButton>, + html: LinkButtonDisabled, + }, + 'Extra Small': { + jsx: <ReactButton btnType='link' size='x-small' onClick={() => {}}>Click Me</ReactButton>, + html: ExtraSmall + }, + 'Small': { + jsx: <ReactButton btnType='link' size='small' onClick={() => {}}>Click Me</ReactButton>, + html: Small, + }, + 'Medium': { + jsx: <ReactButton btnType='link' size='medium' onClick={() => {}}>Click Me</ReactButton>, + html: Medium + }, + 'Large': { + jsx: <ReactButton btnType='link' size='large' onClick={() => {}}>Click Me</ReactButton>, + html: Large, + }, + 'Auto Sizing': { + jsx: <ReactButton btnType='link' size='default' onClick={() => {}}>Click Me</ReactButton>, + html: Auto, + } +}; + +const DefaultButtons = () => ( + <Examples examples={examples} /> +); + +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: <ReactButton onClick={() => {}}>Click Me</ReactButton>, + html: PrimaryButton + }, + 'Primary Disabled': { + jsx: <ReactButton onClick={() => {}} disabled>Click Me</ReactButton>, + html: PrimaryButtonDisabled, + }, + 'Extra Small': { + jsx: <ReactButton size='x-small' onClick={() => {}}>Click Me</ReactButton>, + html: ExtraSmall + }, + 'Small': { + jsx: <ReactButton size='small' onClick={() => {}}>Click Me</ReactButton>, + html: Small, + }, + 'Medium': { + jsx: <ReactButton size='medium' onClick={() => {}}>Click Me</ReactButton>, + html: Medium + }, + 'Large': { + jsx: <ReactButton size='large' onClick={() => {}}>Click Me</ReactButton>, + html: Large, + }, + 'Auto Sizing': { + jsx: <ReactButton size='default' onClick={() => {}}>Click Me</ReactButton>, + html: Auto, + } +}; + +const DefaultButtons = () => ( + <Examples examples={examples} /> +); + +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: <ReactButton btnType='secondary' onClick={() => {}}>Click Me</ReactButton>, + html: SecondaryButton + }, + 'Secondary Disabled': { + jsx: <ReactButton btnType='secondary' onClick={() => {}} disabled>Click Me</ReactButton>, + html: SecondaryButtonDisabled, + }, + 'Extra Small': { + jsx: <ReactButton btnType='secondary' size='x-small' onClick={() => {}}>Click Me</ReactButton>, + html: ExtraSmall + }, + 'Small': { + jsx: <ReactButton btnType='secondary' size='small' onClick={() => {}}>Click Me</ReactButton>, + html: Small, + }, + 'Medium': { + jsx: <ReactButton btnType='secondary' size='medium' onClick={() => {}}>Click Me</ReactButton>, + html: Medium + }, + 'Large': { + jsx: <ReactButton btnType='secondary' size='large' onClick={() => {}}>Click Me</ReactButton>, + html: Large, + }, + 'Auto Sizing': { + jsx: <ReactButton btnType='secondary' size='default' onClick={() => {}}>Click Me</ReactButton>, + html: Auto, + } +}; + +const DefaultButtons = () => ( + <Examples examples={examples} /> +); + +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', () => <Colors />); + +storiesOf('Typography', module) + .add('Typography', () => <Typography />); + +storiesOf('Accordion', module) + .add('Accordion', () => <Accordion />); + +storiesOf('Buttons', module) + .add('Primary', () => <PrimaryButtons />) + .add('Secondary', () => <SecondaryButtons />) + .add('Link', () => <LinkButtons />); + +storiesOf('Checkboxes', module) + .add('Checkboxes', () => <Checkboxes />); + +storiesOf('Checklist', module) + .add('Checklist', () => <Checklist />); + +storiesOf('Input Fields', module) + .add('Input Text', () => <Input />); + +storiesOf('Icons', module) + .add('SVG Icons', () => <Icons />); + +storiesOf('Menu', module) + .add('Popup Menu', () => <PopupMenu />); + +storiesOf('Modals', module) + .add('Modal examples', () => <Modals />); + +storiesOf('Radios', module) + .add('Radio Buttons', () => <Radios />) + .add('Radio Button Groups', () => <RadioGroups />); + +storiesOf('Panel', module) + .add('Panel', () => <Panel />); + +storiesOf('Tabs', module) + .add('Tabs', () => <Tabs />); + +storiesOf('Tiles', module) + .add('Tiles', () => <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}) => ( + <div className={'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 <SourceToggle title={displayTitle && title} jsx={jsx} html={html} key={key} exclude={exclude} renderFromJsx={renderFromJsx}/>; + })} + </div> +); + +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(/(<svg\b[^<>]*>)[\s\S]*?(<\/svg>)/g); + let newHTML = html.replace(/\s*<!-- insert SVG -->/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 ? <div className={classname}>{jsx}</div> : <div className={classname} dangerouslySetInnerHTML={{__html: html}} />; + case sources.React: + default: + return <div className={classname}>{jsx}</div>; + } + } + + 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 ( + <div className='source-toggle-wrapper'> + {title && <div className='source-toggle-title'>{title}</div>} + <div className='source-toggle'> + {this.renderFromSource()} + <div className='source-toggle-code'> + <div className='source-toggle-code-tabs'> + {Object.keys(sources).map((source, i) => ( + <div + key={i} + className={`source-toggle-tab${this.state.source === source ? ' selected' : ''}`} + onClick={() => this.setState({source})}> + {source} + </div> + ))} + </div> + <pre> + <code dangerouslySetInnerHTML={this.renderMarkdown()} /> + </pre> + </div> + </div> + </div> + ); + } +} 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}) => ( + <div className='option-container'> + <label>{title}</label> + <select value={value} onChange={onChange}> + {options.map((option, i) => + <option key={i} value={option}>{option}</option> + )} + </select> + </div> +); + +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)}</${name}>`; + return result + closingTag; + } + + return result + ' />'; +} + +export default jsxToString; |