├── .ci_config ├── .gitignore ├── .npmrc ├── .nvmrc ├── .storybook ├── addons.js ├── config.js ├── preview-head.html ├── stories.scss └── webpack.config.js ├── .travis.yml ├── .vscode ├── extensions.json └── launch.json ├── README.md ├── package.json ├── pom.xml ├── protractor.conf.js ├── scripts ├── build-standalone.js └── toESModules.js ├── src ├── colors.st.css ├── common │ └── testkitTests.ts ├── components │ ├── AddressInput │ │ ├── AddressInput.driver.ts │ │ ├── AddressInput.e2e.ts │ │ ├── AddressInput.protractor.driver.ts │ │ ├── AddressInput.spec.tsx │ │ ├── AddressInput.st.css │ │ ├── AddressInput.tsx │ │ └── index.ts │ ├── Autocomplete │ │ ├── Autocomplete.driver.ts │ │ ├── Autocomplete.e2e.ts │ │ ├── Autocomplete.protractor.driver.ts │ │ ├── Autocomplete.spec.tsx │ │ ├── Autocomplete.st.css │ │ ├── Autocomplete.tsx │ │ ├── index.ts │ │ └── readme.md │ ├── Badge │ │ ├── Badge.driver.ts │ │ ├── Badge.e2e.ts │ │ ├── Badge.protractor.driver.ts │ │ ├── Badge.spec.tsx │ │ ├── Badge.st.css │ │ ├── Badge.tsx │ │ ├── constants.ts │ │ └── index.ts │ ├── Button │ │ ├── Button.driver.ts │ │ ├── Button.e2e.ts │ │ ├── Button.protractor.driver.ts │ │ ├── Button.spec.tsx │ │ ├── Button.st.css │ │ ├── Button.tsx │ │ ├── constants.ts │ │ └── index.ts │ ├── Checkbox │ │ ├── Checkbox.driver.ts │ │ ├── Checkbox.e2e.ts │ │ ├── Checkbox.spec.tsx │ │ ├── Checkbox.st.css │ │ ├── Checkbox.tsx │ │ └── index.ts │ ├── CircularProgressBar │ │ ├── CircularProgressBar.driver.ts │ │ ├── CircularProgressBar.e2e.ts │ │ ├── CircularProgressBar.protractor.driver.ts │ │ ├── CircularProgressBar.spec.tsx │ │ ├── CircularProgressBar.st.css │ │ ├── CircularProgressBar.tsx │ │ ├── constants.ts │ │ └── index.ts │ ├── CloseButton │ │ ├── CloseButton.driver.ts │ │ ├── CloseButton.e2e.ts │ │ ├── CloseButton.protractor.driver.ts │ │ ├── CloseButton.spec.tsx │ │ ├── CloseButton.st.css │ │ ├── CloseButton.tsx │ │ ├── constants.ts │ │ └── index.ts │ ├── FloatingHelper │ │ ├── ClosablePopover │ │ │ ├── ClosablePopover.driver.ts │ │ │ ├── ClosablePopover.protractor.driver.ts │ │ │ ├── ClosablePopover.spec.tsx │ │ │ ├── ClosablePopover.tsx │ │ │ └── index.ts │ │ ├── DataHooks.ts │ │ ├── FloatingHelper.driver.ts │ │ ├── FloatingHelper.e2e.ts │ │ ├── FloatingHelper.protractor.driver.ts │ │ ├── FloatingHelper.spec.tsx │ │ ├── FloatingHelper.st.css │ │ ├── FloatingHelper.tsx │ │ ├── FloatingHelperContent │ │ │ ├── DataHooks.ts │ │ │ ├── FloatingHelperContent.driver.ts │ │ │ ├── FloatingHelperContent.e2e.ts │ │ │ ├── FloatingHelperContent.protractor.driver.ts │ │ │ ├── FloatingHelperContent.spec.tsx │ │ │ ├── FloatingHelperContent.st.css │ │ │ ├── FloatingHelperContent.tsx │ │ │ ├── README.md │ │ │ ├── constants.ts │ │ │ └── index.ts │ │ ├── README.md │ │ ├── constants.ts │ │ └── index.ts │ ├── FullTextView │ │ ├── FullTextView.driver.ts │ │ ├── FullTextView.e2e.ts │ │ ├── FullTextView.protractor.driver.ts │ │ ├── FullTextView.spec.tsx │ │ ├── FullTextView.st.css │ │ ├── FullTextView.tsx │ │ ├── FullTextView.uni.driver.tsx │ │ └── index.ts │ ├── HBox │ │ ├── HBox.driver.ts │ │ ├── HBox.e2e.ts │ │ ├── HBox.protractor.driver.ts │ │ ├── HBox.spec.tsx │ │ ├── HBox.st.css │ │ ├── HBox.tsx │ │ ├── index.ts │ │ └── utils.tsx │ ├── Heading │ │ ├── Heading.driver.ts │ │ ├── Heading.e2e.ts │ │ ├── Heading.protractor.driver.ts │ │ ├── Heading.spec.tsx │ │ ├── Heading.st.css │ │ ├── Heading.tsx │ │ └── index.ts │ ├── Input │ │ ├── Error.st.css │ │ ├── Input.e2e.ts │ │ ├── Input.st.css │ │ ├── Input.tsx │ │ ├── InputStates.st.css │ │ ├── InputSuffixes.tsx │ │ └── index.ts │ ├── Label │ │ ├── Label.driver.ts │ │ ├── Label.e2e.ts │ │ ├── Label.protractor.driver.ts │ │ ├── Label.spec.tsx │ │ ├── Label.st.css │ │ ├── Label.tsx │ │ ├── Label.uni.driver.ts │ │ ├── constants.ts │ │ └── index.ts │ ├── LabelWithOptions │ │ ├── LabelWithOptions.driver.ts │ │ ├── LabelWithOptions.e2e.ts │ │ ├── LabelWithOptions.protractor.driver.ts │ │ ├── LabelWithOptions.spec.tsx │ │ ├── LabelWithOptions.st.css │ │ ├── LabelWithOptions.tsx │ │ ├── index.ts │ │ └── readme.md │ ├── LinearProgressBar │ │ ├── LinearProgressBar.driver.ts │ │ ├── LinearProgressBar.e2e.ts │ │ ├── LinearProgressBar.protractor.driver.ts │ │ ├── LinearProgressBar.spec.tsx │ │ ├── LinearProgressBar.st.css │ │ ├── LinearProgressBar.tsx │ │ └── index.ts │ ├── StylableCounterBadge │ │ ├── CounterBadge.driver.ts │ │ ├── CounterBadge.e2e.tsx │ │ ├── CounterBadge.protractor.driver.ts │ │ ├── CounterBadge.spec.tsx │ │ ├── CounterBadge.st.css │ │ ├── CounterBadge.tsx │ │ ├── constants.ts │ │ ├── index.ts │ │ └── utils.ts │ ├── Text │ │ ├── README.md │ │ ├── Text.driver.ts │ │ ├── Text.e2e.ts │ │ ├── Text.protractor.driver.ts │ │ ├── Text.spec.tsx │ │ ├── Text.st.css │ │ ├── Text.tsx │ │ ├── constants.ts │ │ └── index.ts │ ├── Thumbnail │ │ ├── Thumbnail.driver.ts │ │ ├── Thumbnail.e2e.ts │ │ ├── Thumbnail.protractor.driver.ts │ │ ├── Thumbnail.spec.tsx │ │ ├── Thumbnail.st.css │ │ ├── Thumbnail.tsx │ │ └── index.ts │ ├── TimePicker │ │ ├── TimePicker.driver.ts │ │ ├── TimePicker.e2e.ts │ │ ├── TimePicker.protractor.driver.ts │ │ ├── TimePicker.spec.tsx │ │ ├── TimePicker.st.css │ │ ├── TimePicker.tsx │ │ ├── constants.ts │ │ └── index.ts │ ├── ToggleSwitch │ │ ├── ToggleSwitch.driver.ts │ │ ├── ToggleSwitch.e2e.ts │ │ ├── ToggleSwitch.protractor.driver.ts │ │ ├── ToggleSwitch.spec.tsx │ │ ├── ToggleSwitch.st.css │ │ ├── ToggleSwitch.tsx │ │ ├── constants.ts │ │ └── index.ts │ ├── Tooltip │ │ ├── Tooltip.driver.ts │ │ ├── Tooltip.spec.tsx │ │ ├── Tooltip.st.css │ │ ├── Tooltip.tsx │ │ └── index.ts │ ├── VBox │ │ ├── VBox.driver.ts │ │ ├── VBox.e2e.ts │ │ ├── VBox.protractor.driver.ts │ │ ├── VBox.spec.tsx │ │ ├── VBox.st.css │ │ ├── VBox.tsx │ │ ├── index.ts │ │ └── utils.tsx │ └── core │ │ └── CoreText │ │ ├── Text.driver.ts │ │ ├── Text.protractor.driver.ts │ │ ├── Text.spec.tsx │ │ ├── Text.st.css │ │ ├── Text.tsx │ │ ├── TextStyle.st.css │ │ └── index.ts ├── palette.st.css ├── protractor.d.ts ├── shadows.st.css ├── testkit │ ├── enzyme.ts │ ├── index.ts │ └── protractor.ts ├── types │ └── common.ts ├── typography.st.css └── utils │ ├── index.ts │ └── utils.spec.ts ├── stories ├── AddressInput.story.tsx ├── Autocomplete.story.tsx ├── Badge │ ├── ExampleBadgeOnClick.tsx │ ├── ExampleBadges.scss │ ├── ExampleBadges.tsx │ └── index.story.tsx ├── Button │ ├── index.story.tsx │ └── storySettings.ts ├── Checkbox.story.tsx ├── CircularProgressBar │ ├── CircularProgressBar.story.tsx │ └── index.ts ├── CloseButton │ ├── index.story.tsx │ └── storySettings.ts ├── FloatingHelper │ ├── ControlledExample.tsx │ ├── FullExample.tsx │ ├── ProgrammaticExample.tsx │ ├── SimpleExample.tsx │ ├── SimpleExampleLight.tsx │ ├── StorySettings.ts │ └── index.story.tsx ├── FloatingHelperContent │ ├── StorySettings.ts │ └── index.story.tsx ├── FullTextView.story.tsx ├── HBox │ ├── index.story.tsx │ └── style.st.css ├── Heading.story.tsx ├── Input.story.tsx ├── Label.story.tsx ├── Label │ └── index.tsx ├── LabelWithOptions.story.tsx ├── LinearProgressBar │ ├── LinearProgressBar.story.tsx │ └── index.ts ├── StylableCounterBadge │ └── index.tsx ├── Text.story.tsx ├── Thumbnail.story.tsx ├── TimePicker.story.tsx ├── ToggleSwitch │ └── index.tsx ├── Tooltip │ └── index.tsx ├── VBox │ ├── index.story.tsx │ └── style.st.css ├── helpers.tsx ├── index.ts └── storyTypes.ts ├── test ├── enzyme-setup.js └── testkitUtils.ts ├── tsconfig.json ├── tslint.json └── wallaby.js /.ci_config: -------------------------------------------------------------------------------- 1 | { 2 | "pr_env_params" : {"APPLITOOLS_GITHUB_FT": "true"}, 3 | "env_params" : {"APPLITOOLS_GITHUB_FT": "true"} 4 | } 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | target 4 | coverage 5 | typings 6 | maven 7 | .history 8 | test/e2e/screenshots 9 | package-lock.json 10 | .yo-rc.json 11 | npm-debug.log 12 | yarn.lock 13 | storybook-static 14 | /*.js 15 | /*.d.ts 16 | !wallaby.js 17 | !protractor.conf.js 18 | .DS_Store 19 | .idea -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 12 2 | -------------------------------------------------------------------------------- /.storybook/addons.js: -------------------------------------------------------------------------------- 1 | import '@storybook/addon-options/register'; 2 | import '@storybook/addon-links/register'; 3 | -------------------------------------------------------------------------------- /.storybook/config.js: -------------------------------------------------------------------------------- 1 | import {configure, storiesOf} from '@storybook/react'; 2 | import {setOptions} from '@storybook/addon-options'; 3 | 4 | function loadStories() { 5 | require('../stories'); 6 | require('./stories.scss'); 7 | } 8 | 9 | configure(loadStories, module); 10 | 11 | setOptions({ 12 | showDownPanel: false, 13 | name: 'wix-ui-backoffice', 14 | url: 'https://github.com/wix/wix-ui-backoffice', 15 | sidebarAnimations: false 16 | }); 17 | -------------------------------------------------------------------------------- /.storybook/preview-head.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.storybook/stories.scss: -------------------------------------------------------------------------------- 1 | html { 2 | -webkit-font-smoothing: antialiased; 3 | -moz-osx-font-smoothing: grayscale; 4 | } 5 | 6 | body { 7 | font-family: "HelveticaNeueW01-45Ligh", "HelveticaNeueW02-45Ligh", "HelveticaNeueW10-45Ligh", "Helvetica Neue", "Helvetica", "Arial", "\30E1\30A4\30EA\30AA", "meiryo", "\30D2\30E9\30AE\30CE\89D2\30B4 pro w3", "hiragino kaku gothic pro"; 8 | color: #222; 9 | line-height: 1.2; 10 | font-size: 13px; 11 | } 12 | -------------------------------------------------------------------------------- /.storybook/webpack.config.js: -------------------------------------------------------------------------------- 1 | const wixStorybookConfig = require('yoshi/config/webpack.config.storybook'); 2 | 3 | module.exports = (config, env, defaultConfig) => { 4 | const newConfig = wixStorybookConfig(defaultConfig); 5 | 6 | newConfig.module.rules.push({ 7 | test: /\.story\.[j|t]sx?$/, 8 | loader: 'wix-storybook-utils/loader', 9 | options: { 10 | storyConfig: { 11 | moduleName: 'wix-ui-backoffice', 12 | repoBaseURL: 'https://github.com/wix/wix-ui-backoffice/tree/master/src/components/', 13 | importFormat: "import {%componentName} from '%moduleName/%componentName'", 14 | }, 15 | }, 16 | }); 17 | 18 | return newConfig; 19 | }; 20 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | dist: trusty 3 | language: node_js 4 | node_js: 5 | - 8.9.1 6 | 7 | before_install: 8 | - export CHROME_BIN=/usr/bin/google-chrome 9 | - export DISPLAY=:99.0 10 | - sh -e /etc/init.d/xvfb start 11 | - sudo apt-get update 12 | - sudo apt-get install -y libappindicator1 fonts-liberation 13 | - wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb 14 | - sudo dpkg -i google-chrome*.deb 15 | 16 | script: 17 | - npm run build && npm run test 18 | 19 | notifications: 20 | email: 21 | recipients: 22 | - fed-infra@wix.com 23 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "wix.stylable-intelligence", 4 | "eg2.tslint", 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Unit Test Debug", 9 | "type": "node", 10 | "request": "launch", 11 | "args" : ["test", "--jest", "--debug-brk"], 12 | "port": 9229, 13 | "program": "${workspaceFolder}/node_modules/.bin/yoshi" 14 | }, 15 | { 16 | "name": "e2e Test Debug", 17 | "type": "node", 18 | "request": "launch", 19 | "args" : ["test", "--protractor", "--debug-brk"], 20 | "port": 9229, 21 | "program": "${workspaceFolder}/node_modules/.bin/yoshi" 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wix-ui-backoffice (archived and no longer supported) 2 | 3 | Please refer to [wix-style-react](https://github.com/wix-private/wix-design-systems/tree/master/packages/wix-style-react) 4 | 5 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | com.wixpress.infra 5 | wix-ui-backoffice 6 | pom 7 | wix-ui-backoffice 8 | Common UI components library which is being used across Wix backoffice applications 9 | 1.0.0-SNAPSHOT 10 | 11 | 12 | com.wixpress.common 13 | wix-master-parent 14 | 100.0.0-SNAPSHOT 15 | 16 | 17 | 18 | 19 | Arijus Šukys 20 | arijuss@wix.com 21 | 22 | owner 23 | 24 | 25 | 26 | 27 | 28 | 29 | slack 30 | wix-ui 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /protractor.conf.js: -------------------------------------------------------------------------------- 1 | const {baseProtractorConfig} = require('wix-ui-test-utils/dist/src/protractor/protractor.conf'); 2 | 3 | exports.config = baseProtractorConfig; 4 | -------------------------------------------------------------------------------- /scripts/build-standalone.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const execa = require('execa'); 3 | 4 | const outDir = path.join('dist', 'standalone'); 5 | const esOutDir = path.join(outDir, 'es'); 6 | 7 | function buildStandalone() { 8 | console.log('Creating "standalone" version'); 9 | console.log('running tsc...'); 10 | 11 | // https://www.typescriptlang.org/docs/handbook/compiler-options.html 12 | execa.sync('tsc', ['--outDir', outDir], { stdio: 'inherit' }); 13 | 14 | console.log('✔︎'); 15 | 16 | console.log('running stc...'); 17 | 18 | // https://github.com/wix/stylable/tree/master/packages/cli#usage 19 | execa.sync( 20 | 'stc', 21 | [ 22 | `--outDir=${path.join(outDir, 'src')}`, 23 | '--srcDir=src', 24 | '--cssFilename=[filename].global.css', 25 | '--compat', 26 | '--cjs', 27 | '--css', 28 | '--icr', 29 | '--optimized' 30 | ], 31 | { stdio: 'inherit' }, 32 | ); 33 | 34 | console.log('✔︎'); 35 | } 36 | 37 | buildStandalone(); -------------------------------------------------------------------------------- /scripts/toESModules.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const glob = require('glob'); 3 | const path = require('path'); 4 | const ProgressBar = require('progress'); 5 | 6 | const targetDir = path.resolve(__dirname, '..', 'dist/es/src/components'); 7 | 8 | const STYLABLE_PATTERN = '/**/*.st.css'; 9 | const JS_PATTERN = '/**/*.js'; 10 | const STYLABLE_ES_PATTERN = '/**/*.es.st.css'; 11 | const stylableFiles = glob.sync(targetDir + STYLABLE_PATTERN, { ignore: [ targetDir + STYLABLE_ES_PATTERN ] }); 12 | const esFiles = glob.sync(targetDir + JS_PATTERN); 13 | 14 | const progress = new ProgressBar( 15 | 'Transpiling es style import paths in `dist/es` :bar :percent', 16 | { 17 | total: stylableFiles.length + esFiles.length, 18 | }, 19 | ); 20 | 21 | stylableFiles.forEach(filepath => { 22 | fs.readFile(filepath, 'utf-8', function (e, content) { 23 | if (e != null) { 24 | console.warn(e); 25 | return; 26 | } 27 | const codeWithEsImport = content.replace(/wix\-ui\-core\/index\.st\.css/g, 'wix-ui-core/index.es.st.css'); 28 | fs.writeFile(filepath, codeWithEsImport, function (e) { 29 | if (e) { 30 | console.warn(e); 31 | return; 32 | } 33 | progress.tick(1); 34 | }); 35 | }); 36 | }); 37 | 38 | esFiles.forEach(filepath => { 39 | fs.readFile(filepath, 'utf-8', function (e, content) { 40 | if (e != null) { 41 | console.warn(e); 42 | return; 43 | } 44 | content = content.replace(/wix\-ui\-core\/dist\/src/g, 'wix-ui-core/dist/es/src'); 45 | fs.writeFile(filepath, content, function (e) { 46 | if (e) { 47 | console.warn(e); 48 | return; 49 | } 50 | progress.tick(1); 51 | }); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /src/colors.st.css: -------------------------------------------------------------------------------- 1 | :import { 2 | -st-from: "wix-ui-core/dist/src/themes/backoffice/colors.st.css"; 3 | -st-named: D10-30; 4 | } 5 | 6 | :vars { 7 | /* DARK - Primary */ 8 | D10: #162D3D; /* Primary Text */ 9 | D20: #32536A; /* Secondary Text */ 10 | D30: #577083; 11 | D40: #7A92A5; /* Placeholder Text */ 12 | D50: #B6C1CD; /* Disabled - Text + System Icons */ 13 | D55: #CBD3DC; /* Disabled button - new version */ 14 | D60: #DFE5EB; /* Dividers, Disabled - Borders */ 15 | D70: #F0F4F7; /* Page Background, Disabled - Background */ 16 | D80: #FFFFFF; /* Content box background */ 17 | 18 | /* BLUE - Brand */ 19 | B00: #2B81CB; /* Button Focus */ 20 | B05: #308DDD; /* CTA */ 21 | B10: #3899EC; /* Main, Button */ 22 | B20: #4EB7F5; /* Hover for elements with B10, buttons, Notifications */ 23 | B25: #A1D7FB; 24 | B27: #B3E0FB; 25 | B30: #C1E4FE; 26 | B40: #DAEFFE; 27 | B50: #EAF7FF; 28 | B60: #F4FAFE; 29 | 30 | /* PURPLE - Premium */ 31 | P00: #8E21B1; 32 | P10: #AA4DC8; 33 | P20: #CD68ED; 34 | P30: #E5C9EE; 35 | P40: #EEDBF4; 36 | P50: #FAEEFF; 37 | P60: #FAF7FC; 38 | 39 | /* ORANGE - Used ONLY in Labels */ 40 | O00: #EA5F0E; 41 | O10: #FB7D33; 42 | O20: #FF9A48; 43 | 44 | /* RED - Danger or Destructive */ 45 | R00: #D6453D; 46 | R05: #D8504C; /* CTA */ 47 | R10: #EE5951; /* Main, Destructive Button */ 48 | R20: #FF6666; /* Notifications */ 49 | R30: #FFD7D7; 50 | R40: #FFE1E1; 51 | R50: #FFEBEB; 52 | R60: #FFF5F5; 53 | 54 | /* GREY - disabled */ 55 | GR10: #C8C8C8; /* Disabled buttons */ 56 | GR20: #DADADA; /* Disabled fields */ 57 | GR30: #F1F1F1; /* Disabled background */ 58 | GR40: #CBD3DC; /* Disabled button - new version - naming not final */ 59 | GR50: #EFF1F2; 60 | GR60: #A3ABB0; /* placeholder for InputArea theme="amaterial" */ 61 | 62 | 63 | /* GREEN - Success */ 64 | G00: #44823F; 65 | G05: #61AD5A; /* CTA */ 66 | G10: #60BC57; /* Main, Button */ 67 | G20: #80C979; /* Notifications */ 68 | G30: #C9EEBC; 69 | G40: #DEF4D4; 70 | G50: #EDF9E5; 71 | G60: #F2FBEF; 72 | 73 | /* YELLOW - Warning */ 74 | Y00: #C68801; 75 | Y05: #EDA200; /* CTA */ 76 | Y10: #FDB10C; /* Notification */ 77 | Y20: #FAC249; 78 | Y30: #FEF0BA; 79 | Y40: #FEF4CD; 80 | Y50: #FDF7DF; 81 | Y60: #FFFCF0; 82 | 83 | /* Focus */ 84 | F00: #AADBFC; 85 | 86 | /* Helpers */ 87 | TRANSPARENT: transparent; 88 | WHITE: #FFFFFF; 89 | BLACK: #000000; 90 | } 91 | -------------------------------------------------------------------------------- /src/common/testkitTests.ts: -------------------------------------------------------------------------------- 1 | import {mount} from 'enzyme'; 2 | import {isEnzymeTestkitExists, WrapperData} from 'wix-ui-test-utils/enzyme'; 3 | import {isTestkitExists} from 'wix-ui-test-utils/vanilla'; 4 | import {BaseDriver} from 'wix-ui-test-utils/driver-factory'; 5 | 6 | export interface TestkitSuiteParams { 7 | Element: React.ReactElement; 8 | testkitFactory: (obj: {wrapper: any; dataHook: string; }) => T; 9 | enzymeTestkitFactory: (obj: WrapperData) => T; 10 | } 11 | 12 | export function runTestkitExistsSuite(params: TestkitSuiteParams) { 13 | 14 | describe('testkits', () => { 15 | describe('vanilla', () => { 16 | it('should exist', () => { 17 | expect(isTestkitExists(params.Element, params.testkitFactory, {dataHookPropName: 'data-hook'})).toBe(true); 18 | }); 19 | }); 20 | 21 | describe('enzyme', () => { 22 | it('should exist', () => { 23 | expect(isEnzymeTestkitExists(params.Element, params.enzymeTestkitFactory, mount, {dataHookPropName: 'data-hook'})).toBe(true); 24 | }); 25 | }); 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /src/components/AddressInput/AddressInput.driver.ts: -------------------------------------------------------------------------------- 1 | export {addressInputDriverFactory} from 'wix-ui-core/drivers/vanilla'; 2 | -------------------------------------------------------------------------------- /src/components/AddressInput/AddressInput.e2e.ts: -------------------------------------------------------------------------------- 1 | import * as eyes from 'eyes.it'; 2 | import {$, browser, by} from 'protractor'; 3 | import * as autoExampleDriver from 'wix-storybook-utils/AutoExampleDriver'; 4 | import {getStoryUrl, waitForVisibilityOf} from 'wix-ui-test-utils/protractor'; 5 | import {addressInputTestkitFactory} from '../../testkit/protractor'; 6 | 7 | describe('AddressInput', () => { 8 | const storyUrl = getStoryUrl('Components', 'AddressInput'); 9 | let driver; 10 | 11 | beforeAll(async () => { 12 | await browser.get(storyUrl); 13 | driver = addressInputTestkitFactory({dataHook: 'storybook-address-input'}); 14 | await waitForVisibilityOf(driver.element(), 'Cannot find AddressInput'); 15 | }); 16 | 17 | afterEach(() => autoExampleDriver.reset()); 18 | 19 | eyes.it('should exist', () => { 20 | expect(driver.element().isPresent()).toBe(true); 21 | }); 22 | 23 | eyes.it('should display mocked addresses', async () => { 24 | driver.pressKey('n'); 25 | const optionCount = await driver.dropdownContent().getOptionsCount(); 26 | expect(optionCount).toBeGreaterThan(0); 27 | driver.pressKey('\b'); 28 | driver.pressKey('\t'); 29 | }); 30 | 31 | eyes.it('should display the disabled state', async () => { 32 | await autoExampleDriver.setProps({disabled: true}); 33 | const element = await driver.element(); 34 | const input = await element.element(by.css('input')); 35 | const isDisabled = await input.getAttribute('disabled'); 36 | expect(isDisabled).toBeTruthy(); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /src/components/AddressInput/AddressInput.protractor.driver.ts: -------------------------------------------------------------------------------- 1 | export {addressInputDriverFactory, AddressInputDriver} from 'wix-ui-core/drivers/protractor'; 2 | -------------------------------------------------------------------------------- /src/components/AddressInput/AddressInput.st.css: -------------------------------------------------------------------------------- 1 | :import { 2 | -st-from: "wix-ui-core/index.st.css"; 3 | -st-named: AddressInput; 4 | } 5 | 6 | :import { 7 | -st-from: "../Input/Input.st.css"; 8 | -st-default: Input; 9 | -st-named: inputHover; 10 | } 11 | 12 | :import { 13 | -st-from: "../Input/InputStates.st.css"; 14 | -st-named: input-large, input-medium, input-small; 15 | } 16 | 17 | :import { 18 | -st-from: "../../typography.st.css"; 19 | -st-named: fontRoman; 20 | } 21 | 22 | :import { 23 | -st-from: "../../colors.st.css"; 24 | -st-named: 25 | B10, B20, B30, B40, 26 | D10, D50, 27 | WHITE; 28 | } 29 | 30 | :import { 31 | -st-from: "../../shadows.st.css"; 32 | -st-named: shadow30; 33 | } 34 | 35 | .root { 36 | -st-extends: AddressInput; 37 | -st-states: size(enum(large, medium, small)); 38 | font-family: value(fontRoman); 39 | width: 100%; 40 | } 41 | 42 | .root > [data-hook="popover-content"] { 43 | border: none; 44 | border-radius: 8px; 45 | box-shadow: value(shadow30); 46 | width: 100%; 47 | overflow: hidden; 48 | } 49 | 50 | .root::inputComponent { 51 | -st-mixin: Input; 52 | } 53 | 54 | .root:size(large)::inputComponent { 55 | -st-mixin: input-large; 56 | } 57 | 58 | .root:size(medium)::inputComponent { 59 | -st-mixin: input-medium; 60 | } 61 | 62 | .root:size(small)::inputComponent { 63 | -st-mixin: input-small; 64 | } 65 | 66 | .root::dropdownContent::dropdownOption { 67 | white-space: nowrap; 68 | padding: 8px 20px; 69 | text-overflow: ellipsis; 70 | font-size: 16px; 71 | color: value(D10); 72 | overflow: hidden; 73 | } 74 | 75 | .root::dropdownContent::dropdownOption:hovered { 76 | background: value(inputHover); 77 | } 78 | 79 | .root::dropdownContent::dropdownOption:selected { 80 | background: value(B10); 81 | color: value(WHITE); 82 | } 83 | 84 | .root::dropdownContent::dropdownOption:selected:hovered { 85 | background: value(B20); 86 | color: value(WHITE); 87 | } 88 | 89 | .root::dropdownContent::dropdownOption:disabled { 90 | color: value(D50); 91 | } 92 | 93 | .root::dropdownContent::dropdownOption:not(:selectable) { 94 | padding: 0; 95 | } 96 | 97 | .search { 98 | width: 24px; 99 | height: 24px; 100 | fill: value(B10); 101 | } 102 | 103 | .root::inputComponent:disabled .search { 104 | fill: value(B40); 105 | } 106 | 107 | .root::inputComponent:disabled:hover .search { 108 | fill: value(B30); 109 | } 110 | -------------------------------------------------------------------------------- /src/components/AddressInput/AddressInput.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { 3 | AddressInput as CoreAddressInput, 4 | AddressInputProps as CoreAddressInputProps 5 | } from 'wix-ui-core/dist/src/components/address-input'; 6 | import style from './AddressInput.st.css'; 7 | import Location from 'wix-ui-icons-common/Location'; 8 | import { Omit } from '../../types/common'; 9 | import Search from 'wix-ui-icons-common/Search'; 10 | 11 | const THROTTLE_INTERVAL = 150; 12 | 13 | const excludePropsArray = [ 14 | 'forceContentElementVisibility', 15 | 'forceOptions', 16 | 'throttleInterval', 17 | 'locationIcon' 18 | ]; 19 | export type excludeProps = 20 | | 'forceContentElementVisibility' 21 | | 'forceOptions' 22 | | 'throttleInterval' 23 | | 'locationIcon'; 24 | 25 | export interface AddressInputProps 26 | extends Omit { 27 | size?: 'large' | 'medium' | 'small'; 28 | showLocationIcon?: boolean; 29 | magnifyingGlass?: boolean; 30 | } 31 | 32 | export class AddressInput extends React.PureComponent { 33 | static displayName = 'AddressInput'; 34 | addressInputRef; 35 | static bypassDefaultPropsTypecheck; 36 | static defaultProps = { 37 | size: 'medium', 38 | magnifyingGlass: true 39 | }; 40 | 41 | focus() { 42 | this.addressInputRef.focus(); 43 | } 44 | 45 | blur() { 46 | this.addressInputRef.blur(); 47 | } 48 | 49 | render() { 50 | const { size, showLocationIcon, magnifyingGlass, ...rest } = this.props; 51 | return ( 52 | } 59 | suffix={ 60 | magnifyingGlass ? : undefined 61 | } 62 | ref={ref => (this.addressInputRef = ref)} 63 | /> 64 | ); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/components/AddressInput/index.ts: -------------------------------------------------------------------------------- 1 | export {AddressInput} from './AddressInput'; 2 | -------------------------------------------------------------------------------- /src/components/Autocomplete/Autocomplete.driver.ts: -------------------------------------------------------------------------------- 1 | export {autocompleteDriverFactory} from 'wix-ui-core/drivers/vanilla'; 2 | -------------------------------------------------------------------------------- /src/components/Autocomplete/Autocomplete.e2e.ts: -------------------------------------------------------------------------------- 1 | import * as eyes from 'eyes.it'; 2 | import { getStoryUrl, waitForVisibilityOf } from 'wix-ui-test-utils/protractor'; 3 | import { browser } from 'protractor'; 4 | import { autocompleteTestkitFactory } from '../../testkit/protractor'; 5 | 6 | describe('Autocomplete', () => { 7 | const storyUrl = getStoryUrl('Components', 'Autocomplete'); 8 | const dataHook = 'storybook-autocomplete'; 9 | 10 | beforeEach(() => browser.get(storyUrl)); 11 | 12 | eyes.it('should render autocomplete', async () => { 13 | const driver = autocompleteTestkitFactory({ dataHook }); 14 | await waitForVisibilityOf(driver.element(), 'Cannot find Autocomplete'); 15 | expect(driver.element()).toBeDefined(); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /src/components/Autocomplete/Autocomplete.protractor.driver.ts: -------------------------------------------------------------------------------- 1 | export {autocompleteDriverFactory, AutocompleteDriver} from 'wix-ui-core/drivers/protractor'; 2 | -------------------------------------------------------------------------------- /src/components/Autocomplete/Autocomplete.spec.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import {createDriverFactory} from 'wix-ui-test-utils/driver-factory'; 3 | import {autocompleteDriverFactory} from './Autocomplete.driver'; 4 | import {Autocomplete} from '.'; 5 | import {autocompleteTestkitFactory} from '../../testkit'; 6 | import {autocompleteTestkitFactory as enzymeAutocompleteTestkitFactory} from '../../testkit/enzyme'; 7 | import {isEnzymeTestkitExists} from 'wix-ui-test-utils/enzyme'; 8 | import {isTestkitExists} from 'wix-ui-test-utils/vanilla'; 9 | import {mount} from 'enzyme'; 10 | 11 | describe('Autocomplete', () => { 12 | const createDriver = createDriverFactory(autocompleteDriverFactory); 13 | 14 | it('should render autocomplete', () => { 15 | const driver = createDriver(); 16 | expect(driver.isTargetElementExists()).toBeTruthy(); 17 | expect(driver.isContentElementExists()).toBeFalsy(); 18 | }); 19 | 20 | describe('testkit', () => { 21 | it('should exist', () => { 22 | expect(isTestkitExists(, autocompleteTestkitFactory)).toBe(true); 23 | }); 24 | }); 25 | 26 | describe('enzyme testkit', () => { 27 | it('should exist', () => { 28 | expect(isEnzymeTestkitExists(, enzymeAutocompleteTestkitFactory, mount)).toBe(true); 29 | }); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /src/components/Autocomplete/Autocomplete.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { 3 | Autocomplete as CoreAutocomplete, 4 | AutocompleteProps as CoreAutocompleteProps 5 | } from 'wix-ui-core/dist/src/components/autocomplete'; 6 | import { withStylable } from 'wix-ui-core/dist/src/utils/withStylable'; 7 | import ChevronDown from 'wix-ui-icons-common/ChevronDown'; 8 | import style from './Autocomplete.st.css'; 9 | import { getInputSuffix } from '../Input'; 10 | 11 | export interface AutocompleteProps { 12 | // The size of the autocomplete 13 | size?: 'large' | 'medium' | 'small'; 14 | } 15 | 16 | const defaultProps = { 17 | size: 'medium' 18 | }; 19 | 20 | const StyledAutocomplete = withStylable< 21 | CoreAutocompleteProps, 22 | AutocompleteProps 23 | >(CoreAutocomplete, style, ({ size }) => ({ size }), defaultProps); 24 | 25 | export type AutocompleteType = React.SFC< 26 | CoreAutocompleteProps & AutocompleteProps 27 | > & { 28 | createOption: typeof CoreAutocomplete.createOption; 29 | createDivider: typeof CoreAutocomplete.createDivider; 30 | }; 31 | 32 | const defaultSuffix = ; 33 | export const Autocomplete: AutocompleteType = (( 34 | props: CoreAutocompleteProps & AutocompleteProps 35 | ) => { 36 | const { error, disabled, suffix } = props; 37 | const inputSuffix = getInputSuffix({ 38 | error, 39 | disabled, 40 | suffix: defaultSuffix 41 | }); 42 | 43 | return ( 44 | 49 | {suffix} 50 | {inputSuffix} 51 | 52 | ) : ( 53 | inputSuffix 54 | ) 55 | } 56 | /> 57 | ); 58 | }) as AutocompleteType; 59 | 60 | Autocomplete.displayName = 'Autocomplete'; 61 | 62 | Autocomplete.createOption = CoreAutocomplete.createOption; 63 | Autocomplete.createDivider = CoreAutocomplete.createDivider; 64 | -------------------------------------------------------------------------------- /src/components/Autocomplete/index.ts: -------------------------------------------------------------------------------- 1 | export {Autocomplete} from './Autocomplete'; 2 | -------------------------------------------------------------------------------- /src/components/Autocomplete/readme.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | dropdown like component where trigger is input 4 | 5 | ### Usage example 6 | 7 | ```js 8 | import {Autocomplete} from 'wix-ui-backoffice/Autocomplete'; 9 | 10 | const options = [ 11 | Autocomplete.createOption({value: `value0`}), // generates an option with a unique id 12 | Autocomplete.createOption({id: 1, value: `value1`}), // generates an option with id, value 13 | Autocomplete.createOption({id: 2, value: `value2`, isDisabled: true}), // genrates a disabled option 14 | Autocomplete.createOption({id: 3, value: `value3`, isSelectable: false}), // generates an unselectable option 15 | Autocomplete.createOption({id: 4, value: `value4`, render: value => value + 's'}), // generates an option with a custom render function 16 | Autocomplete.createDivider(), // generates default divider 17 | Autocomplete.createDivider('Value') // generates a divider with value 18 | ]; 19 | 20 | null} 23 | initialSelectedId={null || 1} 24 | fixedHeader={'Fixed Header'} 25 | fixedFooter={'Fixed Footer'} 26 | onManualInput={value => null} 27 | autoFocus={false} 28 | disabled={false} 29 | onBlur={event => null} 30 | onChange={event => null} 31 | onFocus={event => null} 32 | placeholder={'This is a placeholder'} 33 | error={false || 'Error message'} 34 | size={'large' || 'medium' || 'small'} 35 | /> 36 | ``` 37 | -------------------------------------------------------------------------------- /src/components/Badge/Badge.driver.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFactory } from 'wix-ui-test-utils/driver-factory'; 2 | import { StylableDOMUtil } from '@stylable/dom-test-kit'; 3 | import style from './Badge.st.css'; 4 | import { Type, Skin, Size } from './constants'; 5 | 6 | export interface BadgeDriver { 7 | exists: () => boolean, 8 | getContent: () => string, 9 | text: () => string, 10 | getType: () => Type, 11 | getSkin: () => Skin, 12 | getSize: () => Size, 13 | isUppercase: () => boolean, 14 | hasClickCursor: () => boolean, 15 | getPrefixIcon: () => Element | null, 16 | getSuffixIcon: () => Element | null, 17 | click: () => void 18 | } 19 | 20 | 21 | export const badgeDriverFactory = (factoryParams: ComponentFactory): BadgeDriver => { 22 | const { element, eventTrigger } = factoryParams; 23 | const stylableDOMUtil = new StylableDOMUtil(style, element); 24 | 25 | return { 26 | /** checks if element exists */ 27 | exists: () => !!element, 28 | /** returns elements innerHtml */ 29 | getContent: () => element.innerHTML, 30 | /** returns elements text */ 31 | text: () => element.textContent, 32 | getType: () => stylableDOMUtil.getStyleState(element, 'type') as Type, 33 | getSkin: () => stylableDOMUtil.getStyleState(element, 'skin') as Skin, 34 | getSize: () => stylableDOMUtil.getStyleState(element, 'size') as Size, 35 | isUppercase: () => stylableDOMUtil.getStyleState(element, 'uppercase') === 'true', 36 | hasClickCursor: () => stylableDOMUtil.getStyleState(element, 'clickable') === 'true', 37 | getPrefixIcon: () => stylableDOMUtil.select('.prefix'), 38 | getSuffixIcon: () => stylableDOMUtil.select('.suffix'), 39 | click: () => eventTrigger.click(element) 40 | }; 41 | }; 42 | -------------------------------------------------------------------------------- /src/components/Badge/Badge.e2e.ts: -------------------------------------------------------------------------------- 1 | import * as eyes from 'eyes.it'; 2 | import {$, browser, Key} from 'protractor'; 3 | import {getStoryUrl, scrollToElement, waitForVisibilityOf} from 'wix-ui-test-utils/protractor'; 4 | import {badgeTestkitFactory} from '../../testkit/protractor'; 5 | import * as autoExampleDriver from 'wix-storybook-utils/AutoExampleDriver'; 6 | 7 | const byDataHook = dataHook => $(`[data-hook="${dataHook}"]`); 8 | 9 | // TODO: move method to protractor-helpers, or to the AutoExampleDriver? 10 | const focusElementInAutoExample = async element => { 11 | const parentElement = await element.getWebElement().getDriver(); 12 | 13 | await parentElement 14 | .actions() 15 | .click() 16 | .perform(); 17 | 18 | await browser 19 | .actions() 20 | .sendKeys(Key.TAB) 21 | .perform(); 22 | }; 23 | 24 | describe('Badge', () => { 25 | const storyUrl = getStoryUrl('Components', 'Badge'); 26 | 27 | beforeEach(() => browser.get(storyUrl)); 28 | 29 | describe('AutoExample', () => { 30 | 31 | beforeEach(async () => { 32 | await autoExampleDriver.reset(); 33 | }); 34 | 35 | eyes.it('should display correct content', async () => { 36 | const driver = badgeTestkitFactory({dataHook: 'storybook-badge'}); 37 | await waitForVisibilityOf(driver.element(), 'Cannot find Badge'); 38 | expect(await driver.text()).toBe('I\'M A BADGE!'); 39 | }); 40 | 41 | eyes.it('should not have a focus state when onClick prop is not used', async () => { 42 | await autoExampleDriver.setProps({onClick: undefined}); 43 | 44 | const driver = badgeTestkitFactory({dataHook: 'storybook-badge'}); 45 | await waitForVisibilityOf(driver.element(), 'Cannot find Badge'); 46 | await focusElementInAutoExample(driver.element()); 47 | }); 48 | 49 | eyes.it('should have a focus state when onClick prop is used', async () => { 50 | await autoExampleDriver.setProps({onClick: () => true}); 51 | 52 | const driver = badgeTestkitFactory({dataHook: 'storybook-badge'}); 53 | await waitForVisibilityOf(driver.element(), 'Cannot find Badge'); 54 | await focusElementInAutoExample(driver.element()); 55 | }); 56 | }); 57 | 58 | eyes.it('should not break design', async () => { 59 | const dataHook = 'badge-variations'; 60 | const element = byDataHook(dataHook); 61 | await waitForVisibilityOf(element, `Cannot find ${dataHook}`); 62 | await scrollToElement(element); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /src/components/Badge/Badge.protractor.driver.ts: -------------------------------------------------------------------------------- 1 | import {isFocused} from 'wix-ui-test-utils/protractor'; 2 | import {BaseDriver, DriverFactory} from 'wix-ui-core/dist/src/common/BaseDriver.protractor'; 3 | 4 | export interface BadgeDriver extends BaseDriver { 5 | text: () => Promise; 6 | } 7 | 8 | export const badgeDriverFactory: DriverFactory = component => ({ 9 | /** returns the component element */ 10 | element: () => component, 11 | /** returns the component text */ 12 | text: async () => component.getText() 13 | }); 14 | -------------------------------------------------------------------------------- /src/components/Badge/Badge.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import {SKIN, TYPE, SIZE, Type, Skin, Size} from './constants'; 3 | import style from './Badge.st.css'; 4 | 5 | export interface BadgeProps { 6 | type?: Type; 7 | skin?: Skin; 8 | size?: Size; 9 | prefixIcon?: React.ReactElement; 10 | suffixIcon?: React.ReactElement; 11 | onClick?: React.EventHandler>; 12 | uppercase?: boolean; 13 | 14 | focusableOnFocus?: () => void; 15 | focusableOnBlur?: () => void; 16 | 17 | /** usually just text to be displayed */ 18 | children: React.ReactNode; 19 | } 20 | 21 | const defaultProps = { 22 | type: TYPE.solid, 23 | skin: SKIN.general, 24 | size: SIZE.medium, 25 | uppercase: true 26 | }; 27 | 28 | export class Badge extends React.PureComponent { 29 | static displayName = 'Badge'; 30 | 31 | static defaultProps = defaultProps; 32 | 33 | render() { 34 | const { 35 | children, 36 | prefixIcon, 37 | suffixIcon, 38 | onClick, 39 | focusableOnFocus, 40 | focusableOnBlur, 41 | ...rest 42 | } = this.props; 43 | 44 | const focusableProps = onClick ? { 45 | onFocus: focusableOnFocus, 46 | onBlur: focusableOnBlur, 47 | 'tabIndex': 0 48 | } : {}; 49 | 50 | return ( 51 |
56 | {prefixIcon && React.cloneElement(prefixIcon, {className: style.prefix})} 57 | {children} 58 | {suffixIcon && React.cloneElement(suffixIcon, {className: style.suffix})} 59 |
60 | ); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/components/Badge/constants.ts: -------------------------------------------------------------------------------- 1 | export type Skin = 'general' | 'standard' | 'danger' | 'success' | 'neutral' | 'warning' | 'urgent' | 'neutralStandard' | 'neutralSuccess' | 'nutralDanger' | 'premium'; 2 | 3 | export type Type = 'solid' | 'outlined' | 'transparent'; 4 | 5 | export type Size = 'medium' | 'small'; 6 | 7 | export const SKIN = { 8 | general: 'general', 9 | standard: 'standard', 10 | danger: 'danger', 11 | success: 'success', 12 | neutral: 'neutral', 13 | neutralLight: 'neutralLight', 14 | warning: 'warning', 15 | warningLight: 'warningLight', 16 | urgent: 'urgent', 17 | neutralStandard: 'neutralStandard', 18 | neutralSuccess: 'neutralSuccess', 19 | neutralDanger: 'neutralDanger', 20 | premium: 'premium', 21 | }; 22 | 23 | export const TYPE = { 24 | solid: 'solid', 25 | outlined: 'outlined', 26 | transparent: 'transparent' 27 | }; 28 | 29 | export const SIZE = { 30 | medium: 'medium', 31 | small: 'small' 32 | }; 33 | -------------------------------------------------------------------------------- /src/components/Badge/index.ts: -------------------------------------------------------------------------------- 1 | import {Badge as BadgeComponent} from './Badge'; 2 | import {createHOC} from 'wix-ui-core/dist/src/createHOC'; 3 | import {withFocusable} from 'wix-ui-core/dist/src/hocs/Focusable/FocusableHOC'; 4 | 5 | export const Badge = createHOC( 6 | withFocusable(BadgeComponent) 7 | ); 8 | 9 | export * from './constants' 10 | -------------------------------------------------------------------------------- /src/components/Button/Button.driver.ts: -------------------------------------------------------------------------------- 1 | import { StylableDOMUtil } from '@stylable/dom-test-kit'; 2 | import { buttonDriverFactory as coreButtonDriverFactory, ButtonDriver as CoreButtonDriver } from 'wix-ui-core/drivers/vanilla'; 3 | import { DriverFactory, BaseDriver, ComponentFactory } from 'wix-ui-test-utils/driver-factory'; 4 | import style from './Button.st.css'; 5 | import { Skin, Priority, Size } from './constants'; 6 | 7 | export interface ButtonDriver extends CoreButtonDriver { 8 | getSkin: () => Skin; 9 | getPriority: () => Priority; 10 | getSize: () => Size; 11 | } 12 | 13 | export const buttonDriverFactory: DriverFactory = (factoryParams: ComponentFactory): ButtonDriver => { 14 | const { element } = factoryParams; 15 | const stylableDOMUtil = new StylableDOMUtil(style, element); 16 | const getStyleState = (stateName: string) => stylableDOMUtil.getStyleState(element, stateName) as any as T | null; 17 | 18 | return { 19 | ...coreButtonDriverFactory(factoryParams), 20 | getSkin: () => getStyleState('skin'), 21 | getPriority: () => getStyleState('priority'), 22 | getSize: () => getStyleState('size'), 23 | }; 24 | }; 25 | -------------------------------------------------------------------------------- /src/components/Button/Button.e2e.ts: -------------------------------------------------------------------------------- 1 | import { storySettings } from './../../../stories/Button/storySettings'; 2 | import * as eyes from 'eyes.it'; 3 | import { browser } from 'protractor'; 4 | import { createStoryUrl , mouseEnter, mouseLeave} from 'wix-ui-test-utils/protractor'; 5 | import { buttonTestkitFactory } from '../../testkit/protractor'; 6 | import { Skin, Size, Priority } from './constants'; 7 | import * as autoExampleDriver from 'wix-storybook-utils/AutoExampleDriver'; 8 | import { enumValues } from '../../utils'; 9 | 10 | describe('Button', () => { 11 | const storyUrl = createStoryUrl({ kind: storySettings.kind, story: storySettings.story, withExamples: false }); 12 | const dataHook = 'storybook-button'; 13 | 14 | beforeAll(() => browser.get(storyUrl)); 15 | afterEach(() => autoExampleDriver.reset()); 16 | 17 | eyes.it('should render with default props', async () => { 18 | const driver = buttonTestkitFactory({ dataHook }); 19 | expect(await driver.element().isPresent()).toBeTruthy(); 20 | }); 21 | 22 | eyes.it('should render in all sizes', async () => { 23 | for (let size of enumValues(Size)) { 24 | await autoExampleDriver.setProps({ size }) 25 | eyes.checkWindow(`size=${size}`); 26 | } 27 | }); 28 | 29 | eyes.it('should render in all skins and priorities', async () => { 30 | for (let skin of enumValues(Skin)) { 31 | for (let priority of enumValues(Priority)) { 32 | await autoExampleDriver.setProps({ skin, priority }); 33 | eyes.checkWindow(`[skin=${skin}, priority=${priority}]`); 34 | } 35 | } 36 | }); 37 | 38 | eyes.it('should render in all skins and priorities when hovered', async () => { 39 | for (let skin of enumValues(Skin)) { 40 | for (let priority of enumValues(Priority)) { 41 | await autoExampleDriver.setProps({ skin, priority }); 42 | const driver = buttonTestkitFactory({ dataHook }); 43 | await mouseEnter(driver.element()); 44 | await eyes.checkWindow(`[skin=${skin}, priority=${priority}]`); 45 | await mouseLeave(); 46 | } 47 | } 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /src/components/Button/Button.protractor.driver.ts: -------------------------------------------------------------------------------- 1 | export {buttonDriverFactory, ButtonDriver} from 'wix-ui-core/drivers/protractor'; 2 | -------------------------------------------------------------------------------- /src/components/Button/Button.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { 3 | Button as CoreButton, 4 | ButtonProps as CoreButtonProps 5 | } from 'wix-ui-core/dist/src/components/deprecated/button'; 6 | import { enumValues } from '../../utils'; 7 | import style from './Button.st.css'; 8 | import { Skin, Priority, Size } from './constants'; 9 | import { Text, TextProps, TextSkin, TextSize } from '../Text'; 10 | 11 | export interface ButtonOwnProps extends CoreButtonProps { 12 | /**Skin of the Button (Styling)*/ 13 | skin?: Skin; 14 | /** Priority of the Button (Styling)*/ 15 | priority?: Priority; 16 | /** Size of the button (Styling) */ 17 | size?: Size; 18 | /** The button's text */ 19 | children?: string; 20 | } 21 | 22 | export type ButtonProps = ButtonOwnProps & CoreButtonProps; 23 | const toTextColorProps: { 24 | [k in Priority]: { [y in Skin]: Pick } 25 | } = { 26 | [Priority.primary]: { 27 | [Skin.standard]: { skin: TextSkin.standard, light: true }, 28 | [Skin.white]: { skin: TextSkin.standard, light: false }, 29 | [Skin.destructive]: { skin: TextSkin.standard, light: true }, 30 | [Skin.premium]: { skin: TextSkin.standard, light: true } 31 | }, 32 | [Priority.secondary]: { 33 | [Skin.standard]: { skin: TextSkin.standard, light: false }, 34 | [Skin.white]: { skin: TextSkin.standard, light: true }, 35 | [Skin.destructive]: { skin: TextSkin.error, light: false }, 36 | [Skin.premium]: { skin: TextSkin.premium, light: false } 37 | } 38 | }; 39 | 40 | export const Button: React.SFC = props => { 41 | const { children, skin, priority, size, ...rest } = props; 42 | const textColorProps = toTextColorProps[priority][skin]; 43 | const textSize = 44 | size === Size.large || size === Size.medium 45 | ? TextSize.medium 46 | : TextSize.small; 47 | 48 | return ( 49 | 50 | 56 | {children} 57 | 58 | 59 | ); 60 | }; 61 | 62 | Button.displayName = 'Button'; 63 | 64 | Button.defaultProps = { 65 | skin: Skin.standard, 66 | priority: Priority.primary, 67 | size: Size.medium 68 | }; 69 | -------------------------------------------------------------------------------- /src/components/Button/constants.ts: -------------------------------------------------------------------------------- 1 | export enum Skin { 2 | standard = 'standard', 3 | white = 'light', 4 | destructive = 'destructive', 5 | premium = 'premium' 6 | } 7 | 8 | export enum Priority { 9 | primary = 'primary', 10 | secondary = 'secondary' 11 | } 12 | 13 | export enum Size { 14 | large = 'large', 15 | medium = 'medium', 16 | small = 'small', 17 | tiny = 'tiny' 18 | } 19 | -------------------------------------------------------------------------------- /src/components/Button/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | Button, 3 | ButtonProps, 4 | } from './Button'; 5 | 6 | export { 7 | Skin as ButtonSkin, 8 | Priority as ButtonPriority, 9 | Size as ButtonSize 10 | } from './constants'; 11 | -------------------------------------------------------------------------------- /src/components/Checkbox/Checkbox.driver.ts: -------------------------------------------------------------------------------- 1 | import {checkboxDriverFactory as CheckboxDriverFactory} from 'wix-ui-core/drivers/vanilla'; 2 | 3 | export const checkboxDriverFactory = ({element, eventTrigger}) => { 4 | return { 5 | ...CheckboxDriverFactory({element, eventTrigger}) 6 | }; 7 | }; 8 | -------------------------------------------------------------------------------- /src/components/Checkbox/Checkbox.e2e.ts: -------------------------------------------------------------------------------- 1 | import * as eyes from 'eyes.it'; 2 | import {getStoryUrl, scrollToElement, mouseLeave} from 'wix-ui-test-utils/protractor'; 3 | import {checkboxTestkitFactory} from 'wix-ui-core/dist/src/testkit/protractor'; 4 | import {browser} from 'protractor'; 5 | import * as autoExampleDriver from 'wix-storybook-utils/AutoExampleDriver'; 6 | 7 | describe('Checkbox', () => { 8 | const storyUrl = getStoryUrl('Components', 'Checkbox'); 9 | const dataHook = 'storybook-checkbox'; 10 | 11 | beforeAll(() => browser.get(storyUrl)); 12 | afterEach(async () => { 13 | await autoExampleDriver.reset(); 14 | }); 15 | 16 | describe('not hovered', () => { 17 | eyes.it('should be unchecked', async () => { 18 | const driver = checkboxTestkitFactory({dataHook}); 19 | expect(await driver.isChecked()).toBeFalsy(); 20 | }); 21 | 22 | eyes.it('should be checked', async () => { 23 | await autoExampleDriver.setProps({checked: true}); 24 | const driver = checkboxTestkitFactory({dataHook}); 25 | expect(await driver.isChecked()).toBeTruthy(); 26 | }); 27 | 28 | eyes.it('should be indetermined', async () => { 29 | await autoExampleDriver.setProps({indeterminate: true}); 30 | const driver = checkboxTestkitFactory({dataHook}); 31 | // TODO: implement driver.isIndeterminate() in wix-ui-core 32 | // expect(await driver.isIndeterminate()).toBeTruthy(); 33 | }); 34 | }); 35 | 36 | 37 | it('should be unchecked and not disabled by default', async () => { 38 | const driver = checkboxTestkitFactory({dataHook}); 39 | expect(await driver.isChecked()).toBe(false); 40 | expect(await driver.isDisabled()).toBe(false); 41 | }); 42 | 43 | it('should be checked when clicked', async () => { 44 | const driver = checkboxTestkitFactory({dataHook}); 45 | expect(await driver.isChecked()).toBe(false); 46 | await driver.click(); 47 | expect(await driver.isChecked()).toBe(true); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /src/components/Checkbox/Checkbox.st.css: -------------------------------------------------------------------------------- 1 | :import { 2 | -st-from: "wix-ui-core/index.st.css"; 3 | -st-named: Checkbox; 4 | } 5 | 6 | :import { 7 | -st-from: "../../colors.st.css"; 8 | -st-named: 9 | B10, B20, B50, 10 | D50, D60, D70, 11 | GR20, 12 | R10, R30, 13 | WHITE, 14 | F00; 15 | } 16 | 17 | :vars { 18 | boxSize: 16px; 19 | focusVisibleShadow: 0 0 0 3px; 20 | } 21 | 22 | .root { 23 | -st-extends: Checkbox; 24 | display: inline-flex; 25 | align-items: center; 26 | } 27 | 28 | .root:disabled { 29 | pointer-events: none; 30 | } 31 | 32 | .root::childContainer { 33 | font-size: 16px; 34 | padding-left: 12px; 35 | } 36 | 37 | .root:disabled::childContainer { 38 | color: value(D70); 39 | } 40 | 41 | .root::box { 42 | background: value(WHITE); 43 | border-radius: 4px; 44 | border: solid 1px value(B20); 45 | box-sizing: border-box; 46 | width: value(boxSize); 47 | height: value(boxSize); 48 | display: flex; 49 | align-items: center; 50 | justify-content: center; 51 | } 52 | 53 | .root:disabled::box { 54 | background-color: value(D70); 55 | border-color: value(GR20); 56 | } 57 | 58 | .root:disabled:checked::box { 59 | border-color: value(D60); 60 | } 61 | 62 | .root::box:active { 63 | background-color: value(B20); 64 | } 65 | 66 | .root:error::box { 67 | border-color: value(R10); 68 | } 69 | 70 | .root:focus-visible::box { 71 | box-shadow: value(focusVisibleShadow) value(F00); 72 | border-color: value(B10); 73 | } 74 | 75 | .root:error:focus-visible::box { 76 | border-color: value(R10); 77 | box-shadow: value(focusVisibleShadow) value(R30); 78 | } 79 | 80 | .root:hover:not(:disabled):not(:checked):not(:active)::box { 81 | background-color: value(B50); 82 | } 83 | 84 | .root:checked:not(:active):not(:disabled)::box { 85 | background-color: value(B10); 86 | } 87 | 88 | .root:indeterminate:not(:disabled):not(:checked):not(:active)::box { 89 | background-color: value(B10); 90 | } 91 | 92 | .root:hover:indeterminate:not(:disabled):not(:checked):not(:active)::box { 93 | color: value(B50); 94 | } 95 | 96 | .checkedIcon { 97 | width: 9px; 98 | height: 9px; 99 | } 100 | 101 | .indeterminateIcon { 102 | width: 8px; 103 | height: 8px; 104 | } 105 | 106 | .root::box svg { 107 | fill: value(WHITE); 108 | } 109 | 110 | .root:disabled::box svg { 111 | fill: value(D50); 112 | } 113 | -------------------------------------------------------------------------------- /src/components/Checkbox/Checkbox.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { 3 | Checkbox as CoreCheckbox, 4 | CheckboxProps as CoreCheckboxProps 5 | } from 'wix-ui-core/dist/src/components/checkbox'; 6 | import CheckboxChecked from 'wix-ui-icons-common/system/CheckboxChecked'; 7 | import CheckboxIndeterminate from 'wix-ui-icons-common/system/CheckboxIndeterminate'; 8 | import style from './Checkbox.st.css'; 9 | import { withStylable } from 'wix-ui-core/dist/src/utils/withStylable'; 10 | 11 | const defaultProps = { 12 | checkedIcon: , 13 | indeterminateIcon: ( 14 | 15 | ) 16 | }; 17 | 18 | export const Checkbox = withStylable( 19 | CoreCheckbox, 20 | style, 21 | () => null, 22 | defaultProps 23 | ); 24 | 25 | Checkbox.displayName = 'Checkbox'; 26 | -------------------------------------------------------------------------------- /src/components/Checkbox/index.ts: -------------------------------------------------------------------------------- 1 | export {Checkbox} from './Checkbox'; 2 | -------------------------------------------------------------------------------- /src/components/CircularProgressBar/CircularProgressBar.driver.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFactory } from 'wix-ui-test-utils/driver-factory'; 2 | import { 3 | circularProgressBarDriverFactory as coreCircularProgressBarDriverFactory, 4 | CircularProgressBarDriver as CoreCircularProgressBarDriver 5 | } from 'wix-ui-core/drivers/vanilla'; 6 | import { BaseDriver, DriverFactory } from 'wix-ui-test-utils/driver-factory'; 7 | import { tooltipDriverFactory } from '../Tooltip/Tooltip.driver' 8 | import { StylableDOMUtil } from '@stylable/dom-test-kit'; 9 | import style from './CircularProgressBar.st.css'; 10 | import { Size } from './constants'; 11 | 12 | export interface CircularProgressBarDriver extends CoreCircularProgressBarDriver { 13 | /* Returns true if the tooltip is shown */ 14 | isTooltipShown: () => boolean; 15 | /* Returns true if the error icon is shown */ 16 | isErrorIconShown: () => boolean; 17 | /* Returns true if the success icon is shown */ 18 | isSuccessIconShown: () => boolean; 19 | /* Returns the tooltip driver */ 20 | getTooltip: () => any; 21 | /* Returns bars size */ 22 | getSize: () => Size; 23 | 24 | } 25 | 26 | export const circularProgressBarDriverFactory: DriverFactory = ({ element, eventTrigger, wrapper }: ComponentFactory): CircularProgressBarDriver => { 27 | const createTooltipDriver = () => tooltipDriverFactory({ element: element.querySelector(`[data-hook='circular-progressbar-tooltip']`), wrapper, eventTrigger }); 28 | const coreProgressBarDriver = coreCircularProgressBarDriverFactory({ element, wrapper, eventTrigger }); 29 | const errorIcon = () => element.querySelector(`[data-hook='error-icon']`); 30 | const successIcon = () => element.querySelector(`[data-hook='success-icon']`); 31 | const progressBar = () => element.querySelector(`[data-hook='circular-progress-bar']`); 32 | const stylableDOMUtil = new StylableDOMUtil(style, element); 33 | 34 | return { 35 | ...coreProgressBarDriver, 36 | isTooltipShown: () => createTooltipDriver().isContentElementExists(), 37 | getTooltip: () => createTooltipDriver(), 38 | isErrorIconShown: () => !!errorIcon(), 39 | isSuccessIconShown: () => !!successIcon(), 40 | getSize: () => stylableDOMUtil.getStyleState(progressBar(), 'size') as Size, 41 | }; 42 | } 43 | -------------------------------------------------------------------------------- /src/components/CircularProgressBar/CircularProgressBar.protractor.driver.ts: -------------------------------------------------------------------------------- 1 | import {$, ElementFinder} from 'protractor'; 2 | import {DriverFactory} from 'wix-ui-core/dist/src/common/BaseDriver.protractor'; 3 | import {circularProgressBarDriverFactory as coreCircularProgressBarDriverFactory, CircularProgressBarDriver as CoreCircularProgressBarDriver} from 'wix-ui-core/drivers/protractor'; 4 | 5 | export interface CircularProgressBarDriver extends CoreCircularProgressBarDriver { 6 | /** Get tooltip that appears on error icons */ 7 | getTooltip?: () => ElementFinder; 8 | } 9 | 10 | export const circularProgressBarDriverFactory: DriverFactory = (element: ElementFinder): CircularProgressBarDriver => { 11 | return { 12 | ...coreCircularProgressBarDriverFactory($(`[data-hook='circular-progress-bar']`)), 13 | getTooltip: () => $(`[data-hook='circular-progressbar-tooltip']`), 14 | }; 15 | }; 16 | -------------------------------------------------------------------------------- /src/components/CircularProgressBar/CircularProgressBar.st.css: -------------------------------------------------------------------------------- 1 | :import { 2 | -st-from: "wix-ui-core/index.st.css"; 3 | -st-named: CircularProgressBar; 4 | } 5 | 6 | :import { 7 | -st-from: "../../colors.st.css"; 8 | -st-named: 9 | B00, B30, 10 | D20, 11 | R00, R10, R30, 12 | WHITE, 13 | } 14 | 15 | :import { 16 | -st-from: "../../typography.st.css"; 17 | -st-named: fontMedium; 18 | } 19 | 20 | .progressBar { 21 | -st-states: light, size(enum(small, medium, large)); 22 | -st-extends: CircularProgressBar; 23 | } 24 | 25 | .root { 26 | display: inline-block; 27 | } 28 | 29 | .root .progressBar::foreArc { 30 | stroke: value(B00); 31 | } 32 | 33 | .root .progressBar::backArc { 34 | stroke: value(B30); 35 | } 36 | 37 | .root .progressBar:error::foreArc { 38 | stroke: value(R00); 39 | } 40 | 41 | .root .progressBar:error::backArc { 42 | stroke: value(R30); 43 | } 44 | 45 | .root .progressBar:light::backArc { 46 | stroke: value(WHITE); 47 | } 48 | 49 | .root .progressBar::statusIndicator { 50 | width: 20px; 51 | height: 20px; 52 | display: flex; 53 | justify-content: center; 54 | align-items: center; 55 | z-index: 1; 56 | } 57 | 58 | .root .progressBar:success::statusIndicator { 59 | color: value(B00); 60 | } 61 | 62 | .root .progressBar:error::statusIndicator { 63 | color: value(R10); 64 | } 65 | 66 | .root .progressBar::statusIndicator svg { 67 | height: 15px; 68 | width: 20px; 69 | } 70 | 71 | .root .progressBar:size(small)::statusIndicator svg { 72 | height: 9px; 73 | width: 12px; 74 | } 75 | 76 | .root .progressBar::progressIndicator { 77 | color: value(D20); 78 | font-family: value(fontMedium); 79 | font-size: 10px; 80 | font-weight: 500; 81 | margin-top: 18px; 82 | } 83 | -------------------------------------------------------------------------------- /src/components/CircularProgressBar/CircularProgressBar.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { 3 | CircularProgressBar as CoreCircularProgressBar, 4 | CircularProgressBarProps as CoreCircularProgressBarProps 5 | } from 'wix-ui-core/circular-progress-bar'; 6 | import CircleLoaderCheck from 'wix-ui-icons-common/system/CircleLoaderCheck'; 7 | import CircleLoaderCheckSmall from 'wix-ui-icons-common/system/CircleLoaderCheckSmall'; 8 | import FormFieldError from 'wix-ui-icons-common/system/FormFieldError'; 9 | import FormFieldErrorSmall from 'wix-ui-icons-common/system/FormFieldErrorSmall'; 10 | import style from './CircularProgressBar.st.css'; 11 | import { Tooltip } from '../Tooltip'; 12 | import { Size, sizesMap } from './constants'; 13 | import { enumValues } from '../../utils'; 14 | import { Omit } from '../../types/common'; 15 | 16 | export interface CircularProgressBarProps 17 | extends Omit { 18 | /** message to display when an error happens */ 19 | errorMessage?: string; 20 | /** use light theme instead of dark theme */ 21 | light?: boolean; 22 | /** size of the bar */ 23 | size?: Size; 24 | } 25 | 26 | const sizeToSuccessIcon = { 27 | [Size.small]: , 28 | [Size.medium]: , 29 | [Size.large]: 30 | }; 31 | 32 | const sizeToErrorIcon = { 33 | [Size.small]: , 34 | [Size.medium]: , 35 | [Size.large]: 36 | }; 37 | 38 | export const CircularProgressBar: React.SFC = ( 39 | props: CircularProgressBarProps 40 | ) => { 41 | const { errorMessage, light, size, ...otherProps } = props; 42 | 43 | const ProgressBar = ( 44 | 52 | ); 53 | 54 | return ( 55 |
56 | {props.error && errorMessage ? ( 57 | 62 | {ProgressBar} 63 | 64 | ) : ( 65 | ProgressBar 66 | )} 67 |
68 | ); 69 | }; 70 | 71 | CircularProgressBar.displayName = 'CircularProgressBar'; 72 | 73 | CircularProgressBar.defaultProps = { 74 | size: Size.medium 75 | }; 76 | -------------------------------------------------------------------------------- /src/components/CircularProgressBar/constants.ts: -------------------------------------------------------------------------------- 1 | export enum Size { 2 | small = 'small', 3 | medium = 'medium', 4 | large = 'large', 5 | } 6 | 7 | export const sizesMap = { 8 | small: 30, 9 | medium: 54, 10 | large: 102, 11 | } -------------------------------------------------------------------------------- /src/components/CircularProgressBar/index.ts: -------------------------------------------------------------------------------- 1 | import {CircularProgressBar as CircularProgressBarComponent} from './CircularProgressBar'; 2 | import {createHOC} from 'wix-ui-core/dist/src/createHOC'; 3 | 4 | export const CircularProgressBar = createHOC(CircularProgressBarComponent); 5 | -------------------------------------------------------------------------------- /src/components/CloseButton/CloseButton.driver.ts: -------------------------------------------------------------------------------- 1 | import { StylableDOMUtil } from '@stylable/dom-test-kit'; 2 | import { buttonDriverFactory, ButtonDriver } from 'wix-ui-core/drivers/vanilla'; 3 | import { DriverFactory, BaseDriver, ComponentFactory } from 'wix-ui-test-utils/driver-factory'; 4 | import style from './CloseButton.st.css'; 5 | import { Skin, Size } from './constants'; 6 | 7 | export interface CloseButtonDriver extends ButtonDriver { 8 | getSkin: () => Skin; 9 | getSize: () => Size; 10 | } 11 | 12 | export const closeButtonDriverFactory = (factoryParams: ComponentFactory): CloseButtonDriver => { 13 | const { element } = factoryParams; 14 | const stylableDOMUtil = new StylableDOMUtil(style, element); 15 | const getStyleState = (stateName: string) => stylableDOMUtil.getStyleState(element, stateName) as any as T | null; 16 | 17 | return { 18 | ...buttonDriverFactory(factoryParams), 19 | getSkin: () => getStyleState('skin'), 20 | getSize: () => getStyleState('size'), 21 | }; 22 | }; 23 | -------------------------------------------------------------------------------- /src/components/CloseButton/CloseButton.e2e.ts: -------------------------------------------------------------------------------- 1 | import * as eyes from 'eyes.it'; 2 | import { browser } from 'protractor'; 3 | import { waitForVisibilityOf, createStoryUrl } from 'wix-ui-test-utils/protractor'; 4 | import { enumValues } from '../../utils'; 5 | import { closeButtonTestkitFactory } from '../../testkit/protractor'; 6 | import { storySettings } from '../../../stories/CloseButton/storySettings'; 7 | import {Skin, Size} from './constants'; 8 | 9 | describe('CloseButton', () => { 10 | const storyUrl = createStoryUrl(storySettings); 11 | const dataHook = 'storybook-close-button'; 12 | 13 | beforeAll(() => browser.get(storyUrl)); 14 | 15 | eyes.it('should render all skins', async () => { 16 | const driver = closeButtonTestkitFactory({ dataHook }); 17 | await waitForVisibilityOf(driver.element()); 18 | for (let skin in enumValues(Skin)) { 19 | await eyes.checkWindow(`skin=${skin}`); 20 | } 21 | }); 22 | 23 | }); 24 | -------------------------------------------------------------------------------- /src/components/CloseButton/CloseButton.protractor.driver.ts: -------------------------------------------------------------------------------- 1 | export {buttonDriverFactory as closeButtonDriverFactory, ButtonDriver as CloseButtonDriver} from 'wix-ui-core/drivers/protractor'; 2 | -------------------------------------------------------------------------------- /src/components/CloseButton/CloseButton.spec.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { createDriverFactory } from 'wix-ui-test-utils/driver-factory'; 3 | import { closeButtonDriverFactory } from './CloseButton.driver'; 4 | import { closeButtonTestkitFactory } from '../../testkit'; 5 | import { closeButtonTestkitFactory as enzymeCloseButtonTestkitFactory } from '../../testkit/enzyme'; 6 | import { runTestkitExistsSuite } from '../../common/testkitTests'; 7 | import { CloseButton, CloseButtonProps } from './CloseButton'; 8 | import { Skin, Size } from './constants'; 9 | import { enumValues } from '../../utils'; 10 | const defaults = require('lodash/defaults'); 11 | 12 | describe('CloseButton', () => { 13 | const createDriver = createDriverFactory(closeButtonDriverFactory); 14 | const CloseButtonWithDefaults = withDefaultsHOC(CloseButton, 15 | { 16 | children: 'Click me!' 17 | }); 18 | 19 | describe('skin prop', () => { 20 | it('should be standard by default', () => { 21 | const driver = createDriver(); 22 | expect(driver.getSkin()).toBe(Skin.standard); 23 | }); 24 | 25 | enumValues(Skin).forEach((skin: Skin) => { 26 | it(`should be '${skin}'`, () => { 27 | const driver = createDriver(); 28 | expect(driver.getSkin()).toBe(skin); 29 | }); 30 | }); 31 | }); 32 | 33 | describe('size prop', () => { 34 | it('should be small by default', () => { 35 | const driver = createDriver(); 36 | expect(driver.getSize()).toBe(Size.small); 37 | }); 38 | 39 | enumValues(Size).forEach((size: Size) => { 40 | it(`should be '${size}'`, () => { 41 | const driver = createDriver(); 42 | expect(driver.getSize()).toBe(size); 43 | }); 44 | }); 45 | }); 46 | 47 | runTestkitExistsSuite({ 48 | Element: , 49 | testkitFactory: closeButtonTestkitFactory, 50 | enzymeTestkitFactory: enzymeCloseButtonTestkitFactory 51 | }); 52 | }); 53 | 54 | 55 | // TODO: consider putting this in 'test/utils' 56 | /** 57 | * Create a Component with applied default props. 58 | * The new component can receive Partial

instead of P. 59 | */ 60 | function withDefaultsHOC

(Component: React.SFC

, defaultProps: P): React.SFC> { 61 | return (partialProps?: Partial

) => { 62 | return React.createElement(Component, defaults({}, partialProps, defaultProps)); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/components/CloseButton/CloseButton.st.css: -------------------------------------------------------------------------------- 1 | :import { 2 | -st-from: "wix-ui-core/index.st.css"; 3 | -st-named: Button; 4 | } 5 | 6 | :import { 7 | -st-from: "../../colors.st.css"; 8 | -st-named: 9 | B10, B20, B50, 10 | D10, D20, 11 | WHITE; 12 | } 13 | 14 | .root { 15 | -st-extends: Button; 16 | -st-states: skin(enum(standard, white, dark)), size(enum(small, large)); 17 | 18 | box-sizing: border-box; 19 | 20 | display: flex; 21 | justify-content: center; 22 | align-items: center; 23 | 24 | background-color: transparent; 25 | border: none; 26 | 27 | cursor: pointer; 28 | } 29 | 30 | .root:skin(standard) { 31 | color: value(B10); 32 | } 33 | 34 | .root:skin(standard):hover { 35 | color: value(B20); 36 | } 37 | 38 | .root:skin(white) { 39 | color: value(WHITE); 40 | } 41 | .root:skin(white):hover { 42 | color: value(B50); 43 | } 44 | 45 | .root:skin(dark) { 46 | color: value(D10); 47 | } 48 | .root:skin(dark):hover { 49 | color: value(D20); 50 | } 51 | 52 | .root:size(small) { 53 | width: 18px; 54 | height: 18px; 55 | } 56 | 57 | /* svg sizing will be obsolete once we have 2 sets of icons which are based on 18x18 view and 24x24 view */ 58 | .root:size(small) svg { 59 | width: 6px; 60 | height: 6px; 61 | } 62 | 63 | .root:size(large) { 64 | width: 24px; 65 | height: 24px; 66 | } 67 | .root:size(large) svg { 68 | width: 8px; 69 | height: 8px; 70 | } 71 | 72 | -------------------------------------------------------------------------------- /src/components/CloseButton/CloseButton.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { 3 | Button as CoreButton, 4 | ButtonProps as CoreButtonProps 5 | } from 'wix-ui-core/dist/src/components/deprecated/button'; 6 | import { enumValues } from '../../utils'; 7 | import style from './CloseButton.st.css'; 8 | import { Skin, Size } from './constants'; 9 | import { Close as CloseIcon } from 'wix-ui-icons-common/system'; 10 | 11 | export interface CloseButtonOwnProps extends CoreButtonProps { 12 | /**Skin of the Button (Styling)*/ 13 | skin?: Skin; 14 | /** Size of the button (Styling) */ 15 | size?: Size; 16 | } 17 | 18 | export type CloseButtonProps = CloseButtonOwnProps & CoreButtonProps; 19 | 20 | export const CloseButton: React.SFC = props => { 21 | // children is ommited on purpose (and not used) 22 | const { children, skin, size, ...rest } = props; 23 | 24 | return ( 25 | 26 | 27 | 28 | ); 29 | }; 30 | 31 | CloseButton.displayName = 'CloseButton'; 32 | 33 | CloseButton.defaultProps = { 34 | skin: Skin.standard, 35 | size: Size.small 36 | }; 37 | -------------------------------------------------------------------------------- /src/components/CloseButton/constants.ts: -------------------------------------------------------------------------------- 1 | export enum Skin { 2 | standard = 'standard', 3 | white = 'white', 4 | dark = 'dark' 5 | }; 6 | 7 | export enum Size { 8 | small = 'small', 9 | large = 'large' 10 | } 11 | -------------------------------------------------------------------------------- /src/components/CloseButton/index.ts: -------------------------------------------------------------------------------- 1 | export { CloseButton, CloseButtonProps } from './CloseButton'; 2 | export { Skin as CloseButtonSkin, Size as CloseButtonSize } from './constants'; -------------------------------------------------------------------------------- /src/components/FloatingHelper/ClosablePopover/ClosablePopover.driver.ts: -------------------------------------------------------------------------------- 1 | import { 2 | BaseDriver, 3 | DriverFactory, 4 | ComponentFactory 5 | } from 'wix-ui-test-utils/driver-factory'; 6 | import { popoverDriverFactory } from 'wix-ui-core/drivers/vanilla'; 7 | 8 | // TODO: Move this interface to Core's PopoverDriver (big PR with dependencies) 9 | export interface PopoverDriver extends BaseDriver { 10 | exists: () => boolean; 11 | getTargetElement: () => Element; 12 | getContentElement: () => any; 13 | isTargetElementExists: () => boolean; 14 | isContentElementExists: () => boolean; 15 | mouseEnter: () => any; 16 | mouseLeave: () => any; 17 | click: () => any; 18 | clickOutside: () => void; 19 | getArrowOffset: () => { 20 | top: string; 21 | left: string; 22 | right: string; 23 | bottom: string; 24 | }; 25 | inlineStyles: () => CSSStyleDeclaration; 26 | getElementId: () => string; 27 | getArrowElement: () => any; 28 | } 29 | 30 | export interface ClosablePopoverDriver extends PopoverDriver { 31 | /** Checks is the popover's content is open */ 32 | isOpened: () => boolean; 33 | } 34 | 35 | export const closablePopoverDriverFactory: DriverFactory< 36 | ClosablePopoverDriver & PopoverDriver 37 | > = ({ element, eventTrigger }: ComponentFactory): ClosablePopoverDriver => { 38 | const popoverDriver = popoverDriverFactory({ element, eventTrigger }); 39 | 40 | return { 41 | ...popoverDriver, 42 | isOpened: () => popoverDriver.isContentElementExists() 43 | }; 44 | }; 45 | -------------------------------------------------------------------------------- /src/components/FloatingHelper/ClosablePopover/ClosablePopover.protractor.driver.ts: -------------------------------------------------------------------------------- 1 | import { ElementFinder } from 'protractor'; 2 | import { popoverDriverFactory, PopoverDriver } from 'wix-ui-core/drivers/protractor'; 3 | import { DriverFactory, BaseDriver } from 'wix-ui-core/dist/src/common/BaseDriver.protractor'; 4 | 5 | export interface ClosablePopoverDriver extends PopoverDriver { 6 | isOpened: () => Promise; 7 | } 8 | 9 | export const closablePopoverDriverFactory: DriverFactory = element => { 10 | const popoverDriver = popoverDriverFactory(element); 11 | 12 | return { 13 | ...popoverDriver, 14 | isOpened: async () => popoverDriver.isContentElementExists(), 15 | }; 16 | }; 17 | -------------------------------------------------------------------------------- /src/components/FloatingHelper/ClosablePopover/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ClosablePopover'; -------------------------------------------------------------------------------- /src/components/FloatingHelper/DataHooks.ts: -------------------------------------------------------------------------------- 1 | export const DataHooks = { 2 | innerContent: 'inner-content', 3 | closeButton: 'close-button', 4 | contentWrapper: 'content-wrapper' 5 | }; 6 | -------------------------------------------------------------------------------- /src/components/FloatingHelper/FloatingHelper.driver.ts: -------------------------------------------------------------------------------- 1 | import {BaseDriver, DriverFactory} from 'wix-ui-test-utils/driver-factory'; 2 | import {closablePopoverDriverFactory,ClosablePopoverDriver} from './ClosablePopover/ClosablePopover.driver'; 3 | import {DataHooks} from './DataHooks'; 4 | import {floatingHelperContentDriverFactory, FloatingHelperContentDriver} from '../../components/FloatingHelper/FloatingHelperContent/FloatingHelperContent.driver'; 5 | 6 | // TODO: add interface of PopoverDriver 7 | export interface FloatingHelperDriver extends ClosablePopoverDriver { 8 | /** Get the driver for the helper's content */ 9 | getHelperContentDriver: () => FloatingHelperContentDriver; 10 | /** check wether the helper has a close button */ 11 | hasCloseButton: () => boolean; 12 | /** click the close button */ 13 | clickCloseButton: () => void; 14 | /** Get width of content's root element */ 15 | getWidth: () => string; 16 | } 17 | 18 | export const floatingHelperDriverFactory: 19 | DriverFactory = 20 | ({wrapper, element, eventTrigger}) => { 21 | const closablePopoverDriver = closablePopoverDriverFactory({wrapper, element, eventTrigger}); 22 | const popoverContent = () => closablePopoverDriver.getContentElement(); 23 | const innerContent = () => popoverContent().querySelector(`[data-hook='${DataHooks.innerContent}']`); 24 | const closeButton = () => popoverContent().querySelector(`[data-hook='${DataHooks.closeButton}']`); 25 | const contentWrapper = () => popoverContent().querySelector(`[data-hook='${DataHooks.contentWrapper}']`); 26 | 27 | 28 | return { 29 | ...closablePopoverDriver, 30 | hasCloseButton: () => !!closeButton(), 31 | clickCloseButton: () => eventTrigger.click(closeButton()), 32 | getHelperContentDriver: () => floatingHelperContentDriverFactory({wrapper, element: innerContent(), eventTrigger}), 33 | getWidth: () => window.getComputedStyle(contentWrapper()).width 34 | }; 35 | }; 36 | -------------------------------------------------------------------------------- /src/components/FloatingHelper/FloatingHelper.e2e.ts: -------------------------------------------------------------------------------- 1 | import * as eyes from 'eyes.it'; 2 | import { browser, ElementFinder , $} from 'protractor'; 3 | import { createStoryUrl, waitForVisibilityOf, scrollToElement } from 'wix-ui-test-utils/protractor'; 4 | import * as autoExampleDriver from 'wix-storybook-utils/AutoExampleDriver'; 5 | import { floatingHelperTestkitFactory, FloatingHelperDriver } from '../../testkit/protractor'; 6 | import { storySettings } from '../../../stories/FloatingHelper/StorySettings'; 7 | 8 | describe('FloatingHelper', () => { 9 | let driver: FloatingHelperDriver; 10 | 11 | eyes.it('should be opened by default', async () => { 12 | const storyUrl = createStoryUrl({kind:storySettings.kind, story:storySettings.story, withExamples:false}); 13 | await browser.get(storyUrl); 14 | driver = floatingHelperTestkitFactory({ dataHook: storySettings.dataHook }); 15 | await waitForVisibilityOf(driver.element(), 'Cannot find FloatingHelper'); 16 | expect(await driver.isOpened()).toBeTruthy(); 17 | }); 18 | 19 | eyes.it('should have appearance light', async () => { 20 | const storyUrl = createStoryUrl({kind:storySettings.kind, story:storySettings.story, withExamples:true}); 21 | await browser.get(storyUrl); 22 | driver = floatingHelperTestkitFactory({ dataHook: 'story-floating-helper-light' }); 23 | await waitForVisibilityOf(driver.element(), 'Cannot find FloatingHelper'); 24 | await scrollToElement($('[data-hook=appearance-light-example-container]')); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /src/components/FloatingHelper/FloatingHelper.protractor.driver.ts: -------------------------------------------------------------------------------- 1 | import { $, ElementFinder, by } from 'protractor'; 2 | import { DriverFactory } from 'wix-ui-core/dist/src/common/BaseDriver.protractor'; 3 | import { ClosablePopover } from './ClosablePopover/ClosablePopover'; 4 | import { closablePopoverDriverFactory, ClosablePopoverDriver } from './ClosablePopover/ClosablePopover.protractor.driver'; 5 | import { DataHooks } from './DataHooks'; 6 | import { floatingHelperContentDriverFactory, FloatingHelperContentDriver } from '../../components/FloatingHelper/FloatingHelperContent/FloatingHelperContent.protractor.driver'; 7 | 8 | export interface FloatingHelperDriver extends ClosablePopoverDriver { 9 | /** Get HelperContent driver */ 10 | getHelperContentDriver: () => FloatingHelperContentDriver; 11 | } 12 | 13 | export const floatingHelperDriverFactory: DriverFactory = (element: ElementFinder): FloatingHelperDriver => { 14 | return { 15 | ...closablePopoverDriverFactory(element), 16 | getHelperContentDriver: () => floatingHelperContentDriverFactory(element.$(byDataHook(DataHooks.innerContent))), 17 | }; 18 | }; 19 | 20 | export function byDataHook(hook: string) { 21 | return `[data-hook='${hook}']`; 22 | } 23 | -------------------------------------------------------------------------------- /src/components/FloatingHelper/FloatingHelper.st.css: -------------------------------------------------------------------------------- 1 | :import { 2 | -st-from: "wix-ui-core/index.st.css"; 3 | -st-named: Popover; 4 | } 5 | 6 | :import { 7 | -st-from: "./FloatingHelperContent/FloatingHelperContent.st.css"; 8 | -st-default: FloatingHelperContent; 9 | } 10 | 11 | :import { 12 | -st-from: "../Text/Text.st.css"; 13 | -st-default: Text; 14 | } 15 | 16 | :import { 17 | -st-from: "../Button/Button.st.css"; 18 | -st-default: Button; 19 | } 20 | 21 | :import { 22 | -st-from: "../../colors.st.css"; 23 | -st-named: D80, WHITE; 24 | } 25 | 26 | :import { 27 | -st-from: "../../shadows.st.css"; 28 | -st-named: shadow30; 29 | } 30 | 31 | :vars { 32 | /* TODO: create and use a fade function */ 33 | 34 | /** background color D10 with opacity 0.95 */ 35 | backgroundColorDark: rgba(22,45,61,0.95); 36 | backgroundColorLight: value(D80); 37 | closeButtonPadding: 6px; 38 | } 39 | 40 | .root { 41 | -st-states: bounce, placement-right, placement-left, placement-top, placement-bottom, appearance(enum(dark,light)); 42 | -st-extends: Popover; 43 | } 44 | 45 | .root:appearance(dark) { 46 | -st-mixin: Popover( 47 | contentBorderColor value(backgroundColorDark), 48 | contentBackgroundColor value(backgroundColorDark), 49 | contentBorderWidth 0, 50 | contentBorderRadius 8px, 51 | contentPadding 0 0 52 | ); 53 | } 54 | 55 | .root:appearance(light) { 56 | -st-mixin: Popover( 57 | contentBorderColor value(backgroundColorLight), 58 | contentBackgroundColor value(backgroundColorLight), 59 | contentBorderWidth 0, 60 | contentBorderRadius 8px, 61 | contentPadding 0 0 62 | ); 63 | } 64 | 65 | .root::arrow { 66 | z-index: 2; 67 | } 68 | 69 | /* popoverContent and innerContent are taken from Tooltip.tooltipContent, 70 | * but I split them. 71 | */ 72 | .root::popoverContent { 73 | position: relative; 74 | box-sizing: border-box; 75 | box-shadow: value(shadow30); 76 | } 77 | 78 | .closeButton { 79 | position: absolute; 80 | top: value(closeButtonPadding); 81 | 82 | /* default dir=ltr */ 83 | right: value(closeButtonPadding); 84 | left: initial; 85 | } 86 | 87 | :global([dir="rtl"]) .closeButton { 88 | right: initial; 89 | left: value(closeButtonPadding); 90 | } 91 | 92 | .innerContent { 93 | padding: 30px 36px; 94 | color: value(WHITE); 95 | } 96 | 97 | 98 | -------------------------------------------------------------------------------- /src/components/FloatingHelper/FloatingHelperContent/DataHooks.ts: -------------------------------------------------------------------------------- 1 | export const DataHooks = { 2 | title: 'helper-content-title', 3 | body: 'helper-content-body', 4 | actionButton: 'helper-content-action-button', 5 | image: 'helper-content-image', 6 | footer: 'helper-content-footer' 7 | }; 8 | -------------------------------------------------------------------------------- /src/components/FloatingHelper/FloatingHelperContent/FloatingHelperContent.e2e.ts: -------------------------------------------------------------------------------- 1 | import * as eyes from 'eyes.it'; 2 | import { browser, ElementFinder } from 'protractor'; 3 | import { getStoryUrl, waitForVisibilityOf, scrollToElement, protractorTestkitFactoryCreator } from 'wix-ui-test-utils/protractor'; 4 | import { floatingHelperContentDriverFactory, FloatingHelperContentDriver } from './FloatingHelperContent.protractor.driver'; 5 | import { storySettings } from '../../../../stories/FloatingHelperContent/StorySettings'; 6 | 7 | 8 | export const floatingHelperContentTestkitFactory = protractorTestkitFactoryCreator(floatingHelperContentDriverFactory); 9 | 10 | describe('FloatingHelperContent', () => { 11 | const storyUrl = getStoryUrl(storySettings.kind, storySettings.story); 12 | 13 | beforeEach(async () => { 14 | await browser.get(storyUrl); 15 | }); 16 | 17 | describe('FloatingHelperContent variations', () => { 18 | storySettings.exampleDataHooks.forEach(dataHook => { 19 | eyes.it(`should display example with dataHook ${dataHook}`, async () => { 20 | const driver = floatingHelperContentTestkitFactory({ dataHook }); 21 | await scrollToElement(driver.element()); 22 | await waitForVisibilityOf(driver.element(), 'Cannot find FloatingHelperContent'); 23 | }); 24 | }); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /src/components/FloatingHelper/FloatingHelperContent/FloatingHelperContent.protractor.driver.ts: -------------------------------------------------------------------------------- 1 | import {ElementFinder} from 'protractor'; 2 | import {DataHooks} from './DataHooks'; 3 | import {DriverFactory, BaseDriver} from 'wix-ui-core/dist/src/common/BaseDriver.protractor'; 4 | import {textDriverFactory} from '../../../components/Text/Text.protractor.driver'; 5 | 6 | export interface FloatingHelperContentDriver extends BaseDriver { 7 | hasActionButton: () => Promise; 8 | } 9 | 10 | export const floatingHelperContentDriverFactory: DriverFactory = element => { 11 | const actionButton = () => element.$(byDataHook(DataHooks.actionButton)); 12 | 13 | return { 14 | element: () => element, 15 | hasActionButton: async () => actionButton().isPresent(), 16 | }; 17 | }; 18 | 19 | export function byDataHook(hook: string) { 20 | return `[data-hook='${hook}']`; 21 | } 22 | -------------------------------------------------------------------------------- /src/components/FloatingHelper/FloatingHelperContent/FloatingHelperContent.st.css: -------------------------------------------------------------------------------- 1 | .root { 2 | -st-states: hasBody(boolean), appearance(enum(dark,light)); 3 | 4 | display: flex; 5 | flex-direction: row; 6 | } 7 | 8 | .root:hasBody .title { 9 | margin-bottom: 6px; 10 | } 11 | 12 | .action { 13 | margin-top: 18px; 14 | } 15 | 16 | .image { 17 | margin-left: 18px; 18 | display: flex; 19 | } 20 | 21 | .footer { 22 | margin-top: 12px; 23 | display: flex; 24 | } 25 | -------------------------------------------------------------------------------- /src/components/FloatingHelper/FloatingHelperContent/README.md: -------------------------------------------------------------------------------- 1 | # `` 2 | -------------------------------------------------------------------------------- /src/components/FloatingHelper/FloatingHelperContent/constants.ts: -------------------------------------------------------------------------------- 1 | export enum ActionButtonTheme { 2 | standard = 'standard', 3 | white = 'white', 4 | premium = 'premium', 5 | lightPrimary = 'lightPrimary' 6 | } 7 | -------------------------------------------------------------------------------- /src/components/FloatingHelper/FloatingHelperContent/index.ts: -------------------------------------------------------------------------------- 1 | export * from './FloatingHelperContent'; 2 | export * from './constants'; 3 | -------------------------------------------------------------------------------- /src/components/FloatingHelper/README.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | This is a Popover helper component 4 | 5 | ### Open/Close behavior 6 | This component can be Controlled or Uncontrolled according to wether the `opened` property is defined or undefined. 7 | In Uncontrolled mode, the default behavior is that the popover content is opened when mouse-enter is triggered on the target, an closes when the close button is clicked. 8 | 9 | ### Programatic Open/Close 10 | Works only in Uncontrolled mode. 11 | See "Programatic Open Example". 12 | 13 | ### Playground & Preview 14 | The playground's live Code section is not working well for this component. Please refer to the Examples section, and click "Show code" to see code examples. 15 | -------------------------------------------------------------------------------- /src/components/FloatingHelper/constants.ts: -------------------------------------------------------------------------------- 1 | export enum Appearance { 2 | dark = 'dark', 3 | light = 'light' 4 | } 5 | -------------------------------------------------------------------------------- /src/components/FloatingHelper/index.ts: -------------------------------------------------------------------------------- 1 | import {createHOC} from 'wix-ui-core/dist/src/createHOC'; 2 | import {FloatingHelper as FLoatingHelperRaw} from './FloatingHelper'; 3 | export * from './FloatingHelper'; 4 | export const FloatingHelper = createHOC(FLoatingHelperRaw); 5 | 6 | export * from './constants'; -------------------------------------------------------------------------------- /src/components/FullTextView/FullTextView.driver.ts: -------------------------------------------------------------------------------- 1 | import {BaseDriver, DriverFactory} from 'wix-ui-test-utils/driver-factory'; 2 | 3 | export interface FullTextViewDriver extends BaseDriver { 4 | getText: () => string; 5 | getTagName: () => string; 6 | } 7 | 8 | export const fullTextViewDriverFactory: DriverFactory = ({element}) => { 9 | return { 10 | /** check if element exists */ 11 | exists: () => !!element, 12 | /** get the rendered content */ 13 | getText: () => element.innerHTML, 14 | /** get the rendered tag name */ 15 | getTagName: () => element.tagName.toLowerCase(), 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /src/components/FullTextView/FullTextView.e2e.ts: -------------------------------------------------------------------------------- 1 | import * as eyes from 'eyes.it'; 2 | import { browser } from 'protractor'; 3 | import { waitForVisibilityOf, createStoryUrl } from 'wix-ui-test-utils/protractor'; 4 | import { fullTextViewTestkitFactory } from '../../testkit/protractor'; 5 | 6 | describe('FullTextView', () => { 7 | const dataHook = 'storybook-fullTextView'; 8 | const storyUrl = createStoryUrl({ 9 | kind: 'Components', 10 | story: 'FullTextView' 11 | }); 12 | 13 | beforeEach(() => browser.get(storyUrl)); 14 | 15 | eyes.it('should render with default props', async () => { 16 | const driver = fullTextViewTestkitFactory({ dataHook }); 17 | await waitForVisibilityOf(driver.element()); 18 | expect(await driver.element().isPresent()).toBeTruthy(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /src/components/FullTextView/FullTextView.protractor.driver.ts: -------------------------------------------------------------------------------- 1 | import {ElementFinder} from 'protractor'; 2 | import { DriverFactory } from 'wix-ui-core/dist/src/common/BaseDriver.protractor'; 3 | 4 | export interface FullTextViewDriver { 5 | element: () => ElementFinder; 6 | getText: () => Promise; 7 | } 8 | 9 | export const fullTextViewDriverFactory: DriverFactory = component => ({ 10 | /** returns the component element */ 11 | element: () => component, 12 | /** returns the component text */ 13 | getText: async () => component.getText() 14 | }); 15 | -------------------------------------------------------------------------------- /src/components/FullTextView/FullTextView.spec.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import {createDriverFactory} from 'wix-ui-test-utils/driver-factory'; 3 | import {isEnzymeTestkitExists} from 'wix-ui-test-utils/enzyme'; 4 | import {isTestkitExists} from 'wix-ui-test-utils/vanilla'; 5 | import {mount} from 'enzyme'; 6 | import {fullTextViewDriverFactory} from './FullTextView.driver'; 7 | import {fullTextViewUniDriverFactory} from './FullTextView.uni.driver'; 8 | import {FullTextView} from './FullTextView'; 9 | 10 | import {fullTextViewTestkitFactory} from '../../testkit'; 11 | import {fullTextViewTestkitFactory as enzymeFullTextViewTestkitFactory} from '../../testkit/enzyme'; 12 | import {createUniDriverFactory} from 'wix-ui-test-utils/dist/src/uni-driver-factory'; 13 | 14 | describe('FullTextView', () => { 15 | describe('[sync]', () => { 16 | runTests(createDriverFactory(fullTextViewDriverFactory)); 17 | }); 18 | 19 | describe('[async]', () => { 20 | runTests(createUniDriverFactory(fullTextViewUniDriverFactory)); 21 | }); 22 | 23 | function runTests(createDriver) { 24 | it('should render a span tag by default', async () => { 25 | const wrapper = createDriver(Hello World); 26 | expect(await wrapper.getTagName()).toBe('span'); 27 | }); 28 | 29 | it('should display full content on hover and hide it on leave in tooltip', async () => { 30 | const content = ( 31 |

32 | Delete this super awesome thing 33 | ? 34 |
35 | ); 36 | const component = mount({content}); 37 | 38 | expect(component.find('[data-hook="popover-content"]').length).toBe(0); 39 | component.setState({isEllipsisActive: true}); 40 | component.simulate('mouseEnter'); 41 | expect(component.find('[data-hook="popover-content"]').at(0).text()).toBe('Delete this super awesome thing?'); 42 | }); 43 | 44 | describe('testkit', () => { 45 | it('should exist', () => { 46 | expect(isTestkitExists(Hello World, 47 | fullTextViewTestkitFactory)).toBe(true); 48 | }); 49 | }); 50 | 51 | describe('enzyme testkit', () => { 52 | it('should exist', () => { 53 | expect(isEnzymeTestkitExists(Hello World, 54 | enzymeFullTextViewTestkitFactory, mount)).toBe(true); 55 | }); 56 | }); 57 | } 58 | }); 59 | -------------------------------------------------------------------------------- /src/components/FullTextView/FullTextView.st.css: -------------------------------------------------------------------------------- 1 | .root { 2 | display: inline-block; 3 | text-overflow: ellipsis; 4 | overflow: hidden; 5 | white-space: nowrap; 6 | width: 100%; 7 | } 8 | -------------------------------------------------------------------------------- /src/components/FullTextView/FullTextView.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import * as shallowequal from 'shallowequal'; 3 | import {Tooltip} from '../Tooltip'; 4 | import style from './FullTextView.st.css'; 5 | 6 | export interface FullTextViewProps { 7 | children?: React.ReactNode; 8 | maxWidth?: number | string; 9 | } 10 | 11 | export interface FullTextViewState { 12 | isEllipsisActive: boolean; 13 | } 14 | 15 | const isEllipsisActive = (node: HTMLElement) => node && node.offsetWidth < node.scrollWidth; 16 | 17 | export class FullTextView extends React.Component { 18 | static displayName = 'FullTextView'; 19 | 20 | private textNode: any; 21 | private ellipsesTimeout: any; 22 | 23 | state = { 24 | isEllipsisActive: false 25 | } 26 | 27 | componentDidMount() { 28 | window.addEventListener('resize', this.updateEllipsesState); 29 | this.updateEllipsesState(); 30 | } 31 | 32 | componentDidUpdate(prevProps) { 33 | // if props changed, then we want to re-check node for ellipsis state 34 | // and we can not do such check in render, because we want to check already rendered node 35 | if (!shallowequal(prevProps, this.props)) { 36 | this.updateEllipsesState(); 37 | } 38 | } 39 | 40 | componentWillUnmount() { 41 | window.removeEventListener('resize', this.updateEllipsesState); 42 | } 43 | 44 | handleTextRef = node => this.textNode = node; 45 | 46 | updateEllipsesState = () => { 47 | clearTimeout(this.ellipsesTimeout); 48 | this.ellipsesTimeout = setTimeout(() => { 49 | this.setState({isEllipsisActive: isEllipsisActive(this.textNode)}) 50 | }, 30); 51 | }; 52 | 53 | renderText() { 54 | return ( 55 | 60 | {this.props.children} 61 | 62 | ); 63 | } 64 | 65 | render() { 66 | if (!this.state.isEllipsisActive) { 67 | return this.renderText(); 68 | } 69 | 70 | return ( 71 | 72 | {this.renderText()} 73 | 74 | ); 75 | } 76 | }; 77 | -------------------------------------------------------------------------------- /src/components/FullTextView/FullTextView.uni.driver.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | BaseUniDriver, 3 | baseUniDriverFactory, 4 | } from 'wix-ui-test-utils/base-driver'; 5 | import {UniDriver} from 'wix-ui-test-utils/unidriver'; 6 | 7 | export interface FullTextViewUniDriver extends BaseUniDriver { 8 | getText: () => Promise; 9 | getTagName: () => Promise; 10 | } 11 | 12 | export const fullTextViewUniDriverFactory = (base: UniDriver): FullTextViewUniDriver => { 13 | return { 14 | ...baseUniDriverFactory(base), 15 | getText: () => base.text() as Promise, 16 | getTagName: async () => (await base._prop('tagName')).toLowerCase() as Promise, 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /src/components/FullTextView/index.ts: -------------------------------------------------------------------------------- 1 | import {FullTextView as FullTextViewComponent} from './FullTextView'; 2 | import {createHOC} from 'wix-ui-core/dist/src/createHOC'; 3 | 4 | export const FullTextView = createHOC(FullTextViewComponent); 5 | -------------------------------------------------------------------------------- /src/components/HBox/HBox.driver.ts: -------------------------------------------------------------------------------- 1 | export const hBoxDriverFactory = ({element}) => { 2 | return { 3 | /** check if element exists */ 4 | exists: () => !!element, 5 | /** get the rendered content */ 6 | getChildren: () => element.innerHTML 7 | }; 8 | }; 9 | -------------------------------------------------------------------------------- /src/components/HBox/HBox.e2e.ts: -------------------------------------------------------------------------------- 1 | import * as eyes from 'eyes.it'; 2 | import {browser} from 'protractor'; 3 | import {getStoryUrl, waitForVisibilityOf} from 'wix-ui-test-utils/protractor'; 4 | import {hBoxTestkitFactory} from '../../testkit/protractor'; 5 | 6 | describe('HBox', () => { 7 | const storyUrl = getStoryUrl('Components', 'HBox'); 8 | 9 | beforeEach(() => browser.get(storyUrl)); 10 | eyes.it('should display correct content', () => { 11 | const dataHook = 'storybook-hbox'; 12 | const driver = hBoxTestkitFactory({dataHook}); 13 | 14 | return waitForVisibilityOf(driver.element(), 'Cannot find HBox'); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/components/HBox/HBox.protractor.driver.ts: -------------------------------------------------------------------------------- 1 | export const hBoxDriverFactory = component => ({ 2 | /** Returns the wrapped component instance */ 3 | element: () => component 4 | }); 5 | -------------------------------------------------------------------------------- /src/components/HBox/HBox.spec.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import {mount} from 'enzyme'; 3 | import {HBox} from './'; 4 | 5 | describe('HBox', () => { 6 | let wrapper; 7 | 8 | afterEach(() => wrapper.detach()); 9 | 10 | it('should render the passed children', () => { 11 | wrapper = mount(
1
, {attachTo: document.createElement('div')}); 12 | expect(wrapper.html()).toContain('
1
'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /src/components/HBox/HBox.st.css: -------------------------------------------------------------------------------- 1 | .root { 2 | -st-states: verticalAlignment(enum(bottom, center, top)); 3 | display: flex; 4 | flex-wrap: wrap; 5 | width: 100%; 6 | height: 100%; 7 | } 8 | 9 | .root:verticalAlignment(bottom) { 10 | align-items: flex-end; 11 | } 12 | 13 | .root:verticalAlignment(center) { 14 | align-items: center; 15 | } 16 | 17 | .root:verticalAlignment(top) { 18 | align-items: flex-start; 19 | } 20 | 21 | -------------------------------------------------------------------------------- /src/components/HBox/HBox.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import style from './HBox.st.css'; 3 | import {addSpacing} from './utils'; 4 | 5 | export interface HBoxProps { 6 | children?: React.ReactNode; 7 | verticalAlignment?: Alignment; 8 | spacing?: number; 9 | dir?: 'ltr' | 'rtl'; 10 | } 11 | 12 | export type Alignment = 'top' | 'center' | 'bottom'; 13 | 14 | const defaultProps: HBoxProps = { 15 | children: null, 16 | verticalAlignment: 'top', 17 | spacing: 0, 18 | dir: 'ltr' 19 | }; 20 | 21 | /** 22 | * HBox 23 | */ 24 | export const HBox: React.SFC = props => { 25 | const {children, verticalAlignment, spacing, dir} = props; 26 | return
{addSpacing(children, spacing, dir)}
; 27 | }; 28 | 29 | HBox.displayName = 'HBox'; 30 | 31 | HBox.defaultProps = defaultProps; 32 | -------------------------------------------------------------------------------- /src/components/HBox/index.ts: -------------------------------------------------------------------------------- 1 | export {HBox, HBoxProps} from './HBox'; 2 | -------------------------------------------------------------------------------- /src/components/HBox/utils.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | export function addSpacing(children, spacing: number, dir?: 'ltr' | 'rtl') { 4 | if (!children || !spacing) { 5 | return children; 6 | } 7 | 8 | const spacedChildren = []; 9 | const marginProperty = dir === 'rtl' ? 'marginLeft' : 'marginRight'; 10 | 11 | for (let i = 0; i < children.length - 1; i++) { 12 | spacedChildren.push( 13 | React.cloneElement(children[i], {style: {[marginProperty]: spacing}}) 14 | ); 15 | } 16 | 17 | spacedChildren.push(children[children.length - 1]); 18 | 19 | return spacedChildren; 20 | } 21 | -------------------------------------------------------------------------------- /src/components/Heading/Heading.driver.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFactory } from 'wix-ui-test-utils/driver-factory'; 2 | import { textDriverFactory, TextDriver } from '../core/CoreText/Text.driver'; 3 | import { StylableDOMUtil } from '@stylable/dom-test-kit'; 4 | import style from './Heading.st.css'; 5 | import { Appearance } from './Heading'; 6 | 7 | export interface HeadingDriver extends TextDriver { 8 | getAppearance: () => Appearance; 9 | isLight: () => boolean; 10 | } 11 | 12 | export const headingDriverFactory = (factoryParams: ComponentFactory): HeadingDriver => { 13 | const coreTextDriver = textDriverFactory(factoryParams); 14 | const stylableDOMUtil = new StylableDOMUtil(style); 15 | const { element } = factoryParams; 16 | 17 | return { 18 | ...coreTextDriver, 19 | getAppearance: () => stylableDOMUtil.getStyleState(element, 'appearance') as Appearance, 20 | isLight: () => stylableDOMUtil.hasStyleState(element, 'light'), 21 | }; 22 | }; 23 | -------------------------------------------------------------------------------- /src/components/Heading/Heading.e2e.ts: -------------------------------------------------------------------------------- 1 | import * as eyes from 'eyes.it'; 2 | import {browser} from 'protractor'; 3 | import {getStoryUrl, waitForVisibilityOf} from 'wix-ui-test-utils/protractor'; 4 | import {headingTestkitFactory} from '../../testkit/protractor'; 5 | 6 | describe('Heading', () => { 7 | const storyUrl = getStoryUrl('Components', 'Heading'); 8 | 9 | beforeEach(() => browser.get(storyUrl)); 10 | eyes.it('should display correct content', () => { 11 | const dataHook = 'storybook-heading'; 12 | const driver = headingTestkitFactory({dataHook}); 13 | 14 | return waitForVisibilityOf(driver.element(), 'Cannot find Heading') 15 | .then(() => expect(driver.getText()).toBe('Some text')); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /src/components/Heading/Heading.protractor.driver.ts: -------------------------------------------------------------------------------- 1 | export {textDriverFactory as headingDriverFactory, TextDriver as HeadingDriver} from '../core/CoreText/Text.protractor.driver'; 2 | -------------------------------------------------------------------------------- /src/components/Heading/Heading.spec.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import {headingDriverFactory} from './Heading.driver'; 3 | import {Heading} from './'; 4 | import {Appearance} from './Heading'; 5 | import {createDriverFactory} from 'wix-ui-test-utils/driver-factory'; 6 | import {isEnzymeTestkitExists} from 'wix-ui-test-utils/enzyme'; 7 | import {isTestkitExists} from 'wix-ui-test-utils/vanilla'; 8 | import {mount} from 'enzyme'; 9 | import {headingTestkitFactory} from '../../testkit'; 10 | import {headingTestkitFactory as enzymeHeadingTestkitFactory} from '../../testkit/enzyme'; 11 | 12 | describe('Heading', () => { 13 | const createDriver = createDriverFactory(headingDriverFactory); 14 | 15 | describe('appearance prop', () => { 16 | it('should render a h1 tag by default', () => { 17 | const wrapper = createDriver(Hello); 18 | expect(wrapper.getTagName()).toBe('h1'); 19 | expect(wrapper.getAppearance()).toBe('H1'); 20 | }); 21 | 22 | ['H2', 'H3', 'H4'].forEach((appearance: Appearance) => { 23 | it(`should render a ${appearance.toLowerCase()} tag`, () => { 24 | const wrapper = createDriver(Hello); 25 | expect(wrapper.getTagName()).toBe(appearance.toLocaleLowerCase()); 26 | expect(wrapper.getAppearance()).toBe(appearance); 27 | }); 28 | }); 29 | }); 30 | 31 | describe('light prop', () => { 32 | it('should be dark by default', () => { 33 | const wrapper = createDriver(Hello); 34 | expect(wrapper.isLight()).toBe(false); 35 | }); 36 | 37 | it('should be light', () => { 38 | const wrapper = createDriver(Hello); 39 | expect(wrapper.isLight()).toBe(true); 40 | }); 41 | }); 42 | 43 | describe('testkit', () => { 44 | it('should exist', () => { 45 | expect(isTestkitExists(Hello World, headingTestkitFactory)).toBe(true); 46 | }); 47 | }); 48 | 49 | describe('enzyme testkit', () => { 50 | it('should exist', () => { 51 | expect(isEnzymeTestkitExists(Hello World, enzymeHeadingTestkitFactory, mount)).toBe(true); 52 | }); 53 | }); 54 | }); 55 | -------------------------------------------------------------------------------- /src/components/Heading/Heading.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import {Text as CoreText, TextProps as CoreTextProps} from '../core/CoreText'; 3 | import style from './Heading.st.css'; 4 | import {withStylable} from 'wix-ui-core/dist/src/utils/withStylable'; 5 | 6 | export enum Appearance { 7 | H1 = 'H1', 8 | H2 = 'H2', 9 | H3 = 'H3', 10 | H4 = 'H4' 11 | }; 12 | export type TagName = 'h1' | 'h2' | 'h3' | 'h4'; 13 | 14 | export interface Props { 15 | /** any nodes to be rendered (usually text nodes) */ 16 | children?: React.ReactNode; 17 | 18 | /** is the text has dark or light skin */ 19 | light?: boolean; 20 | 21 | /** typography of the heading */ 22 | appearance?: Appearance; 23 | } 24 | 25 | export interface State { tagName: TagName; } 26 | 27 | const defaultProps: Props = { 28 | appearance: Appearance.H1, 29 | light: false 30 | }; 31 | 32 | const StyledText = withStylable( 33 | CoreText, 34 | style, 35 | ({light, appearance}) => ({light, appearance}), 36 | defaultProps 37 | ); 38 | 39 | 40 | export class Heading extends React.PureComponent { 41 | static displayName = 'Heading'; 42 | 43 | static defaultProps: Props = defaultProps; 44 | 45 | state = {tagName: (this.props.appearance.toLowerCase()) as TagName} 46 | 47 | render() { 48 | return ( 49 | 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/components/Heading/index.ts: -------------------------------------------------------------------------------- 1 | import {Heading as HeadingComponent} from './Heading'; 2 | import {createHOC} from 'wix-ui-core/dist/src/createHOC'; 3 | 4 | export const Heading = createHOC(HeadingComponent); 5 | -------------------------------------------------------------------------------- /src/components/Input/Error.st.css: -------------------------------------------------------------------------------- 1 | :import { 2 | -st-from: "../../colors.st.css"; 3 | -st-named: 4 | R10, 5 | WHITE; 6 | } 7 | 8 | .root { 9 | width: 21px; 10 | height: 21px; 11 | border-radius: 50%; 12 | display: flex; 13 | justify-content: center; 14 | align-items: center; 15 | background: value(R10); 16 | } 17 | 18 | .root svg { 19 | fill: value(WHITE); 20 | } 21 | -------------------------------------------------------------------------------- /src/components/Input/Input.e2e.ts: -------------------------------------------------------------------------------- 1 | import * as eyes from 'eyes.it'; 2 | import {getStoryUrl} from 'wix-ui-test-utils/protractor'; 3 | import {inputTestkitFactory} from 'wix-ui-core/dist/src/testkit/protractor'; 4 | import {browser} from 'protractor'; 5 | 6 | describe('Input', () => { 7 | const storyUrl = getStoryUrl('Components', 'Input'); 8 | const dataHook = 'storybook-input'; 9 | 10 | beforeEach(() => browser.get(storyUrl)); 11 | 12 | eyes.it('should render', () => { 13 | const driver = inputTestkitFactory({dataHook}); 14 | 15 | expect(driver.element().isDisplayed()).toBe(true); 16 | }, {version: 'story with value'}); 17 | }); 18 | -------------------------------------------------------------------------------- /src/components/Input/Input.st.css: -------------------------------------------------------------------------------- 1 | :import { 2 | -st-from: "wix-ui-core/index.st.css"; 3 | -st-named: Input; 4 | } 5 | 6 | :import { 7 | -st-from: "../../colors.st.css"; 8 | -st-named: 9 | B20, B30, B40, B50, 10 | D10, D50, D55, D60, 11 | GR20, 12 | R10, 13 | WHITE 14 | } 15 | 16 | :import { 17 | -st-from: "../../typography.st.css"; 18 | -st-named: fontRoman; 19 | } 20 | 21 | :import { 22 | -st-from: "./InputStates.st.css"; 23 | -st-named: input-large, input-medium, input-small; 24 | } 25 | 26 | /* Input colors */ 27 | :vars { 28 | inputBackground: value(WHITE); 29 | inputBorderColor: value(B30); 30 | inputHover: value(B50); 31 | inputFocusBorderColor: value(B20); 32 | inputDisabledColor: value(D55); 33 | inputDisabledBorderColor: value(D60); 34 | inputDisabledHoverBorderColor: value(GR20); 35 | } 36 | 37 | .root { 38 | -st-extends: Input; 39 | -st-states: size(enum(large, medium, small)); 40 | 41 | display: flex; 42 | align-items: center; 43 | position: relative; 44 | box-sizing: border-box; 45 | color: value(D10); 46 | width: 100%; 47 | border-radius: 6px; 48 | border: 1px solid value(inputBorderColor); 49 | background-color: value(inputBackground); 50 | padding: 0 6px; 51 | } 52 | 53 | .root:error, 54 | .root:error:focus { 55 | border-color: value(R10); 56 | } 57 | 58 | .root:hover { 59 | background-color: value(inputHover); 60 | } 61 | 62 | .root:disabled { 63 | background-color: inherit; 64 | } 65 | 66 | .root:disabled { 67 | color: value(inputDisabledColor); 68 | border-color: value(inputDisabledBorderColor); 69 | } 70 | 71 | .root:disabled::nativeInput { 72 | color: value(inputDisabledColor); 73 | } 74 | 75 | .root:focus { 76 | border-color: value(inputFocusBorderColor); 77 | } 78 | 79 | .root::nativeInput { 80 | background-color: transparent; 81 | outline: none; 82 | width: 100%; 83 | font-family: value(fontRoman); 84 | border: none; 85 | padding: 0 6px; 86 | } 87 | 88 | .root::nativeInput::-webkit-input-placeholder { color: value(D50); } 89 | .root::nativeInput:-moz-placeholder { color: value(D50); } 90 | .root::nativeInput::-moz-placeholder { color: value(D50); } 91 | .root::nativeInput:-ms-input-placeholder { color: value(D50); } 92 | 93 | .root::nativeInput::selection { background: value(B40); } 94 | .root::nativeInput:-moz-selection { background: value(B40); } 95 | 96 | .root:size(large) { 97 | -st-mixin: input-large; 98 | } 99 | 100 | .root:size(medium) { 101 | -st-mixin: input-medium; 102 | } 103 | 104 | .root:size(small) { 105 | -st-mixin: input-small; 106 | } 107 | -------------------------------------------------------------------------------- /src/components/Input/Input.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { 3 | Input as CoreInput, 4 | InputProps as CoreInputProps 5 | } from 'wix-ui-core/dist/src/components/input'; 6 | import { withStylable } from 'wix-ui-core/dist/src/utils/withStylable'; 7 | import style from './Input.st.css'; 8 | import { getInputSuffix } from './InputSuffixes'; 9 | 10 | export interface InputProps { 11 | // The size of the input 12 | size?: 'large' | 'medium' | 'small'; 13 | } 14 | 15 | const defaultProps = { 16 | size: 'medium' 17 | }; 18 | 19 | export const StyledInput = withStylable( 20 | CoreInput, 21 | style, 22 | ({ size }) => ({ size }), 23 | defaultProps 24 | ); 25 | 26 | export const Input: React.SFC = ( 27 | props: CoreInputProps & InputProps 28 | ) => { 29 | const { error, disabled, suffix } = props; 30 | 31 | return ( 32 | 36 | ); 37 | }; 38 | 39 | Input.displayName = 'Input'; 40 | -------------------------------------------------------------------------------- /src/components/Input/InputStates.st.css: -------------------------------------------------------------------------------- 1 | :import { 2 | -st-from: "./Input.st.css"; 3 | -st-named: Input; 4 | } 5 | 6 | :import { 7 | -st-from: "../../colors.st.css"; 8 | -st-named: 9 | R10, 10 | } 11 | 12 | :import { 13 | -st-from: "wix-ui-core/dist/src/mixins/calc"; 14 | -st-default: calc; 15 | } 16 | 17 | :vars { 18 | largeFont: 22px; 19 | medFont: 16px; 20 | smallFont: 14px; 21 | 22 | largeHeight: 60px; 23 | medHeight: 36px; 24 | smallHeight: 30px; 25 | } 26 | 27 | .input-error { 28 | color: value(R10); 29 | border-color: value(R10); 30 | } 31 | 32 | .input-large { 33 | -st-extends: Input; 34 | } 35 | 36 | .input-large::nativeInput { 37 | height: value(largeHeight); 38 | line-height: calc(value(largeHeight) - 2px); 39 | font-size: value(largeFont); 40 | } 41 | 42 | .input-medium { 43 | -st-extends: Input; 44 | } 45 | 46 | .input-medium::nativeInput { 47 | height: value(medHeight); 48 | line-height: calc(value(medHeight) - 2px); 49 | font-size: value(medFont); 50 | } 51 | 52 | .input-small { 53 | -st-extends: Input; 54 | } 55 | 56 | .input-small::nativeInput { 57 | height: value(smallHeight); 58 | line-height: calc(value(smallHeight) - 2px); 59 | font-size: value(smallFont); 60 | } 61 | -------------------------------------------------------------------------------- /src/components/Input/InputSuffixes.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import FormFieldError from 'wix-ui-icons-common/system/FormFieldError'; 3 | import {Tooltip} from '../Tooltip'; 4 | import style from './Error.st.css'; 5 | 6 | const ErrorComponent = () => ( 7 |
8 | 9 |
10 | ); 11 | 12 | const getInputErrorSuffix = (error: boolean | string) => { 13 | if (error === true) { 14 | return ; 15 | } 16 | 17 | return ( 18 | 19 | 20 | 21 | ); 22 | }; 23 | 24 | export const getInputSuffix = ({error, disabled, suffix}) => { 25 | if (!error || disabled) { 26 | return suffix; 27 | } 28 | 29 | return getInputErrorSuffix(error); 30 | }; 31 | -------------------------------------------------------------------------------- /src/components/Input/index.ts: -------------------------------------------------------------------------------- 1 | export {Input, InputProps} from './Input'; 2 | export {getInputSuffix} from './InputSuffixes'; 3 | -------------------------------------------------------------------------------- /src/components/Label/Label.driver.ts: -------------------------------------------------------------------------------- 1 | import {labelDriverFactory as CoreLabelDriverFactory} from 'wix-ui-core/drivers/vanilla'; 2 | import {StylableDOMUtil} from '@stylable/dom-test-kit'; 3 | import style from './Label.st.css'; 4 | 5 | export const labelDriverFactory = ({element, eventTrigger}) => { 6 | const coreLabelDriver = CoreLabelDriverFactory({element, eventTrigger}); 7 | const stylableDOMUtil = new StylableDOMUtil(style); 8 | 9 | return { 10 | ...coreLabelDriver, 11 | getSize: () => stylableDOMUtil.getStyleState(element, 'size') 12 | }; 13 | }; 14 | -------------------------------------------------------------------------------- /src/components/Label/Label.e2e.ts: -------------------------------------------------------------------------------- 1 | import * as eyes from 'eyes.it'; 2 | import {browser} from 'protractor'; 3 | import {getStoryUrl, waitForVisibilityOf} from 'wix-ui-test-utils/protractor'; 4 | import {labelTestkitFactory} from '../../testkit/protractor'; 5 | 6 | describe('Label', () => { 7 | const storyUrl = getStoryUrl('Components', 'Label'); 8 | 9 | beforeEach(() => browser.get(storyUrl)); 10 | eyes.it('should display correct content', () => { 11 | const dataHook = 'storybook-label'; 12 | const driver = labelTestkitFactory({dataHook}); 13 | 14 | return waitForVisibilityOf(driver.element(), 'Cannot find Label') 15 | .then(() => expect(driver.getLabelText()).toBe('Some label')); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /src/components/Label/Label.protractor.driver.ts: -------------------------------------------------------------------------------- 1 | export {labelDriverFactory, LabelDriver} from 'wix-ui-core/drivers/protractor'; 2 | -------------------------------------------------------------------------------- /src/components/Label/Label.spec.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import {labelDriverFactory} from './Label.driver'; 3 | import {labelUniDriverFactory} from './Label.uni.driver'; 4 | import {Label} from './'; 5 | import {Size} from './constants'; 6 | import {createDriverFactory} from 'wix-ui-test-utils/driver-factory'; 7 | import {createUniDriverFactory} from 'wix-ui-test-utils/uni-driver-factory'; 8 | import {isEnzymeTestkitExists} from 'wix-ui-test-utils/enzyme'; 9 | import {isTestkitExists} from 'wix-ui-test-utils/vanilla'; 10 | import {mount} from 'enzyme'; 11 | import {labelTestkitFactory} from '../../testkit'; 12 | import {labelTestkitFactory as enzymeLabelTestkitFactory} from '../../testkit/enzyme'; 13 | 14 | describe('Label', () => { 15 | 16 | describe('[sync]', () => { 17 | runTests(createDriverFactory(labelDriverFactory)); 18 | }); 19 | 20 | describe('[async]', () => { 21 | runTests(createUniDriverFactory(labelUniDriverFactory)); 22 | }); 23 | 24 | function runTests(createDriver) { 25 | describe('size prop', () => { 26 | it('should be medium by default', async() => { 27 | const wrapper = createDriver(); 28 | expect(await wrapper.getSize()).toBe('medium'); 29 | }); 30 | 31 | it('should be small', async () => { 32 | const wrapper = createDriver(); 33 | expect(await wrapper.getSize()).toBe('small'); 34 | }); 35 | }); 36 | 37 | describe('children prop', () => { 38 | it('renders', async () => { 39 | const wrapper = createDriver(); 40 | expect(await wrapper.getLabelText()).toBe('Hello'); 41 | }); 42 | }); 43 | } 44 | 45 | describe('testkit', () => { 46 | it('should exist', () => { 47 | expect(isTestkitExists(, labelTestkitFactory)).toBe(true); 48 | }); 49 | }); 50 | 51 | describe('enzyme testkit', () => { 52 | it('should exist', () => { 53 | expect(isEnzymeTestkitExists(, enzymeLabelTestkitFactory, mount)).toBe(true); 54 | }); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /src/components/Label/Label.st.css: -------------------------------------------------------------------------------- 1 | :import { 2 | -st-from: "wix-ui-core/index.st.css"; 3 | -st-named: Label; 4 | } 5 | 6 | :import { 7 | -st-from: "../../colors.st.css"; 8 | -st-named: 9 | D20, 10 | } 11 | 12 | :import { 13 | -st-from: "../../typography.st.css"; 14 | -st-named: fontLight; 15 | } 16 | 17 | .root { 18 | -st-extends: Label; 19 | -st-states: size(enum(small, medium)); 20 | color: value(D20); 21 | font-family: value(fontLight); 22 | } 23 | 24 | .root:size(medium) { 25 | font-size: 16px; 26 | line-height: 24px; 27 | } 28 | 29 | .root:size(small) { 30 | font-size: 14px; 31 | line-height: 18px; 32 | } 33 | -------------------------------------------------------------------------------- /src/components/Label/Label.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { 3 | Label as CoreLabel, 4 | LabelProps as CoreLabelProps 5 | } from 'wix-ui-core/dist/src/components/deprecated/label'; 6 | import style from './Label.st.css'; 7 | import { Size, SIZES } from './constants'; 8 | 9 | export interface LabelProps { 10 | /** size of the label */ 11 | size?: Size; 12 | } 13 | 14 | export const Label: React.SFC = (props: CoreLabelProps & LabelProps) => { 15 | const {size, className,...rest} = props; 16 | return 17 | }; 18 | 19 | Label.defaultProps = { 20 | size: SIZES.medium 21 | }; 22 | 23 | Label.displayName = 'Label'; 24 | -------------------------------------------------------------------------------- /src/components/Label/Label.uni.driver.ts: -------------------------------------------------------------------------------- 1 | import {UniDriver} from 'wix-ui-test-utils/unidriver'; 2 | import {labelUniDriverFactory as coreLabelUniDriverFactory,LabelDriver as CoreLabelDriver} from 'wix-ui-core/dist/src/components/deprecated/label/Label.uni.driver'; 3 | 4 | import {Size} from './constants'; 5 | 6 | export interface LabelDriver extends CoreLabelDriver { 7 | /** 8 | * Get size 9 | */ 10 | getSize: () => Promise; 11 | } 12 | 13 | export const labelUniDriverFactory = (base: UniDriver): LabelDriver => { 14 | 15 | return { 16 | ...coreLabelUniDriverFactory(base), 17 | getSize: () => base.attr('data-size') as Promise 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /src/components/Label/constants.ts: -------------------------------------------------------------------------------- 1 | export type Size = 'small' | 'medium'; 2 | 3 | export enum SIZES { 4 | small = 'small', 5 | medium = 'medium' 6 | } 7 | -------------------------------------------------------------------------------- /src/components/Label/index.ts: -------------------------------------------------------------------------------- 1 | import {Label as LabelComponent} from './Label'; 2 | import {createHOC} from 'wix-ui-core/dist/src/createHOC'; 3 | 4 | export const Label = createHOC(LabelComponent); 5 | -------------------------------------------------------------------------------- /src/components/LabelWithOptions/LabelWithOptions.driver.ts: -------------------------------------------------------------------------------- 1 | export {labelWithOptionsDriverFactory} from 'wix-ui-core/drivers/vanilla'; 2 | -------------------------------------------------------------------------------- /src/components/LabelWithOptions/LabelWithOptions.e2e.ts: -------------------------------------------------------------------------------- 1 | import * as eyes from 'eyes.it'; 2 | import {getStoryUrl, waitForVisibilityOf} from 'wix-ui-test-utils/protractor'; 3 | import {labelWithOptionsTestkitFactory} from '../../testkit/protractor'; 4 | import {browser} from 'protractor'; 5 | 6 | describe('LabelWithOptions', () => { 7 | const storyUrl = getStoryUrl('Components', 'LabelWithOptions'); 8 | const dataHook = 'storybook-labelwithoptions'; 9 | 10 | beforeEach(() => browser.get(storyUrl)); 11 | 12 | eyes.it('should render LabelWithOptions', async () => { 13 | const driver = labelWithOptionsTestkitFactory({dataHook}); 14 | await waitForVisibilityOf(driver.element(), 'Cannot find LabelWithOptions'); 15 | expect(driver.element()).toBeDefined(); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /src/components/LabelWithOptions/LabelWithOptions.protractor.driver.ts: -------------------------------------------------------------------------------- 1 | export {labelWithOptionsDriverFactory, LabelWithOptionsDriver} from 'wix-ui-core/drivers/protractor'; 2 | -------------------------------------------------------------------------------- /src/components/LabelWithOptions/LabelWithOptions.spec.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import {createDriverFactory} from 'wix-ui-test-utils/driver-factory'; 3 | import {labelWithOptionsDriverFactory} from './LabelWithOptions.driver'; 4 | import {LabelWithOptions} from '.'; 5 | import {labelWithOptionsTestkitFactory} from '../../testkit'; 6 | import {labelWithOptionsTestkitFactory as enzymeLabelWithOptionsTestkitFactory} from '../../testkit/enzyme'; 7 | import {isEnzymeTestkitExists} from 'wix-ui-test-utils/enzyme'; 8 | import {isTestkitExists} from 'wix-ui-test-utils/vanilla'; 9 | import {mount} from 'enzyme'; 10 | 11 | describe('LabelWithOptions', () => { 12 | const createDriver = createDriverFactory(labelWithOptionsDriverFactory); 13 | 14 | it('should render LabelWithOptions', () => { 15 | const driver = createDriver(); 16 | expect(driver.isTargetElementExists()).toBeTruthy(); 17 | expect(driver.isContentElementExists()).toBeFalsy(); 18 | }); 19 | 20 | describe('testkit', () => { 21 | it('should exist', () => { 22 | expect(isTestkitExists(, labelWithOptionsTestkitFactory)).toBe(true); 23 | }); 24 | }); 25 | 26 | describe('enzyme testkit', () => { 27 | it('should exist', () => { 28 | expect(isEnzymeTestkitExists(, enzymeLabelWithOptionsTestkitFactory, mount)).toBe(true); 29 | }); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /src/components/LabelWithOptions/LabelWithOptions.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { 3 | LabelWithOptions as CoreLabelWithOptions, 4 | LabelWithOptionsProps as CoreLabelWithOptionsProps 5 | } from 'wix-ui-core/dist/src/components/label-with-options'; 6 | import { withStylable } from 'wix-ui-core/dist/src/utils/withStylable'; 7 | import ChevronDown from 'wix-ui-icons-common/ChevronDown'; 8 | import style from './LabelWithOptions.st.css'; 9 | import { Tooltip } from '../Tooltip'; 10 | import { getInputSuffix } from '../Input/InputSuffixes'; 11 | import FormFieldError from 'wix-ui-icons-common/system/FormFieldError'; 12 | 13 | export interface LabelWithOptionsProps { 14 | // The size of the LabelWithOptions 15 | size?: 'large' | 'medium' | 'small'; 16 | } 17 | 18 | const defaultProps = { 19 | size: 'medium' 20 | }; 21 | 22 | const StyledLabelWithOptions = withStylable< 23 | CoreLabelWithOptionsProps, 24 | LabelWithOptionsProps 25 | >(CoreLabelWithOptions, style, ({ size }) => ({ size }), defaultProps); 26 | 27 | export type LabelWithOptionsType = React.SFC< 28 | CoreLabelWithOptionsProps & LabelWithOptionsProps 29 | > & { 30 | createOption: typeof CoreLabelWithOptions.createOption; 31 | createDivider: typeof CoreLabelWithOptions.createDivider; 32 | }; 33 | 34 | const defaultSuffix = ; 35 | const renderSuffix = ({ isError, disabled }) => 36 | getInputSuffix({ 37 | error: isError ? 'Selection is required!' : null, 38 | disabled, 39 | suffix: defaultSuffix 40 | }); 41 | 42 | export const LabelWithOptions: LabelWithOptionsType = (( 43 | props: CoreLabelWithOptionsProps & LabelWithOptionsProps 44 | ) => { 45 | const { disabled } = props; 46 | return ( 47 | renderSuffix({ isError, disabled })} 49 | {...props} 50 | /> 51 | ); 52 | }) as LabelWithOptionsType; 53 | 54 | LabelWithOptions.displayName = 'LabelWithOptions'; 55 | LabelWithOptions.createOption = CoreLabelWithOptions.createOption; 56 | LabelWithOptions.createDivider = CoreLabelWithOptions.createDivider; 57 | -------------------------------------------------------------------------------- /src/components/LabelWithOptions/index.ts: -------------------------------------------------------------------------------- 1 | export {LabelWithOptions} from './LabelWithOptions'; 2 | -------------------------------------------------------------------------------- /src/components/LabelWithOptions/readme.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | A dropdown like component, where trigger is text 4 | 5 | ```js 6 | import {LabelWithOptions} from 'wix-ui-backoffice/LabelWithOptions'; 7 | 8 | const options = [ 9 | LabelWithOptions.createOption({value: `value0`}), // generates an option with a unique id 10 | LabelWithOptions.createOption({id: 1, value: `value1`}), // generates an option with id, value 11 | LabelWithOptions.createOption({id: 2, value: `value2`, isDisabled: true}), // genrates a disabled option 12 | LabelWithOptions.createOption({id: 3, value: `value3`, isSelectable: false}), // generates an unselectable option 13 | LabelWithOptions.createOption({id: 4, value: `value4`, render: value => value + 's'}), // generates an option with a custom render function 14 | LabelWithOptions.createDivider(), // generates default divider 15 | LabelWithOptions.createDivider('Value') // generates a divider with value 16 | ]; 17 | 18 | null} 21 | onDeselect={option => null} 22 | initialSelectedIds={null || [1]} 23 | fixedHeader={'Fixed Header'} 24 | fixedFooter={'Fixed Footer'} 25 | disabled={false} 26 | placeholder={'This is a placeholder'} 27 | required={false} 28 | size={'large' || 'medium' || 'small'} 29 | /> 30 | ``` 31 | -------------------------------------------------------------------------------- /src/components/LinearProgressBar/LinearProgressBar.driver.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFactory } from 'wix-ui-test-utils/driver-factory'; 2 | import { 3 | linearProgressBarDriverFactory as coreLinearProgressBarDriverFactory, 4 | LinearProgressBarDriver as CoreLinearProgressBarDriver 5 | } from 'wix-ui-core/drivers/vanilla'; 6 | import { BaseDriver, DriverFactory } from 'wix-ui-test-utils/driver-factory'; 7 | import { tooltipDriverFactory } from '../Tooltip/Tooltip.driver' 8 | 9 | export interface LinearProgressBarDriver extends CoreLinearProgressBarDriver { 10 | /* Returns true if the tooltip is shown */ 11 | isTooltipShown: () => boolean; 12 | /* Returns true if the error icon is shown */ 13 | isErrorIconShown: () => boolean; 14 | /* Returns true if the success icon is shown */ 15 | isSuccessIconShown: () => boolean; 16 | /* Returns the tooltip driver */ 17 | getTooltip: () => any; 18 | 19 | } 20 | 21 | export const linearProgressBarDriverFactory: DriverFactory = ({ element, eventTrigger, wrapper }: ComponentFactory): LinearProgressBarDriver => { 22 | const createTooltipDriver = () => tooltipDriverFactory({ element: element.querySelector(`[data-hook='linear-progressbar-tooltip']`), wrapper, eventTrigger }); 23 | const coreProgressBarDriver = coreLinearProgressBarDriverFactory({ element, wrapper, eventTrigger }); 24 | const errorIcon = () => element.querySelector(`[data-hook='error-icon']`); 25 | const successIcon = () => element.querySelector(`[data-hook='success-icon']`); 26 | 27 | return { 28 | ...coreProgressBarDriver, 29 | isTooltipShown: () => createTooltipDriver().isContentElementExists(), 30 | getTooltip: () => createTooltipDriver(), 31 | isErrorIconShown: () => !!errorIcon(), 32 | isSuccessIconShown: () => !!successIcon() 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /src/components/LinearProgressBar/LinearProgressBar.e2e.ts: -------------------------------------------------------------------------------- 1 | import * as eyes from 'eyes.it'; 2 | import {$, browser} from 'protractor'; 3 | import * as autoExampleDriver from 'wix-storybook-utils/AutoExampleDriver'; 4 | import {getStoryUrl, waitForVisibilityOf} from 'wix-ui-test-utils/protractor'; 5 | import {linearProgressBarTestkitFactory, LinearProgressBarDriver} from '../../testkit/protractor'; 6 | import {enumValues} from '../../utils'; 7 | 8 | describe('LinearProgressBar', () => { 9 | const storyUrl = getStoryUrl('Components', 'LinearProgressBar'); 10 | let driver: LinearProgressBarDriver; 11 | 12 | beforeAll(async () => { 13 | await browser.get(storyUrl); 14 | driver = linearProgressBarTestkitFactory({dataHook: 'linear-progress-bar-story'}); 15 | await waitForVisibilityOf(driver.element(), 'Cannot find LinearProgressBar'); 16 | }); 17 | 18 | afterEach(() => autoExampleDriver.reset()); 19 | 20 | eyes.it('should exist', () => { 21 | expect(driver.element().isPresent()).toBe(true); 22 | }); 23 | 24 | eyes.it('should render correct success state', async () => { 25 | await autoExampleDriver.setProps({value: 100, showProgressIndication: true}); 26 | expect(driver.element().isPresent()).toBe(true); 27 | }); 28 | 29 | eyes.it('should render correct error state', async () => { 30 | await autoExampleDriver.setProps({value: 30, showProgressIndication: true, error: true, errorMessage: 'Some error'}); 31 | expect(driver.element().isPresent()).toBe(true); 32 | 33 | eyes.checkWindow('errorIcon'); 34 | 35 | driver.showError(); 36 | 37 | await waitForVisibilityOf($(`[data-hook="linear-progressbar-tooltip"]`), 'Cannot find CircularProgressBar tooltip'); 38 | }); 39 | 40 | eyes.it('should render correct light state', async () => { 41 | await autoExampleDriver.setProps({value: 20, light: true}); 42 | expect(driver.element().isPresent()).toBe(true); 43 | 44 | eyes.checkWindow('light'); 45 | 46 | await autoExampleDriver.setProps({value: 20, light: true, error: true}); 47 | expect(driver.element().isPresent()).toBe(true); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /src/components/LinearProgressBar/LinearProgressBar.protractor.driver.ts: -------------------------------------------------------------------------------- 1 | import {promise, browser, $, ElementFinder} from 'protractor'; 2 | import {DriverFactory} from 'wix-ui-core/dist/src/common/BaseDriver.protractor'; 3 | import {linearProgressBarDriverFactory as coreLinearProgressBarDriverFactory, LinearProgressBarDriver as CoreLinearProgressBarDriver} from 'wix-ui-core/drivers/protractor'; 4 | 5 | export interface LinearProgressBarDriver extends CoreLinearProgressBarDriver { 6 | /** Hovers over the error icon to display the tooltip with the error message */ 7 | showError: () => promise.Promise; 8 | } 9 | 10 | export const linearProgressBarDriverFactory: DriverFactory = (element: ElementFinder): LinearProgressBarDriver => { 11 | const errorIcon = () => element.$(`[data-hook='error-icon']`); 12 | return { 13 | ...coreLinearProgressBarDriverFactory(element), 14 | showError: () => browser.actions().mouseMove(errorIcon()).perform() 15 | }; 16 | }; 17 | -------------------------------------------------------------------------------- /src/components/LinearProgressBar/LinearProgressBar.st.css: -------------------------------------------------------------------------------- 1 | :import { 2 | -st-from: "wix-ui-core/index.st.css"; 3 | -st-named: LinearProgressBar; 4 | } 5 | 6 | :import { 7 | -st-from: "../../typography.st.css"; 8 | -st-named: fontMedium; 9 | } 10 | 11 | :import { 12 | -st-from: "../../colors.st.css"; 13 | -st-named: 14 | B00, B10, B30, 15 | D20, 16 | R00, R10, R30, 17 | WHITE, 18 | } 19 | 20 | .root { 21 | -st-states: light; 22 | -st-extends: LinearProgressBar; 23 | padding: 0px 6px; 24 | height: 30px; 25 | } 26 | 27 | .root::barForeground { 28 | background: value(B00); 29 | transition: width 0.5s ease-in-out; 30 | } 31 | 32 | .root::barBackground { 33 | background: value(B30); 34 | } 35 | 36 | .root::barBackground, 37 | .root::barForeground 38 | { 39 | border-radius: 2px; 40 | height: 4px; 41 | } 42 | 43 | .root:error::barForeground { 44 | background: value(R00); 45 | } 46 | 47 | .root:error::barBackground { 48 | background: value(R30); 49 | } 50 | 51 | .root:light::barBackground { 52 | background: value(WHITE); 53 | } 54 | 55 | .root::progressIndicationSection { 56 | margin-left: 18px; 57 | } 58 | 59 | :global([dir="rtl"]) .root::progressIndicationSection { 60 | margin-right: 18px; 61 | margin-left: 0; 62 | } 63 | 64 | .root::indicationContainer { 65 | width: 18px; 66 | height: 18px; 67 | border-radius: 12px; 68 | display: flex; 69 | justify-content: center; 70 | align-items: center; 71 | color: value(D20); 72 | font-size: 10px; 73 | font-family: value(fontMedium); 74 | } 75 | 76 | .root:success::indicationContainer { 77 | background: value(B10); 78 | } 79 | 80 | .root:error::indicationContainer { 81 | background: value(R10); 82 | } 83 | 84 | .root::indicationContainer svg { 85 | height: 8px; 86 | width: 10px; 87 | color: value(WHITE); 88 | } 89 | -------------------------------------------------------------------------------- /src/components/LinearProgressBar/LinearProgressBar.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { 3 | LinearProgressBar as CoreLinearProgressBar, 4 | LinearProgressBarProps as CoreLinearProgressBarProps 5 | } from 'wix-ui-core/linear-progress-bar'; 6 | import ToggleOn from 'wix-ui-icons-common/system/ToggleOn'; 7 | import FormFieldError from 'wix-ui-icons-common/system/FormFieldError'; 8 | import style from './LinearProgressBar.st.css'; 9 | import { Tooltip } from '../Tooltip'; 10 | import { Omit } from '../../types/common'; 11 | 12 | export interface LinearProgressBarProps 13 | extends Omit { 14 | /** message to display when an error happens */ 15 | errorMessage?: string; 16 | /** use light theme instead of dark theme */ 17 | light?: boolean; 18 | } 19 | 20 | export const LinearProgressBar: React.SFC = ( 21 | props: LinearProgressBarProps 22 | ) => { 23 | const { errorMessage, light, ...otherProps } = props; 24 | 25 | return ( 26 | } 30 | errorIcon={ 31 | 36 | 37 | 38 | } 39 | /> 40 | ); 41 | }; 42 | 43 | LinearProgressBar.displayName = 'LinearProgressBar'; 44 | -------------------------------------------------------------------------------- /src/components/LinearProgressBar/index.ts: -------------------------------------------------------------------------------- 1 | import {LinearProgressBar as LinearProgressBarComponent} from './LinearProgressBar'; 2 | import {createHOC} from 'wix-ui-core/dist/src/createHOC'; 3 | 4 | export const LinearProgressBar = createHOC(LinearProgressBarComponent); 5 | -------------------------------------------------------------------------------- /src/components/StylableCounterBadge/CounterBadge.driver.ts: -------------------------------------------------------------------------------- 1 | import { Skin } from './constants'; 2 | import { ComponentFactory, BaseDriver } from 'wix-ui-test-utils/driver-factory'; 3 | import { badgeDriverFactory as coreBadgeDriverFactory, BadgeDriver as CoreBadgeDriver } from 'wix-ui-core/drivers/vanilla'; 4 | import { StylableDOMUtil } from '@stylable/dom-test-kit'; 5 | import style from './CounterBadge.st.css'; 6 | 7 | export interface CounterBadgeDriver extends CoreBadgeDriver { 8 | /** returns the skin color */ 9 | getSkin: () => Skin | null; 10 | /** checks if the component is in wide mode */ 11 | isWide: () => boolean; 12 | /** returns the icon if provided */ 13 | getIcon: () => Element | null; 14 | } 15 | 16 | export const counterBadgeDriverFactory = (factoryParams: ComponentFactory): CounterBadgeDriver => { 17 | const coreBadgeDriver = coreBadgeDriverFactory(factoryParams); 18 | const { element } = factoryParams; 19 | const stylableDOMUtil = new StylableDOMUtil(style, element); 20 | 21 | return { 22 | ...coreBadgeDriver, 23 | getSkin: () => stylableDOMUtil.getStyleState(element, 'skin') as Skin | null, 24 | isWide: () => stylableDOMUtil.hasStyleState(element, 'wide'), 25 | getIcon: () => stylableDOMUtil.select('.icon') 26 | }; 27 | }; 28 | -------------------------------------------------------------------------------- /src/components/StylableCounterBadge/CounterBadge.e2e.tsx: -------------------------------------------------------------------------------- 1 | import * as eyes from 'eyes.it'; 2 | import { browser } from 'protractor'; 3 | import { getStoryUrl, waitForVisibilityOf } from 'wix-ui-test-utils/protractor'; 4 | import { stylableCounterBadgeTestkitFactory as counterBadgeTestkitFactory } from '../../testkit/protractor'; 5 | 6 | describe('CounterBadge', () => { 7 | const storyUrl = getStoryUrl('Components', 'StylableCounterBadge'); 8 | 9 | beforeEach(() => browser.get(storyUrl)); 10 | eyes.it('should display correct content', () => { 11 | const dataHook = 'storybook-counterBadge'; 12 | const driver = counterBadgeTestkitFactory({ dataHook }); 13 | 14 | return waitForVisibilityOf( 15 | driver.element(), 16 | 'Cannot find CounterBadge' 17 | ).then(() => expect(driver.text()).toBe('12')); 18 | }); 19 | 20 | eyes.it('should display "99+" when number > 99', () => { 21 | const dataHook = 'storybook-counterBadge'; 22 | const driver = counterBadgeTestkitFactory({ dataHook }); 23 | 24 | return waitForVisibilityOf( 25 | driver.element(), 26 | 'Cannot find CounterBadge' 27 | ).then(() => expect(driver.text()).toBe('99+')); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /src/components/StylableCounterBadge/CounterBadge.protractor.driver.ts: -------------------------------------------------------------------------------- 1 | export {badgeDriverFactory as counterBadgeDriverFactory, BadgeDriver} from 'wix-ui-core/drivers/protractor'; 2 | -------------------------------------------------------------------------------- /src/components/StylableCounterBadge/CounterBadge.st.css: -------------------------------------------------------------------------------- 1 | :import { 2 | -st-from: "wix-ui-core/index.st.css"; 3 | -st-named: BadgeStyle; 4 | } 5 | 6 | :import { 7 | -st-from: "wix-ui-core/index.st.css"; 8 | -st-named: Badge; 9 | } 10 | 11 | :import { 12 | -st-from: "../../typography.st.css"; 13 | -st-named: fontMedium; 14 | } 15 | 16 | :import { 17 | -st-from: "../../colors.st.css"; 18 | -st-named: 19 | B10, 20 | D20, 21 | G10, 22 | O10, 23 | R10, 24 | Y10, 25 | WHITE; 26 | } 27 | 28 | .root { 29 | -st-extends: Badge; 30 | -st-states: skin(string), wide; 31 | } 32 | 33 | .text { 34 | font-family: value(fontMedium); 35 | font-size: 10px; 36 | line-height: 12px; 37 | letter-spacing: 0; 38 | color: currentColor; 39 | text-transform: uppercase; 40 | } 41 | 42 | .icon { 43 | width: 12px; 44 | height: 12px; 45 | } 46 | 47 | .root:skin(general) { 48 | -st-mixin: BadgeStyle( 49 | backgroundColor value(D20), 50 | borderColor value(D20) 51 | ); 52 | } 53 | 54 | .root:skin(standard) { 55 | -st-mixin: BadgeStyle( 56 | backgroundColor value(B10), 57 | borderColor value(B10) 58 | ); 59 | } 60 | 61 | .root:skin(danger) { 62 | -st-mixin: BadgeStyle( 63 | backgroundColor value(R10), 64 | borderColor value(R10) 65 | ); 66 | } 67 | 68 | .root:skin(warning) { 69 | -st-mixin: BadgeStyle( 70 | backgroundColor value(Y10), 71 | borderColor value(Y10) 72 | ); 73 | } 74 | 75 | .root:skin(urgent) { 76 | -st-mixin: BadgeStyle( 77 | backgroundColor value(O10), 78 | borderColor value(O10) 79 | ); 80 | } 81 | 82 | .root:skin(success) { 83 | -st-mixin: BadgeStyle( 84 | backgroundColor value(G10), 85 | borderColor value(G10) 86 | ); 87 | } 88 | 89 | .root:skin(general), 90 | .root:skin(standard), 91 | .root:skin(danger), 92 | .root:skin(warning), 93 | .root:skin(urgent), 94 | .root:skin(success) { 95 | min-width: 18px; 96 | border-radius: 12px; 97 | border: initial; 98 | height: 18px; 99 | padding: 2px; 100 | } 101 | 102 | .root:wide { 103 | padding: 2px 6px; 104 | } 105 | 106 | .root:wide .text { 107 | letter-spacing: 1px; 108 | } 109 | -------------------------------------------------------------------------------- /src/components/StylableCounterBadge/CounterBadge.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { withStylable } from 'wix-ui-core/dist/src/utils/withStylable'; 3 | import { 4 | Badge as CoreBadge, 5 | BadgeProps as CoreBadgeProps 6 | } from 'wix-ui-core/dist/src/components/deprecated/stylable-badge'; 7 | import { Skin, SKIN, maxNumberBeforeTruncation } from './constants'; 8 | import { isIcon, isWide } from './utils'; 9 | import style from './CounterBadge.st.css'; 10 | 11 | export type Content = string | number | React.ReactElement; 12 | 13 | export interface CounterBadgeProps { 14 | /** Skin of the badge */ 15 | skin?: Skin; 16 | 17 | /** Content of the badge */ 18 | children?: Content; 19 | } 20 | 21 | const defaultProps: CounterBadgeProps = { 22 | skin: SKIN.general, 23 | children: '' 24 | }; 25 | 26 | type CounterBadgeExtendedProps = CounterBadgeProps & { wide: boolean }; 27 | const getState = ({ skin, wide }) => ({ skin, wide }); 28 | 29 | const StyledCounterBadge = withStylable< 30 | CoreBadgeProps, 31 | CounterBadgeExtendedProps 32 | >(CoreBadge, style, getState, defaultProps); 33 | 34 | export class CounterBadge extends React.PureComponent { 35 | static displayName = 'CounterBadge'; 36 | 37 | static defaultProps = defaultProps; 38 | 39 | private readonly getContent = () => { 40 | const { children } = this.props; 41 | const isChildrenIcon = isIcon(children); 42 | let content = children; 43 | 44 | if (!isChildrenIcon && Number(children) > maxNumberBeforeTruncation) { 45 | content = '99+'; 46 | } 47 | 48 | return isChildrenIcon ? ( 49 | React.cloneElement(children as React.ReactElement, { 50 | className: style.icon 51 | }) 52 | ) : ( 53 | {content} 54 | ); 55 | }; 56 | 57 | render() { 58 | const { children, ...rest } = this.props; 59 | 60 | return ( 61 | 62 | {this.getContent()} 63 | 64 | ); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/components/StylableCounterBadge/constants.ts: -------------------------------------------------------------------------------- 1 | export type Skin = 'general' | 'standard' | 'danger' | 'warning' | 'urgent' | 'success'; 2 | 3 | export enum SKIN { 4 | general = 'general', 5 | standard = 'standard', 6 | danger = 'danger', 7 | warning = 'warning', 8 | urgent = 'urgent', 9 | success = 'success' 10 | } 11 | 12 | export const maxContentLength = 2; 13 | 14 | export const maxNumberBeforeTruncation = 99; 15 | -------------------------------------------------------------------------------- /src/components/StylableCounterBadge/index.ts: -------------------------------------------------------------------------------- 1 | import {CounterBadge as CounterBadgeComponent} from './CounterBadge'; 2 | import {createHOC} from 'wix-ui-core/dist/src/createHOC'; 3 | 4 | export const CounterBadge = createHOC(CounterBadgeComponent); 5 | -------------------------------------------------------------------------------- /src/components/StylableCounterBadge/utils.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import {maxContentLength} from './constants'; 3 | 4 | export const getContent = children => React.Children.toArray(children)[0]; 5 | 6 | export const isIcon = children => typeof children !== 'string' && typeof children !== 'number'; 7 | 8 | export const isWide = children => { 9 | const content = getContent(children); 10 | 11 | if (isIcon(children)) { 12 | return false; 13 | } 14 | 15 | const contentLength = content.toString().length; 16 | 17 | return contentLength >= maxContentLength; 18 | }; 19 | -------------------------------------------------------------------------------- /src/components/Text/README.md: -------------------------------------------------------------------------------- 1 | # `` 2 | 3 | General text component with Wix styling. 4 | 5 | ## Usage 6 | 7 | 1. Load Wix fonts from CDN: 8 | 9 | ```html 10 | 11 | ``` 12 | 13 | 2. Use `` component with appropriate appearance: 14 | 15 | ```js 16 | import {Text} from 'wix-ui-backoffice/Text'; 17 | 18 | const Component = () => 19 |
20 | Some Text 21 |
; 22 | ``` 23 | -------------------------------------------------------------------------------- /src/components/Text/Text.driver.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFactory } from 'wix-ui-test-utils/driver-factory'; 2 | import { textDriverFactory as coreTextDriverFactory, TextDriver as CoreTextDriver } from '../core/CoreText/Text.driver'; 3 | import { StylableDOMUtil } from '@stylable/dom-test-kit'; 4 | import style from './Text.st.css'; 5 | import { Skin, Size } from './constants'; 6 | 7 | export interface TextDriver extends CoreTextDriver { 8 | getSize: () => Size, 9 | getSkin: () => Skin, 10 | isLight: () => boolean, 11 | isBold: () => boolean, 12 | isSecondary: () => boolean 13 | } 14 | 15 | export const textDriverFactory = ({ element, eventTrigger, wrapper }: ComponentFactory): TextDriver => { 16 | const coreTextDriver = coreTextDriverFactory({ element, eventTrigger, wrapper }); 17 | const stylableDOMUtil = new StylableDOMUtil(style); 18 | 19 | return { 20 | ...coreTextDriver, 21 | getSize: () => stylableDOMUtil.getStyleState(element, 'size'), 22 | getSkin: () => stylableDOMUtil.getStyleState(element, 'skin'), 23 | isLight: () => stylableDOMUtil.hasStyleState(element, 'light'), 24 | isBold: () => stylableDOMUtil.hasStyleState(element, 'bold'), 25 | isSecondary: () => stylableDOMUtil.hasStyleState(element, 'secondary') 26 | }; 27 | }; 28 | -------------------------------------------------------------------------------- /src/components/Text/Text.e2e.ts: -------------------------------------------------------------------------------- 1 | import * as eyes from 'eyes.it'; 2 | import {browser} from 'protractor'; 3 | import {getStoryUrl, waitForVisibilityOf} from 'wix-ui-test-utils/protractor'; 4 | import {textTestkitFactory} from '../../testkit/protractor'; 5 | 6 | describe('Text', () => { 7 | const storyUrl = getStoryUrl('Components', 'Text'); 8 | 9 | beforeEach(() => browser.get(storyUrl)); 10 | eyes.it('should display correct content', () => { 11 | const dataHook = 'storybook-text'; 12 | const driver = textTestkitFactory({dataHook}); 13 | 14 | return waitForVisibilityOf(driver.element(), 'Cannot find Heading') 15 | .then(() => expect(driver.getText()).toBe('Some text')); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /src/components/Text/Text.protractor.driver.ts: -------------------------------------------------------------------------------- 1 | export {textDriverFactory, TextDriver} from '../core/CoreText/Text.protractor.driver'; 2 | -------------------------------------------------------------------------------- /src/components/Text/Text.st.css: -------------------------------------------------------------------------------- 1 | :import { 2 | -st-from: "../core/CoreText/Text.st.css"; 3 | -st-default: Text; 4 | } 5 | 6 | :import { 7 | -st-from: "../../colors.st.css"; 8 | -st-named: 9 | D10, D20, D50, 10 | G10,P10, 11 | R10, 12 | WHITE, 13 | } 14 | 15 | :import { 16 | -st-from: "../../typography.st.css"; 17 | -st-named: fontLight, fontRoman; 18 | } 19 | 20 | .root { 21 | -st-extends: Text; 22 | -st-states: 23 | size(enum(small, medium)), 24 | secondary, 25 | skin(enum(standard, success, error, premium)), 26 | light, 27 | bold; 28 | 29 | font-family: value(fontLight); 30 | } 31 | 32 | .root:not(:ellipsis) { 33 | white-space: pre-line; 34 | } 35 | 36 | .root:size(medium), .root:size(medium):secondary { 37 | font-size: 16px; 38 | line-height: 24px; 39 | } 40 | 41 | .root:size(small), .root:size(small):secondary { 42 | font-size: 14px; 43 | line-height: 18px; 44 | } 45 | 46 | .root:size(medium), .root:size(small) { 47 | color: value(D10); 48 | } 49 | 50 | .root:size(medium):light, .root:size(small):light { 51 | color: value(WHITE); 52 | } 53 | 54 | .root:size(medium):secondary, .root:size(small):secondary { 55 | color: value(D20); 56 | } 57 | 58 | .root:size(medium):secondary:light, .root:size(small):secondary:light { 59 | color: value(D50); 60 | } 61 | 62 | .root:skin(success), 63 | .root:skin(success):light, 64 | .root:skin(success):secondary { 65 | color: value(G10); 66 | } 67 | 68 | .root:skin(error), 69 | .root:skin(error):light, 70 | .root:skin(error):secondary { 71 | color: value(R10); 72 | } 73 | 74 | .root:skin(premium), 75 | .root:skin(premium):light, 76 | .root:skin(premium):secondary { 77 | color: value(P10); 78 | } 79 | 80 | .root:bold { 81 | font-family: value(fontRoman); 82 | } -------------------------------------------------------------------------------- /src/components/Text/Text.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import {Text as CoreText, TextProps as CoreTextProps} from '../core/CoreText'; 3 | import {withStylable} from 'wix-ui-core/dist/src/utils/withStylable'; 4 | import {Skin, Size} from './constants'; 5 | import style from './Text.st.css'; 6 | 7 | export interface Props { 8 | /** font size of the text */ 9 | size?: Size; 10 | 11 | /** is the text type is secondary. Affects the font color */ 12 | secondary?: boolean; 13 | 14 | /** skin color of the text */ 15 | skin?: Skin; 16 | 17 | /** is the text has dark or light skin */ 18 | light?: boolean; 19 | 20 | /** is the text bold */ 21 | bold?: boolean; 22 | } 23 | 24 | const defaultProps: Props = { 25 | size: Size.medium, 26 | secondary: false, 27 | skin: Skin.standard, 28 | light: false, 29 | bold: false 30 | }; 31 | 32 | export const Text = withStylable( 33 | CoreText, 34 | style, 35 | ({size, secondary, skin, light, bold}) => ({ 36 | size, 37 | secondary, 38 | skin, 39 | light: light && skin === Skin.standard, 40 | bold 41 | }), 42 | defaultProps 43 | ); 44 | 45 | Text.displayName = 'Text'; 46 | -------------------------------------------------------------------------------- /src/components/Text/constants.ts: -------------------------------------------------------------------------------- 1 | export enum Skin { 2 | standard = 'standard', 3 | error = 'error', 4 | success = 'success', 5 | premium = 'premium' 6 | } 7 | 8 | export enum Size { 9 | small = 'small', 10 | medium = 'medium' 11 | } 12 | -------------------------------------------------------------------------------- /src/components/Text/index.ts: -------------------------------------------------------------------------------- 1 | import { Text as TextComponent , Props } from './Text'; 2 | import { createHOC } from 'wix-ui-core/dist/src/createHOC'; 3 | 4 | export const Text = createHOC(TextComponent); 5 | export { Props as TextProps } 6 | export { Skin as TextSkin, Size as TextSize } from './constants'; -------------------------------------------------------------------------------- /src/components/Thumbnail/Thumbnail.driver.ts: -------------------------------------------------------------------------------- 1 | import {ComponentFactory} from 'wix-ui-test-utils/driver-factory'; 2 | import {thumbnailDriverFactory as coreTuhmbnailDriverFactory, ThumbnailDriver as CoreThumbnailDriver} from 'wix-ui-core/drivers/vanilla'; 3 | import {StylableDOMUtil} from '@stylable/dom-test-kit'; 4 | import style from './Thumbnail.st.css'; 5 | import {textDriverFactory, TextDriver} from '../Text/Text.driver'; 6 | import {DriverFactory} from 'wix-ui-test-utils/driver-factory'; 7 | 8 | export interface ThumbnailDriver extends CoreThumbnailDriver { 9 | titleDriver: () => TextDriver; 10 | getTitle: () => string; 11 | hasDescription: () => boolean; 12 | getDescription: () => string; 13 | hasImage: () => boolean; 14 | getImage: () => HTMLElement; 15 | } 16 | 17 | export const thumbnailDriverFactory = ({ element, eventTrigger, wrapper }: ComponentFactory): ThumbnailDriver => { 18 | const coreThumbnailDriver = coreTuhmbnailDriverFactory({element, eventTrigger, wrapper}); 19 | const stylableDOMUtil = new StylableDOMUtil(style, element); 20 | const titleDriver = textDriverFactory({element: stylableDOMUtil.select('.title'), wrapper, eventTrigger}); 21 | const descriptionDriver = textDriverFactory({element: stylableDOMUtil.select('.description'), wrapper, eventTrigger}); 22 | const image = element.querySelector('[data-hook="image"]'); 23 | 24 | return { 25 | ...coreThumbnailDriver, 26 | titleDriver: () => titleDriver, 27 | /** returns the title of the thumbnail */ 28 | getTitle: () => titleDriver.getText(), 29 | /** returns true if the thumbnail has description */ 30 | hasDescription: () => descriptionDriver.exists(), 31 | /** returns the description of the thumbnail */ 32 | getDescription: () => descriptionDriver.getText(), 33 | /** returns the image of the thumbnail */ 34 | getImage: () => image && image.childNodes[0] as HTMLElement, 35 | /** returns true if the thumbnail has an image */ 36 | hasImage: () => !!image 37 | }; 38 | }; 39 | -------------------------------------------------------------------------------- /src/components/Thumbnail/Thumbnail.e2e.ts: -------------------------------------------------------------------------------- 1 | import * as eyes from 'eyes.it'; 2 | import {browser} from 'protractor'; 3 | import {getStoryUrl, waitForVisibilityOf} from 'wix-ui-test-utils/protractor'; 4 | import {thumbnailTestkitFactory} from '../../testkit/protractor'; 5 | 6 | describe('Thumbnail', () => { 7 | const storyUrl = getStoryUrl('Components', 'Thumbnail'); 8 | 9 | beforeEach(() => browser.get(storyUrl)); 10 | eyes.it('should exist', () => { 11 | const dataHook = 'storybook-thumbnail'; 12 | const driver = thumbnailTestkitFactory({dataHook}); 13 | 14 | return waitForVisibilityOf(driver.element(), 'Cannot find Thumbnail') 15 | .then(() => expect(driver.element().isPresent()).toBe(true)); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /src/components/Thumbnail/Thumbnail.protractor.driver.ts: -------------------------------------------------------------------------------- 1 | export {thumbnailDriverFactory, ThumbnailDriver} from 'wix-ui-core/drivers/protractor'; 2 | -------------------------------------------------------------------------------- /src/components/Thumbnail/Thumbnail.st.css: -------------------------------------------------------------------------------- 1 | :import { 2 | -st-from: "wix-ui-core/index.st.css"; 3 | -st-named: Thumbnail; 4 | } 5 | 6 | :import { 7 | -st-from: "../../typography.st.css"; 8 | -st-named: fontRoman; 9 | } 10 | 11 | :import { 12 | -st-from: "../../colors.st.css"; 13 | -st-named: 14 | B10, B20, B50, 15 | D55, 16 | WHITE; 17 | } 18 | 19 | .root { 20 | -st-extends: Thumbnail; 21 | margin: 19px 0; 22 | border: 1px solid value(B50); 23 | border-radius: 8px; 24 | cursor: pointer; 25 | } 26 | 27 | .root:selected { 28 | border: 2px solid value(B10); 29 | } 30 | 31 | .root:selected:hover { 32 | border: 2px solid value(B20); 33 | } 34 | 35 | .root:selected:disabled { 36 | border: 2px solid value(D55); 37 | } 38 | 39 | .root:disabled { 40 | border: 1px solid value(D55); 41 | cursor: default; 42 | } 43 | 44 | .container { 45 | display: flex; 46 | flex-direction: column; 47 | align-items: center; 48 | } 49 | 50 | .root:selected::selectedIcon { 51 | background: value(B10); 52 | width: 24px; 53 | height: 24px; 54 | border-radius: 12px; 55 | display: flex; 56 | justify-content: center; 57 | align-items: center; 58 | color: value(WHITE); 59 | } 60 | 61 | .root:selected:hover:not(:disabled)::selectedIcon { 62 | background: value(B20); 63 | } 64 | 65 | .root:disabled::selectedIcon { 66 | background: value(D55); 67 | } 68 | 69 | .title {} 70 | 71 | .description {} 72 | 73 | .root:disabled .title, .root:disabled .description { 74 | color: value(D55); 75 | } 76 | -------------------------------------------------------------------------------- /src/components/Thumbnail/Thumbnail.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import style from './Thumbnail.st.css'; 3 | import Check from 'wix-ui-icons-common/Check'; 4 | import { 5 | Thumbnail as CoreThumbnail, 6 | ThumbnailProps as CoreThumbnailProps 7 | } from 'wix-ui-core/dist/src/components/thumbnail'; 8 | import { withStylable } from 'wix-ui-core/dist/src/utils/withStylable'; 9 | import { Text } from '../Text'; 10 | 11 | export interface ThumbnailProps extends CoreThumbnailProps { 12 | /** image of the thumbnail */ 13 | image?: React.ReactElement; 14 | /** title of the thumbnail */ 15 | title: string; 16 | /** description of the thumbnail */ 17 | description?: string; 18 | } 19 | 20 | const StyledThumbnail = withStylable( 21 | CoreThumbnail, 22 | style, 23 | () => ({}) 24 | ); 25 | 26 | export const Thumbnail: React.SFC = props => { 27 | const { children, title, image, description, ...rest } = props; 28 | 29 | return ( 30 | }> 31 |
32 | {image &&
{image}
} 33 | 34 | {title} 35 | 36 | {description && ( 37 | 38 | {description} 39 | 40 | )} 41 |
42 |
43 | ); 44 | }; 45 | 46 | Thumbnail.displayName = 'Thumbnail'; 47 | -------------------------------------------------------------------------------- /src/components/Thumbnail/index.ts: -------------------------------------------------------------------------------- 1 | export {Thumbnail, ThumbnailProps} from './Thumbnail'; 2 | -------------------------------------------------------------------------------- /src/components/TimePicker/TimePicker.driver.ts: -------------------------------------------------------------------------------- 1 | import { 2 | timePickerDriverFactory as coreTimePickerDriverFactory 3 | } from 'wix-ui-core/drivers/vanilla'; 4 | 5 | export const timePickerDriverFactory = ({element, eventTrigger}) => { 6 | const coreTimePickerDriver = coreTimePickerDriverFactory({element, eventTrigger}); 7 | 8 | return { 9 | ...coreTimePickerDriver, 10 | getValue: () => coreTimePickerDriver.getValue().slice(0, 5), 11 | isAmPmIndicatorExist: () => { 12 | const value = coreTimePickerDriver.getValue().toLowerCase(); 13 | return value.includes('am') || value.includes('pm'); 14 | }, 15 | getAmPmIndicatorText: () => coreTimePickerDriver.getValue().toLowerCase().slice(6, 8) 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /src/components/TimePicker/TimePicker.protractor.driver.ts: -------------------------------------------------------------------------------- 1 | export {timePickerDriverFactory, TimePickerDriver} from 'wix-ui-core/drivers/protractor'; 2 | -------------------------------------------------------------------------------- /src/components/TimePicker/TimePicker.st.css: -------------------------------------------------------------------------------- 1 | :import { 2 | -st-from: "wix-ui-core/index.st.css"; 3 | -st-named: TimePicker; 4 | } 5 | 6 | :import { 7 | -st-from: "../Input/Input.st.css"; 8 | -st-default: Input; 9 | } 10 | 11 | :import { 12 | -st-from: "../Input/InputStates.st.css"; 13 | -st-named: input-large, input-medium, input-small; 14 | } 15 | 16 | :import { 17 | -st-from: "../../colors.st.css"; 18 | -st-named: 19 | B30, B10, D55; 20 | } 21 | 22 | .root { 23 | -st-extends: TimePicker; 24 | -st-mixin: Input; 25 | -st-states: disabled, size(enum(large, medium, small)), 26 | inputWidth(enum(small, medium, large, small_ampm, medium_ampm, large_ampm)); 27 | 28 | display: inline-flex; 29 | width: auto; 30 | } 31 | 32 | .root:size(large) { 33 | -st-mixin: input-large; 34 | } 35 | 36 | .root:size(medium) { 37 | -st-mixin: input-medium; 38 | } 39 | 40 | .root:size(small) { 41 | -st-mixin: input-small; 42 | } 43 | 44 | .root::nativeInput::selection { 45 | background: value(B30); 46 | } 47 | 48 | .root:inputWidth(small)::nativeInput { 49 | width: 47px; 50 | } 51 | 52 | .root:inputWidth(medium)::nativeInput { 53 | width: 53px; 54 | } 55 | 56 | .root:inputWidth(large)::nativeInput { 57 | width: 67px; 58 | } 59 | 60 | .root:inputWidth(small_ampm)::nativeInput { 61 | width: 72px; 62 | } 63 | 64 | .root:inputWidth(medium_ampm)::nativeInput { 65 | width: 80px; 66 | } 67 | 68 | .root:inputWidth(large_ampm)::nativeInput { 69 | width: 107px; 70 | } 71 | 72 | .root::tickers { 73 | padding: 0 6px 0 12px; 74 | } 75 | 76 | .root::tickers::ticker { 77 | padding: 5px 0; 78 | color: value(B10); 79 | cursor: pointer; 80 | } 81 | 82 | .root::tickers::ticker > svg { 83 | display: block; 84 | width: 10px; 85 | height: 5px; 86 | } 87 | 88 | .root:disabled::tickers::ticker { 89 | cursor: default; 90 | color: value(D55); 91 | } 92 | -------------------------------------------------------------------------------- /src/components/TimePicker/constants.ts: -------------------------------------------------------------------------------- 1 | export enum Size { 2 | large = 'large', 3 | medium = 'medium', 4 | small = 'small', 5 | } 6 | -------------------------------------------------------------------------------- /src/components/TimePicker/index.ts: -------------------------------------------------------------------------------- 1 | import {TimePicker as TimePickerComponent} from './TimePicker'; 2 | import {createHOC} from 'wix-ui-core/dist/src/createHOC'; 3 | 4 | export const TimePicker = createHOC(TimePickerComponent); 5 | -------------------------------------------------------------------------------- /src/components/ToggleSwitch/ToggleSwitch.driver.ts: -------------------------------------------------------------------------------- 1 | import {toggleSwitchDriverFactory as coreToggleSwitchDriverFactory} from 'wix-ui-core/drivers/vanilla'; 2 | import {StylableDOMUtil} from '@stylable/dom-test-kit'; 3 | import style from './ToggleSwitch.st.css'; 4 | 5 | export const toggleSwitchDriverFactory = ({element, eventTrigger}) => { 6 | const coreToggleSwitchDriver = coreToggleSwitchDriverFactory({element, eventTrigger}); 7 | const stylableDOMUtil = new StylableDOMUtil(style, element); 8 | 9 | return { 10 | ...coreToggleSwitchDriver, 11 | getSize: () => stylableDOMUtil.getStyleState(element, 'size'), 12 | getSkin: () => stylableDOMUtil.getStyleState(element, 'skin') 13 | }; 14 | }; 15 | -------------------------------------------------------------------------------- /src/components/ToggleSwitch/ToggleSwitch.e2e.ts: -------------------------------------------------------------------------------- 1 | import * as eyes from 'eyes.it'; 2 | import {browser} from 'protractor'; 3 | import {getStoryUrl, waitForVisibilityOf} from 'wix-ui-test-utils/protractor'; 4 | import {toggleSwitchTestkitFactory} from '../../testkit/protractor'; 5 | import {protractor} from 'protractor'; 6 | 7 | describe('ToggleSwitch', () => { 8 | const storyUrl = getStoryUrl('Components', 'ToggleSwitch'); 9 | const dataHook = 'storybook-toggleSwitch'; 10 | 11 | beforeEach(() => browser.get(storyUrl)); 12 | 13 | eyes.it('should toggle', () => { 14 | const driver = toggleSwitchTestkitFactory({dataHook}); 15 | 16 | return waitForVisibilityOf(driver.element(), 'Cannot find ToggleSwitch') 17 | .then(() => { 18 | expect(driver.checked()).toBeFalsy(); 19 | 20 | driver.click(); 21 | expect(driver.checked()).toBeTruthy(); 22 | 23 | driver.click(); 24 | expect(driver.checked()).toBeFalsy(); 25 | }); 26 | }); 27 | 28 | eyes.it('should support accessiblility features', () => { 29 | const driver = toggleSwitchTestkitFactory({dataHook}); 30 | 31 | return waitForVisibilityOf(driver.element(), 'Cannot find ToggleSwitch') 32 | .then(() => { 33 | browser 34 | .actions() 35 | .mouseMove(driver.element()) 36 | .mouseMove({x: 0, y: -20}) 37 | .mouseDown() 38 | .mouseUp() 39 | .sendKeys(protractor.Key.TAB) 40 | .sendKeys(protractor.Key.SPACE) 41 | .perform(); 42 | 43 | expect(driver.checked()).toBe(true); 44 | 45 | browser.actions().sendKeys(protractor.Key.SPACE).perform(); 46 | expect(driver.checked()).toBe(false); 47 | }); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /src/components/ToggleSwitch/ToggleSwitch.protractor.driver.ts: -------------------------------------------------------------------------------- 1 | export {toggleSwitchDriverFactory, ToggleSwitchDriver} from 'wix-ui-core/drivers/protractor'; 2 | -------------------------------------------------------------------------------- /src/components/ToggleSwitch/ToggleSwitch.st.css: -------------------------------------------------------------------------------- 1 | :import { 2 | -st-from: "wix-ui-core/index.st.css"; 3 | -st-named: ToggleSwitch; 4 | } 5 | 6 | :import { 7 | -st-from: "wix-ui-core/index.st.css"; 8 | -st-named: ToggleSwitchStyle; 9 | } 10 | 11 | :import { 12 | -st-from: "wix-ui-core/index.st.css"; 13 | -st-named: ToggleSwitchLayout; 14 | } 15 | 16 | :import { 17 | -st-from: "wix-ui-core/index.st.css"; 18 | -st-named: ToggleSwitchColor; 19 | } 20 | 21 | :import { 22 | -st-from: "../../colors.st.css"; 23 | -st-named: 24 | B10, B20, B30, B40, B50, 25 | D50, 26 | F00, 27 | G10, G20, G30, G40, 28 | R10, R20, R30, R40, 29 | WHITE; 30 | } 31 | 32 | :import { 33 | -st-from: "../../shadows.st.css"; 34 | -st-named: shadow10; 35 | } 36 | 37 | .root { 38 | -st-extends: ToggleSwitch; 39 | -st-states: 40 | size(enum(small, medium, large)), 41 | skin(enum(standard, success, error)); 42 | 43 | -st-mixin: ToggleSwitchStyle; 44 | } 45 | 46 | .root:size(small) { 47 | -st-mixin: ToggleSwitchLayout( 48 | rootWidth 30px, 49 | rootHeight 16px, 50 | knobWidth 14px, 51 | knobHeight 14px 52 | ); 53 | } 54 | 55 | .root:size(medium) { 56 | -st-mixin: ToggleSwitchLayout( 57 | rootWidth 36px, 58 | rootHeight 20px, 59 | knobWidth 18px, 60 | knobHeight 18px 61 | ); 62 | } 63 | 64 | .root:size(large) { 65 | -st-mixin: ToggleSwitchLayout( 66 | rootWidth 48px, 67 | rootHeight 24px, 68 | knobWidth 22px, 69 | knobHeight 22px 70 | ); 71 | } 72 | 73 | .root:skin(standard) { 74 | -st-mixin: ToggleSwitchColor( 75 | colorUnchecked value(B40), 76 | colorChecked value(B10), 77 | colorUncheckedHover value(B30), 78 | colorCheckedHover value(B20), 79 | colorDisabled value(D50) 80 | ); 81 | } 82 | 83 | .root:skin(success) { 84 | -st-mixin: ToggleSwitchColor( 85 | colorUnchecked value(G40), 86 | colorChecked value(G10), 87 | colorUncheckedHover value(G30), 88 | colorCheckedHover value(G20), 89 | colorDisabled value(D50) 90 | ); 91 | } 92 | 93 | .root:skin(error) { 94 | -st-mixin: ToggleSwitchColor( 95 | colorUnchecked value(R40), 96 | colorChecked value(R10), 97 | colorUncheckedHover value(R30), 98 | colorCheckedHover value(R20), 99 | colorDisabled value(D50) 100 | ); 101 | } 102 | 103 | .root:focus-visible::track { 104 | box-shadow: 0 0 0 3px value(F00); 105 | } 106 | 107 | .root::knob { 108 | box-shadow: value(shadow10); 109 | } 110 | -------------------------------------------------------------------------------- /src/components/ToggleSwitch/ToggleSwitch.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { 3 | ToggleSwitch as CoreToggleSwitch, 4 | ToggleSwitchProps as CoreToggleSwitchProps 5 | } from 'wix-ui-core/dist/src/components/toggle-switch'; 6 | import style from './ToggleSwitch.st.css'; 7 | import { Skin, Size, SKINS, SIZES } from './constants'; 8 | import { 9 | ToggleOff, 10 | ToggleOn, 11 | ToggleOffSmall, 12 | ToggleOnSmall 13 | } from 'wix-ui-icons-common/system'; 14 | import { withStylable } from 'wix-ui-core/dist/src/utils/withStylable'; 15 | 16 | export interface ToggleSwitchProps { 17 | skin?: Skin; 18 | size?: Size; 19 | } 20 | 21 | const defaultProps = { 22 | skin: SKINS.standard, 23 | size: SIZES.large 24 | }; 25 | 26 | const checkedIconMap = { 27 | [SIZES.small]: undefined, 28 | [SIZES.medium]: , 29 | [SIZES.large]: 30 | }; 31 | 32 | const uncheckedIconMap = { 33 | [SIZES.small]: undefined, 34 | [SIZES.medium]: , 35 | [SIZES.large]: 36 | }; 37 | 38 | const StyledToggleSwitch = withStylable< 39 | CoreToggleSwitchProps, 40 | ToggleSwitchProps 41 | >(CoreToggleSwitch, style, ({ size, skin }) => ({ size, skin }), defaultProps); 42 | 43 | export class ToggleSwitch extends React.PureComponent< 44 | ToggleSwitchProps & CoreToggleSwitchProps 45 | > { 46 | static displayName = 'ToggleSwitch'; 47 | 48 | static defaultProps = defaultProps; 49 | 50 | render() { 51 | const { styles, ...desiredProps } = this.props; 52 | 53 | return ( 54 | 59 | ); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/components/ToggleSwitch/constants.ts: -------------------------------------------------------------------------------- 1 | export type Skin = 'standard' | 'success' | 'error'; 2 | 3 | export type Size = 'small' | 'medium' | 'large'; 4 | 5 | export enum SKINS { 6 | standard = 'standard', 7 | success = 'success', 8 | error = 'error' 9 | } 10 | 11 | export enum SIZES { 12 | small = 'small', 13 | medium = 'medium', 14 | large = 'large' 15 | } 16 | -------------------------------------------------------------------------------- /src/components/ToggleSwitch/index.ts: -------------------------------------------------------------------------------- 1 | import {ToggleSwitch as ToggleSwitchComponent} from './ToggleSwitch'; 2 | import {createHOC} from 'wix-ui-core/dist/src/createHOC'; 3 | 4 | export const ToggleSwitch = createHOC(ToggleSwitchComponent); 5 | -------------------------------------------------------------------------------- /src/components/Tooltip/Tooltip.driver.ts: -------------------------------------------------------------------------------- 1 | export {tooltipDriverFactory} from 'wix-ui-core/drivers/vanilla'; 2 | -------------------------------------------------------------------------------- /src/components/Tooltip/Tooltip.spec.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { tooltipDriverFactory } from './Tooltip.driver'; 3 | import { Tooltip } from './'; 4 | import { createDriverFactory } from 'wix-ui-test-utils/driver-factory'; 5 | 6 | describe('Tooltip', () => { 7 | const createDriver = createDriverFactory(tooltipDriverFactory); 8 | 9 | it('renders BO tooltip', () => { 10 | const tooltip = createDriver(); 11 | expect(tooltip.exists()).toBeTruthy(); 12 | }); 13 | 14 | it('closing when hovered out', () => { 15 | const tooltip = createDriver(); 16 | expect(tooltip.isContentElementExists()).toBeFalsy(); 17 | 18 | tooltip.mouseEnter(); 19 | expect(tooltip.isContentElementExists()).toBeTruthy(); 20 | 21 | tooltip.mouseLeave(); 22 | expect(tooltip.isContentElementExists()).toBeFalsy(); 23 | }); 24 | 25 | it('remains open when hovered out if relevant property is provided', () => { 26 | const tooltip = createDriver(); 27 | expect(tooltip.isContentElementExists()).toBeFalsy(); 28 | 29 | tooltip.mouseEnter(); 30 | expect(tooltip.isContentElementExists()).toBeTruthy(); 31 | 32 | tooltip.mouseLeave(); 33 | expect(tooltip.isContentElementExists()).toBeTruthy(); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /src/components/Tooltip/Tooltip.st.css: -------------------------------------------------------------------------------- 1 | :import { 2 | -st-from: "wix-ui-core/index.st.css"; 3 | -st-named: Tooltip; 4 | } 5 | 6 | :import { 7 | -st-from: "../../colors.st.css"; 8 | -st-named: 9 | D10, 10 | WHITE; 11 | } 12 | 13 | :import { 14 | -st-from: "../../typography.st.css"; 15 | -st-named: fontRoman; 16 | } 17 | 18 | :import { 19 | -st-from: "../../shadows.st.css"; 20 | -st-named: shadow30; 21 | } 22 | 23 | .root { 24 | -st-states: bounce, placement-right, placement-left, placement-top, placement-bottom; 25 | -st-extends: Tooltip; 26 | } 27 | 28 | .root::popoverContent { 29 | border: none; 30 | 31 | font-family: value(fontRoman); 32 | border-radius: 8px; 33 | padding: 12px 24px; 34 | box-sizing: border-box; 35 | font-size: 14px; 36 | line-height: 1.29; 37 | box-shadow: value(shadow30); 38 | word-wrap: break-word; 39 | -webkit-font-smoothing: antialiased; 40 | 41 | color: value(WHITE); 42 | background: value(D10); 43 | font-size: 14px; 44 | line-height: 18px; 45 | text-align: center; 46 | max-width: 230px; 47 | } 48 | 49 | .root:bounce::popover { 50 | animation-duration: 1.15s; 51 | animation-iteration-count: infinite; 52 | } 53 | 54 | .root:bounce:placement-right::popover { 55 | animation-name: right-bounce; 56 | } 57 | 58 | .root:bounce:placement-left::popover { 59 | animation-name: left-bounce; 60 | } 61 | 62 | .root:bounce:placement-top::popover { 63 | animation-name: top-bounce; 64 | } 65 | 66 | .root:bounce:placement-bottom::popover { 67 | animation-name: bottom-bounce; 68 | } 69 | 70 | @keyframes right-bounce { 71 | 0%, 100% { left: 5px; } 72 | 50% { left: -5px; } 73 | } 74 | 75 | @keyframes left-bounce { 76 | 0%, 100% { left: -5px; } 77 | 50% { left: 5px; } 78 | } 79 | 80 | @keyframes top-bounce { 81 | 0%, 100% { top: -5px; } 82 | 50% { top: 5px; } 83 | } 84 | 85 | @keyframes bottom-bounce { 86 | 0%, 100% { top: 5px; } 87 | 50% { top: -5px; } 88 | } 89 | -------------------------------------------------------------------------------- /src/components/Tooltip/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Tooltip'; 2 | -------------------------------------------------------------------------------- /src/components/VBox/VBox.driver.ts: -------------------------------------------------------------------------------- 1 | export const vBoxDriverFactory = ({element}) => { 2 | return { 3 | /** check if element exists */ 4 | exists: () => !!element, 5 | /** get the rendered content */ 6 | getChildren: () => element.innerHTML 7 | }; 8 | }; 9 | -------------------------------------------------------------------------------- /src/components/VBox/VBox.e2e.ts: -------------------------------------------------------------------------------- 1 | import * as eyes from 'eyes.it'; 2 | import {browser} from 'protractor'; 3 | import {getStoryUrl, waitForVisibilityOf} from 'wix-ui-test-utils/protractor'; 4 | import {vBoxTestkitFactory} from '../../testkit/protractor'; 5 | 6 | describe('VBox', () => { 7 | const storyUrl = getStoryUrl('Components', 'VBox'); 8 | 9 | beforeEach(() => browser.get(storyUrl)); 10 | eyes.it('should display correct content', () => { 11 | const dataHook = 'storybook-vbox'; 12 | const driver = vBoxTestkitFactory({dataHook}); 13 | 14 | return waitForVisibilityOf(driver.element(), 'Cannot find VBox'); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/components/VBox/VBox.protractor.driver.ts: -------------------------------------------------------------------------------- 1 | export const vBoxDriverFactory = component => ({ 2 | /** returns the component element */ 3 | element: () => component 4 | }); 5 | -------------------------------------------------------------------------------- /src/components/VBox/VBox.spec.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import {mount} from 'enzyme'; 3 | import {VBox} from './'; 4 | 5 | describe('VBox', () => { 6 | let wrapper; 7 | 8 | afterEach(() => wrapper.detach()); 9 | 10 | it('should render the passed children', () => { 11 | wrapper = mount(
1
, {attachTo: document.createElement('div')}); 12 | expect(wrapper.html()).toContain('
1
'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /src/components/VBox/VBox.st.css: -------------------------------------------------------------------------------- 1 | .root { 2 | -st-states: horizontalAlignment(enum(left, center, right)); 3 | display: flex; 4 | flex-direction: column; 5 | width: 100%; 6 | height: 100%; 7 | } 8 | 9 | .root:horizontalAlignment(left) { 10 | align-items: flex-start; 11 | } 12 | 13 | .root:horizontalAlignment(center) { 14 | align-items: center; 15 | } 16 | 17 | .root:horizontalAlignment(right) { 18 | align-items: flex-end; 19 | } 20 | -------------------------------------------------------------------------------- /src/components/VBox/VBox.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import style from './VBox.st.css'; 3 | import {addSpacing} from './utils'; 4 | 5 | export interface VBoxProps { 6 | children?: React.ReactNode; 7 | horizontalAlignment?: Alignment; 8 | spacing?: number; 9 | } 10 | 11 | export type Alignment = 'left' | 'center' | 'right'; 12 | 13 | const defaultProps: VBoxProps = { 14 | children: null, 15 | horizontalAlignment: 'left', 16 | spacing: 0 17 | }; 18 | 19 | /** 20 | * VBox 21 | */ 22 | export const VBox: React.SFC = props => { 23 | const {children, horizontalAlignment, spacing} = props; 24 | return
{addSpacing(children, spacing)}
; 25 | }; 26 | 27 | VBox.displayName = 'VBox'; 28 | VBox.defaultProps = defaultProps; 29 | -------------------------------------------------------------------------------- /src/components/VBox/index.ts: -------------------------------------------------------------------------------- 1 | export {VBox, VBoxProps} from './VBox'; 2 | -------------------------------------------------------------------------------- /src/components/VBox/utils.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | export function addSpacing (children, spacing: number) { 4 | if (!children || !spacing) { 5 | return children; 6 | } 7 | 8 | const spacedChildren = []; 9 | 10 | for (let i = 0; i < children.length - 1; i++) { 11 | spacedChildren.push( 12 | React.cloneElement(children[i], {style: {marginBottom: spacing}}) 13 | ); 14 | } 15 | 16 | spacedChildren.push(children[children.length - 1]); 17 | 18 | return spacedChildren; 19 | } 20 | -------------------------------------------------------------------------------- /src/components/core/CoreText/Text.driver.ts: -------------------------------------------------------------------------------- 1 | import {StylableDOMUtil} from '@stylable/dom-test-kit'; 2 | import style from './Text.st.css'; 3 | import {BaseDriver, DriverFactory} from 'wix-ui-test-utils/driver-factory'; 4 | 5 | export interface TextDriver extends BaseDriver { 6 | hasEllipsis: () => boolean; 7 | hasTitleAttribute: () => boolean; 8 | getTitle: () => string; 9 | getTagName: () => string; 10 | getText: () => string; 11 | } 12 | 13 | export const textDriverFactory: DriverFactory = ({element}) => { 14 | const stylableDOMUtil = new StylableDOMUtil(style); 15 | 16 | return { 17 | /** check if element exists */ 18 | exists: () => !!element, 19 | /** check if component has ellipsis */ 20 | hasEllipsis: () => stylableDOMUtil.hasStyleState(element, 'ellipsis'), 21 | /** check if element has title attribute */ 22 | hasTitleAttribute: () => element.getAttribute('title') !== null, 23 | /** check if element has title attribute */ 24 | getTitle: () => (element as HTMLElement).title, 25 | /** get the rendered tag name */ 26 | getTagName: () => element.tagName.toLowerCase(), 27 | /** get the rendered content */ 28 | getText: () => element.innerHTML 29 | }; 30 | }; 31 | -------------------------------------------------------------------------------- /src/components/core/CoreText/Text.protractor.driver.ts: -------------------------------------------------------------------------------- 1 | import {ElementFinder} from 'protractor'; 2 | 3 | export interface TextDriver { 4 | element: () => ElementFinder; 5 | getText: () => Promise; 6 | } 7 | 8 | export const textDriverFactory = component => ({ 9 | /** returns the component element */ 10 | element: () => component, 11 | /** returns the component text */ 12 | getText: async () => component.getText() 13 | }); 14 | -------------------------------------------------------------------------------- /src/components/core/CoreText/Text.st.css: -------------------------------------------------------------------------------- 1 | .root { 2 | -st-states: ellipsis; 3 | } 4 | 5 | /* ellipsis state */ 6 | .root:ellipsis { 7 | display: block; 8 | text-overflow: ellipsis; 9 | overflow: hidden; 10 | white-space: nowrap; 11 | width: 100%; 12 | } 13 | -------------------------------------------------------------------------------- /src/components/core/CoreText/Text.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import style from './Text.st.css'; 3 | 4 | export interface TextProps { 5 | children?: React.ReactNode; 6 | ellipsis?: boolean; 7 | forceHideTitle?: boolean; 8 | tagName?: string; 9 | className?: string; 10 | } 11 | /** 12 | * Text 13 | */ 14 | export const Text: React.SFC = props => { 15 | const {children, ellipsis, tagName, forceHideTitle} = props; 16 | return React.createElement( 17 | tagName, 18 | { 19 | title: typeof children === 'string' && ellipsis && !forceHideTitle ? children : null, 20 | ...style('root', {ellipsis}, props) 21 | }, 22 | children 23 | ); 24 | }; 25 | 26 | Text.displayName = 'Text'; 27 | Text.defaultProps = { 28 | tagName: 'span' 29 | }; 30 | -------------------------------------------------------------------------------- /src/components/core/CoreText/TextStyle.st.css: -------------------------------------------------------------------------------- 1 | :import { 2 | -st-from: "./Text.st.css"; 3 | -st-default: Text; 4 | } 5 | 6 | :vars { 7 | fontFamily: Arial; 8 | fontSize: 12px; 9 | lineHeight: normal; 10 | color: #000; 11 | textTransform: none; 12 | letterSpacing: normal; 13 | margin: 0; 14 | } 15 | 16 | .root { 17 | -st-extends: Text; 18 | font-family: value(fontFamily); 19 | font-size: value(fontSize); 20 | line-height: value(lineHeight); 21 | color: value(color); 22 | text-transform: value(textTransform); 23 | letter-spacing: value(letterSpacing); 24 | margin: value(margin); 25 | } 26 | -------------------------------------------------------------------------------- /src/components/core/CoreText/index.ts: -------------------------------------------------------------------------------- 1 | export {Text, TextProps} from './Text'; 2 | -------------------------------------------------------------------------------- /src/protractor.d.ts: -------------------------------------------------------------------------------- 1 | // This file is copy of 'wix-ui-core/node_modules/protractor/built/index.d.ts' 2 | // with fixes of protractor issue https://github.com/angular/protractor/issues/5348: 3 | // error TS2440: Import declaration conflicts with local declaration of 'PluginConfig'. 4 | // error TS2440: Import declaration conflicts with local declaration of 'ProtractorPlugin'. 5 | 6 | import { ElementHelper, ProtractorBrowser } from 'protractor/built/browser'; 7 | import { ElementArrayFinder, ElementFinder } from 'protractor/built/element'; 8 | import { ProtractorExpectedConditions } from 'protractor/built/expectedConditions'; 9 | import { ProtractorBy } from 'protractor/built/locators'; 10 | import { Ptor } from 'protractor/built/ptor'; 11 | export { PluginConfig, ProtractorPlugin } from 'protractor/built/plugins'; 12 | export { 13 | ActionSequence, 14 | Browser, 15 | Builder, 16 | Button, 17 | Capabilities, 18 | Capability, 19 | error, 20 | EventEmitter, 21 | FileDetector, 22 | Key, 23 | logging, 24 | promise, 25 | Session, 26 | until, 27 | WebDriver, 28 | WebElement, 29 | WebElementPromise, 30 | } from 'selenium-webdriver'; 31 | export { ElementHelper, ProtractorBrowser } from 'protractor/built/browser'; 32 | export { Config } from 'protractor/built/config'; 33 | export { ElementArrayFinder, ElementFinder } from 'protractor/built/element'; 34 | export { ProtractorExpectedConditions } from 'protractor/built/expectedConditions'; 35 | export { Locator, ProtractorBy } from 'protractor/built/locators'; 36 | export { Ptor } from 'protractor/built/ptor'; 37 | export { Runner } from 'protractor/built/runner'; 38 | export declare let utils: { 39 | firefox: any; 40 | http: any; 41 | remote: any; 42 | }; 43 | export declare let Command: any; 44 | export declare let CommandName: any; 45 | export declare let protractor: Ptor; 46 | export declare let browser: ProtractorBrowser; 47 | export declare let $: (search: string) => ElementFinder; 48 | export declare let $$: (search: string) => ElementArrayFinder; 49 | export declare let element: ElementHelper; 50 | export declare let By: ProtractorBy; 51 | export declare let by: ProtractorBy; 52 | export declare let ExpectedConditions: ProtractorExpectedConditions; 53 | -------------------------------------------------------------------------------- /src/shadows.st.css: -------------------------------------------------------------------------------- 1 | :vars { 2 | s1: rgba(22, 45, 61, 0.12); 3 | s2: rgba(22, 45, 61, 0.48); 4 | s3: rgba(22, 45, 61, 0.06); 5 | s4: rgba(22, 45, 61, 0.18); 6 | } 7 | 8 | :vars { 9 | shadow10: 0 2px 1px 0 value(s2), 0 0 3px 0 value(s1); 10 | shadow20: 0 2px 4px 0 value(s1), 0 0 6px 0 value(s1); 11 | shadow30: 0 6px 6px 0 value(s3), 0 0 18px 0 value(s1); 12 | shadow40: 0 8px 8px 0 value(s1), 0 3px 24px 0 value(s4); 13 | } 14 | -------------------------------------------------------------------------------- /src/types/common.ts: -------------------------------------------------------------------------------- 1 | // coppied from type zoo: https://github.com/Microsoft/TypeScript/issues/12215#issuecomment-377567046 2 | export type Omit = Pick>; 3 | -------------------------------------------------------------------------------- /src/typography.st.css: -------------------------------------------------------------------------------- 1 | :vars { 2 | fontsFallback: '"Helvetica Neue", "Helvetica", "Arial", "メイリオ", "meiryo", "ヒラギノ角ゴ pro w3", "hiragino kaku gothic pro", "sans-serif"' 3 | } 4 | 5 | :vars { 6 | fontUltraThin: '"HelveticaNeueW01-UltLt", "HelveticaNeueW02-UltLt", "HelveticaNeueW10-25UltL", value(fontsFallback)'; 7 | fontThin: '"HelveticaNeueW01-Thin", "HelveticaNeueW02-Thin", "HelveticaNeueW10-35Thin", value(fontsFallback)'; 8 | fontLight: '"HelveticaNeueW01-45Ligh", "HelveticaNeueW02-45Ligh", "HelveticaNeueW10-45Ligh", value(fontsFallback)'; 9 | fontRoman: '"HelveticaNeueW01-55Roma", "HelveticaNeueW02-55Roma", "HelveticaNeueW10-55Roma", value(fontsFallback)'; 10 | fontMedium: '"HelveticaNeueW01-65Medi", "HelveticaNeueW02-65Medi", "HelveticaNeueW10-65Medi", value(fontsFallback)'; 11 | fontBold: '"HelveticaNeueW01-75Bold", "HelveticaNeueW02-75Bold", "HelveticaNeueW10-75Bold", value(fontsFallback)'; 12 | } 13 | -------------------------------------------------------------------------------- /src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export const hexToRgba = (hex, opacity) => { 2 | const r = parseInt(hex.substring(1, 3), 16); 3 | const g = parseInt(hex.substring(3, 5), 16); 4 | const b = parseInt(hex.substring(5, 7), 16); 5 | return `rgba(${r}, ${g}, ${b}, ${opacity})`; 6 | }; 7 | 8 | export function enumValues(e: object) { 9 | return Object.keys(e).map(k => e[k as any]); 10 | } 11 | 12 | -------------------------------------------------------------------------------- /src/utils/utils.spec.ts: -------------------------------------------------------------------------------- 1 | import {hexToRgba, enumValues} from './'; 2 | 3 | describe('hexToRgba function', () => { 4 | it('should transform hex to Rgba', () => { 5 | const opacity = 0; 6 | expect(hexToRgba('#4af441', opacity)).toBe(`rgba(74, 244, 65, ${opacity})`); 7 | }); 8 | }); 9 | 10 | describe('enumValues function', () => { 11 | 12 | it('should list enum values', () => { 13 | enum Foo { 14 | AAA= 'aaa', 15 | BBB= 'bbb' 16 | } 17 | expect(enumValues(Foo)).toEqual(['aaa','bbb']); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /stories/AddressInput.story.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { AddressInput } from '../src/components/AddressInput'; 3 | import { Option } from 'wix-ui-core/dist/src/components/dropdown-option'; 4 | import { GoogleMapsClientStub } from 'wix-ui-core/dist/src/components/address-input/GoogleMapsClientStub'; 5 | import * as helper from 'wix-ui-core/dist/src/components/address-input/AddressInputTestHelper'; 6 | 7 | GoogleMapsClientStub.setAddresses([helper.ADDRESS_1, helper.ADDRESS_2]); 8 | GoogleMapsClientStub.setGeocode(helper.GEOCODE_1); 9 | 10 | export default { 11 | category: 'Components', 12 | storyName: 'AddressInput', 13 | component: AddressInput, 14 | componentPath: '../src/components/AddressInput/AddressInput.tsx', 15 | 16 | componentProps: { 17 | 'data-hook': 'storybook-address-input', 18 | fixedFooter: 'Fixed Footer', 19 | fixedHeader: 'Fixed Header', 20 | Client: GoogleMapsClientStub 21 | }, 22 | 23 | exampleProps: { 24 | onSelect: (option: Option) => option.value, 25 | onManualInput: (value: string) => `Manual input: ${value}`, 26 | onBlur: () => 'Triggered onBlur', 27 | onFocus: () => 'Triggered onFocus', 28 | onChange: evt => evt.target.value, 29 | size: ['small', 'medium', 'large'] 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /stories/Autocomplete.story.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Autocomplete } from '../src/components/Autocomplete'; 3 | import { generateDropdownOptions } from './helpers'; 4 | import { Option, DividerArgs } from 'wix-ui-core/dist/src/components/dropdown-option'; 5 | 6 | const options = generateDropdownOptions((args: Partial = {}) => 7 | Autocomplete.createDivider(args.value) 8 | ); 9 | 10 | const exampleOptions = [ 11 | { value: options, label: '20 example options' }, 12 | { value: options.slice(0, 1), label: '1 example option' }, 13 | { value: options.slice(0, 5), label: '5 example options' } 14 | ]; 15 | 16 | export default { 17 | category: 'Components', 18 | storyName: 'Autocomplete', 19 | component: Autocomplete, 20 | componentPath: '../src/components/Autocomplete/Autocomplete.tsx', 21 | 22 | componentProps: { 23 | 'data-hook': 'storybook-autocomplete', 24 | options: exampleOptions[2].value, 25 | fixedFooter: 'Fixed Footer', 26 | fixedHeader: 'Fixed Header' 27 | }, 28 | 29 | exampleProps: { 30 | onSelect: (option: Option) => option.value, 31 | onManualInput: (value: string) => `Manual input: ${value}`, 32 | onBlur: () => 'Triggered onBlur', 33 | onFocus: () => 'Triggered onFocus', 34 | onChange: evt => evt.target.value, 35 | size: ['small', 'medium', 'large'], 36 | 37 | options: exampleOptions, 38 | 39 | initialSelectedId: [ 40 | { value: [1], label: '[1]' }, 41 | { value: [1, 2, 3], label: '[1, 2, 3]' } 42 | ] 43 | } 44 | }; 45 | -------------------------------------------------------------------------------- /stories/Badge/ExampleBadgeOnClick.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import {Badge} from '../../src/components/Badge'; 3 | 4 | export default () => ( 5 | alert('Clicked!')}> 6 | I'm a badge! 7 | 8 | ); 9 | -------------------------------------------------------------------------------- /stories/Badge/ExampleBadges.scss: -------------------------------------------------------------------------------- 1 | .option { 2 | padding: 5px; 3 | } 4 | 5 | .wrapper { 6 | display: flex; 7 | align-items: center; 8 | padding: 5px; 9 | } 10 | -------------------------------------------------------------------------------- /stories/Badge/ExampleBadges.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import * as styles from './ExampleBadges.scss'; 3 | 4 | //import {Badge} from 'wix-ui-backoffice/Badge'; 5 | import {Badge} from '../../src/components/Badge'; 6 | 7 | //import {SIZE, SKIN, TYPE} from 'wix-ui-backoffice/Badge'; 8 | import {SIZE, SKIN, TYPE} from '../../src/components/Badge'; 9 | 10 | const skins = Object.keys(SKIN); 11 | const sizes = Object.keys(SIZE); 12 | const sizesString = sizes.join(', '); 13 | const types = Object.keys(TYPE); 14 | const typesString = types.join(', '); 15 | 16 | export default () => ( 17 |
18 | {skins.map(skin => ( 19 |
20 | skin: {skin} | sizes: {sizesString} | types: {typesString} | upppercase: true, false 21 |
22 | {renderSizes({skin})} 23 | {renderBadge({uppercase: false, skin})} 24 |
25 |
26 | ) 27 | )} 28 |
); 29 | 30 | const renderSizes = props => (sizes.map(size => renderTypes({size, ...props}))); 31 | const renderTypes = props => (types.map(type => renderBadge({type, ...props}))); 32 | 33 | const renderBadge = props => ( 34 | 35 | Some Badge 36 | ); 37 | 38 | 39 | -------------------------------------------------------------------------------- /stories/Badge/index.story.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import CodeExample from 'wix-storybook-utils/CodeExample'; 3 | 4 | import * as ExampleBadgeOnClickRaw from '!raw-loader!./ExampleBadgeOnClick'; 5 | import ExampleBadgeOnClick from './ExampleBadgeOnClick'; 6 | 7 | import * as ExampleBadgesRaw from '!raw-loader!./ExampleBadges'; 8 | import ExampleBadges from './ExampleBadges'; 9 | 10 | import {SIZE, SKIN, TYPE} from '../../src/components/Badge/constants'; 11 | 12 | import Facebook from 'wix-ui-icons-common/Facebook'; 13 | import ChevronDown from 'wix-ui-icons-common/ChevronDown'; 14 | import {Badge} from '../../src/components/Badge'; 15 | 16 | const icons = [ 17 | , 18 | 19 | ]; 20 | 21 | export default { 22 | category: 'Components', 23 | storyName: 'Badge', 24 | component: Badge, 25 | componentPath: '../../src/components/Badge/Badge.tsx', 26 | 27 | componentProps: { 28 | children: 'I\'m a badge!', 29 | skin: 'general', 30 | type: 'solid', 31 | size: 'medium', 32 | uppercase: true, 33 | dataHook: 'storybook-badge' 34 | }, 35 | 36 | exampleProps: { 37 | skin: Object.keys(SKIN), 38 | type: Object.keys(TYPE), 39 | size: Object.keys(SIZE), 40 | prefixIcon: icons, 41 | suffixIcon: icons 42 | }, 43 | 44 | examples: ( 45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 |
54 | ) 55 | }; 56 | -------------------------------------------------------------------------------- /stories/Button/index.story.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Button, ButtonProps, ButtonSkin as Skin, ButtonPriority as Priority, ButtonSize as Size } from '../../src/components/Button'; 3 | import { storySettings } from './storySettings'; 4 | import {enumValues} from '../../src/utils'; 5 | 6 | function PButton(props: ButtonProps) { 7 | return ( 8 |
9 | 12 |
13 | ); 14 | } 15 | 16 | export default { 17 | category: storySettings.kind, 18 | storyName: storySettings.story, 19 | component: Button, 20 | componentPath: '../../src/components/Button/Button.tsx', 21 | 22 | componentProps: setState => ({ 23 | 'data-hook': storySettings.dataHook, 24 | children: ['Click me!'], 25 | }), 26 | 27 | exampleProps: { 28 | skin: enumValues(Skin), 29 | priority: enumValues(Priority), 30 | size: enumValues(Size) 31 | }, 32 | 33 | examples: ( 34 |
35 |

Examples

36 |

Primary

37 | 38 | 39 | 40 | 41 |

Secondary

42 | 43 | 44 | 45 | 46 |
47 | ) 48 | }; 49 | -------------------------------------------------------------------------------- /stories/Button/storySettings.ts: -------------------------------------------------------------------------------- 1 | import { StorySettings } from '../storyTypes'; 2 | 3 | export const storySettings: StorySettings = { 4 | kind: 'Components', 5 | story: 'Button', 6 | dataHook: 'storybook-button' 7 | } -------------------------------------------------------------------------------- /stories/Checkbox.story.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import Star from 'wix-ui-icons-common/Star'; 4 | import StarFilled from 'wix-ui-icons-common/StarFilled'; 5 | import Check from 'wix-ui-icons-common/Check'; 6 | 7 | import {Checkbox} from '../src/components/Checkbox'; 8 | 9 | const iconExamples = [ 10 | , 11 | , 12 | 13 | ]; 14 | 15 | export default { 16 | category: 'Components', 17 | storyName: 'Checkbox', 18 | component: Checkbox, 19 | componentPath: '../src/components/Checkbox/Checkbox.tsx', 20 | 21 | componentProps: setState => ({ 22 | 'data-hook': 'storybook-checkbox', 23 | children: 'Hello World!', 24 | onChange: evt => setState({checked: evt.checked}), 25 | }), 26 | 27 | exampleProps: { 28 | onBlur: () => 'Triggered onBlur', 29 | onFocus: () => 'Triggered onFocus', 30 | onChange: evt => evt.checked ? 'Checked' : 'Unchecked', 31 | checkedIcon: iconExamples, 32 | uncheckedIcon: iconExamples, 33 | indeterminateIcon: iconExamples, 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /stories/CircularProgressBar/CircularProgressBar.story.tsx: -------------------------------------------------------------------------------- 1 | import { CircularProgressBar } from '../../src/components/CircularProgressBar'; 2 | import {Size} from '../../src/components/CircularProgressBar/constants'; 3 | import {enumValues} from '../../src/utils'; 4 | 5 | export default { 6 | category: 'Components', 7 | name: 'CircularProgressBar', 8 | storyName: 'CircularProgressBar', 9 | component: CircularProgressBar, 10 | 11 | componentProps: { 12 | errorMessage: 'some error message', 13 | value: 20, 14 | size: 'large', 15 | 'data-hook': 'circular-progress-bar-story', 16 | light: false, 17 | error: false, 18 | errorLabel: '', 19 | showProgressIndication: false 20 | }, 21 | 22 | exampleProps: { 23 | size: enumValues(Size) 24 | } 25 | } -------------------------------------------------------------------------------- /stories/CircularProgressBar/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './CircularProgressBar.story'; 2 | -------------------------------------------------------------------------------- /stories/CloseButton/index.story.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { CloseButton } from '../../src/components/CloseButton'; 4 | import { enumValues } from '../../src/utils'; 5 | import { Skin, Size } from '../../src/components/CloseButton/constants'; 6 | import { storySettings } from './storySettings'; 7 | 8 | export default { 9 | category: storySettings.kind, 10 | storyName: storySettings.story, 11 | component: CloseButton, 12 | componentPath: '../../src/components/CloseButton/CloseButton.tsx', 13 | componentProps: { 14 | 'data-hook': storySettings.dataHook 15 | }, 16 | exampleProps: { 17 | size: enumValues(Size) 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /stories/CloseButton/storySettings.ts: -------------------------------------------------------------------------------- 1 | import { StorySettings } from '../storyTypes'; 2 | 3 | export const storySettings: StorySettings = { 4 | kind: 'Internal', 5 | story: 'CloseButton', 6 | dataHook: 'storybook-close-button' 7 | } -------------------------------------------------------------------------------- /stories/FloatingHelper/ControlledExample.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { FloatingHelper } from '../../src/components/FloatingHelper'; 3 | 4 | export class ControlledExample extends React.Component { 5 | state= {open: true}; 6 | 7 | render() { 8 | return ( 9 |
10 |
11 | 12 | 13 |
14 | I am a FloatingHelper target} 17 | content={ 18 | 22 | } 23 | placement="right" 24 | /> 25 |
26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /stories/FloatingHelper/FullExample.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { FloatingHelper } from '../../src/components/FloatingHelper'; 3 | import Image from 'wix-ui-icons-common/Image'; 4 | 5 | export class FullExample extends React.Component { 6 | render() { 7 | return ( 8 | I am a FloatingHelper target} 10 | content={ 11 | null} 16 | image={} 17 | /> 18 | } 19 | placement="right" 20 | /> 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /stories/FloatingHelper/ProgrammaticExample.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | // import { FloatingHelper } from 'wix-ui-backoffice/FloatingHelper'; 3 | import { FloatingHelper } from '../../src/components/FloatingHelper'; 4 | 5 | export class ProgrammaticExample extends React.Component { 6 | helperRef: FloatingHelper; 7 | 8 | render() { 9 | return ( 10 |
11 |
12 | 13 | 14 |
15 | this.helperRef = ref} 17 | initiallyOpened={false} 18 | target={I am a FloatingHelper target} 19 | content={ 20 | 24 | } 25 | placement="right" 26 | /> 27 |
28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /stories/FloatingHelper/SimpleExample.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { FloatingHelper } from '../../src/components/FloatingHelper'; 3 | 4 | export class SimpleExample extends React.Component { 5 | render() { 6 | return ( 7 | I am a FloatingHelper target} 9 | content={ 10 | 14 | } 15 | placement="right" 16 | /> 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /stories/FloatingHelper/SimpleExampleLight.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { 3 | FloatingHelper, 4 | Appearance 5 | } from '../../src/components/FloatingHelper'; 6 | import Image from 'wix-ui-icons-common/Image'; 7 | import { ActionButtonTheme } from '../../src/components/FloatingHelper/FloatingHelperContent'; 8 | 9 | export class SimpleExampleLight extends React.Component { 10 | render() { 11 | return ( 12 | I am a FloatingHelper target} 15 | content={ 16 | null} 22 | image={ 23 | 29 | } 30 | /> 31 | } 32 | placement="right" 33 | appearance={Appearance.light} 34 | /> 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /stories/FloatingHelper/StorySettings.ts: -------------------------------------------------------------------------------- 1 | import { StorySettings } from '../storyTypes'; 2 | 3 | export const storySettings: StorySettings = { 4 | kind: 'Components', 5 | story: 'FloatingHelper', 6 | dataHook: 'story-floating-helper-right', 7 | }; 8 | -------------------------------------------------------------------------------- /stories/FloatingHelperContent/StorySettings.ts: -------------------------------------------------------------------------------- 1 | import { StorySettings } from '../storyTypes'; 2 | 3 | export const storySettings: StorySettings = { 4 | kind: 'Internal', 5 | story: 'FloatingHelperContent', 6 | dataHook: 'story-floating-helper-content', 7 | exampleDataHooks: [ 8 | 'example-body', 9 | 'example-title-body', 10 | 'example-title-body-action', 11 | 'example-body-action', 12 | 'example-title-body-action-premium', 13 | 'example-title-body-action-image', 14 | 'example-body-image', 15 | ] 16 | }; 17 | -------------------------------------------------------------------------------- /stories/FullTextView.story.tsx: -------------------------------------------------------------------------------- 1 | import {FullTextView} from '../src/components/FullTextView'; 2 | 3 | export default { 4 | category: 'Components', 5 | storyName: 'FullTextView', 6 | component: FullTextView, 7 | componentPath: '../src/components/FullTextView/FullTextView.tsx', 8 | 9 | componentProps: setState => ({ 10 | 'data-hook': 'storybook-fullTextView', 11 | children: 'Very long fancy and hardly fitting tab', 12 | maxWidth: '172px' 13 | }), 14 | }; 15 | -------------------------------------------------------------------------------- /stories/HBox/index.story.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import {HBox} from '../../src/components/HBox'; 4 | import style from './style.st.css'; 5 | 6 | const children = [1, 2, 3, 4, 5].map(i =>
hello
); 7 | 8 | export default { 9 | category: 'Components', 10 | storyName: 'HBox', 11 | 12 | component: HBox, 13 | componentPath: '../../src/components/HBox/HBox.tsx', 14 | 15 | componentProps: { 16 | ...style('root'), 17 | 'data-hook': 'storybook-hbox', 18 | children 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /stories/HBox/style.st.css: -------------------------------------------------------------------------------- 1 | :import { 2 | -st-from: "../../src/components/HBox/HBox.st.css"; 3 | -st-default: HBox; 4 | } 5 | 6 | .root { 7 | -st-extends: HBox; 8 | border: solid green 2px; 9 | height: 100px; 10 | } 11 | -------------------------------------------------------------------------------- /stories/Heading.story.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import {Heading, Appearance} from '../src/components/Heading/Heading'; 3 | import {enumValues} from '../src/utils'; 4 | 5 | export default { 6 | category: 'Components', 7 | storyName: 'Heading', 8 | component: Heading, 9 | componentPath: '../src/components/Heading/Heading.tsx', 10 | 11 | componentProps: { 12 | 'data-hook': 'storybook-heading', 13 | children: 'Some text', 14 | light: false 15 | }, 16 | exampleProps: { 17 | appearance: enumValues(Appearance) 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /stories/Input.story.tsx: -------------------------------------------------------------------------------- 1 | import {Input} from '../src/components/Input'; 2 | 3 | export default { 4 | category: 'Components', 5 | storyName: 'Input', 6 | component: Input, 7 | componentPath: '../src/components/Input/Input.tsx', 8 | 9 | componentProps: setState => ({ 10 | 'data-hook': 'storybook-input', 11 | value: 'Hello, World', 12 | placeholder: 'Greetings', 13 | error: false, 14 | onChange: event => setState({value: event.target.value}) 15 | }), 16 | 17 | exampleProps: { 18 | prefix: ['Mrs.', 'Mr.', 'Prince'], 19 | suffix: ['$', '€'], 20 | onClick: () => 'Triggered onClick', 21 | onChange: () => 'Triggered onChange', 22 | onDoubleClick: () => 'Triggered onDoubleClick', 23 | onBlur: () => 'Triggered onBlur', 24 | onFocus: () => 'Triggered onFocus', 25 | onKeyDown: () => 'Triggered onKeyDown', 26 | onKeyUp: () => 'Triggered onKeyUp' 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /stories/Label.story.tsx: -------------------------------------------------------------------------------- 1 | import {Label} from '../src/components/Label'; 2 | import * as LabelSource from '!raw-loader!../src/components/Label/Label.tsx'; 3 | 4 | export default { 5 | category: 'Components', 6 | storyName: 'Label', 7 | component: Label, 8 | source: LabelSource, 9 | componentPath: '../src/components/Label/Label.tsx', 10 | componentProps: setState => ({ 11 | 'data-hook': 'storybook-label', 12 | children: 'Some label', 13 | size: 'medium' 14 | }), 15 | exampleProps: { 16 | size: ['small', 'medium'], 17 | children: 'Some label' 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /stories/Label/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import {storiesOf} from '@storybook/react'; 3 | import {ToggleSwitch} from '../../src/components/ToggleSwitch'; 4 | import {Autocomplete} from '../../src/components/Autocomplete'; 5 | import {Heading} from '../../src/components/Heading'; 6 | import {Input} from '../../src/components/Input'; 7 | import {Label} from '../../src/components/Label'; 8 | import {SIZES} from '../../src/components/Label/constants'; 9 | 10 | const sizeOptions = Object.keys(SIZES).map(value => Autocomplete.createOption({id: value, value})); 11 | 12 | class ControlledLabelExample extends React.Component { 13 | constructor(props) { 14 | super(props); 15 | this.state = { 16 | size: SIZES.medium, 17 | children: 'Some label' 18 | }; 19 | } 20 | 21 | render() { 22 | return( 23 |
24 |
25 |
26 |
27 | Props


28 | size: this.setState({size: value})} initialSelectedId={this.state.size}/>

29 | children: this.setState({children: e.target.value})} value={this.state.children}/>

30 | 31 |
32 |
33 | Preview








34 |
35 | 41 |
42 |
43 |
44 |
45 | ); 46 | } 47 | } 48 | 49 | storiesOf('Components', module) 50 | .add('Label', () => ); 51 | -------------------------------------------------------------------------------- /stories/LabelWithOptions.story.tsx: -------------------------------------------------------------------------------- 1 | import { LabelWithOptions } from '../src/components/LabelWithOptions'; 2 | import { generateDropdownOptions } from './helpers'; 3 | import { Option, DividerArgs } from 'wix-ui-core/dist/src/components/dropdown-option'; 4 | 5 | const options = generateDropdownOptions((args: Partial = {}) => 6 | LabelWithOptions.createDivider(args.value) 7 | ); 8 | 9 | export default { 10 | category: 'Components', 11 | storyName: 'LabelWithOptions', 12 | component: LabelWithOptions, 13 | componentPath: '../src/components/LabelWithOptions/LabelWithOptions.tsx', 14 | 15 | componentProps: { 16 | 'data-hook': 'storybook-labelwithoptions', 17 | options, 18 | placeholder: 'With placeholder', 19 | fixedFooter: 'Fixed Footer', 20 | fixedHeader: 'Fixed Header' 21 | }, 22 | 23 | exampleProps: { 24 | onSelect: (option: Option) => option.value, 25 | onDeselect: (option: Option) => option.value, 26 | size: ['small', 'medium', 'large'], 27 | 28 | options: [ 29 | { value: options.slice(0, 1), label: '1 example option' }, 30 | { value: options.slice(0, 5), label: '5 example options' }, 31 | { value: options, label: '20 example options' } 32 | ] 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /stories/LinearProgressBar/LinearProgressBar.story.tsx: -------------------------------------------------------------------------------- 1 | import { LinearProgressBar } from '../../src/components/LinearProgressBar'; 2 | 3 | export default { 4 | category: 'Components', 5 | name: 'LinearProgressBar', 6 | storyName: 'LinearProgressBar', 7 | component: LinearProgressBar, 8 | 9 | componentProps: { 10 | errorMessage: 'some error message', 11 | value: 20, 12 | 'data-hook': 'linear-progress-bar-story', 13 | light: false, 14 | error: false, 15 | showProgressIndication: false 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /stories/LinearProgressBar/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './LinearProgressBar.story'; 2 | -------------------------------------------------------------------------------- /stories/StylableCounterBadge/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import {storiesOf} from '@storybook/react'; 3 | import {CounterBadge} from '../../src/components/StylableCounterBadge'; 4 | import {SKIN} from '../../src/components/StylableCounterBadge/constants'; 5 | import Facebook from 'wix-ui-icons-common/Facebook'; 6 | import {Autocomplete} from '../../src/components/Autocomplete'; 7 | import {Heading} from '../../src/components/Heading'; 8 | 9 | const skinOptions = Object.keys(SKIN).map(value => Autocomplete.createOption({id: value, value})); 10 | 11 | const iconsOptions = ['1', '12', '777', 'Facebook'].map(value => Autocomplete.createOption({id: value, value})); 12 | 13 | class ControlledCounterdBadgeExample extends React.Component { 14 | constructor(props) { 15 | super(props); 16 | this.state = { 17 | skin: SKIN.general, 18 | children: '12' 19 | }; 20 | } 21 | 22 | render() { 23 | return( 24 |
25 |
26 | Props


27 | children: this.setState({children: value})} initialSelectedId={this.state.children}/>

28 | skin: this.setState({skin: value})} initialSelectedId={this.state.skin}/>

29 |
30 |
31 | Preview








32 | 36 | {this.state.children === 'Facebook' ? : this.state.children} 37 | 38 |
39 |
40 | ); 41 | } 42 | } 43 | 44 | storiesOf('Components', module) 45 | .add('StylableCounterBadge', () => ); 46 | -------------------------------------------------------------------------------- /stories/Text.story.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import {Text} from '../src/components/Text'; 3 | import {Heading} from '../src/components/Heading'; 4 | 5 | export default { 6 | category: 'Components', 7 | storyName: 'Text', 8 | component: Text, 9 | componentPath: '../src/components/Text/Text.tsx', 10 | displayName: 'Text', 11 | 12 | componentProps: { 13 | dataHook: 'storybook-text', 14 | children: 'Some text' 15 | }, 16 | 17 | examples: ( 18 |
19 | Multiline Example: 20 | {'First line\nSecond line'} 21 |
22 | ) 23 | }; 24 | -------------------------------------------------------------------------------- /stories/Thumbnail.story.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import Image from 'wix-ui-icons-common/Image'; 4 | 5 | import {Thumbnail} from '../src/components/Thumbnail'; 6 | 7 | const image = ; 8 | 9 | export default { 10 | category: 'Components', 11 | storyName: 'Thumbnail', 12 | component: Thumbnail, 13 | componentPath: '../src/components/Thumbnail/Thumbnail.tsx', 14 | 15 | componentProps: { 16 | 'data-hook': 'storybook-thumbnail', 17 | title: 'Thumnbail Title', 18 | description: 'Description about this thumbnail option goes here', 19 | image 20 | }, 21 | 22 | exampleProps: { 23 | image: [ 24 | { label: 'small image', value: }, 25 | { label: 'normal image', value: image }, 26 | { label: 'big image', value: } 27 | ] 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /stories/TimePicker.story.tsx: -------------------------------------------------------------------------------- 1 | import { TimePicker } from '../src/components/TimePicker/TimePicker'; 2 | import { enumValues } from '../src/utils'; 3 | import { Size } from '../src/components/TimePicker/constants'; 4 | import { TimePickerUtils } from 'wix-ui-core/dist/src/components/time-picker'; 5 | 6 | const { leftpad } = TimePickerUtils; 7 | const now = new Date(); 8 | const formattedNow = `${leftpad(now.getHours())}:${leftpad(now.getMinutes())}`; 9 | 10 | export default { 11 | category: 'Components', 12 | name: 'TimePicker', 13 | storyName: 'TimePicker', 14 | component: TimePicker, 15 | componentPath: '../src/components/TimePicker/TimePicker.tsx', 16 | 17 | componentProps: setState => ({ 18 | 'data-hook': 'storybook-timePicker', 19 | error: false, 20 | disableAmPm: false, 21 | onChange: value => setState({ value }) 22 | }), 23 | 24 | exampleProps: { 25 | size: enumValues(Size), 26 | onChange: value => value, 27 | value: [ 28 | { 29 | label: `current time, ${formattedNow}`, 30 | value: `${formattedNow}` 31 | }, 32 | { 33 | label: 'noon', 34 | value: '12:00' 35 | }, 36 | { 37 | label: 'time to sleep', 38 | value: '02:34' 39 | } 40 | ] 41 | } 42 | }; 43 | -------------------------------------------------------------------------------- /stories/Tooltip/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import {storiesOf} from '@storybook/react'; 3 | import {Tooltip} from '../../src/components/Tooltip'; 4 | 5 | function createTooltip(direction, bounce) { 6 | return ( 7 | 16 | I need a tooltip 17 | 18 | ); 19 | } 20 | 21 | class FullTooltip extends React.Component<{direction: string, bounce?: boolean}> { 22 | render() { 23 | const {direction, bounce} = this.props; 24 | return
{createTooltip(direction, bounce)}
; 25 | } 26 | } 27 | 28 | storiesOf('Components', module) 29 | .add('Tooltip', () => ( 30 |
31 | 32 | 33 | 34 | 35 | 36 |
37 | )); 38 | -------------------------------------------------------------------------------- /stories/VBox/index.story.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import {VBox} from '../../src/components/VBox'; 4 | import style from './style.st.css'; 5 | 6 | const children = [1, 2, 3, 4, 5].map(i =>
hello
); 7 | 8 | export default { 9 | category: 'Components', 10 | storyName: 'VBox', 11 | 12 | component: VBox, 13 | componentPath: '../../src/components/VBox/VBox.tsx', 14 | 15 | componentProps: { 16 | ...style('root'), 17 | 'data-hook': 'storybook-vbox', 18 | children 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /stories/VBox/style.st.css: -------------------------------------------------------------------------------- 1 | :import { 2 | -st-from: "../../src/components/VBox/VBox.st.css"; 3 | -st-default: VBox; 4 | } 5 | 6 | .root { 7 | -st-extends: VBox; 8 | border: solid green 2px; 9 | width: 100px; 10 | } 11 | -------------------------------------------------------------------------------- /stories/helpers.tsx: -------------------------------------------------------------------------------- 1 | import { OptionFactory } from 'wix-ui-core/dist/src/components/dropdown-option'; 2 | 3 | export const generateDropdownOptions = ( 4 | dividerFactory = OptionFactory.createDivider 5 | ) => { 6 | const optionsExample = Array.from(Array(20)).map((x, index) => 7 | OptionFactory.create({ id: index, value: `value${index}` }) 8 | ); 9 | 10 | optionsExample[2] = OptionFactory.create({ 11 | id: 2, 12 | isDisabled: true, 13 | value: 'Disabled item' 14 | }); 15 | optionsExample[5] = dividerFactory(); 16 | optionsExample[8].value = 'This is a very very very very very long option'; 17 | optionsExample[12] = dividerFactory({ value: 'Divider' }); 18 | optionsExample[13] = OptionFactory.create({ 19 | id: 13, 20 | value: 'Custom Item', 21 | render: value => {value} 22 | }); 23 | 24 | return optionsExample; 25 | }; 26 | -------------------------------------------------------------------------------- /stories/index.ts: -------------------------------------------------------------------------------- 1 | import './AddressInput.story'; 2 | import './Autocomplete.story'; 3 | import './Checkbox.story'; 4 | import './Badge/index.story'; 5 | import './Button/index.story'; 6 | import './CloseButton/index.story'; 7 | import './FloatingHelper/index.story'; 8 | import './FloatingHelperContent/index.story'; 9 | import './FullTextView.story'; 10 | import './StylableCounterBadge'; 11 | import './Heading.story'; 12 | import './Label'; 13 | import './LinearProgressBar'; 14 | import './CircularProgressBar'; 15 | import './Input.story.tsx'; 16 | import './LabelWithOptions.story'; 17 | import './ToggleSwitch'; 18 | import './Tooltip'; 19 | import './Thumbnail.story'; 20 | import './HBox/index.story'; 21 | import './VBox/index.story'; 22 | import './Text.story'; 23 | import './TimePicker.story'; 24 | -------------------------------------------------------------------------------- /stories/storyTypes.ts: -------------------------------------------------------------------------------- 1 | import { StoryUrlParams } from 'wix-ui-test-utils/dist/src/protractor/'; 2 | 3 | export interface StorySettings extends StoryUrlParams { 4 | kind: 'Internal' | 'Components'; 5 | dataHook: string; 6 | exampleDataHooks?: string[]; 7 | } 8 | -------------------------------------------------------------------------------- /test/enzyme-setup.js: -------------------------------------------------------------------------------- 1 | const Enzyme = require('enzyme'); 2 | const Adapter = require('enzyme-adapter-react-16'); 3 | 4 | Enzyme.configure({adapter: new Adapter()}); 5 | -------------------------------------------------------------------------------- /test/testkitUtils.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import {mount, ReactWrapper} from 'enzyme'; 3 | import { enzymeTestkitFactoryCreator } from 'wix-ui-test-utils/enzyme'; 4 | import { BaseDriver, DriverFactory } from 'wix-ui-test-utils/driver-factory'; 5 | 6 | /* TODO: Add this to wix-ui-test-utils or 7 | * change wix-ui-test-utils/enzyme's enzymeTestkitFactoryCreator to return the 8 | * wrapper and wrapperInstance as well. 9 | */ 10 | export function createEnzymeDriverFactory, T extends BaseDriver>(driverFactory: DriverFactory) { 11 | function createEnzymeDriver(element: React.ReactElement) { 12 | const dataHook = 'arbitrary-hook'; 13 | const enzymeTestkitFactory = enzymeTestkitFactoryCreator(driverFactory); 14 | const wrapper = mount(React.cloneElement(element, { 'data-hook': dataHook })); 15 | const driver = enzymeTestkitFactory({ wrapper, dataHook }); 16 | return { wrapper, driver, wrapperInstance: wrapper.instance() as C }; 17 | } 18 | 19 | return createEnzymeDriver; 20 | } 21 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "sourceMap": true, 4 | "module": "commonjs", 5 | "declaration": true, 6 | "strict": false, 7 | "moduleResolution": "node", 8 | "target": "es5", 9 | "jsx": "react", 10 | "lib": ["dom", "es2016", "esnext.asynciterable"], 11 | "baseUrl": "./", 12 | "paths": { 13 | "*": ["node_modules/@types/*", "*"], 14 | "protractor": ["src/protractor.d.ts"] // Fix protractor issue https://github.com/angular/protractor/issues/5348 15 | } 16 | }, 17 | "include": [ 18 | "./node_modules/wix-ui-core/dist/src/globals.d.ts", 19 | "./node_modules/wix-ui-core/dist/src/types.d.ts", 20 | "./src/**/*.ts", 21 | "./src/**/*.tsx" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "tslint-config-wix", 4 | "tslint-react", 5 | "tslint-config-prettier" 6 | ], 7 | "rules": { 8 | "comma-dangle": ["error", "never"], 9 | "jsx-no-multiline-js": false, 10 | "jsx-no-lambda": false, 11 | "jsx-boolean-value": [true, "never"], 12 | "jsx-alignment": true, 13 | "jsx-wrap-multiline": true, 14 | "space-in-brackets": ["error", "always"], 15 | "arrow-parens": [true, "ban-single-arg-parens"], 16 | "array-bracket-spacing": [true, "never"], 17 | "quotemark": [true, "single", "jsx-double"] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /wallaby.js: -------------------------------------------------------------------------------- 1 | module.exports = require('yoshi/config/wallaby-jest'); 2 | --------------------------------------------------------------------------------