diff --git a/ui_framework/dist/ui_framework.css b/ui_framework/dist/ui_framework.css index 9118d6cde00a6..e60e3e7b70abf 100644 --- a/ui_framework/dist/ui_framework.css +++ b/ui_framework/dist/ui_framework.css @@ -83,7 +83,8 @@ button { border: none; padding: 0; margin: 0; - outline: none; } + outline: none; + font-size: 16px; } button:hover { cursor: pointer; } @@ -335,6 +336,152 @@ table { width: 64px; height: 64px; } +.kuiButton { + display: inline-block; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + cursor: pointer; + height: 40px; + text-decoration: none; + border: solid 1px #0079a5; + border-radius: 4px; + color: #0079a5; + padding: 0 8px; + min-width: 112px; + text-align: center; + font-family: "Roboto", Helvetica, Arial, sans-serif; + transition: all 250ms cubic-bezier(0.34, 1.61, 0.7, 1); + whitespace: nowrap; } + .kuiButton.kuiButton--small { + height: 32px; } + .kuiButton .kuiButton__icon { + vertical-align: -2px; + fill: #0079a5; } + .kuiButton .kuiButton__content { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -webkit-align-items: center; + -ms-flex-align: center; + align-items: center; } + .kuiButton .kuiButton__content > * + * { + margin-left: 8px; } + .kuiButton:hover, .kuiButton:focus { + text-decoration: underline; + background-color: rgba(0, 121, 165, 0.1); } + .kuiButton:focus { + -webkit-animation: kuiButtonFocus 250ms cubic-bezier(0.34, 1.61, 0.7, 1); + animation: kuiButtonFocus 250ms cubic-bezier(0.34, 1.61, 0.7, 1); } + .kuiButton.kuiButton--fill { + background-color: #0079a5; + color: #FFF; + border-color: #0079a5; } + .kuiButton.kuiButton--fill:hover, .kuiButton.kuiButton--fill:focus { + background-color: #00668c; + border-color: #00668c; } + .kuiButton.kuiButton--fill .kuiButton__icon { + fill: #FFF; } + .kuiButton.kuiButton--reverse .kuiButton__content { + -webkit-box-orient: horizontal; + -webkit-box-direction: reverse; + -webkit-flex-direction: row-reverse; + -ms-flex-direction: row-reverse; + flex-direction: row-reverse; } + .kuiButton.kuiButton--reverse .kuiButton__content > * + * { + margin-left: 0; + margin-right: 8px; } + +.kuiButton--secondary { + color: #00A69B; + border-color: #00A69B; } + .kuiButton--secondary .kuiButton__icon { + fill: #00A69B; } + .kuiButton--secondary:hover, .kuiButton--secondary:focus { + background-color: rgba(0, 166, 155, 0.1); } + .kuiButton--secondary.kuiButton--fill { + background-color: #00A69B; + color: #FFF; + border-color: #00A69B; } + .kuiButton--secondary.kuiButton--fill:hover, .kuiButton--secondary.kuiButton--fill:focus { + background-color: #008d83; + border-color: #008d83; } + .kuiButton--secondary.kuiButton--fill .kuiButton__icon { + fill: #FFF; } + +.kuiButton--danger { + color: #A30000; + border-color: #A30000; } + .kuiButton--danger .kuiButton__icon { + fill: #A30000; } + .kuiButton--danger:hover, .kuiButton--danger:focus { + background-color: rgba(163, 0, 0, 0.1); } + .kuiButton--danger.kuiButton--fill { + background-color: #A30000; + color: #FFF; + border-color: #A30000; } + .kuiButton--danger.kuiButton--fill:hover, .kuiButton--danger.kuiButton--fill:focus { + background-color: #8a0000; + border-color: #8a0000; } + .kuiButton--danger.kuiButton--fill .kuiButton__icon { + fill: #FFF; } + +.kuiButton--warning { + color: #E5830E; + border-color: #E5830E; } + .kuiButton--warning .kuiButton__icon { + fill: #E5830E; } + .kuiButton--warning:hover, .kuiButton--warning:focus { + background-color: rgba(229, 131, 14, 0.1); } + .kuiButton--warning.kuiButton--fill { + background-color: #E5830E; + color: #FFF; + border-color: #E5830E; } + .kuiButton--warning.kuiButton--fill:hover, .kuiButton--warning.kuiButton--fill:focus { + background-color: #cd750d; + border-color: #cd750d; } + .kuiButton--warning.kuiButton--fill .kuiButton__icon { + fill: #FFF; } + +.kuiButton--disabled { + color: #c5c5c5; + border-color: #c5c5c5; } + .kuiButton--disabled .kuiButton__icon { + fill: #c5c5c5; } + .kuiButton--disabled:hover, .kuiButton--disabled:focus { + background-color: rgba(197, 197, 197, 0.1); + cursor: not-allowed; } + .kuiButton--disabled.kuiButton--fill { + background-color: #c5c5c5; + color: #FFF; + border-color: #c5c5c5; } + .kuiButton--disabled.kuiButton--fill:hover, .kuiButton--disabled.kuiButton--fill:focus { + background-color: #b8b8b8; + border-color: #b8b8b8; } + .kuiButton--disabled.kuiButton--fill .kuiButton__icon { + fill: #FFF; } + +@-webkit-keyframes kuiButtonFocus { + 50% { + -webkit-transform: translateY(2px); + transform: translateY(2px); } } + +@keyframes kuiButtonFocus { + 50% { + -webkit-transform: translateY(2px); + transform: translateY(2px); } } + .kuiHeader { display: -webkit-box; display: -webkit-flex; @@ -1026,3 +1173,259 @@ table { line-height: 24px; color: #3F3F3F; font-weight: 400; } + +.kuiLoadingKibana { + position: relative; + display: inline-block; } + .kuiLoadingKibana:before, .kuiLoadingKibana:after { + position: absolute; + content: ""; + width: 90%; + left: 50%; + -webkit-transform: translateX(-50%); + transform: translateX(-50%); + border-radius: 50%; + opacity: 0.2; + -webkit-transform-origin: -50% -50%; + transform-origin: -50% -50%; + z-index: 1; } + .kuiLoadingKibana:before { + box-shadow: 0 0 8px #000; + -webkit-animation: 1s kuiLoadingKibanaPulsateAndFade cubic-bezier(0.694, 0.0482, 0.335, 1) infinite; + animation: 1s kuiLoadingKibanaPulsateAndFade cubic-bezier(0.694, 0.0482, 0.335, 1) infinite; } + .kuiLoadingKibana:after { + background-color: #000; + -webkit-animation: 1s kuiLoadingKibanaPulsate cubic-bezier(0.694, 0.0482, 0.335, 1) infinite; + animation: 1s kuiLoadingKibanaPulsate cubic-bezier(0.694, 0.0482, 0.335, 1) infinite; } + +/** + * 1. Requires pixel math for animation. + */ +.kuiLoadingKibana--medium:before, .kuiLoadingKibana--medium:after { + height: 3px; + /* 1 */ + bottom: -4px; } + +.kuiLoadingKibana--medium .kuiLoadingKibana__icon { + z-index: 999; + -webkit-animation: 1s kuiLoadingKibanaBounceMedium cubic-bezier(0.694, 0.0482, 0.335, 1) infinite; + animation: 1s kuiLoadingKibanaBounceMedium cubic-bezier(0.694, 0.0482, 0.335, 1) infinite; } + +/** + * 1. Requires pixel math for animation. + */ +.kuiLoadingKibana--large:before, .kuiLoadingKibana--large:after { + height: 6px; + /* 1 */ + bottom: -8px; } + +.kuiLoadingKibana--large .kuiLoadingKibana__icon { + -webkit-animation: 1s kuiLoadingKibanaBounceLarge cubic-bezier(0.694, 0.0482, 0.335, 1) infinite; + animation: 1s kuiLoadingKibanaBounceLarge cubic-bezier(0.694, 0.0482, 0.335, 1) infinite; } + +.kuiLoadingKibana--xLarge:before, .kuiLoadingKibana--xLarge:after { + height: 8px; + bottom: -12px; } + +.kuiLoadingKibana--xLarge .kuiLoadingKibana__icon { + -webkit-animation: 1s kuiLoadingKibanaBounceXLarge cubic-bezier(0.694, 0.0482, 0.335, 1) infinite; + animation: 1s kuiLoadingKibanaBounceXLarge cubic-bezier(0.694, 0.0482, 0.335, 1) infinite; } + +@-webkit-keyframes kuiLoadingKibanaBounceMedium { + 50% { + -webkit-transform: translateY(-8px); + transform: translateY(-8px); } } + +@keyframes kuiLoadingKibanaBounceMedium { + 50% { + -webkit-transform: translateY(-8px); + transform: translateY(-8px); } } + +@-webkit-keyframes kuiLoadingKibanaBounceLarge { + 50% { + -webkit-transform: translateY(-12px); + transform: translateY(-12px); } } + +@keyframes kuiLoadingKibanaBounceLarge { + 50% { + -webkit-transform: translateY(-12px); + transform: translateY(-12px); } } + +@-webkit-keyframes kuiLoadingKibanaBounceXLarge { + 50% { + -webkit-transform: translateY(-16px); + transform: translateY(-16px); } } + +@keyframes kuiLoadingKibanaBounceXLarge { + 50% { + -webkit-transform: translateY(-16px); + transform: translateY(-16px); } } + +@-webkit-keyframes kuiLoadingKibanaPulsateAndFade { + 0% { + opacity: 0; } + 50% { + -webkit-transform: scale(0.5); + transform: scale(0.5); + opacity: 0.1; } + 100% { + opacity: 0; } } + +@keyframes kuiLoadingKibanaPulsateAndFade { + 0% { + opacity: 0; } + 50% { + -webkit-transform: scale(0.5); + transform: scale(0.5); + opacity: 0.1; } + 100% { + opacity: 0; } } + +@-webkit-keyframes kuiLoadingKibanaPulsate { + 0% { + opacity: 0.15; } + 50% { + -webkit-transform: scale(0.5); + transform: scale(0.5); + opacity: 0.05; } + 100% { + opacity: 0.15; } } + +@keyframes kuiLoadingKibanaPulsate { + 0% { + opacity: 0.15; } + 50% { + -webkit-transform: scale(0.5); + transform: scale(0.5); + opacity: 0.05; } + 100% { + opacity: 0.15; } } + +.kuiLoadingChart { + height: 32px; + z-index: 500; + overflow: hidden; + display: inline-block; } + +.kuiLoadingChart__bar { + height: 100%; + width: 8px; + display: inline-block; + float: left; + margin-bottom: -16px; + margin-left: 2px; + -webkit-animation: kuiLoadingChart 1s infinite; + animation: kuiLoadingChart 1s infinite; } + .kuiLoadingChart__bar:nth-child(1) { + background-color: #0079a5; } + .kuiLoadingChart__bar:nth-child(2) { + background-color: #00A69B; + -webkit-animation-delay: .1s; + animation-delay: .1s; } + .kuiLoadingChart__bar:nth-child(3) { + background-color: #DD0A73; + -webkit-animation-delay: .2s; + animation-delay: .2s; } + .kuiLoadingChart__bar:nth-child(4) { + background-color: #3F3F3F; + -webkit-animation-delay: .3s; + animation-delay: .3s; } + +.kuiLoadingChart--mono .kuiLoadingChart__bar:nth-child(1) { + background-color: #D9D9D9; } + +.kuiLoadingChart--mono .kuiLoadingChart__bar:nth-child(2) { + background-color: #cfcfcf; } + +.kuiLoadingChart--mono .kuiLoadingChart__bar:nth-child(3) { + background-color: #c5c5c5; } + +.kuiLoadingChart--mono .kuiLoadingChart__bar:nth-child(4) { + background-color: #bababa; } + +.kuiLoadingChart--medium { + height: 16px; } + .kuiLoadingChart--medium > div { + width: 2px; + margin-left: 2px; + margin-bottom: 8px; } + +.kuiLoadingChart--large { + height: 24px; } + .kuiLoadingChart--large > div { + width: 4px; + margin-left: 2px; + margin-bottom: 12px; } + +.kuiLoadingChart--xLarge { + height: 32px; } + .kuiLoadingChart--xLarge > div { + width: 8px; + margin-left: 4px; + margin-bottom: 16px; } + +@-webkit-keyframes kuiLoadingChart { + 0% { + -webkit-transform: translateY(0); + transform: translateY(0); } + 50% { + -webkit-transform: translateY(66%); + transform: translateY(66%); } + 100% { + -webkit-transform: translateY(0); + transform: translateY(0); } } + +@keyframes kuiLoadingChart { + 0% { + -webkit-transform: translateY(0); + transform: translateY(0); } + 50% { + -webkit-transform: translateY(66%); + transform: translateY(66%); } + 100% { + -webkit-transform: translateY(0); + transform: translateY(0); } } + +.kuiLoadingSpinner { + display: inline-block; + width: 32px; + height: 32px; + border-radius: 50%; + border: solid 2px #D9D9D9; + border-top-color: #0079a5; + -webkit-animation: kuiLoadingSpinner .6s infinite linear; + animation: kuiLoadingSpinner .6s infinite linear; } + +.kuiLoadingSpinner--small { + width: 8px; + height: 8px; + border-width: 1px; } + +.kuiLoadingSpinner--medium { + width: 16px; + height: 16px; + border-width: 1px; } + +.kuiLoadingSpinner--large { + width: 24px; + height: 24px; } + +.kuiLoadingSpinner--xLarge { + width: 32px; + height: 32px; } + +@-webkit-keyframes kuiLoadingSpinner { + from { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); } + to { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); } } + +@keyframes kuiLoadingSpinner { + from { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); } + to { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); } } diff --git a/ui_framework/doc_site/src/services/routes/routes.js b/ui_framework/doc_site/src/services/routes/routes.js index 7a1db30478397..9f4fbded3afab 100644 --- a/ui_framework/doc_site/src/services/routes/routes.js +++ b/ui_framework/doc_site/src/services/routes/routes.js @@ -3,6 +3,9 @@ import Slugify from '../string/slugify'; import AccessibilityExample from '../../views/accessibility/accessibility_example'; +import ButtonExample + from '../../views/button/button_example'; + import IconExample from '../../views/icon/icon_example'; @@ -24,6 +27,9 @@ import ModalExample import PageExample from '../../views/page/page_example'; +import LoadingExample + from '../../views/loading/loading_example'; + import PopoverExample from '../../views/popover/popover_example'; @@ -38,6 +44,10 @@ const components = [{ name: 'Accessibility', component: AccessibilityExample, hasReact: true, +}, { + name: 'Button', + component: ButtonExample, + hasReact: true, }, { name: 'Icon', component: IconExample, @@ -62,6 +72,10 @@ const components = [{ name: 'Page', component: PageExample, hasReact: true, +}, { + name: 'Loading', + component: LoadingExample, + hasReact: true, }, { name: 'Popover', component: PopoverExample, diff --git a/ui_framework/doc_site/src/views/button/button.js b/ui_framework/doc_site/src/views/button/button.js new file mode 100644 index 0000000000000..1f4f2a9fd0e2b --- /dev/null +++ b/ui_framework/doc_site/src/views/button/button.js @@ -0,0 +1,208 @@ +import React from 'react'; + +import { + KuiButton, +} from '../../../../components/'; + +export default () => ( +
+ window.alert('Button clicked')} + > + Default + + +    + + window.alert('Button clicked')} + > + Filled + + +    + + window.alert('Button clicked')} + > + small + + +    + + window.alert('Button clicked')} + > + small and filled + + +

