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.
+
+
+
+
+
+
+
+
+ The passed icon needs to come from our list of svg icons. Can be flipped
+ to the other side by passing iconReverse .
+
+
+
+
+
+
+
+);
diff --git a/ui_framework/doc_site/src/views/button/button_with_icon.js b/ui_framework/doc_site/src/views/button/button_with_icon.js
new file mode 100644
index 0000000000000..5cb876123a822
--- /dev/null
+++ b/ui_framework/doc_site/src/views/button/button_with_icon.js
@@ -0,0 +1,92 @@
+import React from 'react';
+
+import {
+ KuiButton,
+} from '../../../../components/';
+
+export default () => (
+
+ window.alert('Button clicked')}
+ icon = "arrowUp"
+ >
+ Default
+
+
+
+
+ window.alert('Button clicked')}
+ >
+ Filled
+
+
+
+
+ window.alert('Button clicked')}
+ >
+ small
+
+
+
+
+ window.alert('Button clicked')}
+ >
+ small and filled
+
+
+
+
+ window.alert('Button clicked')}
+ icon = "arrowUp"
+ >
+ Default
+
+
+
+
+ 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/icon/icons.js b/ui_framework/doc_site/src/views/icon/icons.js
index daea4ecc97bb3..5be1700933e34 100644
--- a/ui_framework/doc_site/src/views/icon/icons.js
+++ b/ui_framework/doc_site/src/views/icon/icons.js
@@ -23,5 +23,21 @@ export default () => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
);
diff --git a/ui_framework/doc_site/src/views/loading/loading_chart.js b/ui_framework/doc_site/src/views/loading/loading_chart.js
new file mode 100644
index 0000000000000..2483dc60cc6d1
--- /dev/null
+++ b/ui_framework/doc_site/src/views/loading/loading_chart.js
@@ -0,0 +1,32 @@
+import React from 'react';
+
+import {
+ KuiLoadingChart,
+} from '../../../../components';
+
+export default () => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+);
+
diff --git a/ui_framework/doc_site/src/views/loading/loading_example.js b/ui_framework/doc_site/src/views/loading/loading_example.js
new file mode 100644
index 0000000000000..8e137c338c90d
--- /dev/null
+++ b/ui_framework/doc_site/src/views/loading/loading_example.js
@@ -0,0 +1,87 @@
+import React from 'react';
+
+import { renderToHtml } from '../../services';
+
+import {
+ GuideDemo,
+ GuidePage,
+ GuideSection,
+ GuideSectionTypes,
+ GuideText,
+} from '../../components';
+
+import LoadingKibana from './loading_kibana';
+const loadingKibanaSource = require('!!raw!./loading_kibana');
+const loadingKibanaHtml = renderToHtml(LoadingKibana);
+
+import LoadingChart from './loading_chart';
+const loadingChartSource = require('!!raw!./loading_chart');
+const loadingChartHtml = renderToHtml(LoadingChart);
+
+import LoadingSpinner from './loading_spinner';
+const loadingSpinnerSource = require('!!raw!./loading_spinner');
+const loadingSpinnerHtml = renderToHtml(LoadingSpinner);
+
+export default props => (
+
+
+
+ Logo based load. Should only be used in very large panels, like bootup screens.
+
+
+
+
+
+
+
+
+
+ Loader for the loading of chart or dashboard and visualization elements.
+ The colored versions should be used sparingly, only when a single large
+ visualization is loaded. When loading smaller groups of panels, the smaller,
+ mono versions should be used.
+
+
+
+
+
+
+
+
+
+ A simple spinner for most loading applications.
+
+
+
+
+
+
+
+);
diff --git a/ui_framework/doc_site/src/views/loading/loading_kibana.js b/ui_framework/doc_site/src/views/loading/loading_kibana.js
new file mode 100644
index 0000000000000..398b0f5bd9127
--- /dev/null
+++ b/ui_framework/doc_site/src/views/loading/loading_kibana.js
@@ -0,0 +1,13 @@
+import React from 'react';
+
+import {
+ KuiLoadingKibana,
+} from '../../../../components';
+
+export default () => (
+
+
+
+
+
+);
diff --git a/ui_framework/doc_site/src/views/loading/loading_spinner.js b/ui_framework/doc_site/src/views/loading/loading_spinner.js
new file mode 100644
index 0000000000000..13fea281af54c
--- /dev/null
+++ b/ui_framework/doc_site/src/views/loading/loading_spinner.js
@@ -0,0 +1,24 @@
+import React from 'react';
+
+import {
+ KuiLoadingSpinner,
+} from '../../../../components';
+
+export default () => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+);
+
diff --git a/ui_framework/src/components/button/_button.scss b/ui_framework/src/components/button/_button.scss
new file mode 100644
index 0000000000000..f35d19501e08d
--- /dev/null
+++ b/ui_framework/src/components/button/_button.scss
@@ -0,0 +1,131 @@
+// Our base button
+.kuiButton {
+ display: inline-block;
+ appearance: none;
+ cursor: pointer;
+ height: $kuiSizeXXL;
+ text-decoration: none;
+ border: solid 1px $kuiColorPrimary;
+ border-radius: $kuiBorderRadius;
+ color: $kuiColorPrimary;
+ padding: 0 $kuiSizeS;
+ min-width: $kuiSize * 7;
+ text-align: center;
+ font-family: $kuiFontFamily;
+ transition: all $kuiAnimSpeedNormal $kuiAnimSlightBounce;
+ whitespace: nowrap;
+
+ &.kuiButton--small {
+ height: $kuiSizeXL;
+ }
+
+ .kuiButton__icon {
+ vertical-align: -2px;
+ fill: $kuiColorPrimary;
+ }
+
+ .kuiButton__content {
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+
+ // Apply margin to all but last item in the flex.
+ > * + * {
+ margin-left: $kuiSizeS;
+ }
+ }
+
+ &:hover, &:focus {
+ text-decoration: underline;
+ background-color: transparentize($kuiColorPrimary, .9);
+ }
+
+ &:focus {
+ animation: kuiButtonFocus $kuiAnimSpeedNormal $kuiAnimSlightBounce;
+ }
+
+ &.kuiButton--fill {
+ background-color: $kuiColorPrimary;
+ color: #FFF;
+ border-color: $kuiColorPrimary;
+
+ &:hover, &:focus {
+ background-color: darken($kuiColorPrimary, 5%);
+ border-color: darken($kuiColorPrimary, 5%);
+ }
+
+ .kuiButton__icon {
+ fill: #FFF;
+ }
+ }
+
+ &.kuiButton--reverse {
+
+ .kuiButton__content {
+ flex-direction: row-reverse;
+ // Margin gets flipped because of the row-reverse.
+ > * + * {
+ margin-left: 0;
+ margin-right: $kuiSizeS;
+ }
+ }
+ }
+}
+
+
+// Modifier naming and colors.
+$buttonTypes: (
+ secondary: $kuiColorSecondary,
+ danger: $kuiColorDanger,
+ warning: $kuiColorWarning,
+ disabled: tintOrShade($kuiTextColor, 70%, 80%)
+);
+
+// Create button modifiders based upon the map.
+@each $name, $color in $buttonTypes {
+ .kuiButton--#{$name} {
+ color: $color;
+ border-color: $color;
+
+ .kuiButton__icon {
+ fill: $color;
+ }
+
+ &:hover, &:focus {
+ background-color: transparentize($color, .9);
+ @if ($name == 'disabled') {
+ cursor: not-allowed;
+ }
+ }
+
+ &.kuiButton--fill {
+ background-color: $color;
+ @if (lightness($kuiTextColor) > 50) {
+ color: $kuiTextColor;
+ } @else {
+ color: #FFF;
+ }
+ border-color: $color;
+
+ &:hover, &:focus {
+ background-color: darken($color, 5%);
+ border-color: darken($color, 5%);
+ }
+
+ .kuiButton__icon {
+ @if (lightness($kuiTextColor) > 50) {
+ fill: $kuiTextColor;
+ } @else {
+ fill: #FFF;
+ }
+ }
+ }
+ }
+}
+
+@keyframes kuiButtonFocus {
+ 50% {
+ transform: translateY($kuiSizeXS / 2);
+ }
+}
diff --git a/ui_framework/src/components/button/_index.scss b/ui_framework/src/components/button/_index.scss
new file mode 100644
index 0000000000000..2d4322481826c
--- /dev/null
+++ b/ui_framework/src/components/button/_index.scss
@@ -0,0 +1 @@
+@import 'button';
diff --git a/ui_framework/src/components/button/button.js b/ui_framework/src/components/button/button.js
new file mode 100644
index 0000000000000..467751c7c78ef
--- /dev/null
+++ b/ui_framework/src/components/button/button.js
@@ -0,0 +1,82 @@
+import React, {
+ Component,
+ PropTypes,
+} from 'react';
+import classNames from 'classnames';
+import { KuiIcon } from '../../components';
+
+const typeToClassNameMap = {
+ danger: 'kuiButton--danger',
+ warning: 'kuiButton--warning',
+ secondary: 'kuiButton--secondary',
+ disabled: 'kuiButton--disabled',
+};
+
+const sizeToClassNameMap = {
+ small: 'kuiButton--small',
+ large: 'kuiButton--large',
+};
+
+export const TYPES = Object.keys(typeToClassNameMap);
+export const SIZES = Object.keys(sizeToClassNameMap);
+
+export class KuiButton extends Component {
+ constructor(props) {
+ super(props);
+ }
+
+ render() {
+ const {
+ children,
+ className,
+ icon,
+ iconReverse,
+ type,
+ size,
+ fill,
+ ...rest,
+ } = this.props;
+
+ const classes = classNames(
+ 'kuiButton',
+ typeToClassNameMap[type],
+ sizeToClassNameMap[size],
+ className,
+ fill === true ? 'kuiButton--fill' : '',
+ iconReverse === true ? 'kuiButton--reverse' : ''
+ );
+
+ // Add an icon to the button if one exists.
+ let buttonIcon = null;
+ if (icon) {
+ buttonIcon =
+
+
+ ;
+ }
+
+ return (
+
+
+ {buttonIcon}
+ {children}
+
+
+ );
+ }
+}
+
+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 (
+
+ );
+};
+
+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;