[UI Framework] Reorganize UI Framework and add Yeoman generator (#13172)

* Reorganize documentation styles so they all live in doc_site/components directory. (#12809)
  - Remove global styles, e.g. body and html element selectors.
* Create global_styles dir with sub-directories. (#12833)
* Add SCSS style guide. (#12850)
* Refactor UI Framework directory structure to house everything in a src directory. (#12880)
  - Add components/index.js and services/index.js files to continue to export JS modules from the root.
* Add KUI Yeoman generator.
* Support creation of components.
* Add documentation generator for main page, demo, and sandbox.
  - Add additional documentation snippets to KUI generator. (#13076)
  - Fix incorrect use of double quotes in KUI generator snippet. (#13086)
  - Remove infrequently used imports from the KUI generator test template. (#13110)
* Mock assets files for Jest. (#13060)
* Fix broken coverage report paths in Jest config. (#13082)
* Update eslint config to lint the new UI Framework directory structure. (#13102)
* Fix positioning of doc site pagination buttons. (#13203)
* Support hasReact prop for sandboxes. (#13270)
* Remove deprecated used of component mixin from KUI generator's SCSS template. (#13377)
* Fix rebasing errors.
  - Add dashboard back to Jest config.
  - Add missing form and tool_bar variables.
* Rename tasks to createComponent and documentComponent.
* Reference correct src paths in README.
* Add children and className to templates' propTypes.
* Add default folder name for page demo.
* Add suffix to sandbox routes.
* Specify testPathIgnorePatterns more clearly.
* Rename component.test.js to test.js so that Jenkins won't try to run it.
* Update npm scripts to depend on local yo dependency, not global.
* Add ui_framework/src to copy task.
* Simplify npm scripts and remove requirement for installing Yeoman from README.
* Add services to moduleNameMapper in jest config.
* Clean up Button and Gallery examples.
This commit is contained in:
CJ Cenizal 2017-08-11 08:48:48 -07:00 committed by GitHub
parent bbabe48b36
commit 720297d8da
429 changed files with 1356 additions and 578 deletions

1
.gitignore vendored
View file

@ -36,3 +36,4 @@ selenium
ui_framework/doc_site/build
!ui_framework/doc_site/build/index.html
yarn.lock
.yo-rc.json

View file

@ -7,6 +7,7 @@ recommended for the development of all Kibana plugins.
- [Angular](style_guides/angular_style_guide.md)
- [React](style_guides/react_style_guide.md)
- [CSS](style_guides/css_style_guide.md)
- [SCSS](style_guides/scss_style_guide.md)
- [HTML](style_guides/html_style_guide.md)
- [API](style_guides/api_style_guide.md)
- [Architecture](style_guides/architecture_style_guide.md)

View file

@ -63,7 +63,9 @@
"mocha": "echo 'use `node scripts/mocha`' && false",
"sterilize": "grunt sterilize",
"uiFramework:start": "grunt uiFramework:start",
"uiFramework:build": "grunt uiFramework:build"
"uiFramework:build": "grunt uiFramework:build",
"uiFramework:createComponent": "yo ./ui_framework/generator-kui/app/component.js",
"uiFramework:documentComponent": "yo ./ui_framework/generator-kui/app/documentation.js"
},
"repository": {
"type": "git",
@ -208,6 +210,7 @@
"angular-mocks": "1.4.7",
"babel-eslint": "7.2.3",
"chai": "3.5.0",
"chalk": "2.0.1",
"chance": "1.0.6",
"cheerio": "0.22.0",
"chokidar": "1.6.0",
@ -275,7 +278,9 @@
"supertest": "3.0.0",
"supertest-as-promised": "2.0.2",
"tree-kill": "1.1.0",
"webpack-dev-server": "1.14.1"
"webpack-dev-server": "1.14.1",
"yeoman-generator": "1.1.1",
"yo": "2.0.0"
},
"engines": {
"node": "6.11.1",

View file

@ -5,15 +5,16 @@
"<rootDir>/ui_framework/"
],
"collectCoverageFrom": [
"ui_framework/services/**/*.js",
"!ui_framework/services/index.js",
"!ui_framework/services/**/*/index.js",
"ui_framework/components/**/*.js",
"!ui_framework/components/index.js",
"!ui_framework/components/**/*/index.js"
"ui_framework/src/components/**/*.js",
"!ui_framework/src/components/index.js",
"!ui_framework/src/components/**/*/index.js",
"ui_framework/src/services/**/*.js",
"!ui_framework/src/services/index.js",
"!ui_framework/src/services/**/*/index.js"
],
"moduleNameMapper": {
"^ui_framework/components": "<rootDir>/ui_framework/components",
"^ui_framework/services": "<rootDir>/ui_framework/services",
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/src/jest/file_mock.js",
"\\.(css|less|scss)$": "<rootDir>/src/jest/style_mock.js"
},
@ -29,7 +30,9 @@
"**/*.test.js"
],
"testPathIgnorePatterns": [
"<rootDir>[/\\\\]ui_framework[/\\\\](dist|doc_site|jest)[/\\\\]"
"<rootDir>/ui_framework/dist/",
"<rootDir>/ui_framework/doc_site/",
"<rootDir>/ui_framework/generator-kui/"
],
"transform": {
"^.+\\.js$": "<rootDir>/src/jest/babelTransform.js"

View file

@ -6,7 +6,10 @@ import { ModalOverlay } from './modal_overlay';
const module = uiModules.get('kibana');
import { CONFIRM_BUTTON, CANCEL_BUTTON } from 'ui_framework/components/modal/confirm_modal';
import {
KUI_MODAL_CONFIRM_BUTTON as CONFIRM_BUTTON,
KUI_MODAL_CANCEL_BUTTON as CANCEL_BUTTON,
} from 'ui_framework/components';
export const ConfirmationButtonTypes = {
CONFIRM: CONFIRM_BUTTON,

View file

@ -1,6 +1,22 @@
# CSS Style Guide
## Original style guide
Our style guide is an extension of [CSS Guidelines by Harry Roberts](https://cssguidelin.es/). The rules we especially focus on are:
* [Multiple files](https://cssguidelin.es/#multiple-files)
* [Indenting](https://cssguidelin.es/#indenting)
* [Commenting](https://cssguidelin.es/#commenting)
* [Naming conventions](https://cssguidelin.es/#naming-conventions) (see "Naming convention", below, for exceptions)
* [CSS selectors](https://cssguidelin.es/#css-selectors)
* [Specificity](https://cssguidelin.es/#specificity)
* [Architectural principles](https://cssguidelin.es/#architectural-principles)
Please see the [SCSS Style Guide](scss_style_guide.md) for additional rules pertaining to SCSS.
## Contents
- [CSS Style Guide](#css-style-guide)
- [Selecting elements](#selecting-elements)
- [Using the preprocessor](#using-the-preprocessor)

View file

@ -0,0 +1,16 @@
# SCSS Style Guide
## Original style guide
Our style guide is an extension of [Sass Guidelines by Hugo Giraudel](https://sass-guidelin.es/). The rules we especially focus on are:
* [Syntax & formatting](https://sass-guidelin.es/#syntax--formatting) (exceptions below)
* [Naming conventions](https://sass-guidelin.es/#naming-conventions) (see the [CSS Style Guide](css_style_guide.md) for infomation on exceptions)
* [Variables](https://sass-guidelin.es/#variables)
* [Mixins](https://sass-guidelin.es/#mixins)
## Syntax and formatting
The Sass Guidelines site recommends using RBG and HSL values to format colors, but we're using
hex values.

View file

@ -18,6 +18,7 @@ module.exports = function () {
'ui_framework/components/**',
'ui_framework/services/**',
'ui_framework/dist/**',
'ui_framework/src/**',
'webpackShims/**',
'config/kibana.yml',
],

View file

@ -9,8 +9,9 @@ export default grunt => ({
'scripts',
'tasks',
'test',
'ui_framework/components',
'ui_framework/doc_site',
'ui_framework/src',
'ui_framework/doc_site/src',
'ui_framework/generator_kui',
'utilities',
'webpackShims',
],

View file

@ -83,7 +83,7 @@ module.exports = function (grunt) {
}
function uiFrameworkCompile() {
const src = 'ui_framework/components/index.scss';
const src = 'ui_framework/src/index.scss';
const dest = 'ui_framework/dist/ui_framework.css';
return new Promise(resolve => {
@ -130,7 +130,7 @@ module.exports = function (grunt) {
return new Promise(() => {
debouncedCompile();
chokidar.watch('ui_framework/components', { ignoreInitial: true }).on('all', (event, path) => {
chokidar.watch('ui_framework/src', { ignoreInitial: true }).on('all', (event, path) => {
grunt.log.writeln(event, path);
debouncedCompile();
});

View file

@ -21,48 +21,91 @@ fully-tested the code is.
See the documentation in [`scripts/jest.js`](../scripts/jest.js) for more options.
### React components
Here are the components you can import from the Framework:
```javascript
import {
KuiButton,
KuiButtonGroup,
KuiButtonIcon,
} from '../path/to/ui_framework/components';
```
## Creating components
There are four steps to creating a new component:
1. Create the SCSS for the component in `ui_framework/components`.
1. Create the SCSS for the component in `ui_framework/src/components`.
2. Create the React portion of the component.
3. Document it with examples in `ui_framework/doc_site`.
4. Write tests.
3. Write tests.
4. Document it with examples in `ui_framework/doc_site`.
### Create component SCSS
You can do this using Yeoman (the easy way), or you can do it manually (the hard way).
1. Create a directory for your component in `ui_framework/components`.
### Using Yeoman
#### Create a new component
From the command line, run `npm run uiFramework:createComponent`.
First, you'll be prompted for what kind of component to create:
| Choice | Description |
|---|---|
| Stateless function | A stateless functional React component |
| Component class | A class-based React component |
Next, you'll enter a series of prompts.
#### "What's the name of this component?"
Yeoman will ask you what to name the file. It expects you to provide the name
in snake case. Yeoman will automatically add file extensions and a "kui" prefix so you should leave those out.
#### "Where do you want to create this component's files?"
This defaults to the last directory you specified for this prompt, or to the UI Framework's
components directory if you haven't specified one. To change this location, type in the path to the
directory where the files should live.
If you want Yeoman to automatically generate a directory to organize the files,
that directory will be created inside of the location you specify (see next prompt).
#### "Does it need its own directory?""
This defaults to `YES`. This will automatically generate a directory with the
same name as the file, but without a "kui" prefix.
#### Done!
Yeoman will generate the files you need in your project's folder system.
For your convenience, it will also output some snippets you can tweak to import
and re-export the generated JS and SCSS files.
### Manually
#### Create component SCSS
1. Create a directory for your component in `ui_framework/src/components`.
2. In this directory, create `_{component name}.scss`.
3. _Optional:_ Create any other components that should be [logically-grouped](#logically-grouped-components)
in this directory.
4. Create an `_index.scss` file in this directory that import all of the new component SCSS files
you created.
5. Import the `_index.scss` file into `ui_framework/components/index.scss`.
5. Import the `_index.scss` file into `ui_framework/src/components/index.scss`.
This makes your styles available to Kibana and the UI Framework documentation.
### Create the React component
#### Create the React component
1. Create the React component(s) in the same directory as the related SCSS file(s).
2. Export these components from an `index.js` file.
3. Re-export these components from `ui_framework/components/index.js`.
3. Re-export these components from `ui_framework/src/components/index.js`.
This makes your React component available for import into Kibana.
### Document the component with examples
#### Test the component
1. Start Jest in watch mode by running `node scripts/jest --watch`.
2. Create test files with the name pattern of `{component name}.test.js`.
3. Write your tests and see them fail or succeed.
To see how well the components have been covered by tests, you can run
`node scripts/jest --coverage` and check the generated report in
`target/jest-coverage/index.html`.
#### Document the component with examples
1. Create a directory for your example in `ui_framework/doc_site/src/views`. Name it the name of the
component.
@ -80,15 +123,22 @@ complex they should be. In general, your examples should demonstrate:
content.
* The various states of the component, e.g. disabled, selected, empty of content, error state.
### Test the component
## Creating documentation
1. Start Jest in watch mode by running `node scripts/jest --watch`.
2. Create test files with the name pattern of `{component name}.test.js`.
3. Write your tests and see them fail or succeed.
You can use the same Yeoman generator referenced above to create documentation.
To see how well the components have been covered by tests, you can run
`node scripts/jest --coverage` and check the generated report in
`target/jest-coverage/index.html`.
From the command line, run `npm run uiFramework:documentComponent`.
First, you'll be prompted for what kind of documentation to create:
| Choice | Description |
|---|---|
| Page | A page for documenting a component(s) with multiple demos |
| Page demo | An individual demo of a particular component use case |
| Sandbox | An empty document where you can do pretty much anything |
Just follow the prompts and your documentation files will be created.
You can use the snippets that are printed to the terminal to integrate these files into the UI Framework documentation site.
## Principles
@ -101,7 +151,8 @@ additional SCSS files for these components in the same component directory.
### Writing CSS
Check out our [CSS style guide](https://github.com/elastic/kibana/blob/master/style_guides/css_style_guide.md).
Check out our [CSS style guide](https://github.com/elastic/kibana/blob/master/style_guides/css_style_guide.md)
and [SCSS style guide](https://github.com/elastic/kibana/blob/master/style_guides/scss_style_guide.md).
## Benefits

View file

@ -1,112 +0,0 @@
// --------------------------------------------------------------------------------------
// KUI global variables
// --------------------------------------------------------------------------------------
// This file contains all global variables available within kui. Every variable in this
// document should be prefixed with $global. This lets us know where the variable is
// coming from when looking inside the individual component files. Any component local
// variables should be declared at the top of those documents prefixed with $componentName.
// True colors
$globalColorBlue: #0079a5;
$globalColorTeal: #00A69B;
$globalColorRed: #A30000;
$globalColorLightestGray: #F5F5F5;
$globalColorLightGray: #D9D9D9;
$globalColorMediumGray: #999;
$globalColorDarkGray: #666;
$globalColorDarkestGray: #3F3F3F;
$globalColorBlack: #000;
$globalColorWhite: #FFF;
// Normal colors
$globalTextColor: #2d2d2d;
$globalLinkColor: $globalColorBlue;
$globalLinkColor-isHover: darken($globalLinkColor, 10%);
$globalInputTextColor: $globalTextColor;
$globalInputBackgroundColor: $globalColorWhite;
$globalInputBorderColor: $globalColorLightGray;
// Animations
$globalAnimSlightBounce: cubic-bezier(0.34,1.61,0.7,1);
$globalAnimSlightResistance: cubic-bezier(0.694, 0.0482, 0.335, 1);
$globalAnimSpeedVeryFast: 90ms;
$globalAnimSpeedFast: 150ms;
$globalAnimSpeedNormal: 250ms;
$globalAnimSpeedSlow: 350ms;
$globalAnimSpeedVerySlow: 500ms;
// Dark theme colors
$globalTextColor--darkTheme: #cecece;
$globalBackgroundColor--darkTheme: #777777;
$globalLinkColor--darkTheme: #b7e2ea;
$globalLinkColor-isHover--darkTheme: #def2f6;
$globalInputTextColor--darkTheme: $globalTextColor--darkTheme;
$globalInputBackgroundColor--darkTheme: #444444;
$globalInputBorderColor--darkTheme: $globalInputBackgroundColor--darkTheme;
// Font
$globalFontFamily: "Open Sans", Helvetica, Arial, sans-serif;
$globalFontSize: 14px;
$globalLineHeight: 1.5;
$globalSubTextFontSize: 12px;
$globalTitleFontSize: 18px;
$globalFontWeightRegular: 400;
$globalFontWeightBold: 700;
// Colors
$globalInfoColor: #3fa8c7;
$globalInactiveColor: #c3c3c3;
$globalSuccessColor: #417505;
$globalWarningColor: #ec9800;
$globalDangerColor: $globalColorRed;
$globalFocusColor: $globalColorBlue;
$globalFocusDangerColor: #ff523c;
$globalFocusWarningColor: #ffa500;
$globalFocusBackgroundColor: #ffffff;
$globalFontColor: #191E23;
$globalSubduedTextColor: $globalColorDarkGray;
$globalLinkHoverColor: #006E8A;
$globalSelectedBorderColor: $globalColorBlue;
$globalDangerBorderColor: $globalDangerColor;
$globalFormControlBorderColor: #DEDEDE;
// Borders
$globalBorderColor: $globalColorLightGray;
$globalBorderRadius: 4px;
$globalBorderThick: 2px solid $globalBorderColor;
$globalBorderThin: 1px solid $globalBorderColor;
// Shadows
$globalBoxShadow: 0 4px 8px 0 rgba(0, 0, 0, 0.1);
// Timing
$globalInputTransitionTiming: 0.1s linear;
// Bar
$toolBarHeight: 50px;
$toolBarPadding: 10px;
$toolBarSectionSpacing: 50px;
$toolBarItsemSpacing: 10px;
// Form
$globalFormControlHorizontalPadding: 12px;
$globalFormControlPadding: 3px $globalFormControlHorizontalPadding 4px;
$globalFormInputHeight: 30px;
$globalFormFieldDefaultWidth: 180px;
$globalFormFieldSmallWidth: 60px;
$globalFormFieldLargeWidth: 400px;

View file

@ -1 +0,0 @@
@import "./_screen_reader";

View file

@ -1,123 +1 @@
export { KuiActionItem } from './action_item';
export {
KuiKeyboardAccessible,
KuiScreenReaderOnly,
} from './accessibility';
export {
KuiBar,
KuiBarSection,
} from './bar';
export {
KuiButton,
KuiButtonGroup,
KuiButtonIcon,
KuiLinkButton,
KuiSubmitButton,
} from './button';
export {
KuiCard,
KuiCardDescriptionText,
KuiCardDescriptionTitle,
KuiCardDescription,
KuiCardFooter,
KuiCardGroup,
} from './card';
export {
KuiColorPicker,
} from './color_picker';
export {
KuiCollapseButton,
} from './collapse_button';
export {
KuiEmptyTablePrompt,
KuiEmptyTablePromptMessage,
KuiEmptyTablePromptPanel,
} from './empty_table_prompt';
export {
KuiEvent,
KuiEventSymbol,
KuiEventBody,
KuiEventBodyMessage,
KuiEventBodyMetadata,
} from './event';
export {
KuiFieldGroup,
KuiFieldGroupSection,
} from './form_layout';
export {
KuiGallery,
KuiGalleryButton,
KuiGalleryButtonIcon,
KuiGalleryButtonImage,
KuiGalleryButtonLabel,
} from './gallery';
export {
KuiHeaderBar,
KuiHeaderBarSection,
} from './header_bar';
export { KuiInfoButton } from './info_button';
export {
KuiLocalNav,
KuiLocalNavRow,
KuiLocalNavRowSection,
KuiLocalTab,
KuiLocalTabs,
KuiLocalTitle,
} from './local_nav';
export {
KuiMenu,
KuiMenuItem,
} from './menu';
export * from './modal';
export {
KuiPager,
KuiPagerButtonGroup,
} from './pager';
export {
KuiPopover,
} from './popover';
export {
KuiTabs,
KuiTab
} from './tabs';
export {
KuiTable,
KuiControlledTable,
KuiTableHeaderCell,
KuiTableRow,
KuiTableRowCell,
KuiTableInfo,
KuiTableRowCheckBoxCell,
KuiTableHeaderCheckBoxCell,
KuiTableHeader,
KuiTableBody,
} from './table';
export {
KuiToolBar,
KuiToolBarSearchBox,
KuiToolBarFooter,
KuiToolBarSection,
KuiToolBarFooterSection,
KuiToolBarText
} from './tool_bar';
export * from '../src/components';

View file

@ -6,7 +6,7 @@
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet" type="text/css">
<script src="https://use.fontawesome.com/a9649923ac.js"></script>
</head>
<body>
<body class="guideBody">
<div id="guide" style="height: 100%"></div>
<script src="bundle.js"></script>
</body>

View file

@ -0,0 +1,103 @@
html {
height: 100%;
}
.guideBody {
height: 100%;
background-color: #000000;
margin: 0;
min-width: $guideMinWidth;
}
/**
* 1. Expand container to fit the page if the content is shorter than the page, or expand with the
* content if it's taller than the page.
*/
.guide {
display: flex;
min-height: 100%; /* 1 */
}
.guideContent {
display: flex;
flex-direction: column;
flex: 1 1 auto;
padding-top: $guideNavHeight;
background-color: $guideBaseBackgroundColor;
transition:
padding-right $guideCodeViewerTransition,
opacity $guideCodeViewerTransition;
&.is-code-viewer-open {
padding-right: $guideCodeViewerWidth;
@include whenNarrowerThan($guideNormalBreakpoint) {
padding-right: $guideCodeViewerSmallWidth;
}
}
.is-guide-nav-open + & {
opacity: 0.7;
}
}
@media only screen and (max-width: 1300px) {
.guideHomePage {
justify-content: flex-start !important;
.guideContentPage__content {
margin-left: 250px;
}
}
}
.guideContentPage {
position: relative;
display: flex;
justify-content: center;
flex: 1 0 auto;
background-color: #ffffff;
}
.guideContentPage__hint {
position: absolute;
top: 0;
left: 0;
width: 100%;
max-width: 260px;
max-height: 500px;
padding: 30px;
margin: 20px;
border-radius: 4px;
background-color: #e8e8e8;
line-height: $guideLineHeight;
}
.guideContentPage__content {
width: 100%;
max-width: 800px;
padding: 30px 60px;
}
.guideHintArrow {
position: absolute;
top: -15px;
left: 12px;
background-image: url("images/hint-arrow.svg");
width: 26px;
height: 40px;
background-repeat: no-repeat;
background-size: contain;
}
.guideWarning {
border-left: 5px solid #e8488b;
margin-top: 19px;
padding: 0 14px;
line-height: 21px;
color: #e8488b;
}
.guideBreak {
border: none;
}

View file

@ -1,5 +1,54 @@
$guideVerticalRhythm: 20px;
$guideLineHeight: 24px;
$guideNavHeight: 60px;
$guideSideNavWidth: 400px;
$guideSideNavSmallWidth: 220px;
$guideCodeViewerWidth: 660px;
$guideCodeViewerSmallWidth: 520px;
$guideCodeViewerTransition: 0.2s ease;
// Colors
$guideBaseBackgroundColor: #f7f7f7;
$guidePanelBackgroundColor: #ffffff;
$guideTextColor: #444;
$guideLinkColor: #00a9e5;
$guideLinkHoverColor: #00a9e5;
// Breakpoints
$guideMinWidth: 840px;
$guideNormalBreakpoint: 1900px;
@mixin whenNarrowerThan($browserWidth) {
@media only screen and (max-width: #{$browserWidth}) {
@content;
}
}
@mixin whenWiderThan($browserWidth) {
@media only screen and (min-width: #{$browserWidth}) {
@content;
}
}
@mixin scrollbar($color: rgba(#454D58, 0.4)) {
&::-webkit-scrollbar {
width: 16px;
height: 16px;
}
&::-webkit-scrollbar-thumb {
background-color: $color;
border: 6px solid transparent;
background-clip: content-box;
}
&::-webkit-scrollbar-track {
background-color: transparent;
}
}
@import "guide/guide";
@import "guide_code/guide_code";
@import "guide_code_viewer/guide_code_viewer";
@import "guide_demo/guide_demo";

View file

@ -151,7 +151,7 @@
.guideNavPaginationButtons {
position: absolute;
top: 10px;
top: 20px;
right: 10px;
}

View file

@ -122,6 +122,10 @@ export class GuideNav extends Component {
this.props.sandboxes.filter(item => (
item.name.toLowerCase().indexOf(this.state.search.toLowerCase()) !== -1
)).map((item, index) => {
const icon =
item.hasReact
? <div className="guideNavItem__reactLogo" />
: undefined;
return (
<div key={`sandboxNavItem-${index}`} className="guideNavItem">
<Link
@ -131,6 +135,8 @@ export class GuideNav extends Component {
>
{item.name}
</Link>
{icon}
</div>
);
});

View file

@ -1,5 +1,3 @@
@import "../../variables";
.guidePage {
display: flex;
flex: 1 0 auto;

View file

@ -1,116 +1,2 @@
@import "../../dist/ui_framework.css";
@import "./variables";
@import "./components/guide_components";
* {
box-sizing: border-box;
}
html,
body {
height: 100%;
}
/**
* 1. Insane line-height makes it easier to notice when components are relying
* on styles inherited from body.
*/
body {
background-color: #000000;
line-height: 40px; /* 1 */
margin: 0;
min-width: $guideMinWidth;
}
/**
* 1. Expand container to fit the page if the content is shorter than the page, or expand with the
* content if it's taller than the page.
*/
.guide {
display: flex;
min-height: 100%; /* 1 */
}
.guideContent {
display: flex;
flex-direction: column;
flex: 1 1 auto;
padding-top: $guideNavHeight;
background-color: $guideBaseBackgroundColor;
transition:
padding-right $guideCodeViewerTransition,
opacity $guideCodeViewerTransition;
&.is-code-viewer-open {
padding-right: $guideCodeViewerWidth;
@include whenNarrowerThan($guideNormalBreakpoint) {
padding-right: $guideCodeViewerSmallWidth;
}
}
.is-guide-nav-open + & {
opacity: 0.7;
}
}
@media only screen and (max-width: 1300px) {
.guideHomePage {
justify-content: flex-start !important;
.guideContentPage__content {
margin-left: 250px;
}
}
}
.guideContentPage {
position: relative;
display: flex;
justify-content: center;
flex: 1 0 auto;
background-color: #ffffff;
}
.guideContentPage__hint {
position: absolute;
top: 0;
left: 0;
width: 100%;
max-width: 260px;
max-height: 500px;
padding: 30px;
margin: 20px;
border-radius: 4px;
background-color: #e8e8e8;
line-height: $guideLineHeight;
}
.guideContentPage__content {
width: 100%;
max-width: 800px;
padding: 30px 60px;
}
.guideHintArrow {
position: absolute;
top: -15px;
left: 12px;
background-image: url("images/hint-arrow.svg");
width: 26px;
height: 40px;
background-repeat: no-repeat;
background-size: contain;
}
.guideWarning {
border-left: 5px solid #e8488b;
margin-top: 19px;
padding: 0 14px;
line-height: 21px;
color: #e8488b;
}
.guideBreak {
border: none;
}

View file

@ -1,47 +0,0 @@
$guideLineHeight: 24px;
$guideNavHeight: 60px;
$guideSideNavWidth: 400px;
$guideSideNavSmallWidth: 220px;
$guideCodeViewerWidth: 660px;
$guideCodeViewerSmallWidth: 520px;
$guideCodeViewerTransition: 0.2s ease;
// Colors
$guideBaseBackgroundColor: #f7f7f7;
$guidePanelBackgroundColor: #ffffff;
$guideTextColor: #444;
$guideLinkColor: #00a9e5;
$guideLinkHoverColor: #00a9e5;
// Breakpoints
$guideMinWidth: 840px;
$guideNormalBreakpoint: 1900px;
@mixin whenNarrowerThan($browserWidth) {
@media only screen and (max-width: #{$browserWidth}) {
@content;
}
}
@mixin whenWiderThan($browserWidth) {
@media only screen and (min-width: #{$browserWidth}) {
@content;
}
}
@mixin scrollbar($color: rgba(#454D58, 0.4)) {
&::-webkit-scrollbar {
width: 16px;
height: 16px;
}
&::-webkit-scrollbar-thumb {
background-color: $color;
border: 6px solid transparent;
background-clip: content-box;
}
&::-webkit-scrollbar-track {
background-color: transparent;
}
}

View file

@ -13,6 +13,7 @@ export default () => (
Basic button
</KuiButton>
<br />
<br />
<KuiButton

View file

@ -10,6 +10,7 @@ export default () => (
Danger button
</KuiButton>
<br />
<br />
<KuiButton

View file

@ -12,7 +12,8 @@ export default () => (
Button element
</KuiButton>
&nbsp;
<br />
<br />
<form onSubmit={e => {
e.preventDefault();
@ -24,6 +25,7 @@ export default () => (
</KuiSubmitButton>
</form>
<br />
<form onSubmit={e => {
e.preventDefault();
@ -35,7 +37,7 @@ export default () => (
</KuiSubmitButton>
</form>
&nbsp;
<br />
<KuiLinkButton
buttonType="basic"
@ -45,7 +47,8 @@ export default () => (
Anchor element
</KuiLinkButton>
&nbsp;
<br />
<br />
<KuiLinkButton
buttonType="basic"

View file

@ -50,10 +50,6 @@ import ButtonGroupUnited from './button_group_united';
const buttonGroupUnitedSource = require('!!raw!./button_group_united');
const buttonGroupUnitedHtml = renderToHtml(ButtonGroupUnited);
import InToolBar from './buttons_in_tool_bar';
const inToolBarSource = require('!!raw!./buttons_in_tool_bar');
const inToolBarHtml = renderToHtml(InToolBar);
import Elements from './button_elements';
const elementsSource = require('!!raw!./button_elements');
const elementsHtml = renderToHtml(Elements);
@ -256,25 +252,6 @@ export default props => (
</GuideDemo>
</GuideSection>
<GuideSection
title="In ToolBar"
source={[{
type: GuideSectionTypes.JS,
code: inToolBarSource,
}, {
type: GuideSectionTypes.HTML,
code: inToolBarHtml,
}]}
>
<GuideText>
This example verifies that Buttons are legible against the ToolBar's background.
</GuideText>
<GuideDemo>
<InToolBar />
</GuideDemo>
</GuideSection>
<GuideSection
title="Element variations"
source={[{

View file

@ -10,6 +10,7 @@ export default () => (
Hollow button
</KuiButton>
<br />
<br />
<KuiButton

View file

@ -42,6 +42,7 @@ export default class LoadingButton extends Component {
{this.state.isLoading ? 'Loading...' : 'Load more'}
</KuiButton>
<br />
<br />
<KuiButton

View file

@ -10,6 +10,7 @@ export default () => (
Primary button
</KuiButton>
<br />
<br />
<KuiButton

View file

@ -10,6 +10,7 @@ export default () => (
Secondary button
</KuiButton>
<br />
<br />
<KuiButton

View file

@ -10,6 +10,7 @@ export default () => (
Warning button
</KuiButton>
<br />
<br />
<KuiButton

View file

@ -14,6 +14,7 @@ export default () => (
Create
</KuiButton>
<br />
<br />
<KuiButton
@ -23,6 +24,7 @@ export default () => (
Delete
</KuiButton>
<br />
<br />
<KuiButton
@ -32,6 +34,7 @@ export default () => (
Previous
</KuiButton>
<br />
<br />
<KuiButton
@ -42,6 +45,7 @@ export default () => (
Next
</KuiButton>
<br />
<br />
<KuiButton
@ -51,6 +55,7 @@ export default () => (
Loading
</KuiButton>
<br />
<br />
<KuiButton

View file

@ -1,64 +0,0 @@
import React from 'react';
import {
KuiButton,
} from '../../../../components';
export default () => (
<div className="kuiToolBar">
<KuiButton buttonType="basic">
Basic button
</KuiButton>
<KuiButton
buttonType="basic"
disabled
>
Basic button, disabled
</KuiButton>
<KuiButton buttonType="primary">
Primary button
</KuiButton>
<KuiButton
buttonType="primary"
disabled
>
Primary button, disabled
</KuiButton>
<KuiButton buttonType="secondary">
Secondary button
</KuiButton>
<KuiButton
buttonType="secondary"
disabled
>
Secondary button, disabled
</KuiButton>
<KuiButton buttonType="danger">
Danger button
</KuiButton>
<KuiButton
buttonType="danger"
disabled
>
Danger button, disabled
</KuiButton>
<KuiButton buttonType="warning">
Warning button
</KuiButton>
<KuiButton
buttonType="warning"
disabled
>
Warning button, disabled
</KuiButton>
</div>
);

View file

@ -1,6 +1,6 @@
import React from 'react';
import { KuiColorPicker } from '../../../../components/index';
import { KuiColorPicker } from '../../../../components';
export class ColorPicker extends React.Component {
constructor(props) {

View file

@ -5,7 +5,7 @@ import {
KuiFieldGroup,
KuiFieldGroupSection,
KuiKeyboardAccessible,
} from '../../../../components/index';
} from '../../../../components';
export class ColorPickerLabelAndClear extends React.Component {
constructor(props) {

View file

@ -4,7 +4,7 @@ import {
KuiColorPicker,
KuiFieldGroup,
KuiFieldGroupSection,
} from '../../../../components/index';
} from '../../../../components';
export class ColorPickerNoColorLabel extends React.Component {
constructor(props) {

View file

@ -20,11 +20,11 @@ export default () => {
return (
<div>
<div className="kuiVerticalRhythm">
<h2 className="kuiSubTitle">
<h2 className="kuiSubTitle kuiVerticalRhythmSmall">
Some items
</h2>
<KuiGallery>
<KuiGallery className="kuiVerticalRhythmSmall">
<KuiGalleryButton href="#">
<KuiGalleryButtonImage style={imageStyle}/>
@ -70,11 +70,11 @@ export default () => {
</div>
<div className="kuiVerticalRhythm">
<div className="kuiSubTitle">
<div className="kuiSubTitle kuiVerticalRhythmSmall">
Some more items
</div>
<KuiGallery>
<KuiGallery className="kuiVerticalRhythmSmall">
<KuiGalleryButton href="#">
<KuiGalleryButtonImage style={imageStyle}/>

View file

@ -4,7 +4,7 @@ import {
KuiConfirmModal,
KuiModalOverlay,
KuiButton
} from '../../../../components/index';
} from '../../../../components';
export class ConfirmModalExample extends React.Component {
constructor(props) {

View file

@ -9,17 +9,14 @@ import {
GuideSectionTypes,
} from '../../components';
import {
KuiConfirmModal,
} from '../../../../components';
import { StaticConfirmModal } from './static';
const staticConfirmModalSource = require('!!raw!./static');
const staticConfirmModalHtml = renderToHtml(StaticConfirmModal);
import { ConfirmModalExample } from './confirm_modal_example';
const showConfirmModalSource = require('!!raw!./confirm_modal_example');
const showConfirmModalHtml = renderToHtml(ConfirmModalExample);
const kuiConfirmModalSource = require('!!raw!../../../../components/modal/confirm_modal');
const kuiConfirmModalHtml = renderToHtml(KuiConfirmModal);
export default props => (
<GuidePage title={props.route.name}>
@ -27,21 +24,14 @@ export default props => (
title="Confirmation Modal"
source={[{
type: GuideSectionTypes.JS,
code: kuiConfirmModalSource,
code: staticConfirmModalSource,
}, {
type: GuideSectionTypes.HTML,
code: kuiConfirmModalHtml,
code: staticConfirmModalHtml,
}]}
>
<GuideDemo>
<KuiConfirmModal
onCancel={() => {}}
onConfirm={() => {}}
confirmButtonText="Confirm"
cancelButtonText="Cancel"
message="This is a confirmation modal"
title="Confirm Modal Title"
/>
<StaticConfirmModal />
</GuideDemo>
</GuideSection>

View file

@ -0,0 +1,16 @@
import React from 'react';
import {
KuiConfirmModal,
} from '../../../../components';
export const StaticConfirmModal = () => (
<KuiConfirmModal
onCancel={() => {}}
onConfirm={() => {}}
confirmButtonText="Confirm"
cancelButtonText="Cancel"
message="This is a confirmation modal"
title="Confirm Modal Title"
/>
);

View file

@ -0,0 +1,28 @@
const Generator = require('yeoman-generator');
const componentGenerator = require.resolve('../component/index.js');
module.exports = class extends Generator {
prompting() {
return this.prompt([{
message: 'What do you want to create?',
name: 'fileType',
type: 'list',
choices: [{
name: 'Stateless function',
value: 'function',
}, {
name: 'Component class',
value: 'component',
}],
}]).then(answers => {
this.config = answers;
});
}
writing() {
this.composeWith(componentGenerator, {
fileType: this.config.fileType,
});
}
}

View file

@ -0,0 +1,31 @@
const Generator = require('yeoman-generator');
const documentationGenerator = require.resolve('../documentation/index.js');
module.exports = class extends Generator {
prompting() {
return this.prompt([{
message: 'What do you want to create?',
name: 'fileType',
type: 'list',
choices: [{
name: 'Page',
value: 'documentation',
}, {
name: 'Page demo',
value: 'demo',
}, {
name: 'Sandbox',
value: 'sandbox',
}],
}]).then(answers => {
this.config = answers;
});
}
writing() {
this.composeWith(documentationGenerator, {
fileType: this.config.fileType,
});
}
}

View file

@ -0,0 +1,141 @@
const chalk = require('chalk');
const Generator = require('yeoman-generator');
const utils = require('../utils');
module.exports = class extends Generator {
constructor(args, options) {
super(args, options);
this.fileType = options.fileType;
}
prompting() {
return this.prompt([{
message: 'What\'s the name of this component? Use snake_case, please.',
name: 'name',
type: 'input',
}, {
message: `Where do you want to create this component's files?`,
type: 'input',
name: 'path',
default: 'ui_framework/src/components',
store: true,
}, {
message: 'Does it need its own directory?',
name: 'shouldMakeDirectory',
type: 'confirm',
default: true,
}]).then(answers => {
this.config = answers;
});
}
writing() {
const config = this.config;
const writeComponent = isStatelessFunction => {
const componentName = utils.makeComponentName(config.name);
const cssClassName = utils.lowerCaseFirstLetter(componentName);
const fileName = config.name;
const path = utils.addDirectoryToPath(
config.path, fileName, config.shouldMakeDirectory);
const vars = config.vars = {
componentName,
cssClassName,
fileName,
};
const componentPath = config.componentPath = `${path}/${fileName}.js`;
const testPath = config.testPath = `${path}/${fileName}.test.js`;
const stylesPath = config.stylesPath = `${path}/_${fileName}.scss`;
config.stylesImportPath = `./_${fileName}.scss`;
// If it needs its own directory then it will need a root index file too.
if (this.config.shouldMakeDirectory) {
this.fs.copyTpl(
this.templatePath('_index.scss'),
this.destinationPath(`${path}/_index.scss`),
vars
);
this.fs.copyTpl(
this.templatePath('index.js'),
this.destinationPath(`${path}/index.js`),
vars
);
}
// Create component file.
this.fs.copyTpl(
isStatelessFunction ?
this.templatePath('stateless_function.js') :
this.templatePath('component.js'),
this.destinationPath(componentPath),
vars
);
// Create component test file.
this.fs.copyTpl(
this.templatePath('test.js'),
this.destinationPath(testPath),
vars
);
// Create component styles file.
this.fs.copyTpl(
this.templatePath('_component.scss'),
this.destinationPath(stylesPath),
vars
);
};
switch (this.fileType) {
case 'component':
writeComponent();
break;
case 'function':
writeComponent(true);
break;
}
}
end() {
const showImportComponentSnippet = () => {
const componentName = this.config.vars.componentName;
const componentPath = this.config.componentPath;
this.log(chalk.white(`\n// Export component (e.. from component's index.js).`));
this.log(
`${chalk.magenta('export')} {\n` +
` ${componentName},\n` +
`} ${chalk.magenta('from')} ${chalk.cyan(`'./${this.config.name}'`)};`
);
this.log(chalk.white('\n// Import styles.'));
this.log(
`${chalk.magenta('@import')} ${chalk.cyan(`'${this.config.name}'`)};`
);
this.log(chalk.white('\n// Import component styles into the root index.scss.'));
this.log(
`${chalk.magenta('@import')} ${chalk.cyan(`'./${this.config.name}/index'`)};`
);
};
this.log('------------------------------------------------');
this.log(chalk.bold('Handy snippets:'));
switch (this.fileType) {
case 'component':
showImportComponentSnippet();
break;
case 'function':
showImportComponentSnippet();
break;
}
this.log('------------------------------------------------');
}
}

View file

@ -0,0 +1,3 @@
.<%= cssClassName %> {
}

View file

@ -0,0 +1 @@
@import '<%= fileName %>';

View file

@ -0,0 +1,35 @@
import React, {
Component,
} from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
export class <%= componentName %> extends Component {
static propTypes = {
children: PropTypes.node,
className: PropTypes.string,
}
constructor(props) {
super(props);
}
render() {
const {
children,
className,
...rest,
} = this.props;
const classes = classNames('<%= cssClassName %>', className);
return (
<div
className={classes}
{...rest}
>
{children}
</div>
);
}
}

View file

@ -0,0 +1 @@
export { <%= componentName %> } from './<%= fileName %>';

View file

@ -0,0 +1,21 @@
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
export const <%= componentName %> = ({ children, className, ...rest }) => {
const classes = classNames('<%= cssClassName %>', className);
return (
<div
className={classes}
{...rest}
>
{children}
</div>
);
};
<%= componentName %>.propTypes = {
children: PropTypes.node,
className: PropTypes.string,
};

View file

@ -0,0 +1,16 @@
import React from 'react';
import { render } from 'enzyme';
import { requiredProps } from '../../test/required_props';
import { <%= componentName %> } from './<%= fileName %>';
describe('<%= componentName %>', () => {
test('is rendered', () => {
const component = render(
<<%= componentName %> { ...requiredProps } />
);
expect(component)
.toMatchSnapshot();
});
});

View file

@ -0,0 +1,217 @@
const chalk = require('chalk');
const Generator = require('yeoman-generator');
const utils = require('../utils');
const DOCUMENTATION_PAGE_PATH = 'ui_framework/doc_site/src/views';
module.exports = class extends Generator {
constructor(args, options) {
super(args, options);
this.fileType = options.fileType;
}
prompting() {
let prompts = [{
message: 'What\'s the name of the component you\'re documenting? Use snake_case, please.',
name: 'name',
type: 'input',
store: true,
}];
if (this.fileType === 'demo') {
prompts.push({
message: `What's the name of the directory this demo should go in? (Within ui_framework/doc_site/src/views). Use snake_case, please.`,
name: 'folderName',
type: 'input',
store: true,
default: answers => answers.name,
});
prompts.push({
message: 'What would you like to name this demo? Use snake_case, please.',
name: 'demoName',
type: 'input',
store: true,
});
}
return this.prompt(prompts).then(answers => {
this.config = answers;
});
}
writing() {
const config = this.config;
const writeDocumentationPage = () => {
const componentExampleName = utils.makeComponentName(config.name, false);
const componentExamplePrefix = utils.lowerCaseFirstLetter(componentExampleName);
const fileName = config.name;
const path = DOCUMENTATION_PAGE_PATH;
const vars = config.documentationVars = {
componentExampleName,
componentExamplePrefix,
fileName,
};
const documentationPagePath
= config.documentationPagePath
= `${path}/${config.name}/${config.name}_example.js`;
this.fs.copyTpl(
this.templatePath('documentation_page.js'),
this.destinationPath(documentationPagePath),
vars
);
};
const writeDocumentationPageDemo = (fileName, folderName) => {
const componentExampleName = utils.makeComponentName(fileName, false);
const componentExamplePrefix = utils.lowerCaseFirstLetter(componentExampleName);
const componentName = utils.makeComponentName(config.name);
const path = DOCUMENTATION_PAGE_PATH;
const vars = config.documentationVars = {
componentExampleName,
componentExamplePrefix,
componentName,
fileName,
};
const documentationPageDemoPath
= config.documentationPageDemoPath
= `${path}/${folderName}/${fileName}.js`;
this.fs.copyTpl(
this.templatePath('documentation_page_demo.js'),
this.destinationPath(documentationPageDemoPath),
vars
);
};
const writeSandbox = () => {
const fileName = config.name;
const componentExampleName = utils.makeComponentName(fileName, false);
const path = DOCUMENTATION_PAGE_PATH;
const vars = config.documentationVars = {
componentExampleName,
fileName,
};
const sandboxPath
= config.documentationPageDemoPath
= `${path}/${config.name}/${fileName}`;
this.fs.copyTpl(
this.templatePath('documentation_sandbox.html'),
this.destinationPath(`${sandboxPath}_sandbox.html`)
);
this.fs.copyTpl(
this.templatePath('documentation_sandbox.js'),
this.destinationPath(`${sandboxPath}_sandbox.js`),
vars
);
};
switch (this.fileType) {
case 'documentation':
writeDocumentationPage();
writeDocumentationPageDemo(config.name, config.name);
break;
case 'demo':
writeDocumentationPageDemo(config.demoName, config.folderName);
break;
case 'sandbox':
writeSandbox();
break;
}
}
end() {
const showImportDemoSnippet = () => {
const {
componentExampleName,
componentExamplePrefix,
fileName,
} = this.config.documentationVars;
this.log(chalk.white('\n// Import demo into example.'));
this.log(
`${chalk.magenta('import')} ${componentExampleName} from ${chalk.cyan(`'./${fileName}'`)};\n` +
`${chalk.magenta('const')} ${componentExamplePrefix}Source = require(${chalk.cyan(`'!!raw!./${fileName}'`)});\n` +
`${chalk.magenta('const')} ${componentExamplePrefix}Html = renderToHtml(${componentExampleName});`
);
this.log(chalk.white('\n// Render demo.'));
this.log(
`<GuideSection\n` +
` title="${componentExampleName}"\n` +
` source={[{\n` +
` type: GuideSectionTypes.JS,\n` +
` code: ${componentExamplePrefix}Source,\n` +
` }, {\n` +
` type: GuideSectionTypes.HTML,\n` +
` code: ${componentExamplePrefix}Html,\n` +
` }]}\n` +
`>\n` +
` <GuideText>\n` +
` Description needed: how to use the ${componentExampleName} component.\n` +
` </GuideText>\n` +
`\n` +
` <GuideDemo>\n` +
` <${componentExampleName} />\n` +
` </GuideDemo>\n` +
`</GuideSection>\n`
);
};
const showImportRouteSnippet = (suffix, appendToRoute) => {
const {
componentExampleName,
fileName,
} = this.config.documentationVars;
this.log(chalk.white('\n// Import example into routes.js.'));
this.log(
`${chalk.magenta('import')} ${componentExampleName}${suffix}\n` +
` ${chalk.magenta('from')} ${chalk.cyan(`'../../views/${fileName}/${fileName}_${suffix.toLowerCase()}'`)};`
);
this.log(chalk.white('\n// Import route definition into routes.js.'));
this.log(
`{\n` +
` name: ${chalk.cyan(`'${componentExampleName}${appendToRoute ? suffix : ''}'`)},\n` +
` component: ${componentExampleName}${suffix},\n` +
` hasReact: ${chalk.magenta('true')},\n` +
`}`
);
}
this.log('------------------------------------------------');
this.log(chalk.bold('Import snippets:'));
switch (this.fileType) {
case 'documentation':
showImportRouteSnippet('Example');
break;
case 'demo':
showImportDemoSnippet();
break;
case 'sandbox':
showImportRouteSnippet('Sandbox', true);
break;
}
this.log('------------------------------------------------');
}
}

View file

@ -0,0 +1,38 @@
import React from 'react';
import { renderToHtml } from '../../services';
import {
GuideDemo,
GuidePage,
GuideSection,
GuideSectionTypes,
GuideText,
} from '../../components';
import <%= componentExampleName %> from './<%= fileName %>';
const <%= componentExamplePrefix %>Source = require('!!raw!./<%= fileName %>');
const <%= componentExamplePrefix %>Html = renderToHtml(<%= componentExampleName %>);
export default props => (
<GuidePage title={props.route.name}>
<GuideSection
title="<%= componentExampleName %>"
source={[{
type: GuideSectionTypes.JS,
code: <%= componentExamplePrefix %>Source,
}, {
type: GuideSectionTypes.HTML,
code: <%= componentExamplePrefix %>Html,
}]}
>
<GuideText>
Description needed: how to use the <%= componentExampleName %> component.
</GuideText>
<GuideDemo>
<<%= componentExampleName %> />
</GuideDemo>
</GuideSection>
</GuidePage>
);

View file

@ -0,0 +1,11 @@
import React from 'react';
import {
<%= componentName %>,
} from '../../../../components';
export default () => (
<<%= componentName %>>
</<%= componentName %>>
);

View file

@ -0,0 +1 @@
<p>Do whatever you want here!</p>

View file

@ -0,0 +1,27 @@
import React from 'react';
import {
GuideDemo,
GuideSandbox,
GuideSandboxCodeToggle,
GuideSectionTypes,
} from '../../components';
const html = require('./<%= fileName %>_sandbox.html');
export default props => (
<GuideSandbox>
<GuideDemo
isFullScreen={true}
html={html}
/>
<GuideSandboxCodeToggle
source={[{
type: GuideSectionTypes.HTML,
code: html,
}]}
title={props.route.name}
/>
</GuideSandbox>
);

View file

@ -0,0 +1,35 @@
function makeComponentName(str, usePrefix = true) {
const words = str.split('_');
const componentName = words.map(function(word) {
return upperCaseFirstLetter(word);
}).join('');
return `${usePrefix ? 'Kui' : ''}${componentName}`;
}
function lowerCaseFirstLetter(str) {
return str.replace(/\w\S*/g, function(txt) {
return txt.charAt(0).toLowerCase() + txt.substr(1);
});
}
function upperCaseFirstLetter(str) {
return str.replace(/\w\S*/g, function(txt) {
return txt.charAt(0).toUpperCase() + txt.substr(1);
});
}
function addDirectoryToPath(path, dirName, shouldMakeDirectory) {
if (shouldMakeDirectory) {
return path + '/' + dirName;
}
return path;
}
module.exports = {
makeComponentName: makeComponentName,
lowerCaseFirstLetter: lowerCaseFirstLetter,
upperCaseFirstLetter: upperCaseFirstLetter,
addDirectoryToPath: addDirectoryToPath,
};

View file

@ -1,11 +1 @@
export {
accessibleClickKeys,
comboBoxKeyCodes,
ENTER_KEY,
SPACE_KEY,
} from './accessibility';
export { SortableProperties } from './sort';
export { ESC_KEY_CODE } from './key_codes';
export { LEFT_ALIGNMENT, RIGHT_ALIGNMENT } from './alignment';
export * from '../src/services';

View file

@ -0,0 +1 @@
@import "screen_reader";

Some files were not shown because too many files have changed in this diff Show more