aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.babelrc4
-rw-r--r--.editorconfig18
-rw-r--r--.eslintrc135
-rw-r--r--.gitignore31
-rw-r--r--.gitreview4
-rw-r--r--.ng2-component-lab/lab-configuration.module.ts36
-rw-r--r--.ng2-component-lab/ng2-component-lab.config.js11
-rw-r--r--.ng2-component-lab/ng2-component-lab.scss58
-rw-r--r--.ng2-component-lab/themes/ng2-component-lab-theme-1802.scss58
-rw-r--r--.npmignore6
-rw-r--r--.storybook/config.js8
-rw-r--r--.storybook/storybook.scss231
-rw-r--r--.storybook/typography.scss30
-rw-r--r--.storybook/webpack.config.js39
-rw-r--r--.travis.yml31
-rw-r--r--LICENSE.TXT20
-rw-r--r--README.md111
-rw-r--r--assets/README.md9
-rw-r--r--assets/icons/angleDoubleLeft.svg15
-rw-r--r--assets/icons/angleDoubleRight.svg11
-rw-r--r--assets/icons/angleLeft.svg9
-rw-r--r--assets/icons/angleRight.svg9
-rw-r--r--assets/icons/artifacts.svg1
-rw-r--r--assets/icons/back.svg6
-rw-r--r--assets/icons/base.svg1
-rw-r--r--assets/icons/calendar.svg1
-rw-r--r--assets/icons/caretDown.svg6
-rw-r--r--assets/icons/check.svg9
-rw-r--r--assets/icons/checkCircle.svg1
-rw-r--r--assets/icons/chevronDown.svg9
-rw-r--r--assets/icons/chevronUp.svg9
-rw-r--r--assets/icons/close.svg10
-rw-r--r--assets/icons/download.svg1
-rw-r--r--assets/icons/empty.txt0
-rw-r--r--assets/icons/env.svg1
-rw-r--r--assets/icons/error.svg1
-rw-r--r--assets/icons/errorCircle.svg1
-rw-r--r--assets/icons/exclamationTriangleFull.svg9
-rw-r--r--assets/icons/exclamationTriangleLine.svg25
-rw-r--r--assets/icons/expand.svg1
-rw-r--r--assets/icons/filter.svg9
-rw-r--r--assets/icons/locked.svg3
-rw-r--r--assets/icons/module.svg1
-rw-r--r--assets/icons/nestedHeat.svg1
-rw-r--r--assets/icons/network.svg1
-rw-r--r--assets/icons/notificationBell.svg18
-rw-r--r--assets/icons/notificationFullBell.svg11
-rw-r--r--assets/icons/others.svg1
-rw-r--r--assets/icons/pencil.svg17
-rw-r--r--assets/icons/plus.svg9
-rw-r--r--assets/icons/plusCircle.svg9
-rw-r--r--assets/icons/plusThin.svg7
-rw-r--r--assets/icons/proceedToOverview.svg1
-rw-r--r--assets/icons/questionMark.svg1
-rw-r--r--assets/icons/search.svg8
-rw-r--r--assets/icons/sliders.svg19
-rw-r--r--assets/icons/trashO.svg17
-rw-r--r--assets/icons/unlocked.svg3
-rw-r--r--assets/icons/upload.svg1
-rw-r--r--assets/icons/user.svg10
-rw-r--r--assets/icons/vendor.svg1
-rw-r--r--assets/icons/versionControllerCommit.svg1
-rw-r--r--assets/icons/versionControllerLockClosed.svg17
-rw-r--r--assets/icons/versionControllerLockOpen.svg17
-rw-r--r--assets/icons/versionControllerPermissions.svg1
-rw-r--r--assets/icons/versionControllerRevert.svg14
-rw-r--r--assets/icons/versionControllerSave.svg10
-rw-r--r--assets/icons/versionControllerSubmit.svg10
-rw-r--r--assets/icons/versionControllerSync.svg1
-rw-r--r--assets/icons/versionControllerUndo.svg1
-rw-r--r--assets/icons/viewModule.svg9
-rw-r--r--assets/icons/vlm.svg1
-rw-r--r--assets/icons/vsp.svg1
-rw-r--r--assets/icons/zip.svg1
-rw-r--r--assets/images/empty.txt0
-rw-r--r--assets/images/illustration.pngbin0 -> 29534 bytes
-rw-r--r--assets/images/logo_onap.pngbin0 -> 21360 bytes
-rw-r--r--assets/images/logo_onap_2017.pngbin0 -> 21360 bytes
-rw-r--r--assets/sdc-icons/README.md9
-rw-r--r--assets/sdc-icons/alert-triangle-o.svg3
-rw-r--r--assets/sdc-icons/alert-triangle.svg5
-rw-r--r--assets/sdc-icons/api-o.svg3
-rw-r--r--assets/sdc-icons/arrow2-right-child.svg3
-rw-r--r--assets/sdc-icons/arrow2-right.svg3
-rw-r--r--assets/sdc-icons/arrow3-down-o.svg3
-rw-r--r--assets/sdc-icons/arrow3-up-o.svg3
-rw-r--r--assets/sdc-icons/attachment.svg3
-rw-r--r--assets/sdc-icons/bedge.svg5
-rw-r--r--assets/sdc-icons/browse.svg3
-rw-r--r--assets/sdc-icons/calendar-o.svg3
-rw-r--r--assets/sdc-icons/camera-o.svg3
-rw-r--r--assets/sdc-icons/caret1-down-o.svg3
-rw-r--r--assets/sdc-icons/caret2-right-circle-o.svg3
-rw-r--r--assets/sdc-icons/caret2-right-circle.svg4
-rw-r--r--assets/sdc-icons/caret3-right.svg3
-rw-r--r--assets/sdc-icons/close.svg3
-rw-r--r--assets/sdc-icons/commit-o.svg3
-rw-r--r--assets/sdc-icons/components/checkbox_checked.svg3
-rw-r--r--assets/sdc-icons/components/checkbox_disabled.svg9
-rw-r--r--assets/sdc-icons/components/radio_checked .svg6
-rw-r--r--assets/sdc-icons/components/radio_disabled.svg6
-rw-r--r--assets/sdc-icons/composition-o.svg3
-rw-r--r--assets/sdc-icons/copy-o.svg3
-rw-r--r--assets/sdc-icons/deployment-artifacts-o.svg3
-rw-r--r--assets/sdc-icons/description-o.svg3
-rw-r--r--assets/sdc-icons/distributed.svg3
-rw-r--r--assets/sdc-icons/download-o.svg3
-rw-r--r--assets/sdc-icons/edit-file-o.svg3
-rw-r--r--assets/sdc-icons/edit-o.svg3
-rw-r--r--assets/sdc-icons/expand-o.svg3
-rw-r--r--assets/sdc-icons/eye-o.svg3
-rw-r--r--assets/sdc-icons/filter-o.svg3
-rw-r--r--assets/sdc-icons/info-circle-o.svg3
-rw-r--r--assets/sdc-icons/info-circle.svg5
-rw-r--r--assets/sdc-icons/info-square-o.svg3
-rw-r--r--assets/sdc-icons/inputs-o.svg3
-rw-r--r--assets/sdc-icons/locked.svg3
-rw-r--r--assets/sdc-icons/minus-circle.svg3
-rw-r--r--assets/sdc-icons/minus.svg3
-rw-r--r--assets/sdc-icons/notifications-o.svg3
-rw-r--r--assets/sdc-icons/plus-circle-o.svg3
-rw-r--r--assets/sdc-icons/plus-circle.svg5
-rw-r--r--assets/sdc-icons/plus.svg3
-rw-r--r--assets/sdc-icons/profile-o.svg3
-rw-r--r--assets/sdc-icons/profiles-o.svg3
-rw-r--r--assets/sdc-icons/question-mark-circle-o.svg3
-rw-r--r--assets/sdc-icons/question-mark-circle.svg5
-rw-r--r--assets/sdc-icons/req-capabilities-o.svg3
-rw-r--r--assets/sdc-icons/revert-o.svg3
-rw-r--r--assets/sdc-icons/save-o.svg3
-rw-r--r--assets/sdc-icons/search-o.svg3
-rw-r--r--assets/sdc-icons/settings-o.svg3
-rw-r--r--assets/sdc-icons/spinner.svg50
-rw-r--r--assets/sdc-icons/success-circle-o.svg3
-rw-r--r--assets/sdc-icons/success.svg3
-rw-r--r--assets/sdc-icons/sync-o.svg3
-rw-r--r--assets/sdc-icons/trash-o.svg3
-rw-r--r--assets/sdc-icons/undo-o.svg3
-rw-r--r--assets/sdc-icons/unlocked-o.svg3
-rw-r--r--assets/sdc-icons/upload-o.svg3
-rw-r--r--assets/sdc-icons/v-circle-o.svg3
-rw-r--r--assets/sdc-icons/v-circle.svg3
-rw-r--r--assets/sdc-icons/x-circle-o.svg3
-rw-r--r--assets/sdc-icons/x-circle.svg5
-rw-r--r--components/accordion/accordion-basic.html22
-rw-r--r--components/accordion/accordion.scss50
-rw-r--r--components/autocomplete/_autocomplete.scss43
-rw-r--r--components/autocomplete/autocomlete-close.html22
-rw-r--r--components/autocomplete/autocomplete-open.html24
-rw-r--r--components/button/_button.scss168
-rw-r--r--components/button/button-link-auto.html3
-rw-r--r--components/button/button-link-disabled.html3
-rw-r--r--components/button/button-link-extra-small.html3
-rw-r--r--components/button/button-link-large.html3
-rw-r--r--components/button/button-link-medium.html3
-rw-r--r--components/button/button-link-small.html3
-rw-r--r--components/button/button-link.html3
-rw-r--r--components/button/button-primary-auto.html3
-rw-r--r--components/button/button-primary-disabled.html3
-rw-r--r--components/button/button-primary-extra-small.html3
-rw-r--r--components/button/button-primary-large.html3
-rw-r--r--components/button/button-primary-medium.html3
-rw-r--r--components/button/button-primary-small.html3
-rw-r--r--components/button/button-primary.html3
-rw-r--r--components/button/button-secondary-auto.html3
-rw-r--r--components/button/button-secondary-disabled.html3
-rw-r--r--components/button/button-secondary-extra-small.html3
-rw-r--r--components/button/button-secondary-large.html3
-rw-r--r--components/button/button-secondary-medium.html3
-rw-r--r--components/button/button-secondary-small.html3
-rw-r--r--components/button/button-secondary.html3
-rw-r--r--components/checkbox/_checkbox.scss66
-rw-r--r--components/checkbox/checkbox-checked.html6
-rw-r--r--components/checkbox/checkbox-disabled-checked.html6
-rw-r--r--components/checkbox/checkbox-disabled.html6
-rw-r--r--components/checkbox/checkbox-unchecked.html6
-rw-r--r--components/checklist/_checklist.scss21
-rw-r--r--components/checklist/checklist-with-checked-items.html24
-rw-r--r--components/checklist/checklist-with-disabled-items.html25
-rw-r--r--components/checklist/multi-levels-checklist.html50
-rw-r--r--components/checklist/simple-checklist.html24
-rw-r--r--components/dropdown/_dropdown.scss346
-rw-r--r--components/dropdown/dropdown-disabled.html11
-rw-r--r--components/dropdown/dropdown-groups.html10
-rw-r--r--components/dropdown/dropdown-requiered.html18
-rw-r--r--components/dropdown/dropdown.html9
-rw-r--r--components/filter-bar/_filter-bar.scss51
-rw-r--r--components/filter-bar/filter-bar-with-text.html16
-rw-r--r--components/filter-bar/filter-bar.html17
-rw-r--r--components/icon/_icon.scss250
-rw-r--r--components/input/_input.scss78
-rw-r--r--components/input/input-disabled.html4
-rw-r--r--components/input/input-error.html17
-rw-r--r--components/input/input-number.html6
-rw-r--r--components/input/input-placeholder.html4
-rw-r--r--components/input/input-required.html4
-rw-r--r--components/input/input-view-only.html4
-rw-r--r--components/input/input.html8
-rw-r--r--components/menu/_menu.scss68
-rw-r--r--components/menu/popup-menu.html8
-rw-r--r--components/menu/relative-popup-menu.html8
-rw-r--r--components/modal/_modal.scss194
-rw-r--r--components/modal/alert-modal.html45
-rw-r--r--components/modal/custom-modal.html27
-rw-r--r--components/modal/error-modal.html32
-rw-r--r--components/modal/standard-modal.html46
-rw-r--r--components/notification/_notification.scss59
-rw-r--r--components/notification/notification-info.html3
-rw-r--r--components/notifications-container/_notifications-container.scss8
-rw-r--r--components/panel/basic-panel.html21
-rw-r--r--components/panel/panel.scss8
-rw-r--r--components/radio/_radio.scss69
-rw-r--r--components/radio/radio-checked.html4
-rw-r--r--components/radio/radio-disabled-checked.html4
-rw-r--r--components/radio/radio-disabled.html4
-rw-r--r--components/radio/radio-unchecked.html4
-rw-r--r--components/radioGroup/_radioGroup.scss20
-rw-r--r--components/radioGroup/radio-group-disabled.html13
-rw-r--r--components/radioGroup/radio-group-no-title.html12
-rw-r--r--components/radioGroup/radio-group-value.html13
-rw-r--r--components/radioGroup/radio-group.html13
-rw-r--r--components/search-bar/_search-bar.scss61
-rw-r--r--components/search-bar/search-bar-with-text.html17
-rw-r--r--components/search-bar/search-bar.html16
-rw-r--r--components/tabs/tabs-disabled.html8
-rw-r--r--components/tabs/tabs-header.html8
-rw-r--r--components/tabs/tabs-menu.html8
-rw-r--r--components/tabs/tabs.scss35
-rw-r--r--components/tag-cloud/_tag-cloud.scss116
-rw-r--r--components/tag-cloud/disabled-list.html31
-rw-r--r--components/tag-cloud/list-with-active-add-button.html50
-rw-r--r--components/tag-cloud/list-with-some-read-only-items.html61
-rw-r--r--components/tag-cloud/list-with-unique-error.html52
-rw-r--r--components/tag-cloud/simple-list.html50
-rw-r--r--components/tile/_tile.scss172
-rw-r--r--components/tile/tile-without-footer.html14
-rw-r--r--components/tile/vendor-tile.html26
-rw-r--r--components/tile/vfc-tile.html17
-rw-r--r--components/tile/vlm-tile.html22
-rw-r--r--components/tile/vsp-tile.html17
-rw-r--r--components/tooltip/_tooltip.scss124
-rw-r--r--components/validation/_validation.scss9
-rw-r--r--demo/.gitignore7
-rw-r--r--demo/README.md35
-rw-r--r--demo/assests/README.md9
-rw-r--r--demo/assests/icons/empty.txt0
-rw-r--r--demo/assests/icons/locked.svg39
-rw-r--r--demo/assests/icons/plus.svg9
-rw-r--r--demo/assests/icons/unlocked.svg39
-rw-r--r--demo/assests/icons/vendor.svg1
-rw-r--r--demo/assests/icons/vlm.svg1
-rw-r--r--demo/assests/icons/vsp.svg1
-rw-r--r--demo/assests/images/empty.txt0
-rw-r--r--demo/components/button.html15
-rw-r--r--demo/components/colors.html26
-rw-r--r--demo/components/tiles-generic.html106
-rw-r--r--demo/components/tiles.html105
-rw-r--r--demo/index.css178
-rw-r--r--demo/index.html53
-rw-r--r--demo/index.js84
-rw-r--r--demo/package.json23
-rw-r--r--designs/README.md3
-rw-r--r--jest.config.js30
-rw-r--r--json-typing.d.ts4
-rw-r--r--karma.conf.js87
-rw-r--r--karma.entry.js66
-rw-r--r--ng2-component-lab.webpack.config.js62
-rw-r--r--package.json133
-rw-r--r--pom.xml162
-rw-r--r--rollup.angular.module.config.js33
-rw-r--r--rollup.angular.umd.config.js38
-rw-r--r--src/README.md9
-rw-r--r--src/angular/accordion/accordion.component.html.ts21
-rw-r--r--src/angular/accordion/accordion.component.ts27
-rw-r--r--src/angular/accordion/accordion.module.ts23
-rw-r--r--src/angular/animations/animation-directives.module.ts19
-rw-r--r--src/angular/animations/ripple-click.animation.directive.ts47
-rw-r--r--src/angular/autocomplete/autocomplete.component.html.ts14
-rw-r--r--src/angular/autocomplete/autocomplete.component.ts114
-rw-r--r--src/angular/autocomplete/autocomplete.module.ts23
-rw-r--r--src/angular/autocomplete/autocomplete.pipe.ts16
-rw-r--r--src/angular/buttons/button.component.html.ts15
-rw-r--r--src/angular/buttons/button.component.ts62
-rw-r--r--src/angular/buttons/buttons.module.ts21
-rw-r--r--src/angular/checklist/checklist.component.html.ts15
-rw-r--r--src/angular/checklist/checklist.component.ts50
-rw-r--r--src/angular/checklist/checklist.module.ts11
-rw-r--r--src/angular/checklist/models/Checklist.ts18
-rw-r--r--src/angular/checklist/models/ChecklistItem.ts17
-rw-r--r--src/angular/common/enums.ts34
-rw-r--r--src/angular/common/index.ts3
-rw-r--r--src/angular/components.ts50
-rw-r--r--src/angular/filterbar/filter-bar.component.html.ts30
-rw-r--r--src/angular/filterbar/filter-bar.component.ts30
-rw-r--r--src/angular/filterbar/filter-bar.module.ts17
-rw-r--r--src/angular/form-elements/checkbox/checkbox.component.html.ts8
-rw-r--r--src/angular/form-elements/checkbox/checkbox.component.spec.ts37
-rw-r--r--src/angular/form-elements/checkbox/checkbox.component.ts21
-rw-r--r--src/angular/form-elements/dropdown/dropdown-models.ts18
-rw-r--r--src/angular/form-elements/dropdown/dropdown-trigger.directive.ts17
-rw-r--r--src/angular/form-elements/dropdown/dropdown.component.html.ts59
-rw-r--r--src/angular/form-elements/dropdown/dropdown.component.spec.ts71
-rw-r--r--src/angular/form-elements/dropdown/dropdown.component.ts149
-rw-r--r--src/angular/form-elements/form-elements.module.ts38
-rw-r--r--src/angular/form-elements/input/input.component.html.ts19
-rw-r--r--src/angular/form-elements/input/input.component.ts54
-rw-r--r--src/angular/form-elements/radios/radio-button.model.ts15
-rw-r--r--src/angular/form-elements/radios/radio-buttons-group.component.html.ts20
-rw-r--r--src/angular/form-elements/radios/radio-buttons-group.component.spec.ts52
-rw-r--r--src/angular/form-elements/radios/radio-buttons-group.component.ts52
-rw-r--r--src/angular/form-elements/validation/validatable.component.ts25
-rw-r--r--src/angular/form-elements/validation/validatable.interface.ts5
-rw-r--r--src/angular/form-elements/validation/validation-group.component.html.ts3
-rw-r--r--src/angular/form-elements/validation/validation-group.component.ts47
-rw-r--r--src/angular/form-elements/validation/validation.component.html.ts3
-rw-r--r--src/angular/form-elements/validation/validation.component.ts79
-rw-r--r--src/angular/form-elements/validation/validation.module.ts35
-rw-r--r--src/angular/form-elements/validation/validators/base.validator.component.html.ts10
-rw-r--r--src/angular/form-elements/validation/validators/base.validator.component.ts25
-rw-r--r--src/angular/form-elements/validation/validators/custom.validator.component.ts23
-rw-r--r--src/angular/form-elements/validation/validators/regex.validator.component.ts24
-rw-r--r--src/angular/form-elements/validation/validators/required.validator.component.ts25
-rw-r--r--src/angular/form-elements/validation/validators/validator.interface.ts3
-rw-r--r--src/angular/index.ts68
-rw-r--r--src/angular/infinite-scroll/infinite-scroll.directive.ts35
-rw-r--r--src/angular/infinite-scroll/infinite-scroll.module.ts13
-rw-r--r--src/angular/modals/modal-button.component.ts29
-rw-r--r--src/angular/modals/modal-close-button.component.ts34
-rw-r--r--src/angular/modals/modal.component.html.ts38
-rw-r--r--src/angular/modals/modal.component.spec.ts105
-rw-r--r--src/angular/modals/modal.component.ts96
-rw-r--r--src/angular/modals/modal.module.ts33
-rw-r--r--src/angular/modals/modal.service.ts100
-rw-r--r--src/angular/modals/models/modal-config.ts44
-rw-r--r--src/angular/ng1.module.ts135
-rw-r--r--src/angular/notifications/container/notifcontainer.component.html.ts6
-rw-r--r--src/angular/notifications/container/notifcontainer.component.ts31
-rw-r--r--src/angular/notifications/notification-inner-content-example.component.ts21
-rw-r--r--src/angular/notifications/notification.module.ts29
-rw-r--r--src/angular/notifications/notification/notification.component.html.ts19
-rw-r--r--src/angular/notifications/notification/notification.component.ts42
-rw-r--r--src/angular/notifications/services/notifications.service.ts41
-rw-r--r--src/angular/notifications/utilities/notification.config.ts30
-rw-r--r--src/angular/popup-menu/popup-menu-item.component.spec.ts25
-rw-r--r--src/angular/popup-menu/popup-menu-item.component.ts34
-rw-r--r--src/angular/popup-menu/popup-menu-list.component.ts65
-rw-r--r--src/angular/popup-menu/popup-menu.module.ts21
-rw-r--r--src/angular/searchbar/search-bar.component.html.ts19
-rw-r--r--src/angular/searchbar/search-bar.component.ts19
-rw-r--r--src/angular/searchbar/search-bar.module.ts17
-rw-r--r--src/angular/svg-icon/svg-icon-label.component.html.ts6
-rw-r--r--src/angular/svg-icon/svg-icon-label.component.ts26
-rw-r--r--src/angular/svg-icon/svg-icon.component.html.ts3
-rw-r--r--src/angular/svg-icon/svg-icon.component.ts77
-rw-r--r--src/angular/svg-icon/svg-icon.module.ts21
-rw-r--r--src/angular/tabs/children/tab.component.html.ts5
-rw-r--r--src/angular/tabs/children/tab.component.ts16
-rw-r--r--src/angular/tabs/tabs.component.html.ts14
-rw-r--r--src/angular/tabs/tabs.component.ts41
-rw-r--r--src/angular/tabs/tabs.module.ts23
-rw-r--r--src/angular/tag-cloud/tag-cloud.component.html.ts30
-rw-r--r--src/angular/tag-cloud/tag-cloud.component.ts46
-rw-r--r--src/angular/tag-cloud/tag-cloud.module.ts21
-rw-r--r--src/angular/tag-cloud/tag-item/tag-item.component.html.ts16
-rw-r--r--src/angular/tag-cloud/tag-item/tag-item.component.ts15
-rw-r--r--src/angular/tiles/children/tile-content.component.ts10
-rw-r--r--src/angular/tiles/children/tile-footer.component.ts10
-rw-r--r--src/angular/tiles/children/tile-header.component.ts10
-rw-r--r--src/angular/tiles/tile.component.html.ts5
-rw-r--r--src/angular/tiles/tile.component.ts11
-rw-r--r--src/angular/tiles/tile.module.ts27
-rw-r--r--src/angular/tooltip/tooltip-template.component.ts20
-rw-r--r--src/angular/tooltip/tooltip.directive.ts459
-rw-r--r--src/angular/tooltip/tooltip.module.ts17
-rw-r--r--src/angular/utils/create-dynamic-component.service.ts101
-rw-r--r--src/react/Accordion.js40
-rw-r--r--src/react/Button.js37
-rw-r--r--src/react/Checkbox.js45
-rw-r--r--src/react/Checklist.js43
-rw-r--r--src/react/Input.js88
-rw-r--r--src/react/Modal.js55
-rw-r--r--src/react/ModalBody.js19
-rw-r--r--src/react/ModalFooter.js36
-rw-r--r--src/react/ModalHeader.js41
-rw-r--r--src/react/ModalTitle.js19
-rw-r--r--src/react/Panel.js18
-rw-r--r--src/react/PopupMenu.js39
-rw-r--r--src/react/PopupMenuItem.js34
-rw-r--r--src/react/Portal.js52
-rw-r--r--src/react/Radio.js58
-rw-r--r--src/react/RadioGroup.js40
-rw-r--r--src/react/SVGIcon.js47
-rw-r--r--src/react/Tab.js20
-rw-r--r--src/react/TabPane.js12
-rw-r--r--src/react/Tabs.js29
-rw-r--r--src/react/Tile.js33
-rw-r--r--src/react/TileFooter.js10
-rw-r--r--src/react/TileFooterCell.js7
-rw-r--r--src/react/TileInfo.js10
-rw-r--r--src/react/TileInfoLine.js7
-rw-r--r--src/react/index.js74
-rw-r--r--src/style/scss/_common.scss7
-rw-r--r--src/style/scss/_components.scss22
-rw-r--r--src/style/scss/angular/_svg_icon.scss210
-rw-r--r--src/style/scss/angular/_tooltip_custom_style.scss9
-rw-r--r--src/style/scss/common/_animation.scss149
-rw-r--r--src/style/scss/common/_icons.scss19
-rw-r--r--src/style/scss/common/_normalize.scss578
-rw-r--r--src/style/scss/common/_typography.scss96
-rw-r--r--src/style/scss/common/base.scss96
-rw-r--r--src/style/scss/common/mixins.scss337
-rw-r--r--src/style/scss/common/variables.scss35
-rw-r--r--src/style/scss/style.scss6
-rw-r--r--src/style/scss/themes/1802/_components.scss23
-rw-r--r--src/style/scss/themes/1802/button.scss148
-rw-r--r--src/style/scss/themes/1802/modal.scss193
-rw-r--r--src/style/scss/themes/1802/style.scss5
-rw-r--r--src/style/scss/themes/1802/tabs.scss39
-rw-r--r--stories/README.md9
-rw-r--r--stories/ng2-component-lab/accordion.component.exp.ts146
-rw-r--r--stories/ng2-component-lab/autocomplete.component.exp.ts77
-rw-r--r--stories/ng2-component-lab/button.component.exp.ts164
-rw-r--r--stories/ng2-component-lab/checkbox.component.exp.ts33
-rw-r--r--stories/ng2-component-lab/checklist.component.exp.ts213
-rw-r--r--stories/ng2-component-lab/colors.component.exp.ts42
-rw-r--r--stories/ng2-component-lab/components.module.ts45
-rw-r--r--stories/ng2-component-lab/components/colors-table.component.ts26
-rw-r--r--stories/ng2-component-lab/components/modal-consumer.component.ts106
-rw-r--r--stories/ng2-component-lab/components/modal-inner-content-example.component.ts16
-rw-r--r--stories/ng2-component-lab/components/notifications-example.component.ts57
-rw-r--r--stories/ng2-component-lab/components/svg-icons-table.component.ts189
-rw-r--r--stories/ng2-component-lab/dropdown.component.exp.ts195
-rw-r--r--stories/ng2-component-lab/filter-bar.component.exp.ts56
-rw-r--r--stories/ng2-component-lab/infinite-scroll.component.exp.ts166
-rw-r--r--stories/ng2-component-lab/input.component.exp.ts79
-rw-r--r--stories/ng2-component-lab/modals.component.exp.ts126
-rw-r--r--stories/ng2-component-lab/notification.component.exp.ts11
-rw-r--r--stories/ng2-component-lab/pipes/search-filter-pipe.ts15
-rw-r--r--stories/ng2-component-lab/popup-menu.component.exp.ts104
-rw-r--r--stories/ng2-component-lab/radio.component.exp.ts179
-rw-r--r--stories/ng2-component-lab/search-bar.component.exp.ts19
-rw-r--r--stories/ng2-component-lab/svg-icon.component.exp.ts14
-rw-r--r--stories/ng2-component-lab/tabs.component.exp.ts28
-rw-r--r--stories/ng2-component-lab/tag-cloud.component.exp.ts61
-rw-r--r--stories/ng2-component-lab/tiles.component.exp.ts194
-rw-r--r--stories/ng2-component-lab/tooltip.directive.exp.ts231
-rw-r--r--stories/ng2-component-lab/utils/mock.json6
-rw-r--r--stories/ng2-component-lab/utils/pipes/keys.pipe.ts13
-rw-r--r--stories/ng2-component-lab/validation.component.exp.ts162
-rw-r--r--stories/react/Accordion.stories.js16
-rw-r--r--stories/react/Checkbox.stories.js33
-rw-r--r--stories/react/Checklist.stories.js65
-rw-r--r--stories/react/Colors.stories.js53
-rw-r--r--stories/react/Input.stories.js51
-rw-r--r--stories/react/Modal.stories.js133
-rw-r--r--stories/react/Panel.stories.js22
-rw-r--r--stories/react/PopupMenu.stories.js37
-rw-r--r--stories/react/Radio.stories.js33
-rw-r--r--stories/react/RadioGroup.stories.js34
-rw-r--r--stories/react/SVGIcon.stories.js103
-rw-r--r--stories/react/Tabs.stories.js48
-rw-r--r--stories/react/Tiles.stories.js89
-rw-r--r--stories/react/Typography.stories.js62
-rw-r--r--stories/react/buttons/LinkButtons.stories.js49
-rw-r--r--stories/react/buttons/PrimaryButtons.stories.js49
-rw-r--r--stories/react/buttons/SecondaryButtons.stories.js49
-rw-r--r--stories/react/index.js66
-rw-r--r--stories/react/utils/BeautifyHTML.js33
-rw-r--r--stories/react/utils/Examples.js23
-rw-r--r--stories/react/utils/InsertSVGIcons.js15
-rw-r--r--stories/react/utils/SourceToggle.js73
-rw-r--r--stories/react/utils/components/DropdownMenu.js14
-rw-r--r--stories/react/utils/jsxToString.js74
-rw-r--r--test/react/Accordion.spec.js11
-rw-r--r--test/react/Button.spec.js77
-rw-r--r--test/react/Checkbox.spec.js60
-rw-r--r--test/react/Checklist.spec.js64
-rw-r--r--test/react/Input.spec.js69
-rw-r--r--test/react/Modal.spec.js68
-rw-r--r--test/react/ModalBody.spec.js11
-rw-r--r--test/react/ModalFooter.spec.js11
-rw-r--r--test/react/ModalHeader.spec.js11
-rw-r--r--test/react/ModalTitle.spec.js11
-rw-r--r--test/react/Panel.spec.js11
-rw-r--r--test/react/PopupMenu.spec.js62
-rw-r--r--test/react/PopupMenuItem.spec.js56
-rw-r--r--test/react/Portal.spec.js10
-rw-r--r--test/react/Radio.spec.js60
-rw-r--r--test/react/RadioGroup.spec.js69
-rw-r--r--test/react/Tabs.spec.js55
-rw-r--r--test/react/Tile.spec.js30
-rw-r--r--test/react/__snapshots__/Accordion.spec.js.snap32
-rw-r--r--test/react/__snapshots__/Button.spec.js.snap163
-rw-r--r--test/react/__snapshots__/Checkbox.spec.js.snap49
-rw-r--r--test/react/__snapshots__/Checklist.spec.js.snap165
-rw-r--r--test/react/__snapshots__/Input.spec.js.snap179
-rw-r--r--test/react/__snapshots__/Modal.spec.js.snap9
-rw-r--r--test/react/__snapshots__/ModalBody.spec.js.snap7
-rw-r--r--test/react/__snapshots__/ModalFooter.spec.js.snap17
-rw-r--r--test/react/__snapshots__/ModalHeader.spec.js.snap24
-rw-r--r--test/react/__snapshots__/ModalTitle.spec.js.snap9
-rw-r--r--test/react/__snapshots__/Panel.spec.js.snap9
-rw-r--r--test/react/__snapshots__/PopupMenu.spec.js.snap26
-rw-r--r--test/react/__snapshots__/PopupMenuItem.spec.js.snap19
-rw-r--r--test/react/__snapshots__/Radio.spec.js.snap49
-rw-r--r--test/react/__snapshots__/RadioGroup.spec.js.snap60
-rw-r--r--test/react/__snapshots__/Tabs.spec.js.snap52
-rw-r--r--test/react/__snapshots__/Tile.spec.js.snap108
-rw-r--r--test/react/utils/htmlLoader.js7
-rw-r--r--test/react/utils/svgMock.js3
-rw-r--r--tsconfig.angular.build-es5.json24
-rw-r--r--tsconfig.json31
-rw-r--r--tslint.json77
-rw-r--r--utils/build-demo.js73
-rw-r--r--utils/create-icon-map.js26
-rw-r--r--utils/create-svg-icons-map.js95
-rw-r--r--utils/index-for-gh-pages.html98
-rw-r--r--utils/main-page.html62
-rw-r--r--utils/scripts/map-sources.js9
-rw-r--r--version.properties13
-rw-r--r--webpack.build.config.js63
-rw-r--r--webpack/helpers.js10
-rw-r--r--webpack/webpack.test.js71
523 files changed, 18987 insertions, 0 deletions
diff --git a/.babelrc b/.babelrc
new file mode 100644
index 0000000..a4105e9
--- /dev/null
+++ b/.babelrc
@@ -0,0 +1,4 @@
+{
+ "presets": ["react", "env"],
+ "plugins": ["transform-object-rest-spread"]
+} \ No newline at end of file
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..5ba69e2
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,18 @@
+# EditorConfig is awesome: http://EditorConfig.org
+
+# top-most EditorConfig file
+root = true
+
+# Unix-style newlines with a newline ending every file
+[*]
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+# tab indentation
+[framework/**.js]
+[framework/**.jsx]
+[resources/**.scss]
+indent_style = space
+indent_size = 4
diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 0000000..5a7f317
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,135 @@
+{
+ "parser": "babel-eslint",
+ "env": {
+ "es6": true,
+ "node": true,
+ "jest": true
+ },
+ "plugins": [
+ "react",
+ "import"
+ ],
+ "ecmaFeatures": {
+ "jsx": true,
+ "classes": true,
+ "modules": true
+ },
+ "globals": {
+ "ICON_PATH": true,
+ "ICON_NAMES": true
+ },
+ "rules": {
+ "linebreak-style": 0,
+ "no-unused-vars": 2,
+ "no-bitwise": 0,
+ "no-eq-null": 2,
+ "eqeqeq": 2,
+ "wrap-iife": [
+ 2,
+ "any"
+ ],
+ "no-unused-expressions": 2,
+ "indent": [
+ 1,
+ "tab",
+ {
+ "SwitchCase": 1
+ }
+ ],
+ "no-use-before-define": 2,
+ "new-cap": [
+ 2,
+ {
+ "capIsNewExceptions": [
+ "DataTable",
+ "V"
+ ]
+ }
+ ],
+ "no-caller": 2,
+ "no-empty": 2,
+ "no-undef": 2,
+ "quotes": [
+ 2,
+ "single",
+ "avoid-escape"
+ ],
+ "jsx-quotes": [
+ 2,
+ "prefer-single"
+ ],
+ "no-plusplus": 0,
+ "no-cond-assign": [
+ 2,
+ "except-parens"
+ ],
+ "comma-style": [
+ 2,
+ "last"
+ ],
+ "no-invalid-this": 0,
+ "dot-notation": 0,
+ "max-len": [
+ 1,
+ 200
+ ],
+ "camelcase": [
+ 2,
+ {
+ "properties": "never"
+ }
+ ],
+ "curly": 2,
+ "brace-style": 0,
+ "semi": [
+ 2,
+ "always"
+ ],
+ "space-in-brackets": [
+ 0,
+ "never"
+ ],
+ "space-infix-ops": 2,
+ "import/default": 0,
+ "import/no-unresolved": 0,
+ "import/no-named-as-default": 2,
+ "import/no-duplicates": 0,
+ "import/imports-first": 2,
+ "import/export": 2,
+ "react/display-name": 0,
+ "react/forbid-prop-types": 0,
+ "react/jsx-boolean-value": 0,
+ "react/jsx-closing-bracket-location": [
+ 1,
+ {
+ "nonEmpty": "after-props",
+ "selfClosing": "after-props"
+ }
+ ],
+ "react/jsx-curly-spacing": 0,
+ "react/jsx-indent-props": [
+ 1,
+ "tab"
+ ],
+ "react/jsx-max-props-per-line": 0,
+ "react/jsx-no-duplicate-props": 1,
+ "react/jsx-no-literals": 0,
+ "react/jsx-no-undef": 1,
+ "react/jsx-sort-prop-types": 0,
+ "react/jsx-sort-props": 0,
+ "react/jsx-uses-react": 1,
+ "react/jsx-uses-vars": 1,
+ "react/no-danger": 1,
+ "react/no-did-mount-set-state": 2,
+ "react/no-did-update-set-state": 2,
+ "react/no-direct-mutation-state": 1,
+ "react/no-multi-comp": 0,
+ "react/no-set-state": 0,
+ "react/no-unknown-property": 1,
+ "react/prop-types": 0,
+ "react/react-in-jsx-scope": 1,
+ "react/self-closing-comp": 1,
+ "react/sort-comp": 0,
+ "react/jsx-wrap-multilines": 1
+ }
+}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..75d10d0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,31 @@
+# See http://help.github.com/ignore-files/ for more about ignoring files.
+
+/dist
+/tmp
+/lib
+/build
+/node_modules
+npm-debug.log*
+Thumbs.db
+
+# IDEA files
+.idea
+.vscode
+.history
+package-lock.json
+# build files
+lib
+css
+demo/gen
+.out
+src/react/utils/iconMap.js
+
+#coverage files
+coverage
+
+#ignore generated icons files
+src/common/icons-map.ts
+src/common/icons-map.json
+
+/node/*
+/yarn.lock
diff --git a/.gitreview b/.gitreview
new file mode 100644
index 0000000..50cc496
--- /dev/null
+++ b/.gitreview
@@ -0,0 +1,4 @@
+[gerrit]
+host=gerrit.onap.org
+port=29418
+project=sdc/onap-ui.git
diff --git a/.ng2-component-lab/lab-configuration.module.ts b/.ng2-component-lab/lab-configuration.module.ts
new file mode 100644
index 0000000..d9305dd
--- /dev/null
+++ b/.ng2-component-lab/lab-configuration.module.ts
@@ -0,0 +1,36 @@
+import { createLab } from '@islavi/ng2-component-lab';
+import { ComponentsModule } from './../stories/ng2-component-lab/components.module';
+
+const themeName:string = 'default';
+//const themeName:string = '1802';
+
+// Select the theme
+if (themeName === '1802') {
+ require('./themes/ng2-component-lab-theme-1802.scss');
+} else {
+ // Default theme
+ require('./ng2-component-lab.scss');
+}
+
+createLab({
+ /**
+ * NgModule to import. All components and pipes must be exported
+ * by this module to be useable in your experiments
+ */
+ ngModule: ComponentsModule,
+ /**
+ * Function that returns an array of experiments.
+ *
+ * Here is an example using webpack's `require.context` to
+ * load all modules ending in `.exp.ts` and returning thier
+ * default exports as an array:
+ */
+ loadExperiments() {
+ const context = (require as any).context('./../stories/ng2-component-lab', true, /\.exp\.ts/);
+ var result = context.keys().map(context).map(mod => mod.default);
+ context.keys().forEach(key => {
+ console.log("Going to require: " + key);
+ });
+ return result;
+ }
+});
diff --git a/.ng2-component-lab/ng2-component-lab.config.js b/.ng2-component-lab/ng2-component-lab.config.js
new file mode 100644
index 0000000..963ac45
--- /dev/null
+++ b/.ng2-component-lab/ng2-component-lab.config.js
@@ -0,0 +1,11 @@
+var getWebPackConfig = require('../ng2-component-lab.webpack.config.js');
+
+module.exports = {
+ webpackConfig: getWebPackConfig,
+ host: 'localhost',
+ port: 6007,
+ include: [],
+ suites: {
+ feature: './.ng2-component-lab/lab-configuration.module.ts'
+ }
+};
diff --git a/.ng2-component-lab/ng2-component-lab.scss b/.ng2-component-lab/ng2-component-lab.scss
new file mode 100644
index 0000000..28f0f7b
--- /dev/null
+++ b/.ng2-component-lab/ng2-component-lab.scss
@@ -0,0 +1,58 @@
+@font-face {
+ font-family: 'OpenSans-Regular';
+ font-style: normal;
+ font-weight: 400;
+ src:
+ local('Open Sans Regular'),
+ local('OpenSans-Regular'),
+ url(https://fonts.gstatic.com/s/opensans/v15/cJZKeOuBrn4kERxqtaUH3ZBw1xU1rKptJj_0jans920.woff2) format('woff2'),
+ url(http://fonts.gstatic.com/s/opensans/v15/cJZKeOuBrn4kERxqtaUH3T8E0i7KZn-EPnyo3HZu7kw.woff) format('woff');
+}
+@font-face {
+ font-family: 'OpenSans-Italic';
+ font-style: normal;
+ font-weight: 400;
+ src:
+ local('Open Sans Italic'),
+ local('OpenSans-Italic'),
+ url(https://fonts.gstatic.com/s/opensans/v15/xjAJXh38I15wypJXxuGMBogp9Q8gbYrhqGlRav_IXfk.woff2) format('woff2'),
+ url(http://fonts.gstatic.com/s/opensans/v15/xjAJXh38I15wypJXxuGMBobN6UDyHWBl620a-IRfuBk.woff) format('woff');
+}
+@font-face {
+ font-family: 'OpenSans-Semibold';
+ font-style: normal;
+ font-weight: 400;
+ src:
+ local('Open Sans Semibold'),
+ local('OpenSans-Semibold'),
+ url(https://fonts.gstatic.com/s/opensans/v15/MTP_ySUJH_bn48VBG8sNShampu5_7CjHW5spxoeN3Vs.woff2) format('woff2'),
+ url(http://fonts.gstatic.com/s/opensans/v15/MTP_ySUJH_bn48VBG8sNSnhCUOGz7vYGh680lGh-uXM.woff) format('woff');
+}
+
+@import '../src/style/scss/style.scss';
+
+.colors-table {
+ width: 75%;
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: flex-start;
+ font-size: 13px;
+ .color-section {
+ display: flex;
+ flex-direction: column;
+ margin: 10px 0;
+ min-width: 150px;
+ div {
+ align-self: center;
+ user-select: text;
+ }
+ $circle-size: 40px;
+ .color-circle {
+ height: $circle-size;
+ width: $circle-size;
+ border-radius: $circle-size;
+ padding: 10px;
+ text-align: center;
+ }
+ }
+}
diff --git a/.ng2-component-lab/themes/ng2-component-lab-theme-1802.scss b/.ng2-component-lab/themes/ng2-component-lab-theme-1802.scss
new file mode 100644
index 0000000..59cf05e
--- /dev/null
+++ b/.ng2-component-lab/themes/ng2-component-lab-theme-1802.scss
@@ -0,0 +1,58 @@
+@font-face {
+ font-family: 'OpenSans-Regular';
+ font-style: normal;
+ font-weight: 400;
+ src:
+ local('Open Sans Regular'),
+ local('OpenSans-Regular'),
+ url(https://fonts.gstatic.com/s/opensans/v15/cJZKeOuBrn4kERxqtaUH3ZBw1xU1rKptJj_0jans920.woff2) format('woff2'),
+ url(http://fonts.gstatic.com/s/opensans/v15/cJZKeOuBrn4kERxqtaUH3T8E0i7KZn-EPnyo3HZu7kw.woff) format('woff');
+}
+@font-face {
+ font-family: 'OpenSans-Italic';
+ font-style: normal;
+ font-weight: 400;
+ src:
+ local('Open Sans Italic'),
+ local('OpenSans-Italic'),
+ url(https://fonts.gstatic.com/s/opensans/v15/xjAJXh38I15wypJXxuGMBogp9Q8gbYrhqGlRav_IXfk.woff2) format('woff2'),
+ url(http://fonts.gstatic.com/s/opensans/v15/xjAJXh38I15wypJXxuGMBobN6UDyHWBl620a-IRfuBk.woff) format('woff');
+}
+@font-face {
+ font-family: 'OpenSans-Semibold';
+ font-style: normal;
+ font-weight: 400;
+ src:
+ local('Open Sans Semibold'),
+ local('OpenSans-Semibold'),
+ url(https://fonts.gstatic.com/s/opensans/v15/MTP_ySUJH_bn48VBG8sNShampu5_7CjHW5spxoeN3Vs.woff2) format('woff2'),
+ url(http://fonts.gstatic.com/s/opensans/v15/MTP_ySUJH_bn48VBG8sNSnhCUOGz7vYGh680lGh-uXM.woff) format('woff');
+}
+
+@import './../../src/style/scss/themes/1802/style.scss';
+
+.colors-table {
+ width: 75%;
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: flex-start;
+ font-size: 13px;
+ .color-section {
+ display: flex;
+ flex-direction: column;
+ margin: 10px 0;
+ min-width: 150px;
+ div {
+ align-self: center;
+ user-select: text;
+ }
+ $circle-size: 40px;
+ .color-circle {
+ height: $circle-size;
+ width: $circle-size;
+ border-radius: $circle-size;
+ padding: 10px;
+ text-align: center;
+ }
+ }
+}
diff --git a/.npmignore b/.npmignore
new file mode 100644
index 0000000..7d482d2
--- /dev/null
+++ b/.npmignore
@@ -0,0 +1,6 @@
+/dist
+
+# IDEA files
+.idea
+.vscode
+.history
diff --git a/.storybook/config.js b/.storybook/config.js
new file mode 100644
index 0000000..5896dcc
--- /dev/null
+++ b/.storybook/config.js
@@ -0,0 +1,8 @@
+import { configure } from '@storybook/react';
+import './storybook.scss';
+
+function loadStories() {
+ require('../stories/react');
+}
+
+configure(loadStories, module);
diff --git a/.storybook/storybook.scss b/.storybook/storybook.scss
new file mode 100644
index 0000000..ce905cf
--- /dev/null
+++ b/.storybook/storybook.scss
@@ -0,0 +1,231 @@
+@import 'typography.scss';
+@import '../src/style/scss/style.scss';
+@import '~prismjs/themes/prism.css';
+
+body {
+ @include base-font-regular();
+ margin: 15px;
+ max-width: 800px;
+}
+
+a {
+ color: #1474f3;
+ text-decoration: none;
+ border-bottom: 1px solid #1474f3;
+ padding-bottom: 2px;
+}
+
+.colors-table {
+ width: 100%;
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: flex-start;
+ font-size: 13px;
+ .color-section {
+ display: flex;
+ flex-direction: column;
+ margin: 10px 0;
+ min-width: 150px;
+ div {
+ align-self: center;
+ user-select: text;
+ }
+ $circle-size: 40px;
+ .color-circle {
+ height: $circle-size;
+ width: $circle-size;
+ border-radius: $circle-size;
+ padding: 10px;
+ text-align: center;
+ }
+ }
+}
+
+.icons-screen {
+ width: 1190px;
+ .missing-icon-section {
+ border-top: 1px solid $light-gray;
+ padding-top: 10px;
+ }
+ .icons-option-selector {
+ margin-top: 20px;
+ margin-bottom: 20px;
+ display: flex;
+ .option-container {
+ display: flex;
+ flex-direction: column;
+ flex-basis: 100%;
+ margin-right: 20px;
+ }
+ }
+
+ .icons-table {
+ margin-top: 50px;
+ width: 100%;
+ display: flex;
+ flex-wrap: wrap;
+ border-top: 1px solid $light-gray;
+ justify-content: flex-start;
+ .icon-section {
+ display: flex;
+ flex-direction: column;
+ margin: 10px;
+ min-width: 150px;
+ .svg-icon-wrapper {
+ cursor: pointer;
+ width: 20px;
+ height: 42px;
+ margin-left: auto;
+ margin-right: auto;
+ .svg-icon-label {
+ font-size: 12px;
+ }
+ }
+ }
+ }
+
+ .svg-icon {
+ &.storybook-big {
+ width: 120px;
+ height: 120px;
+ }
+ &.storybook-small {
+ width: 60px;
+ height: 60px;
+ }
+ }
+}
+
+.sdc-popup-menu {
+ @include box-shadow(0 1px 3px 0 rgba(0, 0, 0, 0.2));
+ width: 200px;
+ height: 200px;
+ border: 1px solid $light-gray;
+}
+
+.typography-screen {
+ .typography-section {
+ margin: 20px 0;
+ }
+ ul {
+ font-size: 18px;
+ }
+ .typo-table {
+ .typo-section {
+ div {
+ display: inline-block;
+ //border: 1px solid black;
+ width: 30%;
+ margin: 4px 0;
+ }
+ .sample-text {
+ white-space: nowrap;
+
+ }
+ }
+ }
+ .heading-1 {
+ @include heading-1;
+ }
+ .heading-2 {
+ @include heading-2;
+ }
+ .heading-3 {
+ @include heading-3;
+ }
+ .heading-4 {
+ @include heading-4;
+ }
+ .heading-4-emphasis {
+ @include heading-4-emphasis;
+ }
+ .heading-5 {
+ @include heading-5;
+ }
+
+ .body-1 {
+ @include body-1;
+ }
+
+ .body-1-italic {
+ @include body-1-italic;
+ }
+
+ .body-2 {
+ @include body-2;
+ }
+
+ .body-2-emphasis {
+ @include body-2-emphasis;
+ }
+
+ .body-3 {
+ @include body-3;
+ }
+
+ .body-3-emphasis {
+ @include body-3-emphasis;
+ }
+
+ .body-4 {
+ @include body-4;
+ }
+}
+
+.source-toggle-wrapper {
+ .source-toggle-title {
+ @include heading-2;
+ }
+ .source-toggle {
+ display: flex;
+ border-top: 1px solid $light-gray;
+ padding: 10px 0;
+ &:first-child {
+ border-top: none;
+ }
+ .source-toggle-example {
+ flex-basis: 40%;
+ flex-shrink: 0;
+ }
+ .source-toggle-code {
+ background-color: $light-silver;
+ padding: 5px;
+ margin-left: 30px;
+ pre {
+ margin-top: 0;
+ user-select: text;
+ overflow-x: auto;
+ overflow-y: hidden;
+ max-width: 800px;
+ code {
+ font-size: 15px;
+ font-weight: 600;
+ padding: 2px 5px;
+ border: 1px solid #eae9e9;
+ border-radius: 4px;
+ background-color: #f3f2f2;
+ color: #3a3a3a;
+ .token {
+ line-height: 20px;
+ }
+ }
+ }
+ .source-toggle-code-tabs {
+ display: flex;
+ margin-bottom: 10px;
+ .source-toggle-tab {
+ @include body-1;
+ @include base-font-semibold;
+ margin-right: 20px;
+ cursor: pointer;
+ &.selected {
+ border-bottom: 2px solid $dark-blue;
+ color: $dark-blue;
+ font-weight: bold;
+ }
+ }
+ }
+ }
+ }
+}
+
diff --git a/.storybook/typography.scss b/.storybook/typography.scss
new file mode 100644
index 0000000..36f9b02
--- /dev/null
+++ b/.storybook/typography.scss
@@ -0,0 +1,30 @@
+@font-face {
+ font-family: 'OpenSans-Regular';
+ font-style: normal;
+ font-weight: 400;
+ src:
+ local('Open Sans Regular'),
+ local('OpenSans-Regular'),
+ url(https://fonts.gstatic.com/s/opensans/v15/cJZKeOuBrn4kERxqtaUH3ZBw1xU1rKptJj_0jans920.woff2) format('woff2'),
+ url(http://fonts.gstatic.com/s/opensans/v15/cJZKeOuBrn4kERxqtaUH3T8E0i7KZn-EPnyo3HZu7kw.woff) format('woff');
+}
+@font-face {
+ font-family: 'OpenSans-Italic';
+ font-style: normal;
+ font-weight: 400;
+ src:
+ local('Open Sans Italic'),
+ local('OpenSans-Italic'),
+ url(https://fonts.gstatic.com/s/opensans/v15/xjAJXh38I15wypJXxuGMBogp9Q8gbYrhqGlRav_IXfk.woff2) format('woff2'),
+ url(http://fonts.gstatic.com/s/opensans/v15/xjAJXh38I15wypJXxuGMBobN6UDyHWBl620a-IRfuBk.woff) format('woff');
+}
+@font-face {
+ font-family: 'OpenSans-Semibold';
+ font-style: normal;
+ font-weight: 400;
+ src:
+ local('Open Sans Semibold'),
+ local('OpenSans-Semibold'),
+ url(https://fonts.gstatic.com/s/opensans/v15/MTP_ySUJH_bn48VBG8sNShampu5_7CjHW5spxoeN3Vs.woff2) format('woff2'),
+ url(http://fonts.gstatic.com/s/opensans/v15/MTP_ySUJH_bn48VBG8sNSnhCUOGz7vYGh680lGh-uXM.woff) format('woff');
+}
diff --git a/.storybook/webpack.config.js b/.storybook/webpack.config.js
new file mode 100644
index 0000000..a923d80
--- /dev/null
+++ b/.storybook/webpack.config.js
@@ -0,0 +1,39 @@
+
+const path = require('path');
+const webpack = require('webpack');
+const svgFolder = './assets/icons/';
+const fs = require('fs');
+
+let iconNames = [];
+
+fs.readdirSync(svgFolder).forEach(file => {
+ let fileName = file.split('.');
+ if (fileName[0] && fileName[1] === 'svg') {
+ iconNames.push(fileName[0]);
+ }
+});
+
+module.exports = {
+ module: {
+ rules: [
+ {
+ test: /.scss$/,
+ use: ['style-loader', 'css-loader', 'sass-loader'],
+ include: path.resolve(__dirname, '../')
+ },
+ {
+ test: /.html$/,
+ loader: 'html-loader',
+ options: {
+ minimize: false
+ }
+ }
+ ]
+ },
+ plugins: [
+ new webpack.DefinePlugin({
+ 'ICON_PATH': '"./"',
+ 'ICON_NAMES':JSON.stringify(iconNames)
+ })
+ ]
+};
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..3afac06
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,31 @@
+language: node_js
+node_js:
+- 6
+install: npm install
+script:
+- npm run build-common
+- npm test
+- npm run build
+- npm run build-gh-pages
+deploy:
+ - provider: npm
+ email: onap.sdc@gmail.com
+ api_key: $NPM_TOKEN
+ skip_cleanup: true
+ on:
+ tags: true
+ repo: onap-sdc/sdc-ui
+ - provider: pages
+ repo: onap-sdc/sdc-ui
+ skip_cleanup: true
+ github_token: $GITHUB_TOKEN
+ local_dir: .out
+ on:
+ branch: master
+ - provider: pages
+ skip_cleanup: true
+ github_token: $GITHUB_TOKEN
+ local_dir: .out
+ on:
+ all_branches: true
+ condition: $DEPLOY = 1
diff --git a/LICENSE.TXT b/LICENSE.TXT
new file mode 100644
index 0000000..f2eb9ea
--- /dev/null
+++ b/LICENSE.TXT
@@ -0,0 +1,20 @@
+/*
+* ============LICENSE_START==========================================
+* ===================================================================
+* Copyright © 2018 AT&T Intellectual Property.
+* Copyright © 2018 Amdocs
+* All rights reserved.
+* ===================================================================
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+* ============LICENSE_END============================================
+*/ \ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e83552b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,111 @@
+# SDC-UI Style-Guide and Components
+
+This project aims to create a unified UI styled components for multiple development teams who work on the same web-based applications.
+This repository contains the definition of all the basic widgets and reusable controllers.
+
+
+### Usage
+
+#### Link the library's CSS file
+There are several options to link to sdc-ui CSS file:
+
+###### SCSS
+```scss
+@import "path_to_node_modules/sdc-ui/css/style.css";
+```
+###### HTML
+```html
+<link rel="stylesheet" href="path_to_node_modules/sdc-ui/css/style.css">
+```
+###### As Module (Using loading tool, i.e. [Webpack](https://webpack.github.io/))
+```js
+import 'sdc-ui/css/style.css';
+```
+###### Angular CLI projects
+You can add this line to style.css file:
+```js
+@import "../node_modules/sdc-ui/css/style.css";
+```
+
+#### React Code examples
+###### Importing particular component
+```js
+import Button from 'sdc-ui/lib/react/Button.js';
+
+// inside component rendering...
+render(){
+ return (
+ <Button>I am a Button</Button>
+ );
+}
+```
+###### Importing particular component from the react library
+```js
+import {Button} from 'sdc-ui/lib/react';
+
+// inside component rendering...
+render(){
+ return (
+ <Button>I am a Button</Button>
+ );
+}
+```
+###### Importing the entire library
+```js
+import SDCUI from 'sdc-ui';
+
+// inside component rendering...
+render(){
+ return (
+ <SDCUI.React.Button>I am still a Button</SDCUI.React.Button>
+ );
+}
+```
+
+#### Using the library in Angular (2-5)
+###### Add the library to your module
+```js
+ import { SdcUiComponentsModule, SdcUiComponents } from 'sdc-ui/lib/angular';
+
+ @NgModule({
+ declarations: [
+ AppComponent
+ ],
+ imports: [
+ BrowserModule,
+ FormsModule,
+ HttpModule,
+ SdcUiComponentsModule
+ ],
+ providers: [
+ SdcUiComponents.ModalService
+ ],
+ bootstrap: [AppComponent]
+ })
+ export class AppModule { }
+```
+
+
+### Running storybook
+The components in this library are displayed via [storybook](https://github.com/storybooks/storybook). Head to [http://onap-sdc.github.io/sdc-ui](http://onap-sdc.github.io/sdc-ui) to see the components that are in `master`.
+
+While developing, just run `npm run storybook` in your terminal to launch a local storybook server where you can see your changes. For deploying storybook to your own fork repository, refer to the guides section below.
+
+
+### Running component-lab
+To see angular components in design run: npm run lab
+
+
+### Useful guides
+[Adding a new component](https://github.com/onap-sdc/sdc-ui/wiki/Adding-a-new-component)
+
+[Deploying storybook to a fork's github pages](https://github.com/onap-sdc/sdc-ui/wiki/Deploying-storybook-to-a-fork's-github-pages)
+
+### Having some trouble? Have an issue?
+For bugs and issues, please use the [issues](https://github.com/onap-sdc/sdc-ui/issues) page
+
+### How to Contribute
+**Contribution can be made only by following these guide lines**
+* This project combines both `React` & `Angular` framework libraries. Hence, every change in the basic HTML files structure, must be followed by changes on the frameworks files accordingly (under `src/react` and `src/angular`).
+* There will be no any 3rd party UI framework imported (i.e. `Bootstrap`, `Material`, `Foundation`... etc.).
+* Contribution are done only by the [contribution guide](https://github.com/onap-sdc/sdc-ui/wiki/Contribution-guide). Contributions submitted not in this format and guidelines will not be considered.
diff --git a/assets/README.md b/assets/README.md
new file mode 100644
index 0000000..5f2681b
--- /dev/null
+++ b/assets/README.md
@@ -0,0 +1,9 @@
+
+# Folder Structure
+
+### icons
+Contains `svg` icons **ONLY**
+
+
+### images
+Contains large images (if any...)
diff --git a/assets/icons/angleDoubleLeft.svg b/assets/icons/angleDoubleLeft.svg
new file mode 100644
index 0000000..9e1591a
--- /dev/null
+++ b/assets/icons/angleDoubleLeft.svg
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="angle-double-left_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 9 9.9" style="enable-background:new 0 0 9 9.9;" xml:space="preserve">
+<g>
+ <g transform="translate(0,-952.36218)">
+ <path d="M8.5,952.4c-0.1,0-0.2,0-0.2,0.1l-5.5,4.6c-0.2,0.1-0.2,0.4,0,0.5l0,0l5.5,4.6c0.2,0.1,0.4,0.1,0.5,0
+ c0.1-0.2,0.1-0.4,0-0.5l0,0l-5.2-4.3l5.2-4.3c0.2-0.1,0.2-0.4,0.1-0.5C8.7,952.4,8.6,952.4,8.5,952.4z"/>
+ </g>
+ <g transform="translate(0,-952.36218)">
+ <path d="M5.8,952.4c-0.1,0-0.2,0-0.2,0.1l-5.5,4.6c-0.2,0.1-0.2,0.4,0,0.5l0,0l5.5,4.6c0.2,0.1,0.4,0.1,0.5,0
+ c0.1-0.2,0.1-0.4,0-0.5l0,0l-5.2-4.3l5.2-4.3c0.2-0.1,0.2-0.4,0.1-0.5C6,952.4,5.9,952.4,5.8,952.4z"/>
+ </g>
+</g>
+</svg>
diff --git a/assets/icons/angleDoubleRight.svg b/assets/icons/angleDoubleRight.svg
new file mode 100644
index 0000000..e77031a
--- /dev/null
+++ b/assets/icons/angleDoubleRight.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="angle-double-right_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 9 10" style="enable-background:new 0 0 9 10;" xml:space="preserve">
+<g>
+ <path d="M6.2,4.8C6.2,4.7,6.1,4.7,6.2,4.8L0.6,0.1C0.5,0,0.2,0,0.1,0.1C0,0.3,0,0.5,0.1,0.7L5.3,5L0.1,9.3C0,9.5,0,9.7,0.1,9.9
+ C0.2,10,0.3,10,0.4,10s0.2,0,0.2-0.1l5.5-4.6C6.3,5.2,6.3,4.9,6.2,4.8z"/>
+ <path d="M8.9,4.8C8.9,4.7,8.9,4.7,8.9,4.8L3.4,0.1C3.2,0,3,0,2.8,0.1c-0.1,0.2-0.1,0.4,0,0.5L8,5L2.9,9.3C2.7,9.5,2.7,9.7,2.8,9.9
+ C2.9,10,3,10,3.1,10s0.2,0,0.2-0.1l5.5-4.6C9,5.2,9,4.9,8.9,4.8z"/>
+</g>
+</svg>
diff --git a/assets/icons/angleLeft.svg b/assets/icons/angleLeft.svg
new file mode 100644
index 0000000..b2d2f81
--- /dev/null
+++ b/assets/icons/angleLeft.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="angle-left_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 6.3 9.9" style="enable-background:new 0 0 6.3 9.9;" xml:space="preserve">
+<g transform="translate(0,-952.36218)">
+ <path d="M5.8,952.4c-0.1,0-0.2,0-0.2,0.1l-5.5,4.6c-0.2,0.1-0.2,0.4,0,0.5l0,0l5.5,4.6c0.2,0.1,0.4,0.1,0.5,0
+ c0.1-0.2,0.1-0.4,0-0.5l0,0l-5.2-4.3l5.2-4.3c0.2-0.1,0.2-0.4,0.1-0.5C6,952.4,5.9,952.4,5.8,952.4z"/>
+</g>
+</svg>
diff --git a/assets/icons/angleRight.svg b/assets/icons/angleRight.svg
new file mode 100644
index 0000000..f8e6efc
--- /dev/null
+++ b/assets/icons/angleRight.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="angle-right_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 6.3 9.9" style="enable-background:new 0 0 6.3 9.9;" xml:space="preserve">
+<g transform="translate(0,-952.36218)">
+ <path d="M0.5,962.2c0.1,0,0.2,0,0.2-0.1l5.5-4.6c0.2-0.1,0.2-0.4,0-0.5l0,0l-5.5-4.6c-0.2-0.1-0.4-0.1-0.5,0
+ c-0.1,0.2-0.1,0.4,0,0.5l0,0l5.2,4.3l-5.2,4.3C0,961.6,0,961.9,0.1,962C0.3,962.1,0.4,962.2,0.5,962.2z"/>
+</g>
+</svg>
diff --git a/assets/icons/artifacts.svg b/assets/icons/artifacts.svg
new file mode 100644
index 0000000..41e6c8e
--- /dev/null
+++ b/assets/icons/artifacts.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 20"><title>Asset 1</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path d="M0,0V20H16V0ZM15,19H1V3H15Z"/><rect x="3" y="6" width="10" height="1"/><rect x="3" y="9" width="10" height="1"/><rect x="3" y="12" width="10" height="1"/><rect x="3" y="15" width="10" height="1"/></g></g></svg> \ No newline at end of file
diff --git a/assets/icons/back.svg b/assets/icons/back.svg
new file mode 100644
index 0000000..287355f
--- /dev/null
+++ b/assets/icons/back.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="back_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 9.2 19.9" style="enable-background:new 0 0 9.2 19.9;" xml:space="preserve">
+<polygon points="7.6,19.9 0,10 7.6,0 9.2,1.2 2.5,10 9.2,18.7 "/>
+</svg>
diff --git a/assets/icons/base.svg b/assets/icons/base.svg
new file mode 100644
index 0000000..89fbd43
--- /dev/null
+++ b/assets/icons/base.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 19.95 19.24"><title>base.volume</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path d="M10,1c5,0,8.5,2.11,8.5,4S15,9,10,9s-8.5-2.11-8.5-4S5,1,10,1m0-1C4.73,0,.47,2.24.47,5s4.25,5,9.5,5,9.5-2.24,9.5-5S15.22,0,10,0Z"/><path d="M10,13.24C4.38,13.24,0,10.94,0,8A.5.5,0,0,1,1,8c0,2.3,4.11,4.24,9,4.24s9-1.94,9-4.24a.5.5,0,0,1,1,0C19.95,10.94,15.57,13.24,10,13.24Z"/><path d="M10,16.24c-5.59,0-10-2.3-10-5.24a.5.5,0,0,1,1,0c0,2.3,4.11,4.24,9,4.24s9-1.94,9-4.24a.5.5,0,0,1,1,0C19.95,13.94,15.57,16.24,10,16.24Z"/><path d="M10,19.24c-5.59,0-10-2.3-10-5.24a.5.5,0,0,1,1,0c0,2.3,4.11,4.24,9,4.24s9-1.94,9-4.24a.5.5,0,0,1,1,0C19.95,16.94,15.57,19.24,10,19.24Z"/></g></g></svg> \ No newline at end of file
diff --git a/assets/icons/calendar.svg b/assets/icons/calendar.svg
new file mode 100644
index 0000000..9c05902
--- /dev/null
+++ b/assets/icons/calendar.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 17 18" id="calendar_icon"><title>Asset 1</title><g data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path d="M15.5,2H13V0H12V2H9V0H8V2H5V0H4V2H1.5A1.5,1.5,0,0,0,0,3.5v13A1.5,1.5,0,0,0,1.5,18h14A1.5,1.5,0,0,0,17,16.5V3.5A1.5,1.5,0,0,0,15.5,2ZM16,16.5a.5.5,0,0,1-.5.5H1.5a.5.5,0,0,1-.5-.5V8H16ZM1,7V3.5A.5.5,0,0,1,1.5,3H4V5H5V3H8V5H9V3h3V5h1V3h2.5a.5.5,0,0,1,.5.5V7Z"/><path d="M4.52,13.65l.7-.09a1.55,1.55,0,0,0,.41.86,1,1,0,0,0,.71.26,1.14,1.14,0,0,0,.84-.34,1.16,1.16,0,0,0,.34-.85,1.08,1.08,0,0,0-.32-.8,1.09,1.09,0,0,0-.8-.31,2,2,0,0,0-.5.08L6,11.84H6.1a1.45,1.45,0,0,0,.81-.23.8.8,0,0,0,.36-.72A.85.85,0,0,0,7,10.25.93.93,0,0,0,6.33,10a1,1,0,0,0-.68.26A1.29,1.29,0,0,0,5.3,11l-.7-.12a1.81,1.81,0,0,1,.59-1.1,1.69,1.69,0,0,1,1.14-.39,1.86,1.86,0,0,1,.86.2,1.45,1.45,0,0,1,.6.55A1.41,1.41,0,0,1,8,10.9a1.21,1.21,0,0,1-.2.68,1.36,1.36,0,0,1-.59.48,1.33,1.33,0,0,1,.79.49,1.48,1.48,0,0,1,.28.92,1.69,1.69,0,0,1-.55,1.27,1.92,1.92,0,0,1-1.38.52,1.8,1.8,0,0,1-1.25-.45A1.74,1.74,0,0,1,4.52,13.65Z"/><path d="M11.62,15.17h-.7V10.69a3.68,3.68,0,0,1-.67.48,4.77,4.77,0,0,1-.74.36v-.68a4.26,4.26,0,0,0,1-.67,2.66,2.66,0,0,0,.63-.77h.45Z"/></g></g></svg> \ No newline at end of file
diff --git a/assets/icons/caretDown.svg b/assets/icons/caretDown.svg
new file mode 100644
index 0000000..cfd3c57
--- /dev/null
+++ b/assets/icons/caretDown.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="caret-down_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 10 5" style="enable-background:new 0 0 10 5;" xml:space="preserve">
+<path d="M0,0l5,5l5-5H0z"/>
+</svg>
diff --git a/assets/icons/check.svg b/assets/icons/check.svg
new file mode 100644
index 0000000..43d1881
--- /dev/null
+++ b/assets/icons/check.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="check_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 14 10" style="enable-background:new 0 0 14 10;" xml:space="preserve">
+<g transform="translate(0,-952.36218)">
+ <path d="M13.6,952.4c-0.1,0-0.2,0.1-0.3,0.2c-2.8,2.9-5.6,5.8-8.4,8.7l-4-3.5c-0.2-0.2-0.5-0.2-0.7,0s-0.2,0.5,0,0.7l0,0l4.4,3.7
+ c0.2,0.2,0.5,0.1,0.6,0c2.9-3,5.8-6,8.7-9.1c0.2-0.2,0.2-0.5,0-0.7C13.8,952.4,13.6,952.4,13.6,952.4L13.6,952.4z"/>
+</g>
+</svg>
diff --git a/assets/icons/checkCircle.svg b/assets/icons/checkCircle.svg
new file mode 100644
index 0000000..313657e
--- /dev/null
+++ b/assets/icons/checkCircle.svg
@@ -0,0 +1 @@
+<svg id="check-circle_icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path d="M8,16A8,8,0,1,0,0,8,8,8,0,0,0,8,16ZM4.5,6.8,6.7,9l4.4-4.3,1.2,1.2L6.7,11.5,3.2,8Z"/></g></g></svg>
diff --git a/assets/icons/chevronDown.svg b/assets/icons/chevronDown.svg
new file mode 100644
index 0000000..1ebd094
--- /dev/null
+++ b/assets/icons/chevronDown.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="chevron-down_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 10 6.3" style="enable-background:new 0 0 10 6.3;" xml:space="preserve">
+<g transform="translate(0,-952.36218)">
+ <path d="M0.1,952.8c0,0.1,0,0.2,0.1,0.2l4.6,5.5c0.1,0.2,0.4,0.2,0.5,0l0,0l4.6-5.5c0.1-0.2,0.1-0.4,0-0.5s-0.4-0.1-0.5,0l0,0
+ l-4.3,5.2l-4.3-5.2c-0.1-0.2-0.4-0.2-0.5-0.1C0.1,952.5,0.1,952.6,0.1,952.8z"/>
+</g>
+</svg>
diff --git a/assets/icons/chevronUp.svg b/assets/icons/chevronUp.svg
new file mode 100644
index 0000000..7fce935
--- /dev/null
+++ b/assets/icons/chevronUp.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="chevron-up_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 10 6.3" style="enable-background:new 0 0 10 6.3;" xml:space="preserve">
+<g transform="translate(0,-952.36218)">
+ <path d="M10,958.2c0-0.1,0-0.2-0.1-0.2l-4.6-5.5c-0.1-0.2-0.4-0.2-0.5,0l0,0L0.1,958c-0.1,0.2-0.1,0.4,0,0.5s0.4,0.1,0.5,0l0,0
+ l4.3-5.2l4.3,5.2c0.1,0.2,0.4,0.2,0.5,0.1C10,958.5,10,958.3,10,958.2z"/>
+</g>
+</svg>
diff --git a/assets/icons/close.svg b/assets/icons/close.svg
new file mode 100644
index 0000000..0decc7c
--- /dev/null
+++ b/assets/icons/close.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="close_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 10.1 10.1" style="enable-background:new 0 0 10.1 10.1;" xml:space="preserve">
+<g transform="translate(0,-952.36218)">
+ <path d="M0.5,952.4c-0.2,0-0.4,0.2-0.4,0.5c0,0.1,0.1,0.2,0.1,0.3l4.3,4.3l-4.3,4.3c-0.2,0.2-0.2,0.4,0,0.6c0.2,0.2,0.4,0.2,0.6,0
+ l0,0l4.3-4.4l4.3,4.3c0.2,0.2,0.4,0.2,0.6,0s0.2-0.4,0-0.6l0,0l-4.3-4.3l4.3-4.3c0.2-0.2,0.2-0.4,0-0.6c-0.1-0.1-0.2-0.1-0.4-0.1
+ c-0.1,0-0.2,0.1-0.3,0.1l-4.2,4.3l-4.3-4.3C0.8,952.4,0.6,952.4,0.5,952.4z"/>
+</g>
+</svg>
diff --git a/assets/icons/download.svg b/assets/icons/download.svg
new file mode 100644
index 0000000..dd64605
--- /dev/null
+++ b/assets/icons/download.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 15 11"><title>Asset 2</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><polygon points="14 6 14 10 1 10 1 6 0 6 0 11 15 11 15 6 14 6"/><polygon points="11.29 3.79 10.58 3.08 8 5.66 8 0 7 0 7 5.66 4.42 3.08 3.71 3.79 7.5 7.58 11.29 3.79"/></g></g></svg> \ No newline at end of file
diff --git a/assets/icons/empty.txt b/assets/icons/empty.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/assets/icons/empty.txt
diff --git a/assets/icons/env.svg b/assets/icons/env.svg
new file mode 100644
index 0000000..ac68ae6
--- /dev/null
+++ b/assets/icons/env.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 15 14"><title>env</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><rect x="3" y="6" width="9" height="1"/><rect x="3" y="8" width="9" height="1"/><rect x="5" y="10" width="5" height="1"/><path d="M8,2V0H7V2H0V14H15V2Zm6,11H1V3H7V4H8V3h6Z"/></g></g></svg> \ No newline at end of file
diff --git a/assets/icons/error.svg b/assets/icons/error.svg
new file mode 100644
index 0000000..bafb73b
--- /dev/null
+++ b/assets/icons/error.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 17 17"><title>error</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path d="M8.5,1A7.5,7.5,0,1,1,1,8.5,7.51,7.51,0,0,1,8.5,1m0-1A8.5,8.5,0,1,0,17,8.5,8.5,8.5,0,0,0,8.5,0Z"/><polygon points="11.6 6.1 10.9 5.4 8.5 7.79 6.1 5.4 5.4 6.1 7.79 8.5 5.4 10.9 6.1 11.6 8.5 9.21 10.9 11.6 11.6 10.9 9.21 8.5 11.6 6.1"/></g></g></svg> \ No newline at end of file
diff --git a/assets/icons/errorCircle.svg b/assets/icons/errorCircle.svg
new file mode 100644
index 0000000..8234753
--- /dev/null
+++ b/assets/icons/errorCircle.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" id="error-circle_icon" viewBox="0 0 16 16"><title>Asset 4</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path d="M8,0a8,8,0,1,0,8,8A8,8,0,0,0,8,0Zm.9,12.4H7.1V10.6H8.9Zm0-3.6H7.1V3.5H8.9Z"/></g></g></svg> \ No newline at end of file
diff --git a/assets/icons/exclamationTriangleFull.svg b/assets/icons/exclamationTriangleFull.svg
new file mode 100644
index 0000000..7cab121
--- /dev/null
+++ b/assets/icons/exclamationTriangleFull.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="exclamation-triangle-full_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 19.9 18" style="enable-background:new 0 0 19.9 18;" xml:space="preserve">
+<path d="M19.6,14.3L12,1.3c-0.3-0.6-0.8-1-1.4-1.2C10-0.1,9.3,0,8.7,0.3c-0.4,0.3-0.6,0.6-0.9,1l-7.6,13c-0.3,0.5-0.4,1.2-0.2,1.8
+ c0.2,0.6,0.6,1.1,1.1,1.4C1.6,17.8,1.9,18,2.4,18h15.1c1.3,0,2.4-1.1,2.4-2.4C19.9,15.1,19.8,14.7,19.6,14.3z M10.5,14.2
+ c0,0.3-0.2,0.5-0.5,0.5s-0.5-0.2-0.5-0.5l0-1c0-0.3,0.2-0.5,0.5-0.5s0.5,0.2,0.5,0.5L10.5,14.2z M10.5,9.9c0,0.3-0.2,0.5-0.5,0.5
+ s-0.5-0.2-0.5-0.5l0-5.2c0-0.3,0.2-0.5,0.5-0.5s0.5,0.2,0.5,0.5L10.5,9.9z"/>
+</svg>
diff --git a/assets/icons/exclamationTriangleLine.svg b/assets/icons/exclamationTriangleLine.svg
new file mode 100644
index 0000000..eae6825
--- /dev/null
+++ b/assets/icons/exclamationTriangleLine.svg
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="exclamation-triangle-line_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 19.9 18" style="enable-background:new 0 0 19.9 18;" xml:space="preserve">
+<g>
+ <path d="M17.6,18H2.4c-0.5,0-0.9-0.1-1.3-0.4c-0.5-0.3-0.9-0.8-1.1-1.4c-0.2-0.6-0.1-1.3,0.2-1.8l7.6-13c0.2-0.3,0.5-0.7,0.9-1
+ C9.3,0,10-0.1,10.6,0.1c0.6,0.2,1.1,0.6,1.4,1.2l7.5,13c0.2,0.4,0.4,0.8,0.4,1.3C19.9,16.9,18.9,18,17.6,18z M9.9,1
+ C9.7,1,9.4,1.1,9.2,1.2C9.1,1.3,8.9,1.6,8.7,1.8l-7.5,13C1,15.1,1,15.5,1,15.9c0.1,0.4,0.3,0.7,0.6,0.8C1.9,16.9,2.1,17,2.4,17
+ h15.1c0.9,0,1.4-0.7,1.4-1.4c0-0.2-0.1-0.5-0.2-0.7l0,0l-7.6-13c-0.2-0.4-0.5-0.6-0.8-0.7C10.2,1,10.1,1,9.9,1z"/>
+ <g>
+ <g>
+ <g>
+ <path d="M10,10.4L10,10.4c-0.3,0-0.5-0.2-0.5-0.5l0-5.2c0-0.3,0.2-0.5,0.5-0.5l0,0c0.3,0,0.5,0.2,0.5,0.5l0,5.2
+ C10.5,10.2,10.2,10.4,10,10.4z"/>
+ </g>
+ </g>
+ <g>
+ <g>
+ <path d="M10,14.7L10,14.7c-0.3,0-0.5-0.2-0.5-0.5l0-1c0-0.3,0.2-0.5,0.5-0.5l0,0c0.3,0,0.5,0.2,0.5,0.5l0,1
+ C10.5,14.5,10.2,14.7,10,14.7z"/>
+ </g>
+ </g>
+ </g>
+</g>
+</svg>
diff --git a/assets/icons/expand.svg b/assets/icons/expand.svg
new file mode 100644
index 0000000..4095ef5
--- /dev/null
+++ b/assets/icons/expand.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><title>Asset 1</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><polygon points="0 6 1 6 1 1.71 5.15 5.85 5.85 5.15 1.71 1 6 1 6 0 0 0 0 6"/><polygon points="10 0 10 1 14.29 1 10.15 5.15 10.85 5.85 15 1.71 15 6 16 6 16 0 10 0"/><polygon points="15 14.29 10.85 10.15 10.15 10.85 14.29 15 10 15 10 16 16 16 16 10 15 10 15 14.29"/><polygon points="5.85 10.85 5.15 10.15 1 14.29 1 10 0 10 0 16 6 16 6 15 1.71 15 5.85 10.85"/></g></g></svg> \ No newline at end of file
diff --git a/assets/icons/filter.svg b/assets/icons/filter.svg
new file mode 100644
index 0000000..1c493f4
--- /dev/null
+++ b/assets/icons/filter.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="filter_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 20 20" style="enable-background:new 0 0 20 20;" xml:space="preserve">
+<path d="M8.9,20c-0.2,0-0.4,0-0.6-0.1c-0.6-0.3-1-0.8-1-1.5V9L0.5,3.2C0.2,2.9,0,2.4,0,2V1.6C0,0.7,0.7,0,1.6,0h16.9
+ c0.9,0,1.6,0.7,1.6,1.6v0.7c0,0.5-0.2,0.9-0.6,1.2l-7,5.5v7.5c0,0.4-0.2,0.9-0.4,1.2l-2,1.9C9.7,19.9,9.3,20,8.9,20z M1.6,1
+ C1.3,1,1,1.3,1,1.6V2c0,0.2,0.1,0.4,0.2,0.4l7.1,6.1v9.8c0,0.4,0.3,0.5,0.4,0.6c0.1,0,0.4,0.1,0.7-0.1l2-1.9
+ c0.1-0.1,0.1-0.3,0.1-0.4V8.6l7.4-5.9c0.1-0.1,0.2-0.2,0.2-0.4V1.6c0-0.3-0.3-0.6-0.6-0.6H1.6z"/>
+</svg>
diff --git a/assets/icons/locked.svg b/assets/icons/locked.svg
new file mode 100644
index 0000000..ab9f0b9
--- /dev/null
+++ b/assets/icons/locked.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="11" height="15" viewBox="0 0 11 15" id="locked_icon">
+ <path id="Shape_77_copy_10" data-name="Shape 77 copy 10" class="cls-1" d="M445,359a16.71,16.71,0,0,0-2.1-.009c-1.945.045-3.195,0.049-3.9,0.009v-5a1.743,1.743,0,0,1,2-2h1a1.743,1.743,0,0,1,2,2v5c0.474,0.063.343-.073,1,0,0.266,0.029,0,.279,0,0v-5a2.726,2.726,0,0,0-3-3h-1.142c-1.72-.125-2.715,1.562-2.858,3,0.088,0.009,0,7.338,0,5h0a1.891,1.891,0,0,0-2,1.689v3.461A1.823,1.823,0,0,0,437.775,366h7.448A1.823,1.823,0,0,0,447,364.15v-3.461A2.018,2.018,0,0,0,445,359Z" transform="translate(-436 -351)"/>
+</svg>
diff --git a/assets/icons/module.svg b/assets/icons/module.svg
new file mode 100644
index 0000000..fa3901c
--- /dev/null
+++ b/assets/icons/module.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><title>module</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path d="M20,20H3V14A3,3,0,0,1,3,8V3H8a3,3,0,0,1,6,0h6V9.32l-.64-.19C17.57,8.59,16,9.68,16,11s1.57,2.4,3.36,1.87l.64-.19ZM4,19H19V14c-2.12.29-4-1.17-4-3a3.35,3.35,0,0,1,4-3V4H12.84L13,3.4A2,2,0,0,0,13,3,2,2,0,0,0,9,3a2,2,0,0,0,0,.4l.12.6H4V9.16L3.4,9A2,2,0,0,0,3,9a2,2,0,0,0,0,4,2,2,0,0,0,.4,0l.6-.12Z"/></g></g></svg> \ No newline at end of file
diff --git a/assets/icons/nestedHeat.svg b/assets/icons/nestedHeat.svg
new file mode 100644
index 0000000..7e33068
--- /dev/null
+++ b/assets/icons/nestedHeat.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 15 13"><title>nested_heat</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path d="M4.16,1,5.48,2.63l.3.37H14v9H1V1H4.16m.48-1H0V13H15V2H6.26L4.64,0Z"/><rect x="4" y="7" width="7" height="1"/></g></g></svg> \ No newline at end of file
diff --git a/assets/icons/network.svg b/assets/icons/network.svg
new file mode 100644
index 0000000..018cd3f
--- /dev/null
+++ b/assets/icons/network.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 13 13"><title>network</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path d="M10.5,8a2.48,2.48,0,0,0-1.38.42l-.54-.54a2.48,2.48,0,0,0,0-2.75l.54-.54a2.51,2.51,0,1,0-.71-.71l-.54.54a2.48,2.48,0,0,0-2.75,0l-.54-.54a2.51,2.51,0,1,0-.71.71l.54.54a2.48,2.48,0,0,0,0,2.75l-.54.54a2.51,2.51,0,1,0,.71.71l.54-.54a2.48,2.48,0,0,0,2.75,0l.54.54A2.5,2.5,0,1,0,10.5,8Zm0-7A1.5,1.5,0,1,1,9,2.5,1.5,1.5,0,0,1,10.5,1Zm-8,3A1.5,1.5,0,1,1,4,2.5,1.5,1.5,0,0,1,2.5,4Zm0,8A1.5,1.5,0,1,1,4,10.5,1.5,1.5,0,0,1,2.5,12Zm4-4A1.5,1.5,0,1,1,8,6.5,1.5,1.5,0,0,1,6.5,8Zm4,4A1.5,1.5,0,1,1,12,10.5,1.5,1.5,0,0,1,10.5,12Z"/></g></g></svg> \ No newline at end of file
diff --git a/assets/icons/notificationBell.svg b/assets/icons/notificationBell.svg
new file mode 100644
index 0000000..6001d59
--- /dev/null
+++ b/assets/icons/notificationBell.svg
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="notification_bell_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 18 21.9" style="enable-background:new 0 0 18 21.9;" xml:space="preserve">
+<title>notification_icon</title>
+<g>
+ <path d="M17.7,16.6c-1.8-2.3-1.8-4-1.8-6.7c0-0.2,0-0.4,0-0.6c-0.2-1.8-1-3.5-2.5-4.7c-0.8-0.7-1.8-1.2-2.8-1.4
+ C10.8,2.8,11,2.4,11,2c0-1.1-0.9-2-2-2S7,0.9,7,2c0,0.4,0.1,0.8,0.4,1.2C4.2,4,2,6.8,2.1,10.1c0,2.6-0.1,4.3-1.8,6.5l0,0.1
+ c-0.1,0.2-0.2,0.3-0.2,0.5C0,18,0.6,18.8,1.4,18.9l4.1,0c0.2,1.7,1.7,3,3.5,3c1.8,0,3.2-1.3,3.5-3l4.2,0c0.2,0,0.5-0.1,0.6-0.2
+ C18,18.2,18.2,17.3,17.7,16.6z M9,1c0.6,0,1,0.4,1,1c0,0.5-0.3,0.8-0.7,0.9c-0.2,0-0.3,0-0.5,0C8.3,2.8,8,2.5,8,2C8,1.4,8.4,1,9,1z
+ M9,20.9c-1.2,0-2.2-0.9-2.5-2l4.9,0C11.2,20.1,10.2,20.9,9,20.9z M16.7,17.8c-0.1,0-0.1,0.1-0.2,0.1l-15.1,0
+ c-0.3,0-0.5-0.3-0.4-0.6c0-0.1,0-0.1,0-0.2c1.9-2.5,1.9-4.6,1.9-7C3,7,5.4,4.3,8.5,4c0,0,0,0,0.1,0C8.7,4,8.8,4,9,4
+ c0.1,0,0.3,0,0.4,0c1.3,0.1,2.4,0.5,3.4,1.4c1.2,1,2,2.4,2.1,4c0,0.2,0,0.4,0,0.5c0,2.7,0,4.8,1.9,7.3C17,17.4,17,17.7,16.7,17.8z"
+ />
+ <path d="M8.5,5.8c-2.2,0.2-3.8,2.1-3.7,4.2c0,0.3,0.2,0.5,0.5,0.5c0,0,0,0,0,0c0.3,0,0.5-0.2,0.5-0.5c0-1.7,1.2-3,2.8-3.2
+ c0.3,0,0.5-0.3,0.4-0.6C9.1,6,8.8,5.8,8.5,5.8z"/>
+</g>
+</svg>
diff --git a/assets/icons/notificationFullBell.svg b/assets/icons/notificationFullBell.svg
new file mode 100644
index 0000000..6e7e7cc
--- /dev/null
+++ b/assets/icons/notificationFullBell.svg
@@ -0,0 +1,11 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 17.98 21.94" id="notification_full_bell_icon">
+ <defs>
+ <style></style>
+ </defs>
+ <title>notification_full</title>
+ <g id="Layer_2" data-name="Layer 2">
+ <g id="Layer_2-2" data-name="Layer 2">
+ <path class="cls-1" d="M17.67,16.61c-1.75-2.29-1.75-4.06-1.75-6.74a7,7,0,0,0-2.24-5.1,6.88,6.88,0,0,0-3.06-1.64,2,2,0,1,0-3.28,0,7.19,7.19,0,0,0-5.29,7c0,2.59-.09,4.29-1.76,6.47a1.45,1.45,0,0,0-.15,1.53,1.43,1.43,0,0,0,1.29.8H5.53a3.48,3.48,0,0,0,6.9,0h4.1a1.43,1.43,0,0,0,1.29-.8A1.46,1.46,0,0,0,17.67,16.61ZM4.8,10.06A4.2,4.2,0,0,1,8.55,5.83a.51.51,0,0,1,.54.46.5.5,0,0,1-.46.54A3.2,3.2,0,0,0,5.8,10.06a.5.5,0,0,1-1,0Z"/>
+ </g>
+ </g>
+</svg>
diff --git a/assets/icons/others.svg b/assets/icons/others.svg
new file mode 100644
index 0000000..9a18e4a
--- /dev/null
+++ b/assets/icons/others.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 12"><title>others</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path d="M5,5H0V0H5ZM1,4H4V1H1Z"/><path d="M5,12H0V7H5ZM1,11H4V8H1Z"/><path d="M12,5H7V0h5ZM8,4h3V1H8Z"/><path d="M12,12H7V7h5ZM8,11h3V8H8Z"/></g></g></svg> \ No newline at end of file
diff --git a/assets/icons/pencil.svg b/assets/icons/pencil.svg
new file mode 100644
index 0000000..6701a3a
--- /dev/null
+++ b/assets/icons/pencil.svg
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 20.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="pencil_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 31.7 32" style="enable-background:new 0 0 31.7 32;" xml:space="preserve">
+<g>
+ <path style="fill:#5A5A5A;" d="M9.8,29.4l-7.5-7.5L23.4,0.8C23.9,0.3,24.6,0,25.2,0c0.7,0,1.3,0.3,1.8,0.8l3.9,3.9c1,1,1,2.7,0,3.7
+ L9.8,29.4z M3.5,21.9l6.3,6.3L30.3,7.7C31,7,31,5.9,30.3,5.3l-3.9-3.9c-0.7-0.7-1.8-0.7-2.4,0L3.5,21.9z"/>
+
+ <rect x="23.7" y="2.7" transform="matrix(0.7071 -0.7071 0.7071 0.7071 1.7119 19.3109)" style="fill:#5A5A5A;" width="0.9" height="9.8"/>
+
+ <rect x="2.6" y="16.1" transform="matrix(0.7071 -0.7071 0.7071 0.7071 -7.2669 15.5571)" style="fill:#5A5A5A;" width="25.1" height="0.9"/>
+ <path style="fill:#5A5A5A;" d="M1.3,32c-0.3,0-0.6-0.1-0.9-0.4s-0.5-0.8-0.4-1.3l2.3-8.5L3.2,22l-2.3,8.5C0.8,30.8,1,30.9,1,31
+ c0.1,0,0.2,0.2,0.4,0.1l8.1-2.5l0.3,0.8l-8.1,2.5C1.5,32,1.4,32,1.3,32z"/>
+
+ <rect x="2.6" y="26.5" transform="matrix(0.6865 -0.7271 0.7271 0.6865 -20.0013 11.2276)" style="fill:#5A5A5A;" width="0.9" height="4.6"/>
+</g>
+</svg>
diff --git a/assets/icons/plus.svg b/assets/icons/plus.svg
new file mode 100644
index 0000000..36f3486
--- /dev/null
+++ b/assets/icons/plus.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="plus_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 19 19" style="enable-background:new 0 0 19 19;" xml:space="preserve">
+<g>
+ <rect y="8" width="19" height="3"/>
+ <path id="Rectangle_2139_copy" d="M8,19V0h3v19H8z"/>
+</g>
+</svg>
diff --git a/assets/icons/plusCircle.svg b/assets/icons/plusCircle.svg
new file mode 100644
index 0000000..63781f5
--- /dev/null
+++ b/assets/icons/plusCircle.svg
@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 19 19">
+ <g>
+ <g>
+ <polygon points="10 14 9 14 9 10 5 10 5 9 9 9 9 5 10 5 10 9 14 9 14 10 10 10 10 14"/>
+ <polygon points="10 14 9 14 9 10 5 10 5 9 9 9 9 5 10 5 10 9 14 9 14 10 10 10 10 14"/>
+ <path d="M9.5,1A8.5,8.5,0,1,1,1,9.5,8.51,8.51,0,0,1,9.5,1m0-1A9.5,9.5,0,1,0,19,9.5,9.5,9.5,0,0,0,9.5,0Z"/>
+ </g>
+ </g>
+</svg>
diff --git a/assets/icons/plusThin.svg b/assets/icons/plusThin.svg
new file mode 100644
index 0000000..571c303
--- /dev/null
+++ b/assets/icons/plusThin.svg
@@ -0,0 +1,7 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 9 9">
+ <g>
+ <g>
+ <polygon points="5 9 4 9 4 5 0 5 0 4 4 4 4 0 5 0 5 4 9 4 9 5 5 5 5 9"/>
+ </g>
+ </g>
+</svg>
diff --git a/assets/icons/proceedToOverview.svg b/assets/icons/proceedToOverview.svg
new file mode 100644
index 0000000..4788106
--- /dev/null
+++ b/assets/icons/proceedToOverview.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24.04 20"><title>proceed_to_overview</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><polygon points="16.83 20 0 20 0 0 20 0 20 10 19 10 19 1 1 1 1 19 16.83 19 16.83 20"/><rect x="3" y="10" width="14" height="1"/><rect x="3" y="13" width="14" height="1"/><path d="M17,8H3V3H17ZM4,7H16V4H4Z"/><polygon points="20.85 13.32 20.15 14.03 22.12 16 13 16 13 17 22.12 17 20.15 18.98 20.85 19.68 24.04 16.5 20.85 13.32"/></g></g></svg> \ No newline at end of file
diff --git a/assets/icons/questionMark.svg b/assets/icons/questionMark.svg
new file mode 100644
index 0000000..3b1c7bc
--- /dev/null
+++ b/assets/icons/questionMark.svg
@@ -0,0 +1 @@
+<svg id='question-mark_icon' xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path d="M8,0a8,8,0,1,0,8,8A7.9,7.9,0,0,0,8,0ZM8,13.1A1.1,1.1,0,1,1,9.1,12,1,1,0,0,1,8,13.1Zm2.3-6.6-.4.4L9.8,7l-.2.2c-.1.1-.3.2-.3.3l-.2.3a1.45,1.45,0,0,0-.2.7v.7H7.3V8.3a2.2,2.2,0,0,1,.1-.8A2,2,0,0,1,8,6.8l.9-.9a.62.62,0,0,0,.2-.7.91.91,0,0,0-.3-.7,1,1,0,0,0-1.4,0,.91.91,0,0,0-.3.7v.1H5.4V5.2a2.43,2.43,0,0,1,.9-1.8,3,3,0,0,1,1.9-.7h.1a2.79,2.79,0,0,1,1.8.6,2,2,0,0,1,.7,1.8A2,2,0,0,1,10.3,6.5Z"/></g></g></svg> \ No newline at end of file
diff --git a/assets/icons/search.svg b/assets/icons/search.svg
new file mode 100644
index 0000000..ce83104
--- /dev/null
+++ b/assets/icons/search.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="search_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 14 14.1" style="enable-background:new 0 0 14 14.1;" xml:space="preserve">
+<path d="M13.9,13.3l-3.6-3.6c0.9-1,1.4-2.4,1.4-3.8C11.7,2.6,9.1,0,5.9,0S0,2.6,0,5.9s2.6,5.9,5.9,5.9c1.5,0,2.8-0.5,3.8-1.4
+ l3.6,3.6c0.1,0.1,0.2,0.1,0.3,0.1s0.2,0,0.3-0.1C14,13.7,14,13.4,13.9,13.3z M5.9,10.9c-2.8,0-5-2.2-5-5s2.2-5,5-5s5,2.2,5,5
+ S8.6,10.9,5.9,10.9z"/>
+</svg>
diff --git a/assets/icons/sliders.svg b/assets/icons/sliders.svg
new file mode 100644
index 0000000..ade9de2
--- /dev/null
+++ b/assets/icons/sliders.svg
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="sliders_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 20 17" style="enable-background:new 0 0 20 17;" xml:space="preserve">
+<g>
+ <rect y="8" width="2.8" height="1"/>
+ <rect y="2" width="10.9" height="1"/>
+ <rect x="15" y="2" width="5" height="1"/>
+ <rect x="6.9" y="8" width="13.1" height="1"/>
+ <rect y="14" width="13" height="1"/>
+ <rect x="17.1" y="14" width="2.9" height="1"/>
+ <path d="M13,5c-1.4,0-2.5-1.1-2.5-2.5S11.6,0,13,0s2.5,1.1,2.5,2.5S14.4,5,13,5z M13,1c-0.8,0-1.5,0.7-1.5,1.5S12.2,4,13,4
+ s1.5-0.7,1.5-1.5S13.8,1,13,1z"/>
+ <path d="M15,17c-1.4,0-2.5-1.1-2.5-2.5S13.6,12,15,12s2.5,1.1,2.5,2.5S16.4,17,15,17z M15,13c-0.8,0-1.5,0.7-1.5,1.5S14.2,16,15,16
+ s1.5-0.7,1.5-1.5S15.8,13,15,13z"/>
+ <path d="M4.9,11c-1.4,0-2.5-1.1-2.5-2.5C2.4,7.1,3.5,6,4.9,6s2.5,1.1,2.5,2.5C7.4,9.9,6.3,11,4.9,11z M4.9,7C4.1,7,3.4,7.7,3.4,8.5
+ S4.1,10,4.9,10s1.5-0.7,1.5-1.5S5.7,7,4.9,7z"/>
+</g>
+</svg>
diff --git a/assets/icons/trashO.svg b/assets/icons/trashO.svg
new file mode 100644
index 0000000..26336f1
--- /dev/null
+++ b/assets/icons/trashO.svg
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="trash-o_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 18.9 19.9" style="enable-background:new 0 0 18.9 19.9;" xml:space="preserve">
+<g>
+ <path d="M16.1,19.9H2.8c-0.8,0-1.5-0.7-1.5-1.5V3h1v15.4c0,0.3,0.3,0.5,0.5,0.5h13.3c0.3,0,0.5-0.3,0.5-0.5V3h1v15.4
+ C17.6,19.2,16.9,19.9,16.1,19.9z"/>
+ <path d="M13.7,3h-1V1.7C12.7,1.4,12.4,1,12,1H6.9C6.6,1,6.2,1.3,6.2,1.7V3h-1V1.7c0-1,0.9-1.7,1.7-1.7H12c1,0,1.7,0.9,1.7,1.7V3z"
+ />
+ <rect y="2.5" width="18.9" height="1"/>
+ <g>
+ <rect x="5.2" y="6.1" width="1" height="10.1"/>
+ <rect x="9" y="6.1" width="1" height="10.1"/>
+ <rect x="12.8" y="6.1" width="1" height="10.1"/>
+ </g>
+</g>
+</svg>
diff --git a/assets/icons/unlocked.svg b/assets/icons/unlocked.svg
new file mode 100644
index 0000000..1e341bd
--- /dev/null
+++ b/assets/icons/unlocked.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="11" height="18" viewBox="0 0 11 18" id="unlocked_icon">
+ <path id="Shape_77_copy_16" data-name="Shape 77 copy 16" class="cls-1" d="M663,358a16.723,16.723,0,0,0-2.1-.009c-1.944.045-3.194,0.049-3.9,0.009v-7a1.743,1.743,0,0,1,2-2h1a1.743,1.743,0,0,1,2,2v2c0.474,0.064.343-.073,1,0,0.266,0.029,0,.279,0,0v-2a2.726,2.726,0,0,0-3-3h-1.142c-1.72-.125-2.715,1.562-2.858,3,0.088,0.009,0,9.338,0,7h0a1.891,1.891,0,0,0-2,1.689v4.461a1.823,1.823,0,0,0,1.775,1.85h7.448A1.823,1.823,0,0,0,665,364.15v-4.461A2.018,2.018,0,0,0,663,358Zm1.05,6.15a0.827,0.827,0,0,1-.8.836H655.8a0.827,0.827,0,0,1-.8-0.836l0-4.15a1.164,1.164,0,0,1,.8-1.147h7.448A1.129,1.129,0,0,1,664,360Z" transform="translate(-654 -348)"/>
+</svg>
diff --git a/assets/icons/upload.svg b/assets/icons/upload.svg
new file mode 100644
index 0000000..72e64ff
--- /dev/null
+++ b/assets/icons/upload.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 15 11"><title>upload</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><polygon points="14 6 14 10 1 10 1 6 0 6 0 11 15 11 15 6 14 6"/><polygon points="3.71 3.79 4.42 4.5 7 1.91 7 7.58 8 7.58 8 1.91 10.58 4.5 11.29 3.79 7.5 0 3.71 3.79"/></g></g></svg> \ No newline at end of file
diff --git a/assets/icons/user.svg b/assets/icons/user.svg
new file mode 100644
index 0000000..3363f57
--- /dev/null
+++ b/assets/icons/user.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="user_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 18 20" style="enable-background:new 0 0 18 20;" xml:space="preserve">
+
+<g>
+ <ellipse class="st1" cx="9" cy="6" rx="5.5" ry="5.5"/>
+ <path class="st1" d="M0.7,20c0-4.6,3.7-8.3,8.3-8.3s8.3,3.7,8.3,8.3"/>
+</g>
+</svg>
diff --git a/assets/icons/vendor.svg b/assets/icons/vendor.svg
new file mode 100644
index 0000000..a3b8f5f
--- /dev/null
+++ b/assets/icons/vendor.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 53 47" id="vendor_icon"><title>vendor</title><g id="Layer_2" data-name="Layer 2"><g id="vlm_icon" data-name="vlm icon"><path d="M49,7,38.5,7V5.92A5.92,5.92,0,0,0,32.58,0H20.42A5.92,5.92,0,0,0,14.5,5.92V7.15L4,7.2a3.8,3.8,0,0,0-4,3.5V43.5C0,45.4,2,47,4.2,47L49,46.8a3.8,3.8,0,0,0,4-3.5V10.5A3.8,3.8,0,0,0,49,7ZM16.5,5.92A3.92,3.92,0,0,1,20.42,2H32.58A3.92,3.92,0,0,1,36.5,5.92V7.06l-20,.09ZM2,10.8A1.9,1.9,0,0,1,4,9l45-.2a1.9,1.9,0,0,1,2,1.8v8.87L32.94,24.18a6.49,6.49,0,0,0-12.89,0L2,19.51V10.8ZM31,25a4.5,4.5,0,1,1-4.5-4.5A4.5,4.5,0,0,1,31,25ZM49,45,4,45.2A1.9,1.9,0,0,1,2,43.4V21.57l18.13,4.73a6.5,6.5,0,0,0,12.74,0L51,21.53V43.21A1.9,1.9,0,0,1,49,45Z"/></g></g></svg>
diff --git a/assets/icons/versionControllerCommit.svg b/assets/icons/versionControllerCommit.svg
new file mode 100644
index 0000000..5847c69
--- /dev/null
+++ b/assets/icons/versionControllerCommit.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" id="version-controller-commit_icon" viewBox="0 0 28 19.24"><title>Asset 5</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path d="M27.5,18.24c-7.13,0-12.5-5.8-12.5-13.5V2.41l2.54,2.54.71-.71L14,0,9.76,4.24l.71.71L13,2.41V4.74c0,7.7-5.37,13.5-12.5,13.5H0v1H.5C8.2,19.24,14,13,14,4.74c0,8.27,5.8,14.5,13.5,14.5H28v-1Z"/></g></g></svg> \ No newline at end of file
diff --git a/assets/icons/versionControllerLockClosed.svg b/assets/icons/versionControllerLockClosed.svg
new file mode 100644
index 0000000..73aae7d
--- /dev/null
+++ b/assets/icons/versionControllerLockClosed.svg
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="version-controller-lock-closed_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
+ x="0px" y="0px" viewBox="0 0 22.1 24" style="enable-background:new 0 0 22.1 24;" xml:space="preserve">
+<g>
+ <path d="M16.1,8h-1V5c0-2.2-1.8-4-4-4s-4,1.8-4,4v3h-1V5c0-2.8,2.2-5,5-5s5,2.2,5,5V8z"/>
+ <g id="Rounded_Rectangle_1267">
+ <path d="M19.3,24.1H2.7c-1.5,0-2.8-1.3-2.8-2.8V10.7C0,9.2,1.3,8,2.7,8h16.6c1.5,0,2.8,1.3,2.8,2.8v10.5
+ C22.1,22.8,20.8,24.1,19.3,24.1z M2.7,9C1.8,9,1,9.8,0.9,10.7v10.6c0,1,0.8,1.8,1.8,1.8h16.6c1,0,1.8-0.8,1.8-1.8V10.8
+ c0-1-0.8-1.8-1.8-1.8H2.7z"/>
+ </g>
+ <g>
+ <path d="M10.9,18.6c-1.8,0-3.3-1.5-3.3-3.3S9.1,12,10.9,12s3.3,1.5,3.3,3.3S12.7,18.6,10.9,18.6z M10.9,13c-1.3,0-2.3,1-2.3,2.3
+ s1,2.3,2.3,2.3s2.3-1,2.3-2.3S12.2,13,10.9,13z"/>
+ </g>
+</g>
+</svg>
diff --git a/assets/icons/versionControllerLockOpen.svg b/assets/icons/versionControllerLockOpen.svg
new file mode 100644
index 0000000..52e0b8b
--- /dev/null
+++ b/assets/icons/versionControllerLockOpen.svg
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="version-controller-lock-open_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 25 24.1" style="enable-background:new 0 0 25 24.1;" xml:space="preserve">
+<g>
+ <path d="M10,8H9V5c0-2.2-1.8-4-4-4S1,2.8,1,5v3H0V5c0-2.8,2.2-5,5-5s5,2.2,5,5V8z"/>
+ <g id="Rounded_Rectangle_1267_1_">
+ <path d="M22.2,24.1H5.6c-1.5,0-2.8-1.3-2.8-2.8V10.7C2.9,9.2,4.2,8,5.6,8h16.6c1.5,0,2.8,1.3,2.8,2.8v10.5
+ C25,22.8,23.7,24.1,22.2,24.1z M5.6,9c-0.9,0-1.7,0.8-1.8,1.7v10.6c0,1,0.8,1.8,1.8,1.8h16.6c1,0,1.8-0.8,1.8-1.8V10.8
+ c0-1-0.8-1.8-1.8-1.8H5.6z"/>
+ </g>
+ <g>
+ <path d="M13.8,18.6c-1.8,0-3.3-1.5-3.3-3.3S12,12,13.8,12s3.3,1.5,3.3,3.3S15.6,18.6,13.8,18.6z M13.8,13c-1.3,0-2.3,1-2.3,2.3
+ s1,2.3,2.3,2.3s2.3-1,2.3-2.3S15.1,13,13.8,13z"/>
+ </g>
+</g>
+</svg>
diff --git a/assets/icons/versionControllerPermissions.svg b/assets/icons/versionControllerPermissions.svg
new file mode 100644
index 0000000..91ea9f4
--- /dev/null
+++ b/assets/icons/versionControllerPermissions.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" id="version-controller-permissions_icon" viewBox="0 0 31.11 20"><title>Asset 2</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path d="M24.48,11.67a6,6,0,1,0-3.84,0,8.57,8.57,0,0,0-5.08,3.43,8.57,8.57,0,0,0-5.08-3.43A6,6,0,1,0,2.59,6a6,6,0,0,0,4,5.67A8.56,8.56,0,0,0,0,20H1a7.55,7.55,0,0,1,15.11,0h1a8.49,8.49,0,0,0-1-4,7.55,7.55,0,0,1,14,4h1A8.56,8.56,0,0,0,24.48,11.67ZM3.59,6a5,5,0,1,1,5,5A5,5,0,0,1,3.59,6Zm14,0a5,5,0,1,1,5,5A5,5,0,0,1,17.59,6Z"/></g></g></svg> \ No newline at end of file
diff --git a/assets/icons/versionControllerRevert.svg b/assets/icons/versionControllerRevert.svg
new file mode 100644
index 0000000..f9f02f9
--- /dev/null
+++ b/assets/icons/versionControllerRevert.svg
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1"
+ id="version-controller-revert_icon" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 89 87"
+ style="enable-background:new 0 0 89 87;" xml:space="preserve">
+<g transform="translate(0,-952.36218)">
+ <path d="M45.8,952.4c-1,0-2,1-1.9,2.1c0,1,1,2,2.1,1.9c21.6,0,39,17.4,39,39s-17.4,39-39,39s-39-17.4-39-39
+ c0-9.6,4.5-19.4,10.5-26.5l1.5,11.8c0.1,1,1.2,1.9,2.3,1.8s1.9-1.2,1.8-2.3l-2-16c-0.1-1.1-1.2-1.9-2.3-1.8l-16.1,3
+ c-1.1,0.1-2,1.3-1.8,2.4c0.2,1.1,1.5,1.9,2.5,1.5l10.1-1.9C7.3,975,3,985.1,3,995.4c0,23.7,19.3,43,43,43s43-19.3,43-43
+ c0-23.7-19.3-43-43-43C45.9,952.4,45.9,952.4,45.8,952.4z M42.8,968.1c-1,0.1-1.8,1-1.8,2v28.2c0,1,1,2,2,2h21.8c1.1,0,2-0.9,2-2
+ s-1-2-2-2H45v-26.2C45,969,43.9,968,42.8,968.1z"/>
+</g>
+</svg>
diff --git a/assets/icons/versionControllerSave.svg b/assets/icons/versionControllerSave.svg
new file mode 100644
index 0000000..4a05425
--- /dev/null
+++ b/assets/icons/versionControllerSave.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="version-controller-save_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
+ y="0px" viewBox="0 0 22 21" style="enable-background:new 0 0 22 21;" xml:space="preserve">
+<g>
+ <path d="M22,21H0V0h17.7L22,4.3V21z M1,20h20V4.7L17.3,1H1V20z"/>
+ <polygon points="17,8 4,8 4,0.5 5,0.5 5,7 16,7 16,0.5 17,0.5 "/>
+ <polygon points="17,20.5 16,20.5 16,14 5,14 5,20.5 4,20.5 4,13 17,13 "/>
+</g>
+</svg>
diff --git a/assets/icons/versionControllerSubmit.svg b/assets/icons/versionControllerSubmit.svg
new file mode 100644
index 0000000..9909ab3
--- /dev/null
+++ b/assets/icons/versionControllerSubmit.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="version-controller-submit_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
+ y="0px" viewBox="0 0 21 21" style="enable-background:new 0 0 21 21;" xml:space="preserve">
+<g>
+ <path d="M10.5,21C4.7,21,0,16.3,0,10.5C0,4.7,4.7,0,10.5,0C16.3,0,21,4.7,21,10.5C21,16.3,16.3,21,10.5,21z M10.5,1
+ C5.3,1,1,5.3,1,10.5S5.3,20,10.5,20s9.5-4.3,9.5-9.5S15.7,1,10.5,1z"/>
+ <path id="Shape_637_copy" d="M9.1,12.9L5.8,9.6l-0.7,0.6l4,4l6.7-6.7l-0.7-0.6L9.1,12.9z"/>
+</g>
+</svg>
diff --git a/assets/icons/versionControllerSync.svg b/assets/icons/versionControllerSync.svg
new file mode 100644
index 0000000..dfd42d3
--- /dev/null
+++ b/assets/icons/versionControllerSync.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" id="version-controller-sync_icon" viewBox="0 0 27.11 20"><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path d="M13.72,19a9,9,0,0,1-9-9,8.9,8.9,0,0,1,.61-3.23L8.4,9.93l.71-.71L4.55,4.67,0,9.22l.71.71L4.55,6.08h0a9.82,9.82,0,0,0-.84,4A10,10,0,0,0,17.86,19.1l-.72-.72A9,9,0,0,1,13.72,19Z"/><path d="M26.41,10.07l-3.85,3.85h0a9.82,9.82,0,0,0,.84-4A10,10,0,0,0,9.25.9l.72.72A9,9,0,0,1,22.44,10a8.9,8.9,0,0,1-.61,3.23l-3.12-3.12-.71.71,4.55,4.55,4.55-4.55Z"/></g></g></svg> \ No newline at end of file
diff --git a/assets/icons/versionControllerUndo.svg b/assets/icons/versionControllerUndo.svg
new file mode 100644
index 0000000..8745f54
--- /dev/null
+++ b/assets/icons/versionControllerUndo.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" id="version-controller-undo_icon" viewBox="0 0 20 20"><title>Asset 3</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path d="M10,0A10,10,0,0,0,1,5.66V1H0V7H6V6H1.9a9,9,0,1,1-.72,6H.2A10,10,0,1,0,10,0Z"/></g></g></svg> \ No newline at end of file
diff --git a/assets/icons/viewModule.svg b/assets/icons/viewModule.svg
new file mode 100644
index 0000000..e121d40
--- /dev/null
+++ b/assets/icons/viewModule.svg
@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20.37 20.39">
+ <title>viewModule</title>
+ <g>
+ <path class="a" d="M26.95,19.49H21.06a1.57,1.57,0,0,0-1.57,1.57V27a1.57,1.57,0,0,0,1.57,1.57h5.89A1.57,1.57,0,0,0,28.52,27V21.06A1.57,1.57,0,0,0,26.95,19.49ZM27.52,27a.57.57,0,0,1-.57.57H21.06a.57.57,0,0,1-.57-.57V21.06a.57.57,0,0,1,.57-.57h5.89a.57.57,0,0,1,.57.57Z" transform="translate(-8.15 -8.14)"/>
+ <path class="a" d="M26.95,8.14H21.06a1.57,1.57,0,0,0-1.57,1.57V15.6a1.57,1.57,0,0,0,1.57,1.57h5.89a1.57,1.57,0,0,0,1.57-1.57V9.71A1.57,1.57,0,0,0,26.95,8.14Zm.57,7.46a.57.57,0,0,1-.57.57H21.06a.57.57,0,0,1-.57-.57V9.71a.57.57,0,0,1,.57-.57h5.89a.57.57,0,0,1,.57.57Z" transform="translate(-8.15 -8.14)"/>
+ <path class="a" d="M15.61,19.49H9.72a1.57,1.57,0,0,0-1.57,1.57V27a1.57,1.57,0,0,0,1.57,1.57h5.89A1.57,1.57,0,0,0,17.18,27V21.06A1.57,1.57,0,0,0,15.61,19.49ZM16.18,27a.57.57,0,0,1-.57.57H9.72A.57.57,0,0,1,9.15,27V21.06a.57.57,0,0,1,.57-.57h5.89a.57.57,0,0,1,.57.57Z" transform="translate(-8.15 -8.14)"/>
+ <path class="a" d="M15.61,8.14H9.72A1.57,1.57,0,0,0,8.15,9.71V15.6a1.57,1.57,0,0,0,1.57,1.57h5.89a1.57,1.57,0,0,0,1.57-1.57V9.71A1.57,1.57,0,0,0,15.61,8.14Zm.57,7.46a.57.57,0,0,1-.57.57H9.72a.57.57,0,0,1-.57-.57V9.71a.57.57,0,0,1,.57-.57h5.89a.57.57,0,0,1,.57.57Z" transform="translate(-8.15 -8.14)"/>
+ </g>
+</svg>
diff --git a/assets/icons/vlm.svg b/assets/icons/vlm.svg
new file mode 100644
index 0000000..79b4625
--- /dev/null
+++ b/assets/icons/vlm.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 45 53"><title>vlm_new_icon</title><g id="Layer_2" data-name="Layer 2"><g id="vlm_icon" data-name="vlm icon"><path d="M41,2a2,2,0,0,1,2,2l.19,45a2,2,0,0,1-2,2H4a2,2,0,0,1-2-2L1.81,4a2,2,0,0,1,2-2H41m-.15-2H4A4.2,4.2,0,0,0,0,4.24L.19,49a4,4,0,0,0,4,4H41a4,4,0,0,0,4-4L44.81,4a4,4,0,0,0-4-4Z"/><rect x="14" y="11" width="17" height="2"/><rect x="14" y="18" width="10" height="2"/><polygon points="20.56 38.85 13.87 33.14 15.16 31.62 20.39 36.08 29.08 26.63 30.55 27.98 20.56 38.85"/></g></g></svg> \ No newline at end of file
diff --git a/assets/icons/vsp.svg b/assets/icons/vsp.svg
new file mode 100644
index 0000000..344755c
--- /dev/null
+++ b/assets/icons/vsp.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" 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 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"/></g></g></svg>
diff --git a/assets/icons/zip.svg b/assets/icons/zip.svg
new file mode 100644
index 0000000..51ce7fa
--- /dev/null
+++ b/assets/icons/zip.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 29 23"><title>zip</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path d="M9.47,1l2.83,2.72L12.6,4H28V22H1V1H9.47m.4-1H0V23H29V3H13L9.88,0Z"/><path d="M11.65,16.61H6.25V15.9l4.17-6.32h-4V8.76h5.15v.71L7.37,15.78h4.29Z"/><path d="M14,16.61V8.76h.91v7.85Z"/><path d="M22.87,11a2.2,2.2,0,0,1-.81,1.83,3.68,3.68,0,0,1-2.33.64H18.8v3.09h-.91V8.76h2Q22.87,8.76,22.87,11ZM18.8,12.74h.82a3,3,0,0,0,1.76-.39,1.44,1.44,0,0,0,.54-1.26,1.36,1.36,0,0,0-.51-1.16,2.66,2.66,0,0,0-1.59-.38h-1Z"/></g></g></svg> \ No newline at end of file
diff --git a/assets/images/empty.txt b/assets/images/empty.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/assets/images/empty.txt
diff --git a/assets/images/illustration.png b/assets/images/illustration.png
new file mode 100644
index 0000000..c0ff99a
--- /dev/null
+++ b/assets/images/illustration.png
Binary files differ
diff --git a/assets/images/logo_onap.png b/assets/images/logo_onap.png
new file mode 100644
index 0000000..c6f6857
--- /dev/null
+++ b/assets/images/logo_onap.png
Binary files differ
diff --git a/assets/images/logo_onap_2017.png b/assets/images/logo_onap_2017.png
new file mode 100644
index 0000000..c6f6857
--- /dev/null
+++ b/assets/images/logo_onap_2017.png
Binary files differ
diff --git a/assets/sdc-icons/README.md b/assets/sdc-icons/README.md
new file mode 100644
index 0000000..dc3e798
--- /dev/null
+++ b/assets/sdc-icons/README.md
@@ -0,0 +1,9 @@
+components folder contain icon that are not part of sdc-icon component.
+-Icon naming:
+------------------
+-
+-<name>-<type>-<o>
+-
+-name = if contains multiple words, use "_"
+-type = circle/square/triangle
+-o = outline (for all icons that have white background)
diff --git a/assets/sdc-icons/alert-triangle-o.svg b/assets/sdc-icons/alert-triangle-o.svg
new file mode 100644
index 0000000..c1d8d0a
--- /dev/null
+++ b/assets/sdc-icons/alert-triangle-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="alert-a" d="M20.5815,18.7997 C20.3815,18.9997 20.0815,19.0997 19.8815,19.0997 L2.8815,19.0997 C2.6815,19.0997 2.5815,19.0997 2.3815,18.9997 C1.8815,18.6997 1.7815,18.0997 1.9815,17.5997 L10.4815,3.4997 C10.5815,3.4007 10.6815,3.1997 10.7815,3.1997 C11.2815,2.9007 11.8815,3.0997 12.1815,3.4997 L20.6825,17.5997 C20.7815,17.6997 20.7815,17.9007 20.7815,18.0997 C20.8815,18.4007 20.6825,18.5997 20.5815,18.7997 M22.3815,16.5997 L13.9815,2.4007 C13.5815,1.6997 12.8815,1.1997 12.0815,0.9997 C11.2815,0.7997 10.4815,0.9007 9.7815,1.2997 C9.3815,1.4997 8.9815,1.9007 8.7815,2.2997 L0.3815,16.5997 C-0.4185,17.9997 0.0815,19.9007 1.4815,20.6997 C1.8815,20.9997 2.3815,21.0997 2.8815,21.0997 L19.8815,21.0997 C20.6825,21.0997 21.4815,20.7997 21.9815,20.1997 C22.5815,19.5997 22.8815,18.9007 22.8815,18.0997 C22.7815,17.5997 22.6825,16.9997 22.3815,16.5997 M11,7 C10.4,7 10,7.4 10,8 L10,12 C10,12.601 10.4,13 11,13 C11.6,13 12,12.601 12,12 L12,8 C12,7.4 11.6,7 11,7 M10.3,15.3 C10.1,15.499 10,15.699 10,15.999 C10,16.3 10.1,16.499 10.3,16.699 C10.5,16.9 10.7,16.999 11,16.999 C11.3,16.999 11.5,16.9 11.7,16.699 C11.9,16.499 12,16.199 12,15.999 C12,15.8 11.9,15.499 11.7,15.3 C11.3,14.9 10.7,14.9 10.3,15.3"/>
+</svg>
diff --git a/assets/sdc-icons/alert-triangle.svg b/assets/sdc-icons/alert-triangle.svg
new file mode 100644
index 0000000..ed3f6f8
--- /dev/null
+++ b/assets/sdc-icons/alert-triangle.svg
@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <g fill-rule="evenodd" transform="translate(1 1)">
+ <path id="alert-copy-a" d="M22.3815,16.5997 L13.9815,2.4007 C13.5815,1.6997 12.8815,1.1997 12.0815,0.9997 C11.2815,0.7997 10.4815,0.9007 9.7815,1.2997 C9.3815,1.4997 8.9815,1.9007 8.7815,2.2997 L0.3815,16.5997 C-0.4185,17.9997 0.0815,19.9007 1.4815,20.6997 C1.8815,20.9997 2.3815,21.0997 2.8815,21.0997 L19.8815,21.0997 C20.6825,21.0997 21.4815,20.7997 21.9815,20.1997 C22.5815,19.5997 22.8815,18.9007 22.8815,18.0997 C22.7815,17.5997 22.6825,16.9997 22.3815,16.5997 M11,7 C10.4,7 10,7.4 10,8 L10,12 C10,12.601 10.4,13 11,13 C11.6,13 12,12.601 12,12 L12,8 C12,7.4 11.6,7 11,7 M10.3,15.3 C10.1,15.499 10,15.699 10,15.999 C10,16.3 10.1,16.499 10.3,16.699 C10.5,16.9 10.7,16.999 11,16.999 C11.3,16.999 11.5,16.9 11.7,16.699 C11.9,16.499 12,16.199 12,15.999 C12,15.8 11.9,15.499 11.7,15.3 C11.3,14.9 10.7,14.9 10.3,15.3"/>
+ </g>
+</svg>
diff --git a/assets/sdc-icons/api-o.svg b/assets/sdc-icons/api-o.svg
new file mode 100644
index 0000000..169630a
--- /dev/null
+++ b/assets/sdc-icons/api-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="api-a" d="M18,17 C18,17.6 17.6,18 17,18 L3,18 C2.4,18 2,17.6 2,17 L2,3 C2,2.4 2.4,2 3,2 L17,2 C17.6,2 18,2.4 18,3 L18,17 Z M17,0 L3,0 C1.3,0 0,1.3 0,3 L0,17 C0,18.7 1.3,20 3,20 L17,20 C18.7,20 20,18.7 20,17 L20,3 C20,1.3 18.7,0 17,0 Z M16.707,9.293 L12.707,5.293 C12.316,4.902 11.684,4.902 11.293,5.293 C10.902,5.684 10.902,6.316 11.293,6.707 L14.586,10 L11.293,13.293 C10.902,13.684 10.902,14.316 11.293,14.707 C11.488,14.902 11.744,15 12,15 C12.256,15 12.512,14.902 12.707,14.707 L16.707,10.707 C17.098,10.316 17.098,9.684 16.707,9.293 M3.293,9.293 L7.293,5.293 C7.684,4.902 8.316,4.902 8.707,5.293 C9.098,5.684 9.098,6.316 8.707,6.707 L5.414,10 L8.707,13.293 C9.098,13.684 9.098,14.316 8.707,14.707 C8.512,14.902 8.256,15 8,15 C7.744,15 7.488,14.902 7.293,14.707 L3.293,10.707 C2.902,10.316 2.902,9.684 3.293,9.293"/>
+</svg>
diff --git a/assets/sdc-icons/arrow2-right-child.svg b/assets/sdc-icons/arrow2-right-child.svg
new file mode 100644
index 0000000..0123a82
--- /dev/null
+++ b/assets/sdc-icons/arrow2-right-child.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ <path d="M22.9435415,14.3344739 C23.0188195,14.1839179 23.0188195,13.9580838 22.9435415,13.7322498 C22.8682635,13.6569718 22.8682635,13.5816938 22.7929855,13.5064157 L19.0290847,9.74251497 C18.7279726,9.44140291 18.2763045,9.44140291 17.9751925,9.74251497 C17.6740804,10.043627 17.6740804,10.4952951 17.9751925,10.7964072 L20.459367,13.2805817 L4.76390077,13.2805817 C3.48417451,13.2805817 2.50556031,12.3019675 2.50556031,11.0222412 L2.50556031,5.75278015 C2.50556031,5.30111206 2.20444825,5 1.75278015,5 C1.30111206,5 1,5.30111206 1,5.75278015 L1,11.0222412 C1,13.1300257 2.65611634,14.786142 4.76390077,14.786142 L20.459367,14.786142 L17.9751925,17.2703165 C17.6740804,17.5714286 17.6740804,18.0230967 17.9751925,18.3242087 C18.1257485,18.4747648 18.3515825,18.5500428 18.5021386,18.5500428 C18.6526946,18.5500428 18.8785287,18.4747648 19.0290847,18.3242087 L22.7929855,14.560308 C22.8682635,14.4850299 22.9435415,14.4097519 22.9435415,14.3344739 Z"/>
+</svg>
diff --git a/assets/sdc-icons/arrow2-right.svg b/assets/sdc-icons/arrow2-right.svg
new file mode 100644
index 0000000..b8b808a
--- /dev/null
+++ b/assets/sdc-icons/arrow2-right.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ <path d="M22.9435415,14.3344739 C23.0188195,14.1839179 23.0188195,13.9580838 22.9435415,13.7322498 C22.8682635,13.6569718 22.8682635,13.5816938 22.7929855,13.5064157 L19.0290847,9.74251497 C18.7279726,9.44140291 18.2763045,9.44140291 17.9751925,9.74251497 C17.6740804,10.043627 17.6740804,10.4952951 17.9751925,10.7964072 L20.459367,13.2805817 L2.06347656,13.2805817 C1.51468328,13.2805817 1.37585449,14.560308 2.06347656,14.786142 L20.459367,14.786142 L17.9751925,17.2703165 C17.6740804,17.5714286 17.6740804,18.0230967 17.9751925,18.3242087 C18.1257485,18.4747648 18.3515825,18.5500428 18.5021386,18.5500428 C18.6526946,18.5500428 18.8785287,18.4747648 19.0290847,18.3242087 L22.7929855,14.560308 C22.8682635,14.4850299 22.9435415,14.4097519 22.9435415,14.3344739 Z"/>
+</svg>
diff --git a/assets/sdc-icons/arrow3-down-o.svg b/assets/sdc-icons/arrow3-down-o.svg
new file mode 100644
index 0000000..401a7f8
--- /dev/null
+++ b/assets/sdc-icons/arrow3-down-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="filterdown-a" d="M11.29925,18.7 C11.40025,18.8 11.49925,18.9 11.59925,18.9 C11.69925,19 11.90025,19 11.99925,19 C12.09925,19 12.29925,19 12.40025,18.9 C12.49925,18.8 12.59925,18.8 12.69925,18.7 L16.69925,14.7 C17.09925,14.3 17.09925,13.7 16.69925,13.3 C16.29925,12.9 15.69925,12.9 15.29925,13.3 L12.99925,15.599 L12.99925,4 C12.99925,3.4 12.59925,3 11.99925,3 C11.40025,3 10.99925,3.4 10.99925,4 L10.99925,15.599 L8.69925,13.3 C8.29925,12.9 7.69925,12.9 7.29925,13.3 C6.90025,13.7 6.90025,14.3 7.29925,14.7 L11.29925,18.7 Z"/>
+</svg>
diff --git a/assets/sdc-icons/arrow3-up-o.svg b/assets/sdc-icons/arrow3-up-o.svg
new file mode 100644
index 0000000..331634f
--- /dev/null
+++ b/assets/sdc-icons/arrow3-up-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="filterup-a" d="M11.29925,18.7 C11.40025,18.8 11.49925,18.9 11.59925,18.9 C11.69925,19 11.90025,19 11.99925,19 C12.09925,19 12.29925,19 12.40025,18.9 C12.49925,18.8 12.59925,18.8 12.69925,18.7 L16.69925,14.7 C17.09925,14.3 17.09925,13.7 16.69925,13.3 C16.29925,12.9 15.69925,12.9 15.29925,13.3 L12.99925,15.599 L12.99925,4 C12.99925,3.4 12.59925,3 11.99925,3 C11.40025,3 10.99925,3.4 10.99925,4 L10.99925,15.599 L8.69925,13.3 C8.29925,12.9 7.69925,12.9 7.29925,13.3 C6.90025,13.7 6.90025,14.3 7.29925,14.7 L11.29925,18.7 Z"/>
+</svg>
diff --git a/assets/sdc-icons/attachment.svg b/assets/sdc-icons/attachment.svg
new file mode 100644
index 0000000..a1d7768
--- /dev/null
+++ b/assets/sdc-icons/attachment.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="attach-a" d="M20.67425,9.292 C20.28125,8.92 19.69125,8.92 19.29825,9.292 L10.25125,17.841 C8.28425,19.699 5.23625,19.699 3.27025,17.841 C1.30325,15.982 1.30325,13.102 3.27025,11.243 L12.31725,2.694 C13.39825,1.673 15.36425,1.673 16.44625,2.694 C17.62625,3.81 17.62625,5.575 16.44625,6.598 L7.40025,15.146 C7.00625,15.518 6.41625,15.518 6.02325,15.146 C5.92525,15.053 5.82625,14.867 5.82625,14.589 C5.82625,14.31 5.92525,14.124 6.12125,13.938 L14.48025,6.04 C14.87325,5.668 14.87325,5.11 14.48025,4.739 C14.08625,4.367 13.49625,4.367 13.10325,4.739 L4.74425,12.637 C4.15425,13.102 3.86025,13.845 3.86025,14.589 C3.86025,15.332 4.15425,16.075 4.74425,16.54 C5.92525,17.655 7.79325,17.655 8.87425,16.54 L17.92125,7.991 C19.88825,6.133 19.88825,3.252 17.92125,1.394 C17.03625,0.558 15.75825,0 14.48025,0 C13.20125,0 11.92325,0.465 11.03825,1.394 L1.99125,9.942 C-0.66375,12.451 -0.66375,16.633 1.99125,19.142 C3.36825,20.442 5.13825,21 6.90825,21 C8.67825,21 10.44725,20.35 11.82425,19.142 L20.87125,10.593 C21.06825,10.314 21.06825,9.664 20.67425,9.292"/>
+</svg>
diff --git a/assets/sdc-icons/bedge.svg b/assets/sdc-icons/bedge.svg
new file mode 100644
index 0000000..f43ac9b
--- /dev/null
+++ b/assets/sdc-icons/bedge.svg
@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 30 20">
+ <g fill-rule="evenodd">
+ <rect id="bedge-a" width="30" height="20" rx="8"/>
+ </g>
+</svg>
diff --git a/assets/sdc-icons/browse.svg b/assets/sdc-icons/browse.svg
new file mode 100644
index 0000000..c63620f
--- /dev/null
+++ b/assets/sdc-icons/browse.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="browse-a" d="M1.55555556,3.11111111 C0.696445945,3.11111111 0,2.41466517 0,1.55555556 C0,0.696445945 0.696445945,0 1.55555556,0 C2.41466517,0 3.11111111,0.696445945 3.11111111,1.55555556 C3.11111111,2.41466517 2.41466517,3.11111111 1.55555556,3.11111111 Z M12.4444444,3.11111111 C11.5853348,3.11111111 10.8888889,2.41466517 10.8888889,1.55555556 C10.8888889,0.696445945 11.5853348,0 12.4444444,0 C13.3035541,0 14,0.696445945 14,1.55555556 C14,2.41466517 13.3035541,3.11111111 12.4444444,3.11111111 Z M7,3.11111111 C6.14089039,3.11111111 5.44444444,2.41466517 5.44444444,1.55555556 C5.44444444,0.696445945 6.14089039,0 7,0 C7.85910961,0 8.55555556,0.696445945 8.55555556,1.55555556 C8.55555556,2.41466517 7.85910961,3.11111111 7,3.11111111 Z"/>
+</svg>
diff --git a/assets/sdc-icons/calendar-o.svg b/assets/sdc-icons/calendar-o.svg
new file mode 100644
index 0000000..93f8719
--- /dev/null
+++ b/assets/sdc-icons/calendar-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="calendar-a" d="M17,20 L3,20 C2.4,20 2,19.6 2,19 L2,10 L18,10 L18,19 C18,19.6 17.6,20 17,20 M3,4 L5,4 L5,5 C5,5.6 5.4,6 6,6 C6.6,6 7,5.6 7,5 L7,4 L13,4 L13,5 C13,5.6 13.4,6 14,6 C14.6,6 15,5.6 15,5 L15,4 L17,4 C17.6,4 18,4.4 18,5 L18,8 L2,8 L2,5 C2,4.4 2.4,4 3,4 M17,2 L15,2 L15,1 C15,0.4 14.6,0 14,0 C13.4,0 13,0.4 13,1 L13,2 L7,2 L7,1 C7,0.4 6.6,0 6,0 C5.4,0 5,0.4 5,1 L5,2 L3,2 C1.3,2 0,3.3 0,5 L0,19 C0,20.7 1.3,22 3,22 L17,22 C18.7,22 20,20.7 20,19 L20,5 C20,3.3 18.7,2 17,2"/>
+</svg>
diff --git a/assets/sdc-icons/camera-o.svg b/assets/sdc-icons/camera-o.svg
new file mode 100644
index 0000000..86f1f13
--- /dev/null
+++ b/assets/sdc-icons/camera-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="camera-a" d="M22,17 C22,17.6 21.6,18 21,18 L3,18 C2.4,18 2,17.6 2,17 L2,6 C2,5.4 2.4,5 3,5 L7,5 C7.3,5 7.6,4.8 7.8,4.6 L9.5,2 L14.4,2 L16.1,4.6 C16.4,4.8 16.7,5 17,5 L21,5 C21.6,5 22,5.4 22,6 L22,17 Z M21,3 L17.5,3 L15.8,0.4 C15.6,0.2 15.3,0 15,0 L9,0 C8.7,0 8.4,0.2 8.2,0.4 L6.5,3 L3,3 C1.3,3 0,4.3 0,6 L0,17 C0,18.7 1.3,20 3,20 L21,20 C22.7,20 24,18.7 24,17 L24,6 C24,4.3 22.7,3 21,3 Z M12,15 C10.3,15 9,13.7 9,12 C9,10.3 10.3,9 12,9 C13.7,9 15,10.3 15,12 C15,13.7 13.7,15 12,15 M12,7 C9.2,7 7,9.2 7,12 C7,14.8 9.2,17 12,17 C14.8,17 17,14.8 17,12 C17,9.2 14.8,7 12,7"/>
+</svg>
diff --git a/assets/sdc-icons/caret1-down-o.svg b/assets/sdc-icons/caret1-down-o.svg
new file mode 100644
index 0000000..724152a
--- /dev/null
+++ b/assets/sdc-icons/caret1-down-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 14 14">
+ <path id="chevron-a" d="M5.2998,6.7002 C5.4998,6.9002 5.7998,7.0002 5.9998,7.0002 C6.1998,7.0002 6.4998,6.9002 6.6998,6.7002 L11.6998,1.7002 C12.0998,1.3002 12.0998,0.7002 11.6998,0.3002 C11.2998,-0.0998 10.6998,-0.0998 10.2998,0.3002 L5.9998,4.6002 L1.6998,0.3002 C1.2998,-0.0998 0.6998,-0.0998 0.2998,0.3002 C-0.1002,0.7002 -0.1002,1.3002 0.2998,1.7002 L5.2998,6.7002 Z"/>
+</svg>
diff --git a/assets/sdc-icons/caret2-right-circle-o.svg b/assets/sdc-icons/caret2-right-circle-o.svg
new file mode 100644
index 0000000..2715dad
--- /dev/null
+++ b/assets/sdc-icons/caret2-right-circle-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ <path fill-rule="evenodd" d="M10.7522453,15.1960146 C10.5111563,15.4453129 10.5111563,15.8494423 10.7522453,16.0987406 C10.9933343,16.3480389 11.384156,16.3480389 11.625245,16.0987406 L15.1525166,12.451363 C15.3936056,12.2020647 15.3936056,11.7979353 15.1525166,11.548637 L11.625245,7.90125941 C11.384156,7.65196115 10.9933343,7.65196115 10.7522453,7.90125941 C10.5111563,8.15055767 10.5111563,8.55468711 10.7522453,8.80398537 L13.8447807,12.0018237 L10.7522453,15.1960146 Z M12,21 C7,21 3,17 3,12 C3,7 7,3 12,3 C17,3 21,7 21,12 C21,17 17,21 12,21 M12,1 C5.9,1 1,5.9 1,12 C1,18.1 5.9,23 12,23 C18.1,23 23,18.1 23,12 C23,5.9 18.1,1 12,1"/>
+</svg>
diff --git a/assets/sdc-icons/caret2-right-circle.svg b/assets/sdc-icons/caret2-right-circle.svg
new file mode 100644
index 0000000..e585c1d
--- /dev/null
+++ b/assets/sdc-icons/caret2-right-circle.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ <circle cx="10" cy="10" r="10" fill="#000"/>
+ <path fill="#FFF" d="M8.75224533,13.1960146 C8.51115632,13.4453129 8.51115632,13.8494423 8.75224533,14.0987406 C8.99333434,14.3480389 9.38415603,14.3480389 9.62524504,14.0987406 L13.1525166,10.451363 C13.3936056,10.2020647 13.3936056,9.79793528 13.1525166,9.54863702 L9.62524504,5.90125941 C9.38415603,5.65196115 8.99333434,5.65196115 8.75224533,5.90125941 C8.51115632,6.15055767 8.51115632,6.55468711 8.75224533,6.80398537 L11.8447807,10.0018237 L8.75224533,13.1960146 Z"/>
+</svg>
diff --git a/assets/sdc-icons/caret3-right.svg b/assets/sdc-icons/caret3-right.svg
new file mode 100644
index 0000000..1eefc47
--- /dev/null
+++ b/assets/sdc-icons/caret3-right.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 14 14">
+ <polygon fill-rule="evenodd" points="10 7 5 12 5 2"/>
+</svg>
diff --git a/assets/sdc-icons/close.svg b/assets/sdc-icons/close.svg
new file mode 100644
index 0000000..3c884d2
--- /dev/null
+++ b/assets/sdc-icons/close.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="close-a" d="M13.5996,12 L19.6576,5.942 C20.1146,5.485 20.1146,4.8 19.6576,4.343 C19.2006,3.886 18.5146,3.886 18.0576,4.343 L11.9996,10.4 L5.9426,4.343 C5.4856,3.886 4.7996,3.886 4.3426,4.343 C3.8856,4.8 3.8856,5.485 4.3426,5.942 L10.4006,12 L4.3426,18.058 C3.8856,18.515 3.8856,19.2 4.3426,19.657 C4.5716,19.886 4.7996,20 5.1426,20 C5.4856,20 5.7136,19.886 5.9426,19.657 L11.9996,13.6 L18.0576,19.657 C18.2866,19.886 18.6286,20 18.8576,20 C19.0856,20 19.4286,19.886 19.6576,19.657 C20.1146,19.2 20.1146,18.515 19.6576,18.058 L13.5996,12 Z"/>
+</svg>
diff --git a/assets/sdc-icons/commit-o.svg b/assets/sdc-icons/commit-o.svg
new file mode 100644
index 0000000..e71c18e
--- /dev/null
+++ b/assets/sdc-icons/commit-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="commit-a" d="M19.0020067,16.993 C11.0730067,16.966 11.0170067,6.35 11.0180067,5.894 L11.0180067,3.389 L13.3420067,5.67 C13.5370067,5.862 13.7890067,5.957 14.0420067,5.957 C14.3030067,5.957 14.5620067,5.856 14.7590067,5.656 C15.1450067,5.26 15.1390067,4.624 14.7430067,4.237 L10.7160067,0.286 C10.7080067,0.279 10.6970067,0.277 10.6890067,0.269 C10.6060067,0.192 10.5130067,0.124 10.4030067,0.078 C10.3980067,0.076 10.3950067,0.076 10.3910067,0.075 C10.3740067,0.068 10.3570067,0.068 10.3410067,0.062 C10.2440067,0.029 10.1470067,0.011 10.0480067,0.008 C10.0300067,0.008 10.0140067,0.002 9.99600669,0.002 C9.99200669,0.002 9.98800669,0 9.98400669,0 C9.95900669,0 9.93800669,0.013 9.91300669,0.014 C9.85200669,0.021 9.79300669,0.033 9.73300669,0.051 C9.52300669,0.106 9.34600669,0.221 9.21400669,0.386 L5.32800669,4.217 C4.93400669,4.606 4.92800669,5.241 5.31600669,5.637 C5.70400669,6.031 6.33800669,6.036 6.73200669,5.648 L8.98200669,3.429 L8.98200669,5.899 C8.98300669,6.35 8.92700669,16.966 0.998006685,16.993 C0.445006685,16.995 -0.00199331469,17.446 6.68530859e-06,18 C0.00200668531,18.553 0.450006685,19 1.00200669,19 L1.00600669,19 C3.51500669,18.991 5.62200669,18.142 7.27100669,16.477 C8.60300669,15.131 9.45200669,13.422 10.0000067,11.771 C10.5490067,13.422 11.3980067,15.131 12.7300067,16.477 C14.3780067,18.142 16.4850067,18.991 18.9940067,19 L18.9980067,19 C19.5500067,19 19.9980067,18.553 20.0000067,18 C20.0020067,17.446 19.5550067,16.995 19.0020067,16.993"/>
+</svg>
diff --git a/assets/sdc-icons/components/checkbox_checked.svg b/assets/sdc-icons/components/checkbox_checked.svg
new file mode 100644
index 0000000..520c7b6
--- /dev/null
+++ b/assets/sdc-icons/components/checkbox_checked.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14">
+ <path fill-rule="evenodd" d="M2,0 L12,-2.22044605e-16 C13.1045695,5.56104062e-16 14,0.8954305 14,2 L14,12 C14,13.1045695 13.1045695,14 12,14 L2,14 C0.8954305,14 8.94280938e-16,13.1045695 -2.22044605e-16,12 L-2.22044605e-16,2 C-3.57315355e-16,0.8954305 0.8954305,-1.91384796e-17 2,-2.22044605e-16 Z M3.85355339,7.54977605 C3.65829124,7.35451391 3.34170876,7.35451391 3.14644661,7.54977605 C2.95118446,7.7450382 2.95118446,8.06162069 3.14644661,8.25688283 L5.71469032,10.8251265 C5.93114093,11.0415771 6.28952386,11.0144698 6.47095446,10.7679244 L10.8653572,4.79638422 C11.0290275,4.57397322 10.9814087,4.26099251 10.7589977,4.09732224 C10.5365867,3.93365198 10.223606,3.98127076 10.0599357,4.20368177 L6.01038326,9.70660592 L3.85355339,7.54977605 Z"/>
+</svg>
diff --git a/assets/sdc-icons/components/checkbox_disabled.svg b/assets/sdc-icons/components/checkbox_disabled.svg
new file mode 100644
index 0000000..a032573
--- /dev/null
+++ b/assets/sdc-icons/components/checkbox_disabled.svg
@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14" height="14" viewBox="0 0 14 14">
+
+ <path id="disabled-a" d="M2,0 L12,-2.22044605e-16 C13.1045695,5.56104062e-16 14,0.8954305 14,2 L14,12 C14,13.1045695 13.1045695,14 12,14 L2,14 C0.8954305,14 8.94280938e-16,13.1045695 -2.22044605e-16,12 L-2.22044605e-16,2 C-3.57315355e-16,0.8954305 0.8954305,-1.91384796e-17 2,-2.22044605e-16 Z"/>
+
+ <g fill-rule="evenodd">
+ <use fill="#FFF" xlink:href="#disabled-a"/>
+ <path stroke="#000" d="M2,0.5 C1.17157288,0.5 0.5,1.17157288 0.5,2 L0.5,12 C0.5,12.8284271 1.17157288,13.5 2,13.5 L12,13.5 C12.8284271,13.5 13.5,12.8284271 13.5,12 L13.5,2 C13.5,1.17157288 12.8284271,0.5 12,0.5 L2,0.5 Z"/>
+
+</svg>
diff --git a/assets/sdc-icons/components/radio_checked .svg b/assets/sdc-icons/components/radio_checked .svg
new file mode 100644
index 0000000..534d05d
--- /dev/null
+++ b/assets/sdc-icons/components/radio_checked .svg
@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14">
+ <g fill-rule="evenodd">
+ <path fill-rule="nonzero" d="M7,14 C3.13400675,14 0,10.8659932 0,7 C0,3.13400675 3.13400675,0 7,0 C10.8659932,0 14,3.13400675 14,7 C14,10.8659932 10.8659932,14 7,14 Z M7,13.1764706 C10.4111705,13.1764706 13.1764706,10.4111705 13.1764706,7 C13.1764706,3.58882949 10.4111705,0.823529412 7,0.823529412 C3.58882949,0.823529412 0.823529412,3.58882949 0.823529412,7 C0.823529412,10.4111705 3.58882949,13.1764706 7,13.1764706 Z"/>
+ <circle cx="7" cy="7" r="4"/>
+
+</svg>
diff --git a/assets/sdc-icons/components/radio_disabled.svg b/assets/sdc-icons/components/radio_disabled.svg
new file mode 100644
index 0000000..0906f66
--- /dev/null
+++ b/assets/sdc-icons/components/radio_disabled.svg
@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14">
+ <g fill-rule="evenodd">
+ <path d="M7,14 C3.13400675,14 0,10.8659932 0,7 C0,3.13400675 3.13400675,0 7,0 C8.35813029,0 9.62592397,0.386776975 10.699241,1.0561909 C12.6811805,2.29230086 14,4.49213704 14,7 C14,10.8659932 10.8659932,14 7,14 Z"/>
+ <path fill="#FFF" d="M7,13 C10.3137085,13 13,10.3137085 13,7 C13,3.6862915 10.3137085,1 7,1 C3.6862915,1 1,3.6862915 1,7 C1,10.3137085 3.6862915,13 7,13 Z"/>
+
+</svg>
diff --git a/assets/sdc-icons/composition-o.svg b/assets/sdc-icons/composition-o.svg
new file mode 100644
index 0000000..5648cda
--- /dev/null
+++ b/assets/sdc-icons/composition-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="composition-a" d="M17,18.05 C16.448,18.05 16,17.602 16,17.05 C16,16.498 16.448,16.05 17,16.05 C17.552,16.05 18,16.498 18,17.05 C18,17.602 17.552,18.05 17,18.05 M3,18.05 C2.448,18.05 2,17.602 2,17.05 C2,16.498 2.448,16.05 3,16.05 C3.552,16.05 4,16.498 4,17.05 C4,17.602 3.552,18.05 3,18.05 M3,2.05 C3.552,2.05 4,2.498 4,3.05 C4,3.602 3.552,4.05 3,4.05 C2.448,4.05 2,3.602 2,3.05 C2,2.498 2.448,2.05 3,2.05 M10,9.05 C10.552,9.05 11,9.498 11,10.05 C11,10.602 10.552,11.05 10,11.05 C9.448,11.05 9,10.602 9,10.05 C9,9.498 9.448,9.05 10,9.05 M17,14.05 C15.695,14.05 14.597,14.888 14.184,16.05 L5.816,16.05 C5.515,15.201 4.849,14.535 4,14.234 L4,11.05 L7.184,11.05 C7.597,12.212 8.695,13.05 10,13.05 C11.657,13.05 13,11.707 13,10.05 C13,8.393 11.657,7.05 10,7.05 C8.695,7.05 7.597,7.888 7.184,9.05 L4,9.05 L4,5.866 C5.162,5.453 6,4.355 6,3.05 C6,1.393 4.657,0.05 3,0.05 C1.343,0.05 0,1.393 0,3.05 C0,4.355 0.838,5.453 2,5.866 L2,14.234 C0.838,14.647 0,15.745 0,17.05 C0,18.707 1.343,20.05 3,20.05 C4.305,20.05 5.403,19.212 5.816,18.05 L14.184,18.05 C14.597,19.212 15.695,20.05 17,20.05 C18.657,20.05 20,18.707 20,17.05 C20,15.393 18.657,14.05 17,14.05"/>
+</svg>
diff --git a/assets/sdc-icons/copy-o.svg b/assets/sdc-icons/copy-o.svg
new file mode 100644
index 0000000..eeee9aa
--- /dev/null
+++ b/assets/sdc-icons/copy-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="copy-a" d="M2,19 C2,19.6 2.4,20 3,20 L12,20 C12.6,20 13,19.6 13,19 L13,10 C13,9.4 12.6,9 12,9 L3,9 C2.4,9 2,9.4 2,10 L2,19 Z M3,7 L12,7 C13.7,7 15,8.3 15,10 L15,19 C15,20.7 13.7,22 12,22 L3,22 C1.3,22 0,20.7 0,19 L0,10 C0,8.3 1.3,7 3,7 Z M18,13 L19,13 C19.6,13 20,12.6 20,12 L20,3 C20,2.4 19.6,2 19,2 L10,2 C9.4,2 9,2.4 9,3 L9,4 C9,4.6 8.6,5 8,5 C7.4,5 7,4.6 7,4 L7,3 C7,1.3 8.3,0 10,0 L19,0 C20.7,0 22,1.3 22,3 L22,12 C22,13.7 20.7,15 19,15 L18,15 C17.4,15 17,14.6 17,14 C17,13.4 17.4,13 18,13 Z"/>
+</svg>
diff --git a/assets/sdc-icons/deployment-artifacts-o.svg b/assets/sdc-icons/deployment-artifacts-o.svg
new file mode 100644
index 0000000..e5091cd
--- /dev/null
+++ b/assets/sdc-icons/deployment-artifacts-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="deployment_artifacts-a" d="M18,17 C18,17.6 17.6,18 17,18 L3,18 C2.4,18 2,17.6 2,17 L2,3 C2,2.4 2.4,2 3,2 L17,2 C17.6,2 18,2.4 18,3 L18,17 Z M17,0 L3,0 C1.3,0 0,1.3 0,3 L0,17 C0,18.7 1.3,20 3,20 L17,20 C18.7,20 20,18.7 20,17 L20,3 C20,1.3 18.7,0 17,0 Z M5,14 C5,13.448 5.448,13 6,13 C6.552,13 7,13.448 7,14 C7,14.552 6.552,15 6,15 C5.448,15 5,14.552 5,14 M10,5 C10.552,5 11,5.448 11,6 C11,6.552 10.552,7 10,7 C9.448,7 9,6.552 9,6 C9,5.448 9.448,5 10,5 M15,14 C15,14.552 14.552,15 14,15 C13.448,15 13,14.552 13,14 C13,13.448 13.448,13 14,13 C14.552,13 15,13.448 15,14 M7.513,11.423 L9.064,8.836 C9.36,8.935 9.671,9 10,9 C10.159,9 10.312,8.977 10.465,8.953 L12.367,11.488 C11.82,11.845 11.406,12.375 11.184,13 L8.816,13 C8.579,12.331 8.115,11.777 7.513,11.423 M8.816,15 L11.184,15 C11.597,16.162 12.695,17 14,17 C15.657,17 17,15.657 17,14 C17,12.528 15.938,11.31 14.54,11.055 L12.236,7.982 C12.706,7.453 13,6.764 13,6 C13,4.343 11.657,3 10,3 C8.343,3 7,4.343 7,6 C7,6.591 7.177,7.139 7.472,7.603 L5.397,11.061 C4.029,11.34 3,12.55 3,14 C3,15.657 4.343,17 6,17 C7.305,17 8.403,16.162 8.816,15"/>
+</svg>
diff --git a/assets/sdc-icons/description-o.svg b/assets/sdc-icons/description-o.svg
new file mode 100644
index 0000000..d4e4345
--- /dev/null
+++ b/assets/sdc-icons/description-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="description-a" d="M10,9 C10.6,9 11,9.4 11,10 L11,14 C11,14.601 10.6,15 10,15 C9.4,15 9,14.601 9,14 L9,10 C9,9.4 9.4,9 10,9 Z M9.3,5.29925 C9.7,4.90025 10.3,4.90025 10.7,5.29925 C10.901,5.49925 11,5.69925 11,5.99925 C11,6.29925 10.901,6.49925 10.7,6.69925 C10.5,6.90025 10.3,6.99925 10,6.99925 C9.7,6.99925 9.5,6.90025 9.3,6.69925 C9.1,6.49925 9,6.29925 9,5.99925 C9,5.69925 9.1,5.49925 9.3,5.29925 Z M18,17 C18,17.6 17.6,18 17,18 L3,18 C2.4,18 2,17.6 2,17 L2,3 C2,2.4 2.4,2 3,2 L17,2 C17.6,2 18,2.4 18,3 L18,17 Z M17,0 L3,0 C1.3,0 0,1.3 0,3 L0,17 C0,18.7 1.3,20 3,20 L17,20 C18.7,20 20,18.7 20,17 L20,3 C20,1.3 18.7,0 17,0 Z"/>
+</svg>
diff --git a/assets/sdc-icons/distributed.svg b/assets/sdc-icons/distributed.svg
new file mode 100644
index 0000000..956c51f
--- /dev/null
+++ b/assets/sdc-icons/distributed.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="distributed-a" d="M18.5,13 C17.672,13 17,12.329 17,11.5 C17,10.671 17.672,10 18.5,10 C19.328,10 20,10.671 20,11.5 C20,12.329 19.328,13 18.5,13 M16.5,18 C15.672,18 15,17.329 15,16.5 C15,15.671 15.672,15 16.5,15 C17.328,15 18,15.671 18,16.5 C18,17.329 17.328,18 16.5,18 M11.5,20 C10.672,20 10,19.329 10,18.5 C10,17.671 10.672,17 11.5,17 C12.328,17 13,17.671 13,18.5 C13,19.329 12.328,20 11.5,20 M16.5,5 C17.328,5 18,5.671 18,6.5 C18,7.329 17.328,8 16.5,8 C15.672,8 15,7.329 15,6.5 C15,5.671 15.672,5 16.5,5 M6.5,18 C5.672,18 5,17.329 5,16.5 C5,15.671 5.672,15 6.5,15 C7.328,15 8,15.671 8,16.5 C8,17.329 7.328,18 6.5,18 M11,0 C8.061,0 10.968,6.138 9,8 C6.884,10.001 0,7.84 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"/>
+</svg>
diff --git a/assets/sdc-icons/download-o.svg b/assets/sdc-icons/download-o.svg
new file mode 100644
index 0000000..f54dba7
--- /dev/null
+++ b/assets/sdc-icons/download-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="download-a" d="M19,15 C19.6,15 20,15.4 20,16 L20,19 C20,20.7 18.7,22 17,22 L3,22 C1.3,22 0,20.7 0,19 L0,16 C0,15.4 0.4,15 1,15 C1.6,15 2,15.4 2,16 L2,19 C2,19.6 2.4,20 3,20 L17,20 C17.6,20 18,19.6 18,19 L18,16 C18,15.4 18.4,15 19,15 Z M9.29925,15.7 L5.29925,11.7 C4.90025,11.3 4.90025,10.7 5.29925,10.3 C5.69925,9.9 6.29925,9.9 6.69925,10.3 L8.99925,12.599 L8.99925,1 C8.99925,0.4 9.40025,0 9.99925,0 C10.59925,0 10.99925,0.4 10.99925,1 L10.99925,12.599 L13.29925,10.3 C13.69925,9.9 14.29925,9.9 14.69925,10.3 C15.09925,10.7 15.09925,11.3 14.69925,11.7 L10.69925,15.7 C10.59925,15.8 10.49925,15.8 10.40025,15.9 C10.29925,16 10.09925,16 9.99925,16 C9.90025,16 9.69925,16 9.59925,15.9 C9.49925,15.9 9.40025,15.8 9.29925,15.7 Z"/>
+</svg>
diff --git a/assets/sdc-icons/edit-file-o.svg b/assets/sdc-icons/edit-file-o.svg
new file mode 100644
index 0000000..9f17daa
--- /dev/null
+++ b/assets/sdc-icons/edit-file-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="edit_file-a" d="M19,12.7001 C19.6,12.7001 20,13.0991 20,13.7001 L20,19.0001 C20,20.7001 18.7,22.0001 17,22.0001 L3,22.0001 C1.3,22.0001 0,20.7001 0,19.0001 L0,5.0001 C0,3.3001 1.3,2.0001 3,2.0001 L8.3,2.0001 C8.9,2.0001 9.3,2.4001 9.3,3.0001 C9.3,3.5991 8.9,4.0001 8.3,4.0001 L3,4.0001 C2.4,4.0001 2,4.4001 2,5.0001 L2,19.0001 C2,19.5991 2.4,20.0001 3,20.0001 L17,20.0001 C17.6,20.0001 18,19.5991 18,19.0001 L18,13.7001 C18,13.0991 18.4,12.7001 19,12.7001 Z M10.5996,13.9999 L7.9996,13.9999 L7.9996,11.3999 L16.9996,2.3999 L19.5996,4.9999 L10.5996,13.9999 Z M21.7006,4.2999 L17.7006,0.2999 C17.2996,-0.1001 16.7006,-0.1001 16.2996,0.2999 L6.2996,10.2999 C6.0996,10.4999 5.9996,10.6999 5.9996,10.9999 L5.9996,14.9999 C5.9996,15.5999 6.4006,15.9999 6.9996,15.9999 L10.9996,15.9999 C11.2996,15.9999 11.4996,15.8999 11.7006,15.6999 L21.7006,5.6999 C22.0996,5.2999 22.0996,4.6999 21.7006,4.2999 Z"/>
+</svg>
diff --git a/assets/sdc-icons/edit-o.svg b/assets/sdc-icons/edit-o.svg
new file mode 100644
index 0000000..bfa434e
--- /dev/null
+++ b/assets/sdc-icons/edit-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="edit-a" d="M2,12.3999 L12,2.3999 L14.6,4.9999 L4.6,14.9999 L2,14.9999 L2,12.3999 Z M1,16.9999 C0.4,16.9999 0,16.5999 0,15.9999 L0,11.9999 C0,11.6999 0.1,11.4999 0.3,11.2999 L11.3,0.2999 C11.7,-0.1001 12.3,-0.1001 12.7,0.2999 L16.7,4.2999 C17.1,4.6999 17.1,5.2999 16.7,5.6999 L5.7,16.6999 C5.5,16.8999 5.3,16.9999 5,16.9999 L1,16.9999 Z M19,20 C19.6,20 20,20.4 20,21 C20,21.6 19.6,22 19,22 L1,22 C0.4,22 0,21.6 0,21 C0,20.4 0.4,20 1,20 L19,20 Z"/>
+</svg>
diff --git a/assets/sdc-icons/expand-o.svg b/assets/sdc-icons/expand-o.svg
new file mode 100644
index 0000000..c7127d7
--- /dev/null
+++ b/assets/sdc-icons/expand-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="expand-a" d="M19.9006,0.6 C20.0006,0.701 20.0006,0.901 20.0006,1 L20.0006,7 C20.0006,7.6 19.5996,8 19.0006,8 C18.4006,8 18.0006,7.6 18.0006,7 L18.0006,3.401 L12.7006,8.701 C12.5006,8.901 12.2006,9 12.0006,9 C11.7996,9 11.5006,8.901 11.2996,8.701 C10.9006,8.3 10.9006,7.701 11.2996,7.3 L16.5996,2 L13.0006,2 C12.4006,2 12.0006,1.6 12.0006,1 C12.0006,0.401 12.4006,0 13.0006,0 L19.0006,0 C19.0996,0 19.2996,0 19.4006,0.1 C19.5996,0.201 19.7996,0.401 19.9006,0.6 Z M7.3,11.3002 C7.7,10.9012 8.3,10.9012 8.7,11.3002 C9.1,11.7002 9.1,12.3002 8.7,12.7002 L3.401,18.0002 L7,18.0002 C7.6,18.0002 8,18.4012 8,19.0002 C8,19.6002 7.6,20.0002 7,20.0002 L1,20.0002 C0.901,20.0002 0.7,20.0002 0.6,19.9012 C0.401,19.8002 0.2,19.6002 0.1,19.4012 C0,19.3002 0,19.1002 0,19.0002 L0,13.0002 C0,12.4012 0.401,12.0002 1,12.0002 C1.6,12.0002 2,12.4012 2,13.0002 L2,16.6002 L7.3,11.3002 Z M19.4006,19.9008 C19.2996,20.0008 19.0996,20.0008 19.0006,20.0008 L13.0006,20.0008 C12.4006,20.0008 12.0006,19.5998 12.0006,19.0008 C12.0006,18.4008 12.4006,18.0008 13.0006,18.0008 L16.5996,18.0008 L11.2996,12.7008 C11.0996,12.5008 11.0006,12.2008 11.0006,12.0008 C11.0006,11.7998 11.0996,11.5008 11.2996,11.2998 C11.7006,10.9008 12.2996,10.9008 12.7006,11.2998 L18.0006,16.5998 L18.0006,13.0008 C18.0006,12.4008 18.4006,12.0008 19.0006,12.0008 C19.5996,12.0008 20.0006,12.4008 20.0006,13.0008 L20.0006,19.0008 C20.0006,19.0998 20.0006,19.2998 19.9006,19.4008 C19.7996,19.5998 19.5996,19.7998 19.4006,19.9008 Z M8.7004,7.3002 C9.0994,7.7002 9.0994,8.3002 8.7004,8.7002 C8.3004,9.1002 7.7004,9.1002 7.3004,8.7002 L2.0004,3.4012 L2.0004,7.0002 C2.0004,7.6002 1.5994,8.0002 1.0004,8.0002 C0.4004,8.0002 0.0004,7.6002 0.0004,7.0002 L0.0004,1.0002 C0.0004,0.9012 0.0004,0.7002 0.0994,0.6002 C0.2004,0.4012 0.4004,0.2002 0.5994,0.1002 C0.7004,0.0002 0.9004,0.0002 1.0004,0.0002 L7.0004,0.0002 C7.5994,0.0002 8.0004,0.4012 8.0004,1.0002 C8.0004,1.6002 7.5994,2.0002 7.0004,2.0002 L3.4004,2.0002 L8.7004,7.3002 Z"/>
+</svg>
diff --git a/assets/sdc-icons/eye-o.svg b/assets/sdc-icons/eye-o.svg
new file mode 100644
index 0000000..35cf012
--- /dev/null
+++ b/assets/sdc-icons/eye-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="view-a" d="M11.975,16 C6.575,16 3.075,10.6 2.075,9 C2.975,7.4 6.575,2 11.975,2 C17.375,2 20.875,7.4 21.875,9 C20.875,10.6 17.375,16 11.975,16 M23.875,8.6 C23.675,8.2 19.475,0 11.975,0 C4.475,0 0.275,8.2 0.075,8.6 C-0.025,8.9 -0.025,9.2 0.075,9.5 C0.275,9.8 4.475,18 11.975,18 C19.475,18 23.675,9.8 23.875,9.4 C23.975,9.2 23.975,8.8 23.875,8.6 M12,11 C10.9,11 10,10.1 10,9 C10,7.9 10.9,7 12,7 C13.1,7 14,7.9 14,9 C14,10.1 13.1,11 12,11 M12,5 C9.8,5 8,6.8 8,9 C8,11.2 9.8,13 12,13 C14.2,13 16,11.2 16,9 C16,6.8 14.2,5 12,5"/>
+</svg>
diff --git a/assets/sdc-icons/filter-o.svg b/assets/sdc-icons/filter-o.svg
new file mode 100644
index 0000000..1364bc5
--- /dev/null
+++ b/assets/sdc-icons/filter-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="filter-a" d="M12.2092536,9.8 C12.1082536,10 12.0092536,10.2 12.0092536,10.5 L12.0092536,17.401 L10.0092536,16.401 L10.0092536,10.5 C10.0092536,10.3 9.90925355,10 9.80925355,9.901 L3.20925355,2 L18.9092536,2 L12.2092536,9.8 Z M21.9092536,0.6 C21.7092536,0.2 21.4092536,0 21.0092536,0 L1.00925355,0 C0.608253553,0 0.309253553,0.2 0.108253553,0.6 C-0.0907464471,0.901 0.00925355294,1.3 0.209253553,1.6 L8.00925355,10.8 L8.00925355,17 C8.00925355,17.401 8.20925355,17.7 8.60825355,17.901 L12.6082536,19.901 C12.7092536,20 12.8092536,20 13.0092536,20 C13.2092536,20 13.4092536,20 13.5092536,19.901 C13.8092536,19.7 14.0092536,19.401 14.0092536,19 L14.0092536,10.8 L21.8092536,1.6 C22.0092536,1.3 22.1082536,0.901 21.9092536,0.6 Z"/>
+</svg>
diff --git a/assets/sdc-icons/info-circle-o.svg b/assets/sdc-icons/info-circle-o.svg
new file mode 100644
index 0000000..4d91259
--- /dev/null
+++ b/assets/sdc-icons/info-circle-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="info-a" d="M11,20 C6,20 2,16 2,11 C2,6 6,2 11,2 C16,2 20,6 20,11 C20,16 16,20 11,20 M11,0 C4.9,0 0,4.9 0,11 C0,17.101 4.9,22 11,22 C17.1,22 22,17.101 22,11 C22,4.9 17.1,0 11,0 M11,10 C10.4,10 10,10.4 10,11 L10,15 C10,15.601 10.4,16 11,16 C11.6,16 12,15.601 12,15 L12,11 C12,10.4 11.6,10 11,10 M10.2998,6.2998 C10.0998,6.4998 9.9998,6.6998 9.9998,6.9998 C9.9998,7.2998 10.0998,7.4998 10.2998,7.6998 C10.4998,7.9008 10.6998,7.9998 10.9998,7.9998 C11.2998,7.9998 11.4998,7.9008 11.6998,7.6998 C11.9008,7.4998 11.9998,7.2998 11.9998,6.9998 C11.9998,6.6998 11.9008,6.4998 11.6998,6.2998 C11.2998,5.9008 10.6998,5.9008 10.2998,6.2998"/>
+</svg>
diff --git a/assets/sdc-icons/info-circle.svg b/assets/sdc-icons/info-circle.svg
new file mode 100644
index 0000000..551966a
--- /dev/null
+++ b/assets/sdc-icons/info-circle.svg
@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <g fill-rule="evenodd" transform="translate(1 1)">
+ <path id="info-copy-a" d="M11,0 C4.9,0 0,4.9 0,11 C0,17.101 4.9,22 11,22 C17.1,22 22,17.101 22,11 C22,4.9 17.1,0 11,0 M11,10 C10.4,10 10,10.4 10,11 L10,15 C10,15.601 10.4,16 11,16 C11.6,16 12,15.601 12,15 L12,11 C12,10.4 11.6,10 11,10 M10.2998,6.2998 C10.0998,6.4998 9.9998,6.6998 9.9998,6.9998 C9.9998,7.2998 10.0998,7.4998 10.2998,7.6998 C10.4998,7.9008 10.6998,7.9998 10.9998,7.9998 C11.2998,7.9998 11.4998,7.9008 11.6998,7.6998 C11.9008,7.4998 11.9998,7.2998 11.9998,6.9998 C11.9998,6.6998 11.9008,6.4998 11.6998,6.2998 C11.2998,5.9008 10.6998,5.9008 10.2998,6.2998"/>
+ </g>
+</svg>
diff --git a/assets/sdc-icons/info-square-o.svg b/assets/sdc-icons/info-square-o.svg
new file mode 100644
index 0000000..40a85c6
--- /dev/null
+++ b/assets/sdc-icons/info-square-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="information_artifacts-a" d="M10,9 C10.6,9 11,9.4 11,10 L11,14 C11,14.601 10.6,15 10,15 C9.4,15 9,14.601 9,14 L9,10 C9,9.4 9.4,9 10,9 Z M9.3,5.29925 C9.7,4.90025 10.3,4.90025 10.7,5.29925 C10.901,5.49925 11,5.69925 11,5.99925 C11,6.29925 10.901,6.49925 10.7,6.69925 C10.5,6.90025 10.3,6.99925 10,6.99925 C9.7,6.99925 9.5,6.90025 9.3,6.69925 C9.1,6.49925 9,6.29925 9,5.99925 C9,5.69925 9.1,5.49925 9.3,5.29925 Z M18,17 C18,17.6 17.6,18 17,18 L3,18 C2.4,18 2,17.6 2,17 L2,3 C2,2.4 2.4,2 3,2 L17,2 C17.6,2 18,2.4 18,3 L18,17 Z M17,0 L3,0 C1.3,0 0,1.3 0,3 L0,17 C0,18.7 1.3,20 3,20 L17,20 C18.7,20 20,18.7 20,17 L20,3 C20,1.3 18.7,0 17,0 Z"/>
+</svg>
diff --git a/assets/sdc-icons/inputs-o.svg b/assets/sdc-icons/inputs-o.svg
new file mode 100644
index 0000000..5120b24
--- /dev/null
+++ b/assets/sdc-icons/inputs-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="inputs-a" d="M18,17.05 C18,17.65 17.6,18.05 17,18.05 L3,18.05 C2.4,18.05 2,17.65 2,17.05 L2,3.05 C2,2.45 2.4,2.05 3,2.05 L17,2.05 C17.6,2.05 18,2.45 18,3.05 L18,17.05 Z M17,0.05 L3,0.05 C1.3,0.05 0,1.35 0,3.05 L0,17.05 C0,18.75 1.3,20.05 3,20.05 L17,20.05 C18.7,20.05 20,18.75 20,17.05 L20,3.05 C20,1.35 18.7,0.05 17,0.05 Z M15,5.05 L5,5.05 C4.45,5.05 4,5.5 4,6.05 C4,6.6 4.45,7.05 5,7.05 L15,7.05 C15.55,7.05 16,6.6 16,6.05 C16,5.5 15.55,5.05 15,5.05 M15,9.05 L5,9.05 C4.45,9.05 4,9.5 4,10.05 C4,10.6 4.45,11.05 5,11.05 L15,11.05 C15.55,11.05 16,10.6 16,10.05 C16,9.5 15.55,9.05 15,9.05"/>
+</svg>
diff --git a/assets/sdc-icons/locked.svg b/assets/sdc-icons/locked.svg
new file mode 100644
index 0000000..5c0939f
--- /dev/null
+++ b/assets/sdc-icons/locked.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="locked-a" d="M6,6 C6,3.8 7.8,2 10,2 C12.2,2 14,3.8 14,6 L14,9 L6,9 L6,6 Z M17,9 L16,9 L16,6 C16,2.7 13.3,0 10,0 C6.7,0 4,2.7 4,6 L4,9 L3,9 C1.3,9 0,10.3 0,12 L0,19 C0,20.7 1.3,22 3,22 L17,22 C18.7,22 20,20.7 20,19 L20,12 C20,10.3 18.7,9 17,9 Z"/>
+</svg>
diff --git a/assets/sdc-icons/minus-circle.svg b/assets/sdc-icons/minus-circle.svg
new file mode 100644
index 0000000..d7755dc
--- /dev/null
+++ b/assets/sdc-icons/minus-circle.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="sub_2-a" d="M11,20 C6,20 2,16 2,11 C2,6 6,2 11,2 C16,2 20,6 20,11 C20,16 16,20 11,20 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 L7,10 C6.4,10 6,10.4 6,11 C6,11.6 6.4,12 7,12 L15,12 C15.6,12 16,11.6 16,11 C16,10.4 15.6,10 15,10"/>
+</svg>
diff --git a/assets/sdc-icons/minus.svg b/assets/sdc-icons/minus.svg
new file mode 100644
index 0000000..48fdcae
--- /dev/null
+++ b/assets/sdc-icons/minus.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <rect id="sub-a" width="16" height="2" rx="1"/>
+</svg>
diff --git a/assets/sdc-icons/notifications-o.svg b/assets/sdc-icons/notifications-o.svg
new file mode 100644
index 0000000..f52a4e3
--- /dev/null
+++ b/assets/sdc-icons/notifications-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="notifications-a" d="M4.5,15 C4.8,14.4 5,13.7 5,13 L5,8 C5,4.7 7.7,2 11,2 C14.3,2 17,4.7 17,8 L17,13 C17,13.7 17.2,14.4 17.5,15 L4.5,15 Z M21,15 C21.6,15 22,15.4 22,16 C22,16.6 21.6,17 21,17 L1,17 C0.4,17 0,16.6 0,16 C0,15.4 0.4,15 1,15 C2.1,15 3,14.1 3,13 L3,8 C3,3.6 6.6,0 11,0 C15.4,0 19,3.6 19,8 L19,13 C19,14.1 19.9,15 21,15 Z M14.0968122,19.141054 C14.5968122,19.441054 14.7968122,20.041054 14.2968122,20.541054 C13.6968122,21.541054 12.6968122,22.041054 11.6968122,22.041054 C11.1968122,22.041054 10.6968122,21.941054 10.1968122,21.641054 C9.69681223,21.341054 9.39681223,21.041054 9.09681223,20.541054 C8.89681223,20.041054 8.99581223,19.441054 9.49581223,19.141054 C9.99581223,18.941054 10.5968122,19.041054 10.8968122,19.541054 C10.9958122,19.741054 11.0968122,19.841054 11.2968122,19.941054 C11.7968122,20.141054 12.3968122,20.041054 12.6968122,19.541054 C12.9958122,19.041054 13.5968122,18.841054 14.0968122,19.141054 Z"/>
+</svg>
diff --git a/assets/sdc-icons/plus-circle-o.svg b/assets/sdc-icons/plus-circle-o.svg
new file mode 100644
index 0000000..c87e574
--- /dev/null
+++ b/assets/sdc-icons/plus-circle-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="add_2-a" d="M11,20 C6,20 2,16 2,11 C2,6 6,2 11,2 C16,2 20,6 20,11 C20,16 16,20 11,20 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"/>
+</svg>
diff --git a/assets/sdc-icons/plus-circle.svg b/assets/sdc-icons/plus-circle.svg
new file mode 100644
index 0000000..62840b5
--- /dev/null
+++ b/assets/sdc-icons/plus-circle.svg
@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <g fill-rule="evenodd" transform="translate(1 1)">
+ <path id="add-copy-a" 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"/>
+ </g>
+</svg>
diff --git a/assets/sdc-icons/plus.svg b/assets/sdc-icons/plus.svg
new file mode 100644
index 0000000..00a6673
--- /dev/null
+++ b/assets/sdc-icons/plus.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="add-a" d="M15,7 L9,7 L9,1 C9,0.4 8.6,0 8,0 C7.4,0 7,0.4 7,1 L7,7 L1,7 C0.4,7 0,7.4 0,8 C0,8.6 0.4,9 1,9 L7,9 L7,15 C7,15.6 7.4,16 8,16 C8.6,16 9,15.6 9,15 L9,9 L15,9 C15.6,9 16,8.6 16,8 C16,7.4 15.6,7 15,7"/>
+</svg>
diff --git a/assets/sdc-icons/profile-o.svg b/assets/sdc-icons/profile-o.svg
new file mode 100644
index 0000000..802715e
--- /dev/null
+++ b/assets/sdc-icons/profile-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="profile-a" d="M13,12 L5,12 C2.2,12 0,14.2 0,17 L0,19 C0,19.6 0.4,20 1,20 C1.6,20 2,19.6 2,19 L2,17 C2,15.3 3.3,14 5,14 L13,14 C14.7,14 16,15.3 16,17 L16,19 C16,19.6 16.4,20 17,20 C17.6,20 18,19.6 18,19 L18,17 C18,14.2 15.8,12 13,12 M9,2 C10.7,2 12,3.3 12,5 C12,6.7 10.7,8 9,8 C7.3,8 6,6.7 6,5 C6,3.3 7.3,2 9,2 M9,10 C11.8,10 14,7.8 14,5 C14,2.2 11.8,0 9,0 C6.2,0 4,2.2 4,5 C4,7.8 6.2,10 9,10"/>
+</svg>
diff --git a/assets/sdc-icons/profiles-o.svg b/assets/sdc-icons/profiles-o.svg
new file mode 100644
index 0000000..ac9c673
--- /dev/null
+++ b/assets/sdc-icons/profiles-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="permissions-a" d="M13,12 L5,12 C2.2,12 0,14.2 0,17 L0,19 C0,19.6 0.4,20 1,20 C1.6,20 2,19.6 2,19 L2,17 C2,15.3 3.3,14 5,14 L13,14 C14.7,14 16,15.3 16,17 L16,19 C16,19.6 16.4,20 17,20 C17.6,20 18,19.6 18,19 L18,17 C18,14.2 15.8,12 13,12 M9,2 C10.7,2 12,3.3 12,5 C12,6.7 10.7,8 9,8 C7.3,8 6,6.7 6,5 C6,3.3 7.3,2 9,2 M9,10 C11.8,10 14,7.8 14,5 C14,2.2 11.8,0 9,0 C6.2,0 4,2.2 4,5 C4,7.8 6.2,10 9,10 M20.2191602,12.0191602 C19.7191602,11.9191602 19.1181602,12.2191602 19.0191602,12.7191602 C18.9191602,13.2191602 19.2191602,13.8191602 19.7191602,13.9191602 C21.0191602,14.2191602 21.9191602,15.4191602 21.9191602,16.8191602 L21.9191602,18.8191602 C21.9191602,19.4191602 22.3191602,19.8191602 22.9191602,19.8191602 C23.5191602,19.8191602 23.9191602,19.4191602 23.9191602,18.8191602 L23.9191602,16.8191602 C24.0191602,14.5191602 22.5191602,12.5191602 20.2191602,12.0191602 M16.2525961,0.0617044797 C15.7525961,-0.13829552 15.2525961,0.16170448 15.0525961,0.76170448 C14.9525961,1.26170448 15.2525961,1.86170448 15.7525961,1.96170448 C17.3525961,2.36170448 18.3525961,3.96170448 17.9525961,5.66170448 C17.6515961,6.76170448 16.8525961,7.56170448 15.7525961,7.86170448 C15.2525961,7.96170448 14.8525961,8.56170448 15.0525961,9.06170448 C15.1515961,9.56170448 15.5525961,9.86170448 16.0525961,9.86170448 L16.2525961,9.86170448 C18.0525961,9.36170448 19.4525961,8.06170448 19.8525961,6.26170448 C20.5525961,3.46170448 18.9525961,0.66170448 16.2525961,0.0617044797"/>
+</svg>
diff --git a/assets/sdc-icons/question-mark-circle-o.svg b/assets/sdc-icons/question-mark-circle-o.svg
new file mode 100644
index 0000000..59dabde
--- /dev/null
+++ b/assets/sdc-icons/question-mark-circle-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="?-a" d="M12.1251444,5.21141885 C10.0241444,4.51141885 7.72514439,5.61041885 7.02414439,7.61141885 C6.92514439,8.21141885 7.12514439,8.81141885 7.72514439,8.91141885 C8.22514439,9.11141885 8.82514439,8.81141885 9.02414439,8.31141885 C9.42514439,7.31141885 10.5241444,6.71141885 11.6251444,7.11141885 C12.4251444,7.41141885 12.9251444,8.11141885 12.9251444,9.01141885 C12.9251444,10.0114188 11.2251444,10.8114188 10.6251444,11.1114188 C10.1251444,11.3114188 9.82514439,11.8114188 10.0241444,12.4114188 C10.1251444,12.8114188 10.5241444,13.1114188 10.9251444,13.1114188 C11.0241444,13.1114188 11.1251444,13.1114188 11.2251444,13.0114188 C11.6251444,12.9114188 14.9251444,11.7114188 14.9251444,9.11141885 C14.8251444,7.31141885 13.7251444,5.81141885 12.1251444,5.21141885 M11,20 C6,20 2,16 2,11 C2,6 6,2 11,2 C16,2 20,6 20,11 C20,16 16,20 11,20 M11,0 C4.9,0 0,4.9 0,11 C0,17.101 4.9,22 11,22 C17.1,22 22,17.101 22,11 C22,4.9 17.1,0 11,0 M10.3,15.29925 C10.1,15.49925 10,15.69925 10,15.99925 C10,16.29925 10.1,16.49925 10.3,16.69925 C10.5,16.90025 10.7,16.99925 11,16.99925 C11.3,16.99925 11.5,16.90025 11.7,16.69925 C11.901,16.49925 12,16.19925 12,15.99925 C12,15.79925 11.901,15.49925 11.7,15.29925 C11.3,14.90025 10.7,14.90025 10.3,15.29925"/>
+</svg>
diff --git a/assets/sdc-icons/question-mark-circle.svg b/assets/sdc-icons/question-mark-circle.svg
new file mode 100644
index 0000000..ae5541a
--- /dev/null
+++ b/assets/sdc-icons/question-mark-circle.svg
@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+ <g fill-rule="evenodd" transform="translate(1 1)">
+ <path id="?-copy-a" d="M12.1251444,5.21141885 C10.0241444,4.51141885 7.72514439,5.61041885 7.02414439,7.61141885 C6.92514439,8.21141885 7.12514439,8.81141885 7.72514439,8.91141885 C8.22514439,9.11141885 8.82514439,8.81141885 9.02414439,8.31141885 C9.42514439,7.31141885 10.5241444,6.71141885 11.6251444,7.11141885 C12.4251444,7.41141885 12.9251444,8.11141885 12.9251444,9.01141885 C12.9251444,10.0114188 11.2251444,10.8114188 10.6251444,11.1114188 C10.1251444,11.3114188 9.82514439,11.8114188 10.0241444,12.4114188 C10.1251444,12.8114188 10.5241444,13.1114188 10.9251444,13.1114188 C11.0241444,13.1114188 11.1251444,13.1114188 11.2251444,13.0114188 C11.6251444,12.9114188 14.9251444,11.7114188 14.9251444,9.11141885 C14.8251444,7.31141885 13.7251444,5.81141885 12.1251444,5.21141885 M11,0 C4.9,0 0,4.9 0,11 C0,17.101 4.9,22 11,22 C17.1,22 22,17.101 22,11 C22,4.9 17.1,0 11,0 M10.3,15.29925 C10.1,15.49925 10,15.69925 10,15.99925 C10,16.29925 10.1,16.49925 10.3,16.69925 C10.5,16.90025 10.7,16.99925 11,16.99925 C11.3,16.99925 11.5,16.90025 11.7,16.69925 C11.901,16.49925 12,16.19925 12,15.99925 C12,15.79925 11.901,15.49925 11.7,15.29925 C11.3,14.90025 10.7,14.90025 10.3,15.29925"/>
+ </g>
+</svg>
diff --git a/assets/sdc-icons/req-capabilities-o.svg b/assets/sdc-icons/req-capabilities-o.svg
new file mode 100644
index 0000000..88ace7d
--- /dev/null
+++ b/assets/sdc-icons/req-capabilities-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="req.&amp;capabilities-a" d="M19,20 C19,20.6 18.6,21 18,21 L6,21 C5.4,21 5,20.6 5,20 L5,6 C5,5.4 5.4,5 6,5 L7,5 C7,6.1 7.9,7 9,7 L15,7 C16.1,7 17,6.1 17,5 L18,5 C18.6,5 19,5.4 19,6 L19,20 Z M9,3 L15,3 L15,5 L9,5 L9,4 L9,3 Z M18,3 L17,3 C17,1.9 16.1,1 15,1 L9,1 C7.9,1 7,1.9 7,3 L6,3 C4.3,3 3,4.3 3,6 L3,20 C3,21.7 4.3,23 6,23 L18,23 C19.7,23 21,21.7 21,20 L21,6 C21,4.3 19.7,3 18,3 Z M17,10 L7,10 C6.45,10 6,10.45 6,11 C6,11.55 6.45,12 7,12 L17,12 C17.55,12 18,11.55 18,11 C18,10.45 17.55,10 17,10 M17,14 L7,14 C6.45,14 6,14.45 6,15 C6,15.55 6.45,16 7,16 L17,16 C17.55,16 18,15.55 18,15 C18,14.45 17.55,14 17,14"/>
+</svg>
diff --git a/assets/sdc-icons/revert-o.svg b/assets/sdc-icons/revert-o.svg
new file mode 100644
index 0000000..d48b8d0
--- /dev/null
+++ b/assets/sdc-icons/revert-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="revert-a" d="M13,10.6 L15.7,13.3 C16.1,13.7 16.1,14.3 15.7,14.7 C15.5,14.9 15.2,15 15,15 C14.8,15 14.5,14.9 14.3,14.7 L11.3,11.7 C11.1,11.5 11,11.3 11,11 L11,5 C11,4.4 11.4,4 12,4 C12.6,4 13,4.4 13,5 L13,10.6 Z M21.4037815,6.69868189 C23.3027815,11.8986819 20.5037815,17.5986819 15.3027815,19.3986819 C14.2037815,19.7986819 13.1027815,19.9986819 12.0037815,19.9986819 C7.90378148,19.9986819 4.00378148,17.3986819 2.50378148,13.2986819 C2.30278148,12.7986819 2.60278148,12.1986819 3.10278148,11.9986819 C3.60278148,11.7986819 4.20378148,12.0986819 4.40378148,12.5986819 C5.90378148,16.7986819 10.4037815,18.9986819 14.6027815,17.4986819 C16.7037815,16.7986819 18.3027815,15.2986819 19.2037815,13.3986819 C20.1027815,11.4986819 20.2037815,9.29868189 19.5037815,7.29868189 C18.8027815,5.19868189 17.3027815,3.59868189 15.4037815,2.69868189 C13.5037815,1.79868189 11.3027815,1.69868189 9.30278148,2.39868189 C8.20378148,2.79868189 7.10278148,3.49868189 6.30278148,4.29868189 L3.50378148,6.99868189 L7.00378148,6.99868189 C7.60278148,6.99868189 7.80278148,7.19868189 7.80278148,7.79868189 C7.80278148,8.39868189 7.40378148,8.79868189 6.80278148,8.79868189 L0.802781478,8.79868189 L0.602781478,8.79868189 L0.503781478,8.79868189 L0.403781478,8.69868189 C0.302781478,8.69868189 0.302781478,8.69868189 0.203781478,8.59868189 C0.102781478,8.59868189 0.102781478,8.49868189 0.102781478,8.49868189 C0.102781478,8.39868189 0.00378147753,8.39868189 0.00378147753,8.29868189 L0.00378147753,8.09868189 L0.00378147753,7.99868189 L0.00378147753,1.99868189 C0.00378147753,1.39868189 0.403781478,0.998681894 1.00378148,0.998681894 C1.60278148,0.998681894 2.00378148,1.39868189 2.00378148,1.99868189 L2.00378148,5.69868189 L5.00378148,2.89868189 C6.00378148,1.89868189 7.30278148,1.09868189 8.70378148,0.598681894 C11.2037815,-0.301318106 13.9037815,-0.201318106 16.3027815,0.998681894 C18.7037815,2.19868189 20.5037815,4.19868189 21.4037815,6.69868189 Z"/>
+</svg>
diff --git a/assets/sdc-icons/save-o.svg b/assets/sdc-icons/save-o.svg
new file mode 100644
index 0000000..3b95518
--- /dev/null
+++ b/assets/sdc-icons/save-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="save-a" d="M18,17 C18,17.6 17.6,18 17,18 L16,18 L16,11 C16,10.4 15.6,10 15,10 L5,10 C4.4,10 4,10.4 4,11 L4,18 L3,18 C2.4,18 2,17.6 2,17 L2,3 C2,2.4 2.4,2 3,2 L4,2 L4,6 C4,6.6 4.4,7 5,7 L13,7 C13.6,7 14,6.6 14,6 C14,5.4 13.6,5 13,5 L6,5 L6,2 L13.6,2 L18,6.4 L18,17 Z M6,18 L14,18 L14,12 L6,12 L6,18 Z M19.7,5.3 L14.7,0.3 C14.5,0.1 14.3,0 14,0 L3,0 C1.3,0 0,1.3 0,3 L0,17 C0,18.7 1.3,20 3,20 L17,20 C18.7,20 20,18.7 20,17 L20,6 C20,5.7 19.9,5.5 19.7,5.3 Z"/>
+</svg>
diff --git a/assets/sdc-icons/search-o.svg b/assets/sdc-icons/search-o.svg
new file mode 100644
index 0000000..312e21a
--- /dev/null
+++ b/assets/sdc-icons/search-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="search-a" d="M2,8.5 C2,4.9 4.9,2 8.5,2 C12.1,2 15,4.9 15,8.5 C15,10.3 14.3,11.9 13.1,13.1 C11.9,14.3 10.3,15 8.5,15 C4.9,15 2,12.1 2,8.5 M19.7,18.3 L15.2,13.8 C16.3,12.4 17,10.5 17,8.5 C17,3.8 13.2,0 8.5,0 C3.8,0 0,3.8 0,8.5 C0,13.2 3.8,17 8.5,17 C10.5,17 12.3,16.3 13.8,15.2 L18.3,19.7 C18.5,19.9 18.8,20 19,20 C19.2,20 19.5,19.9 19.7,19.7 C20.1,19.3 20.1,18.7 19.7,18.3"/>
+</svg>
diff --git a/assets/sdc-icons/settings-o.svg b/assets/sdc-icons/settings-o.svg
new file mode 100644
index 0000000..888be2e
--- /dev/null
+++ b/assets/sdc-icons/settings-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="settings-a" d="M12.0004,14.0004 C10.9004,14.0004 10.0004,13.1004 10.0004,12.0004 C10.0004,10.8994 10.9004,10.0004 12.0004,10.0004 C13.1004,10.0004 14.0004,10.8994 14.0004,12.0004 C14.0004,13.1004 13.1004,14.0004 12.0004,14.0004 M12.0004,8.0004 C9.8004,8.0004 8.0004,9.8004 8.0004,12.0004 C8.0004,14.2004 9.8004,16.0004 12.0004,16.0004 C14.2004,16.0004 16.0004,14.2004 16.0004,12.0004 C16.0004,9.8004 14.2004,8.0004 12.0004,8.0004 M19.1,17.6 C19.3,17.8 19.401,18 19.401,18.3 C19.401,18.6 19.3,18.8 19.1,19 C18.901,19.201 18.701,19.3 18.401,19.3 C18.1,19.3 17.901,19.201 17.6,18.9 C16.8,18.1 15.701,17.9 14.701,18.4 C13.701,18.8 13.1,19.8 13.1,20.8 L13.1,21 C13.1,21.6 12.701,22 12.1,22 C11.5,22 11.1,21.6 11.1,21 L11.1,20.9 C11.1,19.8 10.401,18.9 9.401,18.5 C9.1,18.3 8.701,18.3 8.3,18.3 C7.6,18.3 6.901,18.6 6.401,19.1 C6,19.5 5.5,19.5 5.1,19.201 L4.901,18.8 L4.8,18.8 C4.701,18.701 4.701,18.5 4.701,18.4 C4.701,18.1 4.8,17.9 5.1,17.6 C5.901,16.8 6.1,15.701 5.6,14.701 C5.201,13.701 4.201,13.1 3.201,13.1 L3,13.1 C2.401,13.1 2,12.701 2,12.1 C2,11.5 2.401,11.1 3,11.1 L3.1,11.1 C4.201,11.1 5.1,10.4 5.5,9.4 C5.901,8.4 5.701,7.3 4.901,6.4 C4.5,6 4.5,5.4 4.901,5 C5.3,4.6 5.901,4.6 6.401,5.1 C7.1,5.8 8.201,6 9.1,5.701 L9.401,5.6 C10.401,5.201 11,4.201 11,3.201 L11,3 C11,2.4 11.401,2 12,2 C12.6,2 13,2.4 13,3.1 C13,4.201 13.6,5.1 14.6,5.5 C15.6,5.9 16.701,5.701 17.6,4.9 C17.8,4.701 18,4.6 18.3,4.6 C18.6,4.6 18.8,4.701 19,4.9 C19.401,5.3 19.401,5.9 18.901,6.4 C18.201,7.1 18,8.201 18.3,9.1 L18.401,9.4 C18.8,10.4 19.8,11 20.8,11 L21,11 C21.6,11 22,11.4 22,12 C22,12.6 21.6,13 20.901,13 C19.8,13 18.901,13.6 18.5,14.6 C18,15.6 18.3,16.701 19.1,17.6 M20.3,15.4 C20.401,15.201 20.6,15 21,15 C22.701,15 24,13.701 24,12 C24,10.3 22.701,9 21,9 L20.8,9 C20.6,9 20.401,8.9 20.3,8.701 L20.201,8.5 C20.1,8.3 20.1,8 20.401,7.701 C21.5,6.6 21.6,5 20.701,3.8 L20.701,3.5 L20.3,3.3 C19.8,2.8 19.1,2.5 18.3,2.5 C17.5,2.5 16.701,2.8 16.1,3.4 C15.901,3.6 15.6,3.6 15.401,3.5 C15.201,3.6 15,3.3 15,3 C15,1.3 13.701,0 12,0 C10.3,0 9,1.3 9,3 L9,3.201 C9,3.4 8.901,3.6 8.701,3.701 L8.5,3.8 C8.3,3.9 8,3.8 7.701,3.6 C6.5,2.4 4.6,2.4 3.5,3.6 C2.3,4.8 2.3,6.701 3.6,7.9 C3.8,8.1 3.8,8.4 3.701,8.701 C3.6,8.9 3.3,9.1 3,9.1 C1.3,9.1 0,10.4 0,12.1 C0,13.8 1.3,15.1 3,15.1 L3.201,15.1 C3.5,15.1 3.701,15.3 3.8,15.5 C3.901,15.701 3.901,16 3.6,16.3 C3,16.9 2.701,17.6 2.701,18.4 C2.701,19.1 3,19.8 3.5,20.4 L3.6,20.5 L3.901,20.8 C5.1,21.701 6.701,21.6 7.901,20.5 C8.1,20.3 8.401,20.3 8.701,20.4 C9,20.5 9.1,20.701 9.1,21.1 C9.1,22.8 10.401,24.1 12.1,24.1 C13.8,24.1 15.1,22.8 15.1,21.1 L15.1,20.9 C15.1,20.6 15.3,20.4 15.5,20.3 C15.701,20.201 16,20.201 16.3,20.5 C17.5,21.701 19.401,21.701 20.5,20.5 C21.701,19.3 21.701,17.4 20.401,16.201 C20.3,15.9 20.201,15.6 20.3,15.4"/>
+</svg>
diff --git a/assets/sdc-icons/spinner.svg b/assets/sdc-icons/spinner.svg
new file mode 100644
index 0000000..9d0efb8
--- /dev/null
+++ b/assets/sdc-icons/spinner.svg
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="master-artboard" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" style="enable-background:new 0 0 850.4 1133.9;" width="24px" height="24px"><rect id="ee-background" x="0" y="0" width="24" height="24" style="fill: white; fill-opacity: 0; pointer-events: none;"/><g transform="matrix(0.3846159279346466, 0, 0, 0.3846159875392914, -7.18846321105957, -7.272071838378907)"><g transform="rotate(0 50 50)">
+ <path d="M 50 24 H 50 A 3 4.8 0 0 1 53 28.8 V 31.2 A 3 4.8 0 0 1 50 36 H 50 A 3 4.8 0 0 1 47 31.2 V 28.8 A 3 4.8 0 0 1 50 24 Z" fill="#0568ae">
+ <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.9166666666666666s" repeatCount="indefinite"/>
+ </path>
+</g><g transform="rotate(30 50 50)">
+ <path d="M 50 24 H 50 A 3 4.8 0 0 1 53 28.8 V 31.2 A 3 4.8 0 0 1 50 36 H 50 A 3 4.8 0 0 1 47 31.2 V 28.8 A 3 4.8 0 0 1 50 24 Z" fill="#0568ae">
+ <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.8333333333333334s" repeatCount="indefinite"/>
+ </path>
+</g><g transform="rotate(60 50 50)">
+ <path d="M 50 24 H 50 A 3 4.8 0 0 1 53 28.8 V 31.2 A 3 4.8 0 0 1 50 36 H 50 A 3 4.8 0 0 1 47 31.2 V 28.8 A 3 4.8 0 0 1 50 24 Z" fill="#0568ae">
+ <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.75s" repeatCount="indefinite"/>
+ </path>
+</g><g transform="rotate(90 50 50)">
+ <path d="M 50 24 H 50 A 3 4.8 0 0 1 53 28.8 V 31.2 A 3 4.8 0 0 1 50 36 H 50 A 3 4.8 0 0 1 47 31.2 V 28.8 A 3 4.8 0 0 1 50 24 Z" fill="#0568ae">
+ <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.6666666666666666s" repeatCount="indefinite"/>
+ </path>
+</g><g transform="rotate(120 50 50)">
+ <path d="M 50 24 H 50 A 3 4.8 0 0 1 53 28.8 V 31.2 A 3 4.8 0 0 1 50 36 H 50 A 3 4.8 0 0 1 47 31.2 V 28.8 A 3 4.8 0 0 1 50 24 Z" fill="#0568ae">
+ <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.5833333333333334s" repeatCount="indefinite"/>
+ </path>
+</g><g transform="rotate(150 50 50)">
+ <path d="M 50 24 H 50 A 3 4.8 0 0 1 53 28.8 V 31.2 A 3 4.8 0 0 1 50 36 H 50 A 3 4.8 0 0 1 47 31.2 V 28.8 A 3 4.8 0 0 1 50 24 Z" fill="#0568ae">
+ <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.5s" repeatCount="indefinite"/>
+ </path>
+</g><g transform="rotate(180 50 50)">
+ <path d="M 50 24 H 50 A 3 4.8 0 0 1 53 28.8 V 31.2 A 3 4.8 0 0 1 50 36 H 50 A 3 4.8 0 0 1 47 31.2 V 28.8 A 3 4.8 0 0 1 50 24 Z" fill="#0568ae">
+ <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.4166666666666667s" repeatCount="indefinite"/>
+ </path>
+</g><g transform="rotate(210 50 50)">
+ <path d="M 50 24 H 50 A 3 4.8 0 0 1 53 28.8 V 31.2 A 3 4.8 0 0 1 50 36 H 50 A 3 4.8 0 0 1 47 31.2 V 28.8 A 3 4.8 0 0 1 50 24 Z" fill="#0568ae">
+ <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.3333333333333333s" repeatCount="indefinite"/>
+ </path>
+</g><g transform="rotate(240 50 50)">
+ <path d="M 50 24 H 50 A 3 4.8 0 0 1 53 28.8 V 31.2 A 3 4.8 0 0 1 50 36 H 50 A 3 4.8 0 0 1 47 31.2 V 28.8 A 3 4.8 0 0 1 50 24 Z" fill="#0568ae">
+ <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.25s" repeatCount="indefinite"/>
+ </path>
+</g><g transform="rotate(270 50 50)">
+ <path d="M 50 24 H 50 A 3 4.8 0 0 1 53 28.8 V 31.2 A 3 4.8 0 0 1 50 36 H 50 A 3 4.8 0 0 1 47 31.2 V 28.8 A 3 4.8 0 0 1 50 24 Z" fill="#0568ae">
+ <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.16666666666666666s" repeatCount="indefinite"/>
+ </path>
+</g><g transform="rotate(300 50 50)">
+ <path d="M 50 24 H 50 A 3 4.8 0 0 1 53 28.8 V 31.2 A 3 4.8 0 0 1 50 36 H 50 A 3 4.8 0 0 1 47 31.2 V 28.8 A 3 4.8 0 0 1 50 24 Z" fill="#0568ae">
+ <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.08333333333333333s" repeatCount="indefinite"/>
+ </path>
+</g><g transform="rotate(330 50 50)">
+ <path d="M 50 24 H 50 A 3 4.8 0 0 1 53 28.8 V 31.2 A 3 4.8 0 0 1 50 36 H 50 A 3 4.8 0 0 1 47 31.2 V 28.8 A 3 4.8 0 0 1 50 24 Z" fill="#0568ae">
+ <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="0s" repeatCount="indefinite"/>
+ </path>
+</g></g></svg> \ No newline at end of file
diff --git a/assets/sdc-icons/success-circle-o.svg b/assets/sdc-icons/success-circle-o.svg
new file mode 100644
index 0000000..2d58e6c
--- /dev/null
+++ b/assets/sdc-icons/success-circle-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="success+20-a" d="M20.1825992,10.445793 C20.6735306,10.445793 21.0008182,10.7730806 21.0008182,11.264012 L21.0008182,12.0004091 C21.0008182,16.9915451 16.9915451,21 12.0004091,21 C7.00927315,21 3,16.9915451 3,12.0004091 C3,7.00927315 7.00927315,3 12.0004091,3 C13.3095595,3 14.536888,3.3272876 15.6823947,3.81821901 C16.0915042,3.98186281 16.255148,4.47279422 16.0915042,4.88190372 C15.9278604,5.29101323 15.436929,5.45465703 15.0278194,5.29101323 C14.0459566,4.88190372 13.0640938,4.63643802 12.0004091,4.63643802 C7.90931406,4.63643802 4.63643802,7.90931406 4.63643802,12.0004091 C4.63643802,16.0906859 7.90931406,19.363562 12.0004091,19.363562 C16.0915042,19.363562 19.3643802,16.0906859 19.3643802,12.0004091 L19.3643802,11.264012 C19.3643802,10.7730806 19.6916678,10.445793 20.1825992,10.445793 Z M21.5737352,4.06343925 C21.9002046,4.39072685 21.9002046,4.88165826 21.5737352,5.20894586 L12.5733261,14.209355 C12.4096823,14.3729988 12.1642166,14.4548207 12.0005728,14.4548207 C11.836929,14.4548207 11.5914632,14.3729988 11.4278194,14.209355 L8.97316242,11.7546979 C8.64587481,11.4274103 8.64587481,10.9364789 8.97316242,10.6091913 C9.30045002,10.2819037 9.79138143,10.2819037 10.118669,10.6091913 L12.0005728,12.491095 L20.4282286,4.06343925 C20.7555162,3.73615164 21.2464476,3.73615164 21.5737352,4.06343925 Z"/>
+</svg>
diff --git a/assets/sdc-icons/success.svg b/assets/sdc-icons/success.svg
new file mode 100644
index 0000000..918833b
--- /dev/null
+++ b/assets/sdc-icons/success.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="success-a" d="M16.667,0.3232 C16.223,-0.1078 15.556,-0.1078 15.111,0.3232 L6.667,12.4152 L1.889,7.7842 C1.444,7.3542 0.777,7.3542 0.333,7.7842 C-0.111,8.2152 -0.111,8.8612 0.333,9.2922 L5.889,14.6772 C6.111,14.8922 6.333,15.0002 6.667,15.0002 C7,15.0002 7.223,14.8922 7.444,14.6772 L16.667,1.8302 C17.111,1.4002 17.111,0.7542 16.667,0.3232"/>
+</svg>
diff --git a/assets/sdc-icons/sync-o.svg b/assets/sdc-icons/sync-o.svg
new file mode 100644
index 0000000..88a64d1
--- /dev/null
+++ b/assets/sdc-icons/sync-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="sync-a" d="M20.6,12.1 C21.1,12.2 21.401,12.8 21.3,13.4 C20.8,14.8 19.901,16.1 18.901,17.1 C17,19 14.5,20 11.8,20 C9.1,20 6.6,19 4.901,17.1 L2,14.3 L2,18 C2,18.6 1.6,19 1,19 C0.401,19 0,18.6 0,18 L0,12 L0,11.9 L0,11.7 C0,11.6 0.1,11.6 0.1,11.5 C0.201,11.5 0.201,11.4 0.201,11.4 C0.201,11.3 0.3,11.2 0.401,11.2 C0.401,11.1 0.5,11.1 0.5,11.1 L0.6,11.1 C0.6,11 0.701,11 0.8,11 L6.8,11 C7.401,11 7.8,11.4 7.8,12 C7.8,12.6 7.401,13 6.8,13 L3.3,13 L6.1,15.6 C7.701,17.2 9.701,18 11.8,18 C13.901,18 16,17.2 17.401,15.7 C18.3,14.9 18.901,13.8 19.3,12.7 C19.5,12.2 20.1,11.9 20.6,12.1 Z M22.4626462,1.01696034 C23.0626462,1.01696034 23.4626462,1.41696034 23.4626462,2.01696034 L23.4626462,8.01696034 L23.4626462,8.11696034 C23.4626462,8.21696034 23.4626462,8.31696034 23.3626462,8.41696034 C23.3626462,8.51696034 23.2626462,8.51696034 23.2626462,8.61696034 C23.1626462,8.61696034 23.1626462,8.71696034 23.1626462,8.71696034 C23.0626462,8.81696034 22.9626462,8.81696034 22.8626462,8.91696034 C22.7626462,9.01696034 22.5626462,9.01696034 22.4626462,9.01696034 L16.4626462,9.01696034 C15.8626462,9.01696034 15.4626462,8.61696034 15.4626462,8.01696034 C15.4626462,7.41696034 15.8626462,7.01696034 16.4626462,7.01696034 L19.9626462,7.01696034 L17.1626462,4.31696034 C16.3626462,3.41696034 15.2626462,2.81696034 14.1626462,2.41696034 C12.1626462,1.71696034 9.96264622,1.81696034 8.06264622,2.71696034 C6.16264622,3.71696034 4.66264622,5.31696034 3.96264622,7.31696034 C3.76264622,7.81696034 3.16264622,8.11696034 2.66264622,7.91696034 C2.16264622,7.81696034 1.86264622,7.21696034 2.06264622,6.71696034 C2.96264622,4.11696034 4.76264622,2.11696034 7.16264622,1.01696034 C9.56264622,-0.183039661 12.2626462,-0.283039661 14.8626462,0.516960339 C16.2626462,1.01696034 17.5626462,1.91696034 18.5626462,2.91696034 L21.4626462,5.71696034 L21.4626462,2.01696034 C21.4626462,1.41696034 21.8626462,1.01696034 22.4626462,1.01696034 Z"/>
+</svg>
diff --git a/assets/sdc-icons/trash-o.svg b/assets/sdc-icons/trash-o.svg
new file mode 100644
index 0000000..7a841fb
--- /dev/null
+++ b/assets/sdc-icons/trash-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="trash-a" d="M16,19 C16,19.6 15.6,20 15,20 L5,20 C4.4,20 4,19.6 4,19 L4,6 L16,6 L16,19 Z M7,3 C7,2.4 7.4,2 8,2 L12,2 C12.6,2 13,2.4 13,3 L13,4 L7,4 L7,3 Z M19,4 L15,4 L15,3 C15,1.3 13.7,0 12,0 L8,0 C6.3,0 5,1.3 5,3 L5,4 L1,4 C0.4,4 0,4.4 0,5 C0,5.6 0.4,6 1,6 L2,6 L2,19 C2,20.7 3.3,22 5,22 L15,22 C16.7,22 18,20.7 18,19 L18,6 L19,6 C19.6,6 20,5.6 20,5 C20,4.4 19.6,4 19,4 Z M8,17.0001 C8.6,17.0001 9,16.6001 9,16.0001 L9,10.0001 C9,9.4001 8.6,9.0001 8,9.0001 C7.4,9.0001 7,9.4001 7,10.0001 L7,16.0001 C7,16.6001 7.4,17.0001 8,17.0001 M12,17.0001 C12.6,17.0001 13,16.6001 13,16.0001 L13,10.0001 C13,9.4001 12.6,9.0001 12,9.0001 C11.4,9.0001 11,9.4001 11,10.0001 L11,16.0001 C11,16.6001 11.4,17.0001 12,17.0001"/>
+</svg>
diff --git a/assets/sdc-icons/undo-o.svg b/assets/sdc-icons/undo-o.svg
new file mode 100644
index 0000000..f6f0dd1
--- /dev/null
+++ b/assets/sdc-icons/undo-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="undo-a" d="M21.4,6.69868189 C20.5,4.19868189 18.7,2.19868189 16.299,0.998681894 C13.9,-0.201318106 11.2,-0.301318106 8.7,0.598681894 C7.299,1.09868189 6,1.89868189 5,2.89868189 L2,5.69868189 L2,1.99868189 C2,1.39868189 1.599,0.998681894 1,0.998681894 C0.4,0.998681894 0,1.39868189 0,1.99868189 L0,7.99868189 L0,8.09868189 L0,8.29868189 C0,8.39868189 0.099,8.39868189 0.099,8.49868189 C0.099,8.49868189 0.099,8.59868189 0.2,8.59868189 C0.299,8.69868189 0.299,8.69868189 0.4,8.69868189 L0.5,8.79868189 L0.599,8.79868189 L0.799,8.79868189 L6.799,8.79868189 C7.4,8.79868189 7.799,8.39868189 7.799,7.79868189 C7.799,7.19868189 7.599,6.99868189 7,6.99868189 L3.5,6.99868189 L6.299,4.29868189 C7.099,3.49868189 8.2,2.79868189 9.299,2.39868189 C11.299,1.69868189 13.5,1.79868189 15.4,2.69868189 C17.299,3.59868189 18.799,5.19868189 19.5,7.29868189 C20.2,9.29868189 20.099,11.4986819 19.2,13.3986819 C18.299,15.2986819 16.7,16.7986819 14.599,17.4986819 C10.4,18.9986819 5.9,16.7986819 4.4,12.5986819 C4.2,12.0986819 3.599,11.7986819 3.099,11.9986819 C2.599,12.1986819 2.299,12.7986819 2.5,13.2986819 C4,17.3986819 7.9,19.9986819 12,19.9986819 C13.099,19.9986819 14.2,19.7986819 15.299,19.3986819 C20.5,17.5986819 23.299,11.8986819 21.4,6.69868189"/>
+</svg>
diff --git a/assets/sdc-icons/unlocked-o.svg b/assets/sdc-icons/unlocked-o.svg
new file mode 100644
index 0000000..6e677e0
--- /dev/null
+++ b/assets/sdc-icons/unlocked-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="unlocked-a" d="M18,18.9999 C18,19.5999 17.6,19.9999 17,19.9999 L3,19.9999 C2.4,19.9999 2,19.5999 2,18.9999 L2,11.9999 C2,11.3999 2.4,10.9999 3,10.9999 L17,10.9999 C17.6,10.9999 18,11.3999 18,11.9999 L18,18.9999 Z M17,8.9999 L6,8.9999 L6,5.9999 C6,4.8999 6.4,3.8999 7.2,3.1999 C7.9,2.3999 8.9,1.9999 10,1.9999 C11.9,1.9999 13.5,3.2999 13.9,5.1999 C14,5.6999 14.6,6.0999 15.1,5.9999 C15.6,5.8999 16,5.3999 15.9,4.7999 C15.3,1.9999 12.8,-0.0001 10,-0.0001 C8.4,-0.0001 6.9,0.5999 5.8,1.7999 C4.6,2.8999 4,4.3999 4,5.9999 L4,8.9999 L3,8.9999 C1.3,8.9999 0,10.2999 0,11.9999 L0,18.9999 C0,20.6999 1.3,21.9999 3,21.9999 L17,21.9999 C18.7,21.9999 20,20.6999 20,18.9999 L20,11.9999 C20,10.2999 18.7,8.9999 17,8.9999 Z"/>
+</svg>
diff --git a/assets/sdc-icons/upload-o.svg b/assets/sdc-icons/upload-o.svg
new file mode 100644
index 0000000..bf62707
--- /dev/null
+++ b/assets/sdc-icons/upload-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="upload-a" d="M19,15 C19.6,15 20,15.4 20,16 L20,19 C20,20.7 18.7,22 17,22 L3,22 C1.3,22 0,20.7 0,19 L0,16 C0,15.4 0.4,15 1,15 C1.6,15 2,15.4 2,16 L2,19 C2,19.6 2.4,20 3,20 L17,20 C17.6,20 18,19.6 18,19 L18,16 C18,15.4 18.4,15 19,15 Z M6.7,5.67525 C6.3,6.07425 5.7,6.07425 5.3,5.67525 C4.9,5.27525 4.9,4.67525 5.3,4.27525 L9.3,0.27525 C9.4,0.17525 9.5,0.17525 9.599,0.07425 C9.9,-0.02475 10.2,-0.02475 10.4,0.07425 C10.5,0.07425 10.599,0.17525 10.7,0.27525 L14.7,4.27525 C15.099,4.67525 15.099,5.27525 14.7,5.67525 C14.5,5.87525 14.3,5.97525 14,5.97525 C13.7,5.97525 13.5,5.87525 13.3,5.67525 L11,3.37525 L11,14.97525 C11,15.57425 10.599,15.97525 10,15.97525 C9.4,15.97525 9,15.57425 9,14.97525 L9,3.37525 L6.7,5.67525 Z"/>
+</svg>
diff --git a/assets/sdc-icons/v-circle-o.svg b/assets/sdc-icons/v-circle-o.svg
new file mode 100644
index 0000000..1d6f737
--- /dev/null
+++ b/assets/sdc-icons/v-circle-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="success-a" d="M11,20 C6,20 2,16 2,11 C2,6 6,2 11,2 C16,2 20,6 20,11 C20,16 16,20 11,20 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.2471,6.3413 L8.9511,13.5373 L5.7071,10.2933 C5.3161,9.9023 4.6841,9.9023 4.2931,10.2933 C3.9021,10.6833 3.9021,11.3163 4.2931,11.7073 L8.2931,15.7073 C8.4801,15.8953 8.7351,16.0003 9.0001,16.0003 C9.0111,16.0003 9.0221,16.0003 9.0331,15.9993 C9.3101,15.9903 9.5701,15.8663 9.7531,15.6583 L16.7531,7.6583 C17.1161,7.2423 17.0741,6.6113 16.6581,6.2473 C16.2441,5.8833 15.6111,5.9243 15.2471,6.3413"/>
+</svg>
diff --git a/assets/sdc-icons/v-circle.svg b/assets/sdc-icons/v-circle.svg
new file mode 100644
index 0000000..9baa0f2
--- /dev/null
+++ b/assets/sdc-icons/v-circle.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="success-copy-a" d="M16.753,7.659 L9.753,15.659 C9.57,15.867 9.31,15.991 9.033,16 C9.023,16 9.011,16 9,16 C8.735,16 8.481,15.895 8.293,15.707 L4.293,11.707 C3.902,11.317 3.902,10.684 4.293,10.293 C4.684,9.903 5.316,9.903 5.707,10.293 L8.951,13.537 L15.247,6.342 C15.611,5.925 16.244,5.884 16.658,6.248 C17.074,6.612 17.116,7.243 16.753,7.659 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"/>
+</svg>
diff --git a/assets/sdc-icons/x-circle-o.svg b/assets/sdc-icons/x-circle-o.svg
new file mode 100644
index 0000000..ec0d80b
--- /dev/null
+++ b/assets/sdc-icons/x-circle-o.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <path id="x_o_20-a" d="M9,16.3636364 C4.90909091,16.3636364 1.63636364,13.0909091 1.63636364,9 C1.63636364,4.90909091 4.90909091,1.63636364 9,1.63636364 C13.0909091,1.63636364 16.3636364,4.90909091 16.3636364,9 C16.3636364,13.0909091 13.0909091,16.3636364 9,16.3636364 M9,0 C4.00909091,0 0,4.00909091 0,9 C0,13.9909091 4.00909091,18 9,18 C13.9909091,18 18,13.9909091 18,9 C18,4.00909091 13.9909091,0 9,0 M12.0272727,5.97211364 C11.7,5.64565909 11.2090909,5.64565909 10.8818182,5.97211364 L9,7.85393182 L7.11818182,5.97211364 C6.79090909,5.64565909 6.3,5.64565909 5.97272727,5.97211364 C5.64545455,6.29938636 5.64545455,6.79029545 5.97272727,7.11756818 L7.85372727,8.99938636 L5.97272727,10.8812045 C5.64545455,11.2084773 5.64545455,11.6993864 5.97272727,12.0266591 C6.13636364,12.1911136 6.3,12.2721136 6.54545455,12.2721136 C6.79090909,12.2721136 6.95454545,12.1911136 7.11818182,12.0266591 L9,10.1456591 L10.8818182,12.0266591 C11.0454545,12.1911136 11.2909091,12.2721136 11.4545455,12.2721136 C11.6181818,12.2721136 11.8636364,12.1911136 12.0272727,12.0266591 C12.3537273,11.6993864 12.3537273,11.2084773 12.0272727,10.8812045 L10.1454545,8.99938636 L12.0272727,7.11756818 C12.3537273,6.79029545 12.3537273,6.29938636 12.0272727,5.97211364"/>
+</svg>
diff --git a/assets/sdc-icons/x-circle.svg b/assets/sdc-icons/x-circle.svg
new file mode 100644
index 0000000..15982ce
--- /dev/null
+++ b/assets/sdc-icons/x-circle.svg
@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+ <g fill-rule="evenodd" transform="translate(1 1)">
+ <path id="x-copy-a" 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 M14.2591,7.29935 C13.8591,6.90035 13.2591,6.90035 12.8591,7.29935 L10.5591,9.59935 L8.2591,7.29935 C7.8591,6.90035 7.2591,6.90035 6.8591,7.29935 C6.4591,7.69935 6.4591,8.29935 6.8591,8.69935 L9.1581,10.99935 L6.8591,13.29935 C6.4591,13.69935 6.4591,14.29935 6.8591,14.69935 C7.0591,14.90035 7.2591,14.99935 7.5591,14.99935 C7.8591,14.99935 8.0591,14.90035 8.2591,14.69935 L10.5591,12.40035 L12.8591,14.69935 C13.0591,14.90035 13.3591,14.99935 13.5591,14.99935 C13.7591,14.99935 14.0591,14.90035 14.2591,14.69935 C14.6581,14.29935 14.6581,13.69935 14.2591,13.29935 L11.9591,10.99935 L14.2591,8.69935 C14.6581,8.29935 14.6581,7.69935 14.2591,7.29935"/>
+ </g>
+</svg>
diff --git a/components/accordion/accordion-basic.html b/components/accordion/accordion-basic.html
new file mode 100644
index 0000000..fe85473
--- /dev/null
+++ b/components/accordion/accordion-basic.html
@@ -0,0 +1,22 @@
+<div class="sdc-accordion ">
+ <div class="sdc-accordion-header">
+ <div class="svg-icon-wrapper bottom">
+ <svg class="svg-icon __chevronUp" version="1.1" id="chevron-up_icon" x="0px" y="0px" viewBox="0 0 10 6.3" style="enable-background:new 0 0 10 6.3;"
+ xml:space="preserve">
+ <g transform="translate(0,-952.36218)">
+ <path d="M10,958.2c0-0.1,0-0.2-0.1-0.2l-4.6-5.5c-0.1-0.2-0.4-0.2-0.5,0l0,0L0.1,958c-0.1,0.2-0.1,0.4,0,0.5s0.4,0.1,0.5,0l0,0
+ l4.3-5.2l4.3,5.2c0.1,0.2,0.4,0.2,0.5,0.1C10,958.5,10,958.3,10,958.2z">
+ </path>
+ </g>
+ </svg>
+ </div>
+ <div class="title">
+ Accordion Title
+ </div>
+ </div>
+ <div class="sdc-accordion-body ">
+ <div>
+ Accordion body
+ </div>
+ </div>
+</div> \ No newline at end of file
diff --git a/components/accordion/accordion.scss b/components/accordion/accordion.scss
new file mode 100644
index 0000000..ef65b9c
--- /dev/null
+++ b/components/accordion/accordion.scss
@@ -0,0 +1,50 @@
+.sdc-accordion {
+ display: flex;
+ flex-direction: column;
+ margin-bottom: 10px;
+ &.disabled {
+ opacity: .4;
+ pointer-events: none;
+ }
+ &:not(.disabled) {
+ .sdc-accordion-header {
+ cursor: pointer;
+ }
+ }
+ .sdc-accordion-header {
+ display: flex;
+ flex-direction: row;
+ .svg-icon-wrapper {
+ margin-right: 20px;
+ transition: transform 0.4s;
+ &.down {
+ transform: rotate(180deg);
+ }
+ .svg-icon {
+ fill: $gray;
+ width: 14px;
+ height: 8px;
+ }
+ }
+ &.arrow-right {
+ justify-content: space-between;
+ .svg-icon-wrapper{
+ order:1;
+ margin:0;
+ }
+ }
+ }
+ .sdc-accordion-body {
+ padding-left: 10px;
+ opacity: 0;
+ overflow-y: hidden;
+ max-height: 0;
+ padding-top: 0px;
+ transition: opacity 0.33s linear, padding-top 0.3s linear;
+ &.open {
+ padding-top: 5px;
+ opacity: 1;
+ max-height: 9999px;
+ }
+ }
+}
diff --git a/components/autocomplete/_autocomplete.scss b/components/autocomplete/_autocomplete.scss
new file mode 100644
index 0000000..7275156
--- /dev/null
+++ b/components/autocomplete/_autocomplete.scss
@@ -0,0 +1,43 @@
+.sdc-autocomplete-container{
+ position: relative;
+
+ &.results-shown{
+ .sdc-input__input{
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 0;
+ }
+ }
+
+ ul.autocomplete-results {
+ opacity: 0;
+ border: solid 1px $blue;
+ border-bottom-left-radius: 4px;
+ border-bottom-right-radius: 4px;
+ border-top:none;
+ background-color: $white;
+ max-height: 200px;
+ box-shadow: 0 3px 7px -3px $dark-gray;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ position: absolute;
+ box-sizing: border-box;
+ width: 100%;
+ left: 0;
+ top: 100%;
+
+ li {
+ color:$text-black;
+ text-indent: 10px;
+ line-height: 30px;
+ cursor:pointer;
+ @include body-1;
+
+ &:hover {
+ background-color: $lighter-blue;
+ color: $blue;
+ }
+ }
+
+ }
+
+ }
diff --git a/components/autocomplete/autocomlete-close.html b/components/autocomplete/autocomlete-close.html
new file mode 100644
index 0000000..93946bb
--- /dev/null
+++ b/components/autocomplete/autocomlete-close.html
@@ -0,0 +1,22 @@
+<div class="sdc-autocomplete-container">
+ <div class="search-bar-container">
+ <div class="sdc-input">
+ <label class="sdc-input__label">search by color:</label>
+ <input class="sdc-input__input" type="text" name="undefined" placeholder="search text">
+ </div>
+ <span class="search-bar-button">
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+ <defs>
+ <path id="search-a" d="M2,8.5 C2,4.9 4.9,2 8.5,2 C12.1,2 15,4.9 15,8.5 C15,10.3 14.3,11.9 13.1,13.1 C11.9,14.3 10.3,15 8.5,15 C4.9,15 2,12.1 2,8.5 M19.7,18.3 L15.2,13.8 C16.3,12.4 17,10.5 17,8.5 C17,3.8 13.2,0 8.5,0 C3.8,0 0,3.8 0,8.5 C0,13.2 3.8,17 8.5,17 C10.5,17 12.3,16.3 13.8,15.2 L18.3,19.7 C18.5,19.9 18.8,20 19,20 C19.2,20 19.5,19.9 19.7,19.7 C20.1,19.3 20.1,18.7 19.7,18.3"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd" transform="translate(2 2)">
+ <use fill="#000" xlink:href="#search-a"/>
+ </g>
+ </svg>
+ </span>
+ </div>
+ <div class="autocomplete-results" style="height: 0px; opacity: 0;">
+
+ </div>
+</div>
+
diff --git a/components/autocomplete/autocomplete-open.html b/components/autocomplete/autocomplete-open.html
new file mode 100644
index 0000000..01b1f40
--- /dev/null
+++ b/components/autocomplete/autocomplete-open.html
@@ -0,0 +1,24 @@
+<div class="sdc-autocomplete-container">
+ <div class="search-bar-container">
+ <div class="sdc-input">
+ <label class="sdc-input__label">search by color:</label>
+ <input class="sdc-input__input" type="text" name="undefined" placeholder="search text">
+ </div>
+ <span class="clear-search-x">
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+ <defs>
+ <path id="close-a" d="M13.5996,12 L19.6576,5.942 C20.1146,5.485 20.1146,4.8 19.6576,4.343 C19.2006,3.886 18.5146,3.886 18.0576,4.343 L11.9996,10.4 L5.9426,4.343 C5.4856,3.886 4.7996,3.886 4.3426,4.343 C3.8856,4.8 3.8856,5.485 4.3426,5.942 L10.4006,12 L4.3426,18.058 C3.8856,18.515 3.8856,19.2 4.3426,19.657 C4.5716,19.886 4.7996,20 5.1426,20 C5.4856,20 5.7136,19.886 5.9426,19.657 L11.9996,13.6 L18.0576,19.657 C18.2866,19.886 18.6286,20 18.8576,20 C19.0856,20 19.4286,19.886 19.6576,19.657 C20.1146,19.2 20.1146,18.515 19.6576,18.058 L13.5996,12 Z"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd">
+ <use fill="#000" xlink:href="#close-a"/>
+ </g>
+ </svg>
+ </span>
+ </div>
+ <div class="autocomplete-results">
+ <div class="autocomplete-result-item">red</div>
+ <div class="autocomplete-result-item">yellow</div>
+ <div class="autocomplete-result-item">orange</div>
+ <div class="autocomplete-result-item">green</div>
+ </div>
+</div>
diff --git a/components/button/_button.scss b/components/button/_button.scss
new file mode 100644
index 0000000..3c21a45
--- /dev/null
+++ b/components/button/_button.scss
@@ -0,0 +1,168 @@
+.sdc-button {
+ order:1;
+ @include box-sizing;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ flex-direction: row;
+ outline: none;
+ border-radius: 2px;
+ padding: 0 12px;
+ height: 36px;
+ line-height: 36px;
+ width: 120px;
+ min-width: 90px;
+ cursor: pointer;
+ text-align: center;
+ text-transform: uppercase;
+ @include body-1;
+
+ &:disabled {
+ cursor: default;
+ }
+
+ // Primary button
+ &.sdc-button__primary {
+ border: 1px solid transparent;
+ background-color: $blue;
+ color: $white;
+
+ &:not(:disabled) {
+ &:hover, &:active {
+ background-color: $light-blue;
+ }
+ &:focus:not(:active) {
+ border: 1px solid $white;
+ background-color: $light-blue;
+ box-shadow: 0px 0px 0px 1px $light-blue;
+ }
+ }
+
+ &:disabled{
+ background: $blue-disabled;
+ }
+ }
+
+ // Secondary button
+ &.sdc-button__secondary {
+ border: 1px solid $blue;
+ background-color: transparent;
+ color: $blue;
+
+ &:not(:disabled) {
+ &:hover, &:active {
+ background-color: $light-blue;
+ color:$white;
+ }
+ &:focus:not(:active) {
+ color: $light-blue;
+ box-shadow: inset 0px 0px 0px 0px $dark-blue, 0px 0px 0px 1px $blue;
+ &:hover {
+ color: $white;
+ }
+ }
+ }
+
+ &:disabled {
+ color: $blue-disabled;
+ border-color: $blue-disabled;
+ }
+ }
+
+ // Link button
+ &.sdc-button__link {
+ background-color: transparent;
+ color: $blue;
+ fill: $blue;
+ border: none;
+
+ &:not(:disabled) {
+ &:hover, &:active {
+ color: $light-blue;
+ }
+ &:focus:not(:active) {
+ border: 1px solid $dark-blue;
+ color: $light-blue;
+ }
+ }
+
+ &:disabled{
+ color: $blue-disabled;
+ }
+ }
+
+
+ // alert button
+ &.sdc-button__alert {
+ border: none;
+ background-color: $red;
+ color: $white;
+
+ &:not(:disabled) {
+ &:hover, &:active {
+ background-color: $light-red;
+ }
+ &:focus:not(:active) {
+ border: 0.5px solid $white;
+ background-color: $light-red;
+ box-shadow: 0px 0px 0px 1px $light-red;
+ }
+ }
+
+ &:disabled{
+ background: $disabled-red;
+ }
+ }
+
+
+ /*** Sizes ***/
+ &.btn-large{
+ width: $btn-large;
+ }
+
+ &.btn-medium{
+ width: $btn-medium;
+ }
+
+ &.btn-small{
+ width: $btn-small;
+ }
+
+ &.btn-x-small{
+ width: $btn-extra-small;
+ }
+
+ &.btn-default{
+ width: $btn-default;
+ }
+
+ /*** Buttons with icons ***/
+ &.sdc-icon-right {
+ flex-direction: row-reverse;
+ .svg-icon {
+ margin-left: 15px;
+ }
+ }
+
+ &.sdc-icon-left {
+ flex-direction: row;
+ .svg-icon {
+ margin-right: 15px;
+ }
+ }
+
+ svg {
+ display: inline-block;
+ vertical-align: middle;
+ }
+}
+.sdc-button__wrapper {
+ display: inline-flex;
+}
+.sdc-button__spinner {
+ padding-top: 6px;
+ margin:0 2px;
+ &.left {
+ order:2;
+ }
+}
diff --git a/components/button/button-link-auto.html b/components/button/button-link-auto.html
new file mode 100644
index 0000000..22ac4c8
--- /dev/null
+++ b/components/button/button-link-auto.html
@@ -0,0 +1,3 @@
+<button class="sdc-button sdc-button__link btn-default">
+ Click Me
+</button>
diff --git a/components/button/button-link-disabled.html b/components/button/button-link-disabled.html
new file mode 100644
index 0000000..9267620
--- /dev/null
+++ b/components/button/button-link-disabled.html
@@ -0,0 +1,3 @@
+<button class="sdc-button sdc-button__link" disabled>
+ Click Me
+</button>
diff --git a/components/button/button-link-extra-small.html b/components/button/button-link-extra-small.html
new file mode 100644
index 0000000..245f885
--- /dev/null
+++ b/components/button/button-link-extra-small.html
@@ -0,0 +1,3 @@
+<button class="sdc-button sdc-button__link btn-x-small">
+ Click Me
+</button>
diff --git a/components/button/button-link-large.html b/components/button/button-link-large.html
new file mode 100644
index 0000000..6d1780c
--- /dev/null
+++ b/components/button/button-link-large.html
@@ -0,0 +1,3 @@
+<button class="sdc-button sdc-button__link btn-large">
+ Click Me
+</button>
diff --git a/components/button/button-link-medium.html b/components/button/button-link-medium.html
new file mode 100644
index 0000000..cb0293d
--- /dev/null
+++ b/components/button/button-link-medium.html
@@ -0,0 +1,3 @@
+<button class="sdc-button sdc-button__link btn-medium">
+ Click Me
+</button>
diff --git a/components/button/button-link-small.html b/components/button/button-link-small.html
new file mode 100644
index 0000000..5c195fa
--- /dev/null
+++ b/components/button/button-link-small.html
@@ -0,0 +1,3 @@
+<button class="sdc-button sdc-button__link btn-small">
+ Click Me
+</button>
diff --git a/components/button/button-link.html b/components/button/button-link.html
new file mode 100644
index 0000000..5c2070b
--- /dev/null
+++ b/components/button/button-link.html
@@ -0,0 +1,3 @@
+<button class="sdc-button sdc-button__link">
+ Click Me
+</button>
diff --git a/components/button/button-primary-auto.html b/components/button/button-primary-auto.html
new file mode 100644
index 0000000..125276f
--- /dev/null
+++ b/components/button/button-primary-auto.html
@@ -0,0 +1,3 @@
+<button class="sdc-button sdc-button__primary btn-default">
+ Click Me
+</button>
diff --git a/components/button/button-primary-disabled.html b/components/button/button-primary-disabled.html
new file mode 100644
index 0000000..b2ef842
--- /dev/null
+++ b/components/button/button-primary-disabled.html
@@ -0,0 +1,3 @@
+<button class="sdc-button sdc-button__primary" disabled>
+ Click Me
+</button>
diff --git a/components/button/button-primary-extra-small.html b/components/button/button-primary-extra-small.html
new file mode 100644
index 0000000..a3be965
--- /dev/null
+++ b/components/button/button-primary-extra-small.html
@@ -0,0 +1,3 @@
+<button class="sdc-button sdc-button__primary btn-x-small">
+ Click Me
+</button>
diff --git a/components/button/button-primary-large.html b/components/button/button-primary-large.html
new file mode 100644
index 0000000..c0a41b1
--- /dev/null
+++ b/components/button/button-primary-large.html
@@ -0,0 +1,3 @@
+<button class="sdc-button sdc-button__primary btn-large">
+ Click Me
+</button>
diff --git a/components/button/button-primary-medium.html b/components/button/button-primary-medium.html
new file mode 100644
index 0000000..9ddedc5
--- /dev/null
+++ b/components/button/button-primary-medium.html
@@ -0,0 +1,3 @@
+<button class="sdc-button sdc-button__primary btn-medium">
+ Click Me
+</button>
diff --git a/components/button/button-primary-small.html b/components/button/button-primary-small.html
new file mode 100644
index 0000000..847f753
--- /dev/null
+++ b/components/button/button-primary-small.html
@@ -0,0 +1,3 @@
+<button class="sdc-button sdc-button__primary btn-small">
+ Click Me
+</button>
diff --git a/components/button/button-primary.html b/components/button/button-primary.html
new file mode 100644
index 0000000..b1524bf
--- /dev/null
+++ b/components/button/button-primary.html
@@ -0,0 +1,3 @@
+<button class="sdc-button sdc-button__primary">
+ Click Me
+</button>
diff --git a/components/button/button-secondary-auto.html b/components/button/button-secondary-auto.html
new file mode 100644
index 0000000..a183ad8
--- /dev/null
+++ b/components/button/button-secondary-auto.html
@@ -0,0 +1,3 @@
+<button class="sdc-button sdc-button__secondary btn-default">
+ Click Me
+</button>
diff --git a/components/button/button-secondary-disabled.html b/components/button/button-secondary-disabled.html
new file mode 100644
index 0000000..4125328
--- /dev/null
+++ b/components/button/button-secondary-disabled.html
@@ -0,0 +1,3 @@
+<button class="sdc-button sdc-button__secondary" disabled>
+ Click Me
+</button>
diff --git a/components/button/button-secondary-extra-small.html b/components/button/button-secondary-extra-small.html
new file mode 100644
index 0000000..92c4784
--- /dev/null
+++ b/components/button/button-secondary-extra-small.html
@@ -0,0 +1,3 @@
+<button class="sdc-button sdc-button__secondary btn-x-small">
+ Click Me
+</button>
diff --git a/components/button/button-secondary-large.html b/components/button/button-secondary-large.html
new file mode 100644
index 0000000..958c151
--- /dev/null
+++ b/components/button/button-secondary-large.html
@@ -0,0 +1,3 @@
+<button class="sdc-button sdc-button__secondary btn-large">
+ Click Me
+</button>
diff --git a/components/button/button-secondary-medium.html b/components/button/button-secondary-medium.html
new file mode 100644
index 0000000..67f9741
--- /dev/null
+++ b/components/button/button-secondary-medium.html
@@ -0,0 +1,3 @@
+<button class="sdc-button sdc-button__secondary btn-medium">
+ Click Me
+</button>
diff --git a/components/button/button-secondary-small.html b/components/button/button-secondary-small.html
new file mode 100644
index 0000000..d9d8cd7
--- /dev/null
+++ b/components/button/button-secondary-small.html
@@ -0,0 +1,3 @@
+<button class="sdc-button sdc-button__secondary btn-small">
+ Click Me
+</button>
diff --git a/components/button/button-secondary.html b/components/button/button-secondary.html
new file mode 100644
index 0000000..64967cc
--- /dev/null
+++ b/components/button/button-secondary.html
@@ -0,0 +1,3 @@
+<button class="sdc-button sdc-button__secondary">
+ Click Me
+</button>
diff --git a/components/checkbox/_checkbox.scss b/components/checkbox/_checkbox.scss
new file mode 100644
index 0000000..c35c8e0
--- /dev/null
+++ b/components/checkbox/_checkbox.scss
@@ -0,0 +1,66 @@
+.sdc-checkbox {
+ line-height: 14px;
+
+ label {
+ position: relative;
+ display: block;
+ padding-left: 14px;
+ }
+
+ .sdc-checkbox__input {
+ appearance: none;
+ -moz-appearance: none;
+ -webkit-appearance: none;
+ position: absolute;
+ z-index: -1;
+ opacity: 0;
+
+ // Checkbox not checked
+ + .sdc-checkbox__label:before {
+ display: inline-block;
+ position: absolute;
+ left: 0;
+ top: 0;
+ content: "";
+ width: 14px;
+ height: 14px;
+ box-sizing: content-box;
+ background: no-repeat url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%2214%22%20height%3D%2214%22%20viewBox%3D%220%200%2014%2014%22%3E%20%3Cdefs%3E%20%3Cpath%20id%3D%22disabled-a%22%20d%3D%22M2%2C0%20L12%2C-2.22044605e-16%20C13.1045695%2C5.56104062e-16%2014%2C0.8954305%2014%2C2%20L14%2C12%20C14%2C13.1045695%2013.1045695%2C14%2012%2C14%20L2%2C14%20C0.8954305%2C14%208.94280938e-16%2C13.1045695%20-2.22044605e-16%2C12%20L-2.22044605e-16%2C2%20C-3.57315355e-16%2C0.8954305%200.8954305%2C-1.91384796e-17%202%2C-2.22044605e-16%20Z%22%2F%3E%20%3C%2Fdefs%3E%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%20%3Cuse%20fill%3D%22%23FFFFFF%22%20xlink%3Ahref%3D%22%23disabled-a%22%2F%3E%20%3Cpath%20stroke%3D%22%23D2D2D2%22%20d%3D%22M2%2C0.5%20C1.17157288%2C0.5%200.5%2C1.17157288%200.5%2C2%20L0.5%2C12%20C0.5%2C12.8284271%201.17157288%2C13.5%202%2C13.5%20L12%2C13.5%20C12.8284271%2C13.5%2013.5%2C12.8284271%2013.5%2C12%20L13.5%2C2%20C13.5%2C1.17157288%2012.8284271%2C0.5%2012%2C0.5%20L2%2C0.5%20Z%22%2F%3E%20%3C%2Fg%3E%20%3C%2Fsvg%3E');
+ }
+
+ // Checkbox disabled and not checked
+ &:disabled {
+ + .sdc-checkbox__label {
+ color: $gray;
+ &:before {
+ background: no-repeat url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%2214%22%20height%3D%2214%22%20viewBox%3D%220%200%2014%2014%22%3E%20%3Cdefs%3E%20%3Cpath%20id%3D%22disabled-a%22%20d%3D%22M2%2C0%20L12%2C-2.22044605e-16%20C13.1045695%2C5.56104062e-16%2014%2C0.8954305%2014%2C2%20L14%2C12%20C14%2C13.1045695%2013.1045695%2C14%2012%2C14%20L2%2C14%20C0.8954305%2C14%208.94280938e-16%2C13.1045695%20-2.22044605e-16%2C12%20L-2.22044605e-16%2C2%20C-3.57315355e-16%2C0.8954305%200.8954305%2C-1.91384796e-17%202%2C-2.22044605e-16%20Z%22%2F%3E%20%3C%2Fdefs%3E%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%20%3Cuse%20fill%3D%22%23F2F2F2%22%20xlink%3Ahref%3D%22%23disabled-a%22%2F%3E%20%3Cpath%20stroke%3D%22%23D2D2D2%22%20d%3D%22M2%2C0.5%20C1.17157288%2C0.5%200.5%2C1.17157288%200.5%2C2%20L0.5%2C12%20C0.5%2C12.8284271%201.17157288%2C13.5%202%2C13.5%20L12%2C13.5%20C12.8284271%2C13.5%2013.5%2C12.8284271%2013.5%2C12%20L13.5%2C2%20C13.5%2C1.17157288%2012.8284271%2C0.5%2012%2C0.5%20L2%2C0.5%20Z%22%2F%3E%20%3C%2Fg%3E%20%3C%2Fsvg%3E');
+ }
+ }
+ }
+
+ &:checked {
+ // Checkbox checked
+ + .sdc-checkbox__label:before {
+ background: no-repeat url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2214%22%20height%3D%2214%22%20viewBox%3D%220%200%2014%2014%22%20fill%3D%22%23009fdb%22%3E%3Cpath%20d%3D%22M2%2C0%20L12%2C-2.22044605e-16%20C13.1045695%2C5.56104062e-16%2014%2C0.8954305%2014%2C2%20L14%2C12%20C14%2C13.1045695%2013.1045695%2C14%2012%2C14%20L2%2C14%20C0.8954305%2C14%208.94280938e-16%2C13.1045695%20-2.22044605e-16%2C12%20L-2.22044605e-16%2C2%20C-3.57315355e-16%2C0.8954305%200.8954305%2C-1.91384796e-17%202%2C-2.22044605e-16%20Z%20M3.85355339%2C7.54977605%20C3.65829124%2C7.35451391%203.34170876%2C7.35451391%203.14644661%2C7.54977605%20C2.95118446%2C7.7450382%202.95118446%2C8.06162069%203.14644661%2C8.25688283%20L5.71469032%2C10.8251265%20C5.93114093%2C11.0415771%206.28952386%2C11.0144698%206.47095446%2C10.7679244%20L10.8653572%2C4.79638422%20C11.0290275%2C4.57397322%2010.9814087%2C4.26099251%2010.7589977%2C4.09732224%20C10.5365867%2C3.93365198%2010.223606%2C3.98127076%2010.0599357%2C4.20368177%20L6.01038326%2C9.70660592%20L3.85355339%2C7.54977605%20Z%22%2F%3E%3C%2Fsvg%3E');
+ }
+
+ // Checkbox disabled and checked
+ &:disabled {
+ + .sdc-checkbox__label:before {
+ background: no-repeat url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2214%22%20height%3D%2214%22%20viewBox%3D%220%200%2014%2014%22%3E%3Cpath%20fill%3D%22%23d2d2d2%22%20fill-rule%3D%22evenodd%22%20d%3D%22M2%2C0%20L12%2C-2.22044605e-16%20C13.1045695%2C5.56104062e-16%2014%2C0.8954305%2014%2C2%20L14%2C12%20C14%2C13.1045695%2013.1045695%2C14%2012%2C14%20L2%2C14%20C0.8954305%2C14%208.94280938e-16%2C13.1045695%20-2.22044605e-16%2C12%20L-2.22044605e-16%2C2%20C-3.57315355e-16%2C0.8954305%200.8954305%2C-1.91384796e-17%202%2C-2.22044605e-16%20Z%20M3.85355339%2C7.54977605%20C3.65829124%2C7.35451391%203.34170876%2C7.35451391%203.14644661%2C7.54977605%20C2.95118446%2C7.7450382%202.95118446%2C8.06162069%203.14644661%2C8.25688283%20L5.71469032%2C10.8251265%20C5.93114093%2C11.0415771%206.28952386%2C11.0144698%206.47095446%2C10.7679244%20L10.8653572%2C4.79638422%20C11.0290275%2C4.57397322%2010.9814087%2C4.26099251%2010.7589977%2C4.09732224%20C10.5365867%2C3.93365198%2010.223606%2C3.98127076%2010.0599357%2C4.20368177%20L6.01038326%2C9.70660592%20L3.85355339%2C7.54977605%20Z%22%2F%3E%3C%2Fsvg%3E');
+ }
+ }
+ }
+
+ &:not(:disabled) {
+ + .sdc-checkbox__label {
+ cursor: pointer;
+ }
+ }
+ }
+
+ .sdc-checkbox__label:not(:empty) {
+ padding-left: 14px;
+ @include body-1;
+ }
+}
diff --git a/components/checkbox/checkbox-checked.html b/components/checkbox/checkbox-checked.html
new file mode 100644
index 0000000..de0c0d8
--- /dev/null
+++ b/components/checkbox/checkbox-checked.html
@@ -0,0 +1,6 @@
+<div class="sdc-checkbox">
+ <label>
+ <input type="checkbox" class="sdc-checkbox__input" checked>
+ <span class="sdc-checkbox__label">This is the checkbox label</span>
+ </label>
+</div>
diff --git a/components/checkbox/checkbox-disabled-checked.html b/components/checkbox/checkbox-disabled-checked.html
new file mode 100644
index 0000000..53e77ec
--- /dev/null
+++ b/components/checkbox/checkbox-disabled-checked.html
@@ -0,0 +1,6 @@
+<div class="sdc-checkbox">
+ <label>
+ <input type="checkbox" class="sdc-checkbox__input" checked disabled>
+ <span class="sdc-checkbox__label">This is the checkbox label</span>
+ </label>
+</div>
diff --git a/components/checkbox/checkbox-disabled.html b/components/checkbox/checkbox-disabled.html
new file mode 100644
index 0000000..2425218
--- /dev/null
+++ b/components/checkbox/checkbox-disabled.html
@@ -0,0 +1,6 @@
+<div class="sdc-checkbox">
+ <label>
+ <input type="checkbox" class="sdc-checkbox__input" disabled>
+ <span class="sdc-checkbox__label">This is the checkbox label</span>
+ </label>
+</div>
diff --git a/components/checkbox/checkbox-unchecked.html b/components/checkbox/checkbox-unchecked.html
new file mode 100644
index 0000000..9cc3d1c
--- /dev/null
+++ b/components/checkbox/checkbox-unchecked.html
@@ -0,0 +1,6 @@
+<div class="sdc-checkbox">
+ <label>
+ <input type="checkbox" class="sdc-checkbox__input">
+ <span class="sdc-checkbox__label">This is the checkbox label</span>
+ </label>
+</div>
diff --git a/components/checklist/_checklist.scss b/components/checklist/_checklist.scss
new file mode 100644
index 0000000..248993d
--- /dev/null
+++ b/components/checklist/_checklist.scss
@@ -0,0 +1,21 @@
+$space-lines: 14px;
+$padding-for-sub-level: 28px;
+.checkbox-item{
+ margin: $space-lines 0;
+ .sdc-checkbox__label{
+ @include body-2-emphasis;
+ }
+ .semi-checked{
+ .sdc-checkbox__label:before{
+ background: no-repeat url('data:image/svg+xml;utf8,<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path d="M2,0 L12,-2.22044605e-16 C13.1045695,5.56104062e-16 14,0.8954305 14,2 L14,12 C14,13.1045695 13.1045695,14 12,14 L2,14 C0.8954305,14 8.94280938e-16,13.1045695 -2.22044605e-16,12 L-2.22044605e-16,2 C-3.57315355e-16,0.8954305 0.8954305,-1.91384796e-17 2,-2.22044605e-16 Z" id="path-1"></path><rect id="path-2" x="3" y="6" width="8" height="2" rx="1"></rect></defs><g id="Symbols-" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g id="icons/checkbox/semiselected"><g id="form/checkbox_checked-copy-3"><g id="Rectangle-Copy-2"><use fill="#FFFFFF" fill-rule="evenodd" xlink:href="#path-1"></use><path stroke="#D2D2D2" stroke-width="1" d="M2,0.5 C1.17157288,0.5 0.5,1.17157288 0.5,2 L0.5,12 C0.5,12.8284271 1.17157288,13.5 2,13.5 L12,13.5 C12.8284271,13.5 13.5,12.8284271 13.5,12 L13.5,2 C13.5,1.17157288 12.8284271,0.5 12,0.5 L2,0.5 Z"></path></g></g><mask id="mask-3" fill="white"><use xlink:href="#path-2"></use></mask><use id="Mask" fill="#009FDB" xlink:href="#path-2"></use></g></g></svg>');
+ }
+ }
+}
+.checkbox-sublist{
+ padding-left: $padding-for-sub-level;
+ .checkbox-item{
+ .sdc-checkbox__label{
+ @include body-2;
+ }
+ }
+}
diff --git a/components/checklist/checklist-with-checked-items.html b/components/checklist/checklist-with-checked-items.html
new file mode 100644
index 0000000..e1adbd7
--- /dev/null
+++ b/components/checklist/checklist-with-checked-items.html
@@ -0,0 +1,24 @@
+<div>
+ <div class="checkbox-item">
+ <div class="sdc-checkbox">
+ <input class="sdc-checkbox__input" type="checkbox" checked>
+ <label class="sdc-checkbox__label">apple</label>
+ </div>
+ </div>
+</div>
+<div>
+ <div class="checkbox-item">
+ <div class="sdc-checkbox">
+ <input class="sdc-checkbox__input" type="checkbox">
+ <label class="sdc-checkbox__label">banana</label>
+ </div>
+ </div>
+</div>
+<div>
+ <div class="checkbox-item">
+ <div class="sdc-checkbox">
+ <input class="sdc-checkbox__input" type="checkbox" checked>
+ <label class="sdc-checkbox__label">orange</label>
+ </div>
+ </div>
+</div>
diff --git a/components/checklist/checklist-with-disabled-items.html b/components/checklist/checklist-with-disabled-items.html
new file mode 100644
index 0000000..f001ec1
--- /dev/null
+++ b/components/checklist/checklist-with-disabled-items.html
@@ -0,0 +1,25 @@
+<div>
+ <div class="checkbox-item">
+ <div class="sdc-checkbox">
+ <input class="sdc-checkbox__input" type="checkbox" disabled>
+ <label class="sdc-checkbox__label">apple</label>
+ </div>
+ </div>
+</div>
+<div>
+ <div class="checkbox-item">
+ <div class="sdc-checkbox">
+ <input class="sdc-checkbox__input" type="checkbox" disabled>
+ <label class="sdc-checkbox__label">banana</label>
+ </div>
+ </div>
+</div>
+<div>
+ <div class="checkbox-item">
+ <div class="sdc-checkbox">
+ <input class="sdc-checkbox__input" type="checkbox">
+ <label class="sdc-checkbox__label">orange</label>
+ </div>
+ </div>
+</div>
+
diff --git a/components/checklist/multi-levels-checklist.html b/components/checklist/multi-levels-checklist.html
new file mode 100644
index 0000000..9aa136e
--- /dev/null
+++ b/components/checklist/multi-levels-checklist.html
@@ -0,0 +1,50 @@
+<div>
+ <div class="checkbox-item">
+ <div class="sdc-checkbox">
+ <input class="sdc-checkbox__input" type="checkbox">
+ <label class="sdc-checkbox__label">apple</label>
+ </div>
+ </div>
+ <div class="checkbox-sublist">
+ <div>
+ <div class="checkbox-item">
+ <div class="sdc-checkbox">
+ <input class="sdc-checkbox__input" type="checkbox">
+ <label class="sdc-checkbox__label">red</label>
+ </div>
+ </div>
+ </div>
+ <div>
+ <div class="checkbox-item">
+ <div class="sdc-checkbox">
+ <input class="sdc-checkbox__input" type="checkbox">
+ <label class="sdc-checkbox__label">green</label>
+ </div>
+ </div>
+ </div>
+ <div>
+ <div class="checkbox-item">
+ <div class="sdc-checkbox">
+ <input class="sdc-checkbox__input" type="checkbox">
+ <label class="sdc-checkbox__label">yellow</label>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+<div>
+ <div class="checkbox-item">
+ <div class="sdc-checkbox">
+ <input class="sdc-checkbox__input" type="checkbox">
+ <label class="sdc-checkbox__label">banana</label>
+ </div>
+ </div>
+</div>
+<div>
+ <div class="checkbox-item">
+ <div class="sdc-checkbox">
+ <input class="sdc-checkbox__input" type="checkbox">
+ <label class="sdc-checkbox__label">orange</label>
+ </div>
+ </div>
+</div>
diff --git a/components/checklist/simple-checklist.html b/components/checklist/simple-checklist.html
new file mode 100644
index 0000000..1fe55da
--- /dev/null
+++ b/components/checklist/simple-checklist.html
@@ -0,0 +1,24 @@
+<div>
+ <div class="checkbox-item">
+ <div class="sdc-checkbox">
+ <input class="sdc-checkbox__input" type="checkbox">
+ <label class="sdc-checkbox__label">apple</label>
+ </div>
+ </div>
+</div>
+<div>
+ <div class="checkbox-item">
+ <div class="sdc-checkbox">
+ <input class="sdc-checkbox__input" type="checkbox">
+ <label class="sdc-checkbox__label">banana</label>
+ </div>
+ </div>
+</div>
+<div>
+ <div class="checkbox-item">
+ <div class="sdc-checkbox">
+ <input class="sdc-checkbox__input" type="checkbox">
+ <label class="sdc-checkbox__label">orange</label>
+ </div>
+ </div>
+</div>
diff --git a/components/dropdown/_dropdown.scss b/components/dropdown/_dropdown.scss
new file mode 100644
index 0000000..908bbaa
--- /dev/null
+++ b/components/dropdown/_dropdown.scss
@@ -0,0 +1,346 @@
+.sdc-dropdown {
+ @include body-1;
+ position: relative;
+ display: block;
+
+ .sdc-dropdown__error--block {
+ display: none;
+ }
+
+ &.headless {
+ display: none;
+ }
+
+ /*************************************
+ SDC DropDown styles
+ *************************************/
+ .sdc-dropdown__component-container {
+ position: relative;
+ height: 40px;
+
+ .sdc-dropdown__header {
+ background: $white;
+ text-align: left;
+ position: relative;
+ color: $dark-gray;
+ @include base-font-regular;
+ font-size: 14px;
+ text-indent: 6px;
+ border: solid 1px $light-gray;
+ width: 100%;
+ height: 40px;
+ line-height: 36px;
+ box-sizing: border-box;
+ border-radius: 2px;
+
+ &.placeholder {
+ @include base-font-italic;
+ color: $gray;
+ }
+
+ &.disabled {
+ border: solid 1px $light-gray;
+ background-color: $light-silver;
+ color: $light-gray;
+ cursor: default;
+
+ &:focus {
+ border: solid 1px $light-gray;
+ outline: none;
+ .svg-icon>svg {
+ fill: $light-gray;
+ }
+ }
+ .svg-icon>svg {
+ fill: $light-gray;
+ }
+ }
+
+ &:focus {
+ border: solid 1px $light-blue;
+ outline: none;
+ .svg-icon>svg {
+ fill: $light-blue;
+ }
+ }
+
+ .sdc-dropdown-handle {
+ float: right;
+ .svg-icon>svg {
+ fill: $dark-gray;
+ }
+ }
+
+ svg-icon {
+ margin: 10px 6px;
+ float: right;
+ }
+
+ }
+
+ }
+
+ &.open-bottom {
+ .sdc-dropdown__header {
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+
+ border: 1px solid $light-blue;
+ box-sizing: border-box;
+ .svg-icon>svg {
+ fill: $light-blue;
+ }
+
+ }
+ }
+
+ &.open-top {
+ .sdc-dropdown__header {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+ }
+ }
+
+ .sdc-dropdown__options-list {
+ position: relative;
+ opacity: 0;
+ top: 100%;
+ left: 0;
+ width: 100%;
+ max-height: 0;
+ overflow-y: auto;
+ box-sizing: border-box;
+ border: 1px solid $light-blue;
+ background-color: white;
+ box-shadow: 0 3px 7px -3px $dark-gray;
+ z-index: 999;
+ &.sdc-dropdown__options-wrapper--top {
+ bottom: 40px;
+ border-top: 1px solid $light-blue;
+ }
+ &.sdc-dropdown__options-list--headless {
+ border-top: 1px solid $light-blue;
+ }
+ .sdc-dropdown__option {
+ @include base-font-regular;
+ font-size: 14px;
+ text-indent: 10px;
+ padding: 10px;
+ background: transparent;
+ cursor: pointer;
+ height: 40px;
+ box-sizing: border-box;
+ &.sdc-dropdown__option--hr {
+ height: 1px;
+ overflow: hidden;
+ border-top: 1px solid $silver;
+ padding: 0;
+ margin: 10px 20px;
+ }
+ &.sdc-dropdown__option--group {
+ text-indent: 30px;
+ }
+ &:hover {
+ background-color: $light-silver;
+ //@include base-font-semibold;
+ }
+ &.selected {
+ background-color: $lighter-blue;
+ color: $blue;
+ @include base-font-semibold;
+ }
+ &.sdc-dropdown__option--header {
+ @include base-font-semibold;
+ color: $text-black;
+ cursor: default;
+ &.sdc-dropdown__option--group {
+ text-indent: 10px;
+ }
+ &:hover {
+ background-color: transparent;
+ }
+ }
+ &.sdc-dropdown__option--disabled {
+ color: $gray;
+ cursor: default;
+ &:hover {
+ background-color: transparent;
+ }
+ &::after {
+ color: $gray;
+ }
+ &:focus {
+ border: solid 1px $light-gray;
+ outline: none;
+ }
+ }
+ }
+ }
+ .sdc-dropdown__select {
+ @include base-font-regular;
+ text-indent: 6px;
+ border: solid 1px $light-gray;
+ width: 100%;
+ &.disabled {
+ opacity: 0.7;
+ }
+ option {
+ padding: 3px;
+ }
+ }
+ .sdc-dropdown__label {
+ margin-bottom: 5px;
+ display: block;
+ @include body-3-emphasis;
+ color: $text-black;
+ &.required::before {
+ content: '*';
+ color: $red;
+ margin: 0 4px 0 0;
+ }
+ }
+
+ /*************************************
+ SDC Auto-DropDown styles
+ *************************************/
+ &.open-bottom {
+ .sdc-dropdown-auto__wrapper {
+ border: 1px solid $light-blue;
+ box-sizing: border-box;
+ .svg-icon>svg {
+ fill: $light-blue;
+ }
+ }
+ }
+
+ .sdc-dropdown-auto__wrapper {
+ display: flex;
+ border: solid 1px $light-gray;
+ border-radius: 2px;
+
+ .sdc-dropdown__header {
+ border: none;
+ color: $gray;
+
+ &:focus {
+ border: none;
+ }
+ }
+
+ svg-icon {
+ margin: 12px 10px;
+ float: right;
+ }
+ }
+
+ /*************************************
+ SDC Error styles
+ *************************************/
+ &.sdc-dropdown__error {
+ .sdc-dropdown__header {
+ border: solid 1px $red;
+ @include font-error;
+ &::after {
+ @include font-error;
+ }
+ &:focus {
+ border: solid 1px $red;
+ .sdc-dropdown-handle {
+ use {
+ fill: $red;
+ }
+ }
+ }
+ .sdc-dropdown-handle {
+ use {
+ fill: $red;
+ }
+ }
+ }
+ .sdc-dropdown__error--block {
+ display: block;
+ @include font-error;
+ margin: 4px 0;
+ @include body-3;
+ }
+ .sdc-dropdown__options-wrapper--frame {
+ .sdc-dropdown__options-list {
+ border: 1px solid $red;
+ border-top: none;
+ }
+ &.sdc-dropdown__options-wrapper--top {
+ .sdc-dropdown__options-list {
+ border-top: 1px solid $red;
+ }
+ }
+ }
+ .svg-icon.__exclamationTriangleFull {
+ width: 12px;
+ height: 10px;
+ margin-right: 6px;
+ }
+ }
+}
+
+.sdc-dropdown__error--icon {
+ fill: $red;
+}
+
+/********************************************************/
+
+/* Animation */
+
+/********************************************************/
+
+@include keyframes-expand-animation('top-to-bottom-exp', 244px);
+@include keyframes-collapse-animation('top-to-bottom', 244px);
+@include keyframes-expand-animation('bottom-to-top-exp', 244px);
+@include keyframes-collapse-animation('bottom-to-top', 244px);
+.sdc-dropdown__options-wrapper--frame {
+ overflow: hidden;
+ position: absolute;
+ top: auto;
+ width: 100%;
+ &.sdc-dropdown__options-wrapper--top {
+ bottom: 40px;
+ top: auto;
+ padding: 10px 0 0 0;
+ /* Expend animation from bottom to top */
+ .sdc-dropdown__options-list {
+ border-top: 1px solid $light-blue;
+ box-shadow: 0 0 7px -1px $dark-gray;
+ &.sdc-dropdown__options-list--animation-init {
+ border-bottom: none;
+ padding: 0;
+ animation: bottom-to-top .0s forwards;
+ }
+ }
+ &.sdc-dropdown__options-wrapper--uncollapsed {
+ .sdc-dropdown__options-list {
+ animation: bottom-to-top-exp .0s forwards;
+ }
+ }
+ }
+}
+
+/**
+Fold animation from top to bottom
+ */
+
+.sdc-dropdown {
+ .sdc-dropdown__options-list.sdc-dropdown__options-list--animation-init {
+ animation: top-to-bottom .0s forwards;
+ }
+}
+
+/**
+Expend animation from top to bottom
+ */
+
+.sdc-dropdown {
+ .sdc-dropdown__options-wrapper--uncollapsed {
+ .sdc-dropdown__options-list.sdc-dropdown__options-list--animation-init {
+ animation: top-to-bottom-exp .0s forwards;
+ }
+ }
+}
diff --git a/components/dropdown/dropdown-disabled.html b/components/dropdown/dropdown-disabled.html
new file mode 100644
index 0000000..9e0bd86
--- /dev/null
+++ b/components/dropdown/dropdown-disabled.html
@@ -0,0 +1,11 @@
+<div class="sdc-dropdown">
+ <label class="sdc-dropdown__label">DropDown example</label>
+ <button class="sdc-dropdown__header disabled">Please choose option</button>
+ <!--[This part won't be created on disabled drop-down]-->
+ <ul class="sdc-dropdown__options-list">
+ <li class="sdc-dropdown__option selected">First Option</li>
+ <li class="sdc-dropdown__option">Second Option</li>
+ <li class="sdc-dropdown__option">Third Option</li>
+ </ul>
+ <!--[...]-->
+</div>
diff --git a/components/dropdown/dropdown-groups.html b/components/dropdown/dropdown-groups.html
new file mode 100644
index 0000000..3e32f16
--- /dev/null
+++ b/components/dropdown/dropdown-groups.html
@@ -0,0 +1,10 @@
+<div class="sdc-dropdown">
+ <label class="sdc-dropdown__label">DropDown example</label>
+ <button class="sdc-dropdown__header">Please choose option</button>
+ <ul class="sdc-dropdown__options-list">
+ <li class="sdc-dropdown__option sdc-dropdown__option--group sdc-dropdown__option--header">Group 1 title</li>
+ <li class="sdc-dropdown__option sdc-dropdown__option--group selected">First Option</li>
+ <li class="sdc-dropdown__option sdc-dropdown__option--group">Second Option</li>
+ <li class="sdc-dropdown__option sdc-dropdown__option--group">Third Option</li>
+ </ul>
+</div>
diff --git a/components/dropdown/dropdown-requiered.html b/components/dropdown/dropdown-requiered.html
new file mode 100644
index 0000000..4fd555d
--- /dev/null
+++ b/components/dropdown/dropdown-requiered.html
@@ -0,0 +1,18 @@
+<div class="sdc-dropdown">
+ <label class="sdc-dropdown__label">DropDown example</label>
+ <button class="sdc-dropdown__header">Please choose option</button>
+ <ul class="sdc-dropdown__options-list">
+ <li class="sdc-dropdown__option selected">First Option</li>
+ <li class="sdc-dropdown__option">Second Option</li>
+ <li class="sdc-dropdown__option">Third Option</li>
+ </ul>
+ <div class="sdc-dropdown__error">
+ <!--[Will be replaced by the correct error icon]-->
+ <svg class="svg-icon __exclamationTriangleFull" version="1.1" id="exclamation-triangle-full_icon" x="0px" y="0px" viewBox="0 0 19.9 18" xml:space="preserve"><path class="sdc-dropdown__error--icon" d="M19.6,14.3L12,1.3c-0.3-0.6-0.8-1-1.4-1.2C10-0.1,9.3,0,8.7,0.3c-0.4,0.3-0.6,0.6-0.9,1l-7.6,13c-0.3,0.5-0.4,1.2-0.2,1.8
+ c0.2,0.6,0.6,1.1,1.1,1.4C1.6,17.8,1.9,18,2.4,18h15.1c1.3,0,2.4-1.1,2.4-2.4C19.9,15.1,19.8,14.7,19.6,14.3z M10.5,14.2
+ c0,0.3-0.2,0.5-0.5,0.5s-0.5-0.2-0.5-0.5l0-1c0-0.3,0.2-0.5,0.5-0.5s0.5,0.2,0.5,0.5L10.5,14.2z M10.5,9.9c0,0.3-0.2,0.5-0.5,0.5
+ s-0.5-0.2-0.5-0.5l0-5.2c0-0.3,0.2-0.5,0.5-0.5s0.5,0.2,0.5,0.5L10.5,9.9z"></path></svg>
+ Error message!
+ </div>
+</div>
+
diff --git a/components/dropdown/dropdown.html b/components/dropdown/dropdown.html
new file mode 100644
index 0000000..440f70b
--- /dev/null
+++ b/components/dropdown/dropdown.html
@@ -0,0 +1,9 @@
+<div class="sdc-dropdown">
+ <label class="sdc-dropdown__label">DropDown example</label>
+ <button class="sdc-dropdown__header">Please choose option</button>
+ <ul class="sdc-dropdown__options-list">
+ <li class="sdc-dropdown__option selected">First Option</li>
+ <li class="sdc-dropdown__option">Second Option</li>
+ <li class="sdc-dropdown__option">Third Option</li>
+ </ul>
+</div>
diff --git a/components/filter-bar/_filter-bar.scss b/components/filter-bar/_filter-bar.scss
new file mode 100644
index 0000000..f48a3df
--- /dev/null
+++ b/components/filter-bar/_filter-bar.scss
@@ -0,0 +1,51 @@
+$inputHeight: 38px;
+
+.sdc-filter-bar {
+ .sdc-input {
+ margin: 0;
+ .sdc-input__input{
+ padding-right: 40px;
+ }
+ }
+
+ .filter-button{
+ position: relative;
+ float: right;
+ bottom: $inputHeight;
+ height: $inputHeight;
+ right: 11px;
+ svg{
+ position: relative;
+ top: 50%;
+ transform: translateY(-50%);
+ }
+ }
+
+ .magnify-button {
+ svg{
+ height: 20px;
+ width: 20px;
+ path{
+ fill: $dark-gray;
+ }
+ }
+ }
+
+ .clear-search-x {
+ cursor: pointer;
+ svg{
+ height: 14px;
+ width: 14px;
+ path{
+ fill: $dark-gray;
+ }
+ &:hover{
+ path{
+ fill: $blue;
+ }
+ }
+ }
+ }
+}
+
+
diff --git a/components/filter-bar/filter-bar-with-text.html b/components/filter-bar/filter-bar-with-text.html
new file mode 100644
index 0000000..de7a225
--- /dev/null
+++ b/components/filter-bar/filter-bar-with-text.html
@@ -0,0 +1,16 @@
+<div class="sdc-filter-bar">
+ <div class="search-bar-container">
+ <label class="sdc-input__label">search box example:</label>
+ <input class="sdc-input__input" type="text" name="undefined" placeholder="search text">
+ <span class="filter-button clear-search-x">
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+ <defs>
+ <path id="close-a" d="M13.5996,12 L19.6576,5.942 C20.1146,5.485 20.1146,4.8 19.6576,4.343 C19.2006,3.886 18.5146,3.886 18.0576,4.343 L11.9996,10.4 L5.9426,4.343 C5.4856,3.886 4.7996,3.886 4.3426,4.343 C3.8856,4.8 3.8856,5.485 4.3426,5.942 L10.4006,12 L4.3426,18.058 C3.8856,18.515 3.8856,19.2 4.3426,19.657 C4.5716,19.886 4.7996,20 5.1426,20 C5.4856,20 5.7136,19.886 5.9426,19.657 L11.9996,13.6 L18.0576,19.657 C18.2866,19.886 18.6286,20 18.8576,20 C19.0856,20 19.4286,19.886 19.6576,19.657 C20.1146,19.2 20.1146,18.515 19.6576,18.058 L13.5996,12 Z"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd">
+ <use fill="#000" xlink:href="#close-a"/>
+ </g>
+ </svg>
+ </span>
+ </div>
+</div>
diff --git a/components/filter-bar/filter-bar.html b/components/filter-bar/filter-bar.html
new file mode 100644
index 0000000..90f580d
--- /dev/null
+++ b/components/filter-bar/filter-bar.html
@@ -0,0 +1,17 @@
+<div class="sdc-filter-bar">
+ <div class="search-bar-container">
+ <label class="sdc-input__label">search box example:</label>
+ <input class="sdc-input__input" type="text" name="undefined" placeholder="search text">
+ <span class="filter-button magnify-button">
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+ <defs>
+ <path id="search-a" d="M2,8.5 C2,4.9 4.9,2 8.5,2 C12.1,2 15,4.9 15,8.5 C15,10.3 14.3,11.9 13.1,13.1 C11.9,14.3 10.3,15 8.5,15 C4.9,15 2,12.1 2,8.5 M19.7,18.3 L15.2,13.8 C16.3,12.4 17,10.5 17,8.5 C17,3.8 13.2,0 8.5,0 C3.8,0 0,3.8 0,8.5 C0,13.2 3.8,17 8.5,17 C10.5,17 12.3,16.3 13.8,15.2 L18.3,19.7 C18.5,19.9 18.8,20 19,20 C19.2,20 19.5,19.9 19.7,19.7 C20.1,19.3 20.1,18.7 19.7,18.3"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd" transform="translate(2 2)">
+ <use fill="#000" xlink:href="#search-a"/>
+ </g>
+ </svg>
+ </span>
+ </div>
+</div>
+
diff --git a/components/icon/_icon.scss b/components/icon/_icon.scss
new file mode 100644
index 0000000..cd94eb7
--- /dev/null
+++ b/components/icon/_icon.scss
@@ -0,0 +1,250 @@
+@mixin color-icon($primary-color, $secondary-color) {
+ color: $primary-color;
+ fill: $primary-color;
+ span{
+ color: $primary-color;
+ }
+ &:not([disabled]):hover, &:active, &:focus {
+ &.clickable {
+ color: $secondary-color;
+ fill: $secondary-color;
+ }
+ }
+}
+
+.svg-icon-wrapper {
+ display: inline-flex;
+ justify-content: center;
+ align-items: center;
+
+ &[disabled] {
+ opacity: 0.7;
+ }
+
+ &.bottom {
+ flex-direction: column;
+ .svg-icon-label {
+ margin-bottom: 5px;
+ }
+ }
+
+ &.right {
+ float: none;
+ .svg-icon-label {
+ margin-left: 5px;
+ }
+ }
+
+ &.top {
+ flex-direction: column-reverse;
+ .svg-icon-label {
+ margin-top: 5px;
+ }
+ }
+
+ &.left {
+ flex-direction: row-reverse;
+ .svg-icon-label {
+ margin-right: 5px;
+ }
+ }
+
+ &.__warning {
+ @include color-icon($yellow, $yellow);
+ }
+
+ &.__primary {
+ @include color-icon($blue, $light-blue);
+ }
+
+ &.__secondary {
+ @include color-icon($gray, $dark-gray);
+ }
+
+ &.__positive {
+ @include color-icon($green, $green);
+ }
+
+ &.__negative {
+ @include color-icon($red, $red);
+ }
+}
+
+
+.svg-icon {
+ width: 20px;
+ height: 20px;
+
+ &.__angleDoubleLeft {
+ width: 14px;
+ height: 14px;
+ }
+ &.__angleDoubleRight {
+ width: 14px;
+ height: 14px;
+ }
+ &.__angleLeft {
+ width: 14px;
+ height: 14px;
+ }
+ &.__angleRight {
+ width: 14px;
+ height: 14px;
+ }
+ &.__artifacts {
+ width: 16px;
+ height: 20px;
+ }
+ &.__back {
+ width: 25px;
+ height: 25px;
+ }
+ &.__base {
+ //
+ }
+ &.__calendar {
+ //
+ }
+ &.__caretDown {
+ }
+ &.__check {
+ }
+ &.__checkCircle {
+ width: 16px;
+ height: 16px;
+ }
+ &.__chevronDown{
+ width: 10px;
+ height: 7px;
+ }
+ &.__chevronUp {
+ width: 11px;
+ height: 7px;
+ }
+ &.__close {
+ width: 10px;
+ height: 10px;
+ }
+ &.__download {
+ width: 15px;
+ height: 11px;
+ }
+ &.__env {
+ width: 15px;
+ height: 14px;
+ }
+ &.__error {
+ width: 14px;
+ height: 14px;
+ }
+ &.__errorCircle {
+ width: 16px;
+ height: 16px;
+ }
+ &.__exclamationTriangleFull {
+ width: 15px;
+ height: 13px;
+ }
+ &.__exclamationTriangleLine {
+ width: 15px;
+ height: 13px;
+ }
+ &.__filter {
+ //
+ }
+ &.__locked {
+ width: 11px;
+ }
+ &.__module {
+ //
+ }
+ &.__nestedHeat {
+ width: 15px;
+ height: 13px;
+ }
+ &.__network {
+ width: 13px;
+ height: 13px;
+ }
+ &.__others {
+ width: 12px;
+ height: 12px;
+ }
+ &.__pencil {
+ width: 15px;
+ height: 15px;
+ }
+ &.__plus {
+ width: 9px;
+ height: 9px;
+ }
+ &.__plusCircle {
+ width: 19px;
+ height: 19px;
+ }
+ &.__plusThin {
+ width: 9px;
+ height: 9px;
+ }
+ &.__proceedToOverview {
+ width: 24px;
+ height: 20px;
+ }
+ &.__search {
+ //
+ }
+ &.__sliders {
+ }
+ &.__trashO {
+ width: 15px;
+ height: 16px;
+ }
+ &.__unlocked {
+ width: 11px;
+ }
+ &.__upload {
+ width: 15px;
+ height: 11px;
+ }
+ &.__vendor {
+ width: 53px;
+ height: 47px;
+ }
+ &.__versionControllerLockClosed {
+ width: 21px;
+ height: 23px;
+ }
+ &.__versionControllerLockOpen {
+ width: 24px;
+ height: 28px;
+ }
+ &.__versionControllerRevert {
+ //
+ }
+ &.__versionControllerSave {
+ //
+ }
+ &.__versionControllerSubmit {
+ //
+ }
+ &.__versionControllerPermissions {
+ //
+ }
+ &.__vlm {
+ width: 53px;
+ height: 47px;
+ }
+ &.__vsp {
+ width: 53px;
+ height: 47px;
+ }
+ &.__zip {
+ width: 29px;
+ height: 23px;
+ }
+}
+
+.svg-icon-missing {
+ @include body-2;
+ @include font-error;
+}
diff --git a/components/input/_input.scss b/components/input/_input.scss
new file mode 100644
index 0000000..a84d312
--- /dev/null
+++ b/components/input/_input.scss
@@ -0,0 +1,78 @@
+.sdc-input {
+ margin-bottom: 10px;
+
+ .sdc-input__label {
+ margin-bottom: 5px;
+ display: block;
+ @include body-3-emphasis;
+
+ &.required::before {
+ content: '*';
+ color: $red;
+ margin: 0 4px 0 0;
+ }
+ }
+
+ .sdc-input__input {
+ @include box-sizing;
+ padding: 0 10px;
+ height: 38px;
+ width: 100%;//415px;
+ border: solid 1px $light-gray;
+ border-radius:2px;
+ color: $dark-gray;
+
+ &.error, &.error:focus, &.error:disabled {
+ border: solid 1px $red;
+ color: $red;
+ outline: none;
+ }
+
+ &:read-only{
+ border: none;
+ outline: none;
+ color: $text-black
+ }
+ &:-moz-read-only { /* For Firefox */
+ border: none;
+ outline: none;
+ color: $text-black
+ }
+
+ &:focus {
+ border-color: $blue;
+ outline: 0 none;
+ color: $text-black;
+ }
+
+ &:disabled {
+ background: $light-silver;
+ color: $gray;
+ }
+
+ &::-webkit-input-placeholder /* Chrome/Opera/Safari */ {
+ color: $gray;
+ @include base-font-italic;
+ }
+ &::-moz-placeholder /* Firefox 19+ */ {
+ color: $gray;
+ @include base-font-italic;
+ }
+ &:-moz-placeholder /* Firefox 18- */ {
+ color: $gray;
+ @include base-font-italic;
+ }
+ &:-ms-input-placeholder /* IE 10+ */
+ {
+ color: $gray;
+ @include base-font-italic;
+ }
+ }
+
+ .sdc-label__error{
+ margin-top: 2px;
+ margin-left: 2px;
+ @include body-3;
+ }
+
+} \ No newline at end of file
diff --git a/components/input/input-disabled.html b/components/input/input-disabled.html
new file mode 100644
index 0000000..bea21b4
--- /dev/null
+++ b/components/input/input-disabled.html
@@ -0,0 +1,4 @@
+<div class="sdc-input __disabled">
+ <label class="sdc-input__label">I am a label</label>
+ <input class="sdc-input__input" type="text" disabled value="Default"/>
+</div>
diff --git a/components/input/input-error.html b/components/input/input-error.html
new file mode 100644
index 0000000..aafee55
--- /dev/null
+++ b/components/input/input-error.html
@@ -0,0 +1,17 @@
+<div class="sdc-input">
+ <label class="sdc-input__label">I am a label</label>
+ <input class="sdc-input__input error" type="text" value="Default"/>
+ <div class="sdc-label__error ">
+ <div class="svg-icon-wrapper __negative">
+ <svg class="svg-icon __exclamationTriangleFull __negative" version="1.1" id="exclamation-triangle-full_icon" x="0px" y="0px" viewBox="0 0 19.9 18" style="enable-background:new 0 0 19.9 18;" xml:space="preserve">
+ <path d="M19.6,14.3L12,1.3c-0.3-0.6-0.8-1-1.4-1.2C10-0.1,9.3,0,8.7,0.3c-0.4,0.3-0.6,0.6-0.9,1l-7.6,13c-0.3,0.5-0.4,1.2-0.2,1.8
+ c0.2,0.6,0.6,1.1,1.1,1.4C1.6,17.8,1.9,18,2.4,18h15.1c1.3,0,2.4-1.1,2.4-2.4C19.9,15.1,19.8,14.7,19.6,14.3z M10.5,14.2
+ c0,0.3-0.2,0.5-0.5,0.5s-0.5-0.2-0.5-0.5l0-1c0-0.3,0.2-0.5,0.5-0.5s0.5,0.2,0.5,0.5L10.5,14.2z M10.5,9.9c0,0.3-0.2,0.5-0.5,0.5
+ s-0.5-0.2-0.5-0.5l0-5.2c0-0.3,0.2-0.5,0.5-0.5s0.5,0.2,0.5,0.5L10.5,9.9z">
+ </path>
+ </svg>
+ <span class="svg-icon-label __negative">This is the error message.
+ </span>
+ </div>
+ </div>
+</div> \ No newline at end of file
diff --git a/components/input/input-number.html b/components/input/input-number.html
new file mode 100644
index 0000000..59ef93c
--- /dev/null
+++ b/components/input/input-number.html
@@ -0,0 +1,6 @@
+<div class="sdc-input">
+ <label class="sdc-input__label">I am a label</label>
+ <div>
+ <input class="sdc-input__input" type="number"/>
+ </div>
+</div> \ No newline at end of file
diff --git a/components/input/input-placeholder.html b/components/input/input-placeholder.html
new file mode 100644
index 0000000..b07d75d
--- /dev/null
+++ b/components/input/input-placeholder.html
@@ -0,0 +1,4 @@
+<div class="sdc-input">
+ <label class="sdc-input__label">I am a label</label>
+ <input class="sdc-input__input" placeholder="Write Here..." type="text"/>
+</div>
diff --git a/components/input/input-required.html b/components/input/input-required.html
new file mode 100644
index 0000000..f9dbb16
--- /dev/null
+++ b/components/input/input-required.html
@@ -0,0 +1,4 @@
+<div class="sdc-input">
+ <label class="sdc-input__label required">I am a label</label>
+ <input class="sdc-input__input" value="Default" type="text"/>
+</div>
diff --git a/components/input/input-view-only.html b/components/input/input-view-only.html
new file mode 100644
index 0000000..4381b22
--- /dev/null
+++ b/components/input/input-view-only.html
@@ -0,0 +1,4 @@
+<div class="sdc-input">
+ <label class="sdc-input__label">I am a label</label>
+ <input class="sdc-input__input view-only" type="text" value="Default"/>
+</div> \ No newline at end of file
diff --git a/components/input/input.html b/components/input/input.html
new file mode 100644
index 0000000..ef2ba61
--- /dev/null
+++ b/components/input/input.html
@@ -0,0 +1,8 @@
+<div class="sdc-input">
+ <label class="sdc-input__label">I am a label</label>
+ <input
+ class="sdc-input__input"
+ value="Default"
+ type="text"
+ />
+</div> \ No newline at end of file
diff --git a/components/menu/_menu.scss b/components/menu/_menu.scss
new file mode 100644
index 0000000..fe32f32
--- /dev/null
+++ b/components/menu/_menu.scss
@@ -0,0 +1,68 @@
+.sdc-menu-list {
+ position: static;
+ @include box-sizing;
+ @include box-shadow(0 2px 4px 0 rgba($black, 0.3));
+ @include border-radius(2px);
+ border: 1px solid $light-gray;
+ border-top: solid 3px $blue;
+ background: $white;
+ min-width: 150px;
+ width: -webkit-max-content;
+ width: -moz-max-content;
+ width: max-content;
+
+ .sdc-menu-item:not(.separator) {
+ @include body-1;
+ height: 40px;
+ color: $dark-gray;
+ padding: 0 12px;
+ display: flex;
+ align-items: center;
+
+ svg {
+ margin-right: 16px;
+ g, path {
+ fill: $dark-gray;
+ }
+ }
+
+ &:hover {
+ &:not(.disabled) {
+ cursor: pointer;
+ &:not(.selected) {
+ background: $light-silver;
+ color: $text-black;
+ g, path {
+ fill: $dark-gray;
+ }
+ }
+ }
+ }
+
+ &.disabled {
+ color: $gray;
+ g, path {
+ fill: $light-gray;
+ }
+ }
+
+ &.selected {
+ background: $lighter-blue;
+ color: $light-blue;
+ g, path {
+ fill: $dark-gray;
+ }
+ }
+ }
+
+ &.relative {
+ position: relative;
+ }
+
+ .separator {
+ cursor: default;
+ border-top: 1px solid $silver;
+ margin: 0 0;
+ height: 0;
+ }
+}
diff --git a/components/menu/popup-menu.html b/components/menu/popup-menu.html
new file mode 100644
index 0000000..f4f1cbd
--- /dev/null
+++ b/components/menu/popup-menu.html
@@ -0,0 +1,8 @@
+
+<ul class="sdc-menu-list static">
+ <li class="sdc-menu-item selected">item 1 (selected)</li>
+ <li class="sdc-menu-item disabled">item 2</li>
+ <li class="separator"/>
+ <li class="sdc-menu-item">item 3</li>
+ <li class="sdc-menu-item">custom action</li>
+</ul> \ No newline at end of file
diff --git a/components/menu/relative-popup-menu.html b/components/menu/relative-popup-menu.html
new file mode 100644
index 0000000..e5a5449
--- /dev/null
+++ b/components/menu/relative-popup-menu.html
@@ -0,0 +1,8 @@
+<div class="sdc-popup-menu">
+ <ul class="sdc-menu-list relative" style="top: 10px; left: 10px;">
+ <li class="sdc-menu-item selected">item 1 (selected)</li>
+ <li class="sdc-menu-item disabled">item 2</li>
+ <li class="separator"/>
+ <li class="sdc-menu-item">item 3</li>
+ </ul>
+</div> \ No newline at end of file
diff --git a/components/modal/_modal.scss b/components/modal/_modal.scss
new file mode 100644
index 0000000..e87e516
--- /dev/null
+++ b/components/modal/_modal.scss
@@ -0,0 +1,194 @@
+.sdc-modal {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ overflow: auto;
+ margin: auto;
+ display: flex;
+ align-items: center;
+ z-index: 1001;
+ svg path {
+ fill: inherit;
+ }
+ .sdc-modal__wrapper {
+ @include body-1;
+ background: $white;
+ width: 100%;
+ @include box-shadow(0 0 4px 0 rgba(0, 0, 0, 0.50));
+ color: $text-black;
+ display: flex;
+ flex-direction: column;
+ &.sdc-modal-type-info {
+ border-top: solid 6px $blue;
+ .sdc-modal__svg-use {
+ fill: $blue;
+ }
+ .svg-icon {
+ &.__errorCircle {
+ width: 30px;
+ height: 30px;
+ }
+ }
+ }
+ &.sdc-modal-type-alert {
+ border-top: solid 6px $yellow;
+ .sdc-modal__svg-use {
+ fill: $yellow;
+ }
+ .svg-icon {
+ &.__exclamationTriangleLine {
+ width: 30px;
+ height: 30px;
+ }
+ }
+ }
+ &.sdc-modal-type-error {
+ border-top: solid 6px $red;
+ .sdc-modal__svg-use {
+ fill: $red;
+ }
+ .svg-icon {
+ &.__error {
+ width: 30px;
+ height: 30px;
+ }
+ }
+ }
+ &.sdc-modal-type-custom {
+ padding: 0px;
+ border-top: none;
+ .sdc-custom__header {
+ @include box-sizing;
+ background-color: $blue;
+ color: $white;
+ height: 50px;
+ align-items: center;
+ padding-top: 0px;
+ .title {
+ color: $white;
+ padding-top: 0px;
+ @include heading-3;
+ }
+ .sdc-modal__close-button {
+ margin-top: 0px;
+ width: 16px;
+ height: 16px;
+ line-height: 16px;
+ .svg-icon > svg {
+ fill: $white;
+ color: $white;
+ }
+ &.disabled {
+ cursor: default;
+ .svg-icon > svg {
+ fill: $silver;
+ color: $silver;
+ }
+ }
+ }
+ .sdc-modal__close-button-svg {
+ width: 16px;
+ height: 16px;
+ .sdc-modal__svg-use {
+ fill: $white;
+ }
+ .svg-icon {
+ height: 16px;
+ width: 16px;
+ fill: $white;
+ }
+ }
+ }
+ .sdc-modal__content {
+ padding: 20px 40px;
+ }
+ }
+ .sdc-modal__header {
+ padding: 20px 20px 0 20px;
+ display: flex;
+ justify-content: space-between;
+ text-align: left;
+ height: 30px;
+ line-height: 30px;
+ .sdc-modal__icon {
+ margin-right: 10px;
+ }
+ .title {
+ @include heading-2;
+ flex: 1 1 auto;
+ color: $text-black;
+ }
+ .sdc-modal__close-button {
+ order: 3;
+ width: 14px;
+ height: 14px;
+ line-height: 14px;
+ cursor: pointer;
+ .sdc-modal__svg-use {
+ fill: $black;
+ }
+ &.disabled {
+ cursor: default;
+ }
+ }
+ }
+ .sdc-modal__content {
+ order: 2;
+ padding: 10px 60px 20px 60px;
+ }
+ .sdc-modal__footer {
+ order: 3;
+ background-color: $white;
+ border-top: solid 1px $silver;
+ padding: 10px;
+ display: flex;
+ justify-content: flex-end;
+ button {
+ margin-left: 10px;
+ }
+ }
+ }
+}
+
+.modal-background {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ background-color: $black;
+ opacity: 0.70;
+ z-index: 1000;
+ &.show {
+ z-index: 1000;
+ opacity: 0.70;
+ transition: opacity .3s ease, z-index .3s;
+ }
+ &.hide {
+ z-index: -1;
+ opacity: 0;
+ transition: opacity .35s ease, z-index .35s;
+ }
+}
+
+.xl {
+ width: 1200px;
+}
+
+.l {
+ width: 875px;
+}
+
+.md {
+ width: 650px;
+}
+
+.sm {
+ width: 500px;
+}
+
+.xsm {
+ width: 432px;
+}
diff --git a/components/modal/alert-modal.html b/components/modal/alert-modal.html
new file mode 100644
index 0000000..1ed72e8
--- /dev/null
+++ b/components/modal/alert-modal.html
@@ -0,0 +1,45 @@
+<div class="sdc-modal sm">
+ <div class="sdc-modal__wrapper sdc-modal-type-alert">
+ <div class="sdc-modal__header">
+ <div class="svg-icon-wrapper sdc-modal__icon sdc-modal__svg-use bottom">
+ <svg class="svg-icon __exclamationTriangleLine" version="1.1" id="exclamation-triangle-line_icon" x="0px" y="0px" viewBox="0 0 19.9 18" xml:space="preserve">
+ <g>
+ <path d="M17.6,18H2.4c-0.5,0-0.9-0.1-1.3-0.4c-0.5-0.3-0.9-0.8-1.1-1.4c-0.2-0.6-0.1-1.3,0.2-1.8l7.6-13c0.2-0.3,0.5-0.7,0.9-1
+ C9.3,0,10-0.1,10.6,0.1c0.6,0.2,1.1,0.6,1.4,1.2l7.5,13c0.2,0.4,0.4,0.8,0.4,1.3C19.9,16.9,18.9,18,17.6,18z M9.9,1
+ C9.7,1,9.4,1.1,9.2,1.2C9.1,1.3,8.9,1.6,8.7,1.8l-7.5,13C1,15.1,1,15.5,1,15.9c0.1,0.4,0.3,0.7,0.6,0.8C1.9,16.9,2.1,17,2.4,17
+ h15.1c0.9,0,1.4-0.7,1.4-1.4c0-0.2-0.1-0.5-0.2-0.7l0,0l-7.6-13c-0.2-0.4-0.5-0.6-0.8-0.7C10.2,1,10.1,1,9.9,1z"></path>
+ <g>
+ <g>
+ <g>
+ <path d="M10,10.4L10,10.4c-0.3,0-0.5-0.2-0.5-0.5l0-5.2c0-0.3,0.2-0.5,0.5-0.5l0,0c0.3,0,0.5,0.2,0.5,0.5l0,5.2
+ C10.5,10.2,10.2,10.4,10,10.4z"></path>
+ </g>
+ </g>
+ <g>
+ <g>
+ <path d="M10,14.7L10,14.7c-0.3,0-0.5-0.2-0.5-0.5l0-1c0-0.3,0.2-0.5,0.5-0.5l0,0c0.3,0,0.5,0.2,0.5,0.5l0,1
+ C10.5,14.5,10.2,14.7,10,14.7z"></path>
+ </g>
+ </g>
+ </g>
+ </g>
+ </svg>
+ </div>
+ <div class="title ">Title</div>
+ <div class="svg-icon-wrapper sdc-modal__close-button-svg sdc-modal__close-button clickable bottom">
+ <svg class="svg-icon __close" version="1.1" id="close_icon" x="0px" y="0px" viewBox="0 0 10.1 10.1" xml:space="preserve">
+ <g transform="translate(0,-952.36218)">
+ <path d="M0.5,952.4c-0.2,0-0.4,0.2-0.4,0.5c0,0.1,0.1,0.2,0.1,0.3l4.3,4.3l-4.3,4.3c-0.2,0.2-0.2,0.4,0,0.6c0.2,0.2,0.4,0.2,0.6,0
+ l0,0l4.3-4.4l4.3,4.3c0.2,0.2,0.4,0.2,0.6,0s0.2-0.4,0-0.6l0,0l-4.3-4.3l4.3-4.3c0.2-0.2,0.2-0.4,0-0.6c-0.1-0.1-0.2-0.1-0.4-0.1
+ c-0.1,0-0.2,0.1-0.3,0.1l-4.2,4.3l-4.3-4.3C0.8,952.4,0.6,952.4,0.5,952.4z"></path>
+ </g>
+ </svg>
+ </div>
+ </div>
+ <div class="sdc-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</div>
+ <div class="sdc-modal__footer">
+ <div><button class="sdc-button sdc-button__primary ">Ok</button></div>
+ </div>
+ </div>
+</div>
+<div class="modal-background"></div> \ No newline at end of file
diff --git a/components/modal/custom-modal.html b/components/modal/custom-modal.html
new file mode 100644
index 0000000..1011ca6
--- /dev/null
+++ b/components/modal/custom-modal.html
@@ -0,0 +1,27 @@
+<div class="sdc-modal md">
+ <div class="sdc-modal__wrapper sdc-modal-type-custom">
+ <div class="sdc-custom__header sdc-modal__header">
+ <div class="title ">Title</div>
+ <div class="svg-icon-wrapper sdc-modal__close-button-svg sdc-modal__close-button clickable bottom">
+ <svg class="svg-icon __close" version="1.1" id="close_icon" x="0px" y="0px" viewBox="0 0 10.1 10.1" xml:space="preserve">
+ <g transform="translate(0,-952.36218)">
+ <path d="M0.5,952.4c-0.2,0-0.4,0.2-0.4,0.5c0,0.1,0.1,0.2,0.1,0.3l4.3,4.3l-4.3,4.3c-0.2,0.2-0.2,0.4,0,0.6c0.2,0.2,0.4,0.2,0.6,0
+ l0,0l4.3-4.4l4.3,4.3c0.2,0.2,0.4,0.2,0.6,0s0.2-0.4,0-0.6l0,0l-4.3-4.3l4.3-4.3c0.2-0.2,0.2-0.4,0-0.6c-0.1-0.1-0.2-0.1-0.4-0.1
+ c-0.1,0-0.2,0.1-0.3,0.1l-4.2,4.3l-4.3-4.3C0.8,952.4,0.6,952.4,0.5,952.4z"></path>
+ </g>
+ </svg>
+ </div>
+ </div>
+ <div class="sdc-modal__content ">
+ <div>
+ <div class="sdc-input "><label class="sdc-input__label " for="input1">I am a label</label><input type="text" class="sdc-input__input " id="input1" name="input1" value="Default"></div>
+ <div class="sdc-input "><label class="sdc-input__label " for="input1">I am a label</label><input type="text" class="sdc-input__input " id="input1" name="input1" value="Default"></div>
+ <div class="sdc-input "><label class="sdc-input__label " for="input1">I am a label</label><input type="text" class="sdc-input__input " id="input1" name="input1" value="Default"></div>
+ </div>
+ </div>
+ <div class="sdc-modal__footer">
+ <div><button class="sdc-button sdc-button__primary ">Ok</button><button class="sdc-button sdc-button__secondary">Close</button></div>
+ </div>
+ </div>
+</div>
+<div class="modal-background"></div> \ No newline at end of file
diff --git a/components/modal/error-modal.html b/components/modal/error-modal.html
new file mode 100644
index 0000000..5a3b5fb
--- /dev/null
+++ b/components/modal/error-modal.html
@@ -0,0 +1,32 @@
+<div class="sdc-modal sm">
+ <div class="sdc-modal__wrapper sdc-modal-type-error">
+ <div class="sdc-modal__header">
+ <div class="svg-icon-wrapper sdc-modal__icon sdc-modal__svg-use bottom">
+ <svg class="svg-icon __error" viewBox="0 0 17 17">
+ <title>error</title>
+ <g id="Layer_2" data-name="Layer 2">
+ <g id="Layer_1-2" data-name="Layer 1">
+ <path d="M8.5,1A7.5,7.5,0,1,1,1,8.5,7.51,7.51,0,0,1,8.5,1m0-1A8.5,8.5,0,1,0,17,8.5,8.5,8.5,0,0,0,8.5,0Z"></path>
+ <polygon points="11.6 6.1 10.9 5.4 8.5 7.79 6.1 5.4 5.4 6.1 7.79 8.5 5.4 10.9 6.1 11.6 8.5 9.21 10.9 11.6 11.6 10.9 9.21 8.5 11.6 6.1"></polygon>
+ </g>
+ </g>
+ </svg>
+ </div>
+ <div class="title ">Title</div>
+ <div class="svg-icon-wrapper sdc-modal__close-button-svg sdc-modal__close-button clickable bottom">
+ <svg class="svg-icon __close" version="1.1" id="close_icon" x="0px" y="0px" viewBox="0 0 10.1 10.1" xml:space="preserve">
+ <g transform="translate(0,-952.36218)">
+ <path d="M0.5,952.4c-0.2,0-0.4,0.2-0.4,0.5c0,0.1,0.1,0.2,0.1,0.3l4.3,4.3l-4.3,4.3c-0.2,0.2-0.2,0.4,0,0.6c0.2,0.2,0.4,0.2,0.6,0
+ l0,0l4.3-4.4l4.3,4.3c0.2,0.2,0.4,0.2,0.6,0s0.2-0.4,0-0.6l0,0l-4.3-4.3l4.3-4.3c0.2-0.2,0.2-0.4,0-0.6c-0.1-0.1-0.2-0.1-0.4-0.1
+ c-0.1,0-0.2,0.1-0.3,0.1l-4.2,4.3l-4.3-4.3C0.8,952.4,0.6,952.4,0.5,952.4z"></path>
+ </g>
+ </svg>
+ </div>
+ </div>
+ <div class="sdc-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</div>
+ <div class="sdc-modal__footer">
+ <div><button class="sdc-button sdc-button__primary ">Ok</button></div>
+ </div>
+ </div>
+</div>
+<div class="modal-background"></div> \ No newline at end of file
diff --git a/components/modal/standard-modal.html b/components/modal/standard-modal.html
new file mode 100644
index 0000000..e367900
--- /dev/null
+++ b/components/modal/standard-modal.html
@@ -0,0 +1,46 @@
+<div class="sdc-modal sm">
+ <div class="sdc-modal__wrapper sdc-modal-type-info">
+ <div class="sdc-modal__header">
+ <div class="svg-icon-wrapper sdc-modal__icon sdc-modal__svg-use bottom">
+ <svg class="svg-icon __errorCircle" id="error-circle_icon" viewBox="0 0 16 16">
+ <title>
+ Asset 4
+ </title>
+ <g id="Layer_2" data-name="Layer 2">
+ <g id="Layer_1-2" data-name="Layer 1">
+ <path d="M8,0a8,8,0,1,0,8,8A8,8,0,0,0,8,0Zm.9,12.4H7.1V10.6H8.9Zm0-3.6H7.1V3.5H8.9Z">
+ </path>
+ </g>
+ </g>
+ </svg>
+ </div>
+ <div class="title ">
+ Standard Modal
+ </div>
+ <div class="svg-icon-wrapper sdc-modal__close-button-svg sdc-modal__close-button bottom">
+ <svg class="svg-icon __close" version="1.1" id="close_icon" x="0px" y="0px" viewBox="0 0 10.1 10.1" style="enable-background:new 0 0 10.1 10.1;" xml:space="preserve">
+ <g transform="translate(0,-952.36218)">
+ <path d="M0.5,952.4c-0.2,0-0.4,0.2-0.4,0.5c0,0.1,0.1,0.2,0.1,0.3l4.3,4.3l-4.3,4.3c-0.2,0.2-0.2,0.4,0,0.6c0.2,0.2,0.4,0.2,0.6,0
+ l0,0l4.3-4.4l4.3,4.3c0.2,0.2,0.4,0.2,0.6,0s0.2-0.4,0-0.6l0,0l-4.3-4.3l4.3-4.3c0.2-0.2,0.2-0.4,0-0.6c-0.1-0.1-0.2-0.1-0.4-0.1
+ c-0.1,0-0.2,0.1-0.3,0.1l-4.2,4.3l-4.3-4.3C0.8,952.4,0.6,952.4,0.5,952.4z">
+ </path>
+ </g>
+ </svg>
+ </div>
+ </div>
+ <div class="sdc-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
+ </div>
+ <div class="sdc-modal__footer">
+ <div>
+ <button class="sdc-button sdc-button__primary ">
+ Yes
+ </button>
+ <button class="sdc-button sdc-button__secondary ">
+ Close
+ </button>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="modal-background"></div>
diff --git a/components/notification/_notification.scss b/components/notification/_notification.scss
new file mode 100644
index 0000000..dafe8d4
--- /dev/null
+++ b/components/notification/_notification.scss
@@ -0,0 +1,59 @@
+@include mixin-keyframes-fade-in-vertically(-50px, 'keyframes-slide-notif-in');
+@include mixin-keyframes-fade-out-vertically(20px, 'keyframes-slide-notif-out');
+
+.sdc-notification {
+ position:relative;
+
+ .sdc-notification__wrapper {
+ padding: 10px;
+ margin-top:10px;
+ width: 212px;
+ animation: keyframes-slide-notif-in 1s;
+
+ &.fade-out__animated {
+ animation: keyframes-slide-notif-out 0.8s
+ }
+
+ &.type-info {
+ background-color: #0e90d2; }
+
+ &.type-error {
+ background-color: #dd514c; }
+
+ &.type-success {
+ background-color: #5eb95e; }
+
+ &.type-warn {
+ background-color: #f37b1d; }
+ }
+
+ .sdc-notification__content {
+ display:flex;
+ flex-direction:row;
+
+ .sdc-notification__icon {
+ flex: 0 0 auto;
+ height: 32px;
+ width: 32px;
+ margin: 0 14px 0 7px;
+ background: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%2382c355%3B%7D.cls-2%7Bfill%3Anone%3Bstroke%3A%23ebf5e4%3Bstroke-miterlimit%3A10%3B%7D%3C/style%3E%3C/defs%3E%3Ctitle%3Evicon%3C/title%3E%3Cg%20id%3D%22Layer_1%22%20data-name%3D%22Layer%201%22%3E%3Ccircle%20class%3D%22cls-1%22%20cx%3D%2216%22%20cy%3D%2216%22%20r%3D%2216%22/%3E%3C/g%3E%3Cg%20id%3D%22Layer_4%22%20data-name%3D%22Layer%204%22%3E%3Cpolyline%20class%3D%22cls-2%22%20points%3D%227.46%2017.43%2015.36%2021.74%2022.54%208.57%22/%3E%3C/g%3E%3C/svg%3E')
+ }
+
+ .sdc-notification__message {
+ flex: 1;
+ text-align: left;
+
+ .sdc-notification__title {
+ font-size:13px;
+ color: white;
+ }
+
+ .sdc-notification__text {
+ font-size: 12px;
+ color: white;
+ }
+ }
+
+ }
+
+}
diff --git a/components/notification/notification-info.html b/components/notification/notification-info.html
new file mode 100644
index 0000000..6eab4c0
--- /dev/null
+++ b/components/notification/notification-info.html
@@ -0,0 +1,3 @@
+<div class="sdc-notification">
+
+</div>
diff --git a/components/notifications-container/_notifications-container.scss b/components/notifications-container/_notifications-container.scss
new file mode 100644
index 0000000..7a7a907
--- /dev/null
+++ b/components/notifications-container/_notifications-container.scss
@@ -0,0 +1,8 @@
+.sdc-notification-container {
+
+
+ position:absolute;
+ top: 10px;
+ right: 10px;
+ width: 232px;
+}
diff --git a/components/panel/basic-panel.html b/components/panel/basic-panel.html
new file mode 100644
index 0000000..14e6461
--- /dev/null
+++ b/components/panel/basic-panel.html
@@ -0,0 +1,21 @@
+<div class="sdc-panel">
+ <h3>
+ Panel
+ </h3>
+ <div class="sdc-checkbox">
+ <label>
+ <input type="checkbox" class="sdc-checkbox__input" />
+ <span class="sdc-checkbox__label">
+ filter-item
+ </span>
+ </label>
+ </div>
+ <div class="sdc-checkbox ">
+ <label>
+ <input type="checkbox" class="sdc-checkbox__input" checked="" />
+ <span class="sdc-checkbox__label">
+ filter-item-checked
+ </span>
+ </label>
+ </div>
+</div> \ No newline at end of file
diff --git a/components/panel/panel.scss b/components/panel/panel.scss
new file mode 100644
index 0000000..921dd74
--- /dev/null
+++ b/components/panel/panel.scss
@@ -0,0 +1,8 @@
+.sdc-panel {
+ width: 280px;
+ overflow-y: auto;
+ height: 100%;
+ box-shadow: 1px 0px 4px 0px $light-gray;
+ background-color: $white;
+ padding: 0;
+} \ No newline at end of file
diff --git a/components/radio/_radio.scss b/components/radio/_radio.scss
new file mode 100644
index 0000000..9c51846
--- /dev/null
+++ b/components/radio/_radio.scss
@@ -0,0 +1,69 @@
+.sdc-radio {
+ line-height: 14px;
+
+ label {
+ position: relative;
+ display: block;
+ padding-left: 14px;
+ }
+
+ .sdc-radio__input {
+ appearance: none;
+ -moz-appearance: none;
+ -webkit-appearance: none;
+ position: absolute;
+ z-index: -1;
+ opacity: 0;
+
+ // Radio not checked
+ + .sdc-radio__label:before {
+ display: inline-block;
+ position: absolute;
+ left: 0;
+ top: 0;
+ content: "";
+ width: 14px;
+ height: 14px;
+ box-sizing: content-box;
+ background: no-repeat url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2214%22%20height%3D%2214%22%20viewBox%3D%220%200%2014%2014%22%3E%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Cpath%20fill%3D%22%23d2d2d2%22%20d%3D%22M7%2C14%20C3.13400675%2C14%200%2C10.8659932%200%2C7%20C0%2C3.13400675%203.13400675%2C0%207%2C0%20C8.35813029%2C0%209.62592397%2C0.386776975%2010.699241%2C1.0561909%20C12.6811805%2C2.29230086%2014%2C4.49213704%2014%2C7%20C14%2C10.8659932%2010.8659932%2C14%207%2C14%20Z%22%2F%3E%3Cpath%20fill%3D%22%23FFF%22%20d%3D%22M7%2C13%20C10.3137085%2C13%2013%2C10.3137085%2013%2C7%20C13%2C3.6862915%2010.3137085%2C1%207%2C1%20C3.6862915%2C1%201%2C3.6862915%201%2C7%20C1%2C10.3137085%203.6862915%2C13%207%2C13%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E');
+ }
+
+ // Radio disabled and not checked
+ &:disabled:not(:checked) {
+ + .sdc-radio__label:before {
+ background: no-repeat url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2214%22%20height%3D%2214%22%20viewBox%3D%220%200%2014%2014%22%3E%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Cpath%20fill%3D%22%23d2d2d2%22%20d%3D%22M7%2C14%20C3.13400675%2C14%200%2C10.8659932%200%2C7%20C0%2C3.13400675%203.13400675%2C0%207%2C0%20C8.35813029%2C0%209.62592397%2C0.386776975%2010.699241%2C1.0561909%20C12.6811805%2C2.29230086%2014%2C4.49213704%2014%2C7%20C14%2C10.8659932%2010.8659932%2C14%207%2C14%20Z%22%2F%3E%3Cpath%20fill%3D%22%23F2F2F2%22%20d%3D%22M7%2C13%20C10.3137085%2C13%2013%2C10.3137085%2013%2C7%20C13%2C3.6862915%2010.3137085%2C1%207%2C1%20C3.6862915%2C1%201%2C3.6862915%201%2C7%20C1%2C10.3137085%203.6862915%2C13%207%2C13%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E');
+ }
+ }
+
+ &:checked {
+ // Radio checked
+ + .sdc-radio__label:before {
+ background: no-repeat url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2214%22%20height%3D%2214%22%20viewBox%3D%220%200%2014%2014%22%3E%3Cg%20fill-rule%3D%22evenodd%22%3E%3Cpath%20fill%3D%22%23009fdb%22%20fill-rule%3D%22nonzero%22%20d%3D%22M7%2C14%20C3.13400675%2C14%200%2C10.8659932%200%2C7%20C0%2C3.13400675%203.13400675%2C0%207%2C0%20C10.8659932%2C0%2014%2C3.13400675%2014%2C7%20C14%2C10.8659932%2010.8659932%2C14%207%2C14%20Z%20M7%2C13.1764706%20C10.4111705%2C13.1764706%2013.1764706%2C10.4111705%2013.1764706%2C7%20C13.1764706%2C3.58882949%2010.4111705%2C0.823529412%207%2C0.823529412%20C3.58882949%2C0.823529412%200.823529412%2C3.58882949%200.823529412%2C7%20C0.823529412%2C10.4111705%203.58882949%2C13.1764706%207%2C13.1764706%20Z%22%2F%3E%3Ccircle%20fill%3D%22%23009fdb%22%20cx%3D%227%22%20cy%3D%227%22%20r%3D%224%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E');
+ }
+
+ // Radio disabled and checked
+ &:disabled {
+ + .sdc-radio__label:before {
+ background: no-repeat url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2214%22%20height%3D%2214%22%20viewBox%3D%220%200%2014%2014%22%3E%3Cg%20fill-rule%3D%22evenodd%22%3E%3Cpath%20fill%3D%22%23d2d2d2%22%20fill-rule%3D%22nonzero%22%20d%3D%22M7%2C14%20C3.13400675%2C14%200%2C10.8659932%200%2C7%20C0%2C3.13400675%203.13400675%2C0%207%2C0%20C10.8659932%2C0%2014%2C3.13400675%2014%2C7%20C14%2C10.8659932%2010.8659932%2C14%207%2C14%20Z%20M7%2C13.1764706%20C10.4111705%2C13.1764706%2013.1764706%2C10.4111705%2013.1764706%2C7%20C13.1764706%2C3.58882949%2010.4111705%2C0.823529412%207%2C0.823529412%20C3.58882949%2C0.823529412%200.823529412%2C3.58882949%200.823529412%2C7%20C0.823529412%2C10.4111705%203.58882949%2C13.1764706%207%2C13.1764706%20Z%22%2F%3E%3Ccircle%20fill%3D%22%23d2d2d2%22%20cx%3D%227%22%20cy%3D%227%22%20r%3D%224%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E');
+ }
+ }
+ }
+
+ &:not(:disabled) {
+ + .sdc-radio__label {
+ cursor: pointer;
+ }
+ }
+
+ &:disabled {
+ + .sdc-radio__label {
+ color: $gray;
+ }
+ }
+ }
+
+ .sdc-radio__label:not(:empty) {
+ padding-left: 14px;
+ @include body-1;
+ }
+}
diff --git a/components/radio/radio-checked.html b/components/radio/radio-checked.html
new file mode 100644
index 0000000..78283b3
--- /dev/null
+++ b/components/radio/radio-checked.html
@@ -0,0 +1,4 @@
+<div class="sdc-radio">
+ <input type="radio" name="grp1" checked class="sdc-radio__input" value="1">
+ <label class="sdc-radio__label">This is the radio label</label>
+</div>
diff --git a/components/radio/radio-disabled-checked.html b/components/radio/radio-disabled-checked.html
new file mode 100644
index 0000000..9ba6f0c
--- /dev/null
+++ b/components/radio/radio-disabled-checked.html
@@ -0,0 +1,4 @@
+<div class="sdc-radio">
+ <input type="radio" name="grp3" checked class="sdc-radio__input" value="1" disabled>
+ <label class="sdc-radio__label">This is the radio label</label>
+</div>
diff --git a/components/radio/radio-disabled.html b/components/radio/radio-disabled.html
new file mode 100644
index 0000000..332435f
--- /dev/null
+++ b/components/radio/radio-disabled.html
@@ -0,0 +1,4 @@
+<div class="sdc-radio">
+ <input type="radio" name="grp2" class="sdc-radio__input" value="1" disabled>
+ <label class="sdc-radio__label">This is the radio label</label>
+</div>
diff --git a/components/radio/radio-unchecked.html b/components/radio/radio-unchecked.html
new file mode 100644
index 0000000..6f6a00d
--- /dev/null
+++ b/components/radio/radio-unchecked.html
@@ -0,0 +1,4 @@
+<div class="sdc-radio">
+ <input type="radio" name="grp4" class="sdc-radio__input" value="1">
+ <label class="sdc-radio__label">This is the radio label</label>
+</div>
diff --git a/components/radioGroup/_radioGroup.scss b/components/radioGroup/_radioGroup.scss
new file mode 100644
index 0000000..6b33a79
--- /dev/null
+++ b/components/radioGroup/_radioGroup.scss
@@ -0,0 +1,20 @@
+.sdc-radio-group {
+ .sdc-radio-group__radios {
+ display: flex;
+ }
+ .sdc-radio-group__legend {
+ @include body-2-emphasis;
+ display: inline-block;
+ margin-bottom: 5px;
+ }
+ .sdc-radio__label {
+ @include body-1;
+ margin-right: 20px;
+ }
+ .vertical{
+ flex-direction: column;
+ .sdc-radio{
+ margin-bottom: 15px;
+ }
+ }
+}
diff --git a/components/radioGroup/radio-group-disabled.html b/components/radioGroup/radio-group-disabled.html
new file mode 100644
index 0000000..3cdedc0
--- /dev/null
+++ b/components/radioGroup/radio-group-disabled.html
@@ -0,0 +1,13 @@
+<div class='sdc-radio-group'>
+ <label class='sdc-radio-group__legend'>Group D</label>
+ <div class='sdc-radio-group__radios'>
+ <div class="sdc-radio">
+ <input type="radio" name="grp4" class="sdc-radio__input" value="1" disabled>
+ <label class="sdc-radio__label">option 1</label>
+ </div>
+ <div class="sdc-radio">
+ <input type="radio" name="grp4" class="sdc-radio__input" value="2" disabled>
+ <label class="sdc-radio__label">option 2</label>
+ </div>
+ </div>
+</div>
diff --git a/components/radioGroup/radio-group-no-title.html b/components/radioGroup/radio-group-no-title.html
new file mode 100644
index 0000000..76217fe
--- /dev/null
+++ b/components/radioGroup/radio-group-no-title.html
@@ -0,0 +1,12 @@
+<div class='sdc-radio-group'>
+ <div class='sdc-radio-group__radios'>
+ <div class="sdc-radio">
+ <input type="radio" name="grp5" class="sdc-radio__input" value="1">
+ <label class="sdc-radio__label">option 1</label>
+ </div>
+ <div class="sdc-radio">
+ <input type="radio" name="grp5" class="sdc-radio__input" value="2">
+ <label class="sdc-radio__label">option 2</label>
+ </div>
+ </div>
+</div>
diff --git a/components/radioGroup/radio-group-value.html b/components/radioGroup/radio-group-value.html
new file mode 100644
index 0000000..ac604a6
--- /dev/null
+++ b/components/radioGroup/radio-group-value.html
@@ -0,0 +1,13 @@
+<div class='sdc-radio-group'>
+ <label class='sdc-radio-group__legend'>Group B</label>
+ <div class='sdc-radio-group__radios'>
+ <div class="sdc-radio">
+ <input type="radio" name="grp2" checked class="sdc-radio__input" value="1">
+ <label class="sdc-radio__label">option 1</label>
+ </div>
+ <div class="sdc-radio">
+ <input type="radio" name="grp2" class="sdc-radio__input" value="2">
+ <label class="sdc-radio__label">option 2</label>
+ </div>
+ </div>
+</div>
diff --git a/components/radioGroup/radio-group.html b/components/radioGroup/radio-group.html
new file mode 100644
index 0000000..baa1444
--- /dev/null
+++ b/components/radioGroup/radio-group.html
@@ -0,0 +1,13 @@
+<div class='sdc-radio-group'>
+ <label class='sdc-radio-group__legend'>Group C</label>
+ <div class='sdc-radio-group__radios'>
+ <div class="sdc-radio">
+ <input type="radio" name="grp3" class="sdc-radio__input" value="1">
+ <label class="sdc-radio__label">option 1</label>
+ </div>
+ <div class="sdc-radio">
+ <input type="radio" name="grp3" class="sdc-radio__input" value="2">
+ <label class="sdc-radio__label">option 2</label>
+ </div>
+ </div>
+</div>
diff --git a/components/search-bar/_search-bar.scss b/components/search-bar/_search-bar.scss
new file mode 100644
index 0000000..3e2dfad
--- /dev/null
+++ b/components/search-bar/_search-bar.scss
@@ -0,0 +1,61 @@
+$inputHeight: 38px;
+.sdc-search-bar{
+ .search-bar-container{
+ display: flex;
+ align-items: flex-end;
+ .sdc-input-wrapper{
+ flex-grow: 1;
+ .sdc-input{
+ margin: 0;
+ .sdc-input__input{
+ border-bottom-right-radius: 0;
+ border-top-right-radius: 0;
+ }
+ }
+ }
+ .search-button{
+ width: $inputHeight;
+ height: $inputHeight - 2;
+ border: solid 1px $light-gray;
+ border-left: none;
+ background-color: $light-silver;
+ cursor: auto;
+ border-top-right-radius: 2px;
+ border-bottom-right-radius: 2px;
+
+ svg{
+ height: 20px;
+ width: 20px;
+ position: relative;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%,-50% );
+ path{
+ fill: $gray;
+ }
+ }
+ }
+
+ &.not-empty{
+ .sdc-input__input {
+ border-color: $blue;
+ }
+ .search-button{
+ background-color: $lighter-blue;
+ border-color: $blue;
+ cursor: pointer;
+ svg path{
+ fill: $blue;
+ }
+ &:hover {
+ background-color: $light-blue;
+ svg{
+ path{
+ fill: $white;
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/components/search-bar/search-bar-with-text.html b/components/search-bar/search-bar-with-text.html
new file mode 100644
index 0000000..f623c2f
--- /dev/null
+++ b/components/search-bar/search-bar-with-text.html
@@ -0,0 +1,17 @@
+<div class="sdc-search-bar">
+ <div class="search-bar-container not-empty">
+ <label class="sdc-input__label">search box example:</label>
+ <input class="sdc-input__input" type="text" name="undefined" placeholder="search text">
+ <span class="search-button magnify-button">
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+ <defs>
+ <path id="search-a" d="M2,8.5 C2,4.9 4.9,2 8.5,2 C12.1,2 15,4.9 15,8.5 C15,10.3 14.3,11.9 13.1,13.1 C11.9,14.3 10.3,15 8.5,15 C4.9,15 2,12.1 2,8.5 M19.7,18.3 L15.2,13.8 C16.3,12.4 17,10.5 17,8.5 C17,3.8 13.2,0 8.5,0 C3.8,0 0,3.8 0,8.5 C0,13.2 3.8,17 8.5,17 C10.5,17 12.3,16.3 13.8,15.2 L18.3,19.7 C18.5,19.9 18.8,20 19,20 C19.2,20 19.5,19.9 19.7,19.7 C20.1,19.3 20.1,18.7 19.7,18.3"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd" transform="translate(2 2)">
+ <use fill="#000" xlink:href="#search-a"/>
+ </g>
+ </svg>
+ </span>
+ </div>
+</div>
+
diff --git a/components/search-bar/search-bar.html b/components/search-bar/search-bar.html
new file mode 100644
index 0000000..d1b9171
--- /dev/null
+++ b/components/search-bar/search-bar.html
@@ -0,0 +1,16 @@
+<div class="sdc-search-bar">
+ <div class="search-bar-container">
+ <label class="sdc-input__label">search box example:</label>
+ <input class="sdc-input__input" type="text" name="undefined" placeholder="search text">
+ <span class="search-button magnify-button">
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+ <defs>
+ <path id="search-a" d="M2,8.5 C2,4.9 4.9,2 8.5,2 C12.1,2 15,4.9 15,8.5 C15,10.3 14.3,11.9 13.1,13.1 C11.9,14.3 10.3,15 8.5,15 C4.9,15 2,12.1 2,8.5 M19.7,18.3 L15.2,13.8 C16.3,12.4 17,10.5 17,8.5 C17,3.8 13.2,0 8.5,0 C3.8,0 0,3.8 0,8.5 C0,13.2 3.8,17 8.5,17 C10.5,17 12.3,16.3 13.8,15.2 L18.3,19.7 C18.5,19.9 18.8,20 19,20 C19.2,20 19.5,19.9 19.7,19.7 C20.1,19.3 20.1,18.7 19.7,18.3"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd" transform="translate(2 2)">
+ <use fill="#000" xlink:href="#search-a"/>
+ </g>
+ </svg>
+ </span>
+ </div>
+</div>
diff --git a/components/tabs/tabs-disabled.html b/components/tabs/tabs-disabled.html
new file mode 100644
index 0000000..5e67f2a
--- /dev/null
+++ b/components/tabs/tabs-disabled.html
@@ -0,0 +1,8 @@
+<div class="sdc-tabs sdc-tabs-header">
+ <ul class="sdc-tabs-list" role="tablist">
+ <li class="sdc-tab sdc-tab-active" role="tab">tab 1</li>
+ <li class="sdc-tab" role="tab" disabled>tab 2</li>
+ <li class="sdc-tab" role="tab" disabled>tab 3</li>
+ </ul>
+ <div class="sdc-tab-content" role="tabpanel"><div>This is the active tab content</div></div>
+</div>
diff --git a/components/tabs/tabs-header.html b/components/tabs/tabs-header.html
new file mode 100644
index 0000000..622dc32
--- /dev/null
+++ b/components/tabs/tabs-header.html
@@ -0,0 +1,8 @@
+<div class="sdc-tabs sdc-tabs-header">
+ <ul class="sdc-tabs-list" role="tablist">
+ <li class="sdc-tab sdc-tab-active" role="tab">tab 1</li>
+ <li class="sdc-tab" role="tab">tab 2</li>
+ <li class="sdc-tab" role="tab">tab 3</li>
+ </ul>
+ <div class="sdc-tab-content" role="tabpanel"><div>This is the active tab content</div></div>
+</div>
diff --git a/components/tabs/tabs-menu.html b/components/tabs/tabs-menu.html
new file mode 100644
index 0000000..753886f
--- /dev/null
+++ b/components/tabs/tabs-menu.html
@@ -0,0 +1,8 @@
+<div class="sdc-tabs sdc-tabs-menu">
+ <ul class="sdc-tabs-list" role="tablist">
+ <li class="sdc-tab sdc-tab-active" role="tab">tab 1</li>
+ <li class="sdc-tab" role="tab">tab 2</li>
+ <li class="sdc-tab" role="tab">tab 3</li>
+ </ul>
+ <div class="sdc-tab-content" role="tabpanel"><div>This is the active tab content</div></div>
+</div>
diff --git a/components/tabs/tabs.scss b/components/tabs/tabs.scss
new file mode 100644
index 0000000..f5df0ba
--- /dev/null
+++ b/components/tabs/tabs.scss
@@ -0,0 +1,35 @@
+.sdc-tabs {
+ .sdc-tab {
+ display: inline-block;
+ cursor: pointer;
+ text-transform: capitalize;
+ color: $dark-gray;
+ padding: 0px 10px 7px 10px;
+ margin-right: 20px;
+ &:last-child {
+ margin-right: 0;
+ }
+ &.sdc-tab-active {
+ color: $blue;
+ border-bottom: 2px solid $blue;
+ }
+ &[disabled] {
+ opacity: 0.3;
+ cursor: default;
+ }
+ }
+ &.sdc-tabs-header {
+ .sdc-tab {
+ @include heading-2;
+ }
+ }
+ &.sdc-tabs-menu {
+ .sdc-tab {
+ @include body-1;
+ padding: 0px 10px 4px 10px;
+ }
+ }
+ .sdc-tab-content {
+ margin-top: 30px;
+ }
+}
diff --git a/components/tag-cloud/_tag-cloud.scss b/components/tag-cloud/_tag-cloud.scss
new file mode 100644
index 0000000..6a94a10
--- /dev/null
+++ b/components/tag-cloud/_tag-cloud.scss
@@ -0,0 +1,116 @@
+.sdc-tag-cloud-new-item-field{
+ display: flex;
+ align-items: flex-end;
+ sdc-input{
+ flex-grow: 1;
+ .sdc-input{
+ margin-bottom: 0;
+ .sdc-input__input{
+ border-bottom-right-radius: 0;
+ border-top-right-radius: 0;
+ }
+ }
+ }
+ .not-empty{
+ .sdc-input__input {
+ border-color: $blue;
+ }
+
+ }
+ .error{
+ .sdc-input__input {
+ border: solid 1px $red;
+ color: $red;
+ outline: none;
+ }
+ }
+ .add-button{
+ cursor: pointer;
+ height: 36px;
+ width: 36px;
+ text-align: center;
+ background-color: $lighter-blue;
+ border: solid 1px $blue;
+ border-left: none;
+ border-top-right-radius: 2px;
+ &.disabled{
+ cursor: default;
+ background-color: $light-silver;
+ border-color: $light-gray;
+ .plus-icon svg g{
+ fill: $gray;
+ }
+ }
+ .plus-icon{
+ line-height: 46px;
+ svg{
+ height: 20px;
+ width: 20px;
+ g{
+ fill: $blue;
+ }
+ }
+ }
+ }
+
+ &.not-empty{
+ .add-button:hover{
+ background-color: $light-blue;
+ svg{
+ g{
+ fill: $white;
+ }
+ }
+ }
+ }
+}
+
+.sdc-list-container{
+ height: 120px;
+ overflow-y: auto;
+ border: solid 1px $light-gray;
+ border-top: none;
+ border-radius: 2px;
+ background-color: $white;
+ padding: 10px 10px 0 0;
+ .sdc-tag-item{
+ padding: 0 0 10px 10px;
+ display: inline-block;
+ .tag-item{
+ min-width: 100px;
+ background-color: $white;
+ border: solid 1px $light-gray;
+ border-radius: 20px;
+ height: 28px;
+ line-height: 28px;
+ padding: 0 10px;
+ color: $text-black;
+ @include body-3;
+ &.view-only{
+ border-color: $silver;
+ }
+ .delete-item{
+ cursor: pointer;
+ padding-left: 10px;
+ float: right;
+ svg{
+ height: 12px;
+ width: 12px;
+ margin-top: 8px;
+ g{
+ fill: $dark-gray;
+ }
+ }
+ }
+ &:hover:not(.view-only){
+ background-color: $lighter-blue;
+ border-color: $lighter-blue;
+ .delete-item{
+ svg g{
+ fill: $blue;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/components/tag-cloud/disabled-list.html b/components/tag-cloud/disabled-list.html
new file mode 100644
index 0000000..6091525
--- /dev/null
+++ b/components/tag-cloud/disabled-list.html
@@ -0,0 +1,31 @@
+<div class="sdc-tag-cloud-new-item-field">
+ <div class="sdc-input">
+ <label class="sdc-input__label">Please Enter value</label>
+ <input class="sdc-input__input disabled" type="text" name="undefined" placeholder="Type a value and then click enter or '+'" disabled="disabled">
+ </div>
+ <div class="add-button disabled">
+ <span class="plus-icon">
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+ <defs>
+ <path id="add-a" d="M15,7 L9,7 L9,1 C9,0.4 8.6,0 8,0 C7.4,0 7,0.4 7,1 L7,7 L1,7 C0.4,7 0,7.4 0,8 C0,8.6 0.4,9 1,9 L7,9 L7,15 C7,15.6 7.4,16 8,16 C8.6,16 9,15.6 9,15 L9,9 L15,9 C15.6,9 16,8.6 16,8 C16,7.4 15.6,7 15,7"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd" transform="translate(4 4)">
+ <use xlink:href="#add-a"/>
+ </g>
+ </svg>
+ </span>
+ </div>
+</div>
+<div class="sdc-list-container">
+ <div class="sdc-tag-item">
+ <div class="tag-item view-only">
+ <span>aaa</span>
+ </div>
+ </div>
+
+ <div class="sdc-tag-item">
+ <div class="tag-item view-only">
+ <span>bbb</span>
+ </div>
+ </div>
+</div>
diff --git a/components/tag-cloud/list-with-active-add-button.html b/components/tag-cloud/list-with-active-add-button.html
new file mode 100644
index 0000000..8bde59f
--- /dev/null
+++ b/components/tag-cloud/list-with-active-add-button.html
@@ -0,0 +1,50 @@
+<div class="sdc-tag-cloud-new-item-field">
+ <div class="sdc-input">
+ <label class="sdc-input__label">Please Enter value</label>
+ <input class="sdc-input__input" type="text" name="undefined" placeholder="Type a value and then click enter or '+'">
+ </div>
+ <div class="add-button">
+ <span class="plus-icon">
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+ <defs>
+ <path id="add-a" d="M15,7 L9,7 L9,1 C9,0.4 8.6,0 8,0 C7.4,0 7,0.4 7,1 L7,7 L1,7 C0.4,7 0,7.4 0,8 C0,8.6 0.4,9 1,9 L7,9 L7,15 C7,15.6 7.4,16 8,16 C8.6,16 9,15.6 9,15 L9,9 L15,9 C15.6,9 16,8.6 16,8 C16,7.4 15.6,7 15,7"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd" transform="translate(4 4)">
+ <use xlink:href="#add-a"/>
+ </g>
+ </svg>
+ </span>
+ </div>
+</div>
+<div class="sdc-list-container">
+ <div class="sdc-tag-item">
+ <div class="tag-item">
+ <span>aaa</span>
+ <span class="delete-item">
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+ <defs>
+ <path id="close-a" d="M13.5996,12 L19.6576,5.942 C20.1146,5.485 20.1146,4.8 19.6576,4.343 C19.2006,3.886 18.5146,3.886 18.0576,4.343 L11.9996,10.4 L5.9426,4.343 C5.4856,3.886 4.7996,3.886 4.3426,4.343 C3.8856,4.8 3.8856,5.485 4.3426,5.942 L10.4006,12 L4.3426,18.058 C3.8856,18.515 3.8856,19.2 4.3426,19.657 C4.5716,19.886 4.7996,20 5.1426,20 C5.4856,20 5.7136,19.886 5.9426,19.657 L11.9996,13.6 L18.0576,19.657 C18.2866,19.886 18.6286,20 18.8576,20 C19.0856,20 19.4286,19.886 19.6576,19.657 C20.1146,19.2 20.1146,18.515 19.6576,18.058 L13.5996,12 Z"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd">
+ <use xlink:href="#close-a"/>
+ </g>
+ </svg>
+ </span>
+ </div>
+ </div>
+ <div class="sdc-tag-item">
+ <div class="tag-item">
+ <span>bbb</span>
+ <span class="delete-item">
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+ <defs>
+ <path id="close-a" d="M13.5996,12 L19.6576,5.942 C20.1146,5.485 20.1146,4.8 19.6576,4.343 C19.2006,3.886 18.5146,3.886 18.0576,4.343 L11.9996,10.4 L5.9426,4.343 C5.4856,3.886 4.7996,3.886 4.3426,4.343 C3.8856,4.8 3.8856,5.485 4.3426,5.942 L10.4006,12 L4.3426,18.058 C3.8856,18.515 3.8856,19.2 4.3426,19.657 C4.5716,19.886 4.7996,20 5.1426,20 C5.4856,20 5.7136,19.886 5.9426,19.657 L11.9996,13.6 L18.0576,19.657 C18.2866,19.886 18.6286,20 18.8576,20 C19.0856,20 19.4286,19.886 19.6576,19.657 C20.1146,19.2 20.1146,18.515 19.6576,18.058 L13.5996,12 Z"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd">
+ <use xlink:href="#close-a"/>
+ </g>
+ </svg>
+ </span>
+ </div>
+ </div>
+</div>
diff --git a/components/tag-cloud/list-with-some-read-only-items.html b/components/tag-cloud/list-with-some-read-only-items.html
new file mode 100644
index 0000000..0db7a07
--- /dev/null
+++ b/components/tag-cloud/list-with-some-read-only-items.html
@@ -0,0 +1,61 @@
+<div class="sdc-tag-cloud-new-item-field">
+ <div class="sdc-input">
+ <label class="sdc-input__label">Please Enter value</label>
+ <input class="sdc-input__input" type="text" name="undefined" placeholder="Type a value and then click enter or '+'">
+ </div>
+
+ <div class="add-button disabled">
+ <span class="plus-icon">
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+ <defs>
+ <path id="add-a" d="M15,7 L9,7 L9,1 C9,0.4 8.6,0 8,0 C7.4,0 7,0.4 7,1 L7,7 L1,7 C0.4,7 0,7.4 0,8 C0,8.6 0.4,9 1,9 L7,9 L7,15 C7,15.6 7.4,16 8,16 C8.6,16 9,15.6 9,15 L9,9 L15,9 C15.6,9 16,8.6 16,8 C16,7.4 15.6,7 15,7"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd" transform="translate(4 4)">
+ <use xlink:href="#add-a"/>
+ </g>
+ </svg>
+ </span>
+ </div>
+</div>
+<div class="sdc-list-container">
+ <div class="sdc-tag-item">
+ <div class="tag-item">
+ <span>aaa</span>
+ <span class="delete-item">
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+ <defs>
+ <path id="close-a" d="M13.5996,12 L19.6576,5.942 C20.1146,5.485 20.1146,4.8 19.6576,4.343 C19.2006,3.886 18.5146,3.886 18.0576,4.343 L11.9996,10.4 L5.9426,4.343 C5.4856,3.886 4.7996,3.886 4.3426,4.343 C3.8856,4.8 3.8856,5.485 4.3426,5.942 L10.4006,12 L4.3426,18.058 C3.8856,18.515 3.8856,19.2 4.3426,19.657 C4.5716,19.886 4.7996,20 5.1426,20 C5.4856,20 5.7136,19.886 5.9426,19.657 L11.9996,13.6 L18.0576,19.657 C18.2866,19.886 18.6286,20 18.8576,20 C19.0856,20 19.4286,19.886 19.6576,19.657 C20.1146,19.2 20.1146,18.515 19.6576,18.058 L13.5996,12 Z"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd">
+ <use xlink:href="#close-a"/>
+ </g>
+ </svg>
+ </span>
+ </div>
+ </div>
+ <div class="sdc-tag-item">
+ <div class="tag-item view-only">
+ <span>bbb</span>
+ </div>
+ </div>
+ <div class="sdc-tag-item">
+ <div class="tag-item">
+ <span>ccc</span>
+ <span class="delete-item">
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+ <defs>
+ <path id="close-a" d="M13.5996,12 L19.6576,5.942 C20.1146,5.485 20.1146,4.8 19.6576,4.343 C19.2006,3.886 18.5146,3.886 18.0576,4.343 L11.9996,10.4 L5.9426,4.343 C5.4856,3.886 4.7996,3.886 4.3426,4.343 C3.8856,4.8 3.8856,5.485 4.3426,5.942 L10.4006,12 L4.3426,18.058 C3.8856,18.515 3.8856,19.2 4.3426,19.657 C4.5716,19.886 4.7996,20 5.1426,20 C5.4856,20 5.7136,19.886 5.9426,19.657 L11.9996,13.6 L18.0576,19.657 C18.2866,19.886 18.6286,20 18.8576,20 C19.0856,20 19.4286,19.886 19.6576,19.657 C20.1146,19.2 20.1146,18.515 19.6576,18.058 L13.5996,12 Z"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd">
+ <use xlink:href="#close-a"/>
+ </g>
+ </svg>
+ </span>
+ </div>
+ </div>
+ <tag class="sdc-tag-item">
+ <div class="tag-item view-only">
+ <span>ddd</span>
+ </div>
+ </tag>
+</div>
diff --git a/components/tag-cloud/list-with-unique-error.html b/components/tag-cloud/list-with-unique-error.html
new file mode 100644
index 0000000..14de80c
--- /dev/null
+++ b/components/tag-cloud/list-with-unique-error.html
@@ -0,0 +1,52 @@
+<div class="sdc-tag-cloud-new-item-field">
+ <div class="sdc-input">
+ <label class="sdc-input__label">Please Enter value</label>
+ <input class="sdc-input__input" type="text" name="undefined" placeholder="Type a value and then click enter or '+'">
+ </div>
+ <div class="add-button disabled">
+ <span class="plus-icon">
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+ <defs>
+ <path id="add-a" d="M15,7 L9,7 L9,1 C9,0.4 8.6,0 8,0 C7.4,0 7,0.4 7,1 L7,7 L1,7 C0.4,7 0,7.4 0,8 C0,8.6 0.4,9 1,9 L7,9 L7,15 C7,15.6 7.4,16 8,16 C8.6,16 9,15.6 9,15 L9,9 L15,9 C15.6,9 16,8.6 16,8 C16,7.4 15.6,7 15,7"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd" transform="translate(4 4)">
+ <use xlink:href="#add-a"/>
+ </g>
+ </svg>
+ </span>
+ </div>
+</div>
+<div class="sdc-list-container">
+ <div class="sdc-tag-item">
+ <div class="tag-item">
+ <span>aaa</span>
+ <span class="delete-item">
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+ <defs>
+ <path id="close-a" d="M13.5996,12 L19.6576,5.942 C20.1146,5.485 20.1146,4.8 19.6576,4.343 C19.2006,3.886 18.5146,3.886 18.0576,4.343 L11.9996,10.4 L5.9426,4.343 C5.4856,3.886 4.7996,3.886 4.3426,4.343 C3.8856,4.8 3.8856,5.485 4.3426,5.942 L10.4006,12 L4.3426,18.058 C3.8856,18.515 3.8856,19.2 4.3426,19.657 C4.5716,19.886 4.7996,20 5.1426,20 C5.4856,20 5.7136,19.886 5.9426,19.657 L11.9996,13.6 L18.0576,19.657 C18.2866,19.886 18.6286,20 18.8576,20 C19.0856,20 19.4286,19.886 19.6576,19.657 C20.1146,19.2 20.1146,18.515 19.6576,18.058 L13.5996,12 Z"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd">
+ <use xlink:href="#close-a"/>
+ </g>
+ </svg>
+ </span>
+ </div>
+ </div>
+ <div class="sdc-tag-item">
+ <div class="tag-item">
+ <span>bbb</span>
+ <span class="delete-item">
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+ <defs>
+ <path id="close-a" d="M13.5996,12 L19.6576,5.942 C20.1146,5.485 20.1146,4.8 19.6576,4.343 C19.2006,3.886 18.5146,3.886 18.0576,4.343 L11.9996,10.4 L5.9426,4.343 C5.4856,3.886 4.7996,3.886 4.3426,4.343 C3.8856,4.8 3.8856,5.485 4.3426,5.942 L10.4006,12 L4.3426,18.058 C3.8856,18.515 3.8856,19.2 4.3426,19.657 C4.5716,19.886 4.7996,20 5.1426,20 C5.4856,20 5.7136,19.886 5.9426,19.657 L11.9996,13.6 L18.0576,19.657 C18.2866,19.886 18.6286,20 18.8576,20 C19.0856,20 19.4286,19.886 19.6576,19.657 C20.1146,19.2 20.1146,18.515 19.6576,18.058 L13.5996,12 Z"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd">
+ <use xlink:href="#close-a"/>
+ </g>
+ </svg>
+ </span>
+ </div>
+ </div>
+</div>
+<div class="error-message">This value is already in the list</div>
+
diff --git a/components/tag-cloud/simple-list.html b/components/tag-cloud/simple-list.html
new file mode 100644
index 0000000..075751f
--- /dev/null
+++ b/components/tag-cloud/simple-list.html
@@ -0,0 +1,50 @@
+<div class="sdc-tag-cloud-new-item-field">
+ <div class="sdc-input">
+ <label class="sdc-input__label">Please Enter value</label>
+ <input class="sdc-input__input" type="text" name="undefined" placeholder="Type a value and then click enter or '+'">
+ </div>
+ <div class="add-button disabled">
+ <span class="plus-icon">
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+ <defs>
+ <path id="add-a" d="M15,7 L9,7 L9,1 C9,0.4 8.6,0 8,0 C7.4,0 7,0.4 7,1 L7,7 L1,7 C0.4,7 0,7.4 0,8 C0,8.6 0.4,9 1,9 L7,9 L7,15 C7,15.6 7.4,16 8,16 C8.6,16 9,15.6 9,15 L9,9 L15,9 C15.6,9 16,8.6 16,8 C16,7.4 15.6,7 15,7"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd" transform="translate(4 4)">
+ <use xlink:href="#add-a"/>
+ </g>
+ </svg>
+ </span>
+ </div>
+</div>
+<div class="sdc-list-container">
+ <div class="sdc-tag-item">
+ <div class="tag-item">
+ <span>aaa</span>
+ <span class="delete-item">
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+ <defs>
+ <path id="close-a" d="M13.5996,12 L19.6576,5.942 C20.1146,5.485 20.1146,4.8 19.6576,4.343 C19.2006,3.886 18.5146,3.886 18.0576,4.343 L11.9996,10.4 L5.9426,4.343 C5.4856,3.886 4.7996,3.886 4.3426,4.343 C3.8856,4.8 3.8856,5.485 4.3426,5.942 L10.4006,12 L4.3426,18.058 C3.8856,18.515 3.8856,19.2 4.3426,19.657 C4.5716,19.886 4.7996,20 5.1426,20 C5.4856,20 5.7136,19.886 5.9426,19.657 L11.9996,13.6 L18.0576,19.657 C18.2866,19.886 18.6286,20 18.8576,20 C19.0856,20 19.4286,19.886 19.6576,19.657 C20.1146,19.2 20.1146,18.515 19.6576,18.058 L13.5996,12 Z"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd">
+ <use xlink:href="#close-a"/>
+ </g>
+ </svg>
+ </span>
+ </div>
+ </div>
+ <div class="sdc-tag-item">
+ <div class="tag-item">
+ <span>bbb</span>
+ <span class="delete-item">
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+ <defs>
+ <path id="close-a" d="M13.5996,12 L19.6576,5.942 C20.1146,5.485 20.1146,4.8 19.6576,4.343 C19.2006,3.886 18.5146,3.886 18.0576,4.343 L11.9996,10.4 L5.9426,4.343 C5.4856,3.886 4.7996,3.886 4.3426,4.343 C3.8856,4.8 3.8856,5.485 4.3426,5.942 L10.4006,12 L4.3426,18.058 C3.8856,18.515 3.8856,19.2 4.3426,19.657 C4.5716,19.886 4.7996,20 5.1426,20 C5.4856,20 5.7136,19.886 5.9426,19.657 L11.9996,13.6 L18.0576,19.657 C18.2866,19.886 18.6286,20 18.8576,20 C19.0856,20 19.4286,19.886 19.6576,19.657 C20.1146,19.2 20.1146,18.515 19.6576,18.058 L13.5996,12 Z"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd">
+ <use xlink:href="#close-a"/>
+ </g>
+ </svg>
+ </span>
+ </div>
+ </div>
+</div>
diff --git a/components/tile/_tile.scss b/components/tile/_tile.scss
new file mode 100644
index 0000000..80629cf
--- /dev/null
+++ b/components/tile/_tile.scss
@@ -0,0 +1,172 @@
+.sdc-tile {
+ $tile-full-width: 204px;
+ $tile-full-height: 204px;
+ $tile-padding: 10px;
+
+ $header-height: $body-font-1;
+ $footer-height: 23px;
+ $content-height: 100%;
+
+ width: $tile-full-width;
+ height: $tile-full-height;
+
+ padding: $tile-padding;
+ border: 1px solid $silver;
+ @include border-radius(2px);
+ @include box-sizing;
+
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+
+ position: relative;
+ cursor: pointer;
+ user-select: none;
+
+ background: $white;
+ color: $text-black;
+ fill: $dark-gray;
+ transition: box-shadow 0.3s ease-in-out;
+ @include body-3;
+ @include box-shadow(0 1px 4px 0 rgba($text-black, 0.06));
+
+ &:hover {
+ border-color: $light-gray;
+ @include box-shadow( 0 10px 30px 0 rgba($text-black, 0.25));
+ }
+
+ .blue {
+ color: $blue;
+ fill: $blue;
+ }
+
+ .purple {
+ color: $purple;
+ fill: $purple;
+ }
+
+ .centered {
+ &.sdc-tile-footer, .sdc-tile-info-line {
+ text-align: center;
+ }
+ }
+
+ .sdc-tile-header {
+ height: 1.1em;
+ line-height: 1em;
+ @include ellipsis($display: block);
+
+ font-size: $body-font-1;
+ text-transform: uppercase;
+ }
+
+ .sdc-tile-content {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ height: $content-height;
+
+ .sdc-tile-content-icon {
+ margin-top: 27px;
+ text-align: center;
+
+ svg {
+ width: 50px;
+ height: 50px;
+
+ &.__vsp {
+ width: 60px;
+ height: 40px;
+ }
+ &.__vlm {
+ width: 45px;
+ height: 53px;
+ }
+ &.__vendor {
+ width: 53px;
+ height: 47px;
+ }
+ }
+ }
+
+ .sdc-tile-content-info {
+ display: flex;
+ flex-direction: column;
+
+ .sdc-tile-info-line {
+ text-transform: capitalize;
+ @include ellipsis($display: inline-block);
+
+ button {
+ height: 1.67em;
+ width: initial;
+ margin-bottom: 5px;
+ margin-top: 1px;
+ padding: 0 8px;
+ font-size: inherit;
+ }
+ &.supertitle {
+ height: 1.1em;
+ line-height: 1.2;
+ color: $gray;
+ }
+ &.title {
+ height: 1.6em;
+ line-height: 1.8;
+ color: $text-black;
+ @include heading-5;
+ }
+ &.subtitle {
+ height: 1.5em;
+ line-height: 1.6;
+ color: $dark-gray;
+ }
+ &:last-child {
+ margin-bottom: 4px;
+ }
+ }
+ }
+ }
+
+ .sdc-tile-footer {
+ height: $footer-height;
+ @include box-sizing;
+
+ border-top: 1px solid $silver;
+ padding-top: 8px;
+
+ color: $dark-gray;
+ fill: $dark-gray;
+ text-transform: capitalize;
+
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+
+ .sdc-tile-footer-cell {
+ &:first-child {
+ @include ellipsis;
+ }
+ svg{
+ width: 20px;
+ height: 12px;
+ }
+ button {
+ width: initial;
+ height: initial;
+ @include body-2;
+
+ .svg-icon-wrapper {
+ .svg-icon-label {
+ font-size: inherit;
+ }
+ svg {
+ width: 9px;
+ height: 9px;
+ }
+ }
+ }
+ }
+
+ }
+}
diff --git a/components/tile/tile-without-footer.html b/components/tile/tile-without-footer.html
new file mode 100644
index 0000000..514a19e
--- /dev/null
+++ b/components/tile/tile-without-footer.html
@@ -0,0 +1,14 @@
+<div class="sdc-tile">
+ <div class="sdc-tile-header blue">Header</div>
+ <div class="sdc-tile-content">
+ <div class="sdc-tile-content-icon blue">
+ <div class="svg-icon-wrapper">
+ <!-- insert SVG -->
+ </div>
+ </div>
+ <div class="sdc-tile-content-info">
+ <div class="sdc-tile-info-line supertitle">Supertitle</div>
+ <div class="sdc-tile-info-line title">Title</div>
+ </div>
+ </div>
+</div>
diff --git a/components/tile/vendor-tile.html b/components/tile/vendor-tile.html
new file mode 100644
index 0000000..ede3fbf
--- /dev/null
+++ b/components/tile/vendor-tile.html
@@ -0,0 +1,26 @@
+<div class="sdc-tile">
+ <div class="sdc-tile-header"></div>
+ <div class="sdc-tile-content">
+ <div class="sdc-tile-content-icon dark-gray">
+ <div class="svg-icon-wrapper">
+ <!-- insert SVG -->
+ </div>
+ </div>
+ <div class="sdc-tile-content-info centered">
+ <div class="sdc-tile-info-line title">Vendor Name</div>
+ <div class="sdc-tile-info-line">
+ <button class="sdc-button sdc-button-outline-rounded sdc-button__dark-gray">100 VSPs</button>
+ </div>
+ </div>
+ </div>
+ <div class="sdc-tile-footer centered">
+ <span class="sdc-tile-footer-cell">
+ <button class="sdc-button sdc-button-link sdc-button__primary sdc-button__with-icon">
+ <div class="svg-icon-wrapper sdc-button-icon right">
+ <!-- insert SVG -->
+ <span class="svg-icon-label sdc-button-label">Create new VSP</span>
+ </div>
+ </button>
+ </span>
+ </div>
+</div>
diff --git a/components/tile/vfc-tile.html b/components/tile/vfc-tile.html
new file mode 100644
index 0000000..7b4753e
--- /dev/null
+++ b/components/tile/vfc-tile.html
@@ -0,0 +1,17 @@
+<div class="sdc-tile">
+ <div class="sdc-tile-header purple">VFC</div>
+ <div class="sdc-tile-content">
+ <div class="sdc-tile-content-icon">
+ <div class="svg-icon-wrapper">
+ <!-- insert SVG -->
+ </div>
+ </div>
+ <div class="sdc-tile-content-info">
+ <div class="sdc-tile-info-line title">Title</div>
+ <div class="sdc-tile-info-line subtitle">V 1.0</div>
+ </div>
+ </div>
+ <div class="sdc-tile-footer">
+ <span class="sdc-tile-footer-cell">Certified</span>
+ </div>
+</div>
diff --git a/components/tile/vlm-tile.html b/components/tile/vlm-tile.html
new file mode 100644
index 0000000..be629a1
--- /dev/null
+++ b/components/tile/vlm-tile.html
@@ -0,0 +1,22 @@
+<div class="sdc-tile">
+ <div class="sdc-tile-header purple">VLM</div>
+ <div class="sdc-tile-content">
+ <div class="sdc-tile-content-icon purple">
+ <div class="svg-icon-wrapper">
+ <!-- insert SVG -->
+ </div>
+ </div>
+ <div class="sdc-tile-content-info">
+ <div class="sdc-tile-info-line title">VLM Name</div>
+ </div>
+ </div>
+ <div class="sdc-tile-footer">
+ <span class="sdc-tile-footer-cell">Certified</span>
+ <span class="sdc-tile-footer-cell">
+ <div class="svg-icon-wrapper left">
+ <!-- insert SVG -->
+ <span class="svg-icon-label">Owner</span>
+ </div>
+ </span>
+ </div>
+</div>
diff --git a/components/tile/vsp-tile.html b/components/tile/vsp-tile.html
new file mode 100644
index 0000000..1a3dc1d
--- /dev/null
+++ b/components/tile/vsp-tile.html
@@ -0,0 +1,17 @@
+<div class="sdc-tile">
+ <div class="sdc-tile-header blue">VSP</div>
+ <div class="sdc-tile-content">
+ <div class="sdc-tile-content-icon blue">
+ <div class="svg-icon-wrapper">
+ <!-- insert SVG -->
+ </div>
+ </div>
+ <div class="sdc-tile-content-info">
+ <div class="sdc-tile-info-line supertitle">VLM</div>
+ <div class="sdc-tile-info-line title">VSP Name</div>
+ </div>
+ </div>
+ <div class="sdc-tile-footer">
+ <span class="sdc-tile-footer-cell">Draft</span>
+ </div>
+</div>
diff --git a/components/tooltip/_tooltip.scss b/components/tooltip/_tooltip.scss
new file mode 100644
index 0000000..3f255ed
--- /dev/null
+++ b/components/tooltip/_tooltip.scss
@@ -0,0 +1,124 @@
+/* Tooltip animation */
+@keyframes animation-fade-in-from-bottom {
+ from {
+ transform: translateY(10px);
+ opacity: 0;
+ }
+ to {
+ transform: translateY(0px);
+ opacity: 1;
+ }
+}
+
+/* Tooltop styles */
+.sdc-tooltip {
+ @include base-font-regular;
+ line-height: 14px;
+ font-size: 12px;
+ max-width: 223px;
+ background-color: $black;
+ color: $white;
+ text-align: left;
+ border-radius: 2px;
+ padding: 5px 11px;
+ position: absolute;
+ z-index: 1000;
+ display: block;
+ opacity: 0;
+ transition: opacity 300ms;
+ border: solid 1px $black;
+ animation: animation-fade-in-from-bottom .75s ease-in-out; /* tooltip animation */
+}
+
+.sdc-tooltip-show {
+ opacity: 1;
+}
+
+.sdc-tooltip::after {
+ content: "";
+ position: absolute;
+ border-style: solid;
+}
+
+.sdc-tooltip-top::after {
+ top: 100%;
+ left: 10px;
+ margin-left: -5px;
+ border-width: 5px;
+ border-color: $black transparent transparent transparent;
+}
+.sdc-tooltip-top-right__bottom::after {
+ right: 10px;
+ left:auto;
+}
+.sdc-tooltip-top-center__middle::after {
+ left: 50%;
+}
+
+.sdc-tooltip-bottom::after {
+ bottom: 100%;
+ left: 10px;
+ margin-left: -5px;
+ border-width: 5px;
+ border-color: transparent transparent $black transparent;
+}
+.sdc-tooltip-bottom-right__bottom::after {
+ right: 10px;
+ left:auto;
+}
+.sdc-tooltip-bottom-center__middle::after {
+ left: 50%;
+}
+
+.sdc-tooltip-left::after {
+ top: 10px; /*50%;*/
+ left: 100%;
+ margin-top: -5px;
+ border-width: 5px;
+ border-color: transparent transparent transparent $black;
+}
+.sdc-tooltip-left-right__bottom::after {
+ bottom: 10px;
+ top: auto;
+}
+.sdc-tooltip-left-center__middle::after {
+ top: 50%
+}
+
+.sdc-tooltip-right::after {
+ top: 10px;
+ right: 100%;
+ margin-top: -5px;
+ border-width: 5px;
+ border-color: transparent $black transparent transparent;
+}
+.sdc-tooltip-right-right__bottom::after {
+ bottom: 10px;
+ top: auto;
+}
+.sdc-tooltip-right-center__middle::after {
+ top: 50%
+}
+
+/* Tooltip template */
+.sdc-tooltip-template-title {
+ @include base-font-regular;
+ font-size: 12px;
+ font-weight: normal;
+ background-color: $black;
+ color: $white; /* silver */
+}
+
+.sdc-tooltip-template-big-title {
+ font-size: 20px;
+ line-height: 24px;
+}
+
+.sdc-tooltip-template-content {
+ @include base-font-regular;
+ font-size: 12px;
+ font-weight: normal;
+ background-color: $black;
+ color: $white;
+ line-height: 14px;
+}
diff --git a/components/validation/_validation.scss b/components/validation/_validation.scss
new file mode 100644
index 0000000..771a242
--- /dev/null
+++ b/components/validation/_validation.scss
@@ -0,0 +1,9 @@
+.sdc-validation {
+
+ font-size: $body-font-4;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ margin-top: 10px;
+
+}
diff --git a/demo/.gitignore b/demo/.gitignore
new file mode 100644
index 0000000..7788a08
--- /dev/null
+++ b/demo/.gitignore
@@ -0,0 +1,7 @@
+# See http://help.github.com/ignore-files/ for more about ignoring files.
+
+/dist
+/tmp
+/node_modules
+npm-debug.log*
+Thumbs.db
diff --git a/demo/README.md b/demo/README.md
new file mode 100644
index 0000000..6a478d8
--- /dev/null
+++ b/demo/README.md
@@ -0,0 +1,35 @@
+# Local DEMO
+
+### How to compile
+Go to <b>root</b> folder (sdc-ui) and run: `npm run build`
+This will compile all scss files and will copy generated style.css and assets folder to gen folder inside demo project.
+
+### How to run
+Go to <b>demo</b> and run: `npm start`
+This will open the default browser at port 2900.
+
+### How to build component HTML for DEMO
+<ul>
+ <li>Create new HTML file for the component and put it in components folder</li>
+ <li>In the top of the HTML add <div class='component'>Name of component</div></li>
+ <li>Inside the HTML for each type of component add header <h3>sub component name</h3></li>
+ <li>
+ In order to show the HTML of the component to the user, add <b>data-code</b> attribute to the outerHTML of the component.
+ This component outerHTML will be copied and will be shown highlighted below the component.
+ <br>You can also use <b>data-code-ref</b> and <b>data-code-id</b> where data-code-ref is a reference to the
+ component data-code-id, the data-code-ref will be replaced by highlighted outerHTML of the component.
+ </li>
+</ul>
+For more info see example in <a href='components/tiles'>tiles.html</a> file
+
+### How add the new component to router for DEMO
+In index.html file (under id main-navigation) add new <li> with id equal to HTML file you created above
+<br><u>Example:</u>
+<div id='main-navigation'>
+ <div class='title'>Components</div>
+ <ul>
+ <li id='colors'>Colors</li>
+ <li id='button'>Buttons</li>
+ <li id='tiles'>Tiles</li>
+ </ul>
+</div>
diff --git a/demo/assests/README.md b/demo/assests/README.md
new file mode 100644
index 0000000..5f2681b
--- /dev/null
+++ b/demo/assests/README.md
@@ -0,0 +1,9 @@
+
+# Folder Structure
+
+### icons
+Contains `svg` icons **ONLY**
+
+
+### images
+Contains large images (if any...)
diff --git a/demo/assests/icons/empty.txt b/demo/assests/icons/empty.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/demo/assests/icons/empty.txt
diff --git a/demo/assests/icons/locked.svg b/demo/assests/icons/locked.svg
new file mode 100644
index 0000000..9785f8d
--- /dev/null
+++ b/demo/assests/icons/locked.svg
@@ -0,0 +1,39 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="11" height="15" viewBox="0 0 11 15" id="locked_icon">
+ <metadata><?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
+<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.6-c138 79.159824, 2016/09/14-01:09:01 ">
+ <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+ <rdf:Description rdf:about=""/>
+ </rdf:RDF>
+</x:xmpmeta>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<?xpacket end="w"?></metadata>
+<defs>
+ <style>
+ .cls-1 {
+ fill: #959595;
+ fill-rule: evenodd;
+ }
+ </style>
+ </defs>
+ <path id="Shape_77_copy_10" data-name="Shape 77 copy 10" class="cls-1" d="M445,359a16.71,16.71,0,0,0-2.1-.009c-1.945.045-3.195,0.049-3.9,0.009v-5a1.743,1.743,0,0,1,2-2h1a1.743,1.743,0,0,1,2,2v5c0.474,0.063.343-.073,1,0,0.266,0.029,0,.279,0,0v-5a2.726,2.726,0,0,0-3-3h-1.142c-1.72-.125-2.715,1.562-2.858,3,0.088,0.009,0,7.338,0,5h0a1.891,1.891,0,0,0-2,1.689v3.461A1.823,1.823,0,0,0,437.775,366h7.448A1.823,1.823,0,0,0,447,364.15v-3.461A2.018,2.018,0,0,0,445,359Z" transform="translate(-436 -351)"/>
+</svg>
diff --git a/demo/assests/icons/plus.svg b/demo/assests/icons/plus.svg
new file mode 100644
index 0000000..36f3486
--- /dev/null
+++ b/demo/assests/icons/plus.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="plus_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 19 19" style="enable-background:new 0 0 19 19;" xml:space="preserve">
+<g>
+ <rect y="8" width="19" height="3"/>
+ <path id="Rectangle_2139_copy" d="M8,19V0h3v19H8z"/>
+</g>
+</svg>
diff --git a/demo/assests/icons/unlocked.svg b/demo/assests/icons/unlocked.svg
new file mode 100644
index 0000000..6d94a94
--- /dev/null
+++ b/demo/assests/icons/unlocked.svg
@@ -0,0 +1,39 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="11" height="18" viewBox="0 0 11 18" id="unlocked_icon">
+ <metadata><?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
+<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.6-c138 79.159824, 2016/09/14-01:09:01 ">
+ <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+ <rdf:Description rdf:about=""/>
+ </rdf:RDF>
+</x:xmpmeta>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<?xpacket end="w"?></metadata>
+<defs>
+ <style>
+ .cls-1 {
+ fill: #959595;
+ fill-rule: evenodd;
+ }
+ </style>
+ </defs>
+ <path id="Shape_77_copy_16" data-name="Shape 77 copy 16" class="cls-1" d="M663,358a16.723,16.723,0,0,0-2.1-.009c-1.944.045-3.194,0.049-3.9,0.009v-7a1.743,1.743,0,0,1,2-2h1a1.743,1.743,0,0,1,2,2v2c0.474,0.064.343-.073,1,0,0.266,0.029,0,.279,0,0v-2a2.726,2.726,0,0,0-3-3h-1.142c-1.72-.125-2.715,1.562-2.858,3,0.088,0.009,0,9.338,0,7h0a1.891,1.891,0,0,0-2,1.689v4.461a1.823,1.823,0,0,0,1.775,1.85h7.448A1.823,1.823,0,0,0,665,364.15v-4.461A2.018,2.018,0,0,0,663,358Zm1.05,6.15a0.827,0.827,0,0,1-.8.836H655.8a0.827,0.827,0,0,1-.8-0.836l0-4.15a1.164,1.164,0,0,1,.8-1.147h7.448A1.129,1.129,0,0,1,664,360Z" transform="translate(-654 -348)"/>
+</svg>
diff --git a/demo/assests/icons/vendor.svg b/demo/assests/icons/vendor.svg
new file mode 100644
index 0000000..a3b8f5f
--- /dev/null
+++ b/demo/assests/icons/vendor.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 53 47" id="vendor_icon"><title>vendor</title><g id="Layer_2" data-name="Layer 2"><g id="vlm_icon" data-name="vlm icon"><path d="M49,7,38.5,7V5.92A5.92,5.92,0,0,0,32.58,0H20.42A5.92,5.92,0,0,0,14.5,5.92V7.15L4,7.2a3.8,3.8,0,0,0-4,3.5V43.5C0,45.4,2,47,4.2,47L49,46.8a3.8,3.8,0,0,0,4-3.5V10.5A3.8,3.8,0,0,0,49,7ZM16.5,5.92A3.92,3.92,0,0,1,20.42,2H32.58A3.92,3.92,0,0,1,36.5,5.92V7.06l-20,.09ZM2,10.8A1.9,1.9,0,0,1,4,9l45-.2a1.9,1.9,0,0,1,2,1.8v8.87L32.94,24.18a6.49,6.49,0,0,0-12.89,0L2,19.51V10.8ZM31,25a4.5,4.5,0,1,1-4.5-4.5A4.5,4.5,0,0,1,31,25ZM49,45,4,45.2A1.9,1.9,0,0,1,2,43.4V21.57l18.13,4.73a6.5,6.5,0,0,0,12.74,0L51,21.53V43.21A1.9,1.9,0,0,1,49,45Z"/></g></g></svg>
diff --git a/demo/assests/icons/vlm.svg b/demo/assests/icons/vlm.svg
new file mode 100644
index 0000000..79b4625
--- /dev/null
+++ b/demo/assests/icons/vlm.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 45 53"><title>vlm_new_icon</title><g id="Layer_2" data-name="Layer 2"><g id="vlm_icon" data-name="vlm icon"><path d="M41,2a2,2,0,0,1,2,2l.19,45a2,2,0,0,1-2,2H4a2,2,0,0,1-2-2L1.81,4a2,2,0,0,1,2-2H41m-.15-2H4A4.2,4.2,0,0,0,0,4.24L.19,49a4,4,0,0,0,4,4H41a4,4,0,0,0,4-4L44.81,4a4,4,0,0,0-4-4Z"/><rect x="14" y="11" width="17" height="2"/><rect x="14" y="18" width="10" height="2"/><polygon points="20.56 38.85 13.87 33.14 15.16 31.62 20.39 36.08 29.08 26.63 30.55 27.98 20.56 38.85"/></g></g></svg> \ No newline at end of file
diff --git a/demo/assests/icons/vsp.svg b/demo/assests/icons/vsp.svg
new file mode 100644
index 0000000..344755c
--- /dev/null
+++ b/demo/assests/icons/vsp.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" 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 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"/></g></g></svg>
diff --git a/demo/assests/images/empty.txt b/demo/assests/images/empty.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/demo/assests/images/empty.txt
diff --git a/demo/components/button.html b/demo/components/button.html
new file mode 100644
index 0000000..5a68bb5
--- /dev/null
+++ b/demo/components/button.html
@@ -0,0 +1,15 @@
+<div class='component'>Button</div>
+
+<ul class='buttons-showcase'>
+ <li>
+ <button class='sdc-button' data-code>Simple Default Button</button>
+ </li>
+
+ <li>
+ <button class='sdc-button purple' data-code>Simple Button - Purple</button>
+ </li>
+
+ <li>
+ <button class='sdc-button blue' data-code>Simple Button - Blue</button>
+ </li>
+</ul> \ No newline at end of file
diff --git a/demo/components/colors.html b/demo/components/colors.html
new file mode 100644
index 0000000..a9bb9f9
--- /dev/null
+++ b/demo/components/colors.html
@@ -0,0 +1,26 @@
+<div class='component'>Colors</div>
+<P>
+ List of supported colors. All colors are background colors.
+</P>
+<ul class='sdc-colors-showcase'>
+ <li class='sdc-bc-blue'>sdc-bc-blue</li>
+ <li class='sdc-bc-dark-blue'>sdc-bc-dark-blue</li>
+ <li class='sdc-bc-light-blue'>sdc-bc-light-blue</li>
+ <li class='sdc-bc-green'>sdc-bc-green</li>
+ <li class='sdc-bc-dark-green'>sdc-bc-dark-green</li>
+ <li class='sdc-bc-light-green'>sdc-bc-light-green</li>
+ <li class='sdc-bc-orange'>sdc-bc-orange</li>
+ <li class='sdc-bc-yellow'>sdc-bc-yellow</li>
+ <li class='sdc-bc-dark-purple'>sdc-bc-dark-purple</li>
+ <li class='sdc-bc-purple'>sdc-bc-purple</li>
+ <li class='sdc-bc-light-purple'>sdc-bc-light-purple</li>
+ <li class='sdc-bc-black'>sdc-bc-black</li>
+ <li class='sdc-bc-dark-gray'>sdc-bc-dark-gray</li>
+ <li class='sdc-bc-gray'>sdc-bc-gray</li>
+ <li class='sdc-bc-light-gray'>sdc-bc-light-gray</li>
+ <li class='sdc-bc-white'>sdc-bc-white</li>
+</ul>
+<p>Example of usage:</p>
+<code>
+ &lt;div class='sdc-bc-blue'&gt;sdc-bc-blue&lt;/div&gt;
+</code> \ No newline at end of file
diff --git a/demo/components/tiles-generic.html b/demo/components/tiles-generic.html
new file mode 100644
index 0000000..3d03909
--- /dev/null
+++ b/demo/components/tiles-generic.html
@@ -0,0 +1,106 @@
+<div class='component'>Tiles Generic</div>
+<p>
+ Tile do not have size, you can define the size in the wrapping container, or adding them
+ to css in your project.
+ <br><b>Note:</b> specific tiles like sdc-tile-catalog has specifc width & height.
+ <br>Tiles content has overflow auto, so if the content overflow a scroll will appear.
+</p>
+
+<h3>Basic tile</h3>
+<p>Tile without width or height</p>
+<div class="sdc-tile" data-code>
+ <div class='sdc-tile-content'>
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec volutpat, lorem at vulputate sollicitudin, neque magna hendrerit diam, nec sagittis eros libero ut dolor. Donec tincidunt, elit nec vestibulum tristique, nulla tellus aliquam eros, at rutrum massa purus quis ipsum. In aliquet non augue quis condimentum. Praesent efficitur tellus quis mauris auctor, vel semper erat vulputate. Mauris rhoncus nunc et ante dapibus, id luctus urna sodales. Proin eu augue efficitur ligula tincidunt placerat. Suspendisse potenti.
+ </div>
+</div>
+
+<h3>Tile with header & footer</h3>
+<p>
+ <b>Note:</b> The background-color is just for showing header, content & footer sections.
+ This is done using inline styles which should not be included in the final component.
+ <br>The content will resize automaticly his height.
+</p>
+<div class="sdc-tile" data-code>
+ <div class="sdc-tile-header" style="background-color: #EEEEEE;">top</div>
+ <div class='sdc-tile-content' style="background-color: #CCCCCC;">
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec volutpat, lorem at vulputate sollicitudin, neque magna hendrerit diam, nec sagittis eros libero ut dolor. Donec tincidunt, elit nec vestibulum tristique, nulla tellus aliquam eros, at rutrum massa purus quis ipsum. In aliquet non augue quis condimentum. Praesent efficitur tellus quis mauris auctor, vel semper erat vulputate. Mauris rhoncus nunc et ante dapibus, id luctus urna sodales. Proin eu augue efficitur ligula tincidunt placerat. Suspendisse potenti.
+ </div>
+ <div class='sdc-tile-footer' style="background-color: #EEEEEE;">footer</div>
+</div>
+
+<h3>Catalog tile (VSP)</h3>
+<p>
+ Specific tile of SDC.
+ <br><b>Note:</b> The differences betweeb the tiles is the color (diffrent class) and the icons.
+ The div with class='sdc-tile-content-info-vendor-name' is not needed in the second tile.
+</p>
+
+<div class='sdc-tile-showcase-tiles'>
+
+ <div class="sdc-tile-catalog sdc-tile-fix-width" data-code-id='catalog-sample'>
+ <div class="sdc-tile-header">
+ <div class='sdc-tile-header-type blue'>
+ vsp
+ </div>
+ </div>
+ <div class='sdc-tile-content'>
+ <div class='sdc-tile-content-icon'>
+ <svg class="svg-icon blue">
+ <use href="./gen/assets/icons/vsp.svg#vsp_icon" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="./assets/icons/vsp.svg#vsp_icon"></use>
+ </svg>
+ </div>
+ <div class='sdc-tile-content-info'>
+ <div class="sdc-tile-content-info-vendor-name">vlm</div>
+ <div class="sdc-tile-content-info-item-name">lilach vsp</div>
+ <div class="sdc-tile-content-info-version-info">
+ <div class="sdc-tile-content-info-version-info-text" data-test-id="sdc-catalog-item-version">V 0.1</div>
+ </div>
+ </div>
+ </div>
+ <div class='sdc-tile-footer'>
+ <div class='sdc-tile-footer-text'>
+ Footer text
+ </div>
+ <div class='sdc-tile-footer-icon'>
+ <svg class="svg-icon unlocked black">
+ <use href="./gen/assets/icons/unlocked.svg#unlocked_icon" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="./assets/icons/unlocked.svg#unlocked_icon"></use>
+ </svg>
+ </div>
+ </div>
+ </div>
+
+ <div class="sdc-tile-catalog sdc-tile-fix-width sdc-code">
+ <div class="sdc-tile-header">
+ <div class='sdc-tile-header-type purple'>
+ vlm
+ </div>
+ </div>
+ <div class='sdc-tile-content'>
+ <div class='sdc-tile-content-icon'>
+ <svg class="svg-icon purple">
+ <use href="./gen/assets/icons/vsp.svg#vsp_icon" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="./assets/icons/vsp.svg#vsp_icon"></use>
+ </svg>
+ </div>
+ <div class='sdc-tile-content-info'>
+ <div class="sdc-tile-content-info-item-name">vlm</div>
+ <div class="sdc-tile-content-info-version-info">
+ <div class="sdc-tile-content-info-version-info-text" data-test-id="sdc-catalog-item-version">V 0.1</div>
+ </div>
+ </div>
+ </div>
+ <div class='sdc-tile-footer'>
+ <div class='sdc-tile-footer-text'>
+ Footer text
+ </div>
+ <div class='sdc-tile-footer-icon'>
+ <svg class="svg-icon unlocked black">
+ <use href="./gen/assets/icons/locked.svg#locked_icon" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="./assets/icons/locked.svg#locked_icon"></use>
+ </svg>
+ </div>
+ </div>
+ </div>
+
+</div>
+
+<div data-code-ref='catalog-sample'></div>
+
diff --git a/demo/components/tiles.html b/demo/components/tiles.html
new file mode 100644
index 0000000..3519817
--- /dev/null
+++ b/demo/components/tiles.html
@@ -0,0 +1,105 @@
+<div class='component'>Tiles</div>
+
+<h3>VSP Tile</h3>
+<p>
+ Example
+</p>
+<div class="catalog-tile tile software-product-type sdc-code" data-test-id="software-product-type">
+ <div class="catalog-tile-top item-details">
+ <div class="catalog-tile-type software-product-type">VSP</div>
+ <div class="catalog-tile-icon software-product-type">
+ <div class="icon">
+ <div class="svg-icon-wrapper bottom">
+ <svg class="svg-icon vsp ">
+ <use href="./gen/assets/icons/vsp.svg#vsp_icon" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="./assets/icons/vsp.svg#vsp_icon"></use>
+ </svg>
+ </div>
+ </div>
+ </div>
+ <div class="catalog-tile-entity-details">
+ <div>
+ <div class="catalog-tile-vendor-name">vlm</div>
+ </div>
+ <div>
+ <div class="catalog-tile-item-name">lilach vsp</div>
+ </div>
+ <div class="catalog-tile-version-info">
+ <div class="catalog-tile-item-version" data-test-id="catalog-item-version">V 0.1</div>
+ </div>
+ </div>
+ <div class="catalog-tile-content software-product-type">
+ <div class="catalog-tile-locking-user-name">Checked Out</div>
+ <div class="catalog-tile-check-in-status">
+ <div data-test-id="catalog-item-checked-out" class="svg-icon-wrapper bottom">
+ <svg class="svg-icon unlocked ">
+ <use href="./gen/assets/icons/unlocked.svg#unlocked_icon" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="./assets/icons/unlocked.svg#unlocked_icon"></use>
+ </svg>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+
+<h3>VLM Tile</h3>
+<div class="catalog-tile tile license-model-type sdc-code" data-test-id="license-model-type">
+ <div class="catalog-tile-top item-details">
+ <div class="catalog-tile-type license-model-type">VLM</div>
+ <div class="catalog-tile-icon license-model-type">
+ <div class="icon">
+ <div class="svg-icon-wrapper bottom">
+ <svg class="svg-icon vlm ">
+ <use href="./gen/assets/icons/vlm.svg#vlm_icon" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="./assets/icons/vlm.svg#vlm_icon"></use>
+ </svg>
+ </div>
+ </div>
+ </div>
+ <div class="catalog-tile-entity-details">
+ <div>
+ <div class="catalog-tile-vendor-name"></div>
+ </div>
+ <div>
+ <div class="catalog-tile-item-name">vlm</div>
+ </div>
+ <div class="catalog-tile-version-info">
+ <div class="catalog-tile-item-version" data-test-id="catalog-item-version">V 0.2</div>
+ </div>
+ </div>
+ <div class="catalog-tile-content license-model-type">
+ <div class="catalog-tile-locking-user-name">Checked In</div>
+ <div class="catalog-tile-check-in-status">
+ <div data-test-id="catalog-item-checked-in" class="svg-icon-wrapper bottom">
+ <svg class="svg-icon locked ">
+ <use href="./gen/assets/icons/locked.svg#locked_icon" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="./assets/icons/locked.svg#locked_icon"></use>
+ </svg>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+
+<h3>Vendor Tile</h3>
+<div class="catalog-tile tile vendor-type sdc-code" data-test-id="vendor-type">
+ <div class="catalog-tile-top">
+ <div class="catalog-tile-icon vendor-type">
+ <div class="icon">
+ <div class="svg-icon-wrapper bottom">
+ <svg class="svg-icon vendor ">
+ <use href="./gen/assets/icons/vendor.svg#vendor_icon" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="./assets/icons/vendor.svg#vendor_icon"></use>
+ </svg>
+ </div>
+ </div>
+ </div>
+ <div class="catalog-tile-item-name">vlm</div>
+ <div class="catalog-tile-vsp-count clickable" data-test-id="catalog-vsp-count">1 VSPs</div>
+ <div class="catalog-tile-content" data-test-id="catalog-create-new-vsp-from-vendor">
+ <div class="create-new-vsp-button">
+ <div class="svg-icon-wrapper bottom">
+ <svg class="svg-icon plus ">
+ <use href="./gen/assets/icons/plus.svg#plus_icon" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="./assets/icons/plus.svg#plus_icon"></use>
+ </svg>
+ </div>
+ &nbsp;&nbsp;&nbsp;Create new VSP
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/demo/index.css b/demo/index.css
new file mode 100644
index 0000000..ef71773
--- /dev/null
+++ b/demo/index.css
@@ -0,0 +1,178 @@
+/* GENERAL */
+body {
+ margin: 0;
+ color: #333333;
+ /*font-family: 'Open Sans Condensed';*/
+ font-family: 'Overlock';
+ font-size: 16px;
+ display: flex;
+ flex-wrap: wrap;
+ height: auto;
+}
+
+h1 { font-size: 1.5em; }
+h2 { font-size: 1.3em; }
+h3 { font-size: 1.2em; }
+h1, h2, h3 { margin: 2em 0 0.5em 0; color: #009fdb; }
+p { margin: 6px 0; }
+
+/* LAYOUT */
+header {
+ order: 1;
+ width: 100%;
+ background-color: #ffffff;
+}
+
+footer {
+ order: 4;
+ width: 100%;
+}
+
+#main-navigation {
+ order: 2;
+ width: 100%;
+}
+
+#main-content {
+ order: 3;
+ width: 100%;
+}
+
+/* HEADER */
+header {
+ box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.33);
+ height: 50px;
+ line-height: 50px;
+ z-index: 9;
+ display: flex;
+ flex-direction: row;
+ padding: 0 1vw;
+}
+
+header .logo {
+ font-size: 22px;
+ font-weight: 700;
+}
+
+header .title {
+ font-size: 20px;
+ margin-left: 2vw;
+}
+
+/* FOOTER */
+footer {
+ height: 50px;
+ line-height: 50px;
+ z-index: 6;
+ display: flex;
+ flex-direction: row;
+ padding: 0 1vw;
+ border-top: solid 1px #dddddd;
+}
+
+/* MAIN NAVIGATION */
+#main-navigation {
+ align-content: stretch;
+ z-index: 8;
+ box-shadow: 2px 0 0 0 rgba(68,68,68,0.2);
+}
+
+#main-navigation .title {
+ font-size: 20px;
+ font-weight: 700;
+ background-color: #ffffff;
+ color: #009fdb;
+ border-bottom: 1px solid #d2d2d2;
+ height: 30px;
+ line-height: 30px;
+ padding: 0.3em;
+}
+
+#main-navigation ul {
+ padding: 0;
+}
+
+#main-navigation ul li {
+ background-color: #f8f8f8;
+ border-bottom: 1px solid #d2d2d2;
+ height: 30px;
+ line-height: 30px;
+ cursor: pointer;
+ padding: 0.3em;
+}
+
+#main-navigation ul li.selected {
+ background-color: #009fdb;
+ color: #ffffff;
+}
+
+/* MAIN CONTENT */
+#main-content {
+ -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
+ -moz-box-sizing: border-box; /* Firefox, other Gecko */
+ box-sizing: border-box; /* Opera/IE 8+ */
+ align-content: stretch;
+ padding: 2vh 2vw;
+ z-index: 7;
+}
+
+/* RESPONSIVE */
+@media screen and (min-width: 800px) {
+ #main-navigation { width: 20%; }
+ #main-content { width: 80%; }
+}
+
+/* OTHERS */
+.component {
+ background-color: #009fdb;
+ color: #ffffff;
+ font-size: 20px;
+ padding: 0.5em 1em;
+ margin: 0 0 0.5em 0;
+}
+
+pre {
+ padding: 1em;
+ display: block;
+ margin: 1em 0;
+ font-family: 'PT Sans Narrow';
+ font-size: 1em;
+}
+
+/* SPECIFIC COMPONENT - TILE */
+.sdc-tile-showcase-tiles {
+ display: flex;
+ flex-direction: row;
+}
+.sdc-tile-showcase-tiles > div.sdc-tile-catalog {
+ margin: 0 5px 5px 5px;
+}
+.sdc-tile-showcase-tiles > div.sdc-tile-catalog:first-child { margin-left: 0; }
+.sdc-tile-showcase-tiles > div.sdc-tile-catalog:last-child { margin-right: 0; }
+
+/* SPECIFIC COMPONENT - COLORS */
+.sdc-colors-showcase li {
+ padding: 1vw;
+ margin: 1vw;
+}
+
+/* SPECIFIC COMPONENTS - BUTTONS */
+.buttons-showcase li {
+ display: flex;
+ flex-direction: column;
+ margin-top: 2vh;
+}
+.buttons-showcase li pre {
+ flex-grow: 1;
+ margin: 1vw 0 0.5vw 0;
+}
+
+@media screen and (min-width: 600px) {
+ .buttons-showcase li {
+ margin-top: 0;
+ flex-direction: row;
+ }
+ .buttons-showcase li pre {
+ margin: 0.5vw 0 0.5vw 2vw;
+ }
+}
diff --git a/demo/index.html b/demo/index.html
new file mode 100644
index 0000000..f3b4cb4
--- /dev/null
+++ b/demo/index.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset=UTF-8>
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+
+ <!-- Componentes generates styles -->
+ <link rel="stylesheet" type="text/css" href="gen/css/style.css">
+
+ <!-- Html story board styles -->
+ <link rel="stylesheet" type="text/css" href="index.css">
+
+ <!-- Html story borad fonts -->
+ <!--<link href='//fonts.googleapis.com/css?family=Open Sans Condensed:300' rel='stylesheet'>-->
+ <link href='//fonts.googleapis.com/css?family=Overlock:400' rel='stylesheet'>
+ <link href='//fonts.googleapis.com/css?family=PT Sans Narrow:400' rel='stylesheet'>
+
+ <!-- Html story borad external libs -->
+ <link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.10.0/styles/default.min.css" rel="stylesheet">
+ <script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.10.0/highlight.min.js"></script>
+ <script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
+
+ <!-- Html story borad javascript -->
+ <script src="index.js"></script>
+
+ <title>SDC-UI Show case</title>
+ </head>
+ <body>
+
+ <header>
+ <div class='logo'>SDC-UI</div>
+ <div class='title'>Show case</div>
+ </header>
+
+ <div id='main-navigation'>
+ <div class='title'>Components</div>
+ <ul>
+ <li id='colors'>Colors</li>
+ <li id='button'>Buttons</li>
+ <li id='tiles'>Tiles</li>
+ <li id='tiles-generic'>Tiles Generic</li>
+ </ul>
+ </div>
+
+ <div id='main-content'></div>
+
+ <footer>
+ Copywrite 2017. All rights reserved.
+ </footer>
+
+ </body>
+
+</html>
diff --git a/demo/index.js b/demo/index.js
new file mode 100644
index 0000000..1c9a4bb
--- /dev/null
+++ b/demo/index.js
@@ -0,0 +1,84 @@
+$( document ).ready(function() {
+
+ initNavigation();
+ registerEvents();
+ doAfterComponentHtmlLoaded();
+
+});
+
+var initNavigation = function() {
+
+ // Set default page
+ var page = window.location.hash;
+ if (page === '') {
+ page = "button";
+ window.location.hash = page;
+ }
+
+ // Remove # at the begining
+ if (page.indexOf('#')!==-1){
+ page = page.substr(1);
+ }
+ console.log("page: " + page);
+
+ // Upload the content
+ $("#main-content").load( "./components/" + page + ".html" );
+
+ // Set selected in navigation
+ $('#main-navigation #' + page).addClass('selected');
+
+};
+
+/**
+ * Simple router to load components HTML based on id.
+ */
+var registerEvents = function() {
+ $("#main-navigation li").click(function(e){
+ page = e.target.id;
+ $("#main-content").load( "./components/" + page + ".html", function() {
+ doAfterComponentHtmlLoaded();
+ });
+ window.location.hash = page;
+ $('#main-navigation li').removeClass('selected');
+ $('#main-navigation #' + page).addClass('selected');
+ });
+};
+
+/**
+ * Wait for component to load before applying javascript actions on it.
+ */
+var doAfterComponentHtmlLoaded = function() {
+ window.setTimeout(function() {
+ // Build code text to show to user
+ buildCode();
+
+ // highlight the code
+ hljs.initHighlightingOnLoad();
+ },1000);
+};
+
+/**
+ * Build HTML code automaticly when attribute data-code exists
+ * For example:
+ * <button class='sdc-button' data-code>This is button</button>
+ * Will add the HTML of this (highlighted) button below the button.
+ */
+var buildCode = function() {
+ $('[data-code]').each(function(index, element){
+ var result = $(element).removeAttr('data-code')[0].outerHTML;
+ var resultEncoded = $('<div/>').text(result).html();
+ var newElement = $('<pre><code>' + resultEncoded + '</code></pre>')[0];
+ $(element).after(newElement);
+ hljs.highlightBlock(newElement);
+ });
+
+ $('[data-code-id]').each(function(index, element){
+ var attVlue = $(element).attr('data-code-id');
+ var codeHere = $('[data-code-ref='+attVlue+']');
+ var result = $(element).removeAttr('data-code-id')[0].outerHTML;
+ var resultEncoded = $('<div/>').text(result).html();
+ var newElement = $('<pre><code>' + resultEncoded + '</code></pre>')[0];
+ codeHere.replaceWith(newElement);
+ hljs.highlightBlock(newElement);
+ });
+};
diff --git a/demo/package.json b/demo/package.json
new file mode 100644
index 0000000..40a7b7d
--- /dev/null
+++ b/demo/package.json
@@ -0,0 +1,23 @@
+{
+ "name": "onap-sdc",
+ "preferGlobal": true,
+ "version": "1.0.0",
+ "author": "Onap Sdc <onap.sdc@gmail.com>",
+ "description": "Styles and UI components for ONAP SDC",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10"
+ },
+ "scripts": {
+ "start": "watch-http-server ./ -a 127.0.0.1 -p 2900 -o"
+ },
+ "dependencies": {
+ "express": "~3.4.7",
+ "http-server": "^0.9.0"
+ },
+ "devDependencies": {
+ "node-sass": "^4.5.2",
+ "nodemon": "^1.11.0",
+ "watch-http-server": "^0.7.6"
+ }
+}
diff --git a/designs/README.md b/designs/README.md
new file mode 100644
index 0000000..5de4d30
--- /dev/null
+++ b/designs/README.md
@@ -0,0 +1,3 @@
+# Designs
+
+Reference folder for graphics and designs
diff --git a/jest.config.js b/jest.config.js
new file mode 100644
index 0000000..51e3f70
--- /dev/null
+++ b/jest.config.js
@@ -0,0 +1,30 @@
+module.exports = {
+ moduleFileExtensions: [
+ 'js',
+ 'html'
+ ],
+ globals: {
+ ICON_PATH: './'
+ },
+ transform: {
+ '^.+\\.js$': 'babel-jest',
+ '^.+\\.html$': '<rootDir>/test/react/utils/htmlLoader.js'
+ },
+ moduleNameMapper: {
+ '^.+\\.svg$': '<rootDir>/test/react/utils/svgMock.js'
+ },
+ coveragePathIgnorePatterns: [
+ '<rootDir>/src/react/index.js',
+ '<rootDir>/src/index.js'
+ ],
+ testRegex: '/test/react/.*.(spec|test)\\.jsx?$',
+ testPathIgnorePatterns: [
+ '<rootDir>/node_modules/',
+ ],
+ collectCoverageFrom: [
+ 'src/**/*.{js,jsx}'
+ ],
+ coverageReporters: [
+ 'lcov'
+ ]
+};
diff --git a/json-typing.d.ts b/json-typing.d.ts
new file mode 100644
index 0000000..4b3471f
--- /dev/null
+++ b/json-typing.d.ts
@@ -0,0 +1,4 @@
+declare module "*.json" {
+ const value: any;
+ export default value;
+}
diff --git a/karma.conf.js b/karma.conf.js
new file mode 100644
index 0000000..bc35fb7
--- /dev/null
+++ b/karma.conf.js
@@ -0,0 +1,87 @@
+/****************************************************************************************
+ * Karma configuration file
+ ***************************************************************************************/
+
+module.exports = function (config) {
+ config.set({
+ basePath:'',
+ files:[
+ 'karma.entry.js',
+ ],
+
+ /**
+ * Enable / disable watching file and executing tests whenever any file changes
+ */
+ autoWatch: true,
+
+ /**
+ * Here, we tell Karma we'll be using Jasmine
+ */
+ frameworks:['jasmine'],
+
+ /**
+ * Level of logging
+ * possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+ */
+ logLevel: config.LOG_INFO,
+
+ /**
+ * Currently we have the following launchers: Firefox, Chrome, PhantomJS
+ * Available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+ */
+ browsers: ['Firefox', 'PhantomJS'],
+
+ /**
+ * Tells PhantomJS to shut down if Karma throws a ResourceError, If we didn't, PhantomJS might not shut down,
+ * and this would eat away at our system resources.
+ */
+ phantomJsLauncher: {
+ exitOnResourceError: true
+ },
+
+ /**
+ * We tell Karma to run a list of preprocessors on our karma.entry.js file
+ */
+ preprocessors: {
+ 'karma.entry.js': ['webpack', 'sourcemap']
+ },
+
+
+ /**
+ * dots: Tells karma to use dots reporter, which outputs a single dot for each test instead of descriptive message.
+ * kjhtml - Karma Jasmine HTML Reporter. Reporter that dynamically shows tests results at debug.html page.
+ */
+ reporters: ['dots', 'kjhtml'],
+
+ /**
+ * leave Jasmine Spec Runner output visible in browser
+ */
+ client: {
+ clearContext: false
+ },
+
+ /**
+ * Keeps karma running after it completed it's tests for later rerun.
+ */
+ singleRun: false,
+
+ failOnEmptyTestSuite:false,
+
+ /**
+ * Load webpack test configuration file
+ */
+ webpack: require('./webpack/webpack.test.js'),
+
+ webpackMiddleware: {
+ noInfo: true
+ },
+
+ /**
+ * Hide webpack bundle information messages
+ */
+ webpackServer: {
+ noInfo: true
+ }
+ })
+};
+
diff --git a/karma.entry.js b/karma.entry.js
new file mode 100644
index 0000000..acd16cc
--- /dev/null
+++ b/karma.entry.js
@@ -0,0 +1,66 @@
+/****************************************************************************************
+ * Karma entry file.
+ * Starting point for pulling in our test and application files when using karma.
+ ***************************************************************************************/
+
+/**
+ * Load dependencies:
+ * - core-js/es6 - Javascript polyfills support es6 code on unsupported browsers
+ * - reflect-metadata - support for decorators and reflection.
+ * - Zone library - Monkey patch all asynchronous actions and jasmine so changes could be detected
+ * as well as long stack traces (To get the root cause of errors).
+ */
+
+require('core-js/es6');
+
+require('reflect-metadata');
+
+require('zone.js/dist/zone');
+require('zone.js/dist/async-test');
+require('zone.js/dist/fake-async-test');
+require('zone.js/dist/long-stack-trace-zone'); // Gives us a long backward trace of actions and errors
+require('zone.js/dist/proxy');
+require('zone.js/dist/sync-test');
+require('zone.js/dist/jasmine-patch');
+
+/**
+ * RxJS
+ */
+require('rxjs/Rx');
+
+
+/**
+ * Angular testing libraries dependencies
+ */
+const browserTesting = require('@angular/platform-browser-dynamic/testing');
+const coreTesting = require('@angular/core/testing');
+
+coreTesting.TestBed.initTestEnvironment(
+ browserTesting.BrowserDynamicTestingModule,
+ browserTesting.platformBrowserDynamicTesting()
+);
+
+/**
+ * Webpack method. requires all the files and subdirectories of a pattern.
+ * Checkout {@link https://webpack.github.io/docs/context.html}
+ */
+const context = require.context('./src/angular/', true, /\.spec\.ts$/);
+
+/**
+ * Get all the files, for each file, call the context function
+ * that will require the file and load it up here. Context will
+ * loop and require those spec files here
+ */
+function requireAll(requireContext) {
+ return requireContext.keys().map(requireContext);
+}
+
+requireAll(context);
+
+/**
+ * These lines are the Jasmine setup . We'll make sure that we get full stack traces when we have a
+ * problem and that Jasmine uses two seconds as its default timeout.
+ * The timeout is used when we test asynchronous processes. If we don't set this properly, some of our tests could hang forever.
+ */
+Error.stackTraceLimit = Infinity;
+jasmine.DEFAULT_TIMEOUT_INTERVAL = 2000;
diff --git a/ng2-component-lab.webpack.config.js b/ng2-component-lab.webpack.config.js
new file mode 100644
index 0000000..d2f0551
--- /dev/null
+++ b/ng2-component-lab.webpack.config.js
@@ -0,0 +1,62 @@
+var path = require('path');
+var HtmlReplaceWebpackPlugin = require('html-replace-webpack-plugin')
+var baseHref = process.env.NODE_ENV === 'build' ? '<base href="/angular/">' : '<base href="">'
+
+var webpackConfig = {
+
+ devtool: 'source-map',
+
+ output: {
+ path: path.resolve('.out/angular'),
+ publicPath: ''
+ },
+
+ plugins: [
+ new HtmlReplaceWebpackPlugin([{
+ pattern: '<base href="/">',
+ replacement: baseHref
+ }])
+ ],
+
+ module: {
+ rules: [
+ // .ts files for TypeScript
+ {
+ test: /.ts$/,
+ use: [
+ 'awesome-typescript-loader',
+ 'angular2-template-loader',
+ 'angular2-router-loader'
+ ]
+ },
+ { test: /\.html$/, loader: "html-loader" },
+ {
+ test: /.scss$/,
+ use: ['style-loader', 'css-loader', 'sass-loader'],
+ include: path.resolve(__dirname, '../')
+ },
+ ]
+ },
+
+ resolve: {
+ extensions: ['.ts', '.js'],
+ modules: [path.resolve(__dirname, 'node_modules')],
+ alias: {
+ root: path.resolve(__dirname),
+ app: path.resolve(__dirname, 'src')
+ }
+ },
+
+ node: {
+ global: true,
+ crypto: 'empty',
+ __dirname: true,
+ __filename: true,
+ process: true,
+ Buffer: false,
+ clearImmediate: false,
+ setImmediate: false
+ }
+};
+
+module.exports = webpackConfig;
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..8495da4
--- /dev/null
+++ b/package.json
@@ -0,0 +1,133 @@
+{
+ "name": "sdc-ui",
+ "version": "1.6.42",
+ "description": "This project aims to create a unified UI styled components for multiple development teams who work on the same web-based applications.",
+ "scripts": {
+ "test": "jest && npm run karma-travis",
+ "test-dev": "jest --watch",
+ "test-coverage": "jest --coverage && start coverage/lcov-report/index.html",
+ "karma-travis": "karma start --single-run --browsers PhantomJS",
+ "karma-dev": "karma start",
+ "tslint": "tslint -c tslint.json 'src/**/*.ts'",
+ "prebuild-clean": "rimraf lib",
+ "build-demo": "node utils/build-demo.js",
+ "build-icons": "node utils/create-icon-map.js",
+ "build-themes": "node-sass --include-path src/style/scss/themes src/style/scss/themes/1802/style.scss css/theme_1802.css",
+ "build-svg-icons": "node utils/create-svg-icons-map.js",
+ "build-common": "npm run build-icons && npm run build-svg-icons && node-sass --include-path src/style/scss src/style/scss/style.scss css/style.css && npm run build-themes",
+ "build-react": "babel src/react -d lib/react",
+ "compile-angular": "ngc -p tsconfig.angular.build-es5.json",
+ "rollup-angular:module": "rollup -c rollup.angular.module.config.js",
+ "rollup-angular:umd": "rollup -c rollup.angular.umd.config.js",
+ "rollup-angular:metadata": "find build/* -type f -not -name '*.js' -not -name '*.js.*' -exec cp --parents {} lib \\; && cp -rf lib/build/* lib/ && rm -r lib/build",
+ "build-angular": "npm run compile-angular && npm run rollup-angular:module && npm run rollup-angular:umd && npm run rollup-angular:metadata",
+ "build-style": "npm run build-style-scss && npm run build-style-less",
+ "build-style-scss": "cp -rf src/style lib/",
+ "build-style-less": "sass2less --cwd lib/style/scss **/*.scss ../less/{dir}/{name}.less",
+ "build-pack": "cp -r css lib/ && cp -r assets lib/",
+ "postbuild-clean": "rimraf build",
+ "build": "npm run prebuild-clean && npm run build-common && npm run build-react && npm run build-angular && npm run build-pack && npm run build-style && npm run postbuild-clean",
+ "storybook": "npm run build-common && start-storybook -p 6006",
+ "build-storybook": "npm run build-common && build-storybook -c .storybook -o .out/react && ncp utils/index-for-gh-pages.html .out/index.html && ncp utils/main-page.html .out/main-page.html && ncp assets .out/assets",
+ "lab": "npm run build-common && ng2-component-lab --config .ng2-component-lab/ng2-component-lab.config.js -- feature",
+ "build-lab": "set NODE_ENV=build&& ng2-component-lab --config .ng2-component-lab/ng2-component-lab.config.js --build -- feature",
+ "build-gh-pages": "npm run build-storybook && npm run build-lab && ncp utils/index-for-gh-pages.html .out/index.html && ncp utils/main-page.html .out/main-page.html && ncp assets .out/assets"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/onap-sdc/sdc-ui.git"
+ },
+ "author": "",
+ "bugs": {
+ "url": "https://github.com/onap-sdc/sdc-ui/issues"
+ },
+ "files": [
+ "lib",
+ "css",
+ "assets",
+ "README.md"
+ ],
+ "homepage": "https://github.com/onap-sdc/sdc-ui#readme",
+ "peerDependencies": {
+ "@angular/core": "^2.4.8"
+ },
+ "devDependencies": {
+ "@angular/compiler": "~2.4.8",
+ "@angular/compiler-cli": "~2.4.8",
+ "@islavi/ng2-component-lab": "^1.0.28",
+ "@types/jasmine": "2.5.47",
+ "@types/node": "^7.0.27",
+ "angular2-router-loader": "^0.3.4",
+ "angular2-template-loader": "^0.6.2",
+ "awesome-typescript-loader": "^3.1.3",
+ "babel-cli": "^6.24.1",
+ "babel-eslint": "^7.2.3",
+ "babel-plugin-transform-object-rest-spread": "^6.23.0",
+ "babel-preset-env": "^1.4.0",
+ "babel-preset-react": "^6.24.1",
+ "babel-runtime": "^6.23.0",
+ "chalk": "1.1.3",
+ "codelyzer": "3.1.1",
+ "css-loader": "^0.28.0",
+ "enzyme": "^2.8.2",
+ "eslint": "^3.19.0",
+ "eslint-plugin-import": "^2.2.0",
+ "eslint-plugin-react": "^7.0.1",
+ "html-loader": "^0.4.5",
+ "html-replace-webpack-plugin": "^2.2.6",
+ "jasmine-core": "~2.5.2",
+ "jasmine-spec-reporter": "^4.1.1",
+ "jest": "^20.0.0",
+ "karma": "~1.5.0",
+ "karma-chrome-launcher": "^2.2.0",
+ "karma-coverage": "~1.1.1",
+ "karma-firefox-launcher": "^1.0.1",
+ "karma-htmlfile-reporter": "^0.3.5",
+ "karma-jasmine": "~1.1.0",
+ "karma-jasmine-html-reporter": "^0.2.2",
+ "karma-junit-reporter": "^1.2.0",
+ "karma-phantomjs-launcher": "~1.0.4",
+ "karma-remap-coverage": "0.1.4",
+ "karma-sourcemap-loader": "^0.3.7",
+ "karma-spec-reporter": "0.0.30",
+ "karma-typescript": "^3.0.8",
+ "karma-webpack": "2.0.3",
+ "less-plugin-sass2less": "^1.2.0",
+ "lite-server": "^2.3.0",
+ "ncp": "^2.0.0",
+ "node-sass": "^4.5.3",
+ "prismjs": "^1.6.0",
+ "protractor": "5.1.1",
+ "react-test-renderer": "^15.5.4",
+ "rimraf": "^2.6.2",
+ "rollup": "^0.51.8",
+ "sass-loader": "^6.0.3",
+ "sorcery": "0.10.0",
+ "source-map-loader": "0.2.1",
+ "style-loader": "^0.16.1",
+ "tslint": "5.9.1",
+ "tslint-angular": "^1.1.1",
+ "typescript": "^2.6.1",
+ "uglify-js": "2.8.29",
+ "url-parse": "^1.1.9"
+ },
+ "dependencies": {
+ "@angular/common": "~2.4.8",
+ "@angular/core": "~2.4.8",
+ "@angular/forms": "~2.4.8",
+ "@angular/http": "^2.4.8",
+ "@angular/platform-browser": "~2.4.8",
+ "@angular/platform-browser-dynamic": "~2.4.8",
+ "@angular/router": "~3.2.1",
+ "@angular/upgrade": "^2.4.8",
+ "@storybook/react": "^3.1.5",
+ "http-loader": "0.0.1",
+ "prop-types": "^15.6.0",
+ "react": "15.6.2",
+ "react-dom": "15.6.2",
+ "reflect-metadata": "^0.1.3",
+ "rxjs": "5.4.2",
+ "svg-react-loader": "^0.4.4",
+ "zone.js": "^0.8.18"
+ }
+}
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..d3f133f
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,162 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.onap.sdc</groupId>
+ <artifactId>onap-ui</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <packaging>pom</packaging>
+ <name>onap-ui</name>
+
+ <properties>
+ <nexus.proxy>https://nexus.onap.org</nexus.proxy>
+ <sitePath>/content/sites/site/org/openecomp/sdc/${project.version}</sitePath>
+ <staging.profile.id>176c31dfe190a</staging.profile.id>
+ <maven.build.timestamp.format>yyyyMMdd'T'HHmmss'Z'</maven.build.timestamp.format>
+
+ <maven.compiler.source>1.8</maven.compiler.source>
+ <maven.compiler.target>1.8</maven.compiler.target>
+ </properties>
+
+ <build>
+ <plugins>
+
+ <plugin>
+ <artifactId>maven-clean-plugin</artifactId>
+ <version>2.6.1</version>
+ <executions>
+ <execution>
+ <id>clean.dist.folder</id>
+ <phase>clean</phase>
+ <goals>
+ <goal>clean</goal>
+ </goals>
+ <configuration>
+ <filesets>
+ <fileset>
+ <directory>${basedir}/node_modules</directory>
+ </fileset>
+ <fileset>
+ <directory>${basedir}/dist</directory>
+ </fileset>
+ </filesets>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>com.github.eirslett</groupId>
+ <artifactId>frontend-maven-plugin</artifactId>
+ <version>1.6</version>
+
+ <configuration>
+ <installDirectory>${project.parent.basedir}</installDirectory>
+ </configuration>
+
+ <executions>
+ <execution>
+ <id>install node and npm</id>
+ <goals>
+ <goal>install-node-and-npm</goal>
+ </goals>
+ <configuration>
+ <nodeVersion>v8.11.1</nodeVersion>
+ <npmVersion>5.6.0</npmVersion>
+ </configuration>
+ </execution>
+
+ <execution>
+ <id>npm set progress off</id>
+ <goals>
+ <goal>npm</goal>
+ </goals>
+ <configuration>
+ <arguments>set progress=false</arguments>
+ </configuration>
+ </execution>
+
+ <execution>
+ <id>npm install</id>
+ <goals>
+ <goal>npm</goal>
+ </goals>
+ <configuration>
+ <arguments>install</arguments>
+ </configuration>
+ </execution>
+
+ <execution>
+ <id>npm run build</id>
+ <goals>
+ <goal>npm</goal>
+ </goals>
+ <configuration>
+ <arguments>run build</arguments>
+ </configuration>
+ </execution>
+
+ <execution>
+ <id>npm test</id>
+ <goals>
+ <goal>npm</goal>
+ </goals>
+ <configuration>
+ <arguments>run test</arguments>
+ </configuration>
+ </execution>
+
+ <execution>
+ <id>npm run build-gh-pages</id>
+ <goals>
+ <goal>npm</goal>
+ </goals>
+ <configuration>
+ <arguments>run build-gh-pages</arguments>
+ </configuration>
+ </execution>
+
+ </executions>
+ </plugin>
+
+ </plugins>
+ </build>
+
+ <repositories>
+ <repository>
+ <id>ecomp-releases</id>
+ <name>Release Repository</name>
+ <url>${nexus.proxy}/content/repositories/releases/</url>
+ </repository>
+ <repository>
+ <id>ecomp-snapshots</id>
+ <name>Snapshots Repository</name>
+ <url>${nexus.proxy}/content/repositories/snapshots/</url>
+ </repository>
+ <repository>
+ <id>ecomp-public</id>
+ <name>Public Repository</name>
+ <url>${nexus.proxy}/content/repositories/public/</url>
+ </repository>
+ </repositories>
+
+ <distributionManagement>
+ <repository>
+ <id>ecomp-releases</id>
+ <name>Release Repository</name>
+ <url>${nexus.proxy}/content/repositories/releases/</url>
+ </repository>
+ <snapshotRepository>
+ <id>ecomp-snapshots</id>
+ <name>Snapshot Repository</name>
+ <url>${nexus.proxy}/content/repositories/snapshots/</url>
+ </snapshotRepository>
+ <site>
+ <id>ecomp-site</id>
+ <url>dav:${nexus.proxy}${sitePath}</url>
+ </site>
+ </distributionManagement>
+
+</project>
+
diff --git a/rollup.angular.module.config.js b/rollup.angular.module.config.js
new file mode 100644
index 0000000..18f382b
--- /dev/null
+++ b/rollup.angular.module.config.js
@@ -0,0 +1,33 @@
+export default {
+ input: './build/angular/index.js',
+ output: {
+ name: 'sdcUiAngular',
+ file: './lib/angular/index.js',
+ format: 'es',
+ exports: 'named',
+ },
+ external: [
+ '@angular/core',
+ '@angular/common',
+ '@angular/common/http',
+ '@angular/upgrade/static',
+ '@angular/forms',
+ '@angular/platform-browser',
+ '@angular/http',
+ '@rxjs/add/operator/debounceTime',
+ 'rxjs/Subject',
+ 'rxjs/add/operator/debounceTime',
+ 'rxjs/add/operator/map',
+ 'rxjs/BehaviorSubject',
+ 'rxjs/Subject'
+ ],
+ onwarn: function(warning) {
+ // Skip certain warnings
+
+ // should intercept ... but doesn't in some rollup versions
+ if ( warning.code === 'THIS_IS_UNDEFINED' ) { return; }
+
+ // console.warn everything else
+ console.warn( warning.message );
+ }
+};
diff --git a/rollup.angular.umd.config.js b/rollup.angular.umd.config.js
new file mode 100644
index 0000000..547c6a9
--- /dev/null
+++ b/rollup.angular.umd.config.js
@@ -0,0 +1,38 @@
+export default {
+ input: './build/angular/index.js',
+ output: {
+ name: 'sdcUiAngular',
+ file: './lib/angular/index.umd.js',
+ format: 'umd',
+ exports: 'named',
+ globals: {
+ '@angular/core': 'ngCore',
+ '@angular/common': 'ngCommon',
+ '@angular/forms': 'ngForms'
+ }
+ },
+ external: [
+ '@angular/core',
+ '@angular/common',
+ '@angular/common/http',
+ '@angular/upgrade/static',
+ '@angular/forms',
+ '@angular/platform-browser',
+ '@angular/http',
+ '@rxjs/add/operator/debounceTime',
+ 'rxjs/Subject',
+ 'rxjs/add/operator/debounceTime',
+ 'rxjs/add/operator/map',
+ 'rxjs/BehaviorSubject',
+ 'rxjs/Subject'
+ ],
+ onwarn: function(warning) {
+ // Skip certain warnings
+
+ // should intercept ... but doesn't in some rollup versions
+ if ( warning.code === 'THIS_IS_UNDEFINED' ) { return; }
+
+ // console.warn everything else
+ console.warn( warning.message );
+ }
+};
diff --git a/src/README.md b/src/README.md
new file mode 100644
index 0000000..83d47bf
--- /dev/null
+++ b/src/README.md
@@ -0,0 +1,9 @@
+
+# Folder Structure
+
+### Angular 2 Framework
+Contains **Angular 2** based components
+
+
+### React Framework
+Contains **React.js** based components
diff --git a/src/angular/accordion/accordion.component.html.ts b/src/angular/accordion/accordion.component.html.ts
new file mode 100644
index 0000000..ac5f81f
--- /dev/null
+++ b/src/angular/accordion/accordion.component.html.ts
@@ -0,0 +1,21 @@
+export default `
+<div class="sdc-accordion" [ngClass]="customCSSClass">
+ <div class="sdc-accordion-header" (click)="toggleAccordion()" [ngClass]="{'arrow-right': arrowDirection === accordionArrowDirection.right}">
+ <div class="svg-icon-wrapper bottom" [ngClass]="{'down': open}">
+ <svg class="svg-icon __chevronUp" version="1.1" id="chevron-up_icon" x="0px" y="0px" viewBox="0 0 10 6.3" style="enable-background:new 0 0 10 6.3;"
+ xml:space="preserve">
+ <g transform="translate(0,-952.36218)">
+ <path d="M10,958.2c0-0.1,0-0.2-0.1-0.2l-4.6-5.5c-0.1-0.2-0.4-0.2-0.5,0l0,0L0.1,958c-0.1,0.2-0.1,0.4,0,0.5s0.4,0.1,0.5,0l0,0
+ l4.3-5.2l4.3,5.2c0.1,0.2,0.4,0.2,0.5,0.1C10,958.5,10,958.3,10,958.2z">
+ </path>
+ </g>
+ </svg>
+ </div>
+ <div class="title">
+ {{title}}
+ </div>
+ </div>
+ <div class="sdc-accordion-body" [ngClass]="{open: open}">
+ <ng-content></ng-content>
+ </div>
+</div>`;
diff --git a/src/angular/accordion/accordion.component.ts b/src/angular/accordion/accordion.component.ts
new file mode 100644
index 0000000..b16df89
--- /dev/null
+++ b/src/angular/accordion/accordion.component.ts
@@ -0,0 +1,27 @@
+/**
+ * Created by M.S.BIT on 26/04/2018.
+ */
+
+import {Component, Input, Output, EventEmitter} from "@angular/core";
+import {Placement} from "../common/enums";
+import template from './accordion.component.html';
+
+@Component({
+ selector: 'sdc-accordion',
+ template: template,
+})
+export class AccordionComponent {
+
+ @Input('arrow-direction') arrowDirection: Placement;
+ @Input('css-class') customCSSClass: string;
+ @Input('title') title: string;
+ @Input('open') open: boolean;
+ @Output('accordionChanged') changed = new EventEmitter<boolean>();
+
+ public accordionArrowDirection = Placement;
+
+ public toggleAccordion(){
+ this.open = !this.open;
+ this.changed.emit(this.open);
+ }
+}
diff --git a/src/angular/accordion/accordion.module.ts b/src/angular/accordion/accordion.module.ts
new file mode 100644
index 0000000..6cda646
--- /dev/null
+++ b/src/angular/accordion/accordion.module.ts
@@ -0,0 +1,23 @@
+/**
+ * Created by M.S.BIT on 26/04/2018.
+ */
+import { NgModule } from "@angular/core";
+import { CommonModule } from "@angular/common";
+import {AccordionComponent} from "./accordion.component";
+import {SvgIconModule} from "../svg-icon/svg-icon.module";
+
+@NgModule({
+ declarations: [
+ AccordionComponent
+ ],
+ imports: [
+ CommonModule,
+ SvgIconModule
+ ],
+ exports: [
+ AccordionComponent
+ ],
+})
+export class AccordionModule {
+
+}
diff --git a/src/angular/animations/animation-directives.module.ts b/src/angular/animations/animation-directives.module.ts
new file mode 100644
index 0000000..c6a8203
--- /dev/null
+++ b/src/angular/animations/animation-directives.module.ts
@@ -0,0 +1,19 @@
+import { NgModule } from "@angular/core";
+import { RippleClickAnimationDirective } from "./ripple-click.animation.directive";
+import { CommonModule } from "@angular/common";
+
+@NgModule({
+ declarations: [
+ RippleClickAnimationDirective
+ ],
+ imports: [
+ CommonModule
+ ],
+ exports: [
+ RippleClickAnimationDirective
+
+ ],
+})
+export class AnimationDirectivesModule {
+
+}
diff --git a/src/angular/animations/ripple-click.animation.directive.ts b/src/angular/animations/ripple-click.animation.directive.ts
new file mode 100644
index 0000000..7b9ed55
--- /dev/null
+++ b/src/angular/animations/ripple-click.animation.directive.ts
@@ -0,0 +1,47 @@
+import { Directive, Input, HostBinding, HostListener } from "@angular/core";
+
+export enum RippleAnimationAction {
+ CLICK = 0,
+ MOUSE_ENTER = 1
+};
+
+@Directive({
+ selector: `[SdcRippleClickAnimation]`
+})
+export class RippleClickAnimationDirective {
+ private animated: boolean;
+
+ @Input() rippleClickDisabled: boolean;
+ @Input() rippleOnAction:RippleAnimationAction = RippleAnimationAction.CLICK;
+
+ @HostBinding('class.sdc-ripple-click__animated') animationClass: string;
+
+ @HostListener('click') onClick() {
+ if(this.rippleOnAction === RippleAnimationAction.CLICK){
+ this.animateStart();
+ }
+ }
+
+ @HostListener('mouseenter') onMouseEnter() {
+ //console.log("Mouseenter!", this.rippleOnAction);
+ if(this.rippleOnAction === RippleAnimationAction.MOUSE_ENTER){
+ this.animateStart();
+ }
+ }
+
+ private animateStart():void{
+ if (!this.rippleClickDisabled) {
+ this.animated = true;
+ this.animationClass = 'sdc-ripple-click__animated';
+ }
+ }
+ @HostListener('animationend') onAnimationComplete() {
+ this.animated = false;
+ this.animationClass = '';
+ }
+
+ constructor() {
+ this.rippleClickDisabled = false;
+ this.animated = false;
+ }
+}
diff --git a/src/angular/autocomplete/autocomplete.component.html.ts b/src/angular/autocomplete/autocomplete.component.html.ts
new file mode 100644
index 0000000..5df7352
--- /dev/null
+++ b/src/angular/autocomplete/autocomplete.component.html.ts
@@ -0,0 +1,14 @@
+export default `
+<div class="sdc-autocomplete-container" [ngClass]="{'results-shown': autoCompleteResults.length}">
+ <sdc-filter-bar
+ [placeholder]="placeholder"
+ [label]="label"
+ [searchQuery]="searchQuery"
+ (searchQueryChange)="onSearchQueryChanged($event)">
+ </sdc-filter-bar>
+ <ul class="autocomplete-results" [@displayResultsAnimation]="autoCompleteResults.length ?'true':'false'">
+ <li *ngFor="let item of autoCompleteResults"
+ (click)="onItemSelected(item)">{{item.value}}</li>
+ </ul>
+</div>
+`;
diff --git a/src/angular/autocomplete/autocomplete.component.ts b/src/angular/autocomplete/autocomplete.component.ts
new file mode 100644
index 0000000..5570eff
--- /dev/null
+++ b/src/angular/autocomplete/autocomplete.component.ts
@@ -0,0 +1,114 @@
+import { OnInit, animate, Component, EventEmitter, Input, Output, state, style, transition, trigger } from '@angular/core';
+import { FilterBarComponent } from "../filterbar/filter-bar.component";
+import { URLSearchParams, Http } from "@angular/http";
+import { AutocompletePipe } from "./autocomplete.pipe";
+import template from "./autocomplete.component.html";
+import 'rxjs/add/operator/map';
+
+export interface IDataSchema {
+ key: string;
+ value: string;
+}
+
+@Component({
+ selector: 'sdc-autocomplete',
+ template: template,
+ animations: [
+ trigger('displayResultsAnimation', [
+ state('true', style({
+ height: '*',
+ opacity: 1
+ })),
+ state('false', style({
+ height: 0,
+ opacity: 0
+ })),
+ transition('* => *', animate('200ms'))
+ ]),
+ ],
+ providers: [AutocompletePipe]
+})
+export class SearchWithAutoCompleteComponent implements OnInit {
+ @Input() public data: any[] = [];
+ @Input() public dataSchema: IDataSchema;
+ @Input() public dataUrl: string;
+ @Input() public label: string;
+ @Input() public placeholder: string;
+ @Output() public itemSelected: EventEmitter<any> = new EventEmitter<any>();
+
+ private searchQuery: string;
+ private complexData: any[] = [];
+ private autoCompleteResults: any[] = [];
+ private isItemSelected: boolean = false;
+
+ public constructor(private http: Http, private autocompletePipe: AutocompletePipe) {
+ }
+
+ public ngOnInit(): void {
+ if (this.data) {
+ this.handleLocalData();
+ }
+ this.searchQuery = "";
+ }
+
+ private handleLocalData = (): void => {
+ // Convert the data (simple | complex) to unified complex data with key value.
+ // In case user supplied dataSchema, this is complex data
+ if (!this.dataSchema) {
+ this.convertSimpleData();
+ } else {
+ this.convertComplexData();
+ }
+ }
+
+ private convertSimpleData = (): void => {
+ this.complexData = [];
+ this.data.forEach((item: any) => {
+ this.complexData.push({key: item, value: item});
+ });
+ }
+
+ private convertComplexData = (): void => {
+ this.complexData = [];
+ this.data.forEach((item: any) => {
+ this.complexData.push({key: item[this.dataSchema.key], value: item[this.dataSchema.value]});
+ });
+ }
+
+ private onItemSelected = (selectedItem: IDataSchema): void => {
+ this.searchQuery = selectedItem.value;
+ this.isItemSelected = true;
+ this.autoCompleteResults = [];
+ this.itemSelected.emit(selectedItem.key);
+ }
+
+ private onSearchQueryChanged = (searchText: string): void => {
+ if (searchText !== this.searchQuery) {
+ this.searchQuery = searchText;
+ if (!this.searchQuery) {
+ this.onClearSearch();
+ } else {
+ if (this.dataUrl) {
+ const params: URLSearchParams = new URLSearchParams();
+ params.set('searchQuery', this.searchQuery);
+ this.http.get(this.dataUrl, {search: params})
+ .map((response) => {
+ this.data = response.json();
+ this.handleLocalData();
+ this.autoCompleteResults = this.complexData;
+ }).subscribe();
+ } else {
+ this.autoCompleteResults = this.autocompletePipe.transform(this.complexData, this.searchQuery);
+ }
+ }
+ this.isItemSelected = false;
+ }
+ }
+
+ private onClearSearch = (): void => {
+ this.autoCompleteResults = [];
+ if (this.isItemSelected) {
+ this.itemSelected.emit();
+ }
+ }
+}
diff --git a/src/angular/autocomplete/autocomplete.module.ts b/src/angular/autocomplete/autocomplete.module.ts
new file mode 100644
index 0000000..1bead47
--- /dev/null
+++ b/src/angular/autocomplete/autocomplete.module.ts
@@ -0,0 +1,23 @@
+import { NgModule } from "@angular/core";
+import { SearchWithAutoCompleteComponent } from "./autocomplete.component";
+import { CommonModule } from "@angular/common";
+import { FilterBarModule } from "../filterbar/filter-bar.module";
+import { AutocompletePipe } from "./autocomplete.pipe";
+import { HttpModule } from '@angular/http';
+
+@NgModule({
+ declarations: [
+ SearchWithAutoCompleteComponent,
+ AutocompletePipe
+ ],
+ imports: [
+ FilterBarModule,
+ CommonModule,
+ HttpModule
+ ],
+ exports: [
+ SearchWithAutoCompleteComponent
+ ],
+})
+export class AutoCompleteModule {
+}
diff --git a/src/angular/autocomplete/autocomplete.pipe.ts b/src/angular/autocomplete/autocomplete.pipe.ts
new file mode 100644
index 0000000..bee24ab
--- /dev/null
+++ b/src/angular/autocomplete/autocomplete.pipe.ts
@@ -0,0 +1,16 @@
+import { Pipe, PipeTransform } from '@angular/core';
+import { IDataSchema } from './autocomplete.component';
+
+@Pipe ({
+ name: 'AutocompletePipe',
+})
+export class AutocompletePipe implements PipeTransform {
+ public transform(data: IDataSchema[], text: string) {
+ if (!text || !text.length) {
+ return data;
+ }
+ return data.filter((item: IDataSchema) => {
+ return item.value.toLowerCase().indexOf(text.toLowerCase()) > -1;
+ });
+ }
+}
diff --git a/src/angular/buttons/button.component.html.ts b/src/angular/buttons/button.component.html.ts
new file mode 100644
index 0000000..f903fd1
--- /dev/null
+++ b/src/angular/buttons/button.component.html.ts
@@ -0,0 +1,15 @@
+export default `
+<button class="sdc-button sdc-button__{{ type }} btn-{{ size }} {{ iconPositionClass }}"
+ [disabled] = "disabled || show_spinner"
+ [attr.data-tests-id]="testId">
+ <svg-icon
+ *ngIf="icon_name"
+ [name]="icon_name"
+ [mode]="iconMode"
+ [size]="'medium'"
+ >
+ </svg-icon>
+ {{ text }}
+</button>
+<svg-icon *ngIf="show_spinner" name="spinner" [size]="'medium'" class="sdc-button__spinner" [ngClass]="{left: spinner_position === placement.right}"></svg-icon>
+`;
diff --git a/src/angular/buttons/button.component.ts b/src/angular/buttons/button.component.ts
new file mode 100644
index 0000000..1f049dc
--- /dev/null
+++ b/src/angular/buttons/button.component.ts
@@ -0,0 +1,62 @@
+import { Component, HostBinding, Input, OnInit } from "@angular/core";
+import { Placement } from "../common/enums";
+import template from "./button.component.html";
+
+@Component({
+ selector: "sdc-button",
+ template: template
+})
+
+export class ButtonComponent implements OnInit {
+ @Input() public text: string;
+ @Input() public disabled: boolean;
+ @Input() public type: string;
+ @Input() public size: string;
+ @Input() public preventDoubleClick: boolean;
+ @Input() public icon_name: string;
+ @Input() public icon_position: string;
+ @Input() public show_spinner: boolean;
+ @Input() public spinner_position: Placement;
+ @Input() public testId: string;
+
+ public placement = Placement;
+ private lastClick: Date;
+ private iconPositionClass: string;
+ private iconMode: string;
+
+ @HostBinding('class.sdc-button__wrapper') true;
+
+ constructor() {
+ this.type = "primary";
+ this.size = "default";
+ this.disabled = false;
+ this.iconMode = 'primary';
+ }
+
+ public ngOnInit(): void {
+ this.iconPositionClass = this.icon_position ? 'sdc-icon-' + this.icon_position : '';
+ this.iconMode = (this.type === "primary") ? 'info' : 'primary';
+ }
+
+ public onClick = (e): void => {
+ const now: Date = new Date();
+ if ( this.preventDoubleClick && this.lastClick && (now.getTime() - this.lastClick.getTime()) <= 500 ) {
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ this.lastClick = now;
+ }
+
+ public disableButton = () => {
+ if (!this.disabled) {
+ this.disabled = true;
+ }
+ }
+
+ public enableButton = () => {
+ if (this.disabled) {
+ this.disabled = false;
+ }
+ }
+
+}
diff --git a/src/angular/buttons/buttons.module.ts b/src/angular/buttons/buttons.module.ts
new file mode 100644
index 0000000..c804758
--- /dev/null
+++ b/src/angular/buttons/buttons.module.ts
@@ -0,0 +1,21 @@
+import { NgModule } from "@angular/core";
+import { ButtonComponent } from "./button.component";
+import { CommonModule } from "@angular/common";
+import { SvgIconModule } from './../svg-icon/svg-icon.module';
+
+@NgModule({
+ declarations: [
+ ButtonComponent
+ ],
+ imports: [
+ CommonModule,
+ SvgIconModule
+ ],
+ exports: [
+ ButtonComponent
+
+ ],
+})
+export class ButtonsModule {
+
+}
diff --git a/src/angular/checklist/checklist.component.html.ts b/src/angular/checklist/checklist.component.html.ts
new file mode 100644
index 0000000..cb6f540
--- /dev/null
+++ b/src/angular/checklist/checklist.component.html.ts
@@ -0,0 +1,15 @@
+export default `
+<div *ngFor="let checkbox of checklistModel.checkboxes" #currentCheckbox>
+ <div class="checkbox-item">
+ <sdc-checkbox [label]="checkbox.label"
+ [(checked)]="checkbox.isChecked"
+ [disabled]="checkbox.disabled"
+ (checkedChange)="checkboxCheckedChange(checkbox, checklistModel)"
+ [ngClass]="{'semi-checked': !checkbox.isChecked && hasCheckedChild(currentCheckbox)}"></sdc-checkbox>
+ </div>
+ <div *ngIf="checkbox.subLevelChecklist" class="checkbox-sublist">
+ <sdc-checklist [checklistModel]="checkbox.subLevelChecklist"
+ (checkedChange)="childCheckboxChange($event, checkbox)"></sdc-checklist>
+ </div>
+</div>
+`;
diff --git a/src/angular/checklist/checklist.component.ts b/src/angular/checklist/checklist.component.ts
new file mode 100644
index 0000000..386cd3e
--- /dev/null
+++ b/src/angular/checklist/checklist.component.ts
@@ -0,0 +1,50 @@
+import { Component, EventEmitter, Input, Output } from "@angular/core";
+import { ChecklistModel } from "./models/Checklist";
+import { ChecklistItemModel } from "./models/ChecklistItem";
+import template from "./checklist.component.html";
+
+@Component({
+ selector: 'sdc-checklist',
+ template: template
+})
+export class ChecklistComponent {
+ @Input() public checklistModel: ChecklistModel;
+ @Output() public checkedChange: EventEmitter<ChecklistItemModel> = new EventEmitter<ChecklistItemModel>();
+
+ private checkboxCheckedChange(checkbox: ChecklistItemModel, currentChecklistModel: ChecklistModel, stopPropagation?: boolean) {
+ // push/pop the checkbox value
+ if (checkbox.isChecked) {
+ currentChecklistModel.selectedValues.push(checkbox.value);
+ }else {
+ const index: number = currentChecklistModel.selectedValues.indexOf(checkbox.value);
+ currentChecklistModel.selectedValues.splice(index, 1);
+ }
+ if (!stopPropagation) {
+ if (checkbox.subLevelChecklist &&
+ ((checkbox.isChecked && checkbox.subLevelChecklist.selectedValues.length < checkbox.subLevelChecklist.checkboxes.length) ||
+ (!checkbox.isChecked && checkbox.subLevelChecklist.selectedValues.length))) {
+ checkbox.subLevelChecklist.checkboxes.forEach((childCheckbox: ChecklistItemModel) => {
+ if (childCheckbox.isChecked !== checkbox.isChecked) {
+ childCheckbox.isChecked = checkbox.isChecked;
+ this.checkboxCheckedChange(childCheckbox, checkbox.subLevelChecklist);
+ }
+ });
+ }
+ }
+ // raise event
+ this.checkedChange.emit(checkbox);
+ }
+
+ private childCheckboxChange(updatedCheckbox: ChecklistItemModel, parentCheckbox: ChecklistItemModel) {
+ let updatedValues: any[] = parentCheckbox.subLevelChecklist.selectedValues;
+ if (parentCheckbox.isChecked !== (updatedValues.length === parentCheckbox.subLevelChecklist.checkboxes.length)) {
+ parentCheckbox.isChecked = updatedValues.length === parentCheckbox.subLevelChecklist.checkboxes.length;
+ this.checkboxCheckedChange(parentCheckbox, this.checklistModel, true);
+ }
+ this.checkedChange.emit(updatedCheckbox);
+ }
+
+ private hasCheckedChild(currentCheckbox: Element): boolean {
+ return !!currentCheckbox.querySelector(".sdc-checkbox__input:checked");
+ }
+}
diff --git a/src/angular/checklist/checklist.module.ts b/src/angular/checklist/checklist.module.ts
new file mode 100644
index 0000000..013bf9b
--- /dev/null
+++ b/src/angular/checklist/checklist.module.ts
@@ -0,0 +1,11 @@
+import { NgModule } from "@angular/core";
+import { ChecklistComponent } from "./checklist.component";
+import { CommonModule } from "@angular/common";
+import { FormElementsModule } from "../form-elements/form-elements.module";
+
+@NgModule({
+ declarations: [ChecklistComponent],
+ exports: [ChecklistComponent],
+ imports: [CommonModule, FormElementsModule]
+})
+export class ChecklistModule {}
diff --git a/src/angular/checklist/models/Checklist.ts b/src/angular/checklist/models/Checklist.ts
new file mode 100644
index 0000000..7b50dd3
--- /dev/null
+++ b/src/angular/checklist/models/Checklist.ts
@@ -0,0 +1,18 @@
+import { ChecklistItemModel } from "./ChecklistItem";
+
+export class ChecklistModel {
+ public selectedValues: any[];
+ public checkboxes: ChecklistItemModel[];
+ constructor(selectedValues: any[], checkboxes: ChecklistItemModel[]) {
+ this.selectedValues = selectedValues || [];
+ this.checkboxes = checkboxes;
+ // align the selected values list and checkboxes isChecked param
+ this.checkboxes.forEach((checkbox: ChecklistItemModel) => {
+ if (this.selectedValues.indexOf(checkbox.value) > -1) {
+ checkbox.isChecked = true;
+ }else if (checkbox.isChecked) {
+ this.selectedValues.push(checkbox.value);
+ }
+ });
+ }
+}
diff --git a/src/angular/checklist/models/ChecklistItem.ts b/src/angular/checklist/models/ChecklistItem.ts
new file mode 100644
index 0000000..e2d812a
--- /dev/null
+++ b/src/angular/checklist/models/ChecklistItem.ts
@@ -0,0 +1,17 @@
+import { ChecklistModel } from "./Checklist";
+import { isUndefined } from "util";
+
+export class ChecklistItemModel {
+ public label: string;
+ public value: any;
+ public disabled: boolean;
+ public isChecked: boolean;
+ public subLevelChecklist: ChecklistModel;
+ constructor(label: string, disabled?: boolean, isChecked?: boolean, subLevelChecklist?: ChecklistModel, value?: any) {
+ this.label = label;
+ this.disabled = disabled;
+ this.isChecked = isChecked;
+ this.value = isUndefined(value) ? label : value;
+ this.subLevelChecklist = subLevelChecklist;
+ }
+}
diff --git a/src/angular/common/enums.ts b/src/angular/common/enums.ts
new file mode 100644
index 0000000..0825d2f
--- /dev/null
+++ b/src/angular/common/enums.ts
@@ -0,0 +1,34 @@
+/*
+This file includes all common enum types.
+
+NOTE: The string values might be used as css class names.
+*/
+
+export enum Size {
+ x_large = 'x_large',
+ large = 'large',
+ medium = 'medium',
+ small = 'small',
+ x_small = 'x_small'
+}
+
+export enum Mode {
+ primary = 'primary',
+ secondary = 'secondary',
+ success = 'success',
+ error = 'error',
+ warning = 'warning',
+ info = 'info'
+}
+
+export enum Placement {
+ left = 'left',
+ right = 'right',
+ top = 'top',
+ bottom = 'bottom'
+}
+
+export enum RegexPatterns {
+ email = '^(([^<>()\\[\\]\\\\.,;:\\s@"]+(\.[^<>()\\[\\]\\\\.,;:\\s@"]+)*)|(".+"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$',
+ numbers = '^\\d+$'
+}
diff --git a/src/angular/common/index.ts b/src/angular/common/index.ts
new file mode 100644
index 0000000..839eba9
--- /dev/null
+++ b/src/angular/common/index.ts
@@ -0,0 +1,3 @@
+import * as SdcUiCommon from './enums';
+
+export { SdcUiCommon };
diff --git a/src/angular/components.ts b/src/angular/components.ts
new file mode 100644
index 0000000..8e06197
--- /dev/null
+++ b/src/angular/components.ts
@@ -0,0 +1,50 @@
+/*
+ Exports all the components and services of sdc-ui.
+ */
+
+// Form Elements
+export { InputComponent } from "./form-elements/input/input.component";
+export { DropDownComponent } from "./form-elements/dropdown/dropdown.component";
+export { CheckboxComponent } from "./form-elements/checkbox/checkbox.component";
+export { RadioGroupComponent } from "./form-elements/radios/radio-buttons-group.component";
+
+// Buttons
+export { ButtonComponent } from "./buttons/button.component";
+
+// Modals
+export { ModalComponent } from "./modals/modal.component";
+export { ModalService } from "./modals/modal.service";
+export { ModalButtonComponent } from "./modals/modal-button.component";
+
+// Notifications
+export { NotificationComponent } from "./notifications/notification/notification.component";
+export { NotificationContainerComponent } from "./notifications/container/notifcontainer.component";
+export { NotificationsService } from "./notifications/services/notifications.service";
+
+// Popup Menu
+export { PopupMenuListComponent } from "./popup-menu/popup-menu-list.component";
+export { PopupMenuItemComponent } from "./popup-menu/popup-menu-item.component";
+
+// Tiles
+export { TileComponent } from "./tiles/tile.component";
+export { TileContentComponent } from "./tiles/children/tile-content.component";
+export { TileFooterComponent } from "./tiles/children/tile-footer.component";
+export { TileHeaderComponent } from "./tiles/children/tile-header.component";
+
+// Check List
+export { ChecklistComponent } from "./checklist/checklist.component";
+
+// Tag Cloud
+export { TagItemComponent } from "./tag-cloud/tag-item/tag-item.component";
+export { TagCloudComponent } from "./tag-cloud/tag-cloud.component";
+
+// Tabs
+export { TabsComponent } from "./tabs/tabs.component";
+export { TabComponent } from './tabs/children/tab.component';
+
+// Svg Icons
+export { SvgIconComponent } from "./svg-icon/svg-icon.component";
+export { SvgIconLabelComponent } from "./svg-icon/svg-icon-label.component";
+
+// Accordion
+export { AccordionComponent } from './accordion/accordion.component';
diff --git a/src/angular/filterbar/filter-bar.component.html.ts b/src/angular/filterbar/filter-bar.component.html.ts
new file mode 100644
index 0000000..a7d55e2
--- /dev/null
+++ b/src/angular/filterbar/filter-bar.component.html.ts
@@ -0,0 +1,30 @@
+export default `
+<div class="search-bar-container">
+ <sdc-input class="search-bar-input"
+ [label]="label"
+ [placeHolder]="placeholder"
+ [debounceTime]="debounceTime"
+ [(value)]="searchQuery"
+ (valueChange)="searchTextChange($event)"></sdc-input>
+ <span class="clear-search-x filter-button" *ngIf="searchQuery" (click)="clearSearchQuery()">
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+ <defs>
+ <path id="close-a" d="M13.5996,12 L19.6576,5.942 C20.1146,5.485 20.1146,4.8 19.6576,4.343 C19.2006,3.886 18.5146,3.886 18.0576,4.343 L11.9996,10.4 L5.9426,4.343 C5.4856,3.886 4.7996,3.886 4.3426,4.343 C3.8856,4.8 3.8856,5.485 4.3426,5.942 L10.4006,12 L4.3426,18.058 C3.8856,18.515 3.8856,19.2 4.3426,19.657 C4.5716,19.886 4.7996,20 5.1426,20 C5.4856,20 5.7136,19.886 5.9426,19.657 L11.9996,13.6 L18.0576,19.657 C18.2866,19.886 18.6286,20 18.8576,20 C19.0856,20 19.4286,19.886 19.6576,19.657 C20.1146,19.2 20.1146,18.515 19.6576,18.058 L13.5996,12 Z"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd">
+ <use fill="#000" xlink:href="#close-a"/>
+ </g>
+ </svg>
+ </span>
+ <span class="magnify-button filter-button" *ngIf="!searchQuery">
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+ <defs>
+ <path id="search-a" d="M2,8.5 C2,4.9 4.9,2 8.5,2 C12.1,2 15,4.9 15,8.5 C15,10.3 14.3,11.9 13.1,13.1 C11.9,14.3 10.3,15 8.5,15 C4.9,15 2,12.1 2,8.5 M19.7,18.3 L15.2,13.8 C16.3,12.4 17,10.5 17,8.5 C17,3.8 13.2,0 8.5,0 C3.8,0 0,3.8 0,8.5 C0,13.2 3.8,17 8.5,17 C10.5,17 12.3,16.3 13.8,15.2 L18.3,19.7 C18.5,19.9 18.8,20 19,20 C19.2,20 19.5,19.9 19.7,19.7 C20.1,19.3 20.1,18.7 19.7,18.3"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd" transform="translate(2 2)">
+ <use fill="#000" xlink:href="#search-a"/>
+ </g>
+ </svg>
+ </span>
+</div>
+`;
diff --git a/src/angular/filterbar/filter-bar.component.ts b/src/angular/filterbar/filter-bar.component.ts
new file mode 100644
index 0000000..49cc154
--- /dev/null
+++ b/src/angular/filterbar/filter-bar.component.ts
@@ -0,0 +1,30 @@
+import { Component, Input, Output, EventEmitter, HostBinding } from '@angular/core';
+import template from "./filter-bar.component.html";
+
+@Component({
+ selector: 'sdc-filter-bar',
+ template: template
+})
+export class FilterBarComponent {
+
+ @HostBinding('class') classes = 'sdc-filter-bar';
+
+ @Input() public placeholder: string;
+ @Input() public label: string;
+ @Input() public debounceTime: number;
+
+ @Input() public searchQuery: string;
+ @Output() public searchQueryChange: EventEmitter<any> = new EventEmitter<any>();
+
+ constructor() {
+ this.debounceTime = 200;
+ }
+
+ private searchTextChange = ($event): void => {
+ this.searchQueryChange.emit($event);
+ }
+
+ private clearSearchQuery = (): void => {
+ this.searchQuery = "";
+ }
+}
diff --git a/src/angular/filterbar/filter-bar.module.ts b/src/angular/filterbar/filter-bar.module.ts
new file mode 100644
index 0000000..c3604ed
--- /dev/null
+++ b/src/angular/filterbar/filter-bar.module.ts
@@ -0,0 +1,17 @@
+import { NgModule } from "@angular/core";
+import { FilterBarComponent } from "./filter-bar.component";
+import { CommonModule } from "@angular/common";
+import { FormElementsModule } from "../form-elements/form-elements.module";
+
+@NgModule({
+ declarations: [
+ FilterBarComponent
+ ],
+ imports: [CommonModule,
+ FormElementsModule],
+ exports: [
+ FilterBarComponent
+ ],
+})
+export class FilterBarModule {
+}
diff --git a/src/angular/form-elements/checkbox/checkbox.component.html.ts b/src/angular/form-elements/checkbox/checkbox.component.html.ts
new file mode 100644
index 0000000..f4031db
--- /dev/null
+++ b/src/angular/form-elements/checkbox/checkbox.component.html.ts
@@ -0,0 +1,8 @@
+export default `
+<div class="sdc-checkbox">
+ <label SdcRippleClickAnimation [rippleClickDisabled]="disabled">
+ <input type="checkbox" class="sdc-checkbox__input" [ngModel]="checked" (ngModelChange)="toggleState($event)" [disabled]="disabled">
+ <span class="sdc-checkbox__label">{{ label }}</span>
+ </label>
+</div>
+`;
diff --git a/src/angular/form-elements/checkbox/checkbox.component.spec.ts b/src/angular/form-elements/checkbox/checkbox.component.spec.ts
new file mode 100644
index 0000000..36f478e
--- /dev/null
+++ b/src/angular/form-elements/checkbox/checkbox.component.spec.ts
@@ -0,0 +1,37 @@
+import { TestBed, async } from '@angular/core/testing';
+import { CheckboxComponent } from "./checkbox.component";
+import { AnimationDirectivesModule } from "../../animations/animation-directives.module";
+import { FormsModule } from "@angular/forms";
+
+
+describe("Checbox Tests", ()=>{
+ let component: CheckboxComponent;
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [
+ CheckboxComponent
+ ],
+ imports:[
+ FormsModule,
+ AnimationDirectivesModule
+ ]
+ }).compileComponents();
+ const fixture = TestBed.createComponent(CheckboxComponent);
+ component = fixture.componentInstance;
+ }));
+
+ it("Component Created", async(()=> {
+ expect(component).toBeDefined();
+ }));
+
+ it( "Test Value suppose to be toggled", async( ()=> {
+ component.toggleState(true)
+ expect(component.checked).toEqual(true);
+ }));
+
+ it( "If disabled not toggled"), async(()=>{
+ component.disabled = true;
+ component.toggleState(true);
+ expect(component.checked).toEqual(false);
+ });
+});
diff --git a/src/angular/form-elements/checkbox/checkbox.component.ts b/src/angular/form-elements/checkbox/checkbox.component.ts
new file mode 100644
index 0000000..ec05eac
--- /dev/null
+++ b/src/angular/form-elements/checkbox/checkbox.component.ts
@@ -0,0 +1,21 @@
+import { Component, Input, Output, EventEmitter, ViewEncapsulation } from '@angular/core';
+import template from "./checkbox.component.html";
+
+@Component({
+ selector: 'sdc-checkbox',
+ template: template,
+ encapsulation: ViewEncapsulation.None
+})
+export class CheckboxComponent {
+ @Input() label:string;
+ @Input() checked:boolean;
+ @Input() disabled:boolean;
+ @Output() checkedChange:EventEmitter<any> = new EventEmitter<any>();
+
+ public toggleState(newState:boolean) {
+ if (!this.disabled) {
+ this.checked = newState;
+ this.checkedChange.emit(newState);
+ }
+ }
+}
diff --git a/src/angular/form-elements/dropdown/dropdown-models.ts b/src/angular/form-elements/dropdown/dropdown-models.ts
new file mode 100644
index 0000000..fa8dc23
--- /dev/null
+++ b/src/angular/form-elements/dropdown/dropdown-models.ts
@@ -0,0 +1,18 @@
+export enum DropDownTypes {
+ Regular,
+ Headless,
+ Auto
+}
+
+export enum DropDownOptionType {
+ Simple, // default
+ Header,
+ Disable,
+ HorizontalLine
+}
+
+export interface IDropDownOption {
+ value: any;
+ label: string;
+ type?: DropDownOptionType;
+}
diff --git a/src/angular/form-elements/dropdown/dropdown-trigger.directive.ts b/src/angular/form-elements/dropdown/dropdown-trigger.directive.ts
new file mode 100644
index 0000000..94ab3bc
--- /dev/null
+++ b/src/angular/form-elements/dropdown/dropdown-trigger.directive.ts
@@ -0,0 +1,17 @@
+import { Directive, Input, HostBinding, HostListener } from "@angular/core";
+import { DropDownComponent } from "./dropdown.component";
+
+@Directive({
+ selector: '[SdcDropdownTrigger]'
+})
+
+export class DropDownTriggerDirective {
+
+ @HostBinding('class.js-sdc-dropdown--toggle-hook') true;
+ @Input() dropDown: DropDownComponent;
+
+ @HostListener('click', ['$event']) onClick = (event) => {
+ this.dropDown.toggleDropdown(event);
+ }
+
+}
diff --git a/src/angular/form-elements/dropdown/dropdown.component.html.ts b/src/angular/form-elements/dropdown/dropdown.component.html.ts
new file mode 100644
index 0000000..a4247a4
--- /dev/null
+++ b/src/angular/form-elements/dropdown/dropdown.component.html.ts
@@ -0,0 +1,59 @@
+export default `
+<div class="sdc-dropdown" #dropDownWrapper
+ [ngClass]="{
+ 'headless': type === cIDropDownTypes.Headless,
+ 'sdc-dropdown__error': !valid,
+ 'open-bottom': show && bottomVisible,
+ 'open-top':show && !bottomVisible}">
+ <label *ngIf="label" class="sdc-dropdown__label" [ngClass]="{'required':required}">{{label}}</label>
+ <div class="sdc-dropdown__component-container">
+
+ <!--[DROP-DOWN AUTO HEADER START]-->
+ <div *ngIf="type===cIDropDownTypes.Auto" class="sdc-dropdown-auto__wrapper">
+ <input class="sdc-dropdown__header js-sdc-dropdown--toggle-hook"
+ [(ngModel)]="this.filterValue"
+ (ngModelChange)="filterOptions(this.filterValue)"
+ placeholder="{{this.selectedOption?.label || this.selectedOption?.value || placeHolder}}">
+ <svg-icon name="caret1-down-o" mode="secondary" size="small" (click)="toggleDropdown($event)"></svg-icon>
+ </div>
+ <!--[DROP-DOWN AUTO HEADER END]-->
+
+ <!--[DROP-DOWN REGULAR HEADER START]-->
+ <button *ngIf="type===cIDropDownTypes.Regular"
+ class="sdc-dropdown__header js-sdc-dropdown--toggle-hook"
+ (click)="toggleDropdown($event)"
+ [ngClass]="{'disabled': disabled, 'placeholder':!this.selectedOption}">
+ {{ this.selectedOption?.label || this.selectedOption?.value || placeHolder}}
+ <svg-icon name="caret1-down-o" mode="secondary" size="small"></svg-icon>
+ </button>
+ <!--[DROP-DOWN HEADER END]-->
+
+ <!--[DROP-DOWN OPTIONS START]-->
+ <div class="sdc-dropdown__options-wrapper--frame" [ngClass]="{
+ 'sdc-dropdown__options-wrapper--top':!bottomVisible,
+ 'sdc-dropdown__options-wrapper--uncollapsed':show
+ }">
+ <ul #optionsContainerElement *ngIf="options" class="sdc-dropdown__options-list" [ngClass]="{
+ 'sdc-dropdown__options-list--headless': headless,
+ 'sdc-dropdown__options-list--animation-init':animation_init
+ }">
+ <ng-container *ngFor="let option of options; let i = index">
+ <!--[Drop down item list or string list start]-->
+ <li *ngIf="option" class="sdc-dropdown__option"
+ [ngClass]="{
+ 'selected': option == selectedOption,
+ 'sdc-dropdown__option--group':isGroupDesign,
+ 'sdc-dropdown__option--header': option.type && option.type === cIDropDownOptionType.Header,
+ 'sdc-dropdown__option--disabled': option.type && option.type === cIDropDownOptionType.Disable,
+ 'sdc-dropdown__option--hr': option.type && option.type === cIDropDownOptionType.HorizontalLine
+ }"
+ (click)="selectOption(option.value, $event)">{{option.label || String(option.value)}}</li>
+ <!--[Drop down item list or string list end]-->
+ </ng-container>
+ </ul>
+ </div>
+ <!--[DROP-DOWN OPTIONS END]-->
+
+ </div>
+</div>
+`;
diff --git a/src/angular/form-elements/dropdown/dropdown.component.spec.ts b/src/angular/form-elements/dropdown/dropdown.component.spec.ts
new file mode 100644
index 0000000..1c0cb4d
--- /dev/null
+++ b/src/angular/form-elements/dropdown/dropdown.component.spec.ts
@@ -0,0 +1,71 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { DropDownComponent } from './dropdown.component';
+import { IDropDownOption, DropDownTypes } from "./dropdown-models";
+import { FormsModule } from "@angular/forms";
+import {SvgIconModule} from "../../svg-icon/svg-icon.module";
+
+
+const label:string = "DropDown example";
+const placeHolder:string = "Please choose option";
+const options:IDropDownOption[] = [
+ {
+ label:'First Option',
+ value: 'First Option'
+ },
+ {
+ label:'Second Option',
+ value: 'Second Option'
+ },
+ {
+ label:'Third Option',
+ value: 'Third Option'
+ }
+];
+
+describe('DropDown component', () => {
+ let fixture: ComponentFixture<DropDownComponent>;
+ let component: DropDownComponent;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ DropDownComponent ],
+ imports:[
+ FormsModule,
+ SvgIconModule
+ ]
+ }).compileComponents();
+ fixture = TestBed.createComponent(DropDownComponent);
+ component = fixture.componentInstance;
+
+ }));
+
+ beforeEach(()=>{
+ component.label = label;
+ component.placeHolder = placeHolder;
+ component.options = options;
+ component.type = DropDownTypes.Regular;
+ console.log('herer we got component', component)
+ fixture.detectChanges();
+ });
+
+ it('component should be created', () => {
+ expect(component).toBeTruthy();
+ });
+
+ it('component should export the selected value', () => {
+ const option = options[1];
+ component.selectOption(option);
+ fixture.detectChanges();
+ expect(component.selectedOption).toEqual(option);
+ });
+
+ it('component should have autocomplite', () => {
+ expect(component.options.length).toEqual(3);
+ component.type = DropDownTypes.Auto;
+ component.filterValue = 'testERrorotesttresadfadfasdfasf';
+ fixture.detectChanges();
+ component.filterOptions(component.filterValue);
+ expect(component.options.length).toEqual(0);
+ });
+
+});
diff --git a/src/angular/form-elements/dropdown/dropdown.component.ts b/src/angular/form-elements/dropdown/dropdown.component.ts
new file mode 100644
index 0000000..a23072f
--- /dev/null
+++ b/src/angular/form-elements/dropdown/dropdown.component.ts
@@ -0,0 +1,149 @@
+import { Component, EventEmitter, Input, Output, forwardRef, OnChanges, SimpleChanges, OnInit, ElementRef, ViewChild, AfterViewInit, HostListener, Renderer } from '@angular/core';
+import { IDropDownOption, DropDownOptionType, DropDownTypes } from "./dropdown-models";
+import { ValidatableComponent } from './../validation/validatable.component';
+import template from './dropdown.component.html';
+
+@Component({
+ selector: 'sdc-dropdown',
+ template: template
+})
+export class DropDownComponent extends ValidatableComponent implements OnChanges, OnInit {
+
+ @Output('changed') changeEmitter:EventEmitter<IDropDownOption> = new EventEmitter<IDropDownOption>();
+ @Input() label: string;
+ @Input() options: IDropDownOption[];
+ @Input() disabled: boolean;
+ @Input() placeHolder: string;
+ @Input() required: boolean;
+ @Input() maxHeight: number;
+ @Input() selectedOption: IDropDownOption;
+ @Input() type: DropDownTypes = DropDownTypes.Regular;
+ @ViewChild('dropDownWrapper') dropDownWrapper: ElementRef;
+ @ViewChild('optionsContainerElement') optionsContainerElement: ElementRef;
+ @HostListener('document:click', ['$event']) onClick(e) {
+ this.onClickDocument(e);
+ }
+
+ private bottomVisible = true;
+ private myRenderer: Renderer;
+
+ // Drop-down show/hide flag. default is false (closed)
+ public show = false;
+
+ // Export DropDownOptionType enum so we can use it on the template
+ public cIDropDownOptionType = DropDownOptionType;
+ public cIDropDownTypes = DropDownTypes;
+
+ // Configure unselectable option types
+ private unselectableOptions = [
+ DropDownOptionType.Disable,
+ DropDownOptionType.Header,
+ DropDownOptionType.HorizontalLine
+ ];
+
+ // Set or unset Group style on drop-down
+ public isGroupDesign = false;
+ public animation_init = false;
+ public allOptions: IDropDownOption[];
+ public filterValue: string;
+
+ constructor(public renderer: Renderer) {
+ super();
+ this.myRenderer = renderer;
+ this.maxHeight = 244;
+ this.filterValue = '';
+ }
+
+ ngOnInit(): void {
+ if (this.options) {
+ this.allOptions = this.options;
+ if (this.options.find(option => option.type === DropDownOptionType.Header)) {
+ this.isGroupDesign = true;
+ }
+ }
+ }
+
+ ngOnChanges(changes: SimpleChanges): void {
+ console.log("ngOnChanges");
+ if (changes.selectedOption && changes.selectedOption.currentValue !== changes.selectedOption.previousValue) {
+ if (typeof changes.selectedOption.currentValue === 'string' && this.isSelectable(changes.selectedOption.currentValue)) {
+ this.setSelected(changes.selectedOption.currentValue);
+ } else if (this.isSelectable(changes.selectedOption.currentValue.value)) {
+ this.setSelected(changes.selectedOption.currentValue.value);
+ } else {
+ this.setSelected(undefined);
+ }
+ }
+ }
+
+ public getValue(): any {
+ return this.selectedOption && this.selectedOption.value;
+ }
+
+ public selectOption = (option: IDropDownOption | string, event?): void => {
+ if (event) { event.stopPropagation(); }
+ if (this.type === DropDownTypes.Headless) {
+ // Hide the options when in headless mode and user select option.
+ this.myRenderer.setElementStyle(this.dropDownWrapper.nativeElement, 'display', 'none');
+ }
+ if (typeof option === 'string' && this.isSelectable(option)) {
+ this.setSelected(option);
+ } else if (this.isSelectable((option as IDropDownOption).value)) {
+ this.setSelected((option as IDropDownOption).value);
+ }
+ }
+
+ public toggleDropdown = (event?): void => {
+ if (event) { event.stopPropagation(); }
+ if (this.type === DropDownTypes.Headless) {
+ // Show the options when in headless mode.
+ this.myRenderer.setElementStyle(this.dropDownWrapper.nativeElement, 'display', 'block');
+ }
+ if (this.disabled) { return; }
+ this.animation_init = true;
+ this.bottomVisible = this.isBottomVisible();
+ this.show = !this.show;
+ }
+
+ public filterOptions = (filterValue): void => {
+ if (filterValue.length >= 1 && !this.show) { this.toggleDropdown(); }
+ if (this.selectedOption) { this.selectedOption = null; }
+ this.options = this.allOptions.filter((option) => {
+ return option.value.toLowerCase().indexOf(filterValue.toLowerCase()) > -1;
+ });
+ }
+
+ private isSelectable = (value: string): boolean => {
+ const option: IDropDownOption = this.options.find(o => o.value === value);
+ if (!option) { return false; }
+ if (!option.type) { return true; }
+ return !this.unselectableOptions.find(optionType => optionType === option.type);
+ }
+
+ private setSelected = (value: string): void => {
+ this.selectedOption = this.options.find(o => o.value === value);
+ if (this.type === DropDownTypes.Auto) { this.filterValue = value; }
+ this.show = false;
+ this.changeEmitter.next(this.selectedOption);
+ }
+
+ private isBottomVisible = (): boolean => {
+ const windowPos = window.innerHeight + window.pageYOffset;
+ const boundingRect = this.dropDownWrapper.nativeElement.getBoundingClientRect();
+ const dropDownPos = boundingRect.top + boundingRect.height + this.maxHeight;
+ return windowPos > dropDownPos;
+ }
+
+ private onClickDocument = (event): void => {
+ if (this.type === DropDownTypes.Headless) {
+ if (!this.optionsContainerElement.nativeElement.contains(event.target)) {
+ this.show = false;
+ }
+ } else {
+ if (!this.dropDownWrapper.nativeElement.contains(event.target)) {
+ this.show = false;
+ }
+ }
+ }
+
+}
diff --git a/src/angular/form-elements/form-elements.module.ts b/src/angular/form-elements/form-elements.module.ts
new file mode 100644
index 0000000..744f8b8
--- /dev/null
+++ b/src/angular/form-elements/form-elements.module.ts
@@ -0,0 +1,38 @@
+import { NgModule } from "@angular/core";
+import { FormsModule, ReactiveFormsModule } from "@angular/forms";
+import { InputComponent } from "./input/input.component";
+import { DropDownComponent } from "./dropdown/dropdown.component";
+import { CommonModule } from "@angular/common";
+import { CheckboxComponent } from "./checkbox/checkbox.component";
+import { RadioGroupComponent } from "./radios/radio-buttons-group.component";
+import { AnimationDirectivesModule } from '../animations/animation-directives.module';
+import { DropDownTriggerDirective } from "./dropdown/dropdown-trigger.directive";
+import {SvgIconModule} from "../svg-icon/svg-icon.module";
+import { ValidationModule } from './validation/validation.module';
+
+@NgModule({
+ imports: [
+ CommonModule,
+ FormsModule,
+ ReactiveFormsModule,
+ AnimationDirectivesModule,
+ SvgIconModule
+ ],
+ declarations: [
+ DropDownComponent,
+ InputComponent,
+ CheckboxComponent,
+ RadioGroupComponent,
+ DropDownTriggerDirective,
+ ],
+ exports: [
+ DropDownComponent,
+ DropDownTriggerDirective,
+ InputComponent,
+ CheckboxComponent,
+ RadioGroupComponent,
+ ValidationModule
+ ]
+})
+export class FormElementsModule {
+}
diff --git a/src/angular/form-elements/input/input.component.html.ts b/src/angular/form-elements/input/input.component.html.ts
new file mode 100644
index 0000000..f8a4609
--- /dev/null
+++ b/src/angular/form-elements/input/input.component.html.ts
@@ -0,0 +1,19 @@
+export default `
+<div class="sdc-input ">
+ <label class="sdc-input__label" *ngIf="label" [ngClass]="{'required':required}">{{label}}</label>
+ <input
+ class="sdc-input__input {{classNames}}"
+ [ngClass]="{'error': !valid, 'disabled':disabled}"
+ [attr.name]="name ? name : null"
+ [placeholder]="placeHolder"
+ [(ngModel)]="value"
+ [maxlength]="maxLength"
+ [minlength]="minLength"
+ [type]="type"
+ [formControl]="control"
+ [attr.disabled]="disabled ? 'disabled' : null"
+ (input)="onKeyPress($event.target.value)"
+ [attr.data-tests-id]="testId"
+ />
+</div>
+`;
diff --git a/src/angular/form-elements/input/input.component.ts b/src/angular/form-elements/input/input.component.ts
new file mode 100644
index 0000000..af0e9f4
--- /dev/null
+++ b/src/angular/form-elements/input/input.component.ts
@@ -0,0 +1,54 @@
+import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
+import { FormControl } from "@angular/forms";
+import { ValidationComponent } from '../validation/validation.component';
+import { ValidatableComponent } from './../validation/validatable.component';
+import 'rxjs/add/operator/debounceTime';
+import template from "./input.component.html";
+
+@Component({
+ selector: 'sdc-input',
+ template: template,
+})
+export class InputComponent extends ValidatableComponent implements OnInit {
+
+ @Output('valueChange') public baseEmitter: EventEmitter<any> = new EventEmitter<any>();
+ @Input() public label: string;
+ @Input() public value: any;
+ @Input() public name: string;
+ @Input() public classNames: string;
+ @Input() public disabled: boolean;
+ @Input() public type: string;
+ @Input() public placeHolder: string;
+ @Input() public required: boolean;
+ @Input() public minLength: number;
+ @Input() public maxLength: number;
+ @Input() public debounceTime: number;
+ @Input() public testId: string;
+
+ protected control: FormControl;
+
+ constructor() {
+ super();
+ this.control = new FormControl('', []);
+ this.debounceTime = 0;
+ this.placeHolder = '';
+ this.type = 'text';
+ }
+
+ ngOnInit() {
+ this.control.valueChanges.
+ debounceTime(this.debounceTime)
+ .subscribe((newValue: any) => {
+ this.baseEmitter.emit(this.value);
+ });
+ }
+
+ public getValue(): any {
+ return this.value;
+ }
+
+ onKeyPress(value: string) {
+ this.valueChanged(this.value);
+ }
+
+}
diff --git a/src/angular/form-elements/radios/radio-button.model.ts b/src/angular/form-elements/radios/radio-button.model.ts
new file mode 100644
index 0000000..1ad4b3f
--- /dev/null
+++ b/src/angular/form-elements/radios/radio-button.model.ts
@@ -0,0 +1,15 @@
+export interface IRadioButtonModel {
+ label: string;
+ disabled: boolean;
+ name: string;
+ value: string;
+};
+
+export interface IOptionGroup {
+ items: IRadioButtonModel[];
+};
+
+export enum Direction {
+ vertical,
+ horizontal
+}
diff --git a/src/angular/form-elements/radios/radio-buttons-group.component.html.ts b/src/angular/form-elements/radios/radio-buttons-group.component.html.ts
new file mode 100644
index 0000000..28a27af
--- /dev/null
+++ b/src/angular/form-elements/radios/radio-buttons-group.component.html.ts
@@ -0,0 +1,20 @@
+export default `
+<label class='sdc-radio-group__legend'>{{legend}}</label>
+<div class='sdc-radio-group__radios {{direction}}'>
+ <template *ngFor="let item of options.items">
+ <div class="sdc-radio">
+ <label class="sdc-radio__animation-wrapper" SdcRippleClickAnimation [rippleClickDisabled]="disabled">
+ <input class="sdc-radio__input"
+ type="radio"
+ name="{{item.name}}"
+ value="{{item.value}}"
+ disabled="{{disabled || item.disabled || false}}"
+ (change)="onValueChanged(item.value)"
+ [(ngModel)]="value"
+ />
+ <span class="sdc-radio__label">{{ item.label }}</span>
+ </label>
+ </div>
+ </template>
+</div>
+`;
diff --git a/src/angular/form-elements/radios/radio-buttons-group.component.spec.ts b/src/angular/form-elements/radios/radio-buttons-group.component.spec.ts
new file mode 100644
index 0000000..273a701
--- /dev/null
+++ b/src/angular/form-elements/radios/radio-buttons-group.component.spec.ts
@@ -0,0 +1,52 @@
+import { TestBed, async } from '@angular/core/testing';
+import { RadioGroupComponent } from "./radio-buttons-group.component";
+import { FormsModule } from "@angular/forms";
+import { IRadioButtonModel } from "./radio-button.model";
+import { AnimationDirectivesModule } from "../../animations/animation-directives.module";
+
+
+describe("Radio Buttons unit-tests", ()=>{
+ let component: RadioGroupComponent;
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [
+ RadioGroupComponent
+ ],
+ imports:[
+ FormsModule,
+ AnimationDirectivesModule
+ ]
+ }).compileComponents();
+
+ const fixture = TestBed.createComponent(RadioGroupComponent);
+ component = fixture.componentInstance;
+ component.disabled = false;//TODO constructor
+ component.options = {
+ items: []
+ };
+ }));
+
+ it('Component Created', async(()=> {
+ expect(component).toBeDefined();
+ }));
+
+ it('Not possible to choose value which not exists', async(() =>{
+ component.value = 'test';
+ expect(component.value).not.toEqual('test');
+ }));
+
+ it('Normal flow', async(() =>{
+ component.options.items = [ <IRadioButtonModel> {
+ value: 'val1',
+ name: 'exp6',
+ label: 'Label of Radio1'
+ }, <IRadioButtonModel> {
+ value: 'val2',
+ name: 'exp6',
+ label: 'Label of Radio2'
+ }];
+ component.value = component.options.items[0].value;
+ expect(component.value).toEqual(component.options.items[0].value);
+ }));
+
+});
diff --git a/src/angular/form-elements/radios/radio-buttons-group.component.ts b/src/angular/form-elements/radios/radio-buttons-group.component.ts
new file mode 100644
index 0000000..800d8b0
--- /dev/null
+++ b/src/angular/form-elements/radios/radio-buttons-group.component.ts
@@ -0,0 +1,52 @@
+import { Component, Input, Output, ViewEncapsulation, EventEmitter, HostBinding } from "@angular/core";
+import { Direction, IOptionGroup, IRadioButtonModel } from "./radio-button.model";
+import template from './radio-buttons-group.component.html';
+
+@Component({
+ selector: 'sdc-radio-group',
+ template: template,
+ encapsulation: ViewEncapsulation.None
+})
+export class RadioGroupComponent {
+
+ private _direction: Direction = Direction.vertical;
+ private _selectedValue: string;
+
+ @HostBinding('class') classes = 'sdc-radio-group';
+
+ @Input() public legend: string;
+ @Input() public options: IOptionGroup;
+ @Input() public disabled: boolean;
+
+ @Input()
+ get value(): string {
+ return this._selectedValue;
+ }
+ set value(value: string) {
+ if (this.isOptionExists(value)) {
+ this._selectedValue = value;
+ }
+ }
+
+ @Output() public valueChange: EventEmitter<string> = new EventEmitter<string>();
+
+ @Input()
+ get direction(): string {
+ return Direction[this._direction];
+ }
+ set direction(direction: string) {
+ this._direction = (direction === 'horizontal' ? Direction.horizontal : Direction.vertical);
+ }
+
+ public onValueChanged(value): void {
+ this.valueChange.emit(value);
+ }
+
+ private isOptionExists(value) {
+ const exist = this.options.items.find((item: IRadioButtonModel) => {
+ return item.value === value;
+ });
+ return exist !== undefined;
+ }
+
+}
diff --git a/src/angular/form-elements/validation/validatable.component.ts b/src/angular/form-elements/validation/validatable.component.ts
new file mode 100644
index 0000000..4817dea
--- /dev/null
+++ b/src/angular/form-elements/validation/validatable.component.ts
@@ -0,0 +1,25 @@
+import { Input, Component } from "@angular/core";
+import { ValidationComponent } from './validation.component';
+import { Subject } from 'rxjs/Subject';
+import { IValidatableComponent } from './validatable.interface';
+
+export abstract class ValidatableComponent implements IValidatableComponent {
+
+ // Each ValidatableComponent should handle the style in case of error, according to this boolean
+ public valid = true;
+
+ // Each ValidatableComponent will notify when the value is changed.
+ public notifier: Subject<string>;
+
+ constructor() {
+ this.notifier = new Subject();
+ }
+
+ public abstract getValue(): any;
+
+ // Each ValidatableComponent should call the valueChanged on value changed function.
+ protected valueChanged = (value: any): void => {
+ this.notifier.next(value);
+ }
+
+}
diff --git a/src/angular/form-elements/validation/validatable.interface.ts b/src/angular/form-elements/validation/validatable.interface.ts
new file mode 100644
index 0000000..6aceafe
--- /dev/null
+++ b/src/angular/form-elements/validation/validatable.interface.ts
@@ -0,0 +1,5 @@
+export interface IValidatableComponent {
+
+ getValue(): any;
+
+}
diff --git a/src/angular/form-elements/validation/validation-group.component.html.ts b/src/angular/form-elements/validation/validation-group.component.html.ts
new file mode 100644
index 0000000..dff591e
--- /dev/null
+++ b/src/angular/form-elements/validation/validation-group.component.html.ts
@@ -0,0 +1,3 @@
+export default `
+<ng-content></ng-content>
+`;
diff --git a/src/angular/form-elements/validation/validation-group.component.ts b/src/angular/form-elements/validation/validation-group.component.ts
new file mode 100644
index 0000000..59ecf4c
--- /dev/null
+++ b/src/angular/form-elements/validation/validation-group.component.ts
@@ -0,0 +1,47 @@
+import { Input, Component, ContentChildren, EventEmitter, Output, QueryList, SimpleChanges, HostBinding, AfterContentInit } from "@angular/core";
+import { AbstractControl, FormControl } from "@angular/forms";
+import { Subscribable } from "rxjs/Observable";
+import { AnonymousSubscription } from "rxjs/Subscription";
+import { IValidator } from './validators/validator.interface';
+import { ValidatorComponent } from './validators/base.validator.component';
+import { RegexValidatorComponent } from './validators/regex.validator.component';
+import { RequiredValidatorComponent } from './validators/required.validator.component';
+import { ValidatableComponent } from './validatable.component';
+import { ValidationComponent } from './validation.component';
+import { CustomValidatorComponent } from './validators/custom.validator.component';
+import template from "./validation.component.html";
+
+@Component({
+ selector: 'sdc-validation-group',
+ template
+})
+export class ValidationGroupComponent implements AfterContentInit {
+
+ @Input() public disabled: boolean;
+ @HostBinding('class') classes;
+
+ @ContentChildren(ValidationComponent) public validationsComponents: QueryList<ValidationComponent>;
+
+ private supportedValidator: Array<QueryList<ValidatorComponent>>;
+
+ constructor() {
+ this.disabled = false;
+ this.classes = 'sdc-validation-group';
+ }
+
+ ngAfterContentInit(): void {
+
+ }
+
+ public validate(): boolean {
+ let validationResult = true;
+ // Iterate over all validationComponent inside the group and return boolean result true in case all validations passed.
+ this.validationsComponents.forEach((validationComponent) => {
+ if (validationComponent.validate()) {
+ validationResult = false;
+ }
+ });
+ return validationResult;
+ }
+
+}
diff --git a/src/angular/form-elements/validation/validation.component.html.ts b/src/angular/form-elements/validation/validation.component.html.ts
new file mode 100644
index 0000000..0f11a23
--- /dev/null
+++ b/src/angular/form-elements/validation/validation.component.html.ts
@@ -0,0 +1,3 @@
+export default `
+<ng-content *ngIf="!disabled"></ng-content>
+`;
diff --git a/src/angular/form-elements/validation/validation.component.ts b/src/angular/form-elements/validation/validation.component.ts
new file mode 100644
index 0000000..4abdd12
--- /dev/null
+++ b/src/angular/form-elements/validation/validation.component.ts
@@ -0,0 +1,79 @@
+import { Input, Component, ContentChildren, EventEmitter, Output, QueryList, SimpleChanges, HostBinding, AfterContentInit } from "@angular/core";
+import { AbstractControl, FormControl } from "@angular/forms";
+import { Subscribable } from "rxjs/Observable";
+import { AnonymousSubscription } from "rxjs/Subscription";
+import { IValidator } from './validators/validator.interface';
+import { ValidatorComponent } from './validators/base.validator.component';
+import { RegexValidatorComponent } from './validators/regex.validator.component';
+import { RequiredValidatorComponent } from './validators/required.validator.component';
+import { ValidatableComponent } from './validatable.component';
+import { CustomValidatorComponent } from './validators/custom.validator.component';
+import template from "./validation.component.html";
+
+@Component({
+ selector: 'sdc-validation',
+ template
+})
+export class ValidationComponent implements AfterContentInit {
+
+ @Input() public validateElement: ValidatableComponent;
+ @Input() public disabled: boolean;
+ @Output() public validityChanged: EventEmitter<boolean> = new EventEmitter<boolean>();
+ @HostBinding('class') classes;
+
+ // @ContentChildren does not recieve type any or IValidator or ValidatorComponent, so need to create @ContentChildren for each validator type.
+ @ContentChildren(RegexValidatorComponent) public regexValidator: QueryList<ValidatorComponent>;
+ @ContentChildren(RequiredValidatorComponent) public requireValidator: QueryList<ValidatorComponent>;
+ @ContentChildren(CustomValidatorComponent) public customValidator: QueryList<ValidatorComponent>;
+
+ private supportedValidator: Array<QueryList<ValidatorComponent>>;
+
+ constructor() {
+ this.disabled = false;
+ this.classes = 'sdc-validation';
+ }
+
+ ngAfterContentInit(): void {
+ this.supportedValidator = [
+ this.regexValidator,
+ this.requireValidator,
+ this.customValidator
+ ];
+
+ this.validateElement.notifier.subscribe(
+ (value) => {
+ const validationResult = this.validateOnChange(value);
+ this.validateElement.valid = validationResult;
+ },
+ (error) => console.log('Validation subscribe error')
+ );
+ }
+
+ public validate = (): boolean => {
+ const value = this.validateElement.getValue();
+ return this.validateOnChange(value);
+ }
+
+ private validateOnChange(value: any): boolean {
+ if (this.disabled) { return true; }
+
+ /**
+ * Iterate over all validators types (required, regex, etc...), and inside each iterate over
+ * all validators with same type, and return boolean result true in case all validations passed.
+ */
+ const validationResult: boolean = this.supportedValidator.reduce((sum, validatorName) => {
+ const response: boolean = validatorName.reduce((_sum, validator) => {
+ return _sum && validator.validate(value);
+ }, true);
+ return sum && response;
+ }, true);
+
+ if (this.validateElement.valid !== validationResult) {
+ this.validityChanged.emit(validationResult);
+ }
+
+ return validationResult;
+
+ }
+
+}
diff --git a/src/angular/form-elements/validation/validation.module.ts b/src/angular/form-elements/validation/validation.module.ts
new file mode 100644
index 0000000..4213f76
--- /dev/null
+++ b/src/angular/form-elements/validation/validation.module.ts
@@ -0,0 +1,35 @@
+import { NgModule } from "@angular/core";
+import { FormsModule, ReactiveFormsModule } from "@angular/forms";
+import { CommonModule } from "@angular/common";
+import { SvgIconModule } from './../../svg-icon/svg-icon.module';
+import { ValidationComponent } from './validation.component';
+import { ValidatorComponent } from './validators/base.validator.component';
+import { RequiredValidatorComponent } from './validators/required.validator.component';
+import { RegexValidatorComponent } from './validators/regex.validator.component';
+import { CustomValidatorComponent } from './validators/custom.validator.component';
+import { ValidationGroupComponent } from './validation-group.component';
+
+@NgModule({
+ imports: [
+ FormsModule,
+ CommonModule,
+ ReactiveFormsModule,
+ SvgIconModule
+ ],
+ declarations: [
+ ValidationComponent,
+ RegexValidatorComponent,
+ RequiredValidatorComponent,
+ CustomValidatorComponent,
+ ValidationGroupComponent
+ ],
+ exports: [
+ ValidationComponent,
+ RegexValidatorComponent,
+ RequiredValidatorComponent,
+ CustomValidatorComponent,
+ ValidationGroupComponent
+ ]
+})
+export class ValidationModule {
+}
diff --git a/src/angular/form-elements/validation/validators/base.validator.component.html.ts b/src/angular/form-elements/validation/validators/base.validator.component.html.ts
new file mode 100644
index 0000000..aba8eed
--- /dev/null
+++ b/src/angular/form-elements/validation/validators/base.validator.component.html.ts
@@ -0,0 +1,10 @@
+export default `
+<svg-icon-label
+ *ngIf="!isValid"
+ name="alert-triangle"
+ mode="error"
+ size="small"
+ [label]="message"
+ labelPlacement="right">
+</svg-icon-label>
+`;
diff --git a/src/angular/form-elements/validation/validators/base.validator.component.ts b/src/angular/form-elements/validation/validators/base.validator.component.ts
new file mode 100644
index 0000000..3d751af
--- /dev/null
+++ b/src/angular/form-elements/validation/validators/base.validator.component.ts
@@ -0,0 +1,25 @@
+import { Input, Component, ContentChildren, EventEmitter, Output, QueryList, SimpleChanges, HostBinding } from "@angular/core";
+import { IValidator } from './validator.interface';
+import template from "./base.validator.component.html";
+
+@Component({
+ selector: 'sdc-validator',
+ template: template
+})
+export abstract class ValidatorComponent {
+
+ @Input() public message: any;
+ @Input() public disabled: boolean;
+ @HostBinding('class') classes;
+
+ protected isValid: boolean;
+
+ constructor() {
+ this.disabled = false;
+ this.isValid = true;
+ this.classes = 'sdc-validator sdc-label__error';
+ }
+
+ public abstract validate(value: any): boolean;
+
+}
diff --git a/src/angular/form-elements/validation/validators/custom.validator.component.ts b/src/angular/form-elements/validation/validators/custom.validator.component.ts
new file mode 100644
index 0000000..eb09636
--- /dev/null
+++ b/src/angular/form-elements/validation/validators/custom.validator.component.ts
@@ -0,0 +1,23 @@
+import { Input, Component } from "@angular/core";
+import { ValidatorComponent } from "./base.validator.component";
+import { IValidator } from './validator.interface';
+import template from "./base.validator.component.html";
+
+@Component({
+ selector: 'sdc-custom-validator',
+ template: template
+})
+export class CustomValidatorComponent extends ValidatorComponent implements IValidator {
+
+ @Input() public callback: (...args) => boolean;
+
+ constructor() {
+ super();
+ }
+
+ public validate(value: any): boolean {
+ this.isValid = this.callback(value);
+ return this.isValid;
+ }
+
+}
diff --git a/src/angular/form-elements/validation/validators/regex.validator.component.ts b/src/angular/form-elements/validation/validators/regex.validator.component.ts
new file mode 100644
index 0000000..5929016
--- /dev/null
+++ b/src/angular/form-elements/validation/validators/regex.validator.component.ts
@@ -0,0 +1,24 @@
+import { Input, Component } from "@angular/core";
+import { ValidatorComponent } from "./base.validator.component";
+import { IValidator } from './validator.interface';
+import template from "./base.validator.component.html";
+
+@Component({
+ selector: 'sdc-regex-validator',
+ template: template
+})
+export class RegexValidatorComponent extends ValidatorComponent implements IValidator {
+
+ @Input() public pattern: RegExp;
+
+ constructor() {
+ super();
+ }
+
+ public validate(value: any): boolean {
+ const regexp = new RegExp(this.pattern);
+ this.isValid = regexp.test(value);
+ return this.isValid;
+ }
+
+}
diff --git a/src/angular/form-elements/validation/validators/required.validator.component.ts b/src/angular/form-elements/validation/validators/required.validator.component.ts
new file mode 100644
index 0000000..7eee932
--- /dev/null
+++ b/src/angular/form-elements/validation/validators/required.validator.component.ts
@@ -0,0 +1,25 @@
+import { Input, Component } from "@angular/core";
+import { ValidatorComponent } from "./base.validator.component";
+import { IValidator } from './validator.interface';
+import template from "./base.validator.component.html";
+
+@Component({
+ selector: 'sdc-required-validator',
+ template: template
+})
+export class RequiredValidatorComponent extends ValidatorComponent implements IValidator {
+
+ constructor() {
+ super();
+ }
+
+ public validate(value: any): boolean {
+ if (value) {
+ this.isValid = true;
+ } else {
+ this.isValid = false;
+ }
+ return this.isValid;
+ }
+
+}
diff --git a/src/angular/form-elements/validation/validators/validator.interface.ts b/src/angular/form-elements/validation/validators/validator.interface.ts
new file mode 100644
index 0000000..c0adc24
--- /dev/null
+++ b/src/angular/form-elements/validation/validators/validator.interface.ts
@@ -0,0 +1,3 @@
+export interface IValidator {
+ validate(value: any): void;
+}
diff --git a/src/angular/index.ts b/src/angular/index.ts
new file mode 100644
index 0000000..e8a54bd
--- /dev/null
+++ b/src/angular/index.ts
@@ -0,0 +1,68 @@
+import { NgModule } from "@angular/core";
+import { FormElementsModule } from "./form-elements/form-elements.module";
+import { ButtonsModule } from "./buttons/buttons.module";
+import { ModalModule } from "./modals/modal.module";
+import { NotificationModule } from "./notifications/notification.module";
+import { PopupMenuModule } from "./popup-menu/popup-menu.module";
+import { AnimationDirectivesModule } from "./animations/animation-directives.module";
+import { InfiniteScrollModule } from "./infinite-scroll/infinite-scroll.module";
+import { TileModule } from "./tiles/tile.module";
+import { ChecklistModule } from "./checklist/checklist.module";
+import { SvgIconModule } from "./svg-icon/svg-icon.module";
+import { AutoCompleteModule } from "./autocomplete/autocomplete.module";
+import { FilterBarModule } from "./filterbar/filter-bar.module";
+import { SearchBarModule } from "./searchbar/search-bar.module";
+import { TooltipModule } from "./tooltip/tooltip.module";
+import { TagCloudModule } from './tag-cloud/tag-cloud.module';
+import { TabsModule } from "./tabs/tabs.module";
+import { AccordionModule } from "./accordion/accordion.module";
+
+@NgModule({
+ imports: [
+ AnimationDirectivesModule,
+ ModalModule,
+ NotificationModule,
+ FormElementsModule,
+ ButtonsModule,
+ PopupMenuModule,
+ InfiniteScrollModule,
+ TileModule,
+ ChecklistModule,
+ AutoCompleteModule,
+ FilterBarModule,
+ SearchBarModule,
+ TooltipModule,
+ SvgIconModule,
+ TagCloudModule,
+ TabsModule,
+ AccordionModule
+ ],
+ exports: [
+ AnimationDirectivesModule,
+ ModalModule,
+ NotificationModule,
+ FormElementsModule,
+ ButtonsModule,
+ PopupMenuModule,
+ InfiniteScrollModule,
+ TileModule,
+ ChecklistModule,
+ AutoCompleteModule,
+ FilterBarModule,
+ SearchBarModule,
+ TooltipModule,
+ SvgIconModule,
+ TagCloudModule,
+ TabsModule,
+ AccordionModule
+ ]
+})
+export class SdcUiComponentsModule {
+}
+
+import * as SdcUiComponents from './components';
+import * as SdcUiCommon from './common/index';
+
+export { SdcUiComponentsNg1Module } from './ng1.module';
+export { SdcUiComponents };
+export { SdcUiCommon };
diff --git a/src/angular/infinite-scroll/infinite-scroll.directive.ts b/src/angular/infinite-scroll/infinite-scroll.directive.ts
new file mode 100644
index 0000000..a8ea9f4
--- /dev/null
+++ b/src/angular/infinite-scroll/infinite-scroll.directive.ts
@@ -0,0 +1,35 @@
+import { Directive, ElementRef, Output, EventEmitter, HostListener, Input } from "@angular/core";
+
+@Directive({
+ selector: '[infiniteScroll]'
+})
+export class InfiniteScrollDirective {
+ @Input() public infiniteScrollDistance: number = 0;
+ @Output() public infiniteScroll: EventEmitter<void>;
+
+ private scrollWasHit: boolean = false;
+
+ constructor(private elemRef: ElementRef) {
+ this.infiniteScroll = new EventEmitter<void>();
+ }
+
+ @HostListener('scroll', ['$event'])
+ public onScroll(evt) {
+ const scrollContainerElem: HTMLElement = evt.target;
+ if (scrollContainerElem !== this.elemRef.nativeElement) {
+ return;
+ }
+
+ if (scrollContainerElem.scrollTop + scrollContainerElem.clientHeight + this.infiniteScrollDistance >=
+ scrollContainerElem.scrollHeight) {
+ // hit only once when entering the distance area from bottom
+ // (avoid emitting the handler while scrolling in the bottom area)
+ if (!this.scrollWasHit) {
+ this.infiniteScroll.emit();
+ this.scrollWasHit = true;
+ }
+ } else if (this.scrollWasHit) {
+ this.scrollWasHit = false;
+ }
+ }
+}
diff --git a/src/angular/infinite-scroll/infinite-scroll.module.ts b/src/angular/infinite-scroll/infinite-scroll.module.ts
new file mode 100644
index 0000000..8b559ca
--- /dev/null
+++ b/src/angular/infinite-scroll/infinite-scroll.module.ts
@@ -0,0 +1,13 @@
+import { NgModule } from "@angular/core";
+import { InfiniteScrollDirective } from "./infinite-scroll.directive";
+
+@NgModule({
+ declarations: [
+ InfiniteScrollDirective
+ ],
+ exports: [
+ InfiniteScrollDirective
+ ],
+})
+export class InfiniteScrollModule {
+}
diff --git a/src/angular/modals/modal-button.component.ts b/src/angular/modals/modal-button.component.ts
new file mode 100644
index 0000000..4fa5b7c
--- /dev/null
+++ b/src/angular/modals/modal-button.component.ts
@@ -0,0 +1,29 @@
+import { Component, Input, HostListener } from "@angular/core";
+import { ButtonComponent } from "../buttons/button.component";
+import { ModalService } from "./modal.service";
+import template from "./../buttons/button.component.html";
+
+@Component({
+ selector: "sdc-modal-button",
+ template: template
+})
+export class ModalButtonComponent extends ButtonComponent {
+
+ @Input() public id?: string;
+ @Input() public callback: Function;
+ @Input() public closeModal: boolean;
+ @HostListener('click') invokeCallback = (): void => {
+ if (this.callback) {
+ this.callback();
+ }
+ if (this.closeModal) {
+ this.modalService.closeModal();
+ }
+ }
+
+ constructor(private modalService: ModalService) {
+ super();
+ this.closeModal = false;
+ }
+
+}
diff --git a/src/angular/modals/modal-close-button.component.ts b/src/angular/modals/modal-close-button.component.ts
new file mode 100644
index 0000000..e761019
--- /dev/null
+++ b/src/angular/modals/modal-close-button.component.ts
@@ -0,0 +1,34 @@
+import { Component, Input } from "@angular/core";
+import { ButtonComponent } from "../buttons/button.component";
+import { ModalService } from "./modal.service";
+import { RippleAnimationAction } from "../animations/ripple-click.animation.directive";
+
+@Component({
+ selector: "sdc-modal-close-button",
+ template: `
+ <div class="sdc-modal__close-button"
+ SdcRippleClickAnimation
+ [ngClass]="disabled ? 'disabled' : ''"
+ [rippleOnAction]="!disabled && rippleAnimationAction"
+ [attr.data-tests-id]="testId"
+ (click)="!disabled && closeModal()"
+ >
+ <svg-icon name="close" [mode]="disabled? 'secondary' : 'info'" size="small"></svg-icon>
+ </div>
+ `
+})
+export class ModalCloseButtonComponent {
+
+ @Input() testId: string;
+ @Input() disabled: boolean;
+
+ public rippleAnimationAction: RippleAnimationAction = RippleAnimationAction.MOUSE_ENTER;
+
+ constructor(private modalService: ModalService) {
+ }
+
+ public closeModal = (): void => {
+ this.modalService.closeModal();
+ }
+
+}
diff --git a/src/angular/modals/modal.component.html.ts b/src/angular/modals/modal.component.html.ts
new file mode 100644
index 0000000..90119ac
--- /dev/null
+++ b/src/angular/modals/modal.component.html.ts
@@ -0,0 +1,38 @@
+export default `
+<div class="sdc-modal {{size}}">
+ <div class="sdc-modal__wrapper sdc-modal-type-{{type}}" [@toggleModal]="modalVisible" (@toggleModal.done)="modalToggled($event)">
+
+ <div class="sdc-modal__header sdc-{{type}}__header">
+ <div class="sdc-modal__icon" *ngIf="type != 'custom'">
+ <div *ngIf="type == 'alert'"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="30" height="30" viewBox="0 0 24 24"><defs><path fill="#000" id="alert-a" d="M20.5815,18.7997 C20.3815,18.9997 20.0815,19.0997 19.8815,19.0997 L2.8815,19.0997 C2.6815,19.0997 2.5815,19.0997 2.3815,18.9997 C1.8815,18.6997 1.7815,18.0997 1.9815,17.5997 L10.4815,3.4997 C10.5815,3.4007 10.6815,3.1997 10.7815,3.1997 C11.2815,2.9007 11.8815,3.0997 12.1815,3.4997 L20.6825,17.5997 C20.7815,17.6997 20.7815,17.9007 20.7815,18.0997 C20.8815,18.4007 20.6825,18.5997 20.5815,18.7997 M22.3815,16.5997 L13.9815,2.4007 C13.5815,1.6997 12.8815,1.1997 12.0815,0.9997 C11.2815,0.7997 10.4815,0.9007 9.7815,1.2997 C9.3815,1.4997 8.9815,1.9007 8.7815,2.2997 L0.3815,16.5997 C-0.4185,17.9997 0.0815,19.9007 1.4815,20.6997 C1.8815,20.9997 2.3815,21.0997 2.8815,21.0997 L19.8815,21.0997 C20.6825,21.0997 21.4815,20.7997 21.9815,20.1997 C22.5815,19.5997 22.8815,18.9007 22.8815,18.0997 C22.7815,17.5997 22.6825,16.9997 22.3815,16.5997 M11,7 C10.4,7 10,7.4 10,8 L10,12 C10,12.601 10.4,13 11,13 C11.6,13 12,12.601 12,12 L12,8 C12,7.4 11.6,7 11,7 M10.3,15.3 C10.1,15.499 10,15.699 10,15.999 C10,16.3 10.1,16.499 10.3,16.699 C10.5,16.9 10.7,16.999 11,16.999 C11.3,16.999 11.5,16.9 11.7,16.699 C11.9,16.499 12,16.199 12,15.999 C12,15.8 11.9,15.499 11.7,15.3 C11.3,14.9 10.7,14.9 10.3,15.3"/></defs>
+ <g fill="none" fill-rule="evenodd" transform="translate(1 1)"><use class="sdc-modal__svg-use" xlink:href="#alert-a"/></g></svg></div>
+ <div *ngIf="type == 'info'"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="30" height="30" viewBox="0 0 24 24"><defs><path fill="#000" id="info-a" d="M11,20 C6,20 2,16 2,11 C2,6 6,2 11,2 C16,2 20,6 20,11 C20,16 16,20 11,20 M11,0 C4.9,0 0,4.9 0,11 C0,17.101 4.9,22 11,22 C17.1,22 22,17.101 22,11 C22,4.9 17.1,0 11,0 M11,10 C10.4,10 10,10.4 10,11 L10,15 C10,15.601 10.4,16 11,16 C11.6,16 12,15.601 12,15 L12,11 C12,10.4 11.6,10 11,10 M10.2998,6.2998 C10.0998,6.4998 9.9998,6.6998 9.9998,6.9998 C9.9998,7.2998 10.0998,7.4998 10.2998,7.6998 C10.4998,7.9008 10.6998,7.9998 10.9998,7.9998 C11.2998,7.9998 11.4998,7.9008 11.6998,7.6998 C11.9008,7.4998 11.9998,7.2998 11.9998,6.9998 C11.9998,6.6998 11.9008,6.4998 11.6998,6.2998 C11.2998,5.9008 10.6998,5.9008 10.2998,6.2998"/></defs>
+ <g fill="none" fill-rule="evenodd" transform="translate(1 1)"><use class="sdc-modal__svg-use" xlink:href="#info-a"/></g></svg></div>
+ <div *ngIf="type == 'error'"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="30" height="30" viewBox="0 0 24 24"><defs><path fill="#000" id="x-a" d="M11,20 C6,20 2,16 2,11 C2,6 6,2 11,2 C16,2 20,6 20,11 C20,16 16,20 11,20 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 M14.2591,7.29935 C13.8591,6.90035 13.2591,6.90035 12.8591,7.29935 L10.5591,9.59935 L8.2591,7.29935 C7.8591,6.90035 7.2591,6.90035 6.8591,7.29935 C6.4591,7.69935 6.4591,8.29935 6.8591,8.69935 L9.1581,10.99935 L6.8591,13.29935 C6.4591,13.69935 6.4591,14.29935 6.8591,14.69935 C7.0591,14.90035 7.2591,14.99935 7.5591,14.99935 C7.8591,14.99935 8.0591,14.90035 8.2591,14.69935 L10.5591,12.40035 L12.8591,14.69935 C13.0591,14.90035 13.3591,14.99935 13.5591,14.99935 C13.7591,14.99935 14.0591,14.90035 14.2591,14.69935 C14.6581,14.29935 14.6581,13.69935 14.2591,13.29935 L11.9591,10.99935 L14.2591,8.69935 C14.6581,8.29935 14.6581,7.69935 14.2591,7.29935"/></defs>
+ <g fill="none" fill-rule="evenodd" transform="translate(1 1)"><use class="sdc-modal__svg-use" xlink:href="#x-a"/></g></svg></div>
+ </div>
+ <div *ngIf="title" class="title" >{{ title }}</div>
+ <sdc-modal-close-button #modalCloseButton [testId]="getCalculatedTestId('close')"></sdc-modal-close-button>
+ </div>
+ <div class="sdc-modal__content" >
+ <div *ngIf="message">{{message}}</div>
+ <div #dynamicContentContainer></div>
+ </div>
+ <div class="sdc-modal__footer">
+ <sdc-modal-button *ngFor="let button of buttons"
+ [text]="button.text"
+ [type]="button.type || 'primary'"
+ [disabled]="button.disabled"
+ [size] = "button.size ? button.size : 'default'"
+ [closeModal]="button.closeModal"
+ [spinner_position]="button.spinner_position"
+ [show_spinner]="button.show_spinner"
+ [callback]="button.callback"
+ [testId]="getCalculatedTestId('button-' + button.text)"
+ >
+ </sdc-modal-button>
+ </div>
+ </div>
+</div>
+<div class="modal-background" [@toggleBackground]="modalVisible" ></div>
+`;
diff --git a/src/angular/modals/modal.component.spec.ts b/src/angular/modals/modal.component.spec.ts
new file mode 100644
index 0000000..372d59d
--- /dev/null
+++ b/src/angular/modals/modal.component.spec.ts
@@ -0,0 +1,105 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { Component, Input, NgModule, ViewContainerRef, Inject, Injectable, Type, ApplicationRef, ComponentFactoryResolver, ComponentRef, EmbeddedViewRef, Injector } from '@angular/core';
+import { NO_ERRORS_SCHEMA } from '@angular/core/src/metadata/ng_module';
+import { ModalService } from './modal.service';
+import { CreateDynamicComponentService } from "../utils/create-dynamic-component.service";
+import { IModalConfig, ModalType, ModalSize } from "../../../src/angular/modals/models/modal-config";
+import { ModalInnerContent } from "../../../stories/ng2-component-lab/components/modal-inner-content-example.component";
+
+
+describe("Modal unit-tests", () => {
+ let testService: ModalService;
+ const testInputModal = {
+ size: 'xl', //'xl|l|md|sm|xsm'
+ title: 'Test_Title',
+ message: 'Test_Message',
+ modalVisible: true
+ };
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ providers:[
+ ModalService,
+ { provide : CreateDynamicComponentService, useClass: CreateDynamicComponentServiceTest}
+ ],
+ declarations: [],
+ schemas:[NO_ERRORS_SCHEMA]
+ })
+ testService = TestBed.get(ModalService);
+ }));
+
+ it('Modal should be open test', () => {
+ let modalInstance = testService.openModal(testInputModal);
+ expect(modalInstance).toBeTruthy();
+ })
+
+ it('Modal alert window test', () => {
+ let modalInstance = testService.openAlertModal('testAlert', 'testMessage');
+ expect(modalInstance).toBeTruthy();
+ })
+
+ it('Modal info window test', () => {
+ let modalInstance = testService.openErrorModal('testMessage', 'sampleTestId');
+ expect(modalInstance).toBeTruthy();
+ })
+
+
+ it('Custom Modal should be open', () => {
+ let modalConfig:IModalConfig = <IModalConfig> {
+ size: ModalSize.medium,
+ title: 'Title',
+ type: ModalType.custom,
+ buttons: [{text:"Save & Close", closeModal:true},
+ {text:"Save", callback:this.customModalOnSave, closeModal:false},
+ {text:"Cancel", type: 'secondary', closeModal:true}]
+ };
+ let modalInstance = testService.openCustomModal(modalConfig, ModalInnerContent, {name: "Sample Content"});
+ expect(modalInstance).toBeTruthy();
+ })
+
+ it('Shoul close window', () => {
+ let modalInstance = testService.openModal(testInputModal);
+ testService.closeModal();
+ expect(modalInstance.instance.modalVisible).toBeFalsy();
+ })
+})
+
+
+const testModalInstance = {
+ instance:{
+ closeAnimationComplete:{
+ subscribe:() => {
+ return true;
+ },
+ },
+ _createDynamicComponentService:{
+ insertComponentDynamically:() => {
+ return true;
+ }
+ },
+ modalVisible:true
+ },
+
+};
+
+@Component({
+ selector: 'modal-test',
+ template: `<div></div>`
+})
+
+
+
+export class CreateDynamicComponentServiceTest {
+ modalVisble: true;
+ public createComponentDynamically = (modalInstance, customData) => {
+ return testModalInstance;
+ }
+ public insertComponentDynamically = () =>{
+ return testModalInstance;
+ }
+
+}
+
+
+
+
diff --git a/src/angular/modals/modal.component.ts b/src/angular/modals/modal.component.ts
new file mode 100644
index 0000000..4f4d81f
--- /dev/null
+++ b/src/angular/modals/modal.component.ts
@@ -0,0 +1,96 @@
+import { Component, Input, Output, ViewContainerRef, ViewChild, ComponentRef, trigger, state, animate, transition, style, EventEmitter, Renderer, ElementRef } from '@angular/core';
+import { ModalButtonComponent } from './modal-button.component';
+import { LowerCasePipe } from '@angular/common';
+import { ModalCloseButtonComponent } from './modal-close-button.component';
+import template from './modal.component.html';
+
+@Component({
+ selector: 'sdc-modal',
+ template: template,
+ animations: [
+ trigger('toggleBackground', [
+ transition('* => 1', [style({opacity: 0}), animate('.45s cubic-bezier(0.23, 1, 0.32, 1)')]),
+ transition('1 => *', [animate('.35s cubic-bezier(0.23, 1, 0.32, 1)', style({opacity: 0}))])
+ ]),
+ trigger('toggleModal', [
+ transition('* => 1', [style({opacity: 0, transform: 'translateY(-80px)'}), animate('.45s cubic-bezier(0.23, 1, 0.32, 1)')]),
+ transition('1 => *', [style({opacity: 1, transform: 'translateY(0px)'}), animate('.35s ease-in-out', style({opacity:0, transform: 'translateY(-80px)'}))])
+ ])
+ ]
+})
+
+export class ModalComponent {
+
+ @Input() size: string; 'xl|l|md|sm|xsm';
+ @Input() title: string;
+ @Input() message: string;
+ @Input() buttons: ModalButtonComponent[];
+ @Input() type: string; 'info|error|alert|custom';
+ @Input() testId: string;
+ @Output() closeAnimationComplete: EventEmitter<any> = new EventEmitter<any>();
+
+ @ViewChild('modalCloseButton')
+ set refCloseButton(_modalCloseButton: ModalCloseButtonComponent) {
+ this.modalCloseButton = _modalCloseButton;
+ }
+
+ modalVisible: boolean;
+ // Allows for custom component as body instead of simple message.
+ // See ModalService.createActionModal for implementation details, and HttpService's catchError() for example.
+ @ViewChild('dynamicContentContainer', {read: ViewContainerRef}) dynamicContentContainer: ViewContainerRef;
+ innerModalContent: ComponentRef<ModalComponent>;
+
+ public calculatedTestId: string;
+ public modalCloseButton: ModalCloseButtonComponent;
+
+ constructor(private renderer: Renderer,
+ private lowerCasePipe: LowerCasePipe
+ ) {
+ this.modalVisible = true;
+ }
+
+ getCalculatedTestId = (buttonText: string): string => {
+ // TODO: Replace this
+ if (this.testId) {
+ return this.testId + '-' + this.lowerCasePipe.transform(buttonText);
+ }
+ return null;
+ }
+
+ public modalToggled = (toggleEvent: any) => {
+ if (!toggleEvent.toState) {
+ this.closeAnimationComplete.emit();
+ }
+ }
+
+ public getCloseButton = (): ModalCloseButtonComponent => {
+ return this.modalCloseButton;
+ }
+
+ public getButtonById = (id: string): ModalButtonComponent => {
+ return this.buttons.find((button) => {
+ return button.id && button.id === id;
+ });
+ }
+
+ public getButtons = (): ModalButtonComponent[] => {
+ return this.buttons;
+ }
+
+ public setButtons = (_buttons: ModalButtonComponent[]): void => {
+ this.buttons = _buttons;
+ }
+
+ public getTitle = (): string => {
+ return this.title;
+ }
+
+ public setTitle = (_title: string): void => {
+ this.title = _title;
+ }
+
+ public hoverAnimation(evn: MouseEvent) {
+ this.renderer.setElementClass(evn.target as HTMLElement, 'sdc-ripple-click__animated', true);
+ // evn.taregt.classList.add('sdc-ripple-click__animated');
+ }
+}
diff --git a/src/angular/modals/modal.module.ts b/src/angular/modals/modal.module.ts
new file mode 100644
index 0000000..5697437
--- /dev/null
+++ b/src/angular/modals/modal.module.ts
@@ -0,0 +1,33 @@
+import { NgModule } from "@angular/core";
+import { ModalComponent } from "./modal.component";
+import { ModalService } from "./modal.service";
+import { CommonModule, LowerCasePipe } from "@angular/common";
+import { ButtonsModule } from "../buttons/buttons.module";
+import { AnimationDirectivesModule } from "../animations/animation-directives.module";
+import { CreateDynamicComponentService } from "../utils/create-dynamic-component.service";
+import { ModalButtonComponent } from "./modal-button.component";
+import { ModalCloseButtonComponent } from "./modal-close-button.component";
+import { SvgIconModule } from "../svg-icon/svg-icon.module";
+
+@NgModule({
+ declarations: [
+ ModalComponent,
+ ModalButtonComponent,
+ ModalCloseButtonComponent
+ ],
+ imports: [
+ CommonModule,
+ ButtonsModule,
+ AnimationDirectivesModule,
+ SvgIconModule
+ ],
+ entryComponents: [
+ ModalComponent,
+ ModalCloseButtonComponent
+ ],
+ exports: [ModalButtonComponent],
+ providers: [CreateDynamicComponentService, ModalService, LowerCasePipe]
+})
+export class ModalModule {
+
+}
diff --git a/src/angular/modals/modal.service.ts b/src/angular/modals/modal.service.ts
new file mode 100644
index 0000000..d80ad1f
--- /dev/null
+++ b/src/angular/modals/modal.service.ts
@@ -0,0 +1,100 @@
+import { Injectable, Type, ComponentRef } from '@angular/core';
+import { ModalComponent } from "./modal.component";
+import { CreateDynamicComponentService } from "../utils/create-dynamic-component.service";
+import { IModalConfig, ModalType, ModalSize, IModalButtonComponent } from "./models/modal-config";
+
+@Injectable()
+export class ModalService {
+
+ private currentModal: ComponentRef<any>;
+
+ constructor(private createDynamicComponentService: CreateDynamicComponentService) {
+ }
+
+ /* Shortcut method to open an alert modal with title, message, and close button that simply closes the modal. */
+ public openAlertModal(title: string, message: string, actionButtonText?: string, actionButtonCallback?: Function, testId?: string) {
+ const modalConfig = {
+ size: ModalSize.small,
+ title: title,
+ message: message,
+ testId: testId,
+ buttons: this.createButtons('secondary', actionButtonText, actionButtonCallback),
+ type: ModalType.alert
+ } as IModalConfig;
+ const modalInstance: ComponentRef<ModalComponent> = this.openModal(modalConfig);
+ this.currentModal = modalInstance;
+ return modalInstance;
+ }
+
+ public openActionModal = (title: string, message: string, actionButtonText?: string, actionButtonCallback?: Function, testId?: string): ComponentRef<ModalComponent> => {
+ const modalConfig = {
+ size: ModalSize.small,
+ title: title,
+ message: message,
+ testId: testId,
+ type: ModalType.standard,
+ buttons: this.createButtons('primary', actionButtonText, actionButtonCallback)
+ } as IModalConfig;
+ const modalInstance: ComponentRef<ModalComponent> = this.openModal(modalConfig);
+ this.currentModal = modalInstance;
+ return modalInstance;
+ }
+
+ public openErrorModal = (errorMessage?: string, testId?: string): ComponentRef<ModalComponent> => {
+ const modalConfig = {
+ size: ModalSize.small,
+ title: 'Error',
+ message: errorMessage,
+ testId: testId,
+ buttons: [{text: "OK", type: "alert", closeModal: true}],
+ type: ModalType.error
+ } as IModalConfig;
+ const modalInstance: ComponentRef<ModalComponent> = this.openModal(modalConfig);
+ this.currentModal = modalInstance;
+ return modalInstance;
+ }
+
+ public openCustomModal = (modalConfig: IModalConfig, dynamicComponentType: Type<any>, dynamicComponentInput?: any) => {
+ const modalInstance: ComponentRef<ModalComponent> = this.openModal(modalConfig);
+ this.createInnnerComponent(dynamicComponentType, dynamicComponentInput);
+ return modalInstance;
+ }
+
+ public createInnnerComponent = (dynamicComponentType: Type<any>, dynamicComponentInput?: any): void => {
+ this.currentModal.instance.innerModalContent = this.createDynamicComponentService.insertComponentDynamically(dynamicComponentType, dynamicComponentInput, this.currentModal.instance.dynamicContentContainer);
+ }
+
+ public openModal = (customModalData: IModalConfig): ComponentRef<ModalComponent> => {
+ const modalInstance: ComponentRef<ModalComponent> = this.createDynamicComponentService.createComponentDynamically(ModalComponent, customModalData);
+ modalInstance.instance.closeAnimationComplete.subscribe(() => {
+ this.destroyModal();
+ });
+ this.currentModal = modalInstance;
+ return modalInstance;
+ }
+
+ public getCurrentInstance = () => {
+ return this.currentModal.instance;
+ }
+
+ public closeModal = (): void => { // triggers closeModal animation, which then triggers toggleModal.done and the subscription to destroyModal
+ this.currentModal.instance.modalVisible = false;
+ }
+
+ private createButtons = (type: string, actionButtonText?: string, actionButtonCallback?: Function): Array<IModalButtonComponent> => {
+ const buttons: Array<IModalButtonComponent> = [];
+ if (actionButtonText && actionButtonCallback) {
+ buttons.push({text: actionButtonText, type: type, callback: actionButtonCallback, closeModal: true});
+ buttons.push({text: 'Cancel', type: 'secondary', closeModal: true});
+ } else {
+ buttons.push({text: 'Cancel', type: type, closeModal: true});
+ }
+
+ return buttons;
+ }
+
+ private destroyModal = (): void => {
+ this.currentModal.destroy();
+ }
+
+}
diff --git a/src/angular/modals/models/modal-config.ts b/src/angular/modals/models/modal-config.ts
new file mode 100644
index 0000000..635942b
--- /dev/null
+++ b/src/angular/modals/models/modal-config.ts
@@ -0,0 +1,44 @@
+import { Placement } from "../../common/enums";
+
+export interface IModalConfig {
+ size?: string; // xl|l|md|sm|xsm
+ title?: string;
+ message?: string;
+ buttons?: IModalButtonComponent[];
+ testId?: string;
+ type?: string; // 'info|error|alert';
+}
+
+export interface IButtonComponent {
+ text: string;
+ disabled?: boolean;
+ type?: string;
+ testId?: string;
+ preventDoubleClick?: boolean;
+ icon_name?: string;
+ icon_position?: string;
+ show_spinner?: boolean;
+ spinner_position?: Placement;
+ size?: string;
+}
+
+export interface IModalButtonComponent extends IButtonComponent{
+ id?: string;
+ callback?: Function;
+ closeModal?: boolean;
+}
+
+export enum ModalType {
+ alert = "alert",
+ error = "error",
+ standard = "info",
+ custom = "custom"
+}
+
+export enum ModalSize {
+ xlarge = "xl",
+ large = "l",
+ medium = "md",
+ small = "sm",
+ xsmall = "xsm"
+}
diff --git a/src/angular/ng1.module.ts b/src/angular/ng1.module.ts
new file mode 100644
index 0000000..6f636f4
--- /dev/null
+++ b/src/angular/ng1.module.ts
@@ -0,0 +1,135 @@
+import { SdcUiComponentsModule } from './index';
+import { downgradeComponent, downgradeInjectable } from "@angular/upgrade/static";
+import * as Components from './components';
+declare const angular: any;
+
+let SdcUiComponentsNg1Module = null;
+
+if (typeof angular !== "undefined") {
+
+ SdcUiComponentsNg1Module = angular.module('SdcUiComponentsNg1', []);
+
+ // // Form Elements
+ SdcUiComponentsNg1Module.directive('sdcInput', downgradeComponent({
+ component: Components.InputComponent,
+ inputs: ['label', 'value', 'pattern', 'disabled', 'placeHolder', 'required', 'minLength', 'maxLength', 'debounceTime'],
+ outputs: ['valueChange']
+ }));
+ SdcUiComponentsNg1Module.directive('sdcDropdown', downgradeComponent({
+ component: Components.DropDownComponent,
+ inputs: ['label', 'options', 'disabled', 'placeHolder', 'required', 'validate', 'headless', 'maxHeight', 'selectedOption'],
+ outputs: ['changeEmitter']
+ }));
+ SdcUiComponentsNg1Module.directive('sdcCheckbox', downgradeComponent({
+ component: Components.CheckboxComponent,
+ inputs: ['label', 'checked', 'disabled'],
+ outputs: ['checkedChange']
+ }));
+ SdcUiComponentsNg1Module.directive('sdcRadioGroup', downgradeComponent({
+ component: Components.RadioGroupComponent,
+ inputs: ['legend', 'options', 'disabled', 'value', 'direction'],
+ outputs: ['valueChange']
+ }));
+
+ // Buttons
+ SdcUiComponentsNg1Module.directive('sdcButton', downgradeComponent({
+ component: Components.ButtonComponent,
+ inputs: ['text', 'disabled', 'type', 'size', 'preventDoubleClick', 'icon_name', 'icon_positon']
+ }));
+
+ // Modals
+ SdcUiComponentsNg1Module.service('SdcModalService', downgradeInjectable(Components.ModalService));
+ SdcUiComponentsNg1Module.directive('sdcModal', downgradeComponent({
+ component: Components.ModalComponent,
+ inputs: ['size', 'title', 'message', 'buttons', 'type'],
+ outputs: ['closeAnimationComplete']
+ }));
+ SdcUiComponentsNg1Module.directive('sdcModalButton', downgradeComponent({
+ component: Components.ModalButtonComponent,
+ inputs: ['callback', 'closeModal']
+ }));
+
+ // Notifications
+ SdcUiComponentsNg1Module.service('SdcNotificationService', downgradeInjectable(Components.NotificationsService));
+ SdcUiComponentsNg1Module.directive('sdcNotificationContainer', downgradeComponent({
+ component: Components.NotificationContainerComponent
+ }));
+ SdcUiComponentsNg1Module.directive('sdcNotification', downgradeComponent({
+ component: Components.NotificationComponent,
+ inputs: ['notificationSetting'],
+ outputs: ['destroyComponent']
+ }));
+
+ // Popup Menu
+ SdcUiComponentsNg1Module.directive('popupMenuList', downgradeComponent({
+ component: Components.PopupMenuListComponent,
+ inputs: ['open', 'position', 'className', 'relative'],
+ outputs: ['openChange', 'positionChange']
+ }));
+ SdcUiComponentsNg1Module.directive('popupMenuItem', downgradeComponent({
+ component: Components.PopupMenuItemComponent,
+ inputs: ['className', 'type'],
+ outputs: ['action']
+ }));
+
+ // Tiles
+ SdcUiComponentsNg1Module.directive('sdcTile', downgradeComponent({
+ component: Components.TileComponent
+ }));
+ SdcUiComponentsNg1Module.directive('sdcTileHeader', downgradeComponent({
+ component: Components.TileHeaderComponent
+ }));
+ SdcUiComponentsNg1Module.directive('sdcTileContent', downgradeComponent({
+ component: Components.TileContentComponent
+ }));
+ SdcUiComponentsNg1Module.directive('sdcTileFooter', downgradeComponent({
+ component: Components.TileFooterComponent
+ }));
+
+ // Check List
+ SdcUiComponentsNg1Module.directive('sdcChecklist', downgradeComponent({
+ component: Components.ChecklistComponent,
+ inputs: ['checklistModel'],
+ outputs: ['checkedChange']
+ }));
+
+ // Tag Cloud
+ SdcUiComponentsNg1Module.directive('sdcTagCloud', downgradeComponent({
+ component: Components.TagCloudComponent,
+ inputs: ['list', 'isViewOnly', 'isUniqueList', 'uniqueErrorMessage', 'label', 'placeholder'],
+ outputs: ['listChanged']
+ }));
+ SdcUiComponentsNg1Module.directive('sdcTagItem', downgradeComponent({
+ component: Components.TagItemComponent,
+ inputs: ['text', 'isViewOnly', 'index'],
+ outputs: ['clickOnDelete']
+ }));
+
+ // Tabs
+ SdcUiComponentsNg1Module.directive('sdcTabs', downgradeComponent({
+ component: Components.TabsComponent
+ }));
+ SdcUiComponentsNg1Module.directive('sdcTab', downgradeComponent({
+ component: Components.TabComponent,
+ inputs: ['title', 'active']
+ }));
+
+ // Svg Icons
+ SdcUiComponentsNg1Module.directive('svgIcon', downgradeComponent({
+ component: Components.SvgIconComponent,
+ inputs: ['name', 'mode', 'size', 'disabled', 'clickable', 'className']
+ }));
+ SdcUiComponentsNg1Module.directive('svgIconLabel', downgradeComponent({
+ component: Components.SvgIconLabelComponent,
+ inputs: ['name', 'mode', 'size', 'disabled', 'clickable', 'className', 'label', 'labelPlacement', 'labelClassName']
+ }));
+
+ // Accordion
+ SdcUiComponentsNg1Module.directive('sdcAccordion', downgradeComponent({
+ component: Components.AccordionComponent,
+ inputs: ['arrow-direction', 'css-class', 'title', 'open'],
+ outputs: ['accordionChanged']
+ }));
+}
+
+export {SdcUiComponentsNg1Module};
diff --git a/src/angular/notifications/container/notifcontainer.component.html.ts b/src/angular/notifications/container/notifcontainer.component.html.ts
new file mode 100644
index 0000000..df08bb4
--- /dev/null
+++ b/src/angular/notifications/container/notifcontainer.component.html.ts
@@ -0,0 +1,6 @@
+export default `
+<div id="containerid" class="sdc-notification-container ntns">
+ <sdc-notification *ngFor="let notif of notifications" [notificationSetting]="notif" (destroyComponent)="onDestroyed(notif)" >
+ </sdc-notification>
+</div>
+`;
diff --git a/src/angular/notifications/container/notifcontainer.component.ts b/src/angular/notifications/container/notifcontainer.component.ts
new file mode 100644
index 0000000..a922dc1
--- /dev/null
+++ b/src/angular/notifications/container/notifcontainer.component.ts
@@ -0,0 +1,31 @@
+import { Component, Input, Output, EventEmitter, OnInit } from "@angular/core";
+import { CommonModule } from "@angular/common";
+import { NotificationSettings } from "../utilities/notification.config";
+import { NotificationsService } from "../services/notifications.service";
+import template from "./notifcontainer.component.html";
+
+@Component({
+ selector: "sdc-notification-container",
+ template: template
+})
+export class NotificationContainerComponent implements OnInit {
+ notifications: NotificationSettings[] = [];
+
+ constructor(private notify: NotificationsService) {
+ }
+
+ public ngOnInit(){
+ this.notify.subscribe( (notif : NotificationSettings) => {
+ this.notifications.push(notif);
+ });
+ }
+
+
+ private onDestroyed = (event : any):void =>{
+ let index: number = this.notifications.indexOf(event);
+ if (index !== -1) {
+ this.notifications.splice(index, 1);
+ }
+ }
+
+}
diff --git a/src/angular/notifications/notification-inner-content-example.component.ts b/src/angular/notifications/notification-inner-content-example.component.ts
new file mode 100644
index 0000000..552f7b0
--- /dev/null
+++ b/src/angular/notifications/notification-inner-content-example.component.ts
@@ -0,0 +1,21 @@
+import { Component, Input } from "@angular/core";
+
+@Component({
+ selector: "innernotif-content",
+ template: `
+ <div>
+ <h4>Custom Notification</h4>
+ <div>
+ <span>{{notifyTitle}}</span>
+ </div>
+ <div>
+ <span>{{notifyText}}</span>
+ </div>
+ </div>
+`
+})
+export class InnerNotifContent {
+
+ @Input() notifyTitle:string;
+ @Input() notifyText:string;
+}
diff --git a/src/angular/notifications/notification.module.ts b/src/angular/notifications/notification.module.ts
new file mode 100644
index 0000000..5891391
--- /dev/null
+++ b/src/angular/notifications/notification.module.ts
@@ -0,0 +1,29 @@
+import { NgModule } from "@angular/core";
+import { CommonModule } from "@angular/common";
+import { NotificationComponent } from "./notification/notification.component";
+import { NotificationContainerComponent } from "./container/notifcontainer.component";
+import { NotificationsService } from "./services/notifications.service";
+import { CreateDynamicComponentService } from "../utils/create-dynamic-component.service";
+
+
+@NgModule({
+ declarations: [
+ NotificationComponent,
+ NotificationContainerComponent,
+ ],
+ exports: [
+ NotificationComponent,
+ NotificationContainerComponent,
+ ],
+ entryComponents: [
+ NotificationComponent,
+ NotificationContainerComponent,
+ ],
+ imports: [
+ CommonModule
+ ],
+ providers: [NotificationsService, CreateDynamicComponentService]
+})
+export class NotificationModule {
+
+}
diff --git a/src/angular/notifications/notification/notification.component.html.ts b/src/angular/notifications/notification/notification.component.html.ts
new file mode 100644
index 0000000..450972e
--- /dev/null
+++ b/src/angular/notifications/notification/notification.component.html.ts
@@ -0,0 +1,19 @@
+export default `
+<div class="sdc-notification" (click)="fadeOut()">
+ <div class="sdc-notification__wrapper {{'type-' + notificationSetting.type}}" [class.fade-out__animated]="fade" (animationend)="destroyMe()">
+ <div *ngIf="!notificationSetting.hasCustomContent" class="sdc-notification__content">
+ <div class="sdc-notification__icon" >
+ </div>
+ <div class="sdc-notification__message">
+ <div class="sdc-notification__title">
+ {{notificationSetting.notifyTitle}}
+ </div>
+ <div class="sdc-notification__text" >
+ {{notificationSetting.notifyText}}
+ </div>
+ </div>
+ </div>
+ <div #dynamicContentContainer></div>
+ </div>
+</div>
+`;
diff --git a/src/angular/notifications/notification/notification.component.ts b/src/angular/notifications/notification/notification.component.ts
new file mode 100644
index 0000000..476853c
--- /dev/null
+++ b/src/angular/notifications/notification/notification.component.ts
@@ -0,0 +1,42 @@
+import { Component, Input, Output, EventEmitter, OnInit, ViewContainerRef, ViewChild } from "@angular/core";
+import { NotificationSettings } from "../utilities/notification.config";
+import { CreateDynamicComponentService } from "../../utils/create-dynamic-component.service";
+import template from "./notification.component.html";
+
+@Component({
+ selector: 'sdc-notification',
+ template: template
+})
+
+export class NotificationComponent implements OnInit {
+
+ @Input() notificationSetting:NotificationSettings;
+ @Output() destroyComponent = new EventEmitter<any>();
+ @ViewChild("dynamicContentContainer", {read: ViewContainerRef}) contentContainer:ViewContainerRef;
+ private fade: boolean = false;
+
+ constructor(private createDynamicComponentService: CreateDynamicComponentService) {
+ }
+
+ public ngOnInit() {
+ if(this.notificationSetting.hasCustomContent){
+ this.createDynamicComponentService.insertComponentDynamically(this.notificationSetting.innerComponentType, this.notificationSetting.innerComponentOptions, this.contentContainer);
+ }
+
+ if(!this.notificationSetting.sticky){
+ setTimeout(() => this.fadeOut(), this.notificationSetting.duration);
+ }
+ }
+
+ private fadeOut = ():void => {
+ this.fade = true;
+ }
+
+ private destroyMe() {
+ /*Only destroy on fade out, not on entry animation */
+ if(this.fade){
+ this.destroyComponent.emit(this.notificationSetting);
+ }
+ }
+
+}
diff --git a/src/angular/notifications/services/notifications.service.ts b/src/angular/notifications/services/notifications.service.ts
new file mode 100644
index 0000000..28a645c
--- /dev/null
+++ b/src/angular/notifications/services/notifications.service.ts
@@ -0,0 +1,41 @@
+import { Injectable } from '@angular/core';
+import { NotificationSettings } from '../utilities/notification.config'
+import { Subject } from 'rxjs/Subject';
+import { Subscription } from 'rxjs/Subscription';
+
+
+@Injectable()
+export class NotificationsService {
+
+ notifs : NotificationSettings[] = [];
+
+ notifQueue : Subject<any> = new Subject<any>();
+
+ constructor() {}
+
+ public push(notif : NotificationSettings):void{
+
+ if( this.notifQueue.observers.length > 0 ) {
+ this.notifQueue.next(notif);
+ } else {
+ this.notifs.push(notif);
+ }
+ }
+
+
+
+ public getNotifications() : NotificationSettings[] {
+ return this.notifs;
+ }
+
+
+
+ public subscribe(observer): Subscription {
+ let s:Subscription = this.notifQueue.subscribe(observer);
+ this.notifs.forEach(notif => this.notifQueue.next(notif));
+ this.notifs = [];
+ return s;
+ }
+
+
+}
diff --git a/src/angular/notifications/utilities/notification.config.ts b/src/angular/notifications/utilities/notification.config.ts
new file mode 100644
index 0000000..f469b7d
--- /dev/null
+++ b/src/angular/notifications/utilities/notification.config.ts
@@ -0,0 +1,30 @@
+import { Type, ComponentRef } from '@angular/core';
+
+export type NotificationType =
+ "info" | "warn" | "error" | "success";
+
+export class NotificationSettings {
+
+ public type: NotificationType;
+ public notifyText: string;
+ public notifyTitle: string;
+ public sticky: boolean;
+ public hasCustomContent :boolean;
+ public duration:number;
+ public innerComponentType: Type<any>;
+ public innerComponentOptions : any;
+
+ constructor(type: NotificationType, notifyText: string, notifyTitle: string, duration: number = 10000, sticky: boolean = false, hasCustomContent:boolean = false, innerComponentType?:Type<any>, innerComponentOptions? :any) {
+
+ this.type = type;
+ this.notifyText = notifyText;
+ this.notifyTitle = notifyTitle;
+ this.duration = duration;
+ this.sticky = sticky;
+ this.hasCustomContent = hasCustomContent;
+ this.innerComponentType = innerComponentType;
+ this.innerComponentOptions = innerComponentOptions;
+ }
+
+
+}
diff --git a/src/angular/popup-menu/popup-menu-item.component.spec.ts b/src/angular/popup-menu/popup-menu-item.component.spec.ts
new file mode 100644
index 0000000..25b2694
--- /dev/null
+++ b/src/angular/popup-menu/popup-menu-item.component.spec.ts
@@ -0,0 +1,25 @@
+import { Component, Input, Output, ContentChildren, SimpleChanges, QueryList, EventEmitter, OnChanges, AfterContentInit } from '@angular/core';
+import { FormsModule } from "@angular/forms";
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { PopupMenuItemComponent } from './popup-menu-item.component';
+import { PopupMenuListComponent } from './popup-menu-list.component';
+
+describe('Popup Menu', () => {
+ let component: PopupMenuListComponent;
+ let fixture: ComponentFixture<PopupMenuListComponent>;
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ PopupMenuListComponent ],
+ }).compileComponents();
+ fixture = TestBed.createComponent(PopupMenuListComponent);
+ component = fixture.componentInstance;
+ }));
+
+ it('Popup menu component should be created', () => {
+ expect(component).toBeTruthy();
+ });
+
+ it('Set Position to Popup Menu', () => {
+ expect(component.position).toEqual({ x: 0, y: 0 })
+ });
+})
diff --git a/src/angular/popup-menu/popup-menu-item.component.ts b/src/angular/popup-menu/popup-menu-item.component.ts
new file mode 100644
index 0000000..fb5a71d
--- /dev/null
+++ b/src/angular/popup-menu/popup-menu-item.component.ts
@@ -0,0 +1,34 @@
+import { Component, Input, Output, EventEmitter, OnChanges, SimpleChanges } from '@angular/core';
+import { PopupMenuListComponent } from "./popup-menu-list.component";
+
+@Component({
+ selector: 'popup-menu-item',
+ template:
+ `<li [ngClass]="[className || '', type || '', type == 'separator'? '': 'sdc-menu-item']" (click)="performAction($event)">
+ <ng-content *ngIf="type != 'separator'"></ng-content>
+</li>`
+})
+export class PopupMenuItemComponent {
+ @Input() public className: string;
+ @Input() public type: undefined|'disabled'|'selected'|'separator';
+ @Output() public action: EventEmitter<any> = new EventEmitter<any>();
+
+ public parentMenu: PopupMenuListComponent;
+ public index: number = 0;
+
+ public performAction(evt) {
+ evt.stopPropagation();
+
+ if (['disabled', 'separator'].indexOf(this.type) !== -1) {
+ return;
+ }
+
+ if (this.parentMenu instanceof PopupMenuListComponent) {
+ this.parentMenu.open = false;
+ }
+
+ if (this.action) {
+ this.action.emit();
+ }
+ }
+}
diff --git a/src/angular/popup-menu/popup-menu-list.component.ts b/src/angular/popup-menu/popup-menu-list.component.ts
new file mode 100644
index 0000000..6a20423
--- /dev/null
+++ b/src/angular/popup-menu/popup-menu-list.component.ts
@@ -0,0 +1,65 @@
+import { Component, Input, Output, ContentChildren, SimpleChanges, QueryList, EventEmitter, OnChanges, AfterContentInit } from '@angular/core';
+import { PopupMenuItemComponent } from "./popup-menu-item.component";
+
+export interface IPoint {
+ x: number;
+ y: number;
+}
+
+@Component({
+ selector: 'popup-menu-list',
+ template:
+ `<ul
+ class="sdc-menu-list"
+ *ngIf="open"
+ [ngClass]="[className || '', relative? 'relative': '']"
+ [ngStyle]="{'left': position.x + 'px', 'top': position.y + 'px'}"
+ (click)="$event.stopPropagation()">
+ <ng-content></ng-content>
+ </ul>`
+})
+export class PopupMenuListComponent implements AfterContentInit {
+ @Input()
+ public get open(): boolean {
+ return this._open;
+ }
+ public set open(isOpen: boolean) {
+ isOpen = isOpen !== undefined ? isOpen : false;
+ if (this._open !== isOpen) {
+ this._open = isOpen;
+ this.openChange.emit(this._open);
+ }
+ }
+ @Input()
+ public get position(): IPoint {
+ return this._position;
+ }
+ public set position(position: IPoint) {
+ position = position !== undefined ? position : {x: 0, y: 0};
+ if (this._position.x !== position.x || this._position.y !== position.y) {
+ this._position = position;
+ this.positionChange.emit(this._position);
+ }
+ }
+ @Input() public className: string;
+ @Input() public relative: boolean = false;
+ @Output() public openChange: EventEmitter<boolean> = new EventEmitter<boolean>();
+ @Output() public positionChange: EventEmitter<IPoint> = new EventEmitter<IPoint>();
+
+ @ContentChildren(PopupMenuItemComponent) private menuItems: QueryList<PopupMenuItemComponent>;
+
+ private _open: boolean = false;
+ private _position: IPoint = {x: 0, y: 0};
+
+ public ngAfterContentInit() {
+ this._updateMenuItemsList(this.menuItems);
+ this.menuItems.changes.subscribe(this._updateMenuItemsList);
+ }
+
+ private _updateMenuItemsList(menuItemsList: QueryList<PopupMenuItemComponent>) {
+ menuItemsList.forEach((c, idx) => {
+ c.parentMenu = this;
+ c.index = idx;
+ });
+ }
+}
diff --git a/src/angular/popup-menu/popup-menu.module.ts b/src/angular/popup-menu/popup-menu.module.ts
new file mode 100644
index 0000000..3a58b91
--- /dev/null
+++ b/src/angular/popup-menu/popup-menu.module.ts
@@ -0,0 +1,21 @@
+import { NgModule } from "@angular/core";
+import { PopupMenuListComponent } from "./popup-menu-list.component";
+import { PopupMenuItemComponent } from "./popup-menu-item.component";
+import { CommonModule } from "@angular/common";
+
+
+@NgModule({
+ declarations: [
+ PopupMenuListComponent,
+ PopupMenuItemComponent
+ ],
+ imports: [
+ CommonModule
+ ],
+ exports: [
+ PopupMenuListComponent,
+ PopupMenuItemComponent
+ ],
+})
+export class PopupMenuModule {
+}
diff --git a/src/angular/searchbar/search-bar.component.html.ts b/src/angular/searchbar/search-bar.component.html.ts
new file mode 100644
index 0000000..79153f4
--- /dev/null
+++ b/src/angular/searchbar/search-bar.component.html.ts
@@ -0,0 +1,19 @@
+export default `
+<div class="search-bar-container" [ngClass]="{'not-empty': searchQuery}">
+ <sdc-input class="sdc-input-wrapper"
+ [label]="label"
+ [placeHolder]="placeholder"
+ [debounceTime]="debounceTime"
+ [(value)]="searchQuery"></sdc-input>
+ <span class="magnify-button search-button" (click)="searchButtonClick()">
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+ <defs>
+ <path id="search-a" d="M2,8.5 C2,4.9 4.9,2 8.5,2 C12.1,2 15,4.9 15,8.5 C15,10.3 14.3,11.9 13.1,13.1 C11.9,14.3 10.3,15 8.5,15 C4.9,15 2,12.1 2,8.5 M19.7,18.3 L15.2,13.8 C16.3,12.4 17,10.5 17,8.5 C17,3.8 13.2,0 8.5,0 C3.8,0 0,3.8 0,8.5 C0,13.2 3.8,17 8.5,17 C10.5,17 12.3,16.3 13.8,15.2 L18.3,19.7 C18.5,19.9 18.8,20 19,20 C19.2,20 19.5,19.9 19.7,19.7 C20.1,19.3 20.1,18.7 19.7,18.3"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd" transform="translate(2 2)">
+ <use fill="#000" xlink:href="#search-a"/>
+ </g>
+ </svg>
+ </span>
+</div>
+`;
diff --git a/src/angular/searchbar/search-bar.component.ts b/src/angular/searchbar/search-bar.component.ts
new file mode 100644
index 0000000..7f508d7
--- /dev/null
+++ b/src/angular/searchbar/search-bar.component.ts
@@ -0,0 +1,19 @@
+import { Component, Input, Output, EventEmitter, HostBinding } from '@angular/core';
+import template from "./search-bar.component.html";
+
+@Component({
+ selector: 'sdc-search-bar',
+ template: template
+})
+export class SearchBarComponent {
+
+ @HostBinding('class') classes = 'sdc-search-bar';
+ @Input() public placeholder: string;
+ @Input() public label: string;
+ @Input() public searchQuery: string;
+ @Output() public searchQueryClick: EventEmitter<string> = new EventEmitter<string>();
+
+ private searchButtonClick = (): void => {
+ this.searchQueryClick.emit(this.searchQuery);
+ }
+}
diff --git a/src/angular/searchbar/search-bar.module.ts b/src/angular/searchbar/search-bar.module.ts
new file mode 100644
index 0000000..27750f3
--- /dev/null
+++ b/src/angular/searchbar/search-bar.module.ts
@@ -0,0 +1,17 @@
+import { NgModule } from "@angular/core";
+import { SearchBarComponent } from "./search-bar.component";
+import { CommonModule } from "@angular/common";
+import { FormElementsModule } from "../form-elements/form-elements.module";
+
+@NgModule({
+ declarations: [
+ SearchBarComponent
+ ],
+ imports: [CommonModule,
+ FormElementsModule],
+ exports: [
+ SearchBarComponent
+ ],
+})
+export class SearchBarModule {
+}
diff --git a/src/angular/svg-icon/svg-icon-label.component.html.ts b/src/angular/svg-icon/svg-icon-label.component.html.ts
new file mode 100644
index 0000000..558b7c4
--- /dev/null
+++ b/src/angular/svg-icon/svg-icon-label.component.html.ts
@@ -0,0 +1,6 @@
+export default `
+<div class="svg-icon-wrapper" [ngClass]="[(mode) ? 'mode-'+mode : '', (size) ? 'size-'+size : '', (labelPlacement) ? 'label-placement-'+labelPlacement : '', (clickable) ? 'clickable' : '', className || '']" [attr.disabled]="disabled || undefined">
+ <svg-icon [name]="name" className="svg-icon"></svg-icon>
+ <span class="svg-icon-label" [ngClass]="[labelClassName || '']">{{ label }}</span>
+</div>
+`;
diff --git a/src/angular/svg-icon/svg-icon-label.component.ts b/src/angular/svg-icon/svg-icon-label.component.ts
new file mode 100644
index 0000000..5a00c3d
--- /dev/null
+++ b/src/angular/svg-icon/svg-icon-label.component.ts
@@ -0,0 +1,26 @@
+import { Component, Input } from "@angular/core";
+import { SvgIconComponent } from './svg-icon.component';
+import { Mode, Size, Placement } from "../common/enums";
+import { DomSanitizer, SafeHtml } from "@angular/platform-browser";
+import template from './svg-icon-label.component.html';
+
+@Component({
+ selector: 'svg-icon-label',
+ template: template,
+ styles: [`
+ :host {
+ display: inline-flex;
+ }
+ `]
+})
+export class SvgIconLabelComponent extends SvgIconComponent {
+
+ @Input() public label: string;
+ @Input() public labelPlacement: Placement;
+ @Input() public labelClassName: string;
+
+ constructor(protected domSanitizer: DomSanitizer) {
+ super(domSanitizer);
+ this.labelPlacement = Placement.left;
+ }
+}
diff --git a/src/angular/svg-icon/svg-icon.component.html.ts b/src/angular/svg-icon/svg-icon.component.html.ts
new file mode 100644
index 0000000..1baedbd
--- /dev/null
+++ b/src/angular/svg-icon/svg-icon.component.html.ts
@@ -0,0 +1,3 @@
+export default `
+<div [ngClass]="classes" [attr.disabled]="disabled || undefined" [innerHtml]="svgIconContentSafeHtml"></div>
+`;
diff --git a/src/angular/svg-icon/svg-icon.component.ts b/src/angular/svg-icon/svg-icon.component.ts
new file mode 100644
index 0000000..d53981d
--- /dev/null
+++ b/src/angular/svg-icon/svg-icon.component.ts
@@ -0,0 +1,77 @@
+import { Component, Input, OnChanges, SimpleChanges, HostBinding } from "@angular/core";
+import { DomSanitizer, SafeHtml } from "@angular/platform-browser";
+import { Mode, Size } from "../common/enums";
+import iconsMap from '../../common/icons-map';
+import template from './svg-icon.component.html';
+
+@Component({
+ selector: 'svg-icon',
+ template: template,
+ styles: [`
+ :host {
+ display: inline-flex;
+ }
+ `]
+})
+export class SvgIconComponent implements OnChanges {
+
+ @Input() public name: string;
+ @Input() public mode: Mode;
+ @Input() public size: Size;
+ @Input() public disabled: boolean;
+ @Input() public clickable: boolean;
+ @Input() public className: any;
+
+ public svgIconContent: string;
+ public svgIconContentSafeHtml: SafeHtml;
+ public svgIconCustomClassName: string;
+ private classes: string;
+
+ constructor(protected domSanitizer: DomSanitizer) {
+ this.size = Size.medium;
+ this.disabled = false;
+ }
+
+ static get Icons(): {[key: string]: string} {
+ return iconsMap;
+ }
+
+ public ngOnChanges(changes: SimpleChanges) {
+ if (changes.name) {
+ this.updateSvgIconByName();
+ this.buildClasses();
+ }
+ }
+
+ protected updateSvgIconByName() {
+ this.svgIconContent = SvgIconComponent.Icons[this.name] || null;
+ if (this.svgIconContent) {
+ this.svgIconContentSafeHtml = this.domSanitizer.bypassSecurityTrustHtml(this.svgIconContent);
+ this.svgIconCustomClassName = '__' + this.name.replace(/\s+/g, '_');
+ } else {
+ this.svgIconContentSafeHtml = null;
+ this.svgIconCustomClassName = 'missing';
+ }
+ }
+
+ private buildClasses = (): void => {
+ const _classes = [];
+ _classes.push('svg-icon');
+ if (this.mode) {
+ _classes.push('mode-' + this.mode);
+ }
+ if (this.size) {
+ _classes.push('size-' + this.size);
+ }
+ if (this.clickable) {
+ _classes.push('clickable');
+ }
+ if (this.svgIconCustomClassName) {
+ _classes.push(this.svgIconCustomClassName);
+ }
+ if (this.className) {
+ _classes.push(this.className);
+ }
+ this.classes = _classes.join(" ");
+ }
+}
diff --git a/src/angular/svg-icon/svg-icon.module.ts b/src/angular/svg-icon/svg-icon.module.ts
new file mode 100644
index 0000000..87a0d86
--- /dev/null
+++ b/src/angular/svg-icon/svg-icon.module.ts
@@ -0,0 +1,21 @@
+import { NgModule } from "@angular/core";
+import { CommonModule } from "@angular/common";
+import { SvgIconComponent } from "./svg-icon.component";
+import { SvgIconLabelComponent } from "./svg-icon-label.component";
+
+@NgModule({
+ declarations: [
+ SvgIconComponent,
+ SvgIconLabelComponent
+ ],
+ imports: [
+ CommonModule
+ ],
+ exports: [
+ SvgIconComponent,
+ SvgIconLabelComponent
+ ],
+})
+
+export class SvgIconModule {
+}
diff --git a/src/angular/tabs/children/tab.component.html.ts b/src/angular/tabs/children/tab.component.html.ts
new file mode 100644
index 0000000..36ff413
--- /dev/null
+++ b/src/angular/tabs/children/tab.component.html.ts
@@ -0,0 +1,5 @@
+export default `
+<div [hidden]="!active" class="sdc-tab-content" role="tabpanel">
+ <ng-content></ng-content>
+</div>
+`;
diff --git a/src/angular/tabs/children/tab.component.ts b/src/angular/tabs/children/tab.component.ts
new file mode 100644
index 0000000..3b96e87
--- /dev/null
+++ b/src/angular/tabs/children/tab.component.ts
@@ -0,0 +1,16 @@
+import { Component, Input } from '@angular/core';
+import { Mode } from './../../common/enums';
+import template from "./tab.component.html";
+
+@Component({
+ selector: 'sdc-tab',
+ template: template
+})
+export class TabComponent {
+ @Input() public title: string;
+ @Input() public titleIcon: string;
+ @Input() public active = false;
+
+ public titleIconMode = Mode.secondary;
+
+}
diff --git a/src/angular/tabs/tabs.component.html.ts b/src/angular/tabs/tabs.component.html.ts
new file mode 100644
index 0000000..2333b86
--- /dev/null
+++ b/src/angular/tabs/tabs.component.html.ts
@@ -0,0 +1,14 @@
+export default `
+<ul class="sdc-tabs-list" role="tablist">
+ <li *ngFor="let tab of tabs" class="sdc-tab" role="tab" (click)="selectTab(tab)" [class.sdc-tab-active]="tab.active">
+ <span *ngIf="tab.title">{{tab.title}}</span>
+ <svg-icon-label
+ *ngIf="tab.titleIcon"
+ [name]="tab.titleIcon"
+ [mode]="tab.titleIconMode"
+ [size]="_size">
+ </svg-icon-label>
+ </li>
+</ul>
+<ng-content></ng-content>
+`;
diff --git a/src/angular/tabs/tabs.component.ts b/src/angular/tabs/tabs.component.ts
new file mode 100644
index 0000000..595f304
--- /dev/null
+++ b/src/angular/tabs/tabs.component.ts
@@ -0,0 +1,41 @@
+import { Component, Input, AfterContentInit, ContentChildren, QueryList, HostBinding } from '@angular/core';
+import { TabComponent } from './children/tab.component';
+import { SvgIconComponent } from "./../../../src/angular/svg-icon/svg-icon.component";
+import { Mode, Placement, Size } from './../common/enums';
+import template from "./tabs.component.html";
+
+@Component({
+ selector: 'sdc-tabs',
+ template: template
+})
+
+export class TabsComponent implements AfterContentInit {
+
+ @HostBinding('class') classes = 'sdc-tabs sdc-tabs-header';
+ @ContentChildren(TabComponent) private tabs: QueryList<TabComponent>;
+
+ public _size = Size.medium;
+
+ public selectTab(tab: TabComponent) {
+ // deactivate all tabs
+ this.tabs.toArray().forEach((_tab: TabComponent) => {
+ _tab.active = false;
+ _tab.titleIconMode = Mode.secondary;
+ });
+
+ // activate the tab the user has clicked on.
+ tab.active = true;
+ tab.titleIconMode = Mode.primary;
+ }
+
+ public ngAfterContentInit() {
+ // get all active tabs
+ const activeTabs = this.tabs.filter((tab) => tab.active);
+
+ // if there is no active tab set, activate the first
+ if (activeTabs.length === 0) {
+ this.selectTab(this.tabs.first);
+ }
+ }
+
+ }
diff --git a/src/angular/tabs/tabs.module.ts b/src/angular/tabs/tabs.module.ts
new file mode 100644
index 0000000..107942d
--- /dev/null
+++ b/src/angular/tabs/tabs.module.ts
@@ -0,0 +1,23 @@
+import { NgModule } from "@angular/core";
+import { CommonModule } from "@angular/common";
+import { FormElementsModule } from "../form-elements/form-elements.module";
+import { TabsComponent } from "./tabs.component";
+import { TabComponent } from './children/tab.component';
+import { SvgIconModule } from './../svg-icon/svg-icon.module';
+
+@NgModule({
+ declarations: [
+ TabsComponent,
+ TabComponent
+ ],
+ imports: [
+ CommonModule,
+ SvgIconModule
+ ],
+ exports: [
+ TabsComponent,
+ TabComponent
+ ]
+})
+export class TabsModule {
+}
diff --git a/src/angular/tag-cloud/tag-cloud.component.html.ts b/src/angular/tag-cloud/tag-cloud.component.html.ts
new file mode 100644
index 0000000..2ff4e8a
--- /dev/null
+++ b/src/angular/tag-cloud/tag-cloud.component.html.ts
@@ -0,0 +1,30 @@
+export default `
+<div class="sdc-tag-cloud-new-item-field" [ngClass]="{'not-empty': newTagItem}">
+ <sdc-input [label]="label"
+ [disabled]="(isViewOnly===true)"
+ [placeHolder]="placeholder"
+ [(value)]="newTagItem"
+ (keyup)="onKeyup($event)"
+ [ngClass]="{'error': uniqueError}"></sdc-input>
+ <div class="add-button" (click)="newTagItem && insertItemToList()" [ngClass]="{'disabled': !newTagItem || uniqueError}">
+ <span class="plus-icon">
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+ <defs>
+ <path id="add-a" d="M15,7 L9,7 L9,1 C9,0.4 8.6,0 8,0 C7.4,0 7,0.4 7,1 L7,7 L1,7 C0.4,7 0,7.4 0,8 C0,8.6 0.4,9 1,9 L7,9 L7,15 C7,15.6 7.4,16 8,16 C8.6,16 9,15.6 9,15 L9,9 L15,9 C15.6,9 16,8.6 16,8 C16,7.4 15.6,7 15,7"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd" transform="translate(4 4)">
+ <use xlink:href="#add-a"/>
+ </g>
+ </svg>
+ </span>
+ </div>
+</div>
+<div class="sdc-list-container">
+ <sdc-tag-item *ngFor="let item of list; let i = index;"
+ [text]="item"
+ [index]="i"
+ [isViewOnly]="isViewOnly && (isViewOnly === true || isViewOnly.indexOf(i) > -1)"
+ (clickOnDelete)="deleteItemFromList($event)"></sdc-tag-item>
+</div>
+<div class="error-message" *ngIf="uniqueError">{{uniqueErrorMessage}}</div>
+`;
diff --git a/src/angular/tag-cloud/tag-cloud.component.ts b/src/angular/tag-cloud/tag-cloud.component.ts
new file mode 100644
index 0000000..1635b8d
--- /dev/null
+++ b/src/angular/tag-cloud/tag-cloud.component.ts
@@ -0,0 +1,46 @@
+import { Component, EventEmitter, Input, Output } from "@angular/core";
+import template from "./tag-cloud.component.html";
+
+@Component({
+ selector: 'sdc-tag-cloud',
+ template: template,
+})
+export class TagCloudComponent {
+ @Input() public list: string[];
+ @Input() public isViewOnly: boolean|number[]; // get a boolean parameter or array of specific items indexes.
+ @Input() public isUniqueList: boolean;
+ @Input() public uniqueErrorMessage: string = "Unique error";
+ @Input() public label: string;
+ @Input() public placeholder: string;
+ @Output() public listChanged: EventEmitter<string[]> = new EventEmitter<string[]>();
+ private newTagItem: string;
+ private uniqueError: boolean;
+
+ private onKeyup = (e): void => {
+ if (e.keyCode === 13) {
+ this.insertItemToList();
+ }
+ }
+
+ private insertItemToList = (): void => {
+ this.validateTag();
+ if (!this.uniqueError && this.newTagItem.length) {
+ this.list.push(this.newTagItem);
+ this.newTagItem = "";
+ this.listChanged.emit(this.list);
+ }
+ }
+
+ private deleteItemFromList = (index: number): void => {
+ this.list.splice(index, 1);
+ if (Array.isArray(this.isViewOnly)) {
+ this.isViewOnly = this.isViewOnly.map((i: number) => {
+ return i > index ? i - 1 : i;
+ });
+ }
+ }
+
+ private validateTag = (): void => {
+ this.uniqueError = this.list && this.list.indexOf(this.newTagItem) > -1;
+ }
+}
diff --git a/src/angular/tag-cloud/tag-cloud.module.ts b/src/angular/tag-cloud/tag-cloud.module.ts
new file mode 100644
index 0000000..fd7efb4
--- /dev/null
+++ b/src/angular/tag-cloud/tag-cloud.module.ts
@@ -0,0 +1,21 @@
+import { NgModule } from "@angular/core";
+import { TagItemComponent } from "./tag-item/tag-item.component";
+import { TagCloudComponent } from "./tag-cloud.component";
+import { CommonModule } from "@angular/common";
+import { FormElementsModule } from './../form-elements/form-elements.module';
+
+@NgModule({
+ declarations: [
+ TagItemComponent,
+ TagCloudComponent
+ ],
+ imports: [
+ CommonModule,
+ FormElementsModule
+ ],
+ exports: [
+ TagCloudComponent
+ ]
+})
+export class TagCloudModule {
+}
diff --git a/src/angular/tag-cloud/tag-item/tag-item.component.html.ts b/src/angular/tag-cloud/tag-item/tag-item.component.html.ts
new file mode 100644
index 0000000..04112c1
--- /dev/null
+++ b/src/angular/tag-cloud/tag-item/tag-item.component.html.ts
@@ -0,0 +1,16 @@
+export default `
+<div class="tag-item" [ngClass]="{'view-only':isViewOnly}">
+ <span>{{text}}</span>
+ <span class="delete-item" *ngIf="!isViewOnly" (click)="clickOnDelete.emit(index)">
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+ <defs>
+ <path id="close-a" d="M13.5996,12 L19.6576,5.942 C20.1146,5.485 20.1146,4.8 19.6576,4.343 C19.2006,3.886 18.5146,3.886 18.0576,4.343 L11.9996,10.4 L5.9426,4.343 C5.4856,3.886 4.7996,3.886 4.3426,4.343 C3.8856,4.8 3.8856,5.485 4.3426,5.942 L10.4006,12 L4.3426,18.058 C3.8856,18.515 3.8856,19.2 4.3426,19.657 C4.5716,19.886 4.7996,20 5.1426,20 C5.4856,20 5.7136,19.886 5.9426,19.657 L11.9996,13.6 L18.0576,19.657 C18.2866,19.886 18.6286,20 18.8576,20 C19.0856,20 19.4286,19.886 19.6576,19.657 C20.1146,19.2 20.1146,18.515 19.6576,18.058 L13.5996,12 Z"/>
+ </defs>
+ <g fill="none" fill-rule="evenodd">
+ <use xlink:href="#close-a"/>
+ </g>
+ </svg>
+ </span>
+</div>
+`;
+
diff --git a/src/angular/tag-cloud/tag-item/tag-item.component.ts b/src/angular/tag-cloud/tag-item/tag-item.component.ts
new file mode 100644
index 0000000..f2e2fa7
--- /dev/null
+++ b/src/angular/tag-cloud/tag-item/tag-item.component.ts
@@ -0,0 +1,15 @@
+import { Component, EventEmitter, Input, Output, HostBinding } from "@angular/core";
+import template from "./tag-item.component.html";
+
+@Component({
+ selector: 'sdc-tag-item',
+ template: template
+})
+
+export class TagItemComponent {
+ @HostBinding('class') classes = 'sdc-tag-item';
+ @Input() public text: string;
+ @Input() public isViewOnly: boolean;
+ @Input() public index: number;
+ @Output() public clickOnDelete: EventEmitter<number> = new EventEmitter<number>();
+}
diff --git a/src/angular/tiles/children/tile-content.component.ts b/src/angular/tiles/children/tile-content.component.ts
new file mode 100644
index 0000000..741db26
--- /dev/null
+++ b/src/angular/tiles/children/tile-content.component.ts
@@ -0,0 +1,10 @@
+import { Component, HostBinding } from "@angular/core";
+
+@Component({
+ selector: 'sdc-tile-content',
+ template: '<ng-content></ng-content>'
+})
+
+export class TileContentComponent {
+ @HostBinding('class') classes = 'sdc-tile-content';
+}
diff --git a/src/angular/tiles/children/tile-footer.component.ts b/src/angular/tiles/children/tile-footer.component.ts
new file mode 100644
index 0000000..519c5ba
--- /dev/null
+++ b/src/angular/tiles/children/tile-footer.component.ts
@@ -0,0 +1,10 @@
+import { Component, HostBinding } from '@angular/core';
+
+@Component({
+ selector: 'sdc-tile-footer',
+ template: '<ng-content></ng-content>'
+})
+
+export class TileFooterComponent {
+ @HostBinding('class') classes = 'sdc-tile-footer';
+}
diff --git a/src/angular/tiles/children/tile-header.component.ts b/src/angular/tiles/children/tile-header.component.ts
new file mode 100644
index 0000000..b040bcb
--- /dev/null
+++ b/src/angular/tiles/children/tile-header.component.ts
@@ -0,0 +1,10 @@
+import { Component, HostBinding } from '@angular/core';
+
+@Component({
+ selector: "sdc-tile-header",
+ template: '<ng-content></ng-content>'
+})
+
+export class TileHeaderComponent {
+ @HostBinding('class') classes = 'sdc-tile-header';
+}
diff --git a/src/angular/tiles/tile.component.html.ts b/src/angular/tiles/tile.component.html.ts
new file mode 100644
index 0000000..81803d5
--- /dev/null
+++ b/src/angular/tiles/tile.component.html.ts
@@ -0,0 +1,5 @@
+export default `
+<ng-content select="sdc-tile-header"></ng-content>
+<ng-content select="sdc-tile-content"></ng-content>
+<ng-content select="sdc-tile-footer"></ng-content>
+`;
diff --git a/src/angular/tiles/tile.component.ts b/src/angular/tiles/tile.component.ts
new file mode 100644
index 0000000..3791ca0
--- /dev/null
+++ b/src/angular/tiles/tile.component.ts
@@ -0,0 +1,11 @@
+import { Component, HostBinding } from '@angular/core';
+import template from "./tile.component.html";
+
+@Component({
+ selector: "sdc-tile",
+ template: template
+})
+
+export class TileComponent {
+ @HostBinding('class') classes = 'sdc-tile';
+}
diff --git a/src/angular/tiles/tile.module.ts b/src/angular/tiles/tile.module.ts
new file mode 100644
index 0000000..43c750b
--- /dev/null
+++ b/src/angular/tiles/tile.module.ts
@@ -0,0 +1,27 @@
+import { NgModule } from "@angular/core";
+import { TileComponent } from "./tile.component";
+import { CommonModule } from "@angular/common";
+import { TileContentComponent } from "./children/tile-content.component";
+import { TileFooterComponent } from "./children/tile-footer.component";
+import { TileHeaderComponent } from "./children/tile-header.component";
+
+@NgModule({
+ declarations: [
+ TileComponent,
+ TileContentComponent,
+ TileFooterComponent,
+ TileHeaderComponent
+ ],
+ imports: [CommonModule],
+ entryComponents: [TileComponent],
+ exports: [
+ TileComponent,
+ TileContentComponent,
+ TileFooterComponent,
+ TileHeaderComponent
+ ]
+})
+
+export class TileModule {
+
+}
diff --git a/src/angular/tooltip/tooltip-template.component.ts b/src/angular/tooltip/tooltip-template.component.ts
new file mode 100644
index 0000000..7cb7f72
--- /dev/null
+++ b/src/angular/tooltip/tooltip-template.component.ts
@@ -0,0 +1,20 @@
+import { Component, ViewChild, ViewContainerRef, AfterViewInit } from '@angular/core';
+import { BehaviorSubject } from 'rxjs/BehaviorSubject';
+
+@Component({
+ selector: 'tooltip-template',
+ template: `
+ <div class="sdc-tooltip-template-container">
+ <ng-container #templateContainer></ng-container>
+ </div>`
+})
+
+export class TooltipTemplateComponent implements AfterViewInit {
+ @ViewChild('templateContainer', {read: ViewContainerRef}) public container: ViewContainerRef;
+
+ public viewReady: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
+
+ ngAfterViewInit() : void {
+ this.viewReady.next(true);
+ }
+}
diff --git a/src/angular/tooltip/tooltip.directive.ts b/src/angular/tooltip/tooltip.directive.ts
new file mode 100644
index 0000000..77cec62
--- /dev/null
+++ b/src/angular/tooltip/tooltip.directive.ts
@@ -0,0 +1,459 @@
+import { Directive, ElementRef, HostListener, OnInit, Input, Renderer, TemplateRef } from '@angular/core';
+import { TooltipTemplateComponent } from './tooltip-template.component';
+import { CreateDynamicComponentService } from '../utils/create-dynamic-component.service';
+
+const pixel = 'px';
+const leftStyle = 'left';
+const topStyle = 'top';
+const showSuffix = 'show';
+const rightBottomSuffix = 'right__bottom';
+const centerMiddleSuffix = 'center__middle';
+
+@Directive({
+ selector: '[sdc-tooltip]'
+})
+export class TooltipDirective implements OnInit {
+ @Input('tooltip-text') public text = 'tooltip';
+ @Input('tooltip-placement') public placement: TooltipPlacement = TooltipPlacement.Top;
+ @Input('tooltip-css-class') public customCssClass: string;
+ @Input('tooltip-template') public template: TemplateRef<any>;
+ @Input('tooltip-arrow-offset') public arrowOffset: number = 10;
+ @Input('tooltip-arrow-placement') public arrowPlacement: ArrowPlacement = ArrowPlacement.LeftTop;
+ @Input('tooltip-offset') public tooltipOffset: number = 3;
+
+ private cssClass: string = 'sdc-tooltip'; // default css class
+ private tooltip: any; // tooltip html element
+ private elemPosition: any;
+ private tooltipTemplateContainer: any;
+
+ private scrollEventHandler = () => {};
+
+ constructor(
+ private elementRef: ElementRef,
+ private service: CreateDynamicComponentService,
+ private renderer: Renderer) {
+
+ this.elementRef.nativeElement.title = "";
+ }
+
+ @HostListener('mouseenter')
+ public onMouseEnter() {
+ this.show();
+ this.activateScrollEvent();
+ }
+
+ @HostListener('mouseleave')
+ public onMouseLeave() {
+ this.hide();
+ this.deactivateScrollEvent();
+ }
+
+ ngOnInit(): void {
+ this.initScrollEvent();
+ }
+
+ private get ScreenWidth() {
+ return document.documentElement.clientWidth;
+ }
+
+ private get ScreenHeight() {
+ return document.documentElement.clientHeight;
+ }
+
+ private create() {
+ this.tooltipTemplateContainer = this.service.createComponentDynamically(TooltipTemplateComponent, document.body);
+
+ /**
+ * Creating a view (injecting our template) from template in our component.
+ */
+ this.tooltip = this.tooltipTemplateContainer.location.nativeElement.querySelector(
+ '.sdc-tooltip-template-container');
+
+ if (this.template) {
+ this.tooltipTemplateContainer.instance.container.createEmbeddedView(this.template);
+ } else {
+ this.tooltip.textContent = this.text ? this.text : 'tooltip';
+ }
+
+ this.setCssClass(true);
+ }
+
+ private destroy() {
+ this.tooltipTemplateContainer.destroy();
+ this.tooltip = null;
+ }
+
+ private show() {
+ this.create();
+
+ /**
+ * View is ready (AfterViewInit event in template component)
+ */
+ this.tooltipTemplateContainer.instance.viewReady.subscribe((isReady) => {
+ if (isReady) {
+ this.setPosition();
+ this.toggleShowCssClass(true); // add css class
+ }
+ });
+ }
+
+ private hide() {
+ this.toggleShowCssClass(false); // remove css class
+
+ this.destroy();
+ }
+
+ private toggleShowCssClass(isAdd: boolean) {
+ if (this.tooltip) {
+ this.setCssClass(isAdd, '-' + showSuffix);
+ }
+ }
+
+ /**
+ * Adds placement css class and sets tooltip position in style
+ */
+ private setPosition() {
+ const tooltipPos: IPlacementData = this.getPlacementData();
+
+ const placementSuffix: string = TooltipPlacement[tooltipPos.placement].toLowerCase();
+
+ this.setCssClass(true, '-' + placementSuffix);
+
+ this.setAdditionalCssClass(placementSuffix);
+
+ this.renderer.setElementStyle(this.tooltip, topStyle, tooltipPos.top + pixel);
+ this.renderer.setElementStyle(this.tooltip, leftStyle, tooltipPos.left + pixel);
+ }
+
+ private setAdditionalCssClass(placementSuffix: string) {
+ if (this.arrowPlacement === ArrowPlacement.RightBottom) {
+ this.setCssClass(true, '-' + placementSuffix + '-' + rightBottomSuffix);
+ } else if (this.arrowPlacement === ArrowPlacement.CenterMiddle) {
+ this.setCssClass(true, '-' + placementSuffix + '-' + centerMiddleSuffix);
+ }
+ }
+
+ private setCssClass(isAdd: boolean, suffix: string = '') {
+ this.renderer.setElementClass(this.tooltip, this.cssClass + suffix, isAdd);
+
+ if (this.customCssClass) {
+ this.renderer.setElementClass(this.tooltip, this.customCssClass + suffix, isAdd);
+ }
+ }
+
+ /**
+ * Checks the specified placement (first element in array), if it is not valid - checks other placements
+ * @returns {IPlacementData}
+ */
+ private getPlacementData(): IPlacementData {
+ const placement: TooltipPlacement = this.placement;
+ let tooltipPos: IPlacementData;
+
+ const tooltipPosWithPlacement = this.getPlacement.bind(this, placement);
+
+ // TODO add comments - done
+ switch (placement) {
+ case TooltipPlacement.Left:
+ tooltipPos = tooltipPosWithPlacement(
+ TooltipPlacement.Right,
+ TooltipPlacement.Top,
+ TooltipPlacement.Bottom);
+ break;
+
+ case TooltipPlacement.Right:
+ tooltipPos = tooltipPosWithPlacement(
+ TooltipPlacement.Left,
+ TooltipPlacement.Top,
+ TooltipPlacement.Bottom);
+ break;
+
+ case TooltipPlacement.Top:
+ tooltipPos = tooltipPosWithPlacement(
+ TooltipPlacement.Bottom,
+ TooltipPlacement.Left,
+ TooltipPlacement.Right);
+ break;
+
+ case TooltipPlacement.Bottom:
+ tooltipPos = tooltipPosWithPlacement(
+ TooltipPlacement.Top,
+ TooltipPlacement.Left,
+ TooltipPlacement.Right);
+ break;
+ }
+
+ return tooltipPos;
+ }
+
+ /**
+ * Returns valid tooltip position data
+ * @param {TooltipPlacement} placement
+ * @param {TooltipPlacement} additionalPlacements
+ * @returns {IPlacementData}
+ */
+ private getPlacement(placement: TooltipPlacement,
+ ...additionalPlacements: TooltipPlacement[],
+ ): IPlacementData {
+ const placements: TooltipPlacement[] = [placement, ...additionalPlacements];
+ const filterPlacements = placements
+ .map((pl) => this.getPosition(pl))
+ .filter((item) => this.validatePosition(item));
+ return filterPlacements.length > 0 ? filterPlacements[0] : this.getPosition(placement);
+ }
+
+ /**
+ * Returns input data for getPosition method
+ * @returns {ITooltipPositionParams}
+ */
+ private getPlacementInputParams(): ITooltipPositionParams {
+ this.elemPosition = this.elementRef.nativeElement.getBoundingClientRect();
+
+ return {
+ elemHeight: this.elementRef.nativeElement.offsetHeight,
+ elemLeft: this.elemPosition.left,
+ elemTop: this.elemPosition.top,
+ elemWidth: this.elementRef.nativeElement.offsetWidth,
+ pageYOffset: window.pageYOffset,
+ tooltipHeight: this.tooltip.offsetHeight, // .clientHeight,
+ tooltipOffset: this.tooltipOffset,
+ tooltipWidth: this.tooltip.offsetWidth,
+ arrowOffset: this.arrowOffset
+ };
+ }
+
+ /**
+ * Returns tooltip position data
+ * @param {TooltipPlacement} placement (left, top, right, bottom)
+ * @returns {IPlacementData}
+ */
+ private getPosition(placement: TooltipPlacement): IPlacementData {
+ switch(this.arrowPlacement) {
+ case ArrowPlacement.LeftTop:
+ return this.getLeftTopPosition(placement);
+
+ case ArrowPlacement.RightBottom:
+ return this.getRightBottomPosition(placement);
+ }
+
+ return this.getCenterMiddlePosition(placement);
+ }
+
+ /**
+ * Returns tooltip position data (center / middle arrow)
+ * @param {TooltipPlacement} placement (left, top, right, bottom)
+ * @returns {IPlacementData}
+ */
+ private getCenterMiddlePosition(placement: TooltipPlacement): IPlacementData {
+ let left = 0;
+ let top = 0;
+
+ const inputPos: ITooltipPositionParams = this.getPlacementInputParams();
+ switch (placement) {
+ case TooltipPlacement.Left:
+ left = inputPos.elemLeft - inputPos.tooltipWidth - inputPos.tooltipOffset;
+ top = inputPos.elemTop + inputPos.pageYOffset + inputPos.elemHeight / 2 - inputPos.tooltipHeight / 2;
+ break;
+
+ case TooltipPlacement.Right:
+ left = inputPos.elemLeft + inputPos.elemWidth + inputPos.tooltipOffset;
+ top = inputPos.elemTop + inputPos.pageYOffset + inputPos.elemHeight / 2 - inputPos.tooltipHeight / 2;
+ break;
+
+ case TooltipPlacement.Top:
+ left = inputPos.elemLeft + inputPos.elemWidth / 2 - inputPos.tooltipWidth / 2;
+ top = inputPos.elemTop + inputPos.pageYOffset - inputPos.tooltipHeight - inputPos.tooltipOffset;
+ break;
+
+ case TooltipPlacement.Bottom:
+ left = inputPos.elemLeft + inputPos.elemWidth / 2 - inputPos.tooltipWidth / 2;
+ top = inputPos.elemTop + inputPos.pageYOffset + inputPos.elemHeight + inputPos.tooltipOffset;
+ break;
+ }
+
+ return {
+ height: inputPos.tooltipHeight,
+ left,
+ placement,
+ top,
+ width: inputPos.tooltipWidth,
+ pageYOffset: inputPos.pageYOffset
+ } as IPlacementData;
+ }
+
+ /**
+ * Returns tooltip position data (left / top arrow)
+ * @param {TooltipPlacement} placement (left, top, right, bottom)
+ * @returns {IPlacementData}
+ */
+ private getLeftTopPosition(placement: TooltipPlacement): IPlacementData {
+ let left = 0;
+ let top = 0;
+
+ const inputPos: ITooltipPositionParams = this.getPlacementInputParams();
+ switch (placement) {
+ case TooltipPlacement.Left:
+ left = inputPos.elemLeft - inputPos.tooltipWidth - inputPos.tooltipOffset;
+ top = inputPos.elemTop + inputPos.pageYOffset + inputPos.elemHeight / 2 - inputPos.arrowOffset;
+ break;
+
+ case TooltipPlacement.Right:
+ left = inputPos.elemLeft + inputPos.elemWidth + inputPos.tooltipOffset;
+ top = inputPos.elemTop + inputPos.pageYOffset + inputPos.elemHeight / 2 - inputPos.arrowOffset;
+ break;
+
+ case TooltipPlacement.Top:
+ left = inputPos.elemLeft + inputPos.elemWidth / 2 - inputPos.arrowOffset;
+ top = inputPos.elemTop + inputPos.pageYOffset - inputPos.tooltipHeight - inputPos.tooltipOffset;
+ break;
+
+ case TooltipPlacement.Bottom:
+ left = inputPos.elemLeft + inputPos.elemWidth / 2 - inputPos.arrowOffset;
+ top = inputPos.elemTop + inputPos.pageYOffset + inputPos.elemHeight + inputPos.tooltipOffset;
+ break;
+ }
+
+ return {
+ height: inputPos.tooltipHeight,
+ left,
+ placement,
+ top,
+ width: inputPos.tooltipWidth,
+ pageYOffset: inputPos.pageYOffset
+ } as IPlacementData;
+ }
+
+ /**
+ * Returns tooltip position data (right / bottom arrow)
+ * @param {TooltipPlacement} placement (left, top, right, bottom)
+ * @returns {IPlacementData}
+ */
+ private getRightBottomPosition(placement: TooltipPlacement): IPlacementData {
+ let left = 0;
+ let top = 0;
+
+ const inputPos: ITooltipPositionParams = this.getPlacementInputParams();
+ switch (placement) {
+ case TooltipPlacement.Left:
+ left = inputPos.elemLeft - inputPos.tooltipWidth - inputPos.tooltipOffset;
+ top = inputPos.elemTop + inputPos.pageYOffset + inputPos.elemHeight / 2 - inputPos.tooltipHeight + inputPos.arrowOffset;
+ break;
+
+ case TooltipPlacement.Right:
+ left = inputPos.elemLeft + inputPos.elemWidth + inputPos.tooltipOffset;
+ top = inputPos.elemTop + inputPos.pageYOffset + inputPos.elemHeight / 2 - inputPos.tooltipHeight + inputPos.arrowOffset;
+ break;
+
+ case TooltipPlacement.Top:
+ left = inputPos.elemLeft + inputPos.elemWidth / 2 - inputPos.tooltipWidth + inputPos.arrowOffset;
+ top = inputPos.elemTop + inputPos.pageYOffset - inputPos.tooltipHeight - inputPos.tooltipOffset;
+ break;
+
+ case TooltipPlacement.Bottom:
+ left = inputPos.elemLeft + inputPos.elemWidth / 2 - inputPos.tooltipWidth + inputPos.arrowOffset;
+ top = inputPos.elemTop + inputPos.pageYOffset + inputPos.elemHeight + inputPos.tooltipOffset;
+ break;
+ }
+
+ return {
+ height: inputPos.tooltipHeight,
+ left,
+ placement,
+ top,
+ width: inputPos.tooltipWidth,
+ pageYOffset: inputPos.pageYOffset
+ } as IPlacementData;
+ }
+
+ /**
+ * Checks if tooltip position is valid
+ * @param {IPlacementData} pos
+ * @returns {boolean}
+ */
+ private validatePosition(pos: IPlacementData): boolean {
+ if (pos.left < 0 || pos.left + pos.width - 1 > this.ScreenWidth) {
+ return false;
+ }
+
+ if (pos.top - pos.pageYOffset < 0 || pos.top - pos.pageYOffset + pos.height - 1 > this.ScreenHeight) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Scrolling
+ */
+
+ private debounce(func: Function, wait: number, immediate?: boolean) {
+ let timeout;
+ return function() {
+ const context = this;
+ const args = arguments;
+ const later = () => {
+ timeout = null;
+ if (!immediate) {
+ func.apply(context, args);
+ }
+ };
+ const callNow = immediate && !timeout;
+ clearTimeout(timeout);
+ timeout = setTimeout(later, wait);
+ if (callNow) {
+ func.apply(context, args);
+ }
+ };
+ }
+
+ private initScrollEvent() {
+ this.scrollEventHandler = this.debounce(() => {
+ try {
+ this.setPosition();
+ } catch (e) {
+
+ }
+ }, 10);
+ }
+
+ private activateScrollEvent() {
+ window.addEventListener('scroll', this.scrollEventHandler , true);
+ }
+
+ private deactivateScrollEvent() {
+ window.removeEventListener('scroll', this.scrollEventHandler , true);
+ }
+}
+
+export enum TooltipPlacement {
+ Left,
+ Right,
+ Top,
+ Bottom
+}
+
+export enum ArrowPlacement {
+ CenterMiddle,
+ LeftTop,
+ RightBottom
+}
+
+interface ITooltipPositionParams {
+ elemLeft: number;
+ elemTop: number;
+ elemWidth: number;
+ elemHeight: number;
+ tooltipWidth: number;
+ tooltipHeight: number;
+ tooltipOffset: number;
+ pageYOffset: number;
+ arrowOffset: number;
+}
+
+interface IPlacementData {
+ left: number;
+ top: number;
+ width: number;
+ height: number;
+ pageYOffset: number;
+ placement?: TooltipPlacement;
+}
diff --git a/src/angular/tooltip/tooltip.module.ts b/src/angular/tooltip/tooltip.module.ts
new file mode 100644
index 0000000..a4ad86d
--- /dev/null
+++ b/src/angular/tooltip/tooltip.module.ts
@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { TooltipDirective } from './tooltip.directive';
+import { TooltipTemplateComponent } from './tooltip-template.component';
+
+@NgModule({
+ declarations: [
+ TooltipDirective,
+ TooltipTemplateComponent
+ ],
+ imports: [],
+ entryComponents: [TooltipTemplateComponent],
+ exports: [
+ TooltipDirective
+ ],
+})
+export class TooltipModule {
+}
diff --git a/src/angular/utils/create-dynamic-component.service.ts b/src/angular/utils/create-dynamic-component.service.ts
new file mode 100644
index 0000000..428dd73
--- /dev/null
+++ b/src/angular/utils/create-dynamic-component.service.ts
@@ -0,0 +1,101 @@
+import { Injectable, Type, ApplicationRef, ComponentFactoryResolver, ComponentRef, EmbeddedViewRef, Injector } from '@angular/core';
+import { ViewContainerRef } from '@angular/core/src/linker/view_container_ref';
+
+@Injectable()
+export class CreateDynamicComponentService {
+
+ constructor(private componentFactoryResolver: ComponentFactoryResolver,
+ private applicationRef: ApplicationRef,
+ private injector: Injector) {
+ }
+
+ /**
+ * Gets the root view container to inject the component to.
+ *
+ * @returns {ComponentRef<any>}
+ *
+ * @memberOf InjectionService
+ */
+ private getRootViewContainer(): ComponentRef<any> {
+ const rootComponents = this.applicationRef['_rootComponents']; // Angular2
+ // const rootComponents = this.applicationRef['components']; // Angular5
+ if (rootComponents.length) {
+ return rootComponents[0];
+ }
+ throw new Error('View Container not found! ngUpgrade needs to manually set this via setRootViewContainer.');
+ }
+
+ /**
+ * Gets the html element for a component ref.
+ *
+ * @param {ComponentRef<any>} componentRef
+ * @returns {HTMLElement}
+ *
+ * @memberOf InjectionService
+ */
+ private getComponentRootNode(componentRef: ComponentRef<any>): HTMLElement {
+ return (componentRef.hostView as EmbeddedViewRef<any>).rootNodes[0] as HTMLElement;
+ }
+
+ /**
+ * Gets the root component container html element.
+ *
+ * @returns {HTMLElement}
+ *
+ * @memberOf InjectionService
+ */
+ private getRootViewContainerNode(): HTMLElement {
+ return this.getComponentRootNode(this.getRootViewContainer());
+ }
+
+ /**
+ * Projects the inputs onto the component
+ *
+ * @param {ComponentRef<any>} component
+ * @param {*} options
+ * @returns {ComponentRef<any>}
+ *
+ * @memberOf InjectionService
+ */
+ private projectComponentInputs(component: ComponentRef<any>, options: any): ComponentRef<any> {
+ if (options) {
+ const props = Object.getOwnPropertyNames(options);
+ for (const prop of props) {
+ component.instance[prop] = options[prop];
+ }
+ }
+
+ return component;
+ }
+
+ public createComponentDynamically<T>(componentClass: Type<T>, options: any = {}, location: Element = this.getRootViewContainerNode()): ComponentRef<any> {
+ const componentFactory = this.componentFactoryResolver.resolveComponentFactory(componentClass);
+ const componentRef = componentFactory.create(this.injector);
+ const componentRootNode = this.getComponentRootNode(componentRef);
+
+ // project the options passed to the component instance
+ this.projectComponentInputs(componentRef, options);
+ this.applicationRef.attachView(componentRef.hostView);
+
+ componentRef.onDestroy(() => {
+ this.applicationRef.detachView(componentRef.hostView);
+ });
+
+ location.appendChild(componentRootNode);
+ return componentRef;
+ }
+
+ /**
+ * Inserts a component into an existing viewContainer
+ * @param componentType - type of component to create
+ * @param options - Inputs to project on new component
+ * @param vcRef - viewContainerRef in which to insert the newly created component
+ */
+ public insertComponentDynamically<T>(componentType: Type<T>, options: any = {}, vcRef: ViewContainerRef): ComponentRef<any> {
+ const factory = this.componentFactoryResolver.resolveComponentFactory(componentType);
+ const dynamicComponent = factory.create(vcRef.parentInjector);
+ this.projectComponentInputs(dynamicComponent, options);
+ vcRef.insert(dynamicComponent.hostView);
+ return dynamicComponent;
+ }
+}
diff --git a/src/react/Accordion.js b/src/react/Accordion.js
new file mode 100644
index 0000000..3acdd24
--- /dev/null
+++ b/src/react/Accordion.js
@@ -0,0 +1,40 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import SVGIcon from './SVGIcon.js';
+
+class Accordion extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ open: props.defaultExpanded
+ };
+ }
+ render() {
+ const { children, title, className, dataTestId } = this.props;
+ const { open } = this.state;
+ return (
+ <div className={`sdc-accordion ${className}`}>
+ <div data-test-id={dataTestId} onClick={() => this.setState({ open: !open })} className='sdc-accordion-header'>
+ <SVGIcon name='chevronDown' iconClassName={open ? 'down' : ''} />
+ <div className='title'>{title}</div>
+ </div>
+ <div className={`sdc-accordion-body ${open ? 'open' : ''}`}>{children}</div>
+ </div>
+ );
+ }
+}
+
+Accordion.propTypes = {
+ title: PropTypes.string,
+ children: PropTypes.node,
+ expandByDefault: PropTypes.bool,
+ dataTestId: PropTypes.string
+};
+
+Accordion.defaultProps = {
+ title: '',
+ className: '',
+ defaultExpanded: false
+};
+
+export default Accordion;
diff --git a/src/react/Button.js b/src/react/Button.js
new file mode 100644
index 0000000..c628455
--- /dev/null
+++ b/src/react/Button.js
@@ -0,0 +1,37 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import SVGIcon from './SVGIcon.js';
+
+const Button = ({btnType, size, className, iconName, onClick, disabled, children, ...other}) => (
+ <button
+ onClick={onClick}
+ className={`sdc-button sdc-button__${btnType} ${size && `btn-${size}`} ${className} ${iconName}`}
+ disabled={disabled}
+ {...other}>
+ {
+ iconName ?
+ <SVGIcon name={iconName} label={children} labelPosition='right' />
+ :
+ children
+ }
+ </button>
+);
+
+Button.propTypes = {
+ btnType: PropTypes.string,
+ size: PropTypes.oneOf(['', 'default', 'x-small', 'small', 'medium', 'large']),
+ className: PropTypes.string,
+ iconName: PropTypes.string,
+ onClick: PropTypes.func,
+ disabled: PropTypes.bool
+};
+
+Button.defaultProps = {
+ btnType: 'primary',
+ size: '',
+ className: '',
+ iconName: '',
+ disabled: false
+};
+
+export default Button;
diff --git a/src/react/Checkbox.js b/src/react/Checkbox.js
new file mode 100644
index 0000000..bef6945
--- /dev/null
+++ b/src/react/Checkbox.js
@@ -0,0 +1,45 @@
+import React from 'react';
+
+class Checkbox extends React.Component {
+
+ render() {
+ let {checked = false, disabled, value, label, inputRef, className, name} = this.props;
+ let dataTestId = this.props['data-test-id'];
+
+ return (
+ <div className={`sdc-checkbox ${className || ''}`}>
+ <label>
+ <input
+ className='sdc-checkbox__input'
+ ref={inputRef}
+ data-test-id={dataTestId}
+ type='checkbox'
+ checked={checked}
+ name={name}
+ value={value}
+ onChange={(e) => this.onChange(e)}
+ disabled={disabled} />
+ <span className='sdc-checkbox__label'>{label}</span>
+ </label>
+ </div>
+ );
+ }
+
+ onChange(e) {
+ let {onChange} = this.props;
+ if (onChange) {
+ onChange(e.target.checked);
+ }
+ }
+
+ getChecked() {
+ return this.props.checked;
+ }
+
+ getValue() {
+ return this.props.value;
+ }
+
+}
+
+export default Checkbox;
diff --git a/src/react/Checklist.js b/src/react/Checklist.js
new file mode 100644
index 0000000..1a42aee
--- /dev/null
+++ b/src/react/Checklist.js
@@ -0,0 +1,43 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import Checkbox from './Checkbox.js';
+
+const Checklist = ({ items = [], className, onChange }) => (
+ <div className={className}>
+ {items.map((item, index) => {
+ return (
+ <div key={`checkbox-item-${index}`} className='checkbox-item'>
+ <Checkbox
+ key={`${item.label}${index}`}
+ label={item.label}
+ value={item.value}
+ checked={item.checked}
+ disabled={item.disabled}
+ onChange={value => {
+ let obj = {};
+ obj[item.value] = value;
+ onChange(obj);
+ }}
+ data-test-id={item.dataTestId}
+ />
+ </div>
+ );
+ })}
+ </div>
+);
+
+Checklist.propTypes = {
+ items: PropTypes.arrayOf(
+ PropTypes.shape({
+ label: PropTypes.string,
+ value: PropTypes.string,
+ checked: PropTypes.bool,
+ disabled: PropTypes.bool,
+ dataTestId: PropTypes.string
+ })
+ ),
+ className: PropTypes.string,
+ onChange: PropTypes.func
+};
+
+export default Checklist; \ No newline at end of file
diff --git a/src/react/Input.js b/src/react/Input.js
new file mode 100644
index 0000000..5760637
--- /dev/null
+++ b/src/react/Input.js
@@ -0,0 +1,88 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import SVGIcon from './SVGIcon.js';
+
+class Input extends React.Component {
+
+ render() {
+ let {className, disabled, errorMessage, readOnly, label, name, value, type, placeholder, isRequired} = this.props;
+ let dataTestId = this.props['data-test-id'];
+ let inputClasses = `sdc-input__input ${errorMessage ? 'error' : ''} ${readOnly ? 'view-only' : ''}`;
+ let labelClasses = `sdc-input__label ${readOnly ? 'view-only' : ''} ${isRequired ? 'required' : ''}`;
+
+ return (
+ <div className={`sdc-input ${className || ''}`}>
+
+ <label className={labelClasses} htmlFor={name}>{label}</label>
+ <input className={inputClasses}
+ disabled={disabled}
+ readOnly={readOnly}
+ type={type}
+ id={name}
+ name={name}
+ value={this.props.value}
+ placeholder={placeholder}
+ data-test-id={dataTestId}
+ onBlur={(e) => this.onBlur(e)}
+ onKeyDown={(e) => this.onKeyDown(e)}
+ onChange={(e) => this.onChange(e)}/>
+ { errorMessage && <div className="sdc-label__error">
+ <SVGIcon
+ label={errorMessage}
+ labelPosition='right'
+ color='negative'
+ name='exclamationTriangleFull' />
+ </div>}
+ </div>
+ );
+ }
+
+ onChange(e) {
+ let {onChange, readOnly, disabled} = this.props;
+ if (onChange && !readOnly && !disabled) {
+ onChange(e.target.value);
+ }
+ }
+
+ onBlur(e) {
+ let {onBlur, readOnly} = this.props;
+ if (!readOnly && onBlur) {
+ onBlur(e);
+ }
+ }
+
+ onKeyDown(e) {
+ let {onKeyDown, readOnly} = this.props;
+ if (!readOnly && onKeyDown) {
+ onKeyDown(e);
+ }
+ }
+
+ getValue() {
+ return this.props.value;
+ }
+
+}
+Input.propTypes = {
+ name: PropTypes.string,
+ value: PropTypes.string,
+ type: PropTypes.oneOf(['text', 'number']),
+ placeholder : PropTypes.string,
+ onChange: PropTypes.func,
+ onBlur: PropTypes.func,
+ onKeyDown: PropTypes.func,
+ errorMessage: PropTypes.string,
+ readOnly: PropTypes.bool,
+ isRequired: PropTypes.bool,
+ disabled: PropTypes.bool,
+ label: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
+ className: PropTypes.string
+};
+
+Input.defaultProps = {
+ type: 'text',
+ readOnly: false,
+ isRequired: false,
+ disabled: false
+};
+export default Input;
diff --git a/src/react/Modal.js b/src/react/Modal.js
new file mode 100644
index 0000000..ab2f7d7
--- /dev/null
+++ b/src/react/Modal.js
@@ -0,0 +1,55 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import Portal from './Portal.js';
+import Body from './ModalBody.js';
+import Header from './ModalHeader.js';
+import Footer from './ModalFooter.js';
+import Title from './ModalTitle.js';
+
+export const modalSize = {
+ medium: 'md',
+ large: 'l',
+ extraLarge: 'xl',
+ small: 'sm',
+ extraSmall: 'xsm'
+};
+
+
+class Modal extends React.Component {
+
+ render() {
+ const {size, type, children, show} = this.props;
+ return (
+ <Portal>
+ <div ref={el => { this.modalRef = el;}}>
+ {show && <div className={`sdc-modal ${modalSize[size]}`}>
+ <div className={`sdc-modal__wrapper sdc-modal-type-${type}`}>
+ {children}
+ </div>
+ </div>}
+ {show && <div className='modal-background' />}
+ </div>
+ </Portal>
+ );
+ }
+}
+
+Modal.defaultProps = {
+ show: false,
+ size: 'medium',
+ type: 'info'
+};
+
+Modal.propTypes = {
+ show: PropTypes.bool,
+ size: PropTypes.string,
+ children: PropTypes.node,
+ type: PropTypes.string
+};
+
+Modal.Body = Body;
+Modal.Header = Header;
+Modal.Footer = Footer;
+Modal.Title = Title;
+export default Modal; \ No newline at end of file
diff --git a/src/react/ModalBody.js b/src/react/ModalBody.js
new file mode 100644
index 0000000..4fae0f6
--- /dev/null
+++ b/src/react/ModalBody.js
@@ -0,0 +1,19 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+const ModalBody = ({children, className}) => (
+ <div className={`sdc-modal__content ${className}`} >
+ {children}
+ </div>
+);
+
+ModalBody.propTypes = {
+ children: PropTypes.node,
+ className: PropTypes.string
+};
+
+ModalBody.defaultProps = {
+ className: ''
+};
+
+export default ModalBody; \ No newline at end of file
diff --git a/src/react/ModalFooter.js b/src/react/ModalFooter.js
new file mode 100644
index 0000000..607895d
--- /dev/null
+++ b/src/react/ModalFooter.js
@@ -0,0 +1,36 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import Button from './Button.js';
+
+const Footer = ({onClose, closeButtonText, actionButtonText, actionButtonClick, withButtons, children}) => {
+ const closeBtnType = actionButtonClick ? 'secondary' : 'primary';
+ return (
+ <div className='sdc-modal__footer'>
+ {children}
+ {
+ withButtons && <div>
+ {actionButtonClick &&
+ <Button onClick={actionButtonClick}>{actionButtonText}</Button>
+ }
+ <Button btnType={closeBtnType} onClick={onClose}>{closeButtonText}</Button>
+ </div>
+ }
+ </div>
+ );
+};
+
+Footer.propTypes = {
+ onClose: PropTypes.func,
+ closeButtonText: PropTypes.string,
+ actionButtonText: PropTypes.string,
+ actionButtonClick: PropTypes.func,
+ withButtons: PropTypes.bool,
+ children: PropTypes.node
+};
+
+Footer.defaultProps = {
+ closeButtonText: 'Close',
+ withButtons: true
+};
+
+export default Footer; \ No newline at end of file
diff --git a/src/react/ModalHeader.js b/src/react/ModalHeader.js
new file mode 100644
index 0000000..c6be5ef
--- /dev/null
+++ b/src/react/ModalHeader.js
@@ -0,0 +1,41 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import SVGIcon from './SVGIcon.js';
+
+const iconMaper = {
+ error: 'error',
+ info: 'errorCircle',
+ alert: 'exclamationTriangleLine'
+};
+
+const headerTypes = {
+ error: 'sdc-error__header',
+ info: 'sdc-info__header',
+ alert: 'sdc-alert__header',
+ custom: 'sdc-custom__header'
+}
+
+
+
+const Header = ({children, onClose, type}) => (
+ <div className={ headerTypes[type] + ' sdc-modal__header'} >
+ {type !== 'custom'
+ &&
+ <SVGIcon iconClassName='sdc-modal__icon' className='sdc-modal__svg-use' name={iconMaper[type]}/>
+
+ }
+ {children}
+ <SVGIcon iconClassName ='sdc-modal__close-button-svg' className='sdc-modal__close-button' onClick={onClose} name='close'/>
+ </div>
+);
+
+Header.propTypes = {
+ children: PropTypes.node,
+ onClose: PropTypes.func
+};
+
+Header.defaultProps = {
+ type: 'info'
+};
+
+export default Header; \ No newline at end of file
diff --git a/src/react/ModalTitle.js b/src/react/ModalTitle.js
new file mode 100644
index 0000000..b48cc8a
--- /dev/null
+++ b/src/react/ModalTitle.js
@@ -0,0 +1,19 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+const Title = ({children, className}) => (
+ <div className={`title ${className}`} >
+ {children}
+ </div>
+);
+
+Title.PropTypes = {
+ children: PropTypes.node,
+ className: PropTypes.string
+};
+
+Title.defaultProps = {
+ className: ''
+};
+
+export default Title; \ No newline at end of file
diff --git a/src/react/Panel.js b/src/react/Panel.js
new file mode 100644
index 0000000..34d2e62
--- /dev/null
+++ b/src/react/Panel.js
@@ -0,0 +1,18 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+const Panel = ({ className, children }) => (
+ <div className={`sdc-panel ${className}`}>
+ {children}
+ </div>
+);
+
+Panel.propTypes = {
+ className: PropTypes.string,
+ children: PropTypes.node
+};
+
+Panel.defaultProps = {
+ className: ''
+};
+export default Panel; \ No newline at end of file
diff --git a/src/react/PopupMenu.js b/src/react/PopupMenu.js
new file mode 100644
index 0000000..d2cd29a
--- /dev/null
+++ b/src/react/PopupMenu.js
@@ -0,0 +1,39 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import PopupMenuItem from './PopupMenuItem';
+
+class PopupMenu extends React.Component {
+ render() {
+ const {children = [], onMenuItemClick, position = {}, relative} = this.props;
+ const style = relative ? {left: position.x, top: position.y} : {};
+
+ return (
+ <ul className={`sdc-menu-list ${relative ? 'relative' : ''}`} style={style}>
+ {React.Children.toArray(children).map((child, i) => React.cloneElement(child,
+ {
+ onClick: child.props.onClick || onMenuItemClick,
+ key: i
+ }))}
+ </ul>
+ );
+ }
+}
+
+PopupMenu.propTypes = {
+ relative: PropTypes.bool,
+ position: PropTypes.shape({
+ x: PropTypes.number,
+ y: PropTypes.number
+ }),
+ onMenuItemClick: PropTypes.func
+};
+
+PopupMenu.defaultProps = {
+ relative: false
+};
+
+export const PopupMenuSeparator = () => <li className='separator' />;
+
+PopupMenu.Separator = PopupMenuSeparator;
+PopupMenu.Item = PopupMenuItem;
+export default PopupMenu;
diff --git a/src/react/PopupMenuItem.js b/src/react/PopupMenuItem.js
new file mode 100644
index 0000000..98e3f49
--- /dev/null
+++ b/src/react/PopupMenuItem.js
@@ -0,0 +1,34 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+class PopupMenuItem extends React.Component {
+ render() {
+ const {itemId, value, onClick, selected, disabled} = this.props;
+ const additionalClasses = selected ? 'selected' : disabled ? 'disabled' : '';
+ return (
+ <li
+ className={`sdc-menu-item ${additionalClasses}`}
+ onClick={event => {
+ event.stopPropagation();
+ onClick && !disabled && onClick(itemId);
+ }}>
+ {value}
+ </li>
+ );
+ }
+}
+
+PopupMenuItem.propTypes = {
+ itemId: PropTypes.any,
+ value: PropTypes.any,
+ selected: PropTypes.bool,
+ onClick: PropTypes.func,
+ disabled: PropTypes.bool
+};
+
+PopupMenuItem.defaultProps = {
+ selected: false,
+ disabled: false
+};
+
+export default PopupMenuItem;
diff --git a/src/react/Portal.js b/src/react/Portal.js
new file mode 100644
index 0000000..90e0675
--- /dev/null
+++ b/src/react/Portal.js
@@ -0,0 +1,52 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import ReactDOM from 'react-dom';
+
+class Portal extends React.Component {
+ componentDidMount() {
+ this.renderPortal();
+ }
+
+ componentDidUpdate() {
+ this.renderPortal();
+ }
+
+ componentWillUnmount() {
+ if (this.defaultNode) {
+ document.body.removeChild(this.defaultNode);
+ }
+ this.defaultNode = null;
+ this.portal = null;
+ }
+
+ renderPortal() {
+ if (!this.defaultNode) {
+ this.defaultNode = document.createElement('div');
+ this.defaultNode.className = 'onap-sdc-portal';
+ document.body.appendChild(this.defaultNode);
+ }
+
+ let children = this.props.children;
+ if (typeof this.props.children.type === 'function') {
+ children = React.cloneElement(this.props.children);
+ }
+ /**
+ * Change this to ReactDOM.CreatePortal after upgrading to React 16
+ */
+ this.portal = ReactDOM.unstable_renderSubtreeIntoContainer(
+ this,
+ children,
+ this.defaultNode
+ );
+ }
+ render() {
+ return null;
+ }
+
+}
+
+Portal.propTypes = {
+ children: PropTypes.node.isRequired
+};
+
+export default Portal; \ No newline at end of file
diff --git a/src/react/Radio.js b/src/react/Radio.js
new file mode 100644
index 0000000..483521a
--- /dev/null
+++ b/src/react/Radio.js
@@ -0,0 +1,58 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+class Radio extends React.Component {
+ render() {
+ let {checked, disabled, value, label, className, inputRef, name} = this.props;
+ let dataTestId = this.props['data-test-id'];
+ return (
+ <div className={`sdc-radio ${className}`}>
+ <label>
+ <input
+ ref={inputRef}
+ className='sdc-radio__input'
+ value={value}
+ data-test-id={dataTestId}
+ type='radio'
+ name={name}
+ checked={checked}
+ onChange={(e) => this.onChange(e)}
+ disabled={disabled} />
+ <span className='sdc-radio__label'>{label}</span>
+ </label>
+ </div>
+ );
+ }
+
+ onChange(e) {
+ let {onChange} = this.props;
+ if (onChange) {
+ onChange(e.target.checked);
+ }
+ }
+
+ getChecked() {
+ return this.props.checked;
+ }
+
+ getValue() {
+ return this.props.value;
+ }
+}
+
+Radio.propTypes = {
+ checked: PropTypes.bool,
+ value: PropTypes.any,
+ label: PropTypes.string,
+ className: PropTypes.string,
+ inputRef: PropTypes.func,
+ name: PropTypes.string,
+ disabled: PropTypes.bool
+};
+
+Radio.defaultProps = {
+ checked: false,
+ className: ''
+};
+
+export default Radio;
diff --git a/src/react/RadioGroup.js b/src/react/RadioGroup.js
new file mode 100644
index 0000000..59eaca7
--- /dev/null
+++ b/src/react/RadioGroup.js
@@ -0,0 +1,40 @@
+import React from 'react';
+import Radio from './Radio.js';
+
+class RadioGroup extends React.Component {
+ constructor(props) {
+ super(props);
+ this.radios = {};
+ }
+
+ render() {
+ let {name, disabled, title, options, value, className} = this.props;
+ let dataTestId = this.props['data-test-id'];
+ return (<div data-test-id={dataTestId} className={`sdc-radio-group ${className || ''}`}>
+ { title && <label className='sdc-radio-group__legend'>{title}</label> }
+ <div className='sdc-radio-group__radios'>
+ {options.map(option => {
+ let rName = name + '_' + option.value;
+ return (<Radio ref={(radio) => {this.radios[rName] = radio;}} data-test-id={dataTestId + '_' + option.value}
+ key={rName} value={option.value}
+ label={option.label} checked={value === option.value} disabled={disabled}
+ name={name} onChange={() => this.onChange(rName)} />
+ );})}
+ </div>
+ </div>);
+ }
+
+ onChange(rName) {
+ let {onChange} = this.props;
+ let val = this.radios[rName].getValue();
+ if (onChange) {
+ onChange(val);
+ }
+ }
+
+ getValue() {
+ return this.props.value;
+ }
+}
+
+export default RadioGroup;
diff --git a/src/react/SVGIcon.js b/src/react/SVGIcon.js
new file mode 100644
index 0000000..8a5b1ae
--- /dev/null
+++ b/src/react/SVGIcon.js
@@ -0,0 +1,47 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import iconMap from './utils/iconMap.js';
+
+const SVGIcon = ({name, onClick, label, className, iconClassName, labelClassName, labelPosition, color, disabled, ...other}) => {
+
+ let colorClass = (color !== '') ? '__' + color : '';
+ let classes = `svg-icon-wrapper ${iconClassName} ${className} ${colorClass} ${onClick ? 'clickable' : ''} ${labelPosition}`;
+ let camelCasedName = name.replace(/-([a-z])/g, function (g) { return g[1].toUpperCase(); });
+ let IconComponent = iconMap[camelCasedName];
+ if (!IconComponent) {
+ console.error('Icon by the name ' + camelCasedName + ' is missing.');
+ }
+
+ return (
+ <div {...other} onClick={onClick} className={classes} disabled={disabled}>
+ { IconComponent && <IconComponent className={`svg-icon __${name}`} /> }
+ { !IconComponent && <span className='svg-icon-missing'>Missing Icon</span> }
+ {label && <span className={`svg-icon-label ${labelClassName}`}>{label}</span>}
+ </div>
+ );
+
+};
+
+SVGIcon.propTypes = {
+ name: PropTypes.string.isRequired,
+ onClick: PropTypes.func,
+ label: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
+ labelPosition: PropTypes.string,
+ className: PropTypes.string,
+ iconClassName: PropTypes.string,
+ labelClassName: PropTypes.string,
+ color: PropTypes.string
+};
+
+SVGIcon.defaultProps = {
+ name: '',
+ label: '',
+ className: '',
+ iconClassName: '',
+ labelClassName: '',
+ labelPosition: 'bottom',
+ color: ''
+};
+
+export default SVGIcon;
diff --git a/src/react/Tab.js b/src/react/Tab.js
new file mode 100644
index 0000000..5aa0f16
--- /dev/null
+++ b/src/react/Tab.js
@@ -0,0 +1,20 @@
+import React from 'react';
+
+class Tab extends React.Component {
+ render() {
+ const {activeTab, tabId, title, onClick, disabled, className = ''} = this.props;
+ const dataTestId = this.props['data-test-id'];
+ return (
+ <li
+ className={`sdc-tab ${activeTab === tabId ? 'sdc-tab-active' : ''} ${className}`}
+ onClick={!disabled && onClick}
+ data-test-id={dataTestId}
+ role='tab'
+ disabled={disabled}>
+ {title}
+ </li>
+ );
+ }
+}
+
+export default Tab;
diff --git a/src/react/TabPane.js b/src/react/TabPane.js
new file mode 100644
index 0000000..56a4bf0
--- /dev/null
+++ b/src/react/TabPane.js
@@ -0,0 +1,12 @@
+import React from 'react';
+
+class TabPane extends React.Component {
+ render() {
+ const {children} = this.props;
+ return (<div className='sdc-tab-content' role='tabpanel'>
+ {children}
+ </div>);
+ }
+}
+
+export default TabPane;
diff --git a/src/react/Tabs.js b/src/react/Tabs.js
new file mode 100644
index 0000000..c502038
--- /dev/null
+++ b/src/react/Tabs.js
@@ -0,0 +1,29 @@
+import React from 'react';
+import TabPane from './TabPane.js';
+
+class Tabs extends React.Component {
+ render() {
+ const {type, children = [], activeTab, onTabClick, className} = this.props;
+ return (
+ <div className={type === 'header' ? `sdc-tabs sdc-tabs-header ${className || ''}` : `sdc-tabs sdc-tabs-menu ${className || ''}`} >
+ <ul className='sdc-tabs-list' role='tablist'>
+ {children.map(child => React.cloneElement(child,
+ {
+ key: child.props.tabId,
+ onClick: () => onTabClick(child.props.tabId),
+ activeTab
+ }))}
+ </ul>
+ <TabPane>
+ {children.map(child => {
+ if (child.props.tabId === activeTab) {
+ return child.props.children;
+ }
+ })}
+ </TabPane>
+ </div>
+ );
+ }
+}
+
+export default Tabs;
diff --git a/src/react/Tile.js b/src/react/Tile.js
new file mode 100644
index 0000000..f47f88d
--- /dev/null
+++ b/src/react/Tile.js
@@ -0,0 +1,33 @@
+import React, {Children} from 'react';
+import PropTypes from 'prop-types';
+import TileInfo from './TileInfo.js';
+import TileFooter from './TileFooter.js';
+import SVGIcon from './SVGIcon.js';
+
+const Tile = ({headerText, headerColor, iconName, iconColor, className, onClick, children, dataTestId}) => {
+ let childrenArr = Children.toArray(children);
+ return (
+ <div className={`sdc-tile ${className || ''}`} onClick={onClick} data-test-id={dataTestId}>
+ <div className={`sdc-tile-header ${headerColor || ''}`}>{headerText}</div>
+ <div className='sdc-tile-content'>
+ <div className={`sdc-tile-content-icon ${iconColor || ''}`}>
+ {iconName && <SVGIcon name={iconName}/>}
+ </div>
+ {childrenArr.find(e => e.type === TileInfo)}
+ </div>
+ {childrenArr.find(e => e.type === TileFooter)}
+ </div>
+ );
+};
+
+Tile.propTypes = {
+ headerText: PropTypes.string,
+ headerColor: PropTypes.string,
+ iconName: PropTypes.string,
+ iconColor: PropTypes.string,
+ className: PropTypes.string,
+ onClick: PropTypes.func,
+ dataTestId: PropTypes.string
+};
+
+export default Tile;
diff --git a/src/react/TileFooter.js b/src/react/TileFooter.js
new file mode 100644
index 0000000..3a56908
--- /dev/null
+++ b/src/react/TileFooter.js
@@ -0,0 +1,10 @@
+import React, {Children} from 'react';
+import TileFooterCell from './TileFooterCell.js';
+
+const TileFooter = ({children, align}) => (
+ <div className={`sdc-tile-footer ${align === 'center' ? 'centered' : ''}`}>
+ {Children.toArray(children).filter(e => e.type === TileFooterCell)}
+ </div>
+);
+
+export default TileFooter;
diff --git a/src/react/TileFooterCell.js b/src/react/TileFooterCell.js
new file mode 100644
index 0000000..37e6416
--- /dev/null
+++ b/src/react/TileFooterCell.js
@@ -0,0 +1,7 @@
+import React from 'react';
+
+const TileFooterCell = ({className, children, dataTestId}) => (
+ <span className={`sdc-tile-footer-cell ${className || ''}`} data-test-id={dataTestId}>{children}</span>
+);
+
+export default TileFooterCell;
diff --git a/src/react/TileInfo.js b/src/react/TileInfo.js
new file mode 100644
index 0000000..bda8e74
--- /dev/null
+++ b/src/react/TileInfo.js
@@ -0,0 +1,10 @@
+import React, {Children} from 'react';
+import TileInfoLine from './TileInfoLine.js';
+
+const TileInfo = ({align, children}) => (
+ <div className={`sdc-tile-content-info ${align === 'center' ? 'centered' : ''}`}>
+ {Children.toArray(children).filter(e => e.type === TileInfoLine)}
+ </div>
+);
+
+export default TileInfo;
diff --git a/src/react/TileInfoLine.js b/src/react/TileInfoLine.js
new file mode 100644
index 0000000..5b0e2c9
--- /dev/null
+++ b/src/react/TileInfoLine.js
@@ -0,0 +1,7 @@
+import React from 'react';
+
+const TileInfoLine = ({type, className, children, dataTestId}) => (
+ <div className={`sdc-tile-info-line ${type || ''} ${className || ''}`} data-test-id={dataTestId}>{children}</div>
+);
+
+export default TileInfoLine;
diff --git a/src/react/index.js b/src/react/index.js
new file mode 100644
index 0000000..cbe0161
--- /dev/null
+++ b/src/react/index.js
@@ -0,0 +1,74 @@
+import Accordion from './Accordion.js';
+import Button from './Button.js';
+import Checkbox from './Checkbox.js';
+import Checklist from './Checklist.js';
+import Input from './Input.js';
+import Modal from './Modal.js';
+import ModalBody from './ModalBody.js';
+import ModalFooter from './ModalFooter.js';
+import ModalHeader from './ModalHeader.js';
+import ModalTitle from './ModalTitle.js';
+import Panel from './Panel.js';
+import PopupMenu from './PopupMenu.js';
+import Portal from './Portal.js';
+import Radio from './Radio.js';
+import RadioGroup from './RadioGroup.js';
+import SVGIcon from './SVGIcon.js';
+import Tab from './Tab.js';
+import Tabs from './Tabs.js';
+import Tile from './Tile.js';
+import TileInfo from './TileInfo.js';
+import TileInfoLine from './TileInfoLine.js';
+import TileFooter from './TileFooter.js';
+import TileFooterCell from './TileFooterCell.js';
+
+
+export { Accordion };
+export { Button };
+export { Checkbox };
+export { Checklist };
+export { Input };
+export { Modal };
+export { ModalBody };
+export { ModalFooter };
+export { ModalHeader };
+export { ModalTitle };
+export { Panel };
+export { PopupMenu };
+export { Portal };
+export { Radio };
+export { RadioGroup };
+export { SVGIcon };
+export { Tab };
+export { Tabs };
+export { Tile };
+export { TileInfo };
+export { TileInfoLine };
+export { TileFooter };
+export { TileFooterCell };
+
+export default {
+ Accordion,
+ Button,
+ Checkbox,
+ Checklist,
+ Input,
+ Modal,
+ ModalBody,
+ ModalFooter,
+ ModalHeader,
+ ModalTitle,
+ Panel,
+ PopupMenu,
+ Portal,
+ Radio,
+ RadioGroup,
+ SVGIcon,
+ Tab,
+ Tabs,
+ Tile,
+ TileInfo,
+ TileInfoLine,
+ TileFooter,
+ TileFooterCell
+};
diff --git a/src/style/scss/_common.scss b/src/style/scss/_common.scss
new file mode 100644
index 0000000..7daac20
--- /dev/null
+++ b/src/style/scss/_common.scss
@@ -0,0 +1,7 @@
+@import "common/normalize";
+@import "common/variables";
+@import "common/mixins";
+@import "common/typography";
+@import "common/base";
+@import "common/icons";
+@import "common/animation";
diff --git a/src/style/scss/_components.scss b/src/style/scss/_components.scss
new file mode 100644
index 0000000..3b0d28d
--- /dev/null
+++ b/src/style/scss/_components.scss
@@ -0,0 +1,22 @@
+@import "../../../components/button/button";
+@import "../../../components/tile/tile";
+@import "../../../components/checkbox/checkbox";
+@import "../../../components/radio/radio";
+@import "../../../components/radioGroup/radioGroup";
+@import "../../../components/tabs/tabs";
+@import "../../../components/icon/icon";
+@import "../../../components/input/input";
+@import "../../../components/dropdown/dropdown";
+@import "../../../components/modal/modal";
+@import "../../../components/menu/menu";
+@import "../../../components/filter-bar/_filter-bar";
+@import "../../../components/search-bar/_search-bar";
+@import "../../../components/checklist/checklist";
+@import "../../../components/autocomplete/autocomplete";
+@import "../../../components/tooltip/tooltip";
+@import "../../../components/tag-cloud/_tag-cloud";
+@import "../../../components/notification/notification";
+@import "../../../components/notifications-container/notifications-container";
+@import "../../../components/accordion/accordion";
+@import "../../../components/panel/panel";
+@import "../../../components/validation/validation";
diff --git a/src/style/scss/angular/_svg_icon.scss b/src/style/scss/angular/_svg_icon.scss
new file mode 100644
index 0000000..16be14b
--- /dev/null
+++ b/src/style/scss/angular/_svg_icon.scss
@@ -0,0 +1,210 @@
+@mixin color-icon($primary-color) {
+ color: $primary-color;
+ fill: $primary-color;
+}
+
+@mixin color-icon-hover($secondary-color) {
+ &.clickable {
+ &:not([disabled]):hover, &:active, &:focus {
+ @include color-icon($secondary-color);
+ }
+ }
+}
+
+@mixin color-icon-label($primary-color) {
+ @include color-icon($primary-color);
+
+ .svg-icon {
+ @include color-icon($primary-color);
+ }
+}
+
+@mixin color-icon-label-hover($secondary-color) {
+ &.clickable {
+ &:not([disabled]):hover, &:active, &:focus {
+ @include color-icon-label($secondary-color);
+ }
+ }
+}
+
+.svg-icon {
+ display: inline-flex;
+ width: 24px;
+ height: 24px;
+
+ & > svg {
+ width: 100%;
+ height: 100%;
+ }
+
+ &[disabled] {
+ opacity: 0.7;
+ }
+
+ &.mode-primary {
+ @include color-icon($blue);
+ @include color-icon-hover($light-blue);
+ }
+
+ &.mode-secondary {
+ @include color-icon($gray);
+ @include color-icon-hover($dark-gray);
+ }
+
+ &.mode-success {
+ @include color-icon($green);
+ }
+
+ &.mode-error {
+ @include color-icon($red);
+ }
+
+ &.mode-warning {
+ @include color-icon($yellow);
+ }
+
+ &.mode-info {
+ @include color-icon($text-black);
+ @include color-icon-hover($dark-blue);
+ }
+
+ &.size-x_small {
+ width: 12px;
+ height: 12px;
+ }
+
+ &.size-small {
+ width: 16px;
+ height: 16px;
+ }
+
+ &.size-medium {
+ width: 24px;
+ height: 24px;
+ }
+
+ &.size-large {
+ width: 36px;
+ height: 36px;
+ }
+
+ &.size-x_large {
+ width: 48px;
+ height: 48px;
+ }
+}
+
+.svg-icon-wrapper {
+ display: inline-flex;
+ justify-content: center;
+ align-items: center;
+
+ &.svg-icon-label {
+ }
+
+ &.svg-icon {
+ }
+
+ &[disabled] {
+ opacity: 0.7;
+ }
+
+ &.label-placement-bottom {
+ flex-direction: column;
+ .svg-icon-label {
+ margin-top: 0.25em;
+ }
+ }
+
+ &.label-placement-right {
+ .svg-icon-label {
+ margin-left: 0.25em;
+ }
+ }
+
+ &.label-placement-top {
+ flex-direction: column-reverse;
+ .svg-icon-label {
+ margin-bottom: 0.25em;
+ }
+ }
+
+ &.label-placement-left {
+ flex-direction: row-reverse;
+ .svg-icon-label {
+ margin-right: 0.25em;
+ }
+ }
+
+ &.mode-primary {
+ @include color-icon-label($blue);
+ @include color-icon-label-hover($light-blue);
+ }
+
+ &.mode-secondary {
+ @include color-icon-label($gray);
+ @include color-icon-label-hover($dark-gray);
+ }
+
+ &.mode-success {
+ @include color-icon-label($green);
+ }
+
+ &.mode-error {
+ @include color-icon-label($red);
+ }
+
+ &.mode-warning {
+ @include color-icon-label($yellow);
+ }
+
+ &.mode-info {
+ @include color-icon-label($text-black);
+ @include color-icon-label-hover($dark-blue);
+ }
+
+ &.size-x_small {
+ font-size: 8px;
+ line-height: 10px;
+
+ .svg-icon {
+ @extend .svg-icon.size-x_small;
+ }
+ }
+
+ &.size-small {
+ font-size: 12px;
+ line-height: 14px;
+
+ .svg-icon {
+ @extend .svg-icon.size-small;
+ }
+ }
+
+ &.size-medium {
+ font-size: 16px;
+ line-height: 20px;
+
+ .svg-icon {
+ @extend .svg-icon.size-medium;
+ }
+ }
+
+ &.size-large {
+ font-size: 24px;
+ line-height: 28px;
+
+ .svg-icon {
+ @extend .svg-icon.size-large;
+ }
+ }
+
+ &.size-x_large {
+ font-size: 34px;
+ line-height: 40px;
+
+ .svg-icon {
+ @extend .svg-icon.size-x_large;
+ }
+ }
+}
diff --git a/src/style/scss/angular/_tooltip_custom_style.scss b/src/style/scss/angular/_tooltip_custom_style.scss
new file mode 100644
index 0000000..886b1dc
--- /dev/null
+++ b/src/style/scss/angular/_tooltip_custom_style.scss
@@ -0,0 +1,9 @@
+.sdc-custom-tooltip {
+ background-color: $dark-blue;
+ border-color: $dark-blue;
+ border-radius: 10px;
+
+ &:after {
+ border-color: $dark-blue transparent transparent transparent;
+ }
+}
diff --git a/src/style/scss/common/_animation.scss b/src/style/scss/common/_animation.scss
new file mode 100644
index 0000000..659bd3b
--- /dev/null
+++ b/src/style/scss/common/_animation.scss
@@ -0,0 +1,149 @@
+/***********************************************************************************
+ VERTICAL COLLAPSE-EXPEND TRANSITION ANIMATION PAIR.
+
+ We use the 'transition-vertical-collapse' for the collapse/idle block element,
+ and the 'transition-vertical-expand' to expend that element.
+
+ -important: The element that will be used for the animation should be
+ a block element, adn have a content or width and height settings for it to work.
+*********************************************************************************/
+
+/**
+Enable to fold an expended block element
+@param $offsetY - The top position from which the drop down should fold
+ */
+@mixin keyframes-expand-animation($name, $maxHeight, $boxShadow:0 0 12px 0px rgba(0,0,0,.3), $margin:0){
+ @keyframes #{$name} {
+ 0% {
+ opacity: 0;
+ max-height: 0;
+ overflow: hidden;
+ box-shadow: 0 0 0px 0px rgba(0,0,0,.3);
+ margin:0;
+ }
+ 10% {
+ opacity: 1;
+ margin: $margin;
+ }
+ 50% {
+ box-shadow: $boxShadow;
+ }
+ 99%{
+ max-height:$maxHeight;
+
+ overflow: hidden;
+ }
+ 100%{
+ opacity: 1;
+ max-height:$maxHeight;
+ overflow: auto;
+ }
+ }
+}
+
+/**
+Enable to expend a folded block element
+@param $maxHeight - most of the animation is done over the max-height property
+ so we have to set the maximum height the expended element can expend to.
+ */
+@mixin keyframes-collapse-animation($name, $maxHeight, $boxShadow:0 0 12px 0px rgba(0,0,0,.3)){
+ @keyframes #{$name} {
+ 0% {
+ opacity: 1;
+ max-height:$maxHeight;
+ box-shadow: $boxShadow;
+ overflow: hidden;
+ }
+ 40%{
+ opacity: 1;
+ }
+ 99%{
+ opacity: 0;
+ max-height: 0;
+ overflow: hidden;
+ box-shadow: 0 0 0px 0px rgba(0,0,0,.3);
+ }
+ 100%{
+ opacity: 0;
+ max-height: 0;
+ overflow: auto;
+ }
+ }
+}
+
+/********************************************************************************
+ SIMPLE FADE-IN KEYFRAMES ANIMATION (Used in tooltip for example)
+
+ we use 'mixin-keyframes-fade-in-vertically' to create css @keyframes rule that
+ we later can use with animation property inside our prefered css rules:
+ .our_class {
+ ...
+ animation: keyframes-fade-in-vertically 1s ease-out;
+ ...
+ }
+*********************************************************************************/
+@mixin mixin-keyframes-fade-in-vertically($fromRelativeHeight, $keyframesName:keyframes-fade-in-vertically){
+ @keyframes #{$keyframesName} {
+ from {
+ transform: translateY($fromRelativeHeight);
+ opacity: 0;
+ }
+ to {
+ transform: translateY(0);
+ opacity: 1;
+ }
+ }
+}
+
+/********************************************************************************
+ SIMPLE FADE-OUT KEYFRAMES ANIMATION (Opposite of fade-in mixin above)
+*********************************************************************************/
+@mixin mixin-keyframes-fade-out-vertically($toRelativeHeight, $keyframesName:keyframes-fade-out-vertically){
+ @keyframes #{$keyframesName} {
+ from {
+ transform: translateY(0);
+ opacity: 1;
+ }
+ to {
+ transform: translateY($toRelativeHeight);
+ opacity: 0;
+ }
+ }
+}
+
+
+
+/********************************************************************************
+ RIPPLE ANIMATION (Used for ripple-click directive)
+*********************************************************************************/
+@keyframes ripple-animation {
+ from {
+ transform: scale(0,0);
+ opacity: 1;
+ }
+ to {
+ transform: scale(2,2);
+ opacity: 0;
+ }
+}
+
+.sdc-ripple-click__animated {
+ position:relative;
+}
+.sdc-ripple-click__animated::before{
+ display: inline-block;
+ position:absolute;
+ top: 0;
+ left: 0;
+ content: '';
+ animation: ripple-animation .3s ease-out;
+ background-color: $blue;
+ width: 14px;
+ height: 14px;
+ border-radius: 50%;
+ pointer-events: none;
+ opacity: 0;
+}
+
+
+
diff --git a/src/style/scss/common/_icons.scss b/src/style/scss/common/_icons.scss
new file mode 100644
index 0000000..00f425d
--- /dev/null
+++ b/src/style/scss/common/_icons.scss
@@ -0,0 +1,19 @@
+.sdc-icon {
+ display: inline-block;
+ text-rendering: auto;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ width: 16px;
+ height: 16px;
+}
+
+.sdc-icon-locked {background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='11' height='15' viewBox='0 0 11 15' id='locked_icon'> <metadata><?xpacket begin='' id='W5M0MpCehiHzreSzNTczkc9d'?><x:xmpmeta xmlns:x='adobe:ns:meta/' x:xmptk='Adobe XMP Core 5.6-c138 79.159824, 2016/09/14-01:09:01 '> <rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'> <rdf:Description rdf:about=''/> </rdf:RDF></x:xmpmeta><?xpacket end='w'?></metadata><defs> <style> .cls-1 { fill: #959595; fill-rule: evenodd; } </style> </defs> <path id='Shape_77_copy_10' data-name='Shape 77 copy 10' class='cls-1' d='M445,359a16.71,16.71,0,0,0-2.1-.009c-1.945.045-3.195,0.049-3.9,0.009v-5a1.743,1.743,0,0,1,2-2h1a1.743,1.743,0,0,1,2,2v5c0.474,0.063.343-.073,1,0,0.266,0.029,0,.279,0,0v-5a2.726,2.726,0,0,0-3-3h-1.142c-1.72-.125-2.715,1.562-2.858,3,0.088,0.009,0,7.338,0,5h0a1.891,1.891,0,0,0-2,1.689v3.461A1.823,1.823,0,0,0,437.775,366h7.448A1.823,1.823,0,0,0,447,364.15v-3.461A2.018,2.018,0,0,0,445,359Z' transform='translate(-436 -351)'/></svg>"); background-repeat: no-repeat;}
+.sdc-icon-plus {background-image: url("data:image/svg+xml;utf8,<?xml version='1.0' encoding='utf-8'?><!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --><svg version='1.1' id='plus_icon' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 19 19' style='enable-background:new 0 0 19 19;' xml:space='preserve'><g><rect y='8' width='19' height='3'/><path id='Rectangle_2139_copy' d='M8,19V0h3v19H8z'/></g></svg>"); background-repeat: no-repeat;}
+.sdc-icon-unlocked {background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='11' height='18' viewBox='0 0 11 18' id='unlocked_icon'> <metadata><?xpacket begin='' id='W5M0MpCehiHzreSzNTczkc9d'?><x:xmpmeta xmlns:x='adobe:ns:meta/' x:xmptk='Adobe XMP Core 5.6-c138 79.159824, 2016/09/14-01:09:01 '> <rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'> <rdf:Description rdf:about=''/> </rdf:RDF></x:xmpmeta><?xpacket end='w'?></metadata><defs> <style> .cls-1 { fill: #959595; fill-rule: evenodd; } </style> </defs> <path id='Shape_77_copy_16' data-name='Shape 77 copy 16' class='cls-1' d='M663,358a16.723,16.723,0,0,0-2.1-.009c-1.944.045-3.194,0.049-3.9,0.009v-7a1.743,1.743,0,0,1,2-2h1a1.743,1.743,0,0,1,2,2v2c0.474,0.064.343-.073,1,0,0.266,0.029,0,.279,0,0v-2a2.726,2.726,0,0,0-3-3h-1.142c-1.72-.125-2.715,1.562-2.858,3,0.088,0.009,0,9.338,0,7h0a1.891,1.891,0,0,0-2,1.689v4.461a1.823,1.823,0,0,0,1.775,1.85h7.448A1.823,1.823,0,0,0,665,364.15v-4.461A2.018,2.018,0,0,0,663,358Zm1.05,6.15a0.827,0.827,0,0,1-.8.836H655.8a0.827,0.827,0,0,1-.8-0.836l0-4.15a1.164,1.164,0,0,1,.8-1.147h7.448A1.129,1.129,0,0,1,664,360Z' transform='translate(-654 -348)'/></svg>"); background-repeat: no-repeat;}
+.sdc-icon-vendor {background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 53 47' id='vendor_icon'><title>vendor</title><g id='Layer_2' data-name='Layer 2'><g id='vlm_icon' data-name='vlm icon'><path d='M49,7,38.5,7V5.92A5.92,5.92,0,0,0,32.58,0H20.42A5.92,5.92,0,0,0,14.5,5.92V7.15L4,7.2a3.8,3.8,0,0,0-4,3.5V43.5C0,45.4,2,47,4.2,47L49,46.8a3.8,3.8,0,0,0,4-3.5V10.5A3.8,3.8,0,0,0,49,7ZM16.5,5.92A3.92,3.92,0,0,1,20.42,2H32.58A3.92,3.92,0,0,1,36.5,5.92V7.06l-20,.09ZM2,10.8A1.9,1.9,0,0,1,4,9l45-.2a1.9,1.9,0,0,1,2,1.8v8.87L32.94,24.18a6.49,6.49,0,0,0-12.89,0L2,19.51V10.8ZM31,25a4.5,4.5,0,1,1-4.5-4.5A4.5,4.5,0,0,1,31,25ZM49,45,4,45.2A1.9,1.9,0,0,1,2,43.4V21.57l18.13,4.73a6.5,6.5,0,0,0,12.74,0L51,21.53V43.21A1.9,1.9,0,0,1,49,45Z'/></g></g></svg>"); background-repeat: no-repeat;}
+.sdc-icon-vlm {background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 45 53'><title>vlm_new_icon</title><g id='Layer_2' data-name='Layer 2'><g id='vlm_icon' data-name='vlm icon'><path d='M41,2a2,2,0,0,1,2,2l.19,45a2,2,0,0,1-2,2H4a2,2,0,0,1-2-2L1.81,4a2,2,0,0,1,2-2H41m-.15-2H4A4.2,4.2,0,0,0,0,4.24L.19,49a4,4,0,0,0,4,4H41a4,4,0,0,0,4-4L44.81,4a4,4,0,0,0-4-4Z'/><rect x='14' y='11' width='17' height='2'/><rect x='14' y='18' width='10' height='2'/><polygon points='20.56 38.85 13.87 33.14 15.16 31.62 20.39 36.08 29.08 26.63 30.55 27.98 20.56 38.85'/></g></g></svg>"); background-repeat: no-repeat;}
+.sdc-icon-vsp {background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' 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 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'/></g></g></svg>"); background-repeat: no-repeat;}
+
+.sdc-icon-transform{
+ transform: rotate(180deg);
+}
diff --git a/src/style/scss/common/_normalize.scss b/src/style/scss/common/_normalize.scss
new file mode 100644
index 0000000..9375ee9
--- /dev/null
+++ b/src/style/scss/common/_normalize.scss
@@ -0,0 +1,578 @@
+/* ==========================================================================
+ Normalize.scss settings
+ ========================================================================== */
+/**
+ * Includes legacy browser support IE6/7
+ *
+ * Set to false if you want to drop support for IE6 and IE7
+ */
+
+$legacy_browser_support: false !default;
+
+/* Base
+ ========================================================================== */
+
+/**
+ * 1. Set default font family to sans-serif.
+ * 2. Prevent iOS and IE text size adjust after device orientation change,
+ * without disabling user zoom.
+ * 3. Corrects text resizing oddly in IE 6/7 when body `font-size` is set using
+ * `em` units.
+ */
+
+html {
+ font-family: sans-serif; /* 1 */
+ -ms-text-size-adjust: 100%; /* 2 */
+ -webkit-text-size-adjust: 100%; /* 2 */
+ @if $legacy_browser_support {
+ *font-size: 100%; /* 3 */
+ }
+}
+
+/**
+ * Remove default margin.
+ */
+
+body {
+ margin: 0;
+}
+
+/* HTML5 display definitions
+ ========================================================================== */
+
+/**
+ * Correct `block` display not defined for any HTML5 element in IE 8/9.
+ * Correct `block` display not defined for `details` or `summary` in IE 10/11
+ * and Firefox.
+ * Correct `block` display not defined for `main` in IE 11.
+ */
+
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+menu,
+nav,
+section,
+summary {
+ display: block;
+}
+
+/**
+ * 1. Correct `inline-block` display not defined in IE 6/7/8/9 and Firefox 3.
+ * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
+ */
+
+audio,
+canvas,
+progress,
+video {
+ display: inline-block; /* 1 */
+ vertical-align: baseline; /* 2 */
+ @if $legacy_browser_support {
+ *display: inline;
+ *zoom: 1;
+ }
+}
+
+/**
+ * Prevents modern browsers from displaying `audio` without controls.
+ * Remove excess height in iOS 5 devices.
+ */
+
+audio:not([controls]) {
+ display: none;
+ height: 0;
+}
+
+/**
+ * Address `[hidden]` styling not present in IE 8/9/10.
+ * Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.
+ */
+
+[hidden],
+template {
+ display: none;
+}
+
+/* Links
+ ========================================================================== */
+
+/**
+ * Remove the gray background color from active links in IE 10.
+ */
+
+a {
+ background-color: transparent;
+}
+
+/**
+ * Improve readability of focused elements when they are also in an
+ * active/hover state.
+ */
+
+a {
+ &:active, &:hover {
+ outline: 0;
+ };
+}
+
+/* Text-level semantics
+ ========================================================================== */
+
+/**
+ * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
+ */
+
+abbr[title] {
+ border-bottom: 1px dotted;
+}
+
+/**
+ * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
+ */
+
+b,
+strong {
+ font-weight: bold;
+}
+
+@if $legacy_browser_support {
+ blockquote {
+ margin: 1em 40px;
+ }
+}
+
+/**
+ * Address styling not present in Safari and Chrome.
+ */
+
+dfn {
+ font-style: italic;
+}
+
+/**
+ * Address variable `h1` font-size and margin within `section` and `article`
+ * contexts in Firefox 4+, Safari, and Chrome.
+ */
+
+h1 {
+ font-size: 2em;
+ margin: 0.67em 0;
+}
+
+@if $legacy_browser_support {
+ h2 {
+ font-size: 1.5em;
+ margin: 0.83em 0;
+ }
+
+ h3 {
+ font-size: 1.17em;
+ margin: 1em 0;
+ }
+
+ h4 {
+ font-size: 1em;
+ margin: 1.33em 0;
+ }
+
+ h5 {
+ font-size: 0.83em;
+ margin: 1.67em 0;
+ }
+
+ h6 {
+ font-size: 0.67em;
+ margin: 2.33em 0;
+ }
+}
+
+/**
+ * Addresses styling not present in IE 8/9.
+ */
+
+mark {
+ background: #ff0;
+ color: #000;
+}
+
+@if $legacy_browser_support {
+
+ /**
+ * Addresses margins set differently in IE 6/7.
+ */
+
+ p,
+ pre {
+ *margin: 1em 0;
+ }
+
+ /*
+ * Addresses CSS quotes not supported in IE 6/7.
+ */
+
+ q {
+ *quotes: none;
+ }
+
+ /*
+ * Addresses `quotes` property not supported in Safari 4.
+ */
+
+ q:before,
+ q:after {
+ content: '';
+ content: none;
+ }
+}
+
+/**
+ * Address inconsistent and variable font size in all browsers.
+ */
+
+small {
+ font-size: 80%;
+}
+
+/**
+ * Prevent `sub` and `sup` affecting `line-height` in all browsers.
+ */
+
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+
+sup {
+ top: -0.5em;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+@if $legacy_browser_support {
+
+ /* ==========================================================================
+ Lists
+ ========================================================================== */
+
+ /*
+ * Addresses margins set differently in IE 6/7.
+ */
+
+ dl,
+ menu,
+ ol,
+ ul {
+ *margin: 1em 0;
+ }
+
+ dd {
+ *margin: 0 0 0 40px;
+ }
+
+ /*
+ * Addresses paddings set differently in IE 6/7.
+ */
+
+ menu,
+ ol,
+ ul {
+ *padding: 0 0 0 40px;
+ }
+
+ /*
+ * Corrects list images handled incorrectly in IE 7.
+ */
+
+ nav ul,
+ nav ol {
+ *list-style: none;
+ *list-style-image: none;
+ }
+
+}
+
+/* Embedded content
+ ========================================================================== */
+
+/**
+ * 1. Remove border when inside `a` element in IE 8/9/10.
+ * 2. Improves image quality when scaled in IE 7.
+ */
+
+img {
+ border: 0;
+ @if $legacy_browser_support {
+ *-ms-interpolation-mode: bicubic; /* 2 */
+ }
+}
+
+/**
+ * Correct overflow not hidden in IE 9/10/11.
+ */
+
+svg:not(:root) {
+ overflow: hidden;
+}
+
+/* Grouping content
+ ========================================================================== */
+
+/**
+ * Address margin not present in IE 8/9 and Safari.
+ */
+
+figure {
+ margin: 1em 40px;
+}
+
+/**
+ * Address differences between Firefox and other browsers.
+ */
+
+hr {
+ box-sizing: content-box;
+ height: 0;
+}
+
+/**
+ * Contain overflow in all browsers.
+ */
+
+pre {
+ overflow: auto;
+}
+
+/**
+ * Address odd `em`-unit font size rendering in all browsers.
+ * Correct font family set oddly in IE 6, Safari 4/5, and Chrome.
+ */
+
+code,
+kbd,
+pre,
+samp {
+ font-family: monospace, monospace;
+ @if $legacy_browser_support {
+ _font-family: 'courier new', monospace;
+ }
+ font-size: 1em;
+}
+
+/* Forms
+ ========================================================================== */
+
+/**
+ * Known limitation: by default, Chrome and Safari on OS X allow very limited
+ * styling of `select`, unless a `border` property is set.
+ */
+
+/**
+ * 1. Correct color not being inherited.
+ * Known issue: affects color of disabled elements.
+ * 2. Correct font properties not being inherited.
+ * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
+ * 4. Improves appearance and consistency in all browsers.
+ */
+
+button,
+input,
+optgroup,
+select,
+textarea {
+ color: inherit; /* 1 */
+ font: inherit; /* 2 */
+ margin: 0; /* 3 */
+ @if $legacy_browser_support {
+ vertical-align: baseline; /* 3 */
+ *vertical-align: middle; /* 3 */
+ }
+}
+
+/**
+ * Address `overflow` set to `hidden` in IE 8/9/10/11.
+ */
+
+button {
+ overflow: visible;
+}
+
+/**
+ * Address inconsistent `text-transform` inheritance for `button` and `select`.
+ * All other form control elements do not inherit `text-transform` values.
+ * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
+ * Correct `select` style inheritance in Firefox.
+ */
+
+button,
+select {
+ text-transform: none;
+}
+
+/**
+ * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
+ * and `video` controls.
+ * 2. Correct inability to style clickable `input` types in iOS.
+ * 3. Improve usability and consistency of cursor style between image-type
+ * `input` and others.
+ * 4. Removes inner spacing in IE 7 without affecting normal text inputs.
+ * Known issue: inner spacing remains in IE 6.
+ */
+
+button,
+html input[type="button"], /* 1 */
+input[type="reset"],
+input[type="submit"] {
+ -webkit-appearance: button; /* 2 */
+ cursor: pointer; /* 3 */
+ @if $legacy_browser_support {
+ *overflow: visible; /* 4 */
+ }
+}
+
+/**
+ * Re-set default cursor for disabled elements.
+ */
+
+button[disabled],
+html input[disabled] {
+ cursor: default;
+}
+
+/**
+ * Remove inner padding and border in Firefox 4+.
+ */
+
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+ border: 0;
+ padding: 0;
+}
+
+/**
+ * Address Firefox 4+ setting `line-height` on `input` using `!important` in
+ * the UA stylesheet.
+ */
+
+input {
+ line-height: normal;
+}
+
+/**
+ * 1. Address box sizing set to `content-box` in IE 8/9/10.
+ * 2. Remove excess padding in IE 8/9/10.
+ * Known issue: excess padding remains in IE 6.
+ */
+
+input[type="checkbox"],
+input[type="radio"] {
+ box-sizing: border-box; /* 1 */
+ padding: 0; /* 2 */
+ @if $legacy_browser_support {
+ *height: 13px; /* 3 */
+ *width: 13px; /* 3 */
+ }
+}
+
+/**
+ * Fix the cursor style for Chrome's increment/decrement buttons. For certain
+ * `font-size` values of the `input`, it causes the cursor style of the
+ * decrement button to change from `default` to `text`.
+ */
+
+input[type="number"]::-webkit-inner-spin-button,
+input[type="number"]::-webkit-outer-spin-button {
+ height: auto;
+}
+
+/**
+ * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
+ * 2. Address `box-sizing` set to `border-box` in Safari and Chrome.
+ */
+
+input[type="search"] {
+ -webkit-appearance: textfield; /* 1 */
+ box-sizing: content-box; /* 2 */
+}
+
+/**
+ * Remove inner padding and search cancel button in Safari and Chrome on OS X.
+ * Safari (but not Chrome) clips the cancel button when the search input has
+ * padding (and `textfield` appearance).
+ */
+
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+
+/**
+ * Define consistent border, margin, and padding.
+ */
+
+fieldset {
+ border: 1px solid #c0c0c0;
+ margin: 0 2px;
+ padding: 0.35em 0.625em 0.75em;
+}
+
+/**
+ * 1. Correct `color` not being inherited in IE 8/9/10/11.
+ * 2. Remove padding so people aren't caught out if they zero out fieldsets.
+ * 3. Corrects text not wrapping in Firefox 3.
+ * 4. Corrects alignment displayed oddly in IE 6/7.
+ */
+
+legend {
+ border: 0; /* 1 */
+ padding: 0; /* 2 */
+ @if $legacy_browser_support {
+ white-space: normal; /* 3 */
+ *margin-left: -7px; /* 4 */
+ }
+}
+
+/**
+ * Remove default vertical scrollbar in IE 8/9/10/11.
+ */
+
+textarea {
+ overflow: auto;
+}
+
+/**
+ * Don't inherit the `font-weight` (applied by a rule above).
+ * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
+ */
+
+optgroup {
+ font-weight: bold;
+}
+
+/* Tables
+ ========================================================================== */
+
+/**
+ * Remove most spacing between table cells.
+ */
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+td,
+th {
+ padding: 0;
+}
diff --git a/src/style/scss/common/_typography.scss b/src/style/scss/common/_typography.scss
new file mode 100644
index 0000000..6fd59cc
--- /dev/null
+++ b/src/style/scss/common/_typography.scss
@@ -0,0 +1,96 @@
+$heading-font-1: 28px;
+$heading-font-2: 24px;
+$heading-font-3: 20px;
+$heading-font-4: 16px;
+$heading-font-5: 14px;
+
+$body-font-1: 14px;
+$body-font-2: 13px;
+$body-font-3: 12px;
+$body-font-4: 10px;
+
+@mixin base-font-regular() {
+ font-family: OpenSans-Regular, Arial, sans-serif;
+ font-style: normal;
+ font-weight: 400;
+}
+
+@mixin base-font-italic(){
+ font-family: OpenSans-Italic, OpenSans-Regular, Arial, sans-serif;
+ font-style: normal;
+ font-weight: 400;
+}
+
+@mixin base-font-semibold() {
+ font-family: OpenSans-Semibold, Arial, sans-serif;
+ font-style: normal;
+ font-weight: 400;
+}
+
+@mixin font-error() {
+ color: $red;
+}
+
+@mixin heading-1() {
+ @include base-font-regular;
+ font-size: $heading-font-1;
+}
+
+@mixin heading-2() {
+ @include base-font-regular;
+ font-size: $heading-font-2;
+}
+
+@mixin heading-3 {
+ @include base-font-regular;
+ font-size: $heading-font-3;
+}
+
+@mixin heading-4 {
+ @include base-font-regular;
+ font-size: $heading-font-4;
+}
+
+@mixin heading-4-emphasis {
+ @include base-font-semibold;
+ font-size: $heading-font-4;
+}
+
+@mixin heading-5 {
+ @include base-font-semibold;
+ font-size: $heading-font-5;
+}
+
+@mixin body-1 {
+ @include base-font-regular;
+ font-size: $body-font-1;
+}
+
+@mixin body-1-italic {
+ @include base-font-italic;
+ font-size: $body-font-1;
+}
+
+@mixin body-2 {
+ @include base-font-regular;
+ font-size: $body-font-2;
+}
+
+@mixin body-2-emphasis {
+ @include base-font-semibold;
+ font-size: $body-font-2;
+}
+
+@mixin body-3 {
+ @include base-font-regular;
+ font-size: $body-font-3;
+}
+@mixin body-3-emphasis {
+ @include base-font-semibold;
+ font-size: $body-font-3;
+}
+
+@mixin body-4 {
+ @include base-font-regular;
+ font-size: $body-font-4;
+} \ No newline at end of file
diff --git a/src/style/scss/common/base.scss b/src/style/scss/common/base.scss
new file mode 100644
index 0000000..02baf81
--- /dev/null
+++ b/src/style/scss/common/base.scss
@@ -0,0 +1,96 @@
+html {
+ font-size: 100%;
+ height: 100%;
+}
+
+body {
+ /* scrollbar styling for Internet Explorer */
+ scrollbar-face-color: $light-gray;
+ scrollbar-track-color: $white;
+ scrollbar-shadow-color:$white;
+ scrollbar-arrow-color: $gray;
+
+ height: 100%;
+ @extend %noselect;
+}
+
+/* scrollbar styling for Google Chrome | Safari | Opera */
+::-webkit-scrollbar {
+ width: 11px;
+ height: 8px;
+}
+
+::-webkit-scrollbar-track {
+ background-color: $white;
+ border: 1px solid $light-gray;
+ border-top:none;
+ border-bottom:none;
+}
+
+::-webkit-scrollbar-thumb {
+ border-radius: 6px;
+ background-color: $gray;
+ border: 2px solid rgba(0,0,0,0);
+ background-clip: padding-box;
+
+ &:hover {
+ border-width:1px 0px 1px 1px;
+ }
+}
+
+/* Mozilla Firefox currently doesn't support scrollbar styling */
+
+ul {
+ list-style: none;
+}
+
+h1, h2, h3, h4, h5, h6, ul {
+ margin: 0;
+ padding: 0;
+}
+
+input[type='text'] {
+ padding: 4px;
+ width: 100%;
+}
+
+input[type="checkbox"] {
+ width: auto;
+}
+
+input, select, button {
+ @include body-1;
+ box-sizing: border-box;
+}
+
+fieldset {
+ border: none;
+}
+
+fieldset {
+ label {
+ display: inline-block;
+ }
+}
+
+.nav-tabs > li > a:focus,
+.btn:focus,
+.btn:active:focus,
+.btn.active:focus {
+ outline: none;
+}
+
+.error-message{
+ color: $red;
+ @include body-3;
+ margin-top: 3px;
+ &:before{
+ content: "";
+ display: inline-block;
+ width: 14px;
+ height: 14px;
+ margin-right: 6px;
+ //not correct icon
+ background: no-repeat url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14" height="14" viewBox="0 0 24 24"><defs><path id="alert-copy-a" d="M22.3815,16.5997 L13.9815,2.4007 C13.5815,1.6997 12.8815,1.1997 12.0815,0.9997 C11.2815,0.7997 10.4815,0.9007 9.7815,1.2997 C9.3815,1.4997 8.9815,1.9007 8.7815,2.2997 L0.3815,16.5997 C-0.4185,17.9997 0.0815,19.9007 1.4815,20.6997 C1.8815,20.9997 2.3815,21.0997 2.8815,21.0997 L19.8815,21.0997 C20.6825,21.0997 21.4815,20.7997 21.9815,20.1997 C22.5815,19.5997 22.8815,18.9007 22.8815,18.0997 C22.7815,17.5997 22.6825,16.9997 22.3815,16.5997 M11,7 C10.4,7 10,7.4 10,8 L10,12 C10,12.601 10.4,13 11,13 C11.6,13 12,12.601 12,12 L12,8 C12,7.4 11.6,7 11,7 M10.3,15.3 C10.1,15.499 10,15.699 10,15.999 C10,16.3 10.1,16.499 10.3,16.699 C10.5,16.9 10.7,16.999 11,16.999 C11.3,16.999 11.5,16.9 11.7,16.699 C11.9,16.499 12,16.199 12,15.999 C12,15.8 11.9,15.499 11.7,15.3 C11.3,14.9 10.7,14.9 10.3,15.3"/></defs><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><use fill="'+ $red +'" xlink:href="#alert-copy-a"/></g></svg>');
+ }
+}
diff --git a/src/style/scss/common/mixins.scss b/src/style/scss/common/mixins.scss
new file mode 100644
index 0000000..c4cb733
--- /dev/null
+++ b/src/style/scss/common/mixins.scss
@@ -0,0 +1,337 @@
+/* Colors */
+.sdc-bc-white { background-color: $white; }
+.sdc-bc-blue { background-color: $blue; }
+.sdc-bc-light-blue { background-color: $light-blue; }
+.sdc-bc-lighter-blue { background-color: $lighter-blue; }
+.sdc-bc-blue-disabled { background-color: $blue-disabled; }
+.sdc-bc-dark-blue { background-color: $dark-blue; }
+.sdc-bc-black { background-color: $black; }
+.sdc-bc-rich-black { background-color: $rich-black; }
+.sdc-bc-text-black { background-color: $text-black; }
+.sdc-bc-dark-gray { background-color: $dark-gray; }
+.sdc-bc-gray { background-color: $gray; }
+.sdc-bc-light-gray { background-color: $light-gray; }
+.sdc-bc-silver { background-color: $silver; }
+.sdc-bc-light-silver { background-color: $light-silver; }
+.sdc-bc-green { background-color: $green; }
+.sdc-bc-red { background-color: $red; }
+.sdc-bc-disabled-red { background-color: $disabled-red; }
+.sdc-bc-light-red { background-color: $light-red; }
+.sdc-bc-yellow { background-color: $yellow; }
+.sdc-bc-dark-purple { background-color: $dark-purple; }
+.sdc-bc-purple { background-color: $purple; }
+.sdc-bc-light-purple { background-color: $light-purple; }
+.sdc-bc-lighter-silver { background-color: $lighter-silver; }
+/* Prefix */
+$box-sizing-prefix: webkit moz spec;
+$border-radius-prefix: webkit spec;
+$box-shadow-radius-prefix: webkit moz spec;
+$text-shadow-radius-prefix: spec;
+$text-shadow-prefix: spec;
+$box-shadow-prefix: all;
+$linear-gradient-prefix: all;
+$transition-prefix: webkit moz o spec;
+$flex-prefix: webkit spec;
+$browserPrefixes: webkit moz o ms;
+
+@mixin prefix($property, $value, $prefixeslist: 'all') {
+ @if $prefixeslist == all {
+ -webkit-#{$property}: $value;
+ -moz-#{$property}: $value;
+ -ms-#{$property}: $value;
+ -o-#{$property}: $value;
+ #{$property}: $value;
+ } @else {
+ @each $prefix in $prefixeslist {
+ @if $prefix == webkit {
+ -webkit-#{$property}: $value;
+ } @else if $prefix == moz {
+ -moz-#{$property}: $value;
+ } @else if $prefix == ms {
+ -ms-#{$property}: $value;
+ } @else if $prefix == o {
+ -o-#{$property}: $value;
+ } @else if $prefix == spec {
+ #{$property}: $value;
+ } @else {
+ @warn "No such prefix: #{$prefix}";
+ }
+ }
+ }
+}
+
+/* Value Prefix*/
+@mixin value-suffix-with-range($property, $valuesuffix, $from, $to, $prefixeslist) {
+
+ @if $prefixeslist == all {
+ #{property} : -webkit-#{$valuesuffix}($from, $to);
+ #{property} : -moz-#{$valuesuffix}($from, $to);
+ #{property} : -o-#{$valuesuffix}($from, $to);
+ #{property} : -ms-#{$valuesuffix}($from, $to);
+
+ } @else {
+ @each $prefix in $prefixeslist {
+ @if $prefix == webkit {
+ #{property} : -webkit-#{$valuesuffix}($from, $to);
+ } @else if $prefix == moz {
+ #{property} : -moz-#{$valuesuffix}($from, $to);
+ } @else if $prefix == ms {
+ #{property} : -ms-#{$valuesuffix}($from, $to);
+ } @else if $prefix == o {
+ #{property} : -o-#{$valuesuffix}($from, $to);
+ } @else {
+ @warn "No such prefix: #{$prefix}";
+ }
+ }
+ }
+}
+
+/* Box sizing */
+@mixin box-sizing($value: border-box) {
+ @include prefix(box-sizing, $value, $box-sizing-prefix);
+}
+
+/* Borders & Shadows */
+@mixin box-shadow($value) {
+ @include prefix(box-shadow, $value, $box-shadow-radius-prefix);
+}
+
+@mixin text-shadow($value) {
+ @include prefix(text-shadow, $value, $text-shadow-radius-prefix);
+}
+
+@mixin border-radius($value, $positions: all) {
+ @if ($positions == all) {
+ @include prefix(border-radius, $value, $border-radius-prefix);
+ } @else {
+ @each $position in $positions {
+ @include prefix(border-#{$position}-radius, $value, $border-radius-prefix);
+ }
+ }
+
+}
+
+@mixin transition($value) {
+ @include prefix(transition, $value, $transition-prefix);
+}
+
+/* Opacity */
+@mixin opacity($alpha) {
+ $ie-opacity: round($alpha * 100);
+ opacity: $alpha;
+ filter: unquote("alpha(opacity = #{$ie-opacity})");
+}
+
+/* Ellipsis */
+@mixin ellipsis($width: 100%, $display: inline-block, $max-width: none) {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ width: $width;
+ white-space: nowrap;
+ display: $display;
+ max-width: $max-width;
+}
+
+@mixin multiline-ellipsis($lineHeight: 1.3em, $lineCount: 2, $bgColor: $white){
+ overflow: hidden;
+ position: relative;
+ line-height: $lineHeight;
+ max-height: $lineHeight * $lineCount;
+ text-align: justify;
+ // margin-right: -1em;
+ padding-right: 1em;
+ &:before {
+ content: '...';
+ position: absolute;
+ right: 3px;
+ bottom: 0;
+ }
+ &:after {
+ content: '';
+ position: absolute;
+ right: 0;
+ width: 1em;
+ height: 1em;
+ margin-top: 0.2em;
+ background: $bgColor;
+ }
+}
+
+@mixin gradient($from, $to) {
+ /* fallback/image non-cover color */
+ background-color: $from;
+ background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from($from), to($to));
+ @include value-suffix-with-range(background-color, linear-gradient, $from, $to, $linear-gradient-prefix);
+}
+
+/* Vertical placement of multuple lines of text */
+@mixin vertical-text($height) {
+ position: absolute;
+ top: 50%;
+ margin-top: -$height/2;
+}
+
+@mixin text-vertical-align($align: middle) {
+ display: table;
+ width: 100%;
+
+ & > * {
+ vertical-align: $align;
+ display: table-cell;
+ }
+}
+
+@mixin center-element($width) {
+ width: $width;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+@mixin center-content($width) {
+ & > * {
+ @include center-element($width);
+ }
+}
+
+/* transform-rotate */
+// @mixin
+// Defines a 2D rotation, the angle is specified in the parameter
+// @param
+// $deg - angle in degrees
+@mixin transform-rotate($deg) {
+ transform: rotate($deg + deg); /* IE10 and Mozilla */
+ -ms-transform: rotate($deg + deg); /* IE 9 */
+ -webkit-transform: rotate($deg + deg); /* Safari and Chrome */
+}
+
+/* transform-translate */
+// @mixin
+// Defines a 2D rotation, the angle is specified in the parameter
+// @param
+// $deg - angle in degrees
+@mixin transform-translate($x, $y) {
+ transform: translate($x, $y); /* IE10 and Mozilla */
+ -ms-transform: translate($x, $y); /* IE 9 */
+ -webkit-transform: translate($x, $y); /* Safari and Chrome */
+}
+
+/* transform-scale */
+// @mixin
+// Defines a 2D scale transformation, changing the elements width and height
+// @param
+// $width - width
+// @param
+// $height - height
+@mixin transform-scale($width, $height) {
+ transform: scale($width, $height); /* IE10 and Mozilla */
+ -ms-transform: scale($width, $height); /* IE 9 */
+ -webkit-transform: scale($width, $height); /* Safari and Chrome */
+}
+
+@mixin scrollable() {
+ ::-webkit-scrollbar {
+ width: 8px;
+ }
+}
+
+@mixin create-circle($size, $bgcolor, $content) {
+ border-radius: 50%;
+ width: $size;
+ height: $size;
+ background: $bgcolor;
+ border: 3px solid $bgcolor;
+ &:after {
+ content: $content;
+ position: relative;
+ left: 9px;
+ top: 9px;
+ @include base-font-semibold;
+ font-size: $body-font-1;
+ }
+}
+
+/**/
+@mixin keyframe-animation($animationType, $properties, $fromValue, $toValue) {
+
+ @keyframes #{$animationType} {
+ from {
+ $startIndex: 1;
+ @each $property in $properties {
+ #{$property}: nth($fromValue, $startIndex);
+ $startIndex: $startIndex + 1;
+ }
+ }
+ to {
+ $startIndex: 1;
+ @each $property in $properties {
+ #{$property}: nth($toValue, $startIndex);
+ $startIndex: $startIndex + 1;
+ }
+ }
+ }
+ @-moz-keyframes #{$animationType}{
+ /* Firefox */
+ from {
+ $startIndex: 1;
+ @each $property in $properties {
+ #{$property}: nth($fromValue, $startIndex);
+ $startIndex: $startIndex + 1;
+ }
+ }
+ to {
+ $startIndex: 1;
+ @each $property in $properties {
+ #{$property}: nth($toValue, $startIndex);
+ $startIndex: $startIndex + 1;
+ }
+ }
+ }
+ @-webkit-keyframes #{$animationType} {
+ /* Safari and Chrome */
+ from {
+ $startIndex: 1;
+ @each $property in $properties {
+ #{$property}: nth($fromValue, $startIndex);
+ $startIndex: $startIndex + 1;
+ }
+ }
+ to {
+ $startIndex: 1;
+ @each $property in $properties {
+ #{$property}: nth($toValue, $startIndex);
+ $startIndex: $startIndex + 1;
+ }
+ }
+ }
+ @-o-keyframes #{$animationType} {
+ /* Opera */
+ from {
+ $startIndex: 1;
+ @each $property in $properties {
+ #{$property}: nth($fromValue, $startIndex);
+ $startIndex: $startIndex + 1;
+ }
+ }
+ to {
+ $startIndex: 1;
+ @each $property in $properties {
+ #{$property}: nth($toValue, $startIndex);
+ $startIndex: $startIndex + 1;
+ }
+ }
+ }
+}
+
+
+/**/
+@mixin border-shadow($xShadow: 0.545px, $yShadow: 0.839px, $blur: 4px, $spread: 0, $color: $light-gray, $opacity: 0.2) {
+ @include box-shadow($xShadow $yShadow $blur $spread rgba($color, $opacity));
+}
+
+%noselect {
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
diff --git a/src/style/scss/common/variables.scss b/src/style/scss/common/variables.scss
new file mode 100644
index 0000000..38eded4
--- /dev/null
+++ b/src/style/scss/common/variables.scss
@@ -0,0 +1,35 @@
+// Colors
+$black: #000000;
+$rich-black: #323943;
+$text-black: #191919;
+$blue: #009fdb;
+$dark-blue: #0568ae;
+$light-blue: #1eb9f3;
+$lighter-blue: #e6f6fb;
+$blue-disabled: #9dd9ef;
+$red: #cf2a2a;
+$light-red:#ed4141;
+$disabled-red:#f4adad;
+$purple: #9063cd;
+$dark-purple: #702f8a;
+$yellow: #ffb81c;
+$green: #4ca90c;
+$gray: #959595;
+$dark-gray: #5a5a5a;
+$light-gray: #d2d2d2;
+$light-silver: #f2f2f2;
+$silver: #eaeaea;
+
+
+$light-purple: #caa2dd;
+$lighter-silver: #f8f8f8;
+$white: #ffffff;
+
+$scroll-bar-color: $text-black;
+
+// Button Sizes
+$btn-extra-small: 90px;
+$btn-small: 110px;
+$btn-medium: 140px;
+$btn-large: 180px;
+$btn-default: auto;
diff --git a/src/style/scss/style.scss b/src/style/scss/style.scss
new file mode 100644
index 0000000..5512776
--- /dev/null
+++ b/src/style/scss/style.scss
@@ -0,0 +1,6 @@
+@import "common";
+@import "components";
+
+// for angular
+@import "angular/svg_icon";
+@import "angular/tooltip_custom_style";
diff --git a/src/style/scss/themes/1802/_components.scss b/src/style/scss/themes/1802/_components.scss
new file mode 100644
index 0000000..6800005
--- /dev/null
+++ b/src/style/scss/themes/1802/_components.scss
@@ -0,0 +1,23 @@
+/* Deafult theme */
+@import "../../../../../components/tile/tile";
+@import "../../../../../components/checkbox/checkbox";
+@import "../../../../../components/radio/radio";
+@import "../../../../../components/radioGroup/radioGroup";
+@import "../../../../../components/icon/icon";
+@import "../../../../../components/input/input";
+@import "../../../../../components/dropdown/dropdown";
+@import "../../../../../components/menu/menu";
+@import "../../../../../components/filter-bar/_filter-bar";
+@import "../../../../../components/search-bar/_search-bar";
+@import "../../../../../components/checklist/checklist";
+@import "../../../../../components/autocomplete/autocomplete";
+@import "../../../../../components/tooltip/tooltip";
+@import "../../../../../components/tag-cloud/_tag-cloud";
+@import "../../../../../components/notification/notification";
+@import "../../../../../components/notifications-container/notifications-container";
+@import "../../../../../components/validation/validation";
+
+/* 1802 theme */
+@import "button";
+@import "modal";
+@import "tabs";
diff --git a/src/style/scss/themes/1802/button.scss b/src/style/scss/themes/1802/button.scss
new file mode 100644
index 0000000..05d91d5
--- /dev/null
+++ b/src/style/scss/themes/1802/button.scss
@@ -0,0 +1,148 @@
+.sdc-button {
+ @include box-sizing;
+ display: inline-block;
+
+ outline: none;
+ border-radius: 2px;
+ padding: 0 16px;
+
+ height: 32px;
+ line-height: 32px;
+ width: 120px;
+ min-width: 90px;
+
+ cursor: pointer;
+ text-align: center;
+ @include body-1;
+ &:disabled {
+ cursor: default;
+ }
+
+ // Primary button
+ &.sdc-button__primary {
+ border: none;
+ background-color: $blue;
+ color: $white;
+
+ &:not(:disabled) {
+ &:hover, &:active {
+ background-color: $light-blue;
+ }
+ &:focus:not(:active) {
+ border: 0.5px solid $white;
+ background-color: $light-blue;
+ box-shadow: 0px 0px 0px 1px $light-blue;
+ }
+ }
+
+ &:disabled{
+ background: $blue-disabled;
+ }
+ }
+
+ // Secondary button
+ &.sdc-button__secondary {
+ border: 1px solid $light-gray;
+ background-color: transparent;
+ color: $text-black;
+
+ &:not(:disabled) {
+ &:hover, &:active {
+ background-color: transparent;
+ color:$text-black;
+ border: 1px solid $gray;
+ }
+ &:focus:not(:active) {
+ color: $text-black;
+ box-shadow: inset 0px 0px 0px 0px $light-gray, 0px 0px 0px 1px $gray;
+ }
+ }
+
+ &:disabled {
+ color: $blue-disabled;
+ border-color: $blue-disabled;
+ }
+ }
+
+ // Link button
+ &.sdc-button__link {
+ background-color: transparent;
+ color: $blue;
+ fill: $blue;
+ border: none;
+
+ &:not(:disabled) {
+ &:hover, &:active {
+ color: $light-blue;
+ }
+ &:focus:not(:active) {
+ border: 1px solid $dark-blue;
+ color: $light-blue;
+ }
+ }
+
+ &:disabled{
+ color: $blue-disabled;
+ }
+ }
+
+
+ // alert button
+ &.sdc-button__alert {
+ border: none;
+ background-color: $red;
+ color: $white;
+
+ &:not(:disabled) {
+ &:hover, &:active {
+ background-color: $light-red;
+ }
+ &:focus:not(:active) {
+ border: 0.5px solid $white;
+ background-color: $light-red;
+ box-shadow: 0px 0px 0px 1px $light-red;
+ }
+ }
+
+ &:disabled{
+ background: $disabled-red;
+ }
+ }
+
+
+ /*** Sizes ***/
+ &.btn-large{
+ width: $btn-large;
+ }
+
+ &.btn-medium{
+ width: $btn-medium;
+ }
+
+ &.btn-small{
+ width: $btn-small;
+ }
+
+ &.btn-x-small{
+ width: $btn-extra-small;
+ }
+
+ &.btn-default{
+ width: $btn-default;
+ }
+
+ /*** Buttons with icons ***/
+ .sdc-icon-right{
+ margin-left: 15px;
+ }
+
+ .sdc-icon-left{
+ margin-right: 15px;
+ }
+
+ svg {
+ display: inline-block;
+ vertical-align: middle;
+ }
+}
+
diff --git a/src/style/scss/themes/1802/modal.scss b/src/style/scss/themes/1802/modal.scss
new file mode 100644
index 0000000..de99d52
--- /dev/null
+++ b/src/style/scss/themes/1802/modal.scss
@@ -0,0 +1,193 @@
+
+.sdc-modal {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+
+ overflow: auto;
+ margin: auto;
+ display: flex;
+ align-items: center;
+ z-index: 1001;
+
+
+ svg path {
+ fill: inherit;
+ }
+
+ .sdc-modal__wrapper {
+ @include body-1;
+ background: $white;
+ width: 100%;
+
+ @include box-shadow(0 0 4px 0 rgba(0,0,0,0.50));
+ color: $text-black;
+ display: flex;
+ flex-direction: column;
+ &.sdc-modal-type-info {
+ border-top: solid 6px $blue;
+ .sdc-modal__svg-use {
+ fill: $blue;
+ }
+ .svg-icon {
+ &.__errorCircle {
+ width: 30px;
+ height: 30px;
+ }
+ }
+ }
+ &.sdc-modal-type-alert {
+ border-top: solid 6px $yellow;
+ .sdc-modal__svg-use {
+ fill: $yellow;
+ }
+ .svg-icon {
+ &.__exclamationTriangleLine {
+ width: 30px;
+ height: 30px;
+ }
+ }
+ }
+ &.sdc-modal-type-error {
+ border-top: solid 6px $red;
+ .sdc-modal__svg-use {
+ fill: $red;
+ }
+ .svg-icon {
+ &.__error {
+ width: 30px;
+ height: 30px;
+ }
+ }
+ }
+ &.sdc-modal-type-custom {
+ padding: 0 30px;
+ border-radius: 4px;
+
+ .sdc-custom__header {
+ @include box-sizing;
+ color: $dark-gray;
+ height: 50px;
+ border-bottom: solid 3px $blue;
+ padding: 0;
+
+ .title {
+ @include heading-3;
+ color: $dark-gray;
+ }
+
+ .sdc-modal__close-button {
+ margin-top: 0px;
+ width: 20px;
+ height: 14px;
+ }
+ .sdc-modal__close-button-svg {
+ width: 20px;
+ height: 20px;
+ .sdc-modal__svg-use {
+ fill: $white;
+ }
+ .svg-icon {
+ height: 14px;
+ width: 14px;
+ fill: $white;
+ }
+ }
+ }
+ .sdc-modal__content {
+ padding: 20px 40px;
+ }
+ }
+ .sdc-modal__header {
+ padding: 0px 10px 8px 14px;
+ display: flex;
+ justify-content: space-between;
+ text-align: left;
+ .sdc-modal__icon {
+ padding: 20px 12px 0px 6px;
+ }
+
+ .title {
+ @include heading-2;
+ flex: 1 1 auto;
+ color: $text-black;
+ padding-top: 19px;
+ }
+
+ .sdc-modal__close-button {
+ order:3;
+ width: 14px;
+ height: 14px;
+ margin-top:10px;
+ cursor: pointer;
+ .sdc-modal__svg-use {
+ fill: $black;
+ }
+ }
+ }
+ .sdc-modal__content {
+ order:2;
+ padding-left: 63px;
+ padding-right: 68px;
+ padding-bottom: 26px;
+ }
+
+ .sdc-modal__footer {
+ order:3;
+ background-color: $light-silver;
+ border-top: solid 1px $silver;
+ padding: 17px 30px;
+ display: flex;
+ justify-content: flex-end;
+ margin: 0 -30px;
+ button{
+ margin-left: 10px;
+ }
+ }
+ }
+}
+
+.modal-background {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ background-color: $black;
+ opacity: 0.70;
+ z-index: 1000;
+
+ &.show {
+ z-index: 1000;
+ opacity: 0.70;
+ transition: opacity .3s ease, z-index .3s;
+ }
+ &.hide {
+ z-index: -1;
+ opacity: 0;
+ transition: opacity .35s ease, z-index .35s;
+ }
+}
+
+.xl {
+ width: 1200px;
+}
+
+.l {
+ width: 875px;
+}
+
+.md {
+ width: 650px;
+}
+
+.sm {
+ width: 500px;
+}
+
+.xsm {
+ width: 432px;
+}
+
diff --git a/src/style/scss/themes/1802/style.scss b/src/style/scss/themes/1802/style.scss
new file mode 100644
index 0000000..ae314d8
--- /dev/null
+++ b/src/style/scss/themes/1802/style.scss
@@ -0,0 +1,5 @@
+@import "../../common";
+@import "components";
+
+// for angular
+@import "../../angular/svg_icon";
diff --git a/src/style/scss/themes/1802/tabs.scss b/src/style/scss/themes/1802/tabs.scss
new file mode 100644
index 0000000..70ee4cb
--- /dev/null
+++ b/src/style/scss/themes/1802/tabs.scss
@@ -0,0 +1,39 @@
+.sdc-tabs {
+ .sdc-tab {
+ background-color: $white;
+ border: 1px solid $silver;
+ border-left: none;
+ display: inline-block;
+ height: 36px;
+ text-align: center;
+ cursor: pointer;
+ padding: 2px 10px 0 10px;
+ margin: 0;
+
+
+ &:first-child {
+ border-left: 1px solid $silver;
+ }
+ &.sdc-tab-active {
+ background-color: $silver;
+ }
+ &[disabled] {
+ opacity: 0.3;
+ cursor: default;
+ }
+ }
+ &.sdc-tabs-header {
+ .sdc-tab {
+ @include heading-2;
+ }
+ }
+ &.sdc-tabs-menu {
+ .sdc-tab {
+ @include body-1;
+ padding: 0px 10px 4px 10px;
+ }
+ }
+ .sdc-tab-content {
+ margin-top: 30px;
+ }
+}
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>
+ &lt;svg-icon-label
+ [name]="{{selectedIcon}}"
+ [mode]="{{mode}}"
+ [size]="{{size}}"
+ [clickable]="{{clickable}}"
+ [disabled]="{{disabled}}"
+ [label]="{{label}}"
+ [labelPlacement]="{{labelPlacement}}"&gt;
+ &lt;/svg-icon-label&gt;
+ </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;
diff --git a/test/react/Accordion.spec.js b/test/react/Accordion.spec.js
new file mode 100644
index 0000000..614dcdd
--- /dev/null
+++ b/test/react/Accordion.spec.js
@@ -0,0 +1,11 @@
+import React from 'react';
+import Accordion from '../../src/react/Accordion.js';
+
+import renderer from 'react-test-renderer';
+
+describe('Accordion', () => {
+ test('Accordion - Default', () => {
+ const accordion = renderer.create(<Accordion title='Accordion'>Accordion body</Accordion>).toJSON();
+ expect(accordion).toMatchSnapshot();
+ });
+}); \ No newline at end of file
diff --git a/test/react/Button.spec.js b/test/react/Button.spec.js
new file mode 100644
index 0000000..3b3b72e
--- /dev/null
+++ b/test/react/Button.spec.js
@@ -0,0 +1,77 @@
+import React from 'react';
+import Button from '../../src/react/Button.js';
+
+import renderer from 'react-test-renderer';
+
+describe('Button', () => {
+ test('Button - Default - Primary', () => {
+ const button = renderer.create(<Button>Click Me</Button>).toJSON();
+ expect(button).toMatchSnapshot();
+ });
+
+ test('Button - Default - Primary - Disabled', () => {
+ const button = renderer.create(<Button disabled>Click Me</Button>).toJSON();
+ expect(button).toMatchSnapshot();
+ });
+
+ test('Button - Default - White', () => {
+ const button = renderer.create(<Button color='white'>Click Me</Button>).toJSON();
+ expect(button).toMatchSnapshot();
+ });
+
+ test('Button - Default - Gray', () => {
+ const button = renderer.create(<Button color='gray'>Click Me</Button>).toJSON();
+ expect(button).toMatchSnapshot();
+ });
+
+ test('Button - Default - Positive', () => {
+ const button = renderer.create(<Button color='positive'>Click Me</Button>).toJSON();
+ expect(button).toMatchSnapshot();
+ });
+
+ test('Button - Default - Negative', () => {
+ const button = renderer.create(<Button color='negative'>Click Me</Button>).toJSON();
+ expect(button).toMatchSnapshot();
+ });
+
+ test('Button - Default - Warning', () => {
+ const button = renderer.create(<Button color='warning'>Click Me</Button>).toJSON();
+ expect(button).toMatchSnapshot();
+ });
+
+ test('Button - Outline - Primary', () => {
+ const button = renderer.create(<Button btnType='outline'>Click Me</Button>).toJSON();
+ expect(button).toMatchSnapshot();
+ });
+
+ test('Button - Outline - Gray', () => {
+ const button = renderer.create(<Button btnType='outline' color='gray'>Click Me</Button>).toJSON();
+ expect(button).toMatchSnapshot();
+ });
+
+ test('Button - Outline - Positive', () => {
+ const button = renderer.create(<Button btnType='outline' color='positive'>Click Me</Button>).toJSON();
+ expect(button).toMatchSnapshot();
+ });
+
+ test('Button - Outline - Negative', () => {
+ const button = renderer.create(<Button btnType='outline' color='negative'>Click Me</Button>).toJSON();
+ expect(button).toMatchSnapshot();
+ });
+
+ test('Button - Link - Primary', () => {
+ const button = renderer.create(<Button btnType='link' color='primary'>Click Me</Button>).toJSON();
+ expect(button).toMatchSnapshot();
+ });
+
+ test('Button - Link - Primary - Disabled', () => {
+ const button = renderer.create(<Button btnType='link' color='primary' disabled>Click Me</Button>).toJSON();
+ expect(button).toMatchSnapshot();
+ });
+
+ test('Button - Link - Primary - With Icon', () => {
+ const button = renderer.create(<Button btnType='link' color='primary' iconName='plus'>Click Me</Button>).toJSON();
+ expect(button).toMatchSnapshot();
+ });
+
+});
diff --git a/test/react/Checkbox.spec.js b/test/react/Checkbox.spec.js
new file mode 100644
index 0000000..88ba660
--- /dev/null
+++ b/test/react/Checkbox.spec.js
@@ -0,0 +1,60 @@
+import React from 'react';
+import Checkbox from '../../src/react/Checkbox.js';
+
+import renderer from 'react-test-renderer';
+import {mount} from 'enzyme';
+
+class CheckboxForm extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {checked: false};
+
+ this.handleChange = this.handleChange.bind(this);
+ }
+
+ handleChange(val) {
+ this.setState({checked: val});
+ }
+
+ getChecked() {
+ return this.checkbox.getChecked();
+ }
+
+ render() {
+ return (
+ <form >
+ <Checkbox ref={(checkbox)=>{this.checkbox = checkbox;}} checked={this.state.checked} onChange={this.handleChange} label='This is the checkbox label' />
+ </form>
+ );
+ }
+}
+
+describe('Checkbox', () => {
+ test('Checkbox - unchecked', () => {
+ const checkbox = renderer.create(<Checkbox label='This is the checkbox label'/>).toJSON();
+ expect(checkbox).toMatchSnapshot();
+ });
+
+ test('Checkbox - disabled', () => {
+ const checkbox = renderer.create(<Checkbox disabled={true} label='This is the checkbox label' />).toJSON();
+ expect(checkbox).toMatchSnapshot();
+ });
+
+ test('Checkbox - checked state changes', () => {
+ const checkbox = mount(<CheckboxForm />);
+ expect(checkbox.instance().getChecked()).toEqual(false);
+ expect(checkbox.instance().getChecked()).toEqual(checkbox.find('input').props().checked);
+ checkbox.find('input').simulate('change', { target : { checked: true }});
+ expect(checkbox.instance().getChecked()).toEqual(checkbox.find('input').props().checked);
+ expect(checkbox.instance().getChecked()).toEqual(true);
+ checkbox.find('input').simulate('change', { target : { checked: false }});
+ expect(checkbox.instance().getChecked()).toEqual(false);
+ expect(checkbox.instance().getChecked()).toEqual(checkbox.find('input').props().checked);
+ });
+
+ test('Checkbox - returns its value', () => {
+ const checkbox = mount(<Checkbox label='This is the checkbox label' value='myVal' />);
+ expect(checkbox.instance().getValue()).toEqual('myVal');
+ });
+
+});
diff --git a/test/react/Checklist.spec.js b/test/react/Checklist.spec.js
new file mode 100644
index 0000000..a3409ad
--- /dev/null
+++ b/test/react/Checklist.spec.js
@@ -0,0 +1,64 @@
+import React from 'react';
+import Checklist from '../../src/react/Checklist.js';
+
+import renderer from 'react-test-renderer';
+
+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
+ }
+];
+
+
+describe('Checklist', () => {
+ test('Checklist - Default ', () => {
+ const checklist = renderer.create(<Checklist items={items} onChange={() => { }} />).toJSON();
+ expect(checklist).toMatchSnapshot();
+ });
+
+ test('Checklist - With disabled items ', () => {
+ const checklist = renderer.create(<Checklist items={itemsDisabled} onChange={() => { }} />).toJSON();
+ expect(checklist).toMatchSnapshot();
+ });
+
+
+
+}); \ No newline at end of file
diff --git a/test/react/Input.spec.js b/test/react/Input.spec.js
new file mode 100644
index 0000000..3766e45
--- /dev/null
+++ b/test/react/Input.spec.js
@@ -0,0 +1,69 @@
+import React from 'react';
+import Input from '../../src/react/Input.js';
+
+import renderer from 'react-test-renderer';
+import {mount} from 'enzyme';
+
+class InputForm extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {value: 'Initial'};
+ this.handleChange = this.handleChange.bind(this);
+ }
+
+ handleChange(val) {
+ this.setState({value: val});
+ }
+
+ getValue() {
+ return this.input.getValue();
+ }
+
+ render() {
+ return (
+ <form >
+ <Input ref={(input)=>{this.input = input;}} value={this.state.value} name='testinput' onChange={this.handleChange} />
+ </form>
+ );
+ }
+}
+
+describe('Input', () => {
+ test('Input - default', () => {
+ const input = renderer.create(<Input label='label for input' name='clickme' type='text'/>).toJSON();
+ expect(input).toMatchSnapshot();
+ });
+
+ test('Input - required', () => {
+ const input = renderer.create(<Input required label='label for input' name='clickme' type='text'/>).toJSON();
+ expect(input).toMatchSnapshot();
+ });
+
+ test('Input - number', () => {
+ const input = renderer.create(<Input label='label for input' name='clickme' type='number'/>).toJSON();
+ expect(input).toMatchSnapshot();
+ });
+
+ test('Input - readonly', () => {
+ const input = renderer.create(<Input label='label for input' name='clickme' type='text' readOnly/>).toJSON();
+ expect(input).toMatchSnapshot();
+ });
+
+ test('Input - placeholder', () => {
+ const input = renderer.create(<Input label='label for input' name='clickme' type='text' placeholder='hint'/>).toJSON();
+ expect(input).toMatchSnapshot();
+ });
+
+ test('Input - error', () => {
+ const input = renderer.create(<Input label='label for input' name='clickme' type='text' errorMessage='this is an error'/>).toJSON();
+ expect(input).toMatchSnapshot();
+ });
+
+ test('Input - checked state value changes', () => {
+ const input = mount(<InputForm />);
+ expect(input.instance().getValue()).toEqual('Initial');
+ input.find('input').simulate('change', { target : { value: 'Changed' }});
+ expect(input.instance().getValue()).toEqual('Changed');
+ expect(input.find('input').prop('value')).toEqual('Changed');
+ });
+});
diff --git a/test/react/Modal.spec.js b/test/react/Modal.spec.js
new file mode 100644
index 0000000..7c4738f
--- /dev/null
+++ b/test/react/Modal.spec.js
@@ -0,0 +1,68 @@
+import React from 'react';
+import { mount, ReactWrapper } from 'enzyme';
+
+import Modal from '../../src/react/Modal';
+
+describe('Modal', () => {
+
+ const MODAL_MESSAGE = 'Message';
+ test('standard modal', ()=>{
+ const modal = new ReactWrapper(mount(<Modal show={true} size='small'>
+ <Modal.Header><Modal.Title>Standard Modal</Modal.Title></Modal.Header>
+ <Modal.Body>
+ {MODAL_MESSAGE}
+ </Modal.Body>
+ <Modal.Footer actionButtonText='Yes' actionButtonClick={()=>{}}/>
+ </Modal>).instance().modalRef, true);
+
+ expect(modal.find(Modal.Body).length).toBe(1);
+ expect(modal.find(Modal.Header).length).toBe(1);
+ expect(modal.find(Modal.Title).length).toBe(1);
+ expect(modal.find(Modal.Body).length).toBe(1);
+ expect(modal.find(Modal.Footer).length).toBe(1);
+ expect(modal.find(Modal.Header).props().type).toBe('info');
+ expect(modal.find(Modal.Body).text()).toBe(MODAL_MESSAGE);
+ expect(modal.html()).toMatchSnapshot();
+ });
+
+ test('standard modal - not displayed', ()=>{
+ const modal = new ReactWrapper(mount(<Modal show={false} size='small'>
+ <Modal.Header><Modal.Title>Standard Modal</Modal.Title></Modal.Header>
+ <Modal.Body>
+ {MODAL_MESSAGE}
+ </Modal.Body>
+ <Modal.Footer actionButtonText='Yes' actionButtonClick={()=>{}}/>
+ </Modal>).instance().modalRef, true);
+ expect(modal.find(Modal.Body).length).toBe(0);
+ expect(modal.html()).toMatchSnapshot();
+ });
+
+ test('alert modal', ()=>{
+ const modal = new ReactWrapper(mount(
+ <Modal show type='alert' size='small'>
+ <Modal.Header type='alert'><Modal.Title>Title</Modal.Title></Modal.Header>
+ <Modal.Body>
+ {MODAL_MESSAGE}
+ </Modal.Body>
+ <Modal.Footer closeButtonText='Ok'/>
+ </Modal>).instance().modalRef, true);
+ expect(modal.find(Modal.Body).text()).toBe(MODAL_MESSAGE);
+ expect(modal.find('.sdc-modal-type-alert').length).toBe(1);
+ expect(modal.html()).toMatchSnapshot();
+ });
+
+ test('custom modal', ()=>{
+ const modal = new ReactWrapper(mount(
+ <Modal show type='custom'>
+ <Modal.Header type='custom'><Modal.Title>Title</Modal.Title></Modal.Header>
+ <Modal.Body>
+ {MODAL_MESSAGE}
+ </Modal.Body>
+ <Modal.Footer actionButtonText='Ok' actionButtonClick={()=>{}}/>
+ </Modal>).instance().modalRef, true);
+ expect(modal.find(Modal.Body).text()).toBe(MODAL_MESSAGE);
+ expect(modal.find('.sdc-modal-type-custom').length).toBe(1);
+ expect(modal.html()).toMatchSnapshot();
+ });
+
+});
diff --git a/test/react/ModalBody.spec.js b/test/react/ModalBody.spec.js
new file mode 100644
index 0000000..d83c899
--- /dev/null
+++ b/test/react/ModalBody.spec.js
@@ -0,0 +1,11 @@
+import React from 'react';
+import ModalBody from '../../src/react/ModalBody.js';
+
+import renderer from 'react-test-renderer';
+
+describe('ModalBody', () => {
+ test('basic test', () => {
+ const header = renderer.create(<ModalBody/>).toJSON();
+ expect(header).toMatchSnapshot();
+ });
+}); \ No newline at end of file
diff --git a/test/react/ModalFooter.spec.js b/test/react/ModalFooter.spec.js
new file mode 100644
index 0000000..e4e3f5b
--- /dev/null
+++ b/test/react/ModalFooter.spec.js
@@ -0,0 +1,11 @@
+import React from 'react';
+import ModalFooter from '../../src/react/ModalFooter.js';
+
+import renderer from 'react-test-renderer';
+
+describe('ModalFooter', () => {
+ test('basic test', () => {
+ const footer = renderer.create(<ModalFooter closeButtonText='Ok'/>).toJSON();
+ expect(footer).toMatchSnapshot();
+ });
+}); \ No newline at end of file
diff --git a/test/react/ModalHeader.spec.js b/test/react/ModalHeader.spec.js
new file mode 100644
index 0000000..e9d0602
--- /dev/null
+++ b/test/react/ModalHeader.spec.js
@@ -0,0 +1,11 @@
+import React from 'react';
+import ModalHeader from '../../src/react/ModalHeader.js';
+
+import renderer from 'react-test-renderer';
+
+describe('ModalHeader', () => {
+ test('basic test', () => {
+ const header = renderer.create(<ModalHeader/>).toJSON();
+ expect(header).toMatchSnapshot();
+ });
+}); \ No newline at end of file
diff --git a/test/react/ModalTitle.spec.js b/test/react/ModalTitle.spec.js
new file mode 100644
index 0000000..a8cf2a3
--- /dev/null
+++ b/test/react/ModalTitle.spec.js
@@ -0,0 +1,11 @@
+import React from 'react';
+import ModalTitle from '../../src/react/ModalTitle.js';
+
+import renderer from 'react-test-renderer';
+
+describe('ModalTitle', () => {
+ test('basic test', () => {
+ const header = renderer.create(<ModalTitle>Title</ModalTitle>).toJSON();
+ expect(header).toMatchSnapshot();
+ });
+}); \ No newline at end of file
diff --git a/test/react/Panel.spec.js b/test/react/Panel.spec.js
new file mode 100644
index 0000000..acae6a9
--- /dev/null
+++ b/test/react/Panel.spec.js
@@ -0,0 +1,11 @@
+import React from 'react';
+import Panel from '../../src/react/Panel.js';
+
+import renderer from 'react-test-renderer';
+
+describe('Panel', () => {
+ test('Panel - Default', () => {
+ const panel = renderer.create(<Panel>Panel</Panel>).toJSON();
+ expect(panel).toMatchSnapshot();
+ });
+});
diff --git a/test/react/PopupMenu.spec.js b/test/react/PopupMenu.spec.js
new file mode 100644
index 0000000..5014728
--- /dev/null
+++ b/test/react/PopupMenu.spec.js
@@ -0,0 +1,62 @@
+import React from 'react';
+import PopupMenu from '../../src/react/PopupMenu.js';
+
+import renderer from 'react-test-renderer';
+import {mount} from 'enzyme';
+
+class MyPopupForm extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {position: {}};
+ }
+
+ handleClick(newPos) {
+ this.setState({position: newPos});
+ }
+
+ getPosition() {
+ return this.state.position;
+ }
+
+ render() {
+ return (
+ <form onClick={event => this.handleClick({
+ x: event.pageX - event.target.offsetLeft,
+ y: event.pageY - event.target.offsetTop
+ })}>
+ <PopupMenu position={this.state.position} relative onMenuItemClick={() => {}} />
+ </form>
+ );
+ }
+}
+
+describe('PopupMenu', () => {
+ test('check static menu rendered', () => {
+ const menu = renderer.create(<PopupMenu onMenuItemClick={() => {}}/>).toJSON();
+ expect(menu).toMatchSnapshot();
+ });
+
+ test('check relative menu rendered', () => {
+ const menu = renderer.create(<PopupMenu onMenuItemClick={()=> {}} position={{x: 10, y: 10}} relative/>).toJSON();
+ expect(menu).toMatchSnapshot();
+ });
+
+ test('check separator rendered', () => {
+ const separator = renderer.create(<PopupMenu.Separator/>).toJSON();
+ expect(separator).toMatchSnapshot();
+ });
+
+ test('check position changed', () => {
+ const menuForm = mount(<MyPopupForm />);
+ const position = menuForm.instance().getPosition();
+ expect(position).toEqual({});
+ expect(position).toEqual(menuForm.find('ul').props().style);
+ menuForm.find('form').simulate('click', {
+ target: {offsetLeft: 10, offsetTop: 20},
+ pageX: 30, pageY: 50
+ });
+ const newPosition = menuForm.instance().getPosition();
+ expect(newPosition).toEqual({x:20, y:30});
+ expect({left: newPosition.x, top: newPosition.y}).toEqual(menuForm.find('ul').props().style);
+ });
+}); \ No newline at end of file
diff --git a/test/react/PopupMenuItem.spec.js b/test/react/PopupMenuItem.spec.js
new file mode 100644
index 0000000..9262319
--- /dev/null
+++ b/test/react/PopupMenuItem.spec.js
@@ -0,0 +1,56 @@
+import React from 'react';
+import PopupMenuItem from '../../src/react/PopupMenuItem.js';
+import PopupMenu from '../../src/react/PopupMenu.js';
+
+import renderer from 'react-test-renderer';
+import {mount} from 'enzyme';
+
+describe('PopupMenuItem', () => {
+ test('check selected', () => {
+ const menuItem = renderer.create(<PopupMenuItem itemId='1' value='item 1' selected/>).toJSON();
+ expect(menuItem).toMatchSnapshot();
+ });
+
+ test('check disabled', () => {
+ const menuItem = renderer.create(<PopupMenuItem itemId='2' value='item 2' disabled/>).toJSON();
+ expect(menuItem).toMatchSnapshot();
+ });
+
+ test('check parent onclick invoked by child', () => {
+ const mockFunc = jest.fn();
+ const menu = mount(
+ <PopupMenu onMenuItemClick={mockFunc}>
+ <PopupMenuItem itemId='1' value='item 1'/>
+ </PopupMenu>
+ );
+ expect(menu.find('li')).toHaveLength(1);
+ menu.find('li').simulate('click');
+ expect(mockFunc).toHaveBeenCalled();
+ });
+
+ test('check custom onclick invoked by child', () => {
+ const mockParentFunc = jest.fn();
+ const mockChildFunc = jest.fn();
+ const menu = mount(
+ <PopupMenu onMenuItemClick={mockParentFunc}>
+ <PopupMenuItem itemId='1' value='item 1' onClick={mockChildFunc}/>
+ </PopupMenu>
+ );
+ expect(menu.find('li')).toHaveLength(1);
+ menu.find('li').simulate('click');
+ expect(mockChildFunc).toHaveBeenCalled();
+ expect(mockParentFunc).not.toHaveBeenCalled();
+ });
+
+ test('check no click handler if item is disabled', () => {
+ const mockFunc = jest.fn();
+ const menu = mount(
+ <PopupMenu onMenuItemClick={mockFunc}>
+ <PopupMenuItem itemId='1' value='item 1' disabled/>
+ </PopupMenu>
+ );
+ expect(menu.find('li')).toHaveLength(1);
+ menu.find('li').simulate('click');
+ expect(mockFunc).not.toHaveBeenCalled();
+ });
+}); \ No newline at end of file
diff --git a/test/react/Portal.spec.js b/test/react/Portal.spec.js
new file mode 100644
index 0000000..864b342
--- /dev/null
+++ b/test/react/Portal.spec.js
@@ -0,0 +1,10 @@
+import React from 'react';
+import {mount} from 'enzyme';
+import Portal from '../../src/react/Portal';
+
+describe('Portal',()=>{
+ test('portal basic', ()=>{
+ const portal = mount(<Portal><strong>Message</strong></Portal>);
+ expect(portal.find(Portal).exists()).toBe(true);
+ });
+}); \ No newline at end of file
diff --git a/test/react/Radio.spec.js b/test/react/Radio.spec.js
new file mode 100644
index 0000000..39e33f7
--- /dev/null
+++ b/test/react/Radio.spec.js
@@ -0,0 +1,60 @@
+import React from 'react';
+import Radio from '../../src/react/Radio.js';
+
+import renderer from 'react-test-renderer';
+import {mount} from 'enzyme';
+
+class RadioForm extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {checked: false};
+
+ this.handleChange = this.handleChange.bind(this);
+ }
+
+ handleChange(val) {
+ this.setState({checked: val});
+ }
+
+ getChecked() {
+ return this.radio.getChecked();
+ }
+
+ render() {
+ return (
+ <form >
+ <Radio ref={(radio)=>{this.radio = radio;}} name='grp1' checked={this.state.checked} label='This is the radio label' value='1' onChange={this.handleChange} />
+ </form>
+ );
+ }
+}
+
+describe('Radio', () => {
+ test('Radio - unchecked', () => {
+ const radio = renderer.create(<Radio name='grp4' label='This is the radio label' value='1' />).toJSON();
+ expect(radio).toMatchSnapshot();
+ });
+
+ test('Radio - disabled', () => {
+ const radio = renderer.create(<Radio name='grp2' disabled={true} label='This is the radio label' value='1' />).toJSON();
+ expect(radio).toMatchSnapshot();
+ });
+
+ test('Radio - checked state changes', () => {
+ const radio = mount(<RadioForm />);
+ expect(radio.instance().getChecked()).toEqual(false);
+ expect(radio.instance().getChecked()).toEqual(radio.find('input').props().checked);
+ radio.find('input').simulate('change', { target : { checked: true }});
+ expect(radio.instance().getChecked()).toEqual(true);
+ expect(radio.instance().getChecked()).toEqual(radio.find('input').props().checked);
+ radio.find('input').simulate('change', { target : { checked: false }});
+ expect(radio.instance().getChecked()).toEqual(false);
+ expect(radio.instance().getChecked()).toEqual(radio.find('input').props().checked);
+ });
+
+ test('Radio - returns its value', () => {
+ const radio = mount(<Radio label='This is the radio label' value='myVal' />);
+ expect(radio.instance().getValue()).toEqual('myVal');
+ });
+
+});
diff --git a/test/react/RadioGroup.spec.js b/test/react/RadioGroup.spec.js
new file mode 100644
index 0000000..638b9c4
--- /dev/null
+++ b/test/react/RadioGroup.spec.js
@@ -0,0 +1,69 @@
+import React from 'react';
+import RadioGroup from '../../src/react/RadioGroup.js';
+
+import renderer from 'react-test-renderer';
+import {mount} from 'enzyme';
+
+class RadioGroupForm extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {value: undefined};
+ this.handleChange = this.handleChange.bind(this);
+ }
+
+ handleChange(val) {
+ this.setState({value: val});
+ }
+
+ getValue() {
+ return this.grp.getValue();
+ }
+
+ render() {
+ return (
+ <form >
+ <RadioGroup name='grp1' title='Group A' value={this.state.value} ref={(grp) => { this.grp = grp;}} onChange={this.handleChange} data-test-id='grp1'
+ options={[{value: '1', label: 'option 1'}, {value: '2', label: 'option 2'}]} />
+ </form>
+ );
+ }
+}
+
+describe('RadioGroup', () => {
+ test('RadioGroup - basic rendering', () => {
+ const radio = renderer.create(<RadioGroup name='grp1' defaultValue='2' value='1' title='Group A'
+ onChange={()=>{}} data-test-id='grp1'
+ options={[{value: '1', label: 'option 1'}, {value: '2', label: 'option 2'}]} />).toJSON();
+ expect(radio).toMatchSnapshot();
+ });
+
+ test('RadioGroup - value overrides default value', () => {
+ const radio = mount(<RadioGroup name='grp1' defaultValue='2' value='1' title='Group A'
+ onChange={()=>{}} data-test-id='grp1'
+ options={[{value: '1', label: 'option 1'}, {value: '2', label: 'option 2'}]} />);
+ expect(radio.instance().getValue()).toEqual('1');
+ });
+
+ test('RadioGroup - can have no value', () => {
+ const radio = mount(<RadioGroup name='grp1' title='Group A'
+ onChange={()=>{}} data-test-id='grp1'
+ options={[{value: '1', label: 'option 1'}, {value: '2', label: 'option 2'}]} />);
+ expect(radio.instance().getValue()).toEqual(undefined);
+ });
+
+ test('RadioGroup - can be rendered without title', () => {
+ const radio = mount(<RadioGroup name='grp1'
+ onChange={()=>{}} data-test-id='grp1'
+ options={[{value: '1', label: 'option 1'}, {value: '2', label: 'option 2'}]} />);
+ expect(radio.find('.sdc-radio-group__legend').length).toEqual(0);
+ });
+
+ test('RadioGroup - value changes', () => {
+ const radio = mount(<RadioGroupForm />);
+ expect(radio.instance().getValue()).toEqual(undefined);
+ radio.find('input[value="1"]').simulate('change', { target : { checked: true }});
+ expect(radio.instance().getValue()).toEqual('1');
+ radio.find('input[value="2"]').simulate('change', { target : { checked: true }});
+ expect(radio.instance().getValue()).toEqual('2');
+ });
+});
diff --git a/test/react/Tabs.spec.js b/test/react/Tabs.spec.js
new file mode 100644
index 0000000..9906708
--- /dev/null
+++ b/test/react/Tabs.spec.js
@@ -0,0 +1,55 @@
+import React from 'react';
+import Tab from '../../src/react/Tab.js';
+import Tabs from '../../src/react/Tabs.js';
+
+import renderer from 'react-test-renderer';
+import {mount} from 'enzyme';
+
+class TabsForm extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {tabId: '1'};
+
+ this.handleChange = this.handleChange.bind(this);
+ }
+
+ handleChange(val) {
+ this.setState({tabId: val});
+ }
+
+ render() {
+ return (
+ <form >
+ <fieldset disabled={this.props.disabled}>
+ <Tabs ref={(tabs) => this.tabsInst = tabs} activeTab={this.state.tabId} onTabClick={this.handleChange} >
+ <Tab title='tab 1' tabId='1' data-test-id='1'>Tab #1</Tab>
+ <Tab title='tab 2' tabId='2' data-test-id='2'>Tab #2</Tab>
+ <Tab title='tab 3' tabId='3' data-test-id='3'>Tab #3</Tab>
+ </Tabs>
+ </fieldset>
+
+ </form>
+ );
+ }
+}
+
+describe('Tabs', () => {
+
+ test('Tabs - basic rendering', () => {
+ const tabs = renderer.create(<TabsForm disabled={false} />).toJSON();
+ expect(tabs).toMatchSnapshot();
+ });
+
+ test('Tabs - when active tab id is changed, the respective tab is shown', () => {
+ const tabs = mount(<TabsForm disabled={false} />);
+ expect(tabs.instance().tabsInst.props.activeTab).toEqual('1');
+ expect(tabs.find('.sdc-tab-content').text()).toEqual('Tab #1');
+ expect(tabs.find('li[data-test-id="1"]').hasClass('sdc-tab-active')).toBeTruthy();
+ tabs.find('li[data-test-id="2"]').simulate('click');
+ expect(tabs.instance().tabsInst.props.activeTab).toEqual('2');
+ expect(tabs.find('li[data-test-id="2"]').hasClass('sdc-tab-active')).toBeTruthy();
+ expect(tabs.find('li[data-test-id="1"]').hasClass('sdc-tab-active')).not.toBeTruthy();
+ expect(tabs.find('.sdc-tab-content').text()).toEqual('Tab #2');
+ });
+
+});
diff --git a/test/react/Tile.spec.js b/test/react/Tile.spec.js
new file mode 100644
index 0000000..7ce98a8
--- /dev/null
+++ b/test/react/Tile.spec.js
@@ -0,0 +1,30 @@
+import React from 'react';
+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 renderer from 'react-test-renderer';
+
+describe('Tile', () => {
+ test('Empty tile', () => {
+ const tile = renderer.create(<Tile />).toJSON();
+ expect(tile).toMatchSnapshot();
+ });
+
+ test('Tile with props', () => {
+ const tile = renderer.create(<Tile headerText='header' headerColor='blue' iconName='vlm' iconColor='blue' />).toJSON();
+ expect(tile).toMatchSnapshot();
+ });
+
+ test('Tile with content info', () => {
+ const tile = renderer.create(<Tile><TileInfo align='center'><TileInfoLine type='title'>Info</TileInfoLine></TileInfo></Tile>).toJSON();
+ expect(tile).toMatchSnapshot();
+ });
+
+ test('Tile with footer', () => {
+ const tile = renderer.create(<Tile><TileFooter align='center'><TileFooterCell>Footer</TileFooterCell></TileFooter></Tile>).toJSON();
+ expect(tile).toMatchSnapshot();
+ });
+});
diff --git a/test/react/__snapshots__/Accordion.spec.js.snap b/test/react/__snapshots__/Accordion.spec.js.snap
new file mode 100644
index 0000000..fe75ada
--- /dev/null
+++ b/test/react/__snapshots__/Accordion.spec.js.snap
@@ -0,0 +1,32 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Accordion Accordion - Default 1`] = `
+<div
+ className="sdc-accordion "
+>
+ <div
+ className="sdc-accordion-header"
+ data-test-id={undefined}
+ onClick={[Function]}
+ >
+ <div
+ className="svg-icon-wrapper bottom"
+ disabled={undefined}
+ onClick={undefined}
+ >
+ <svg />
+
+ </div>
+ <div
+ className="title"
+ >
+ Accordion
+ </div>
+ </div>
+ <div
+ className="sdc-accordion-body "
+ >
+ Accordion body
+ </div>
+</div>
+`;
diff --git a/test/react/__snapshots__/Button.spec.js.snap b/test/react/__snapshots__/Button.spec.js.snap
new file mode 100644
index 0000000..16e13bc
--- /dev/null
+++ b/test/react/__snapshots__/Button.spec.js.snap
@@ -0,0 +1,163 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Button Button - Default - Gray 1`] = `
+<button
+ className="sdc-button sdc-button__primary "
+ color="gray"
+ disabled={false}
+ onClick={undefined}
+>
+ Click Me
+</button>
+`;
+
+exports[`Button Button - Default - Negative 1`] = `
+<button
+ className="sdc-button sdc-button__primary "
+ color="negative"
+ disabled={false}
+ onClick={undefined}
+>
+ Click Me
+</button>
+`;
+
+exports[`Button Button - Default - Positive 1`] = `
+<button
+ className="sdc-button sdc-button__primary "
+ color="positive"
+ disabled={false}
+ onClick={undefined}
+>
+ Click Me
+</button>
+`;
+
+exports[`Button Button - Default - Primary - Disabled 1`] = `
+<button
+ className="sdc-button sdc-button__primary "
+ disabled={true}
+ onClick={undefined}
+>
+ Click Me
+</button>
+`;
+
+exports[`Button Button - Default - Primary 1`] = `
+<button
+ className="sdc-button sdc-button__primary "
+ disabled={false}
+ onClick={undefined}
+>
+ Click Me
+</button>
+`;
+
+exports[`Button Button - Default - Warning 1`] = `
+<button
+ className="sdc-button sdc-button__primary "
+ color="warning"
+ disabled={false}
+ onClick={undefined}
+>
+ Click Me
+</button>
+`;
+
+exports[`Button Button - Default - White 1`] = `
+<button
+ className="sdc-button sdc-button__primary "
+ color="white"
+ disabled={false}
+ onClick={undefined}
+>
+ Click Me
+</button>
+`;
+
+exports[`Button Button - Link - Primary - Disabled 1`] = `
+<button
+ className="sdc-button sdc-button__link "
+ color="primary"
+ disabled={true}
+ onClick={undefined}
+>
+ Click Me
+</button>
+`;
+
+exports[`Button Button - Link - Primary - With Icon 1`] = `
+<button
+ className="sdc-button sdc-button__link plus"
+ color="primary"
+ disabled={false}
+ onClick={undefined}
+>
+ <div
+ className="svg-icon-wrapper right"
+ disabled={undefined}
+ onClick={undefined}
+ >
+ <svg />
+ <span
+ className="svg-icon-label "
+ >
+ Click Me
+ </span>
+ </div>
+</button>
+`;
+
+exports[`Button Button - Link - Primary 1`] = `
+<button
+ className="sdc-button sdc-button__link "
+ color="primary"
+ disabled={false}
+ onClick={undefined}
+>
+ Click Me
+</button>
+`;
+
+exports[`Button Button - Outline - Gray 1`] = `
+<button
+ className="sdc-button sdc-button__outline "
+ color="gray"
+ disabled={false}
+ onClick={undefined}
+>
+ Click Me
+</button>
+`;
+
+exports[`Button Button - Outline - Negative 1`] = `
+<button
+ className="sdc-button sdc-button__outline "
+ color="negative"
+ disabled={false}
+ onClick={undefined}
+>
+ Click Me
+</button>
+`;
+
+exports[`Button Button - Outline - Positive 1`] = `
+<button
+ className="sdc-button sdc-button__outline "
+ color="positive"
+ disabled={false}
+ onClick={undefined}
+>
+ Click Me
+</button>
+`;
+
+exports[`Button Button - Outline - Primary 1`] = `
+<button
+ className="sdc-button sdc-button__outline "
+ disabled={false}
+ onClick={undefined}
+>
+ Click Me
+</button>
+`;
diff --git a/test/react/__snapshots__/Checkbox.spec.js.snap b/test/react/__snapshots__/Checkbox.spec.js.snap
new file mode 100644
index 0000000..fa6239b
--- /dev/null
+++ b/test/react/__snapshots__/Checkbox.spec.js.snap
@@ -0,0 +1,49 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Checkbox Checkbox - disabled 1`] = `
+<div
+ className="sdc-checkbox "
+>
+ <label>
+ <input
+ checked={false}
+ className="sdc-checkbox__input"
+ data-test-id={undefined}
+ disabled={true}
+ name={undefined}
+ onChange={[Function]}
+ type="checkbox"
+ value={undefined}
+ />
+ <span
+ className="sdc-checkbox__label"
+ >
+ This is the checkbox label
+ </span>
+ </label>
+</div>
+`;
+
+exports[`Checkbox Checkbox - unchecked 1`] = `
+<div
+ className="sdc-checkbox "
+>
+ <label>
+ <input
+ checked={false}
+ className="sdc-checkbox__input"
+ data-test-id={undefined}
+ disabled={undefined}
+ name={undefined}
+ onChange={[Function]}
+ type="checkbox"
+ value={undefined}
+ />
+ <span
+ className="sdc-checkbox__label"
+ >
+ This is the checkbox label
+ </span>
+ </label>
+</div>
+`;
diff --git a/test/react/__snapshots__/Checklist.spec.js.snap b/test/react/__snapshots__/Checklist.spec.js.snap
new file mode 100644
index 0000000..707e910
--- /dev/null
+++ b/test/react/__snapshots__/Checklist.spec.js.snap
@@ -0,0 +1,165 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Checklist Checklist - Default 1`] = `
+<div
+ className={undefined}
+>
+ <div
+ className="checkbox-item"
+ >
+ <div
+ className="sdc-checkbox "
+ >
+ <label>
+ <input
+ checked={true}
+ className="sdc-checkbox__input"
+ data-test-id="apple"
+ disabled={undefined}
+ name={undefined}
+ onChange={[Function]}
+ type="checkbox"
+ value="apple"
+ />
+ <span
+ className="sdc-checkbox__label"
+ >
+ apple
+ </span>
+ </label>
+ </div>
+ </div>
+ <div
+ className="checkbox-item"
+ >
+ <div
+ className="sdc-checkbox "
+ >
+ <label>
+ <input
+ checked={false}
+ className="sdc-checkbox__input"
+ data-test-id="banana"
+ disabled={undefined}
+ name={undefined}
+ onChange={[Function]}
+ type="checkbox"
+ value="banana"
+ />
+ <span
+ className="sdc-checkbox__label"
+ >
+ banana
+ </span>
+ </label>
+ </div>
+ </div>
+ <div
+ className="checkbox-item"
+ >
+ <div
+ className="sdc-checkbox "
+ >
+ <label>
+ <input
+ checked={true}
+ className="sdc-checkbox__input"
+ data-test-id="orange"
+ disabled={undefined}
+ name={undefined}
+ onChange={[Function]}
+ type="checkbox"
+ value="orange"
+ />
+ <span
+ className="sdc-checkbox__label"
+ >
+ orange
+ </span>
+ </label>
+ </div>
+ </div>
+</div>
+`;
+
+exports[`Checklist Checklist - With disabled items 1`] = `
+<div
+ className={undefined}
+>
+ <div
+ className="checkbox-item"
+ >
+ <div
+ className="sdc-checkbox "
+ >
+ <label>
+ <input
+ checked={true}
+ className="sdc-checkbox__input"
+ data-test-id="apple"
+ disabled={true}
+ name={undefined}
+ onChange={[Function]}
+ type="checkbox"
+ value="apple"
+ />
+ <span
+ className="sdc-checkbox__label"
+ >
+ apple
+ </span>
+ </label>
+ </div>
+ </div>
+ <div
+ className="checkbox-item"
+ >
+ <div
+ className="sdc-checkbox "
+ >
+ <label>
+ <input
+ checked={false}
+ className="sdc-checkbox__input"
+ data-test-id="banana"
+ disabled={true}
+ name={undefined}
+ onChange={[Function]}
+ type="checkbox"
+ value="banana"
+ />
+ <span
+ className="sdc-checkbox__label"
+ >
+ banana
+ </span>
+ </label>
+ </div>
+ </div>
+ <div
+ className="checkbox-item"
+ >
+ <div
+ className="sdc-checkbox "
+ >
+ <label>
+ <input
+ checked={false}
+ className="sdc-checkbox__input"
+ data-test-id="orange"
+ disabled={undefined}
+ name={undefined}
+ onChange={[Function]}
+ type="checkbox"
+ value="orange"
+ />
+ <span
+ className="sdc-checkbox__label"
+ >
+ orange
+ </span>
+ </label>
+ </div>
+ </div>
+</div>
+`;
diff --git a/test/react/__snapshots__/Input.spec.js.snap b/test/react/__snapshots__/Input.spec.js.snap
new file mode 100644
index 0000000..62c3e2e
--- /dev/null
+++ b/test/react/__snapshots__/Input.spec.js.snap
@@ -0,0 +1,179 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Input Input - default 1`] = `
+<div
+ className="sdc-input "
+>
+ <label
+ className="sdc-input__label "
+ htmlFor="clickme"
+ >
+ label for input
+ </label>
+ <input
+ className="sdc-input__input "
+ data-test-id={undefined}
+ disabled={false}
+ id="clickme"
+ name="clickme"
+ onBlur={[Function]}
+ onChange={[Function]}
+ onKeyDown={[Function]}
+ placeholder={undefined}
+ readOnly={false}
+ type="text"
+ value={undefined}
+ />
+</div>
+`;
+
+exports[`Input Input - error 1`] = `
+<div
+ className="sdc-input "
+>
+ <label
+ className="sdc-input__label "
+ htmlFor="clickme"
+ >
+ label for input
+ </label>
+ <input
+ className="sdc-input__input error "
+ data-test-id={undefined}
+ disabled={false}
+ id="clickme"
+ name="clickme"
+ onBlur={[Function]}
+ onChange={[Function]}
+ onKeyDown={[Function]}
+ placeholder={undefined}
+ readOnly={false}
+ type="text"
+ value={undefined}
+ />
+ <div
+ className="sdc-label__error"
+ >
+ <div
+ className="svg-icon-wrapper __negative right"
+ disabled={undefined}
+ onClick={undefined}
+ >
+ <svg />
+ <span
+ className="svg-icon-label "
+ >
+ this is an error
+ </span>
+ </div>
+ </div>
+</div>
+`;
+
+exports[`Input Input - number 1`] = `
+<div
+ className="sdc-input "
+>
+ <label
+ className="sdc-input__label "
+ htmlFor="clickme"
+ >
+ label for input
+ </label>
+ <input
+ className="sdc-input__input "
+ data-test-id={undefined}
+ disabled={false}
+ id="clickme"
+ name="clickme"
+ onBlur={[Function]}
+ onChange={[Function]}
+ onKeyDown={[Function]}
+ placeholder={undefined}
+ readOnly={false}
+ type="number"
+ value={undefined}
+ />
+</div>
+`;
+
+exports[`Input Input - placeholder 1`] = `
+<div
+ className="sdc-input "
+>
+ <label
+ className="sdc-input__label "
+ htmlFor="clickme"
+ >
+ label for input
+ </label>
+ <input
+ className="sdc-input__input "
+ data-test-id={undefined}
+ disabled={false}
+ id="clickme"
+ name="clickme"
+ onBlur={[Function]}
+ onChange={[Function]}
+ onKeyDown={[Function]}
+ placeholder="hint"
+ readOnly={false}
+ type="text"
+ value={undefined}
+ />
+</div>
+`;
+
+exports[`Input Input - readonly 1`] = `
+<div
+ className="sdc-input "
+>
+ <label
+ className="sdc-input__label view-only "
+ htmlFor="clickme"
+ >
+ label for input
+ </label>
+ <input
+ className="sdc-input__input view-only"
+ data-test-id={undefined}
+ disabled={false}
+ id="clickme"
+ name="clickme"
+ onBlur={[Function]}
+ onChange={[Function]}
+ onKeyDown={[Function]}
+ placeholder={undefined}
+ readOnly={true}
+ type="text"
+ value={undefined}
+ />
+</div>
+`;
+
+exports[`Input Input - required 1`] = `
+<div
+ className="sdc-input "
+>
+ <label
+ className="sdc-input__label "
+ htmlFor="clickme"
+ >
+ label for input
+ </label>
+ <input
+ className="sdc-input__input "
+ data-test-id={undefined}
+ disabled={false}
+ id="clickme"
+ name="clickme"
+ onBlur={[Function]}
+ onChange={[Function]}
+ onKeyDown={[Function]}
+ placeholder={undefined}
+ readOnly={false}
+ type="text"
+ value={undefined}
+ />
+</div>
+`;
diff --git a/test/react/__snapshots__/Modal.spec.js.snap b/test/react/__snapshots__/Modal.spec.js.snap
new file mode 100644
index 0000000..c22da8d
--- /dev/null
+++ b/test/react/__snapshots__/Modal.spec.js.snap
@@ -0,0 +1,9 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Modal alert modal 1`] = `"<div><div class=\\"sdc-modal sm\\"><div class=\\"sdc-modal__wrapper sdc-modal-type-alert\\"><div class=\\"sdc-alert__header sdc-modal__header\\"><div class=\\"svg-icon-wrapper sdc-modal__icon sdc-modal__svg-use bottom\\"><svg></svg><!-- react-text: 7 --><!-- /react-text --></div><div class=\\"title \\">Title</div><div class=\\"svg-icon-wrapper sdc-modal__close-button-svg sdc-modal__close-button bottom\\"><svg></svg><!-- react-text: 11 --><!-- /react-text --></div></div><div class=\\"sdc-modal__content \\">Message</div><div class=\\"sdc-modal__footer\\"><div><button class=\\"sdc-button sdc-button__primary \\">Ok</button></div></div></div></div><div class=\\"modal-background\\"></div></div>"`;
+
+exports[`Modal custom modal 1`] = `"<div><div class=\\"sdc-modal md\\"><div class=\\"sdc-modal__wrapper sdc-modal-type-custom\\"><div class=\\"sdc-custom__header sdc-modal__header\\"><div class=\\"title \\">Title</div><div class=\\"svg-icon-wrapper sdc-modal__close-button-svg sdc-modal__close-button bottom\\"><svg></svg><!-- react-text: 8 --><!-- /react-text --></div></div><div class=\\"sdc-modal__content \\">Message</div><div class=\\"sdc-modal__footer\\"><div><button class=\\"sdc-button sdc-button__primary \\">Ok</button><button class=\\"sdc-button sdc-button__secondary \\">Close</button></div></div></div></div><div class=\\"modal-background\\"></div></div>"`;
+
+exports[`Modal standard modal - not displayed 1`] = `"<div></div>"`;
+
+exports[`Modal standard modal 1`] = `"<div><div class=\\"sdc-modal sm\\"><div class=\\"sdc-modal__wrapper sdc-modal-type-info\\"><div class=\\"sdc-info__header sdc-modal__header\\"><div class=\\"svg-icon-wrapper sdc-modal__icon sdc-modal__svg-use bottom\\"><svg></svg><!-- react-text: 7 --><!-- /react-text --></div><div class=\\"title \\">Standard Modal</div><div class=\\"svg-icon-wrapper sdc-modal__close-button-svg sdc-modal__close-button bottom\\"><svg></svg><!-- react-text: 11 --><!-- /react-text --></div></div><div class=\\"sdc-modal__content \\">Message</div><div class=\\"sdc-modal__footer\\"><div><button class=\\"sdc-button sdc-button__primary \\">Yes</button><button class=\\"sdc-button sdc-button__secondary \\">Close</button></div></div></div></div><div class=\\"modal-background\\"></div></div>"`;
diff --git a/test/react/__snapshots__/ModalBody.spec.js.snap b/test/react/__snapshots__/ModalBody.spec.js.snap
new file mode 100644
index 0000000..d0fda4d
--- /dev/null
+++ b/test/react/__snapshots__/ModalBody.spec.js.snap
@@ -0,0 +1,7 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ModalBody basic test 1`] = `
+<div
+ className="sdc-modal__content "
+/>
+`;
diff --git a/test/react/__snapshots__/ModalFooter.spec.js.snap b/test/react/__snapshots__/ModalFooter.spec.js.snap
new file mode 100644
index 0000000..ee98355
--- /dev/null
+++ b/test/react/__snapshots__/ModalFooter.spec.js.snap
@@ -0,0 +1,17 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ModalFooter basic test 1`] = `
+<div
+ className="sdc-modal__footer"
+>
+ <div>
+ <button
+ className="sdc-button sdc-button__primary "
+ disabled={false}
+ onClick={undefined}
+ >
+ Ok
+ </button>
+ </div>
+</div>
+`;
diff --git a/test/react/__snapshots__/ModalHeader.spec.js.snap b/test/react/__snapshots__/ModalHeader.spec.js.snap
new file mode 100644
index 0000000..8559925
--- /dev/null
+++ b/test/react/__snapshots__/ModalHeader.spec.js.snap
@@ -0,0 +1,24 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ModalHeader basic test 1`] = `
+<div
+ className="sdc-info__header sdc-modal__header"
+>
+ <div
+ className="svg-icon-wrapper sdc-modal__icon sdc-modal__svg-use bottom"
+ disabled={undefined}
+ onClick={undefined}
+ >
+ <svg />
+
+ </div>
+ <div
+ className="svg-icon-wrapper sdc-modal__close-button-svg sdc-modal__close-button bottom"
+ disabled={undefined}
+ onClick={undefined}
+ >
+ <svg />
+
+ </div>
+</div>
+`;
diff --git a/test/react/__snapshots__/ModalTitle.spec.js.snap b/test/react/__snapshots__/ModalTitle.spec.js.snap
new file mode 100644
index 0000000..69a7734
--- /dev/null
+++ b/test/react/__snapshots__/ModalTitle.spec.js.snap
@@ -0,0 +1,9 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ModalTitle basic test 1`] = `
+<div
+ className="title "
+>
+ Title
+</div>
+`;
diff --git a/test/react/__snapshots__/Panel.spec.js.snap b/test/react/__snapshots__/Panel.spec.js.snap
new file mode 100644
index 0000000..b31dda7
--- /dev/null
+++ b/test/react/__snapshots__/Panel.spec.js.snap
@@ -0,0 +1,9 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Panel Panel - Default 1`] = `
+<div
+ className="sdc-panel "
+>
+ Panel
+</div>
+`;
diff --git a/test/react/__snapshots__/PopupMenu.spec.js.snap b/test/react/__snapshots__/PopupMenu.spec.js.snap
new file mode 100644
index 0000000..7a9060f
--- /dev/null
+++ b/test/react/__snapshots__/PopupMenu.spec.js.snap
@@ -0,0 +1,26 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`PopupMenu check relative menu rendered 1`] = `
+<ul
+ className="sdc-menu-list relative"
+ style={
+ Object {
+ "left": 10,
+ "top": 10,
+ }
+ }
+/>
+`;
+
+exports[`PopupMenu check separator rendered 1`] = `
+<li
+ className="separator"
+/>
+`;
+
+exports[`PopupMenu check static menu rendered 1`] = `
+<ul
+ className="sdc-menu-list "
+ style={Object {}}
+/>
+`;
diff --git a/test/react/__snapshots__/PopupMenuItem.spec.js.snap b/test/react/__snapshots__/PopupMenuItem.spec.js.snap
new file mode 100644
index 0000000..3334afb
--- /dev/null
+++ b/test/react/__snapshots__/PopupMenuItem.spec.js.snap
@@ -0,0 +1,19 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`PopupMenuItem check disabled 1`] = `
+<li
+ className="sdc-menu-item disabled"
+ onClick={[Function]}
+>
+ item 2
+</li>
+`;
+
+exports[`PopupMenuItem check selected 1`] = `
+<li
+ className="sdc-menu-item selected"
+ onClick={[Function]}
+>
+ item 1
+</li>
+`;
diff --git a/test/react/__snapshots__/Radio.spec.js.snap b/test/react/__snapshots__/Radio.spec.js.snap
new file mode 100644
index 0000000..a878d3a
--- /dev/null
+++ b/test/react/__snapshots__/Radio.spec.js.snap
@@ -0,0 +1,49 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Radio Radio - disabled 1`] = `
+<div
+ className="sdc-radio "
+>
+ <label>
+ <input
+ checked={false}
+ className="sdc-radio__input"
+ data-test-id={undefined}
+ disabled={true}
+ name="grp2"
+ onChange={[Function]}
+ type="radio"
+ value="1"
+ />
+ <span
+ className="sdc-radio__label"
+ >
+ This is the radio label
+ </span>
+ </label>
+</div>
+`;
+
+exports[`Radio Radio - unchecked 1`] = `
+<div
+ className="sdc-radio "
+>
+ <label>
+ <input
+ checked={false}
+ className="sdc-radio__input"
+ data-test-id={undefined}
+ disabled={undefined}
+ name="grp4"
+ onChange={[Function]}
+ type="radio"
+ value="1"
+ />
+ <span
+ className="sdc-radio__label"
+ >
+ This is the radio label
+ </span>
+ </label>
+</div>
+`;
diff --git a/test/react/__snapshots__/RadioGroup.spec.js.snap b/test/react/__snapshots__/RadioGroup.spec.js.snap
new file mode 100644
index 0000000..caf729d
--- /dev/null
+++ b/test/react/__snapshots__/RadioGroup.spec.js.snap
@@ -0,0 +1,60 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`RadioGroup RadioGroup - basic rendering 1`] = `
+<div
+ className="sdc-radio-group "
+ data-test-id="grp1"
+>
+ <label
+ className="sdc-radio-group__legend"
+ >
+ Group A
+ </label>
+ <div
+ className="sdc-radio-group__radios"
+ >
+ <div
+ className="sdc-radio "
+ >
+ <label>
+ <input
+ checked={true}
+ className="sdc-radio__input"
+ data-test-id="grp1_1"
+ disabled={undefined}
+ name="grp1"
+ onChange={[Function]}
+ type="radio"
+ value="1"
+ />
+ <span
+ className="sdc-radio__label"
+ >
+ option 1
+ </span>
+ </label>
+ </div>
+ <div
+ className="sdc-radio "
+ >
+ <label>
+ <input
+ checked={false}
+ className="sdc-radio__input"
+ data-test-id="grp1_2"
+ disabled={undefined}
+ name="grp1"
+ onChange={[Function]}
+ type="radio"
+ value="2"
+ />
+ <span
+ className="sdc-radio__label"
+ >
+ option 2
+ </span>
+ </label>
+ </div>
+ </div>
+</div>
+`;
diff --git a/test/react/__snapshots__/Tabs.spec.js.snap b/test/react/__snapshots__/Tabs.spec.js.snap
new file mode 100644
index 0000000..9a4d0a1
--- /dev/null
+++ b/test/react/__snapshots__/Tabs.spec.js.snap
@@ -0,0 +1,52 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Tabs Tabs - basic rendering 1`] = `
+<form>
+ <fieldset
+ disabled={false}
+ >
+ <div
+ className="sdc-tabs sdc-tabs-menu "
+ >
+ <ul
+ className="sdc-tabs-list"
+ role="tablist"
+ >
+ <li
+ className="sdc-tab sdc-tab-active "
+ data-test-id="1"
+ disabled={undefined}
+ onClick={[Function]}
+ role="tab"
+ >
+ tab 1
+ </li>
+ <li
+ className="sdc-tab "
+ data-test-id="2"
+ disabled={undefined}
+ onClick={[Function]}
+ role="tab"
+ >
+ tab 2
+ </li>
+ <li
+ className="sdc-tab "
+ data-test-id="3"
+ disabled={undefined}
+ onClick={[Function]}
+ role="tab"
+ >
+ tab 3
+ </li>
+ </ul>
+ <div
+ className="sdc-tab-content"
+ role="tabpanel"
+ >
+ Tab #1
+ </div>
+ </div>
+ </fieldset>
+</form>
+`;
diff --git a/test/react/__snapshots__/Tile.spec.js.snap b/test/react/__snapshots__/Tile.spec.js.snap
new file mode 100644
index 0000000..e38ffa2
--- /dev/null
+++ b/test/react/__snapshots__/Tile.spec.js.snap
@@ -0,0 +1,108 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Tile Empty tile 1`] = `
+<div
+ className="sdc-tile "
+ data-test-id={undefined}
+ onClick={undefined}
+>
+ <div
+ className="sdc-tile-header "
+ />
+ <div
+ className="sdc-tile-content"
+ >
+ <div
+ className="sdc-tile-content-icon "
+ />
+ </div>
+</div>
+`;
+
+exports[`Tile Tile with content info 1`] = `
+<div
+ className="sdc-tile "
+ data-test-id={undefined}
+ onClick={undefined}
+>
+ <div
+ className="sdc-tile-header "
+ />
+ <div
+ className="sdc-tile-content"
+ >
+ <div
+ className="sdc-tile-content-icon "
+ />
+ <div
+ className="sdc-tile-content-info centered"
+ >
+ <div
+ className="sdc-tile-info-line title "
+ data-test-id={undefined}
+ >
+ Info
+ </div>
+ </div>
+ </div>
+</div>
+`;
+
+exports[`Tile Tile with footer 1`] = `
+<div
+ className="sdc-tile "
+ data-test-id={undefined}
+ onClick={undefined}
+>
+ <div
+ className="sdc-tile-header "
+ />
+ <div
+ className="sdc-tile-content"
+ >
+ <div
+ className="sdc-tile-content-icon "
+ />
+ </div>
+ <div
+ className="sdc-tile-footer centered"
+ >
+ <span
+ className="sdc-tile-footer-cell "
+ data-test-id={undefined}
+ >
+ Footer
+ </span>
+ </div>
+</div>
+`;
+
+exports[`Tile Tile with props 1`] = `
+<div
+ className="sdc-tile "
+ data-test-id={undefined}
+ onClick={undefined}
+>
+ <div
+ className="sdc-tile-header blue"
+ >
+ header
+ </div>
+ <div
+ className="sdc-tile-content"
+ >
+ <div
+ className="sdc-tile-content-icon blue"
+ >
+ <div
+ className="svg-icon-wrapper bottom"
+ disabled={undefined}
+ onClick={undefined}
+ >
+ <svg />
+
+ </div>
+ </div>
+ </div>
+</div>
+`;
diff --git a/test/react/utils/htmlLoader.js b/test/react/utils/htmlLoader.js
new file mode 100644
index 0000000..fbdfbd8
--- /dev/null
+++ b/test/react/utils/htmlLoader.js
@@ -0,0 +1,7 @@
+const htmlLoader = require('html-loader');
+
+module.exports = {
+ process(src) {
+ return htmlLoader(src);
+ }
+};
diff --git a/test/react/utils/svgMock.js b/test/react/utils/svgMock.js
new file mode 100644
index 0000000..2d6ed81
--- /dev/null
+++ b/test/react/utils/svgMock.js
@@ -0,0 +1,3 @@
+import React from 'react';
+
+module.exports = () => <svg />; \ No newline at end of file
diff --git a/tsconfig.angular.build-es5.json b/tsconfig.angular.build-es5.json
new file mode 100644
index 0000000..17e51af
--- /dev/null
+++ b/tsconfig.angular.build-es5.json
@@ -0,0 +1,24 @@
+{
+ "compilerOptions": {
+ "module": "es2015",
+ "target": "es5",
+ "lib": ["es2015", "dom"],
+ "skipLibCheck": true,
+ "emitDecoratorMetadata": true,
+ "experimentalDecorators": true,
+ "sourceMap": true,
+ "moduleResolution": "node",
+ "declaration": true,
+ "outDir": "build",
+ "rootDir": "src"
+ },
+ "files": [
+ "src/angular/index.ts"
+ ],
+ "angularCompilerOptions": {
+ "skipMetadataEmit": false,
+ "strictMetadataEmit": false,
+ "skipTemplateCodegen": true,
+ "flatModuleId": "sdc-ui"
+ }
+}
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..040ef40
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,31 @@
+{
+ "compilerOptions": {
+ "target": "es5",
+ "module": "commonjs",
+ "outDir": "dist",
+ "rootDir": ".",
+ "sourceMap": true,
+ "emitDecoratorMetadata": true,
+ "experimentalDecorators": true,
+ "moduleResolution": "node",
+ "typeRoots": [
+ "node_modules/@types"
+ ],
+ "lib": ["es6", "dom"]
+ },
+ "exclude": [
+ "node_modules"
+ ],
+ "types":[
+ "jasmine"
+ ],
+ "awesomeTypescriptLoaderOptions": {
+ "useWebpackText": true
+ },
+ "angularCompilerOptions": {
+ "debug": true
+ },
+ "compileOnSave": false,
+ "buildOnSave": false,
+ "atom": { "rewriteTsconfig": false }
+}
diff --git a/tslint.json b/tslint.json
new file mode 100644
index 0000000..9aca897
--- /dev/null
+++ b/tslint.json
@@ -0,0 +1,77 @@
+{
+ "extends": [
+ "tslint:recommended",
+ "tslint-angular"
+ ],
+ "rulesDirectory": [
+ "node_modules/codelyzer"
+ ],
+ "rules": {
+ "member-ordering": [
+ false
+ ],
+ "angular-whitespace": [
+ true,
+ "check-interpolation",
+ "check-pipe"
+ ],
+ "banana-in-box": true,
+ "templates-no-negated-async": true,
+ "directive-selector": [
+ true,
+ "attribute", [
+ "Sdc",
+ "Onap"
+ ],
+ "camelCase"
+ ],
+ "component-selector": [
+ true,
+ "element", [
+ "sdc",
+ "onap"
+ ],
+ "kebab-case"
+ ],
+ "use-input-property-decorator": true,
+ "use-output-property-decorator": true,
+ "use-host-property-decorator": true,
+ "no-attribute-parameter-decorator": true,
+ "no-input-rename": true,
+ "no-output-rename": true,
+ "no-forward-ref": true,
+ "use-view-encapsulation": false,
+ "use-life-cycle-interface": true,
+ "use-pipe-transform-interface": true,
+ "pipe-naming": [
+ true,
+ "camelCase",
+ "Pipe"
+ ],
+ "component-class-suffix": [
+ true,
+ "Component"
+ ],
+ "directive-class-suffix": [
+ true,
+ "Directive"
+ ],
+ "templates-use-public": true,
+ "no-access-missing-member": true,
+ "invoke-injectable": true,
+ "template-to-ng-template": true,
+ "ordered-imports": [
+ false
+ ],
+ "quotemark": [
+ false
+ ],
+ "trailing-comma": [
+ false
+ ],
+ "arrow-parens": false,
+ "object-literal-sort-keys": false,
+ "object-literal-shorthand": false,
+ "max-line-length": [true, 240, "^import |^export | implements "]
+ }
+}
diff --git a/utils/build-demo.js b/utils/build-demo.js
new file mode 100644
index 0000000..8f5edda
--- /dev/null
+++ b/utils/build-demo.js
@@ -0,0 +1,73 @@
+const ncp = require('ncp').ncp;
+const fs = require('fs');
+const path = require('path')
+const svgFolder = './assets/icons';
+const svgOutputFile = './src/style/scss/common/_icons.scss';
+
+var copyFiles = function() {
+ // Copy generated style.css to demo/gen folder
+ ncp('lib/css/style.css', 'demo/gen', function (err) {
+ if (err) {
+ return console.error(err);
+ }
+ });
+
+ // Copy assets folder to demo/gen folder
+ ncp('assets', 'demo/gen/assets', function (err) {
+ if (err) {
+ return console.error(err);
+ }
+ });
+};
+
+// var parseSvgContent = function(content) {
+// var withoutLines = (content+'').replace(/\n|\t|\r/g, '');
+// return withoutLines.replace(/"/g,'\'');
+// };
+
+// var readFile = function(filePath) {
+// return fs.readFileSync(filePath, 'utf8');
+// };
+
+// var clearFile = function(filePath) {
+// return fs.truncateSync(filePath, 0);
+// };
+
+// var writeFile = function(filePath){
+// const text = `.sdc-icon {
+// display: inline-block;
+// text-rendering: auto;
+// -webkit-font-smoothing: antialiased;
+// -moz-osx-font-smoothing: grayscale;
+// width: 16px;
+// height: 16px;
+// }\n`;
+// fs.writeFileSync(filePath, text);
+// console.log("The file was saved!");
+// };
+
+// var appendSvgIcons = function(content) {
+// fs.appendFileSync(svgOutputFile, content);
+// };
+
+// var readFolder = function(folderPath) {
+// var files = fs.readdirSync(svgFolder);
+// files.forEach(file => {
+// var extension = path.extname(file);
+// if (extension ==='.svg'){
+// console.log(folderPath + "/" + file);
+// var fileContent = readFile(folderPath + "/" + file);
+// var svgContent = parseSvgContent(fileContent);
+// var fileName = path.basename(file, '.svg')
+// var scssContent = '.sdc-icon-' + fileName + ' {background-image: url("data:image/svg+xml;utf8,' + svgContent + '"); background-repeat: no-repeat;}';
+// appendSvgIcons(scssContent+'\n');
+// }
+// });
+
+// };
+
+// Generate icons.scss file from multiple SVG files
+// clearFile(svgOutputFile);
+// writeFile(svgOutputFile);
+// readFolder(svgFolder);
+copyFiles();
diff --git a/utils/create-icon-map.js b/utils/create-icon-map.js
new file mode 100644
index 0000000..d980895
--- /dev/null
+++ b/utils/create-icon-map.js
@@ -0,0 +1,26 @@
+
+const fs = require('fs');
+const path = require('path');
+
+const svgFolder = './assets/icons/';
+const iconMapFile = './src/react/utils/iconMap.js';
+
+let dataToWrite = '';
+let iconNames = [];
+
+let iconMapDir = path.dirname(iconMapFile);
+if (!fs.existsSync(iconMapDir)) {
+ fs.mkdirSync(iconMapDir);
+};
+
+fs.readdirSync(svgFolder).forEach(file => {
+ let fileName = file.split('.');
+ if (fileName[0] && fileName[1] === 'svg') {
+ dataToWrite += `import ${fileName[0]} from '-!svg-react-loader!../../.${svgFolder}${file}';\n`;
+ iconNames.push(fileName[0]);
+ }
+});
+
+dataToWrite += '\n' + `export default {\n\t${iconNames.join(',\n\t')}\n};`;
+
+fs.writeFileSync(iconMapFile, dataToWrite);
diff --git a/utils/create-svg-icons-map.js b/utils/create-svg-icons-map.js
new file mode 100644
index 0000000..aec459c
--- /dev/null
+++ b/utils/create-svg-icons-map.js
@@ -0,0 +1,95 @@
+const fs = require('fs');
+const path = require('path');
+const svgFolder = path.resolve(__dirname + '/../assets/sdc-icons/');
+const iconMapFile = path.resolve(__dirname + '/../src/common/icons-map.json');
+const iconMapTSFile = path.resolve(__dirname + '/../src/common/icons-map.ts');
+const disallowedSvgAttributes = ['fill', 'id', 'width', 'height'];
+const disallowedSvgStyle = ['fill'];
+const disallowedSvgInlineAttributes = ['fill', 'id'];
+const disallowedSvgInlineStyle = ['fill'];
+
+function _escapeStrRegex(str) {
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+}
+function _makeSvgAttributesRegex(attrs) {
+ return new RegExp(`\s*(${attrs.map(_escapeStrRegex).join('|')})\s*=\s*("|')[^"']*\\2`, 'g');
+}
+function _makeSvgStyleRegex(attrs) {
+ return new RegExp(`\s*${attrs.map(_escapeStrRegex).join('|')}\s*:[^'";]*;?`, 'g');
+}
+
+// prepare
+const disallowedSvgAttributesRegex = _makeSvgAttributesRegex(disallowedSvgAttributes);
+const disallowedSvgStyleRegex = _makeSvgStyleRegex(disallowedSvgStyle);
+const disallowedSvgInlineAttributesRegex = _makeSvgAttributesRegex(disallowedSvgInlineAttributes);
+const disallowedSvgInlineStyleRegex = _makeSvgStyleRegex(disallowedSvgInlineStyle);
+
+function addIcon(iconsObject, iconName, iconPath) {
+ let iconContent = fs.readFileSync(iconPath).toString();
+ if (!iconContent) {
+ return;
+ }
+
+ let iconInfoMsg = '';
+
+ // clean the first <svg> tag
+ iconContent = iconContent.replace(/<svg\b[^>]*>/, (svgTag) => {
+ let cleanedNum = 0;
+ const disallowedSvgAttributesMatch = svgTag.match(disallowedSvgAttributesRegex);
+ if (disallowedSvgAttributesMatch) {
+ svgTag = svgTag.replace(disallowedSvgAttributesRegex, '');
+ cleanedNum += disallowedSvgAttributesMatch.length;
+ }
+ const disallowedSvgStyleMatch = svgTag.match(disallowedSvgStyleRegex);
+ if (disallowedSvgStyleMatch) {
+ svgTag = svgTag.replace(disallowedSvgStyleRegex, '');
+ cleanedNum += disallowedSvgStyleMatch.length;
+ }
+ iconInfoMsg += 'ADDED';
+ if (cleanedNum > 0) {
+ iconInfoMsg += `\n\t(cleaned ${cleanedNum} attributes and styles)`;
+ }
+ return svgTag;
+ });
+
+ const disallowedSvgInlineAttributesMatch = iconContent.match(disallowedSvgInlineAttributesRegex);
+ if (disallowedSvgInlineAttributesMatch) {
+ iconInfoMsg += `\n\t* CHECK for ${disallowedSvgInlineAttributesMatch.length} inline attributes [${disallowedSvgInlineAttributes.join(', ')}]`;
+ }
+ const disallowedSvgInlineStyleMatch = iconContent.match(disallowedSvgInlineStyleRegex);
+ if (disallowedSvgInlineStyleMatch) {
+ iconInfoMsg += `\n\t* CHECK for ${disallowedSvgInlineStyleMatch.length} inline styles [${disallowedSvgInlineStyle.join(', ')}]`;
+ }
+
+ console.log(`# ${iconName}: ${iconInfoMsg}`);
+
+ iconsObject[iconName] = iconContent;
+}
+
+function main() {
+ const iconMapDir = path.dirname(iconMapFile);
+ if (!fs.existsSync(iconMapDir)) {
+ fs.mkdirSync(iconMapDir);
+ }
+
+ const iconsObject = {};
+ fs.readdirSync(svgFolder).forEach((file) => {
+ const fileName = file.split('.', 2)[0];
+ const fileExtension = file.split('.', 2)[1];
+ if (fileExtension === 'svg') {
+ const filePath = svgFolder + '/' + file;
+ if (fs.existsSync(filePath)) {
+ addIcon(iconsObject, fileName, filePath);
+ }
+ }
+ });
+
+ const dataToWrite = JSON.stringify(iconsObject);
+
+ fs.writeFileSync(iconMapFile, dataToWrite);
+ fs.writeFileSync(iconMapTSFile, `export default ${dataToWrite};`);
+
+ console.log(`Icons Map JSON created! [${iconMapFile}]`);
+}
+
+main();
diff --git a/utils/index-for-gh-pages.html b/utils/index-for-gh-pages.html
new file mode 100644
index 0000000..a6d7f63
--- /dev/null
+++ b/utils/index-for-gh-pages.html
@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <meta content="IE=edge" http-equiv="X-UA-Compatible" />
+ <title>Storybook</title>
+ <style>
+ body, html {
+ width: 100%;
+ height: 100%;
+ padding: 0;
+ margin: 0;
+ }
+ .header {
+ display: flex;
+ padding: 18px 40px 0 40px;
+ }
+ .logo {
+ margin-right: 95px;
+ cursor: pointer;
+ }
+ img {
+ width: 125px;
+ height: 26px;
+ }
+ .showcase-header {
+ display: flex;
+ }
+ .case-tab-name {
+ font-family: OpenSans, OpenSans-Regular, 'Open Sans', Arial, sans-serif;
+ font-size: 14px;
+ line-height: 1.71;
+ letter-spacing: -0.2px;
+ margin: 0 20px;
+ padding: 4px 8px 12px 8px;
+ color: #5a5a5a;
+ cursor: pointer;
+ text-transform: uppercase;
+ }
+ .case-tab-name[active=true] {
+ color: #009fdb;
+ border-bottom: solid 2px #009fdb;
+ }
+ .showcase-wrapper {
+ height: calc(100% - 60px);
+ display: flex;
+ flex-direction: column;
+ background-color: #FFFFFF;
+ }
+ .showcase-iframe {
+ height: 100%;
+ border-top: solid 1px #aaaaaa;
+ }
+ </style>
+
+ <script>
+ var shows = {
+ mainPage: "main-page.html",
+ react: "react/index.html",
+ angular: "angular/index.html"
+ };
+ function show(type){
+ document.getElementById('showcase').src = shows[type];
+ setActiveTab(type);
+ }
+ function setActiveTab(type) {
+ var allTabs = document.getElementsByClassName('case-tab-name');
+ for(var i = 0; i < allTabs.length; i++ ) {
+ if(allTabs[i].getAttribute('id') === type+'-tab') {
+ allTabs[i].setAttribute('active', true);
+ }
+ else {
+ allTabs[i].setAttribute('active', false);
+ }
+ }
+ }
+ </script>
+
+</head>
+
+<body>
+ <div class="header">
+ <div class="logo" onClick="show('mainPage')"><img src="assets/images/logo_onap.png"/></div>
+ <div class="showcase-header">
+ <div class="case-tab-name" id="react-tab" onClick="show('react')">React</div>
+ <div class="case-tab-name" id="angular-tab" onClick="show('angular')">Angular</div>
+ </div>
+ </div>
+
+ <div class="showcase-wrapper">
+ <iframe id="showcase" src="main-page.html" class="showcase-iframe">
+ </iframe>
+ </div>
+</body>
+
+</html>
diff --git a/utils/main-page.html b/utils/main-page.html
new file mode 100644
index 0000000..30fb10f
--- /dev/null
+++ b/utils/main-page.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+
+ <head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <meta content="IE=edge" http-equiv="X-UA-Compatible" />
+ <title>Storybook</title>
+
+ <style>
+ body, html {
+ width: 100%;
+ padding: 0;
+ margin: 0;
+ }
+ body {
+ height: calc(100% - 40px);
+ display: flex;
+ flex-direction: column;
+ background-color: #FFFFFF;
+ padding: 65px 0;
+ }
+ .title, .description {
+ text-align: center;
+ align-self: center;
+
+ }
+ .title {
+ font-family: OpenSans-Light, 'Open Sans', Arial, sans-serif;
+ width: 360px;
+ height: 29px;
+ font-size: 28px;
+ font-weight: 300;
+ line-height: 0.86;
+ letter-spacing: -0.4px;
+ color: #191919;
+ }
+ .description {
+ font-family: OpenSans-Regular, 'Open Sans', Arial, sans-serif;
+ width: 485px;
+ height: 41px;
+ font-size: 16px;
+ line-height: 1.5;
+ letter-spacing: -0.2px;
+ color: #5a5a5a;
+ padding: 28px;
+ }
+ .main-page-img {
+ margin: 15px;
+ display: flex;
+ align-self: center;
+ }
+ </style>
+ </head>
+
+ <body>
+ <div class="title">Welcome to ONAP/UI project!</div>
+ <div class="description">The aim of this project is to create a basic component library, with a unified UX and UI for both Angular and React based projects.</div>
+ <img class="main-page-img" src="assets/images/illustration.png"/>
+ </body>
+
+</html> \ No newline at end of file
diff --git a/utils/scripts/map-sources.js b/utils/scripts/map-sources.js
new file mode 100644
index 0000000..3ce6bfb
--- /dev/null
+++ b/utils/scripts/map-sources.js
@@ -0,0 +1,9 @@
+const sorcery = require('sorcery');
+
+const argv = require('yargs')
+ .alias('f', 'file')
+ .argv;
+
+sorcery.load(argv.file).then(function (chain) {
+ chain.write();
+});
diff --git a/version.properties b/version.properties
new file mode 100644
index 0000000..b479afe
--- /dev/null
+++ b/version.properties
@@ -0,0 +1,13 @@
+###########################################################
+# Versioning variables
+# Note that these variables cannot be structured (e.g. : version.release or version.snapshot etc... )
+# because they are used in Jenkins, whose plug-in doesn't support
+
+major=1
+minor=2
+patch=0
+
+base_version=${major}.${minor}.${patch}
+
+release_version=${base_version}
+snapshot_version=${base_version}-SNAPSHOT \ No newline at end of file
diff --git a/webpack.build.config.js b/webpack.build.config.js
new file mode 100644
index 0000000..9c74402
--- /dev/null
+++ b/webpack.build.config.js
@@ -0,0 +1,63 @@
+var path = require('path');
+
+var webpackConfig = {
+
+ devtool: 'source-map',
+
+ entry: {},
+
+ output: {
+ publicPath: ''
+ },
+
+ plugins: [
+ ],
+
+ module: {
+ rules: [
+ // .ts files for TypeScript
+ {
+ test: /.ts$/,
+ use: [
+ 'awesome-typescript-loader',
+ 'angular2-template-loader',
+ 'angular2-router-loader'
+ ]
+ },
+ {
+ test: /\.html$/,
+ loader: 'html-loader'
+ },
+ {
+ test: /\.scss$/,
+ use: ['style-loader', 'css-loader', 'sass-loader'],
+ include: path.resolve(__dirname, '../')
+ },
+ {
+ test: /\.json$/,
+ loader: 'json',
+ include: path.resolve(__dirname, '../')
+
+ },
+ {
+ test: /\.svg$/,
+ use: 'svg-sprite-loader',
+ options: {
+ extract: true,
+
+ }
+ }
+ ]
+ },
+
+ resolve: {
+ extensions: ['.ts', '.js', '.json'],
+ modules: [path.resolve(__dirname, 'node_modules')],
+ alias: {
+ root: path.resolve(__dirname),
+ app: path.resolve(__dirname, 'src')
+ }
+ }
+};
+
+module.exports = webpackConfig;
diff --git a/webpack/helpers.js b/webpack/helpers.js
new file mode 100644
index 0000000..c2c3717
--- /dev/null
+++ b/webpack/helpers.js
@@ -0,0 +1,10 @@
+var path = require('path');
+
+var _root = path.resolve(__dirname, '..');
+
+function root(args) {
+ args = Array.prototype.slice.call(arguments, 0);
+ return path.join.apply(path, [_root].concat(args));
+}
+
+exports.root = root;
diff --git a/webpack/webpack.test.js b/webpack/webpack.test.js
new file mode 100644
index 0000000..9057d4e
--- /dev/null
+++ b/webpack/webpack.test.js
@@ -0,0 +1,71 @@
+/****************************************************************************************
+ * Webpack test configuration file
+ * Using the current configuration we are able to bundle all the files we need for our
+ * unit testings.
+ ***************************************************************************************/
+
+
+'use strict';
+
+/**
+ * Dependencies:
+ * path: node library for resolving full path names
+ * webpack: for use in our testings
+ */
+const path = require('path');
+const webpack = require('webpack');
+const helpers = require('./helpers');
+module.exports = {
+ /**
+ * Choose a developer tool to enhance debugging. inline-source-map - A SourceMap is added as DataUrl to the JavaScript file.
+ */
+ devtool: 'inline-source-map',
+
+ /**
+ * Set webpack loaders and preloaders for typescript, angular2, SASS and HTML,
+ * so that webpack will be able to process and bundle them.
+ */
+ module: {
+
+ rules: [
+ {
+ test: /.ts$/,
+ exclude: /node_modules/,
+ use: [
+ 'awesome-typescript-loader',
+ 'angular2-template-loader',
+ 'angular2-router-loader'
+ ]
+ },
+ { test: /\.html$/, loader: "html-loader" },
+ {
+ test: /.scss$/,
+ use: ['style-loader', 'css-loader', 'sass-loader'],
+ include: path.resolve(__dirname, '../')
+ },
+
+ ]
+ },
+
+ plugins: [
+ // Workaround for angular/angular#11580
+ new webpack.ContextReplacementPlugin(
+ // The (\\|\/) piece accounts for path separators in *nix and Windows
+ ///angular(\\|\/)core(\\|\/)@angular/,
+ /@angular(\\|\/)core(\\|\/)/,
+ helpers.root('./src'), // location of your src
+ {} // a map of your routes
+ ),
+ ],
+
+ /**
+ * This section lets Webpack know which types of file extensions it should be loading.
+ */
+ resolve: {
+ extensions: ['.js', '.ts'],
+ modules: [
+ path.resolve('.', 'src'),
+ 'node_modules'
+ ]
+ },
+};