+ + window.alert('Button clicked')} + > + Secondary + + +    + + window.alert('Button clicked')} + > + Filled + + +    + + window.alert('Button clicked')} + > + small + + +    + + window.alert('Button clicked')} + > + small and filled + + +

+ + window.alert('Button clicked')} + > + Warning + + +    + + window.alert('Button clicked')} + > + Filled + + +    + + window.alert('Button clicked')} + > + small + + +    + + window.alert('Button clicked')} + > + small and filled + + +

+ + window.alert('Button clicked')} + > + Danger + + +    + + window.alert('Button clicked')} + > + Filled + + +    + + window.alert('Button clicked')} + > + small + + +    + + window.alert('Button clicked')} + > + small and filled + + +

+ + window.alert('Button clicked')} + > + Disabled + + +    + + window.alert('Button clicked')} + > + Filled + + +    + + window.alert('Button clicked')} + > + small + + +    + + window.alert('Button clicked')} + > + small and filled + + +
+); diff --git a/ui_framework/doc_site/src/views/button/button_example.js b/ui_framework/doc_site/src/views/button/button_example.js new file mode 100644 index 0000000000000..89b716e9d28d0 --- /dev/null +++ b/ui_framework/doc_site/src/views/button/button_example.js @@ -0,0 +1,63 @@ +import React from 'react'; + +import { renderToHtml } from '../../services'; + +import { + GuideCode, + GuideDemo, + GuidePage, + GuideSection, + GuideSectionTypes, + GuideText, +} from '../../components'; + +import Button from './button'; +const buttonSource = require('!!raw!./button'); +const buttonHtml = renderToHtml(Button); + +import ButtonWithIcon from './button_with_icon'; +const buttonWithIconSource = require('!!raw!./button_with_icon'); +const buttonWithIconHtml = renderToHtml(Button); + +export default props => ( + + + + Button type defines the color of the button. + fill can be optionally added to add more focus to an action. + + + + + ); + } +} + +KuiButton.propTypes = { + iconReverse: React.PropTypes.bool, + fill: React.PropTypes.bool, + type: PropTypes.oneOf(TYPES), + size: PropTypes.oneOf(SIZES), +}; + +KuiButton.defaultProps = { + iconReverse: false, + fill: false, +}; diff --git a/ui_framework/src/components/button/button.test.js b/ui_framework/src/components/button/button.test.js new file mode 100644 index 0000000000000..cdeb380962ae6 --- /dev/null +++ b/ui_framework/src/components/button/button.test.js @@ -0,0 +1,16 @@ +import React from 'react'; +import { render } from 'enzyme'; +import { requiredProps } from '../../test/required_props'; + +import { KuiButton } from './button'; + +describe('KuiButton', () => { + test('is rendered', () => { + const component = render( + + ); + + expect(component) + .toMatchSnapshot(); + }); +}); diff --git a/ui_framework/src/components/button/index.js b/ui_framework/src/components/button/index.js new file mode 100644 index 0000000000000..6d691b194280d --- /dev/null +++ b/ui_framework/src/components/button/index.js @@ -0,0 +1 @@ +export { KuiButton } from './button'; diff --git a/ui_framework/src/components/icon/assets/arrow_down.svg b/ui_framework/src/components/icon/assets/arrow_down.svg new file mode 100644 index 0000000000000..9acaffeeb0c85 --- /dev/null +++ b/ui_framework/src/components/icon/assets/arrow_down.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/ui_framework/src/components/icon/assets/arrow_left.svg b/ui_framework/src/components/icon/assets/arrow_left.svg new file mode 100644 index 0000000000000..20c9459af317d --- /dev/null +++ b/ui_framework/src/components/icon/assets/arrow_left.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/ui_framework/src/components/icon/assets/arrow_right.svg b/ui_framework/src/components/icon/assets/arrow_right.svg new file mode 100644 index 0000000000000..e5eab7e9aa45a --- /dev/null +++ b/ui_framework/src/components/icon/assets/arrow_right.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/ui_framework/src/components/icon/assets/arrow_up.svg b/ui_framework/src/components/icon/assets/arrow_up.svg new file mode 100644 index 0000000000000..f20652414adeb --- /dev/null +++ b/ui_framework/src/components/icon/assets/arrow_up.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/ui_framework/src/components/icon/icon.js b/ui_framework/src/components/icon/icon.js index 484b635e3429f..dca1f7adf08e5 100644 --- a/ui_framework/src/components/icon/icon.js +++ b/ui_framework/src/components/icon/icon.js @@ -16,6 +16,10 @@ import '!!svg-sprite!./assets/search.svg'; import '!!svg-sprite!./assets/user.svg'; import '!!svg-sprite!./assets/help.svg'; import '!!svg-sprite!./assets/cross.svg'; +import '!!svg-sprite!./assets/arrow_up.svg'; +import '!!svg-sprite!./assets/arrow_down.svg'; +import '!!svg-sprite!./assets/arrow_left.svg'; +import '!!svg-sprite!./assets/arrow_right.svg'; const humanizeCamelCase = str => ( // Put spaces between words in camel-cased strings. @@ -36,6 +40,10 @@ const typeToIconMap = { user: 'user', help: 'help', cross: 'cross', + arrowUp: 'arrow_up', + arrowDown: 'arrow_down', + arrowLeft: 'arrow_left', + arrowRight: 'arrow_right', }; export const TYPES = Object.keys(typeToIconMap); diff --git a/ui_framework/src/components/index.js b/ui_framework/src/components/index.js index 1c10c22d0e187..989d9c23ec0a5 100644 --- a/ui_framework/src/components/index.js +++ b/ui_framework/src/components/index.js @@ -3,6 +3,10 @@ export { KuiScreenReaderOnly, } from './accessibility'; +export { + KuiButton, +} from './button'; + export { KuiHeader, KuiHeaderBreadcrumb, @@ -18,6 +22,12 @@ export { KuiIcon, } from './icon'; +export { + KuiLoadingKibana, + KuiLoadingChart, + KuiLoadingSpinner, +} from './loading'; + export { KuiKeyPadMenu, KuiKeyPadMenuItem, diff --git a/ui_framework/src/components/index.scss b/ui_framework/src/components/index.scss index 7300853bfc990..89033f800f937 100644 --- a/ui_framework/src/components/index.scss +++ b/ui_framework/src/components/index.scss @@ -2,10 +2,12 @@ // Components @import 'avatar/index'; +@import 'button/index'; @import 'header/index'; @import 'icon/index'; @import 'key_pad_menu/index'; @import 'link/index'; +@import 'loading/index'; @import 'modal/index'; @import 'page/index'; @import 'popover/index'; diff --git a/ui_framework/src/components/loading/_index.scss b/ui_framework/src/components/loading/_index.scss new file mode 100644 index 0000000000000..f2bc4969551c1 --- /dev/null +++ b/ui_framework/src/components/loading/_index.scss @@ -0,0 +1,3 @@ +@import 'loading_kibana'; +@import 'loading_chart'; +@import 'loading_spinner'; diff --git a/ui_framework/src/components/loading/_loading_chart.scss b/ui_framework/src/components/loading/_loading_chart.scss new file mode 100644 index 0000000000000..a367383103010 --- /dev/null +++ b/ui_framework/src/components/loading/_loading_chart.scss @@ -0,0 +1,93 @@ +.kuiLoadingChart { + height: 32px; + z-index: 500; + overflow: hidden; + display: inline-block; +} + +.kuiLoadingChart__bar { + height: 100%; + width: 8px; + display: inline-block; + float: left; + margin-bottom: -16px; + margin-left: 2px; + animation: kuiLoadingChart 1s infinite; + + &:nth-child(1) { + background-color: $kuiColorPrimary; + } + + &:nth-child(2) { + background-color: $kuiColorSecondary; + animation-delay: .1s; + } + + &:nth-child(3) { + background-color: $kuiColorAccent; + animation-delay: .2s; + } + + &:nth-child(4) { + background-color: $kuiColorDarkestShade; + animation-delay: .3s; + } +} + +.kuiLoadingChart--mono { + .kuiLoadingChart__bar { + &:nth-child(1) { + background-color: $kuiColorLightShade; + } + &:nth-child(2) { + background-color: darken($kuiColorLightShade, 4%); + } + &:nth-child(3) { + background-color: darken($kuiColorLightShade, 8%); + } + &:nth-child(4) { + background-color: darken($kuiColorLightShade, 12%); + } + } +} + +.kuiLoadingChart--medium { + height: $kuiSize; + > div { + width: $kuiSizeXS / 2; + margin-left: $kuiSizeXS / 2; + margin-bottom: $kuiSizeS; + } +} + +.kuiLoadingChart--large { + height: $kuiSizeL; + > div { + width: $kuiSizeXS; + margin-left: $kuiSizeXS / 2; + margin-bottom: $kuiSizeL / 2; + } +} + +.kuiLoadingChart--xLarge { + height: $kuiSizeXL; + > div { + width: $kuiSizeS; + margin-left: $kuiSizeXS; + margin-bottom: $kuiSizeXL / 2; + } +} + +@keyframes kuiLoadingChart { + 0% { + transform: translateY(0); + } + + 50% { + transform: translateY(66%); + } + + 100% { + transform: translateY(0); + } +} diff --git a/ui_framework/src/components/loading/_loading_kibana.scss b/ui_framework/src/components/loading/_loading_kibana.scss new file mode 100644 index 0000000000000..ab601fc1f7f6c --- /dev/null +++ b/ui_framework/src/components/loading/_loading_kibana.scss @@ -0,0 +1,115 @@ +.kuiLoadingKibana { + position: relative; + display: inline-block; + + &:before, + &:after { + position: absolute; + content: ""; + width: 90%; + left: 50%; + transform: translateX(-50%); + border-radius: 50%; + opacity: 0.2; + transform-origin: -50% -50%; + z-index: 1; + } + + &:before { + box-shadow: 0 0 8px $kuiColorFullShade; + animation: 1s kuiLoadingKibanaPulsateAndFade $kuiAnimSlightResistance infinite; + } + + &:after { + background-color: $kuiColorFullShade; + animation: 1s kuiLoadingKibanaPulsate $kuiAnimSlightResistance infinite; + } +} + +/** + * 1. Requires pixel math for animation. + */ +.kuiLoadingKibana--medium { + &:before, + &:after { + height: $kuiSizeXS - 1; /* 1 */ + bottom: -$kuiSizeXS; + } + .kuiLoadingKibana__icon { + z-index: 999; + animation: 1s kuiLoadingKibanaBounceMedium $kuiAnimSlightResistance infinite; + } +} + +/** + * 1. Requires pixel math for animation. + */ +.kuiLoadingKibana--large { + &:before, + &:after { + height: $kuiSizeS - 2; /* 1 */ + bottom: -$kuiSizeS; + } + .kuiLoadingKibana__icon { + animation: 1s kuiLoadingKibanaBounceLarge $kuiAnimSlightResistance infinite; + } +} + +.kuiLoadingKibana--xLarge { + &:before, + &:after { + height: $kuiSizeS; + bottom: -($kuiSize - $kuiSizeXS); + } + .kuiLoadingKibana__icon { + animation: 1s kuiLoadingKibanaBounceXLarge $kuiAnimSlightResistance infinite; + } +} + +@keyframes kuiLoadingKibanaBounceMedium { + 50% { + transform: translateY(-$kuiSizeS); + } +} + +@keyframes kuiLoadingKibanaBounceLarge { + 50% { + transform: translateY(-($kuiSize - $kuiSizeXS)); + } +} + +@keyframes kuiLoadingKibanaBounceXLarge { + 50% { + transform: translateY(-$kuiSize); + } +} + +@keyframes kuiLoadingKibanaPulsateAndFade { + 0% { + opacity: 0; + } + + 50% { + transform: scale(0.5); + opacity: 0.1; + } + + 100% { + opacity: 0; + } +} + +@keyframes kuiLoadingKibanaPulsate { + 0% { + opacity: 0.15; + } + + 50% { + transform: scale(0.5); + opacity: 0.05; + } + + 100% { + opacity: 0.15; + } +} diff --git a/ui_framework/src/components/loading/_loading_spinner.scss b/ui_framework/src/components/loading/_loading_spinner.scss new file mode 100644 index 0000000000000..a410e36b14bcc --- /dev/null +++ b/ui_framework/src/components/loading/_loading_spinner.scss @@ -0,0 +1,41 @@ +.kuiLoadingSpinner { + display: inline-block; + width: $kuiSizeXL; + height: $kuiSizeXL; + border-radius: 50%; + border: solid $kuiSizeXS / 2 $kuiColorLightShade; + border-top-color: $kuiColorPrimary; + animation: kuiLoadingSpinner .6s infinite linear; +} + +.kuiLoadingSpinner--small { + width: $kuiSizeS; + height: $kuiSizeS; + border-width: 1px; +} + +.kuiLoadingSpinner--medium { + width: $kuiSize; + height: $kuiSize; + border-width: 1px; +} + +.kuiLoadingSpinner--large { + width: $kuiSizeL; + height: $kuiSizeL; +} + +.kuiLoadingSpinner--xLarge { + width: $kuiSizeXL; + height: $kuiSizeXL; +} + +@keyframes kuiLoadingSpinner { + from { + transform: rotate(0deg); + } + + to { + transform: rotate(359deg); + } +} diff --git a/ui_framework/src/components/loading/index.js b/ui_framework/src/components/loading/index.js new file mode 100644 index 0000000000000..aaee44480a06c --- /dev/null +++ b/ui_framework/src/components/loading/index.js @@ -0,0 +1,3 @@ +export { KuiLoadingKibana } from './loading_kibana'; +export { KuiLoadingChart } from './loading_chart'; +export { KuiLoadingSpinner } from './loading_spinner'; diff --git a/ui_framework/src/components/loading/loading.test.js b/ui_framework/src/components/loading/loading.test.js new file mode 100644 index 0000000000000..c9556d68094b1 --- /dev/null +++ b/ui_framework/src/components/loading/loading.test.js @@ -0,0 +1,16 @@ +import React from 'react'; +import { render } from 'enzyme'; +import { requiredProps } from '../../test/required_props'; + +import { KuiLoading } from './loading'; + +describe('KuiLoading', () => { + test('is rendered', () => { + const component = render( + + ); + + expect(component) + .toMatchSnapshot(); + }); +}); diff --git a/ui_framework/src/components/loading/loading_chart.js b/ui_framework/src/components/loading/loading_chart.js new file mode 100644 index 0000000000000..0c99511b6238d --- /dev/null +++ b/ui_framework/src/components/loading/loading_chart.js @@ -0,0 +1,38 @@ +import React, { + PropTypes, +} from 'react'; +import classNames from 'classnames'; + +const sizeToClassNameMap = { + medium: 'kuiLoadingChart--medium', + large: 'kuiLoadingChart--large', + xLarge: 'kuiLoadingChart--xLarge', +}; + +export const SIZES = Object.keys(sizeToClassNameMap); + +export const KuiLoadingChart = ({ size, mono, className, ...rest }) => { + const classes = classNames( + 'kuiLoadingChart', + mono === true ? 'kuiLoadingChart--mono' : '', + className, + sizeToClassNameMap[size], + ); + + return ( +
+
+
+
+
+
+ ); +}; + +KuiLoadingChart.propTypes = { + size: PropTypes.oneOf(SIZES), +}; + diff --git a/ui_framework/src/components/loading/loading_kibana.js b/ui_framework/src/components/loading/loading_kibana.js new file mode 100644 index 0000000000000..9f1f6f15913b7 --- /dev/null +++ b/ui_framework/src/components/loading/loading_kibana.js @@ -0,0 +1,37 @@ +import React, { + PropTypes, +} from 'react'; +import classNames from 'classnames'; +import { KuiIcon } from '../../components'; + +const sizeToClassNameMap = { + medium: 'kuiLoadingKibana--medium', + large: 'kuiLoadingKibana--large', + xLarge: 'kuiLoadingKibana--xLarge', +}; + +export const SIZES = Object.keys(sizeToClassNameMap); + +export const KuiLoadingKibana = ({ children, size, className, ...rest }) => { + const classes = classNames( + 'kuiLoadingKibana', + sizeToClassNameMap[size], + className, + ); + + return ( +
+
+ +
+ {children} +
+ ); +}; + +KuiLoadingKibana.propTypes = { + size: PropTypes.oneOf(SIZES), +}; diff --git a/ui_framework/src/components/loading/loading_spinner.js b/ui_framework/src/components/loading/loading_spinner.js new file mode 100644 index 0000000000000..79ce2937408c2 --- /dev/null +++ b/ui_framework/src/components/loading/loading_spinner.js @@ -0,0 +1,34 @@ +import React, { + PropTypes, +} from 'react'; +import classNames from 'classnames'; + +const sizeToClassNameMap = { + small: 'kuiLoadingSpinner--small', + medium: 'kuiLoadingSpinner--medium', + large: 'kuiLoadingSpinner--large', + xLarge: 'kuiLoadingSpinner--xLarge', +}; + +export const SIZES = Object.keys(sizeToClassNameMap); + +export const KuiLoadingSpinner = ({ children, size, className, ...rest }) => { + const classes = classNames( + 'kuiLoadingSpinner', + sizeToClassNameMap[size], + className + ); + + return ( +
+ {children} +
+ ); +}; + +KuiLoadingSpinner.propTypes = { + size: PropTypes.oneOf(SIZES), +}; diff --git a/ui_framework/src/components/loading/loading_spinner.test.js b/ui_framework/src/components/loading/loading_spinner.test.js new file mode 100644 index 0000000000000..42695782c9465 --- /dev/null +++ b/ui_framework/src/components/loading/loading_spinner.test.js @@ -0,0 +1,16 @@ +import React from 'react'; +import { render } from 'enzyme'; +import { requiredProps } from '../../test/required_props'; + +import { KuiLoadingSpinner } from './loading_spinner'; + +describe('KuiLoadingSpinner', () => { + test('is rendered', () => { + const component = render( + + ); + + expect(component) + .toMatchSnapshot(); + }); +}); diff --git a/ui_framework/src/global_styling/reset/_reset.scss b/ui_framework/src/global_styling/reset/_reset.scss index 1b6eea587e201..50dbafa4c7950 100644 --- a/ui_framework/src/global_styling/reset/_reset.scss +++ b/ui_framework/src/global_styling/reset/_reset.scss @@ -85,6 +85,7 @@ button { padding: 0; margin: 0; outline: none; + font-size: $kuiFontSize; &:hover { cursor: pointer;