diff --git a/packages/ui/.npmrc b/packages/ui/.npmrc
new file mode 100644
index 0000000..43c97e7
--- /dev/null
+++ b/packages/ui/.npmrc
@@ -0,0 +1 @@
+package-lock=false
diff --git a/packages/ui/CHANGELOG.md b/packages/ui/CHANGELOG.md
new file mode 100644
index 0000000..abfbbdc
--- /dev/null
+++ b/packages/ui/CHANGELOG.md
@@ -0,0 +1,35 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+
+# 0.2.0 (2020-10-15)
+
+
+### Features
+
+* **ui:** create ui library + add base components ([9ede4ea](https://github.com/elementor/elementor-editor-packages/commit/9ede4ea2610eb6bbac62713ef3a8271f2ebf3a08))
+
+
+
+
+
+## [0.1.3](https://github.com/elementor/elementor-editor-packages/compare/@elementor/ui@0.1.2...@elementor/ui@0.1.3) (2020-10-13)
+
+**Note:** Version bump only for package @elementor/ui
+
+
+
+
+
+## [0.1.2](https://github.com/elementor/elementor-editor-packages/compare/@elementor/ui@0.1.1...@elementor/ui@0.1.2) (2020-10-13)
+
+**Note:** Version bump only for package @elementor/ui
+
+
+
+
+
+## [0.1.1](https://github.com/elementor/elementor-editor-packages/compare/@elementor/ui@0.1.0...@elementor/ui@0.1.1) (2020-10-13)
+
+**Note:** Version bump only for package @elementor/ui
diff --git a/packages/ui/README.md b/packages/ui/README.md
new file mode 100644
index 0000000..6315144
--- /dev/null
+++ b/packages/ui/README.md
@@ -0,0 +1,3 @@
+# @elementor/ui
+
+### Do not use it!
diff --git a/packages/ui/package.json b/packages/ui/package.json
new file mode 100644
index 0000000..0711c77
--- /dev/null
+++ b/packages/ui/package.json
@@ -0,0 +1,30 @@
+{
+ "name": "@elementor/ui",
+ "version": "0.2.0",
+ "description": "Elementor UI library",
+ "author": "Elementor Team",
+ "homepage": "https://github.com/elementor/elementor-editor-packages",
+ "license": "ISC",
+ "main": "build/index.js",
+ "module": "build/index.es.js",
+ "files": [
+ "build",
+ "src"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/elementor/elementor-editor-packages",
+ "directory": "packages/ui"
+ },
+ "publishConfig": {
+ "registry": "https://npm.pkg.github.com/"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0",
+ "react-dom": "^16.8.0"
+ },
+ "dependencies": {
+ "@babel/runtime": "^7.11.2",
+ "prop-types": "^15.7.2"
+ }
+}
diff --git a/packages/ui/src/components/add-new-button/index.js b/packages/ui/src/components/add-new-button/index.js
new file mode 100644
index 0000000..116cd2e
--- /dev/null
+++ b/packages/ui/src/components/add-new-button/index.js
@@ -0,0 +1,27 @@
+import PropTypes from 'prop-types';
+
+import Button from '../button';
+
+export default class AddNewButton extends Button {
+ getClassName() {
+ let className = this.props.className;
+
+ if (this.props.size) {
+ className += ' eps-add-new-button--' + this.props.size;
+ }
+
+ return className;
+ }
+
+ static propTypes = {
+ ...Button.propTypes,
+ text: PropTypes.string,
+ size: PropTypes.string,
+ };
+
+ static defaultProps = {
+ ...Button.defaultProps,
+ className: 'eps-add-new-button',
+ icon: 'eicon-plus',
+ };
+}
diff --git a/packages/ui/src/components/add-new-button/style.scss b/packages/ui/src/components/add-new-button/style.scss
new file mode 100644
index 0000000..61249c6
--- /dev/null
+++ b/packages/ui/src/components/add-new-button/style.scss
@@ -0,0 +1,33 @@
+$eps-add-new-button-background-color: theme-colors(info);
+$eps-add-new-button-icon-color: theme-colors(light);
+$eps-add-new-button-size: spacing(24);
+$eps-add-new-button-size-sm: spacing(16);
+$eps-add-new-button-icon-size-ratio: 0.75;
+$eps-add-new-button-font-weight: $eps-font-weight-medium;
+
+.#{$eps-prefix}add-new-button {
+ display: inline-flex;
+ --eps-add-new-button-size: #{$eps-add-new-button-size};
+ line-height: var(--eps-add-new-button-size);
+ cursor: pointer;
+
+ .eps-icon {
+ background-color: $eps-add-new-button-background-color;
+ color: $eps-add-new-button-icon-color;
+ width: var(--eps-add-new-button-size);
+ height: var(--eps-add-new-button-size);
+ border-radius: 100%;
+ font-size: calc(var(--eps-add-new-button-size) * #{$eps-add-new-button-icon-size-ratio});
+ text-align: center;
+ line-height: var(--eps-add-new-button-size);
+ }
+
+ span:not(.sr-only) {
+ margin-inline-start: spacing(10);
+ font-weight: $eps-add-new-button-font-weight;
+ }
+
+ &--sm {
+ --eps-add-new-button-size: #{$eps-add-new-button-size-sm};
+ }
+}
diff --git a/packages/ui/src/components/button/api.scss b/packages/ui/src/components/button/api.scss
new file mode 100644
index 0000000..74bba24
--- /dev/null
+++ b/packages/ui/src/components/button/api.scss
@@ -0,0 +1,132 @@
+// BTN API
+$button-font-weight: $eps-font-weight-medium;
+$button-line-height: 16px;
+$button-padding-y: 0.5em;
+$button-padding-x: 1.5em;
+$button-border-radius: $eps-radius;
+$button-hover-constant: 5%;
+$button-active-constant: 3%;
+// sizing
+// -- sm
+$button-sm-font-size: type(text,xs);
+$button-sm-line-height: 14px;
+// --lg
+$button-lg-font-size: type(text,lg);
+$button-lg-line-height: 18px;
+//Semantic Colors
+$button-primary-background-color: theme-colors(success);
+$button-primary-hover-background-color: darken($button-primary-background-color, $button-hover-constant);
+$button-primary-active-background-color: darken($button-primary-background-color, $button-active-constant);
+$button-primary-color: theme-colors(light);
+$button-secondary-background-color: tints(400);
+$button-secondary-hover-background-color: darken($button-secondary-background-color, $button-hover-constant);
+$button-secondary-active-background-color: darken($button-secondary-background-color, $button-active-constant);
+$button-secondary-color: theme-colors(light);
+$button-danger-background-color: theme-colors(danger);
+$button-danger-hover-background-color: darken($button-danger-background-color, $button-hover-constant);
+$button-danger-active-background-color: darken($button-danger-background-color, $button-active-constant);
+$button-danger-color: theme-colors(light);
+$button-cta-background-color: theme-colors(cta);
+$button-cta-hover-background-color: darken($button-cta-background-color, $button-hover-constant);
+$button-cta-active-background-color: darken($button-cta-background-color, $button-active-constant);
+$button-cta-color: theme-colors(light);
+$button-link-background-color: theme-elements-colors(link-color);
+$button-link-hover-background-color: darken($button-link-background-color, $button-hover-constant);
+$button-link-active-background-color: darken($button-link-background-color, $button-active-constant);
+$button-link-color: theme-colors(light);
+$button-disabled-background-color: theme-colors(disabled);
+$button-disabled-hover-background-color: darken($button-disabled-background-color, $button-hover-constant);
+$button-disabled-active-background-color: darken($button-disabled-background-color, $button-active-constant);
+$button-disabled-color: theme-colors(light);
+// -- dark
+$button-dark-primary-background-color: dark-theme-colors(success);
+$button-dark-primary-color: dark-theme-colors(light);
+$button-dark-primary-hover-background-color: darken($button-dark-primary-background-color, $button-hover-constant);
+$button-dark-primary-active-background-color: darken($button-dark-primary-background-color, $button-active-constant);
+$button-dark-secondary-background-color: dark-tints(400);
+$button-dark-secondary-hover-background-color: darken($button-dark-secondary-background-color, $button-hover-constant);
+$button-dark-secondary-active-background-color: darken($button-dark-secondary-background-color, $button-active-constant);
+$button-dark-secondary-color: dark-theme-colors(light);
+$button-dark-danger-background-color: dark-theme-colors(danger);
+$button-dark-danger-hover-background-color: darken($button-dark-danger-background-color, $button-hover-constant);
+$button-dark-danger-active-background-color: darken($button-dark-danger-background-color, $button-active-constant);
+$button-dark-danger-color: dark-theme-colors(light);
+$button-dark-cta-background-color: dark-theme-colors(cta);
+$button-dark-cta-hover-background-color: darken($button-dark-cta-background-color, $button-hover-constant);
+$button-dark-cta-active-background-color: darken($button-dark-cta-background-color, $button-active-constant);
+$button-dark-cta-color: dark-theme-colors(light);
+$button-dark-link-background-color: theme-elements-colors(link-color);
+$button-dark-link-hover-background-color: darken($button-dark-link-background-color, $button-hover-constant);
+$button-dark-link-active-background-color: darken($button-dark-link-background-color, $button-active-constant);
+$button-dark-link-color: theme-colors(light);
+$button-dark-disabled-background-color: dark-theme-colors(disabled);
+$button-dark-disabled-hover-background-color: darken($button-dark-disabled-background-color, $button-hover-constant);
+$button-dark-disabled-active-background-color: darken($button-dark-disabled-background-color, $button-active-constant);
+$button-dark-disabled-color: dark-theme-colors(light);
+
+// using mixing to transfer custom properties
+@mixin button-custom-properties() {
+ --button-line-height: #{$button-line-height};
+ --button-padding-y: #{$button-padding-y};
+ --button-padding-x: #{$button-padding-x};
+ // primary
+ --button-primary-background-color: #{$button-primary-background-color};
+ --button-primary-hover-background-color: #{$button-primary-hover-background-color};
+ --button-primary-active-background-color: #{$button-primary-active-background-color};
+ --button-primary-color: #{$button-primary-color};
+ // secondary
+ --button-secondary-background-color: #{$button-secondary-background-color};
+ --button-secondary-hover-background-color: #{$button-secondary-hover-background-color};
+ --button-secondary-active-background-color: #{$button-secondary-active-background-color};
+ --button-secondary-color: #{$button-secondary-color};
+ // danger
+ --button-danger-background-color: #{$button-danger-background-color};
+ --button-danger-hover-background-color: #{$button-danger-hover-background-color};
+ --button-danger-active-background-color: #{$button-danger-active-background-color};
+ --button-danger-color: #{$button-danger-color};
+ // cta
+ --button-cta-background-color: #{$button-cta-background-color};
+ --button-cta-hover-background-color: #{$button-cta-hover-background-color};
+ --button-cta-active-background-color: #{$button-cta-active-background-color};
+ --button-cta-color: #{$button-cta-color};
+ // link
+ --button-link-background-color: #{$button-link-background-color};
+ --button-link-hover-background-color: #{$button-link-hover-background-color};
+ --button-link-active-background-color: #{$button-link-active-background-color};
+ --button-link-color: #{$button-link-color};
+ // disabled
+ --button-disabled-background-color: #{$button-disabled-background-color};
+ --button-disabled-hover-background-color: #{$button-disabled-hover-background-color};
+ --button-disabled-active-background-color: #{$button-disabled-active-background-color};
+ --button-disabled-color: #{$button-disabled-color};
+}
+
+@mixin button-dark-custom-properties() {
+ // primary
+ --button-primary-background-color: #{$button-dark-primary-background-color};
+ --button-primary-color: #{$button-dark-primary-color};
+ --button-primary-hover-background-color: #{$button-dark-primary-hover-background-color};
+ --button-primary-active-background-color: #{$button-dark-primary-active-background-color};
+ // secondary
+ --button-secondary-background-color: #{$button-dark-secondary-background-color};
+ --button-secondary-color: #{$button-dark-secondary-color};
+ --button-secondary-hover-background-color: #{$button-dark-secondary-hover-background-color};
+ --button-secondary-active-background-color: #{$button-dark-secondary-active-background-color};
+ // cta
+ --button-cta-background-color: #{$button-dark-cta-background-color};
+ --button-cta-hover-background-color: #{$button-dark-cta-hover-background-color};
+ --button-cta-active-background-color: #{$button-dark-cta-active-background-color};
+ --button-cta-color: #{$button-dark-cta-color};
+ // link
+ --button-link-background-color: #{$button-dark-link-background-color};
+ --button-link-hover-background-color: #{$button-dark-link-hover-background-color};
+ --button-link-active-background-color: #{$button-dark-link-active-background-color};
+ --button-link-color: #{$button-dark-link-color};
+ // disabled
+ --button-disabled-background-color: #{$button-dark-disabled-background-color};
+ --button-disabled-hover-background-color: #{$button-dark-disabled-hover-background-color};
+ --button-disabled-active-background-color: #{$button-dark-disabled-active-background-color};
+ --button-disabled-color: #{$button-dark-disabled-color};
+}
+
+
diff --git a/packages/ui/src/components/button/index.js b/packages/ui/src/components/button/index.js
new file mode 100644
index 0000000..47e988a
--- /dev/null
+++ b/packages/ui/src/components/button/index.js
@@ -0,0 +1,127 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import Icon from '../icon';
+
+export default class Button extends React.Component {
+ static propTypes = {
+ text: PropTypes.string.isRequired,
+ hideText: PropTypes.bool,
+ icon: PropTypes.string,
+ tooltip: PropTypes.string,
+ id: PropTypes.string,
+ className: PropTypes.string,
+ url: PropTypes.string,
+ onClick: PropTypes.func,
+ variant: PropTypes.string,
+ color: PropTypes.string,
+ size: PropTypes.string,
+ target: PropTypes.string,
+ };
+
+ static defaultProps = {
+ id: '',
+ className: '',
+ variant: '',
+ target: '_parent',
+ };
+
+ getCssId() {
+ return this.props.id;
+ }
+
+ getClassName() {
+ const baseClassName = 'eps-button',
+ classes = [baseClassName, this.props.className];
+
+ return classes
+ .concat(this.getStylePropsClasses(baseClassName))
+ .filter((classItem) => '' !== classItem)
+ .join(' ');
+ }
+
+ getStylePropsClasses(baseClassName) {
+ const styleProps = ['color', 'size', 'variant'],
+ stylePropClasses = [];
+
+ styleProps.forEach((styleProp) => {
+ const stylePropValue = this.props[styleProp];
+
+ if (stylePropValue) {
+ stylePropClasses.push(baseClassName + '--' + stylePropValue);
+ }
+ });
+
+ return stylePropClasses;
+ }
+
+ getIcon() {
+ if (this.props.icon) {
+ const tooltip = this.props.tooltip || this.props.text;
+ const icon = (
+
+ );
+ let screenReaderText = '';
+
+ if (this.props.hideText) {
+ screenReaderText = {tooltip};
+ }
+
+ return (
+ <>
+ {icon}
+ {screenReaderText}
+ >
+ );
+ }
+ return '';
+ }
+
+ getText() {
+ return this.props.hideText ? '' : {this.props.text};
+ }
+
+ render() {
+ const attributes = {},
+ id = this.getCssId(),
+ className = this.getClassName();
+
+ // Add attributes only if they are not empty.
+ if (id) {
+ attributes.id = id;
+ }
+
+ if (className) {
+ attributes.className = className;
+ }
+
+ if (this.props.onClick) {
+ attributes.onClick = this.props.onClick;
+ }
+
+ const buttonContent = (
+ <>
+ {this.getIcon()}
+ {this.getText()}
+ >
+ );
+
+ if (this.props.url && 0 === this.props.url.indexOf('http')) {
+ return (
+
+ {buttonContent}
+
+ );
+ }
+
+ return
{buttonContent}
;
+ }
+}
diff --git a/packages/ui/src/components/button/style.scss b/packages/ui/src/components/button/style.scss
new file mode 100644
index 0000000..f939138
--- /dev/null
+++ b/packages/ui/src/components/button/style.scss
@@ -0,0 +1,105 @@
+@import "api";
+
+.#{$eps-prefix}button {
+ display: inline-flex;
+ //custom properties
+ @include button-custom-properties;
+ // definitions
+ color: var(--button-background-color, currentColor);
+ font-size: var(--button-font-size, inherit);
+ font-weight: $button-font-weight;
+ line-height: var(--button-line-height);
+ cursor: pointer;
+
+ &:active {
+ --button-background-color: var(--button-active-background-color, transparent);
+ }
+
+ &:hover {
+ --button-background-color: var(--button-hover-background-color);
+ }
+
+ .eps-theme-dark & {
+ //dark custom properties
+ @include button-dark-custom-properties;
+ }
+
+ // Variants
+
+ &--contained {
+ // definitions
+ color: var(--button-color);
+ padding: var(--button-padding-y) var(--button-padding-x);
+ background-color: var(--button-background-color, transparent);
+
+ &:hover {
+ color: var(--button-color);
+ }
+ }
+
+ &--contained,
+ &--outlined {
+ border-radius: $button-border-radius;
+ }
+
+ &--underlined {
+ text-decoration: underline;
+ }
+
+ // Sizes
+ &--sm {
+ --button-font-size: #{$button-sm-font-size};
+ --button-line-height: #{$button-sm-line-height};
+ }
+
+ &--lg {
+ --button-font-size: #{$button-lg-font-size};
+ --button-line-height: #{$button-lg-line-height};
+ }
+
+ // Colors
+
+ &--primary {
+ --button-color: var(--button-primary-color);
+ --button-background-color: var(--button-primary-background-color);
+ --button-hover-background-color: var(--button-primary-hover-background-color);
+ --button-active-background-color: var(--button-primary-active-background-color);
+ }
+
+ &--secondary {
+ --button-color: var(--buton-secondary-color);
+ --button-background-color: var(--button-secondary-background-color);
+ --button-hover-background-color: var(--button-secondary-hover-background-color);
+ --button-active-background-color: var(--button-secondary-active-background-color);
+ }
+
+ &--danger {
+ --button-color: var(--buton-danger-color);
+ --button-background-color: var(--button-danger-background-color);
+ --button-hover-background-color: var(--button-danger-hover-background-color);
+ --button-active-background-color: var(--button-danger-active-background-color);
+ }
+
+ &--cta {
+ --button-color: var(--button-cta-color);
+ --button-background-color: var(--button-cta-background-color);
+ --button-hover-background-color: var(--button-cta-hover-background-color);
+ --button-active-background-color: var(--button-cta-active-background-color);
+ }
+
+ &--link {
+ --button-color: var(--button-link-color);
+ --button-background-color: var(--button-link-background-color);
+ --button-hover-background-color: var(--button-link-hover-background-color);
+ --button-active-background-color: var(--button-link-active-background-color);
+ }
+
+ &--disabled,
+ &[disabled] {
+ --button-color: var(--button-disabled-color);
+ --button-background-color: var(--button-disabled-background-color);
+ --button-hover-background-color: var(--button-disabled-hover-background-color);
+ --button-active-background-color: var(--button-disabled-active-background-color);
+ cursor: default;
+ }
+}
diff --git a/packages/ui/src/components/card/api.scss b/packages/ui/src/components/card/api.scss
new file mode 100644
index 0000000..f4b0b31
--- /dev/null
+++ b/packages/ui/src/components/card/api.scss
@@ -0,0 +1,57 @@
+// Private API. Will consume global tokens
+// - Default tokens
+$card-background-color: rgba(theme-colors(light), $opacity-05);
+$card-background-color-hover: theme-colors(light);
+$card-box-shadow: $eps-box-shadow-2;
+$card-border-radius: $eps-radius;
+$card-transition: $eps-transition-duration;
+$card-font-size: type(text,xs);
+$card-footer-font-size: type(text,xxs);
+$card-padding: spacing(10);
+
+$card-header-padding: $card-padding;
+$card-header-footer-border: $eps-border;
+$card-header-height: $card-padding * 4;
+
+$card-headline-color: tints(600);
+
+$card-headline-font-weight: $eps-font-weight-medium;
+$card-headline-line-height: $line-height-2;
+
+$card-body-padding-y: $card-padding;
+$card-body-padding-x: $card-padding;
+
+$card-figure-background-color: tints(200);
+$card-image-aspect-ratio: var(--card-image-aspect-ratio, #{$ratio-portrait});
+
+$card-image-overlay-background-color: rgba(theme-colors(dark), $opacity-02);
+$card-image-overlay-transition: $card-transition;
+
+// - Dark tokens
+$card-dark-background-color: rgba(dark-tints(600), $opacity-05);
+$card-dark-background-color-hover: dark-tints(600);
+$card-dark-box-shadow: $eps-box-shadow;
+$card-dark-header-border: 1px solid dark-tints(700);
+$card-dark-headline-color: dark-tints(100);
+$card-dark-figure-background-color: dark-tints(700);
+$card-dark-image-overlay-background-color: rgba(dark-tints(700), $opacity-05);
+
+:root {
+ --card-background-color: #{$card-background-color};
+ --card-background-color-hover: #{$card-background-color-hover};
+ --card-box-shadow: #{$card-box-shadow};
+ --card-header-footer-border: #{$card-header-footer-border};
+ --card-headline-color: #{$card-headline-color};
+ --card-figure-background-color: #{$card-figure-background-color};
+ --card-image-overlay-background-color: #{$card-image-overlay-background-color};
+}
+
+.eps-theme-dark {
+ --card-background-color: #{$card-dark-background-color};
+ --card-background-color-hover: #{$card-dark-background-color-hover};
+ --card-box-shadow: #{$card-dark-box-shadow};
+ --card-header-footer-border: #{$card-dark-header-border};
+ --card-headline-color: #{$card-dark-headline-color};
+ --card-figure-background-color: #{$card-dark-figure-background-color};
+ --card-image-overlay-background-color: #{$card-dark-image-overlay-background-color};
+}
diff --git a/packages/ui/src/components/card/body.js b/packages/ui/src/components/card/body.js
new file mode 100644
index 0000000..8b30d9b
--- /dev/null
+++ b/packages/ui/src/components/card/body.js
@@ -0,0 +1,19 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+export default function CardBody(props) {
+ return (
+
+ {props.children}
+
+ );
+}
+
+CardBody.propTypes = {
+ className: PropTypes.string,
+ children: PropTypes.object.isRequired,
+};
+
+CardBody.defaultProps = {
+ className: '',
+};
diff --git a/packages/ui/src/components/card/footer.js b/packages/ui/src/components/card/footer.js
new file mode 100644
index 0000000..1c9b2b9
--- /dev/null
+++ b/packages/ui/src/components/card/footer.js
@@ -0,0 +1,19 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+export default function CardFooter(props) {
+ return (
+
+ );
+}
+
+CardFooter.propTypes = {
+ className: PropTypes.string,
+ children: PropTypes.object.isRequired,
+};
+
+CardFooter.defaultProps = {
+ className: '',
+};
diff --git a/packages/ui/src/components/card/header.js b/packages/ui/src/components/card/header.js
new file mode 100644
index 0000000..f975920
--- /dev/null
+++ b/packages/ui/src/components/card/header.js
@@ -0,0 +1,19 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+export default function CardHeader(props) {
+ return (
+
+ );
+}
+
+CardHeader.propTypes = {
+ className: PropTypes.string,
+ children: PropTypes.any.isRequired,
+};
+
+CardHeader.defaultProps = {
+ className: '',
+};
diff --git a/packages/ui/src/components/card/image.js b/packages/ui/src/components/card/image.js
new file mode 100644
index 0000000..4b2e88e
--- /dev/null
+++ b/packages/ui/src/components/card/image.js
@@ -0,0 +1,26 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+export default function CardImage(props) {
+ const image = (
+
+ );
+
+ return (
+
+ {image}
+ {props.children}
+
+ );
+}
+
+CardImage.propTypes = {
+ className: PropTypes.string,
+ src: PropTypes.string.isRequired,
+ alt: PropTypes.string.isRequired,
+ children: PropTypes.any,
+};
+
+CardImage.defaultProps = {
+ className: '',
+};
diff --git a/packages/ui/src/components/card/index.js b/packages/ui/src/components/card/index.js
new file mode 100644
index 0000000..76aa5fd
--- /dev/null
+++ b/packages/ui/src/components/card/index.js
@@ -0,0 +1,35 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import Body from './body';
+import Footer from './footer';
+import Header from './header';
+import Image from './image';
+import Overlay from './overlay';
+
+const Card = React.forwardRef((props, ref) => {
+ return (
+
+ {props.children}
+
+ );
+});
+
+Card.propTypes = {
+ type: PropTypes.string,
+ className: PropTypes.string,
+ children: PropTypes.any,
+};
+
+Card.defaultProps = {
+ className: '',
+};
+
+Card.displayName = 'Card';
+
+Card.Body = Body;
+Card.Footer = Footer;
+Card.Header = Header;
+Card.Image = Image;
+Card.Overlay = Overlay;
+
+export default Card;
diff --git a/packages/ui/src/components/card/overlay.js b/packages/ui/src/components/card/overlay.js
new file mode 100644
index 0000000..e993d23
--- /dev/null
+++ b/packages/ui/src/components/card/overlay.js
@@ -0,0 +1,19 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+export default function CardOverlay(props) {
+ return (
+
+ {props.children}
+
+ );
+}
+
+CardOverlay.propTypes = {
+ className: PropTypes.string,
+ children: PropTypes.object.isRequired,
+};
+
+CardOverlay.defaultProps = {
+ className: '',
+};
diff --git a/packages/ui/src/components/card/style.scss b/packages/ui/src/components/card/style.scss
new file mode 100644
index 0000000..07630df
--- /dev/null
+++ b/packages/ui/src/components/card/style.scss
@@ -0,0 +1,80 @@
+// Card
+
+// this should emulate external packages consumption
+@import "./api";
+
+.#{$eps-prefix}card {
+ background-color: var(--card-background-color);
+ box-shadow: $card-box-shadow;
+ border-radius: $card-border-radius;
+ transition: $card-transition;
+ font-size: $card-font-size;
+
+ &__header {
+ padding: $card-header-padding;
+ border-bottom: var(--card-header-footer-border);
+ min-height: $card-header-height;
+ display: flex;
+ align-items: center;
+ }
+
+ /*
+ todo: TBD: Optionally remove headline styling in favor of a global atom depending on variation needs
+ */
+
+ &__headline {
+ color: var(--card-headline-color);
+ margin-bottom: 0;
+ font-weight: $card-headline-font-weight;
+ flex-grow: 1;
+ @include text-truncate();
+ }
+
+ &__body {
+ padding: $card-body-padding-y $card-body-padding-x;
+ }
+
+ // figure is here to assist with aspect ratio, and dealing with different image sizes and bg-color for shorter images e.g. header, footer.
+ &__figure {
+ background-color: var(--card-figure-background-color);
+ position: relative;
+ padding-bottom: $card-image-aspect-ratio;
+ overflow: hidden;
+ height: 0;
+ }
+
+ &__image {
+ width: 100%;
+ object-fit: contain;
+ object-position: top;
+ position: absolute;
+ top: 0;
+ left: 0;
+ }
+
+ &__image-overlay {
+ position: absolute;
+ top: 0;
+ background-color: var(--card-image-overlay-background-color);
+ z-index: 1;
+ width: 100%;
+ height: 100%;
+ opacity: 0;
+ transition: $card-image-overlay-transition;
+
+ &:hover {
+ opacity: 1;
+ }
+ }
+
+ &__footer {
+ padding: $card-padding;
+ border-top: var(--card-header-footer-border);
+ font-size: $card-footer-font-size;
+ }
+
+ &:hover {
+ background-color: var(--card-background-color-hover);
+ }
+}
+
diff --git a/packages/ui/src/components/checkbox/api.scss b/packages/ui/src/components/checkbox/api.scss
new file mode 100644
index 0000000..08a3bbf
--- /dev/null
+++ b/packages/ui/src/components/checkbox/api.scss
@@ -0,0 +1,28 @@
+// CHECKBOX: API
+$eps-checkbox-size: 15px;
+$eps-checkbox-border-color: tints(300);
+$eps-checkbox-hover-border-color: darken(tints(300), $eps-hover-state-operator);
+$eps-checkbox-active-border-color: lighten(tints(300), $eps-active-state-operator);
+$eps-checkbox-border-radius: $eps-radius;
+$eps-checkbox-background-color: theme-colors(light);
+$eps-checkbox-checked-background-color: theme-colors(success);
+$eps-checkbox-checked-hover-background-color: darken($eps-checkbox-checked-background-color, $eps-hover-state-operator);
+$eps-checkbox-checked-active-background-color: lighten($eps-checkbox-checked-background-color, $eps-active-state-operator);
+$eps-checkbox-indicator-color: theme-colors(light);
+$eps-checkbox-indicator-border-width: 1px;
+$eps-checkbox-indicator-scale-unit: 1/4;
+$eps-checkbox-indicator-size-unit: ceil($eps-checkbox-indicator-scale-unit * $eps-checkbox-size) - $eps-checkbox-indicator-border-width;
+
+:root {
+ --checkbox-border-color: #{$eps-checkbox-border-color};
+ --checkbox-hover-border-color: #{$eps-checkbox-hover-border-color};
+ --checkbox-active-border-color: #{$eps-checkbox-active-border-color};
+ --checkbox-background-color: #{$eps-checkbox-background-color};
+ --checkbox-checked-background-color: #{$eps-checkbox-checked-background-color};
+ --checkbox-checked-hover-background-color: #{$eps-checkbox-checked-hover-background-color};
+ --checkbox-checked-active-background-color: #{$eps-checkbox-checked-active-background-color};
+ --checkbox-indicator-color: #{$eps-checkbox-indicator-color};
+}
+
+// Theming:
+// no dark theme detected
diff --git a/packages/ui/src/components/checkbox/index.js b/packages/ui/src/components/checkbox/index.js
new file mode 100644
index 0000000..0d8b36a
--- /dev/null
+++ b/packages/ui/src/components/checkbox/index.js
@@ -0,0 +1,26 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+export default function Checkbox(props) {
+ return (
+
+ );
+}
+
+Checkbox.propTypes = {
+ className: PropTypes.string,
+ disabled: PropTypes.bool,
+ checked: PropTypes.bool,
+ onChange: PropTypes.func,
+};
+
+Checkbox.defaultProps = {
+ className: '',
+ disabled: false,
+};
diff --git a/packages/ui/src/components/checkbox/style.scss b/packages/ui/src/components/checkbox/style.scss
new file mode 100644
index 0000000..1433a56
--- /dev/null
+++ b/packages/ui/src/components/checkbox/style.scss
@@ -0,0 +1,52 @@
+@import "api";
+
+// checkbox label
+.#{$eps-prefix}checkbox {
+ -webkit-appearance: none;
+ border-radius: $eps-checkbox-border-radius;
+ width: $eps-checkbox-size;
+ height: $eps-checkbox-size;
+ outline: 0;
+ background-color: var(--checkbox-background-color);
+ display: inline-flex;
+ justify-content: center;
+ align-items: center;
+ border: 1px solid var(--checkbox-border-color);
+
+ &::after {
+ display: inline-block;
+ margin-bottom: percentage($eps-checkbox-indicator-scale-unit / 2);
+ content: " ";
+ width: $eps-checkbox-indicator-size-unit;
+ height: (2 * $eps-checkbox-indicator-size-unit);
+ transform: rotate(45deg);
+ }
+
+ &:hover {
+ --checkbox-border-color: var(--checkbox-hover-border-color);
+ }
+
+ &:active {
+ --checkbox-border-color: var(--checkbox-active-border-color);
+ }
+
+ &:checked {
+ --checkbox-background-color: var(--checkbox-checked-background-color);
+ --checkbox-border-color: var(--checkbox-checked-background-color);
+
+ &::after {
+ border: solid $eps-checkbox-indicator-color;
+ border-width: 0 $eps-checkbox-indicator-border-width $eps-checkbox-indicator-border-width 0;
+ }
+
+ &:hover {
+ --checkbox-background-color: var(--checkbox-checked-hover-background-color);
+ --checkbox-border-color: var(--checkbox-checked-hover-background-color);
+ }
+
+ &:active {
+ --checkbox-background-color: var(--checkbox-checked-active-background-color);
+ --checkbox-border-color: var(--checkbox-checked-active-background-color);
+ }
+ }
+}
diff --git a/packages/ui/src/components/checkbox/test/index.test.js b/packages/ui/src/components/checkbox/test/index.test.js
new file mode 100644
index 0000000..425de98
--- /dev/null
+++ b/packages/ui/src/components/checkbox/test/index.test.js
@@ -0,0 +1,16 @@
+import React from 'react';
+import { render, fireEvent } from '@testing-library/react';
+
+import Checkbox from '../index';
+
+describe('', () => {
+ it('should call onChange prop when checkbox checked changed.', () => {
+ const onChangeMock = jest.fn();
+
+ const { container } = render();
+
+ fireEvent.click(container.firstChild);
+
+ expect(onChangeMock).toHaveBeenCalledTimes(1);
+ });
+});
diff --git a/packages/ui/src/components/css-grid/index.js b/packages/ui/src/components/css-grid/index.js
new file mode 100644
index 0000000..160657d
--- /dev/null
+++ b/packages/ui/src/components/css-grid/index.js
@@ -0,0 +1,32 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { pxToRem } from '../../utils';
+
+export default function CssGrid(props) {
+ const gridStyle = {
+ '--eps-grid-columns': props.columns,
+ '--eps-grid-spacing': pxToRem(props.spacing),
+ '--eps-grid-col-min-width': pxToRem(props.colMinWidth),
+ '--eps-grid-col-max-width': pxToRem(props.colMaxWidth),
+ };
+
+ return (
+
+ {props.children}
+
+ );
+}
+
+CssGrid.propTypes = {
+ className: PropTypes.string,
+ children: PropTypes.any.isRequired,
+ columns: PropTypes.number,
+ spacing: PropTypes.number,
+ colMinWidth: PropTypes.number,
+ colMaxWidth: PropTypes.number,
+};
+
+CssGrid.defaultProps = {
+ spacing: 24,
+ className: '',
+};
diff --git a/packages/ui/src/components/css-grid/style.scss b/packages/ui/src/components/css-grid/style.scss
new file mode 100644
index 0000000..034bbf6
--- /dev/null
+++ b/packages/ui/src/components/css-grid/style.scss
@@ -0,0 +1,8 @@
+$eps-grid-gap: var(--eps-grid-spacing);
+$eps-grid-columns: repeat(var(--eps-grid-columns, auto-fill), minmax(var(--eps-grid-col-min-width, 1fr), var(--eps-grid-col-max-width, 1fr)));
+
+.#{$eps-prefix}css-grid {
+ display: grid;
+ grid-template-columns: $eps-grid-columns;
+ grid-gap: $eps-grid-gap;
+}
diff --git a/packages/ui/src/components/dialog/actions.js b/packages/ui/src/components/dialog/actions.js
new file mode 100644
index 0000000..1010694
--- /dev/null
+++ b/packages/ui/src/components/dialog/actions.js
@@ -0,0 +1,10 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+export default function DialogActions(props) {
+ return {props.children}
;
+}
+
+DialogActions.propTypes = {
+ children: PropTypes.any,
+};
diff --git a/packages/ui/src/components/dialog/button.js b/packages/ui/src/components/dialog/button.js
new file mode 100644
index 0000000..53748eb
--- /dev/null
+++ b/packages/ui/src/components/dialog/button.js
@@ -0,0 +1,25 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import Button from '../button';
+
+export default function DialogButton(props) {
+ return (
+
+ );
+}
+
+DialogButton.propTypes = {
+ ...Button.propTypes,
+ tabIndex: PropTypes.string,
+ type: PropTypes.string,
+};
+
+DialogButton.defaultProps = {
+ ...Button.defaultProps,
+ tabIndex: '0',
+ type: 'button',
+};
diff --git a/packages/ui/src/components/dialog/content.js b/packages/ui/src/components/dialog/content.js
new file mode 100644
index 0000000..841f4dc
--- /dev/null
+++ b/packages/ui/src/components/dialog/content.js
@@ -0,0 +1,10 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+export default function DialogContent(props) {
+ return {props.children}
;
+}
+
+DialogContent.propTypes = {
+ children: PropTypes.any,
+};
diff --git a/packages/ui/src/components/dialog/index.js b/packages/ui/src/components/dialog/index.js
new file mode 100644
index 0000000..1fb7ef2
--- /dev/null
+++ b/packages/ui/src/components/dialog/index.js
@@ -0,0 +1,70 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import Wrapper from './wrapper';
+import Content from './content';
+import Title from './title';
+import Text from './text';
+import Actions from './actions';
+import Button from './button';
+
+export default function Dialog(props) {
+ return (
+
+
+ {props.title && {props.title}}
+ {props.text && {props.text}}
+ {props.children}
+
+
+
+
+
+
+ );
+}
+
+Dialog.propTypes = {
+ title: PropTypes.any,
+ text: PropTypes.any,
+ children: PropTypes.any,
+ onSubmit: PropTypes.func,
+ onClose: PropTypes.func,
+ dismissButtonText: PropTypes.string.isRequired,
+ dismissButtonOnClick: PropTypes.func,
+ dismissButtonUrl: PropTypes.string,
+ dismissButtonTarget: PropTypes.string,
+ approveButtonText: PropTypes.string.isRequired,
+ approveButtonOnClick: PropTypes.func,
+ approveButtonUrl: PropTypes.string,
+ approveButtonColor: PropTypes.string,
+ approveButtonTarget: PropTypes.string,
+};
+
+Dialog.defaultProps = {};
+
+Dialog.Wrapper = Wrapper;
+Dialog.Content = Content;
+Dialog.Title = Title;
+Dialog.Text = Text;
+Dialog.Actions = Actions;
+Dialog.Button = Button;
diff --git a/packages/ui/src/components/dialog/style.scss b/packages/ui/src/components/dialog/style.scss
new file mode 100644
index 0000000..081c92f
--- /dev/null
+++ b/packages/ui/src/components/dialog/style.scss
@@ -0,0 +1,40 @@
+.eps-dialog {
+ border-radius: 3px;
+ width: 375px;
+
+ &__close-button {
+ position: absolute;
+ top: 0;
+ right: 0;
+ margin-top: spacing(10);
+ margin-right: spacing(10);
+ z-index: $eps-zindex-modal;
+ font-size: size(2.5);
+ color: theme-colors(light);
+ }
+
+ &__content {
+ padding: spacing(24) spacing(30) spacing(16);
+ font-size: type(text, xs);
+ }
+
+ &__title, &__text {
+ text-align: center;
+ }
+
+ &__buttons {
+ display: flex;
+ }
+
+ &__button {
+ flex: 1;
+ border-top: 1px solid var(--hr-color);
+ line-height: spacing(44);
+ text-align: center;
+ justify-content: center;
+
+ &:last-child:not(:first-child) {
+ border-inline-start: 1px solid var(--hr-color);
+ }
+ }
+}
diff --git a/packages/ui/src/components/dialog/text.js b/packages/ui/src/components/dialog/text.js
new file mode 100644
index 0000000..acc9079
--- /dev/null
+++ b/packages/ui/src/components/dialog/text.js
@@ -0,0 +1,23 @@
+import React from 'react';
+
+import Text from '../text';
+
+export default function DialogText(props) {
+ return (
+
+ );
+}
+
+DialogText.propTypes = {
+ ...Text.propTypes,
+};
+
+DialogText.defaultProps = {
+ ...Text.defaultProps,
+ tag: 'p',
+ variant: 'sm',
+};
diff --git a/packages/ui/src/components/dialog/title.js b/packages/ui/src/components/dialog/title.js
new file mode 100644
index 0000000..6ced41c
--- /dev/null
+++ b/packages/ui/src/components/dialog/title.js
@@ -0,0 +1,25 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import Heading from '../heading';
+
+export default function DialogTitle(props) {
+ return (
+
+ );
+}
+
+DialogTitle.propTypes = {
+ ...Heading.propTypes,
+ className: PropTypes.string,
+};
+
+DialogTitle.defaultProps = {
+ ...Heading.propTypes,
+ variant: 'h3',
+ tag: 'h3',
+ className: '',
+};
diff --git a/packages/ui/src/components/dialog/wrapper.js b/packages/ui/src/components/dialog/wrapper.js
new file mode 100644
index 0000000..a90cf34
--- /dev/null
+++ b/packages/ui/src/components/dialog/wrapper.js
@@ -0,0 +1,38 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import Button from '../button';
+
+export default function DialogWrapper(props) {
+ let WrapperTag = 'div';
+
+ if (props.onSubmit) {
+ WrapperTag = 'form';
+ }
+
+ return (
+
+ {props.onClose && (
+
+ )}
+
+ {props.children}
+
+
+ );
+}
+
+DialogWrapper.propTypes = {
+ onClose: PropTypes.func,
+ onSubmit: PropTypes.func,
+ children: PropTypes.any,
+};
diff --git a/packages/ui/src/components/drag-drop/index.js b/packages/ui/src/components/drag-drop/index.js
new file mode 100644
index 0000000..6cdecdd
--- /dev/null
+++ b/packages/ui/src/components/drag-drop/index.js
@@ -0,0 +1,69 @@
+import React, { useState } from 'react';
+import PropTypes from 'prop-types';
+import { arrayToClassName } from '../../utils';
+
+export default function DragDrop(props) {
+ const [isDragOver, setIsDragOver] = useState(false),
+ getClassName = () => {
+ const baseClassName = 'e-app-drag-drop',
+ classes = [baseClassName, props.className];
+
+ if (isDragOver && !props.isLoading) {
+ classes.push(baseClassName + '--drag-over');
+ }
+
+ return arrayToClassName(classes);
+ },
+ onDragDropActions = (event) => {
+ event.preventDefault();
+ event.stopPropagation();
+ },
+ dragDropEvents = {
+ onDrop: (event) => {
+ onDragDropActions(event);
+
+ setIsDragOver(false);
+
+ if (props.onDrop) {
+ props.onDrop(event);
+ }
+ },
+ onDragOver: (event) => {
+ onDragDropActions(event);
+
+ setIsDragOver(true);
+
+ if (props.onDragOver) {
+ props.onDragOver(event);
+ }
+ },
+ onDragLeave: (event) => {
+ onDragDropActions(event);
+
+ setIsDragOver(false);
+
+ if (props.onDragLeave) {
+ props.onDragLeave(event);
+ }
+ },
+ };
+
+ return (
+
+ {props.children}
+
+ );
+}
+
+DragDrop.propTypes = {
+ className: PropTypes.string,
+ children: PropTypes.any,
+ onDrop: PropTypes.func,
+ onDragLeave: PropTypes.func,
+ onDragOver: PropTypes.func,
+ isLoading: PropTypes.bool,
+};
+
+DragDrop.defaultProps = {
+ className: '',
+};
diff --git a/packages/ui/src/components/drag-drop/style.scss b/packages/ui/src/components/drag-drop/style.scss
new file mode 100644
index 0000000..ad9b698
--- /dev/null
+++ b/packages/ui/src/components/drag-drop/style.scss
@@ -0,0 +1,27 @@
+$e-app-drag-drop-background-color: theme-colors(light);
+$e-app-drag-drop-dark-background-color: dark-tints(600);
+$e-app-drag-drop-outline-color: tints(300);
+$e-app-drag-drop-dark-outline-color: dark-tints(300);
+
+:root {
+ --e-app-drag-drop-background-color: #{$e-app-drag-drop-background-color};
+ --e-app-drag-drop-outline-color: #{$e-app-drag-drop-outline-color};
+}
+
+.eps-theme-dark {
+ --e-app-drag-drop-background-color: #{$e-app-drag-drop-dark-background-color};
+ --e-app-drag-drop-outline-color: #{$e-app-drag-drop-dark-outline-color};
+}
+
+.e-app-drag-drop {
+ background-color: var(--e-app-drag-drop-background-color);
+ outline: 2px dashed var(--e-app-drag-drop-outline-color);
+ outline-offset: spacing(12) * -1;
+ margin-bottom: spacing(24);
+ padding: 1.5 * spacing(44);
+ text-align: center;
+
+ &--drag-over {
+ outline-color: theme-colors(info);
+ }
+}
diff --git a/packages/ui/src/components/grid/api.scss b/packages/ui/src/components/grid/api.scss
new file mode 100644
index 0000000..3ce078c
--- /dev/null
+++ b/packages/ui/src/components/grid/api.scss
@@ -0,0 +1,43 @@
+// COMPONENT API: GRID
+
+// MIXIN: Grid Coll generator
+$eps-grid-columns: 12;
+$eps-grid-spacing-keys: (5 8 10 12 16);
+$grid-spacing-gutter: calc( var(--grid-spacing-gutter) * #{px-to-rem(1)} );
+
+//defining flex traits
+@mixin grid-item-auto($size) {
+ .#{$eps-prefix}grid-item-#{$size} {
+ flex-grow: 1;
+ max-width: 100%;
+ flex-basis: 0;
+ }
+}
+
+// defining cols.
+@mixin grid-col-generator($size, $grid-columns: $eps-grid-columns) {
+ @for $i from 1 through $grid-columns {
+ .#{$eps-prefix}grid-item-#{$size}-#{$i} {
+ flex-grow: 0;
+ max-width: percentage($i / $grid-columns);
+ flex-basis: percentage($i / $grid-columns);
+ }
+ }
+}
+
+// generating spacing classes and custom properties
+@mixin grid-spacing-classes($keys, $amp:'&') {
+ @each $key in $keys {
+ #{$amp}-#{$key} {
+ --grid-spacing-gutter: #{spacing($key)};
+ }
+ }
+}
+
+// exporting custom properties
+@mixin grid-custom-properties {
+ & {
+ --grid-spacing-gutters: calc(2 * var(--grid-spacing-gutter));
+ --grid-spacing-width: calc(100% + var(--grid-spacing-gutters));
+ }
+}
diff --git a/packages/ui/src/components/grid/index.js b/packages/ui/src/components/grid/index.js
new file mode 100644
index 0000000..1a0bf05
--- /dev/null
+++ b/packages/ui/src/components/grid/index.js
@@ -0,0 +1,111 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+export default function Grid(props) {
+ const propsMap = {
+ direction: '--direction{{ -VALUE }}',
+ justify: '--justify{{ -VALUE }}',
+ alignContent: '--align-content{{ -VALUE }}',
+ alignItems: '--align-items{{ -VALUE }}',
+ container: '-container',
+ item: '-item',
+ noWrap: '-container--no-wrap',
+ wrapReverse: '-container--wrap-reverse',
+ zeroMinWidth: '-item--zero-min-width',
+ spacing: '-container--spacing',
+ xs: '-item-xs{{ -VALUE }}',
+ sm: '-item-sm{{ -VALUE }}',
+ md: '-item-md{{ -VALUE }}',
+ lg: '-item-lg{{ -VALUE }}',
+ xl: '-item-xl{{ -VALUE }}',
+ xxl: '-item-xxl{{ -VALUE }}',
+ },
+ getStyle = () =>
+ isValidPropValue(props.spacing)
+ ? { '--grid-spacing-gutter': props.spacing }
+ : {},
+ classes = [
+ getBaseClassName(),
+ props.className,
+ ...getPropsClasses(propsMap, props),
+ ];
+
+ return (
+ '' !== classItem)
+ .join(' ')}
+ >
+ {props.children}
+
+ );
+}
+
+function getPropsClasses(propsMap, props) {
+ const classes = [];
+
+ for (const prop in propsMap) {
+ if (props[prop]) {
+ const propValue = isValidPropValue(props[prop]) ? props[prop] : '';
+
+ classes.push(
+ getBaseClassName() +
+ renderPropValueBrackets(propsMap[prop], propValue)
+ );
+ }
+ }
+
+ return classes;
+}
+
+function renderPropValueBrackets(propClass, propValue) {
+ const brackets = propClass.match(/{{.*?}}/);
+
+ if (brackets) {
+ const bracketsValue = propValue
+ ? brackets[0].replace(/[{ }]/g, '').replace(/value/i, propValue)
+ : '';
+
+ propClass = propClass.replace(brackets[0], bracketsValue);
+ }
+
+ return propClass;
+}
+
+function getBaseClassName() {
+ return 'eps-grid';
+}
+
+function isValidPropValue(propValue) {
+ return propValue && 'boolean' !== typeof propValue;
+}
+
+Grid.propTypes = {
+ className: PropTypes.string,
+ direction: PropTypes.string,
+ justify: PropTypes.string,
+ alignContent: PropTypes.string,
+ alignItems: PropTypes.string,
+ container: PropTypes.bool,
+ item: PropTypes.bool,
+ noWrap: PropTypes.bool,
+ wrapReverse: PropTypes.bool,
+ zeroMinWidth: PropTypes.bool,
+ spacing: PropTypes.number,
+ xs: PropTypes.oneOfType([PropTypes.number, PropTypes.bool]),
+ sm: PropTypes.oneOfType([PropTypes.number, PropTypes.bool]),
+ md: PropTypes.oneOfType([PropTypes.number, PropTypes.bool]),
+ lg: PropTypes.oneOfType([PropTypes.number, PropTypes.bool]),
+ xl: PropTypes.oneOfType([PropTypes.number, PropTypes.bool]),
+ xxl: PropTypes.oneOfType([PropTypes.number, PropTypes.bool]),
+ children: PropTypes.oneOfType([
+ PropTypes.string,
+ PropTypes.object,
+ PropTypes.arrayOf(PropTypes.object),
+ ]).isRequired,
+};
+
+Grid.defaultProps = {
+ className: '',
+};
diff --git a/packages/ui/src/components/grid/style.scss b/packages/ui/src/components/grid/style.scss
new file mode 100644
index 0000000..a90750f
--- /dev/null
+++ b/packages/ui/src/components/grid/style.scss
@@ -0,0 +1,198 @@
+// COMPONENT: GRID
+// Defines Grid and Item blocks
+
+@import "api";
+
+
+.#{$eps-prefix}grid {
+ @include grid-custom-properties();
+
+ // Flex Structure rules
+ // apply to all screen size
+ // @props: container
+ &-container {
+ display: flex;
+ flex-wrap: wrap;
+ width: 100%;
+
+ // @prop: no-wrap
+ &--no-wrap {
+ flex-wrap: nowrap;
+ }
+
+ &--wrap-reverse {
+ flex-wrap: wrap-reverse;
+ }
+
+ // @prop: spacing[5,8,10,12,16]
+ // defined within container only
+ // item padding can be 8,10,12,16
+ // container width and negative margin are calculated dynamically
+ // @markup
+ &--spacing {
+ --grid-row-gutter: calc(var(--grid-spacing-gutter) * -#{px-to-rem(1)});
+ width: var(--grid-spacing-width);
+ margin: var(--grid-row-gutter);
+
+ > .#{$eps-prefix}grid-item {
+ padding: calc(var(--grid-spacing-gutter) * #{px-to-rem(1)});
+ }
+ }
+ }
+
+ // - direction
+ // @props: direction[
+ // 'row'
+ // 'row-reverse'
+ // 'column'
+ // 'column-reverse'
+ // ]
+ &--direction {
+ &-row {
+ flex-direction: row;
+
+ &-reverse {
+ flex-direction: row-reverse;
+ }
+ }
+
+ &-column {
+ flex-direction: column;
+
+ &-reverse {
+ flex-direction: column-reverse;
+ }
+ }
+ }
+
+ // Flex alignments
+ // @props: justifyContent[
+ // 'stretch'
+ // 'start'
+ // 'center'
+ // 'end'
+ // 'space-between'
+ // 'space-around'
+ // ]
+ // default: 'stretch'
+ &--justify {
+ &-stretch {
+ justify-content: stretch;
+ }
+
+ &-start {
+ justify-content: flex-start;
+ }
+
+ &-center {
+ justify-content: center;
+ }
+
+ &-end {
+ justify-content: flex-end;
+ }
+
+ &-space-between {
+ justify-content: space-between;
+ }
+
+ &-space-around {
+ justify-content: space-around;
+ }
+
+ &-space-evenly {
+ justify-content: space-evenly;
+ }
+ }
+
+ // @props: alignContent[
+ // 'stretch'
+ // 'start'
+ // 'center'
+ // 'end'
+ // 'space-between'
+ // 'space-around'
+ // ]
+ // default: 'stretch'
+ &--align-content {
+ &-stretch {
+ align-content: stretch;
+ }
+
+ &-start {
+ align-content: flex-start;
+ }
+
+ &-center {
+ align-content: center;
+ }
+
+ &-end {
+ align-content: flex-end;
+ }
+
+ &-space-between {
+ align-content: space-between;
+ }
+ }
+
+ // @props: alignItems[
+ // 'start'
+ // 'center'
+ // 'end'
+ // 'baseline'
+ // 'stretch'
+ // ]
+ // default: 'stretch'
+ &--align-items {
+ &-start {
+ align-items: flex-start;
+ }
+
+ &-center {
+ align-items: center;
+ }
+
+ &-end {
+ align-items: flex-end;
+ }
+
+ &-baseline {
+ align-items: baseline;
+ }
+
+ &-stretch {
+ align-items: stretch;
+ }
+ }
+}
+
+// - Grid Item assumes display flex and wrap on parent
+// - Defining Item Base Properties
+// - Generating flex item traits within @media breakpoints
+
+// Zero min width to disable overflow while container is no wrap
+
+// @prop: ZeroMinWidth
+// @markup or and so on..
+.#{$eps-prefix}grid-item--zero-min-width {
+ min-width: 0;
+}
+
+// Item flex sizing, auto grid
+// @prop: [xs,sm,md,lg,xl,xxl]
+// @markup or and so on..
+// No need for container:
+// @prop: [xs={@num<=12}],sm={@num<=12},md={@num<=12},lg={@num<=12},xl={@num<=12},xxl={@num<=12}]
+// @markup or and so on..
+@each $breakpoint in map-keys($breakpoints) {
+ @media screen and (min-width: #{map-get($breakpoints, $breakpoint)}) {
+ @include grid-item-auto($breakpoint);
+ }
+}
+// Generating cols per each media breakpoint
+@each $breakpoint in map-keys($breakpoints) {
+ @media screen and (min-width: #{map-get($breakpoints, $breakpoint)}) {
+ @include grid-col-generator($breakpoint);
+ }
+}
diff --git a/packages/ui/src/components/heading/index.js b/packages/ui/src/components/heading/index.js
new file mode 100644
index 0000000..63b48fc
--- /dev/null
+++ b/packages/ui/src/components/heading/index.js
@@ -0,0 +1,36 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+export default function Heading(props) {
+ const baseClassName = 'eps',
+ allowedTags = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
+ classes = [props.className],
+ tagName = allowedTags.includes(props.tag) ? props.tag : 'h1';
+
+ if (props.variant) {
+ classes.push(baseClassName + '-' + props.variant);
+ }
+
+ return React.createElement(
+ tagName,
+ {
+ className: classes.filter((classItem) => classItem).join(' '),
+ },
+ props.children
+ );
+}
+
+Heading.propTypes = {
+ className: PropTypes.string,
+ children: PropTypes.oneOfType([
+ PropTypes.string,
+ PropTypes.object,
+ PropTypes.arrayOf(PropTypes.object),
+ ]).isRequired,
+ tag: PropTypes.string,
+ variant: PropTypes.string.isRequired,
+};
+
+Heading.defaultProps = {
+ className: '',
+};
diff --git a/packages/ui/src/components/icon/index.js b/packages/ui/src/components/icon/index.js
new file mode 100644
index 0000000..da58016
--- /dev/null
+++ b/packages/ui/src/components/icon/index.js
@@ -0,0 +1,14 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+export default function Icon(props) {
+ return ;
+}
+
+Icon.propTypes = {
+ className: PropTypes.string.isRequired,
+};
+
+Icon.defaultProps = {
+ className: '',
+};
diff --git a/packages/ui/src/components/modal/index.js b/packages/ui/src/components/modal/index.js
new file mode 100644
index 0000000..476af74
--- /dev/null
+++ b/packages/ui/src/components/modal/index.js
@@ -0,0 +1,118 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import Button from '../button';
+import Grid from '../grid';
+import Icon from '../icon';
+
+export default class ModalProvider extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ hideModal: this.hideModal,
+ show: false,
+ showModal: this.showModal,
+ };
+ }
+
+ hideModal = () => {
+ this.setState({
+ show: false,
+ });
+ };
+
+ showModal = () => {
+ this.setState({
+ show: true,
+ });
+ };
+
+ render() {
+ return (
+ <>
+
+
+ {this.props.children}
+
+ >
+ );
+ }
+}
+
+ModalProvider.propTypes = {
+ children: PropTypes.node.isRequired,
+ toggleButtonProps: PropTypes.object.isRequired,
+ title: PropTypes.string.isRequired,
+};
+
+class Modal extends React.Component {
+ modalRef = React.createRef();
+ closeRef = React.createRef();
+
+ closeModal = (e) => {
+ const { modalProps } = this.props;
+ const node = this.modalRef.current,
+ closeNode = this.closeRef.current,
+ isInCloseNode = closeNode && closeNode.contains(e.target);
+ // ignore if click is inside the modal
+ if (node && node.contains(e.target) && !isInCloseNode) {
+ return;
+ }
+
+ modalProps.hideModal();
+ };
+
+ componentDidMount() {
+ document.addEventListener('mousedown', this.closeModal, false);
+ }
+
+ componentWillUnmount() {
+ document.removeEventListener('mousedown', this.closeModal, false);
+ }
+
+ render() {
+ const { modalProps, children } = this.props;
+ return modalProps.show ? (
+ // TODO: Fix eslint issue
+ /* eslint-disable-next-line */
+
+
+
+
+
+ {this.props.title}
+
+
+
+
+
+
+
+
{children}
+
+
+ ) : null;
+ }
+}
+
+Modal.propTypes = {
+ modalProps: PropTypes.object.isRequired,
+ children: PropTypes.any.isRequired,
+ title: PropTypes.string.isRequired,
+};
diff --git a/packages/ui/src/components/modal/style.scss b/packages/ui/src/components/modal/style.scss
new file mode 100644
index 0000000..2774266
--- /dev/null
+++ b/packages/ui/src/components/modal/style.scss
@@ -0,0 +1,92 @@
+$eps-modal-background-color: theme-colors(light);
+$eps-modal-width: px-to-rem(700);
+$eps-modal-border-radius: $eps-radius;
+$eps-modal-overlay: rgba(theme-colors(dark), $opacity-05);
+$eps-modal-zindex: $eps-zindex-modal-backdrop;
+$eps-modal-header-type: type(text, md);
+$eps-modal-header-background-color: theme-colors(info);
+$eps-modal-header-color: theme-colors(light);
+$eps-modal-header-height: spacing(44);
+$eps-modal-header-padding: spacing(10) spacing(16);
+$eps-modal-icon-spacing: spacing(10);
+$eps-modal-body-padding: spacing(30);
+$eps-modal-close-button-spacing: spacing(16);
+$eps-modal-close-button-border: solid 1px theme-colors(light);
+$eps-modal-animation: $eps-pop-animation;
+$eps-tip-padding-start: spacing(12);
+$eps-tip-border-start: 3px solid theme-colors(info);
+$eps-tip-margin-bottom: spacing(30);
+$eps-tip-margin-top: spacing(30);
+
+:root {
+ --eps-modal-background-color: #{$eps-modal-background-color};
+ --eps-modal-header-background-color: #{$eps-modal-header-background-color};
+}
+
+// Dark
+
+$eps-dark-modal-background-color: dark-tints(700);
+$eps-dark-modal-header-background-color: dark-theme-colors(info);
+
+.eps-theme-dark {
+ --eps-modal-background-color: #{$eps-dark-modal-background-color};
+ --eps-modal-header-background-color: #{$eps-dark-modal-header-background-color};
+}
+
+/** ----------------------------------------------------------------
+ EPS Modal
+---------------------------------------------------------------- */
+
+.#{$eps-prefix}modal {
+ max-width: $eps-modal-width;
+ background: var(--eps-modal-background-color);
+ border-radius: $eps-modal-border-radius;
+ animation: $eps-modal-animation;
+ overflow: hidden;
+
+ &__overlay {
+ background: $eps-modal-overlay;
+ position: fixed;
+ display: flex;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ align-items: center;
+ justify-content: center;
+ z-index: $eps-modal-zindex;
+ }
+
+ &__header {
+ font-size: $eps-modal-header-type;
+ background: var(--eps-modal-header-background-color);
+ color: $eps-modal-header-color;
+ height: $eps-modal-header-height;
+ padding: $eps-modal-header-padding;
+ }
+
+ &__icon {
+ margin-inline-end: $eps-modal-icon-spacing;
+ }
+
+ &__body {
+ padding: $eps-modal-body-padding;
+ }
+
+ &__tip, .#{$eps-prefix}tip {
+ padding-inline-start: $eps-tip-padding-start;
+ border-inline-start: $eps-tip-border-start;
+ &:not(:last-child) {
+ margin-bottom: $eps-tip-margin-bottom;
+ }
+
+ &:not(:first-child) {
+ margin-top: $eps-tip-margin-top;
+ }
+ }
+
+ &__close-wrapper {
+ padding-inline-start: $eps-modal-close-button-spacing;
+ border-inline-start: $eps-modal-close-button-border;
+ }
+}
diff --git a/packages/ui/src/components/popover/api.scss b/packages/ui/src/components/popover/api.scss
new file mode 100644
index 0000000..7bad2d3
--- /dev/null
+++ b/packages/ui/src/components/popover/api.scss
@@ -0,0 +1,51 @@
+// POPOVER: API
+$eps-popover-padding-y: 10px;
+$eps-popover-background-color: theme-colors(light);
+$eps-popover-border-radius: $eps-radius;
+$eps-popover-arrow-color: theme-colors(light);
+$eps-popover-arrow-width: 16px;
+$eps-popover-arrow-height: 9px;
+$eps-popover-arrow-position-start: 14px;
+$eps-popover-box-shadow-color: rgba(0, 0, 0, 0.15);
+$eps-popover-box-shadow-size: 0px 1px 20px; // add to globals
+$eps-popover-item-font-size: type(size, "11");
+$eps-popover-item-line-height: type(size, "13"); //todo: refactor
+$eps-popover-font-weight: $eps-font-weight-medium;
+$eps-popover-item-spacing-y: spacing(5);
+$eps-popover-item-spacing-x: spacing(16);
+$eps-popover-item-background-color: theme-colors(light);
+$eps-popover-item-color: tints(600);
+$eps-popover-item-hover-color: tints(700);
+$eps-popover-item-danger-hover-color: theme-colors(danger);
+
+// dark theme
+$eps-dark-popover-background-color: dark-tints(500);
+$eps-dark-popover-item-color: theme-colors(light);
+$eps-dark-popover-item-hover-color: dark-tints(100);
+$eps-dark-popover-item-danger-hover-color: dark-theme-colors(danger);
+$eps-dark-popover-item-background-color: $eps-dark-popover-background-color;
+$eps-dark-popover-box-shadow-color: rgba(0, 0, 0, 0.15);
+$eps-dark-popover-box-shadow-size: 0px 1px 20px;
+$eps-dark-popover-arrow-color: $eps-dark-popover-background-color;
+
+:root {
+ --popover-background-color: #{$eps-popover-background-color};
+ --popover-item-color: #{$eps-popover-item-color};
+ --popover-item-hover-color: #{$eps-popover-item-hover-color};
+ --popover-item-danger-hover-color: #{$eps-popover-item-danger-hover-color};
+ --popover-item-background-color: #{$eps-popover-item-background-color};
+ --popover-box-shadow-color: #{$eps-popover-box-shadow-color};
+ --popover-box-shadow-size: #{$eps-popover-box-shadow-size};
+ --popover-arrow-color: #{$eps-popover-arrow-color};
+}
+
+.eps-theme-dark {
+ --popover-background-color: #{$eps-dark-popover-background-color};
+ --popover-item-color: #{$eps-dark-popover-item-color};
+ --popover-item-hover-color: #{$eps-dark-popover-item-hover-color};
+ --popover-item-danger-hover-color: #{$eps-dark-popover-item-danger-hover-color};
+ --popover-item-background-color: #{$eps-dark-popover-item-background-color};
+ --popover-box-shadow-color: #{$eps-dark-popover-box-shadow-color};
+ --popover-box-shadow-size: #{$eps-dark-popover-box-shadow-size};
+ --popover-arrow-color: #{$eps-dark-popover-arrow-color};
+}
diff --git a/packages/ui/src/components/popover/index.js b/packages/ui/src/components/popover/index.js
new file mode 100644
index 0000000..3b56180
--- /dev/null
+++ b/packages/ui/src/components/popover/index.js
@@ -0,0 +1,32 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+export default function Popover(props) {
+ // TODO: fix eslint issues.
+ /* eslint-disable */
+ return (
+ <>
+
+
+ >
+ );
+ /* eslint-enable */
+}
+
+Popover.propTypes = {
+ children: PropTypes.any.isRequired,
+ className: PropTypes.string,
+ closeFunction: PropTypes.func,
+};
+
+Popover.defaultProps = {
+ className: '',
+};
diff --git a/packages/ui/src/components/popover/style.scss b/packages/ui/src/components/popover/style.scss
new file mode 100644
index 0000000..cc9858d
--- /dev/null
+++ b/packages/ui/src/components/popover/style.scss
@@ -0,0 +1,74 @@
+@import "api";
+
+// checkbox label
+.#{$eps-prefix}popover {
+ padding: $eps-popover-padding-y 0;
+ background-color: var(--popover-background-color);
+ box-shadow: var(--popover-box-shadow-size) var(--popover-box-shadow-color);
+ list-style: none;
+ display: flex;
+ flex-direction: column;
+ min-width: 120px;
+ border-radius: $eps-popover-border-radius;
+ position: absolute;
+ z-index: $eps-zindex-popover;
+ margin-top: $eps-popover-arrow-height;
+ transform: translateX(-50%);
+ left: px-to-rem(4);
+
+ &__background {
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ z-index: $eps-zindex-modal-backdrop;
+ }
+
+ &__container {
+ position: relative;
+ }
+
+ &::before {
+ content: "";
+ display: block;
+ position: absolute;
+ width: $eps-popover-arrow-width;
+ height: $eps-popover-arrow-height;
+ margin: 0 $eps-popover-border-radius $eps-popover-arrow-height;
+ top: -$eps-popover-arrow-height;
+ left: 50%;
+ transform: translateX(-50%);
+ border-color: transparent;
+ border-style: solid;
+ border-width: 0 ($eps-popover-arrow-width / 2) $eps-popover-arrow-height ($eps-popover-arrow-width / 2);
+ border-bottom-color: var(--popover-arrow-color);
+ }
+
+ &__item {
+ padding: $eps-popover-item-spacing-y $eps-popover-item-spacing-x;
+ background-color: var(--popover-item-background-color);
+ color: var(--popover-item-color);
+ font-size: $eps-popover-item-font-size;
+ font-weight: $eps-popover-font-weight;
+ line-height: $eps-popover-item-line-height;
+ width: 100%;
+ align-items: center;
+ cursor: pointer;
+
+ &:hover {
+ color: var(--popover-item-hover-color);
+ }
+
+ &--danger {
+ &:hover {
+ color: var(--popover-item-danger-hover-color);
+ }
+ }
+
+ .#{$eps-prefix}icon {
+ font-size: inherit;
+ margin-inline-end: spacing(5);
+ }
+ }
+}
diff --git a/packages/ui/src/components/select/index.js b/packages/ui/src/components/select/index.js
new file mode 100644
index 0000000..29c7ae2
--- /dev/null
+++ b/packages/ui/src/components/select/index.js
@@ -0,0 +1,47 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+export default function Select(props) {
+ // TODO: fix eslint issue
+ return (
+ /* eslint-disable-next-line */
+
+ );
+}
+Select.propTypes = {
+ className: PropTypes.string,
+ value: PropTypes.string,
+ onChange: PropTypes.func,
+ options: PropTypes.array,
+ elRef: PropTypes.object,
+ multiple: PropTypes.bool,
+};
+Select.defaultProps = {
+ className: '',
+ options: [],
+};
diff --git a/packages/ui/src/components/text/index.js b/packages/ui/src/components/text/index.js
new file mode 100644
index 0000000..58685c3
--- /dev/null
+++ b/packages/ui/src/components/text/index.js
@@ -0,0 +1,32 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+export default function Text(props) {
+ const baseClassName = 'eps',
+ classes = [props.className],
+ tagName = props.tag,
+ variant =
+ props.variant && 'md' !== props.variant ? '-' + props.variant : '';
+
+ classes.push(baseClassName + '-text' + variant);
+
+ return React.createElement(
+ tagName,
+ {
+ className: classes.filter((classItem) => classItem).join(' '),
+ },
+ props.children
+ );
+}
+
+Text.propTypes = {
+ className: PropTypes.string,
+ variant: PropTypes.string,
+ tag: PropTypes.string,
+ children: PropTypes.any.isRequired,
+};
+
+Text.defaultProps = {
+ className: '',
+ tag: 'p',
+};
diff --git a/packages/ui/src/index.js b/packages/ui/src/index.js
new file mode 100644
index 0000000..22a1641
--- /dev/null
+++ b/packages/ui/src/index.js
@@ -0,0 +1,18 @@
+import './style.scss';
+
+export * as utils from './utils';
+
+export { default as AddNewButton } from './components/add-new-button';
+export { default as Button } from './components/button';
+export { default as Card } from './components/card';
+export { default as Checkbox } from './components/checkbox';
+export { default as CssGrid } from './components/css-grid';
+export { default as Dialog } from './components/dialog';
+export { default as DragDrop } from './components/drag-drop';
+export { default as Grid } from './components/grid';
+export { default as Heading } from './components/heading';
+export { default as Icon } from './components/icon';
+export { default as Modal } from './components/modal';
+export { default as Popover } from './components/popover';
+export { default as Select } from './components/select';
+export { default as Text } from './components/text';
diff --git a/packages/ui/src/style.scss b/packages/ui/src/style.scss
new file mode 100644
index 0000000..0c08ca9
--- /dev/null
+++ b/packages/ui/src/style.scss
@@ -0,0 +1,13 @@
+@import "./style/common";
+@import "./style/base";
+
+@import "./components/add-new-button/style";
+@import "./components/button/style";
+@import "./components/card/style";
+@import "./components/checkbox/style";
+@import "./components/css-grid/style";
+@import "./components/dialog/style";
+@import "./components/drag-drop/style";
+@import "./components/grid/style";
+@import "./components/modal/style";
+@import "./components/popover/style";
diff --git a/packages/ui/src/style/_base.scss b/packages/ui/src/style/_base.scss
new file mode 100644
index 0000000..cd08f05
--- /dev/null
+++ b/packages/ui/src/style/_base.scss
@@ -0,0 +1,9 @@
+@import "//fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap";
+@import "base/breakpoints";
+@import "base/custom-properties";
+@import "base/dark/dark-custom-properties";
+@import "base/reset";
+@import "base/animations";
+@import "base/typography";
+@import "base/utilities";
+@import "shame";
diff --git a/packages/ui/src/style/_common.scss b/packages/ui/src/style/_common.scss
new file mode 100644
index 0000000..8de29e0
--- /dev/null
+++ b/packages/ui/src/style/_common.scss
@@ -0,0 +1,3 @@
+@import "./functions";
+@import "./tokens";
+@import "./mixins";
diff --git a/packages/ui/src/style/_functions.scss b/packages/ui/src/style/_functions.scss
new file mode 100644
index 0000000..85a539c
--- /dev/null
+++ b/packages/ui/src/style/_functions.scss
@@ -0,0 +1,6 @@
+// Functions
+@import "functions/deep-map";
+@import "functions/map-collect";
+@import "functions/prefix";
+@import "functions/size";
+@import "functions/px-to-rem";
diff --git a/packages/ui/src/style/_helpers.scss b/packages/ui/src/style/_helpers.scss
new file mode 100644
index 0000000..e69de29
diff --git a/packages/ui/src/style/_mixins.scss b/packages/ui/src/style/_mixins.scss
new file mode 100644
index 0000000..7cdd0b9
--- /dev/null
+++ b/packages/ui/src/style/_mixins.scss
@@ -0,0 +1,4 @@
+// MIXINS: Common mixins
+@import "mixins/create-atom";
+@import "mixins/screen-reader";
+@import "mixins/text-truncate";
diff --git a/packages/ui/src/style/_shame.scss b/packages/ui/src/style/_shame.scss
new file mode 100644
index 0000000..48d0e66
--- /dev/null
+++ b/packages/ui/src/style/_shame.scss
@@ -0,0 +1,54 @@
+// SHAME:
+// Purpose of this partial is to gather all ad hock, not structured code.
+// This will enable to refactor it bit by bit into structured code without effecting current output.
+
+//todo: discuss, is this needed?
+
+.video-wrapper {
+ position: relative;
+ padding-bottom: $eps-ratio-16-9;
+ height: 0;
+
+ iframe {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ }
+}
+
+.#{$eps-prefix}separator {
+ margin-bottom: spacing(44);
+}
+
+
+.eps-theme-dark {
+ --e-app-back-button-color: #{dark-tints(200)};
+}
+
+.back-button, .e-app-back-button {
+ --button-background-color: var(--e-app-back-button-color, #{tints(500)});
+ margin-bottom: spacing(24);
+
+ .eps-icon {
+ margin-inline-end: spacing(5);
+ }
+}
+
+.eps-theme-dark {
+ --input-border-color: --hr-color;
+}
+
+.#{$eps-prefix}input {
+ border: 1px solid var(--hr-color);
+ border-radius: $eps-radius;
+ background: transparent;
+ color: inherit;
+ height: spacing(30);
+ padding: 0 spacing(5);
+
+ &--block {
+ width: 100%;
+ }
+}
diff --git a/packages/ui/src/style/_tokens.scss b/packages/ui/src/style/_tokens.scss
new file mode 100644
index 0000000..7d8ee97
--- /dev/null
+++ b/packages/ui/src/style/_tokens.scss
@@ -0,0 +1,37 @@
+// Global tokens
+// - Sort Order has meaning
+// -- Core
+@import "./tokens/global";
+@import "./tokens/colors";
+@import "./tokens/theme";
+@import "./tokens/spacing";
+@import "./tokens/font";
+@import "./tokens/type";
+@import "./tokens/ratio";
+@import "./tokens/opacity";
+@import "./tokens/z-index";
+
+// - Sort Order is A-Z
+// -- These tokens might use definitions from core layer
+@import "./tokens/styles/border";
+@import "./tokens/styles/motion";
+@import "./tokens/styles/radius";
+@import "./tokens/styles/shadow";
+
+// Maps
+// - Sorted by roles
+@import "./tokens/maps/opacity-map";
+@import "./tokens/maps/theme-map";
+@import "./tokens/maps/tints-map";
+@import "./tokens/maps/spacing-map";
+@import "./tokens/maps/type-map";
+@import "./tokens/maps/z-index-map";
+@import "./tokens/maps/shadow-map";
+@import "./tokens/maps/atoms";
+
+// Map Semantic functions
+@import "./tokens/map-functions";
+
+// Themes
+@import "themes/dark-tokens";
+
diff --git a/packages/ui/src/style/base/_animations.scss b/packages/ui/src/style/base/_animations.scss
new file mode 100644
index 0000000..35c32d7
--- /dev/null
+++ b/packages/ui/src/style/base/_animations.scss
@@ -0,0 +1,12 @@
+$eps-pop-animation: eps-animation-pop 0.15s cubic-bezier(0.57, 0.53, 0.71, 1.47) forwards;
+
+@keyframes eps-animation-pop {
+ from {
+ transform: scale(0.75);
+ opacity: 0;
+ }
+ to {
+ transform: scale(1);
+ opacity: 1;
+ }
+}
diff --git a/packages/ui/src/style/base/_breakpoints.scss b/packages/ui/src/style/base/_breakpoints.scss
new file mode 100644
index 0000000..2116aec
--- /dev/null
+++ b/packages/ui/src/style/base/_breakpoints.scss
@@ -0,0 +1,7 @@
+$breakpoints: (
+ sm: 480px, // Mobile landscape
+ md: 768px, // Tablet
+ lg: 1025px, // Desktop
+ xl: 1440px, // Larger devices
+ xxl: 1600px // Largest devices
+);
diff --git a/packages/ui/src/style/base/_custom-properties.scss b/packages/ui/src/style/base/_custom-properties.scss
new file mode 100644
index 0000000..2f6d4da
--- /dev/null
+++ b/packages/ui/src/style/base/_custom-properties.scss
@@ -0,0 +1,24 @@
+// Base: Custom properties
+// - Generated via loops from relevant maps.
+
+// Custom variable values only support SassScript inside `#{}`.
+
+:root {
+ @each $color, $value in $eps-theme-colors {
+ @if map-get($eps-theme-colors, $color) {
+ --#{$color}: #{$value};
+ }
+ }
+
+ @each $color, $value in $eps-theme-elements-colors {
+ @if map-get($eps-theme-elements-colors, $color) {
+ --#{$color}: #{$value};
+ }
+ }
+
+ @each $color, $value in $eps-tints {
+ @if map-get($eps-tints, $color) {
+ --gray-#{$color}: #{$value};
+ }
+ }
+}
diff --git a/packages/ui/src/style/base/_layout.scss b/packages/ui/src/style/base/_layout.scss
new file mode 100644
index 0000000..e69de29
diff --git a/packages/ui/src/style/base/_reset.scss b/packages/ui/src/style/base/_reset.scss
new file mode 100644
index 0000000..be57173
--- /dev/null
+++ b/packages/ui/src/style/base/_reset.scss
@@ -0,0 +1,212 @@
+// BASE: Reset
+*,
+*::before,
+*::after {
+ box-sizing: border-box;
+}
+
+html {
+ font-family: sans-serif;
+ line-height: 1.15;
+ -webkit-text-size-adjust: 100%;
+ -webkit-tap-highlight-color: rgba($color-black, 0);
+}
+
+// stylelint-disable-next-line selector-list-comma-newline-after
+article, aside, figcaption, figure, footer, header, hgroup, main, nav, section {
+ display: block;
+}
+
+// Body
+
+body {
+ margin: 0;
+ font-family: $eps-font-family;
+ font-size: $eps-body-font-size;
+ font-weight: $eps-font-weight-base;
+ line-height: $eps-line-height-base;
+ color: var(--body-color);
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ background-color: var(--body-bg);
+}
+
+::selection {
+ background-color: rgba(theme-colors(cta), $opacity-05);
+}
+
+[tabindex="-1"]:focus:not(:focus-visible) {
+ outline: 0 !important;
+}
+
+// Typography
+// Reset header Tags
+h1, h2, h3, h4, h5, h6 {
+ font-size:100%;
+ margin:0;
+ padding:0;
+ line-height:inherit;
+ font-weight:normal;
+}
+
+// Reset margins on paragraphs
+p {
+ margin-top: 0;
+ margin-bottom: $eps-paragraph-margin-bottom;
+}
+
+b,
+strong {
+ font-weight: $eps-font-weight-bold; // Add the correct font weight in Chrome, Edge, and Safari
+}
+
+small {
+ font-size: $eps-small-font-size; // Add the correct font size in all browsers
+}
+
+// Links
+a {
+ color: $eps-link-color;
+ background-color: transparent; // Remove the gray background on active links in IE 10.
+
+ &,
+ &:active,
+ &:hover,
+ &:focus {
+ text-decoration: $eps-link-decoration;
+ }
+
+ &:focus,
+ &:hover {
+ color: $eps-link-hover-color;
+ text-decoration: $eps-link-hover-decoration;
+ }
+}
+
+a:not([href]) {
+ color: inherit;
+ text-decoration: none;
+
+ &:hover {
+ color: inherit;
+ text-decoration: none;
+ }
+}
+
+// Code
+pre,
+code,
+kbd,
+samp {
+ font-family: $font-family-monospace;
+ font-size: 1em;
+}
+
+// Figures
+figure {
+ // Apply a consistent margin strategy (matches our type styles).
+ margin: 0 0 0;
+}
+
+// Images and content
+
+img {
+ vertical-align: middle;
+ border-style: none; // Remove the border on images inside links in IE 10-.
+}
+
+svg {
+ overflow: hidden;
+ vertical-align: middle;
+}
+
+
+button {
+ border-radius: 0;
+}
+
+button:focus {
+ outline: 1px dotted;
+ outline: 5px auto -webkit-focus-ring-color;
+}
+
+input,
+button,
+select,
+optgroup,
+textarea {
+ margin: 0;
+ font-family: inherit;
+ font-size: inherit;
+ line-height: inherit;
+}
+
+button,
+input {
+ overflow: visible; // Show the overflow in Edge
+}
+
+button,
+select {
+ text-transform: none; // Remove the inheritance of text transform in Firefox
+}
+
+[role="button"] {
+ cursor: pointer;
+}
+
+select {
+ word-wrap: normal;
+}
+
+
+button,
+[type="button"],
+[type="reset"],
+[type="submit"] {
+ -webkit-appearance: button;
+}
+
+// Opinionated: add "hand" cursor to non-disabled button elements.
+button,
+[type="button"],
+[type="reset"],
+[type="submit"] {
+ &:not(:disabled) {
+ cursor: pointer;
+ }
+}
+
+// Remove inner border and padding from Firefox, but don't restore the outline like Normalize.
+button::-moz-focus-inner,
+[type="button"]::-moz-focus-inner,
+[type="reset"]::-moz-focus-inner,
+[type="submit"]::-moz-focus-inner {
+ padding: 0;
+ border-style: none;
+}
+
+input[type="radio"],
+input[type="checkbox"] {
+ box-sizing: border-box;
+ padding: 0;
+}
+
+
+textarea {
+ overflow: auto;
+ resize: vertical;
+}
+
+
+// Always hide an element with the `hidden` HTML attribute (from PureCSS).
+[hidden] {
+ display: none !important;
+}
+
+// Opinionated resets:
+
+hr {
+ border: 0 none;
+ border-bottom: 1px solid var(--hr-color);
+}
diff --git a/packages/ui/src/style/base/_transitions.scss b/packages/ui/src/style/base/_transitions.scss
new file mode 100644
index 0000000..e69de29
diff --git a/packages/ui/src/style/base/_typography.scss b/packages/ui/src/style/base/_typography.scss
new file mode 100644
index 0000000..57b9715
--- /dev/null
+++ b/packages/ui/src/style/base/_typography.scss
@@ -0,0 +1,81 @@
+// TYPOGRAPHY: Atoms, tags, reusable typography elements
+.#{$eps-prefix}display-1 {
+ @include create-atom(typography, display, 1);
+}
+
+.#{$eps-prefix}display-2 {
+ @include create-atom(typography, display, 2);
+}
+
+.#{$eps-prefix}display-3 {
+ @include create-atom(typography, display, 3);
+}
+
+.#{$eps-prefix}display-4 {
+ @include create-atom(typography, display, 4);
+}
+
+
+h1,
+.#{$eps-prefix}h1 {
+ @include create-atom(typography, heading, 1);
+}
+
+h2,
+.#{$eps-prefix}h2 {
+ @include create-atom(typography, heading, 2);
+}
+
+h3,
+.#{$eps-prefix}h3 {
+ @include create-atom(typography, heading, 3);
+}
+
+h4,
+.#{$eps-prefix}h4 {
+ @include create-atom(typography, heading, 4);
+}
+
+h5,
+.#{$eps-prefix}h5 {
+ @include create-atom(typography, heading, 5);
+}
+
+h6,
+.#{$eps-prefix}h6 {
+ @include create-atom(typography, heading, 6);
+}
+
+// semantic sizing for text
+// todo: should be put !importatnt here? update code and remove comment
+.#{$eps-prefix}text-xxs {
+ @include create-atom(typography, text, xxs);
+}
+
+.#{$eps-prefix}text-xs {
+ @include create-atom(typography, text, xs);
+}
+
+.#{$eps-prefix}text {
+ @include create-atom(typography, text, base);
+}
+
+.#{$eps-prefix}text-sm {
+ @include create-atom(typography, text, sm);
+}
+
+.#{$eps-prefix}text-lg {
+ @include create-atom(typography, text, lg);
+}
+
+.#{$eps-prefix}text-xl {
+ @include create-atom(typography, text, xl);
+}
+
+// todo: placeholders for future semantic work, update or remove
+//.page-title{}
+//.section-title{}
+//.component-title{}
+//.page-subtitle{}
+//.section-subtitle{}
+//.component-subtitle{}
diff --git a/packages/ui/src/style/base/_utilities.scss b/packages/ui/src/style/base/_utilities.scss
new file mode 100644
index 0000000..1c4da75
--- /dev/null
+++ b/packages/ui/src/style/base/_utilities.scss
@@ -0,0 +1,23 @@
+.sr-only {
+ @include sr-only();
+}
+
+@each $breakpoint in map-keys($breakpoints) {
+ @media screen and (min-width: #{map-get($breakpoints, $breakpoint)}) {
+ .text-start-#{$breakpoint} {
+ text-align: start;
+ }
+ }
+
+ @media screen and (min-width: #{map-get($breakpoints, $breakpoint)}) {
+ .text-center-#{$breakpoint} {
+ text-align: center;
+ }
+ }
+
+ @media screen and (min-width: #{map-get($breakpoints, $breakpoint)}) {
+ .text-end-#{$breakpoint} {
+ text-align: end;
+ }
+ }
+}
diff --git a/packages/ui/src/style/base/dark/_dark-custom-properties.scss b/packages/ui/src/style/base/dark/_dark-custom-properties.scss
new file mode 100644
index 0000000..780067b
--- /dev/null
+++ b/packages/ui/src/style/base/dark/_dark-custom-properties.scss
@@ -0,0 +1,23 @@
+// Base: Custom properties
+// - Generated via loops from relevant maps.
+
+// Custom variable values only support SassScript inside `#{}`.
+.eps-theme-dark {
+ @each $color, $value in $eps-dark-theme-colors {
+ @if map-get($eps-dark-theme-colors, $color) {
+ --#{$color}: #{$value};
+ }
+ }
+
+ @each $color, $value in $eps-dark-theme-elements-colors {
+ @if map-get($eps-dark-theme-elements-colors, $color) {
+ --#{$color}: #{$value};
+ }
+ }
+
+ @each $color, $value in $eps-dark-tints {
+ @if map-get($eps-dark-tints, $color) {
+ --gray-#{$color}: #{$value};
+ }
+ }
+}
diff --git a/packages/ui/src/style/functions/_border.scss b/packages/ui/src/style/functions/_border.scss
new file mode 100644
index 0000000..73b47f3
--- /dev/null
+++ b/packages/ui/src/style/functions/_border.scss
@@ -0,0 +1,10 @@
+// Function: Border
+// - @argument: $border-colorm $border-size(default is 1px), $border-style(default is 'solid')
+// - @returns 'border values according to @arguments
+// - use cases:
+// - defining a border without specifying default values
+// - passing semantic values as @arguments
+
+@function border($border-color, $border-size:1px, $border-style:solid){
+ @return #{$border-size} #{$border-style} #{$border-color};
+}
diff --git a/packages/ui/src/style/functions/_deep-map.scss b/packages/ui/src/style/functions/_deep-map.scss
new file mode 100644
index 0000000..8ff8dca
--- /dev/null
+++ b/packages/ui/src/style/functions/_deep-map.scss
@@ -0,0 +1,11 @@
+// map deep get
+@function map-deep-get($map, $keys...) {
+ @each $key in $keys {
+ @if map-has-key($map, $key) {
+ $map: map-get($map, $key);
+ } @else {
+ @error "arguments are:#{$keys}, no key #{$key} found, did you mean #{map-keys($map)}?";
+ }
+ }
+ @return $map;
+}
diff --git a/packages/ui/src/style/functions/_map-collect.scss b/packages/ui/src/style/functions/_map-collect.scss
new file mode 100644
index 0000000..99a8dad
--- /dev/null
+++ b/packages/ui/src/style/functions/_map-collect.scss
@@ -0,0 +1,12 @@
+//Map Collect function
+// Since the builtin map-merge function in Sass only take 2 arguments, it can only merge 2 maps at a time.
+// The map-collect function below allows you to combine multiple maps together in a cleaner way.
+
+@function map-collect($maps...) {
+ $collection: ();
+
+ @each $map in $maps {
+ $collection: map-merge($collection, $map);
+ }
+ @return $collection;
+}
diff --git a/packages/ui/src/style/functions/_prefix.scss b/packages/ui/src/style/functions/_prefix.scss
new file mode 100644
index 0000000..84545b7
--- /dev/null
+++ b/packages/ui/src/style/functions/_prefix.scss
@@ -0,0 +1,12 @@
+// Function: Prefix
+// - Argument: string
+// - Output string + hypen, E.g: .#{$prefix}some-element => .prefix-some-element
+
+
+@function prefix($prefix:null){
+ @if $prefix{
+ @return $prefix + "-";
+ } @else {
+ @return null;
+ }
+}
diff --git a/packages/ui/src/style/functions/_px-to-rem.scss b/packages/ui/src/style/functions/_px-to-rem.scss
new file mode 100644
index 0000000..7274a18
--- /dev/null
+++ b/packages/ui/src/style/functions/_px-to-rem.scss
@@ -0,0 +1,3 @@
+@function px-to-rem($multiplier, $unit:0.0625rem) {
+ @return $multiplier * $unit;
+}
diff --git a/packages/ui/src/style/functions/_size.scss b/packages/ui/src/style/functions/_size.scss
new file mode 100644
index 0000000..4b7d86d
--- /dev/null
+++ b/packages/ui/src/style/functions/_size.scss
@@ -0,0 +1,10 @@
+// Function: size
+// Simple Rem based multiplier
+// - Use to convert pixel dimension to REM units
+// - Default is 0.5rem (8px) which is our Spacing unit.
+// - Optional: Add variable based value to $unit when 1rem is not 16px.
+// E.g: size(5) will output: 2.5rem which is 40px;
+
+@function size($multiplier, $unit:0.5rem) {
+ @return $multiplier * $unit;
+}
diff --git a/packages/ui/src/style/mixins/_create-atom.scss b/packages/ui/src/style/mixins/_create-atom.scss
new file mode 100644
index 0000000..99600e3
--- /dev/null
+++ b/packages/ui/src/style/mixins/_create-atom.scss
@@ -0,0 +1,12 @@
+// MIXIN: Create Atom
+// - This mixin is a small to for creating an atom selector
+// - This mixin uses the 'atomize' function which uses '$eps-atoms' map
+// - Each Atom is configured within map.
+// - Map key are 'properties' and values are mapped to tokens.
+// - Please see 'tokens/,aps/_atoms.css' for more info.
+@mixin create-atom($keys...) {
+ $map: atomizer($keys...);
+ @each $key, $value in $map {
+ #{$key}: $value;
+ }
+}
diff --git a/packages/ui/src/style/mixins/_screen-reader.scss b/packages/ui/src/style/mixins/_screen-reader.scss
new file mode 100644
index 0000000..2123039
--- /dev/null
+++ b/packages/ui/src/style/mixins/_screen-reader.scss
@@ -0,0 +1,34 @@
+// Only display content to screen readers
+//
+// See: https://a11yproject.com/posts/how-to-hide-content/
+// See: https://hugogiraudel.com/2016/10/13/css-hide-and-seek/
+
+@mixin sr-only() {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px; // Fix for https://github.com/twbs/bootstrap/issues/25686
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ white-space: nowrap;
+ border: 0;
+}
+
+// Use in conjunction with .sr-only to only display content when it's focused.
+//
+// Useful for "Skip to main content" links; see https://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1
+//
+// Credit: HTML5 Boilerplate
+
+@mixin sr-only-focusable() {
+ &:active,
+ &:focus {
+ position: static;
+ width: auto;
+ height: auto;
+ overflow: visible;
+ clip: auto;
+ white-space: normal;
+ }
+}
diff --git a/packages/ui/src/style/mixins/_text-truncate.scss b/packages/ui/src/style/mixins/_text-truncate.scss
new file mode 100644
index 0000000..7a25ea9
--- /dev/null
+++ b/packages/ui/src/style/mixins/_text-truncate.scss
@@ -0,0 +1,8 @@
+// Utilities: Text truncate
+// Requires inline-block or block for proper styling
+
+@mixin text-truncate() {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
diff --git a/packages/ui/src/style/themes/_dark-tokens.scss b/packages/ui/src/style/themes/_dark-tokens.scss
new file mode 100644
index 0000000..9c271fc
--- /dev/null
+++ b/packages/ui/src/style/themes/_dark-tokens.scss
@@ -0,0 +1,14 @@
+// Scheme: Dark,
+// -- tokens & maps
+// dark theme
+@import "dark/tokens/dark-theme";
+
+// dark styles tokens
+@import "dark/tokens/styles/dark-shadow";
+
+// Maps
+@import "dark/tokens/maps/dark-theme-map";
+@import "dark/tokens/maps/dark-tints-map";
+
+// Functions
+@import "dark/tokens/dark-map-functions";
diff --git a/packages/ui/src/style/themes/dark/tokens/_dark-map-functions.scss b/packages/ui/src/style/themes/dark/tokens/_dark-map-functions.scss
new file mode 100644
index 0000000..d7ab25b
--- /dev/null
+++ b/packages/ui/src/style/themes/dark/tokens/_dark-map-functions.scss
@@ -0,0 +1,14 @@
+// Theme: Dark | Tokens: map functions
+// - Theme specific map based functions
+// Below functions can be duplicated and modified for Themes
+@function dark-theme-colors($keys...) {
+ @return map-deep-get($eps-dark-theme-colors, $keys...);
+}
+
+@function dark-theme-elements-colors($keys...) {
+ @return map-deep-get($eps-dark-theme-elements-colors, $keys...);
+}
+
+@function dark-tints($keys...) {
+ @return map-deep-get($eps-dark-tints, $keys...);
+}
diff --git a/packages/ui/src/style/themes/dark/tokens/_dark-theme.scss b/packages/ui/src/style/themes/dark/tokens/_dark-theme.scss
new file mode 100644
index 0000000..bc0b033
--- /dev/null
+++ b/packages/ui/src/style/themes/dark/tokens/_dark-theme.scss
@@ -0,0 +1,45 @@
+// Dark Theme
+// - Gray Semantics
+$eps-dark-gray-800: $color-gray-anthracite;
+$eps-dark-gray-700: $color-gray-metalise;
+$eps-dark-gray-600: $color-gray-napoleon;
+$eps-dark-gray-500: $color-gray-abbey;
+$eps-dark-gray-400: $color-gray-stone-hearth;
+$eps-dark-gray-300: $color-gray-silver-filigree;
+$eps-dark-gray-200: $color-gray-brainstem;
+$eps-dark-gray-100: $color-gray-yin-bai-silver;
+
+// Theme semantics
+// - data context
+$eps-dark-theme-text-muted: $eps-dark-gray-300;
+$eps-dark-theme-disabled: $eps-dark-gray-400;
+$eps-dark-theme-light: $color-white;
+$eps-dark-theme-dark: $color-black;
+$eps-dark-theme-info: $color-cyan-ionized-air-glow;
+$eps-dark-theme-accent: $color-cyan-ionized-air-glow;
+$eps-dark-theme-danger: $color-red-tomato-frog;
+$eps-dark-theme-cta: $color-red-rose-garnet;
+$eps-dark-theme-warning: $color-yellow-hot-sun;
+$eps-dark-theme-success: $color-green-spandex;
+// - use context
+$eps-dark-theme-body-color: $eps-dark-gray-100;
+$eps-dark-theme-body-bg: $eps-dark-theme-light;
+$eps-dark-theme-link-color: $color-cyan-ionized-air-glow;
+$eps-dark-theme-link-hover-color: darken($eps-link-color, 15%);
+$eps-dark-theme-hr-color: $eps-dark-gray-500;
+$eps-dark-theme-display-1-color: $eps-dark-gray-100;
+$eps-dark-theme-display-2-color: $eps-dark-gray-100;
+$eps-dark-theme-display-3-color: $eps-dark-gray-100;
+$eps-dark-theme-display-4-color: $eps-dark-gray-100;
+$eps-dark-theme-h1-color: $eps-dark-gray-100;
+$eps-dark-theme-h2-color: $eps-dark-gray-100;
+$eps-dark-theme-h3-color: $eps-dark-gray-100;
+$eps-dark-theme-h4-color: $eps-dark-gray-100;
+$eps-dark-theme-h5-color: $eps-dark-gray-100;
+$eps-dark-theme-h6-color: $eps-dark-gray-100;
+$eps-dark-theme-text-base-color: $eps-dark-gray-200;
+$eps-dark-theme-text-xl-color: $eps-dark-gray-200;
+$eps-dark-theme-text-lg-color: $eps-dark-gray-200;
+$eps-dark-theme-text-sm-color: $eps-dark-gray-200;
+$eps-dark-theme-text-xs-color: $eps-dark-gray-200;
+$eps-dark-theme-text-xxs-color: $eps-dark-gray-200;
diff --git a/packages/ui/src/style/themes/dark/tokens/maps/_dark-theme-map.scss b/packages/ui/src/style/themes/dark/tokens/maps/_dark-theme-map.scss
new file mode 100644
index 0000000..bbe3c83
--- /dev/null
+++ b/packages/ui/src/style/themes/dark/tokens/maps/_dark-theme-map.scss
@@ -0,0 +1,37 @@
+$eps-dark-theme-colors: (
+ text-muted:$eps-dark-theme-text-muted,
+ disabled: $eps-dark-theme-disabled,
+ light: $eps-dark-theme-light,
+ dark: $eps-dark-theme-dark,
+ info:$eps-dark-theme-info,
+ accent:$eps-dark-theme-accent,
+ danger: $eps-dark-theme-danger,
+ cta: $eps-dark-theme-cta,
+ success: $eps-dark-theme-success,
+ warning: $eps-dark-theme-warning,
+);
+
+$eps-dark-theme-elements-colors: (
+ body-color: $eps-dark-theme-body-color,
+ body-bg:$eps-dark-theme-body-bg,
+ link-color: $eps-dark-theme-link-color,
+ link-hover-color: $eps-dark-theme-link-hover-color,
+ hr-color: $eps-dark-theme-hr-color,
+ box-shadow-color: $eps-dark-box-shadow-color,
+ display-1-color:$eps-dark-theme-display-1-color,
+ display-2-color:$eps-dark-theme-display-2-color,
+ display-3-color:$eps-dark-theme-display-3-color,
+ display-4-color:$eps-dark-theme-display-4-color,
+ h1-color:$eps-dark-theme-h1-color,
+ h2-color:$eps-dark-theme-h2-color,
+ h3-color:$eps-dark-theme-h3-color,
+ h4-color:$eps-dark-theme-h4-color,
+ h5-color:$eps-dark-theme-h5-color,
+ h6-color:$eps-dark-theme-h6-color,
+ text-base-color:$eps-dark-theme-text-base-color,
+ text-xl-color:$eps-dark-theme-text-xl-color,
+ text-lg-color:$eps-dark-theme-text-lg-color,
+ text-sm-color:$eps-dark-theme-text-sm-color,
+ text-xs-color:$eps-dark-theme-text-xs-color,
+ text-xxs-color:$eps-dark-theme-text-xxs-color,
+)
diff --git a/packages/ui/src/style/themes/dark/tokens/maps/_dark-tints-map.scss b/packages/ui/src/style/themes/dark/tokens/maps/_dark-tints-map.scss
new file mode 100644
index 0000000..aa71dd1
--- /dev/null
+++ b/packages/ui/src/style/themes/dark/tokens/maps/_dark-tints-map.scss
@@ -0,0 +1,10 @@
+$eps-dark-tints: (
+ 800: $eps-dark-gray-800,
+ 700: $eps-dark-gray-700,
+ 600: $eps-dark-gray-600,
+ 500: $eps-dark-gray-500,
+ 400: $eps-dark-gray-400,
+ 300: $eps-dark-gray-300,
+ 200: $eps-dark-gray-200,
+ 100: $eps-dark-gray-100,
+);
diff --git a/packages/ui/src/style/themes/dark/tokens/styles/_dark-shadow.scss b/packages/ui/src/style/themes/dark/tokens/styles/_dark-shadow.scss
new file mode 100644
index 0000000..8043bc7
--- /dev/null
+++ b/packages/ui/src/style/themes/dark/tokens/styles/_dark-shadow.scss
@@ -0,0 +1,2 @@
+// TOKENS STYLES: DARK SHADOW presets
+$eps-dark-box-shadow-color: rgba($eps-dark-theme-dark, $opacity-015);
diff --git a/packages/ui/src/style/tokens/_colors.scss b/packages/ui/src/style/tokens/_colors.scss
new file mode 100644
index 0000000..3504669
--- /dev/null
+++ b/packages/ui/src/style/tokens/_colors.scss
@@ -0,0 +1,40 @@
+// COLORS: colors registration, semantics and maps
+// Flow:
+// - register hex value as unique names (aliases)
+// - comment color rgb,hsl values for further check
+// - assign aliases to semantics
+// - create color map with aliases as key, values
+// - create semantic map with semantics as key, values
+// -- eg: (malibu: $color-stack-malibu), (info:$brand-color-info)
+// Tooling:
+// https://www.color-hex.com/ get color specs
+// https://colornamer.robertcooper.me/ generate unique names
+
+// stacks: registered hex with unique names
+$color-white: #fff; // RGB (255,255,255), HSL(0, 0%, 100%)
+$color-black: #000; // RGB (0, 0, 0), HSL(0, 0%, 0%)
+$color-cyan-ionized-air-glow: #58d0f5; // RGB(88,208,245), HSL(0.54, 0.89, 0.65)
+$color-red-rose-garnet: #93003F; // RGB(211,12,92), HSL(0.93, 0.89, 0.44)
+$color-red-carnelian: #b01b1b; // RGB(176,27,27), HSL(0, 0.73, 0.40)
+$color-red-tomato-frog: #F84343; // RGB(248, 67, 67), HSL(0.00, 0.93, 0.62)
+$color-yellow-hot-sun: #fcb92c; // RGB(252, 185, 44), HSL(0.11, 0.97, 0.58)
+$color-green-spandex: #39b54a; // RGB(57, 181, 74), HSL(0.36, 0.52, 0.47)
+
+// GRAYS
+// - Sorted by lightness , from dark to light
+$color-gray-anthracite: #26292C; // RGB(38, 41, 44) HSL(0.58, 0.07, 0.16) $theme-dark-dark $eps-dark-gray-800
+$color-gray-metalise: #34383c; // RGB(52, 56, 60) HSL(0.58, 0.07, 0.22) $theme-dark-gray-darkest $eps-dark-gray-700
+$color-gray-napoleon: #404349; // RGB(64, 67, 73) HSL(0.61, 0.07, 0.27) $theme-dark-gray-dark $eps-dark-gray-600
+$color-gray-lamp-post: #495157; // RGB(73, 81, 87) HSL(0.57, 0.09, 0.31) $editor-darkest $eps-gray-800
+$color-gray-abbey: #4c4f56; // RGB(76, 79, 86) HSL(0.62, 0.06, 0.32) $theme-dark-gray $eps-dark-gray-500
+$color-gray-blue-planet: #556068; // RGB(85, 96, 104) HSL(0.57, 0.10, 0.37) $editor-darker $eps-gray-700
+$color-gray-stone-hearth: #64666a; // RGB(100, 102, 106) HSL(0.61, 0.03, 0.40) $theme-dark-gray-light $eps-dark-gray-400
+$color-gray-sheffield: #6d7882; // RGB(109, 120, 130) HSL(0.58, 0.09, 0.47) $editor-dark $eps-gray-600
+$color-gray-silver-filigree: #7d7e82; // RGB(125, 126, 130) HSL(0.63, 0.02, 0.50) $theme-dark-gray-lighter $eps-dark-gray-300
+$color-gray-special-delivery: #a4afb7; // RGB(164, 175, 183) HSL(0.57, 0.12, 0.68) $editor-light $eps-gray-500
+$color-gray-brainstem: #b4b5b7; // RGB(180, 181, 183) HSL(0.61, 0.02, 0.71) $theme-dark-gray-lightest $eps-dark-gray-200
+$color-gray-stone-golem: #c2cbd2; // RGB(194, 203, 210) HSL(0.57, 0.15, 0.79) $editor-lighter $eps-gray-400
+$color-gray-hidden-creek: #d5dadf; // RGB(213, 218, 223) HSL(0.58, 0.14, 0.85) $editor-lightest $eps-gray-300
+$color-gray-yin-bai-silver: #e0e1e3; // RGB(224, 225, 227) HSL(0.61, 0.05, 0.88) $theme-dark-light $eps-dark-gray-100
+$color-gray-anti-flash: #f1f3f5; // RGB(241, 243, 245) HSL(0.58, 0.17, 0.95) $editor-background-light $eps-gray-200
+$color-gray-emptiness: #fcfcfc; // RGB(252, 252, 252) HSL(0, 0, 0.99) $editor-background-lighter $eps-gray-100
diff --git a/packages/ui/src/style/tokens/_font.scss b/packages/ui/src/style/tokens/_font.scss
new file mode 100644
index 0000000..8fc21ca
--- /dev/null
+++ b/packages/ui/src/style/tokens/_font.scss
@@ -0,0 +1,22 @@
+// Font
+//$eps-font-weight-thin: 200;
+//$eps-font-weight-light: 300;
+$eps-font-weight-normal: 400;
+$eps-font-weight-medium: 500;
+$eps-font-weight-bold: 700;
+$eps-font-weight-base: $eps-font-weight-normal;
+
+//font face names
+$font-src-roboto: 'roboto';
+
+// generic, check if exist
+$font-family-monospace: monospace;
+$font-family-roboto: Roboto;
+$font-family-arial: Arial;
+$font-family-helvetica: Helvetica;
+$font-family-verdana: Verdana;
+
+$eps-font-family-code: $font-family-monospace;
+$eps-font-family-fallback: sans-serif;
+$eps-font-family-base: $font-family-roboto, $font-family-arial, $font-family-helvetica, $font-family-verdana;
+$eps-font-family: $eps-font-family-base, $eps-font-family-fallback;
diff --git a/packages/ui/src/style/tokens/_global.scss b/packages/ui/src/style/tokens/_global.scss
new file mode 100644
index 0000000..32097af
--- /dev/null
+++ b/packages/ui/src/style/tokens/_global.scss
@@ -0,0 +1,7 @@
+$eps-prefix: prefix(eps);
+
+$eps-link-decoration: none;
+$eps-link-hover-decoration: none;
+
+$eps-hover-state-operator: 5%;
+$eps-active-state-operator: 5%;
diff --git a/packages/ui/src/style/tokens/_map-functions.scss b/packages/ui/src/style/tokens/_map-functions.scss
new file mode 100644
index 0000000..ed9b399
--- /dev/null
+++ b/packages/ui/src/style/tokens/_map-functions.scss
@@ -0,0 +1,38 @@
+// Tokens: map functions
+// - Simple 'get' mechanizm hardcoded to scoped maps.
+@function spacing($keys...) {
+ @return map-deep-get($eps-spacers, $keys...);
+}
+
+// Below functions can be duplicated and modified for Themes
+@function theme-colors($keys...) {
+ @return map-deep-get($eps-theme-colors, $keys...);
+}
+
+@function tints($keys...) {
+ @return map-deep-get($eps-tints, $keys...);
+}
+
+@function theme-elements-colors($keys...) {
+ @return map-deep-get($eps-theme-elements-colors, $keys...);
+}
+
+@function type($keys...) {
+ @return map-deep-get($eps-type-map, $keys...);
+}
+
+@function z-index($keys...) {
+ @return map-deep-get($eps-z-index-levels, $keys...);
+}
+
+@function opacity($keys...) {
+ @return map-deep-get($eps-opacity-map, $keys...);
+}
+
+@function shadow($keys...) {
+ @return map-deep-get($eps-shadow-map, $keys...);
+}
+
+@function atomizer($keys...){
+ @return map-deep-get($eps-atoms,$keys...);
+};
diff --git a/packages/ui/src/style/tokens/_opacity.scss b/packages/ui/src/style/tokens/_opacity.scss
new file mode 100644
index 0000000..a3df735
--- /dev/null
+++ b/packages/ui/src/style/tokens/_opacity.scss
@@ -0,0 +1,7 @@
+$opacity-08: 0.8;
+$opacity-05: 0.5;
+$opacity-03: 0.3;
+$opacity-02: 0.2;
+$opacity-015: 0.15;
+$opacity-01: 0.1;
+$opacity-005: 0.05;
diff --git a/packages/ui/src/style/tokens/_ratio.scss b/packages/ui/src/style/tokens/_ratio.scss
new file mode 100644
index 0000000..33351a7
--- /dev/null
+++ b/packages/ui/src/style/tokens/_ratio.scss
@@ -0,0 +1,13 @@
+// Ratio
+
+$ratio-portrait: 0.956 * 100%;
+$eps-ratio-16-9: 100% / 16 * 9;
+
+$embed-responsive-aspect-ratios: () !default;
+// stylelint-disable-next-line scss/dollar-variable-default
+$embed-responsive-aspect-ratios: join( (
+ (21 9),
+ (16 9),
+ (4 3),
+ (1 1),
+), $embed-responsive-aspect-ratios );
diff --git a/packages/ui/src/style/tokens/_spacing.scss b/packages/ui/src/style/tokens/_spacing.scss
new file mode 100644
index 0000000..8a6efc5
--- /dev/null
+++ b/packages/ui/src/style/tokens/_spacing.scss
@@ -0,0 +1 @@
+$eps-spacer: 0.5rem;
diff --git a/packages/ui/src/style/tokens/_theme.scss b/packages/ui/src/style/tokens/_theme.scss
new file mode 100644
index 0000000..9f86460
--- /dev/null
+++ b/packages/ui/src/style/tokens/_theme.scss
@@ -0,0 +1,48 @@
+// Default, Light Theme
+// - Gray Semantics
+$eps-gray-800: $color-gray-lamp-post;
+$eps-gray-700: $color-gray-blue-planet;
+$eps-gray-600: $color-gray-sheffield;
+$eps-gray-500: $color-gray-special-delivery;
+$eps-gray-400: $color-gray-stone-golem;
+$eps-gray-300: $color-gray-hidden-creek;
+$eps-gray-200: $color-gray-anti-flash;
+$eps-gray-100: $color-gray-emptiness;
+
+// Theme semantics
+// - data context
+$eps-theme-text-muted: $eps-gray-300;
+$eps-theme-disabled: $eps-gray-400;
+//
+$eps-theme-light: $color-white;
+$eps-theme-dark: $color-black;
+//
+$eps-theme-info: $color-cyan-ionized-air-glow;
+$eps-theme-accent: $color-cyan-ionized-air-glow;
+$eps-theme-danger: $color-red-carnelian;
+$eps-theme-cta: $color-red-rose-garnet;
+$eps-theme-warning: $color-yellow-hot-sun;
+$eps-theme-success: $color-green-spandex;
+
+// -use context
+$eps-body-color: $eps-gray-600;
+$eps-body-bg: null;
+$eps-link-color: $color-cyan-ionized-air-glow;
+$eps-link-hover-color: darken($eps-link-color, 15%);
+$eps-hr-color: $eps-gray-300;
+$eps-display-1-color: $eps-gray-800;
+$eps-display-2-color: $eps-gray-800;
+$eps-display-3-color: $eps-gray-600;
+$eps-display-4-color: $eps-gray-800;
+$eps-h1-color: $eps-gray-600;
+$eps-h2-color: $eps-gray-600;
+$eps-h3-color: $eps-gray-800;
+$eps-h4-color: $eps-gray-800;
+$eps-h5-color: $eps-gray-800;
+$eps-h6-color: $eps-gray-800;
+$eps-text-base-color: $eps-gray-800;
+$eps-text-xl-color: $eps-gray-800;
+$eps-text-lg-color: $eps-gray-800;
+$eps-text-sm-color: $eps-gray-800;
+$eps-text-xs-color: $eps-gray-800;
+$eps-text-xxs-color: $eps-gray-800;
diff --git a/packages/ui/src/style/tokens/_type.scss b/packages/ui/src/style/tokens/_type.scss
new file mode 100644
index 0000000..c480773
--- /dev/null
+++ b/packages/ui/src/style/tokens/_type.scss
@@ -0,0 +1,53 @@
+// TYPE
+$eps-font-size-base: 1rem;
+
+// Font sizes registration
+$font-size-10: (0.625 * $eps-font-size-base); //~10px
+$font-size-11: (0.6875 * $eps-font-size-base); //~11px
+$font-size-12: (0.75 * $eps-font-size-base); //~12px
+$font-size-13: (0.8125 * $eps-font-size-base); //~13px
+$font-size-14: (0.875 * $eps-font-size-base); //~14px
+$font-size-15: (0.9375 * $eps-font-size-base); //~15px
+$font-size-18: (1.125 * $eps-font-size-base); //~18px
+$font-size-20: (1.25 * $eps-font-size-base); //~20px
+$font-size-26: (1.625 * $eps-font-size-base); //~26
+$font-size-30: (1.85 * $eps-font-size-base); //~30px
+
+// Line heights
+// Registration (temps)
+$line-height-2: 2; // [$card-headline-line-height,];
+
+// Semantics
+$eps-line-height-flat: 1; //can be hardcoded as 1
+$eps-line-height-base: 1.5;
+$eps-line-height-sm: 1.2;
+$eps-line-height-lg: 1.8;
+
+// scale
+$eps-display-1-font-size: $font-size-30;
+$eps-display-2-font-size: $font-size-30;
+$eps-display-3-font-size: $font-size-30;
+$eps-display-4-font-size: $font-size-30;
+//
+$eps-h-1-font-size: $font-size-26;
+$eps-h-2-font-size: $font-size-20;
+$eps-h-3-font-size: $eps-font-size-base;
+$eps-h-4-font-size: $font-size-15;
+$eps-h-5-font-size: $font-size-14;
+$eps-h-6-font-size: $font-size-14;
+
+$eps-text-xl-font-size: $eps-font-size-base;//16px
+$eps-text-lg-font-size: $font-size-15;
+$eps-text-md-font-size: $font-size-14;
+$eps-text-sm-font-size: $font-size-13;
+$eps-text-xs-font-size: $font-size-12;
+$eps-text-xxs-font-size: $font-size-11;
+$eps-font-size-micro: $font-size-10; //10px
+
+$eps-body-font-size: $eps-text-md-font-size;
+$eps-font-size-caption: $eps-text-xs-font-size;
+//
+
+$eps-small-font-size: 80%;
+$eps-paragraph-margin-bottom: null;
+$eps-headings-margin-bottom: null;
diff --git a/packages/ui/src/style/tokens/_z-index.scss b/packages/ui/src/style/tokens/_z-index.scss
new file mode 100644
index 0000000..2805601
--- /dev/null
+++ b/packages/ui/src/style/tokens/_z-index.scss
@@ -0,0 +1,8 @@
+// Z-INDEX
+$eps-zindex-dropdown: 1000;
+$eps-zindex-sticky: 1010;
+$eps-zindex-fixed: 1020;
+$eps-zindex-modal-backdrop: 1030;
+$eps-zindex-modal: 1040;
+$eps-zindex-popover: 1050;
+$eps-zindex-tooltip: 1060;
diff --git a/packages/ui/src/style/tokens/maps/_atoms.scss b/packages/ui/src/style/tokens/maps/_atoms.scss
new file mode 100644
index 0000000..f388f3d
--- /dev/null
+++ b/packages/ui/src/style/tokens/maps/_atoms.scss
@@ -0,0 +1,181 @@
+$eps-atoms: (
+ typography:(
+ display:(
+ 1:(
+ font-size: $eps-display-1-font-size,
+ line-height:null,
+ color: var(--display-1-color),
+ margin-top: $eps-spacer,
+ margin-bottom: $eps-spacer,
+ font-familiy:null,
+ font-weight:null,
+ text-transform: null,
+ ),
+ 2:(
+ font-size: $eps-display-2-font-size,
+ line-height:null,
+ color: var(--display-2-color),
+ margin-top: $eps-spacer,
+ margin-bottom: $eps-spacer,
+ font-familiy:null,
+ font-weight:null,
+ font-style: null,
+ text-transform: null,
+ ),
+ 3:(
+ font-size: $eps-display-3-font-size,
+ line-height:null,
+ color: var(--display-3-color),
+ margin-top: $eps-spacer,
+ margin-bottom: $eps-spacer,
+ font-familiy:null,
+ font-weight:null,
+ font-style: null,
+ text-transform: null,
+ ),
+ 4:(
+ font-size: $eps-display-4-font-size,
+ line-height:null,
+ color: var(--display-4-color),
+ margin-top: $eps-spacer,
+ margin-bottom: $eps-spacer,
+ font-familiy:null,
+ font-weight:null,
+ font-style: null,
+ text-transform: null,
+ ),
+ ),
+ heading:(
+ 1:(
+ font-size: $eps-h-1-font-size,
+ line-height: $eps-line-height-flat,
+ color: var(--h1-color),
+ margin-top: null,
+ margin-bottom: 2.5 * $eps-spacer,
+ font-familiy:null,
+ font-weight: $eps-font-weight-medium,
+ font-style: null,
+ text-transform: null,
+ ),
+ 2:(
+ font-size: $eps-h-2-font-size,
+ line-height: $eps-line-height-sm,
+ color: var(--h2-color),
+ margin-top: 0,
+ margin-bottom: 2.5 * $eps-spacer,
+ font-familiy: null,
+ font-weight: $eps-font-weight-medium,
+ font-style: null,
+ text-transform: null,
+ ),
+ 3:(
+ font-size: $eps-h-3-font-size,
+ line-height:$eps-line-height-sm,
+ color: var(--h3-color),
+ margin-top: 0,
+ margin-bottom: 2 * $eps-spacer,
+ font-familiy:null,
+ font-weight:$eps-font-weight-medium,
+ font-style: null,
+ text-transform: null,
+ ),
+ 4:(
+ font-size: $eps-h-4-font-size,
+ line-height:null,
+ color: var(--h4-color),
+ margin-top: 0,
+ margin-bottom: $eps-spacer,
+ font-familiy:null,
+ font-weight:null,
+ font-style: null,
+ text-transform: null,
+ ),
+ 5:(
+ font-size: $eps-h-5-font-size,
+ line-height:null,
+ color: var(--h5-color),
+ margin-top: 0,
+ margin-bottom: $eps-spacer,
+ font-familiy:null,
+ font-weight:null,
+ text-transform: null,
+ ),
+ 6:(
+ font-size: $eps-h-6-font-size,
+ line-height:null,
+ color: var(--h-6-color),
+ margin-top: 0,
+ margin-bottom: $eps-spacer,
+ font-familiy:null,
+ font-weight:$eps-font-weight-bold,
+ text-transform: null,
+ ),
+ ),
+ text:(
+ base:(
+ font-size:$eps-body-font-size,
+ line-height:$eps-line-height-base,
+ color: var(--text-base-color),
+ margin-top: null,
+ margin-bottom:null,
+ font-familiy:null,
+ font-weight:$eps-font-weight-normal,
+ ),
+ xl:(
+ font-size:$eps-text-xl-font-size,
+ line-height:$eps-line-height-base,
+ color: var(--text-xl-color),
+ margin-top: null,
+ margin-bottom:null,
+ font-familiy:null,
+ font-weight:$eps-font-weight-normal,
+ ),
+ lg:(
+ font-size:$eps-text-lg-font-size,
+ line-height:$eps-line-height-base,
+ color: var(--text-lg-color),
+ margin-top: null,
+ margin-bottom:null,
+ font-familiy:null,
+ font-weight:$eps-font-weight-normal,
+ ),
+ md:(
+ font-size:$eps-text-md-font-size,
+ line-height:$eps-line-height-base,
+ color: var(--text-md-color),
+ margin-top: null,
+ margin-bottom:null,
+ font-familiy:null,
+ font-weight:$eps-font-weight-normal,
+ ),
+ sm:(
+ font-size:$eps-text-sm-font-size,
+ line-height:$eps-line-height-base,
+ color: var(--text-sm-color),
+ margin-top: null,
+ margin-bottom:null,
+ font-familiy:null,
+ font-weight:$eps-font-weight-normal,
+ ),
+ xs:(
+ font-size:$eps-text-xs-font-size,
+ line-height:$eps-line-height-base,
+ color: var(--text-xs-color),
+ margin-top: null,
+ margin-bottom:null,
+ font-familiy:null,
+ font-weight:$eps-font-weight-normal,
+ ),
+ xxs:(
+ font-size:$eps-text-xs-font-size,
+ line-height:$eps-line-height-sm,
+ color: var(--text-xxs-color),
+ margin-top: null,
+ margin-bottom:null,
+ font-familiy:null,
+ font-weight:$eps-font-weight-normal,
+ ),
+ ),
+ )
+);
+
diff --git a/packages/ui/src/style/tokens/maps/_opacity-map.scss b/packages/ui/src/style/tokens/maps/_opacity-map.scss
new file mode 100644
index 0000000..5009366
--- /dev/null
+++ b/packages/ui/src/style/tokens/maps/_opacity-map.scss
@@ -0,0 +1,11 @@
+$eps-opacity-map: (
+ "1": 1,
+ "08": $opacity-08,
+ "05": $opacity-05,
+ "03": $opacity-03,
+ "02": $opacity-02,
+ "015": $opacity-015,
+ "01": $opacity-01,
+ "005":$opacity-005,
+ "0": 0,
+);
diff --git a/packages/ui/src/style/tokens/maps/_shadow-map.scss b/packages/ui/src/style/tokens/maps/_shadow-map.scss
new file mode 100644
index 0000000..9a0c4f2
--- /dev/null
+++ b/packages/ui/src/style/tokens/maps/_shadow-map.scss
@@ -0,0 +1,4 @@
+$eps-shadow-map: (
+ "1": $eps-box-shadow,
+ "2": $eps-box-shadow-2,
+);
diff --git a/packages/ui/src/style/tokens/maps/_spacing-map.scss b/packages/ui/src/style/tokens/maps/_spacing-map.scss
new file mode 100644
index 0000000..5e4b6ec
--- /dev/null
+++ b/packages/ui/src/style/tokens/maps/_spacing-map.scss
@@ -0,0 +1,12 @@
+$eps-spacers: (
+ 0: 0,
+ 5: $eps-spacer * 0.625,
+ 8: $eps-spacer,
+ 10: $eps-spacer * 1.25,
+ 12: $eps-spacer * 1.5,
+ 16: $eps-spacer * 2,
+ 20: $eps-spacer * 2.5,
+ 24: $eps-spacer * 3,
+ 30: $eps-spacer * 3.75,
+ 44: $eps-spacer * 5.5,
+);
diff --git a/packages/ui/src/style/tokens/maps/_theme-map.scss b/packages/ui/src/style/tokens/maps/_theme-map.scss
new file mode 100644
index 0000000..48356cc
--- /dev/null
+++ b/packages/ui/src/style/tokens/maps/_theme-map.scss
@@ -0,0 +1,36 @@
+$eps-theme-colors: (
+ text-muted:$eps-theme-text-muted,
+ disabled: $eps-theme-disabled,
+ light: $eps-theme-light,
+ dark: $eps-theme-dark,
+ info: $eps-theme-info,
+ cta: $eps-theme-cta,
+ danger: $eps-theme-danger,
+ success: $eps-theme-success,
+ warning: $eps-theme-warning,
+);
+
+$eps-theme-elements-colors: (
+ body-color: $eps-body-color,
+ body-bg:$eps-body-bg,
+ link-color: $eps-link-color,
+ link-hover-color: $eps-link-hover-color,
+ hr-color: $eps-hr-color,
+ box-shadow-color: $eps-box-shadow-color,
+ display-1-color:$eps-display-1-color,
+ display-2-color:$eps-display-2-color,
+ display-3-color:$eps-display-3-color,
+ display-4-color:$eps-display-4-color,
+ h1-color:$eps-h1-color,
+ h2-color:$eps-h2-color,
+ h3-color:$eps-h3-color,
+ h4-color:$eps-h4-color,
+ h5-color:$eps-h5-color,
+ h6-color:$eps-h6-color,
+ text-base-color:$eps-text-base-color,
+ text-xl-color:$eps-text-xl-color,
+ text-lg-color:$eps-text-lg-color,
+ text-sm-color:$eps-text-sm-color,
+ text-xs-color:$eps-text-xs-color,
+ text-xxs-color:$eps-text-xxs-color,
+)
diff --git a/packages/ui/src/style/tokens/maps/_tints-map.scss b/packages/ui/src/style/tokens/maps/_tints-map.scss
new file mode 100644
index 0000000..2fdcd39
--- /dev/null
+++ b/packages/ui/src/style/tokens/maps/_tints-map.scss
@@ -0,0 +1,11 @@
+// Maps
+$eps-tints: (
+ 800: $eps-gray-800,
+ 700: $eps-gray-700,
+ 600: $eps-gray-600,
+ 500: $eps-gray-500,
+ 400: $eps-gray-400,
+ 300: $eps-gray-300,
+ 200: $eps-gray-200,
+ 100: $eps-gray-100,
+);
diff --git a/packages/ui/src/style/tokens/maps/_type-map.scss b/packages/ui/src/style/tokens/maps/_type-map.scss
new file mode 100644
index 0000000..7dd8290
--- /dev/null
+++ b/packages/ui/src/style/tokens/maps/_type-map.scss
@@ -0,0 +1,46 @@
+$eps-type-map: (
+ size:(
+ base: $eps-font-size-base,
+ "11": $font-size-11,
+ "12": $font-size-12,
+ "13": $font-size-13,
+ "14": $font-size-14,
+ "15": $font-size-15,
+ "18": $font-size-18,
+ "20": $font-size-20,
+ "26": $font-size-26,
+ "30": $font-size-30,
+ ),
+ line-height:(
+ "2":$line-height-2,
+ flat:$eps-line-height-flat,
+ base:$eps-line-height-base,
+ sm:$eps-line-height-sm,
+ lg:$eps-line-height-lg,
+ ),
+ display:(
+ "1":$eps-display-1-font-size,
+ "2":$eps-display-2-font-size,
+ "3":$eps-display-3-font-size,
+ "4":$eps-display-4-font-size,
+ ),
+ h:(
+ "1":$eps-h-1-font-size,
+ "2":$eps-h-2-font-size,
+ "3":$eps-h-3-font-size,
+ "4":$eps-h-4-font-size,
+ "5":$eps-h-5-font-size,
+ "6":$eps-h-6-font-size,
+ ),
+ text:(
+ base:$eps-font-size-base,
+ xxs:$eps-text-xxs-font-size,
+ xs:$eps-text-xs-font-size,
+ sm:$eps-text-sm-font-size,
+ md:$eps-text-md-font-size,
+ lg:$eps-text-lg-font-size,
+ xl:$eps-text-xl-font-size,
+ ),
+ caption: $eps-font-size-caption,
+ micro: $eps-font-size-micro,
+);
diff --git a/packages/ui/src/style/tokens/maps/_z-index-map.scss b/packages/ui/src/style/tokens/maps/_z-index-map.scss
new file mode 100644
index 0000000..5fc2da0
--- /dev/null
+++ b/packages/ui/src/style/tokens/maps/_z-index-map.scss
@@ -0,0 +1,10 @@
+// Maps: z-index map
+$eps-z-index-levels: (
+ dropdown:$eps-zindex-dropdown,
+ sticky: $eps-zindex-sticky,
+ fixed:$eps-zindex-fixed,
+ backdrop: $eps-zindex-modal-backdrop,
+ modal: $eps-zindex-modal,
+ popover: $eps-zindex-popover,
+ tooltip: $eps-zindex-tooltip,
+);
diff --git a/packages/ui/src/style/tokens/styles/_border.scss b/packages/ui/src/style/tokens/styles/_border.scss
new file mode 100644
index 0000000..e24a5a3
--- /dev/null
+++ b/packages/ui/src/style/tokens/styles/_border.scss
@@ -0,0 +1,14 @@
+// EDS border tokens
+$border-style-solid: solid;
+$border-style-dashed: dashed;
+$border-style-dotted: dotted;
+
+$eps-border-style: $border-style-solid;
+$eps-border-width: 1px;
+$eps-border-width-md: 2px;
+$eps-border-width-lg: 3px;
+
+$eps-border-color: $eps-gray-200;
+$eps-border-color-light: lighten($eps-border-color, 10%);
+
+$eps-border: $eps-border-width $eps-border-style $eps-border-color;
diff --git a/packages/ui/src/style/tokens/styles/_motion.scss b/packages/ui/src/style/tokens/styles/_motion.scss
new file mode 100644
index 0000000..eebebe8
--- /dev/null
+++ b/packages/ui/src/style/tokens/styles/_motion.scss
@@ -0,0 +1,6 @@
+// Motion
+
+$duration-03s: 0.3s;
+
+//
+$eps-transition-duration: $duration-03s;
diff --git a/packages/ui/src/style/tokens/styles/_radius.scss b/packages/ui/src/style/tokens/styles/_radius.scss
new file mode 100644
index 0000000..1258392
--- /dev/null
+++ b/packages/ui/src/style/tokens/styles/_radius.scss
@@ -0,0 +1,7 @@
+// EDS radius tokens
+$eps-radius: .1875rem;//~3px
+$eps-radius-sm: .125rem;//~2px
+//$eps-radius-md: .375rem;//~6px
+//$eps-radius-lg: .5rem;//~8px
+$eps-radius-pill: 50rem;
+$eps-radius-round: 50%;
diff --git a/packages/ui/src/style/tokens/styles/_shadow.scss b/packages/ui/src/style/tokens/styles/_shadow.scss
new file mode 100644
index 0000000..40136d1
--- /dev/null
+++ b/packages/ui/src/style/tokens/styles/_shadow.scss
@@ -0,0 +1,26 @@
+// TOKENS STYLES: SHADOW presets
+
+$eps-box-shadow-alpha-unit: 0.05;
+
+$eps-box-shadow-color: $eps-theme-dark;
+$eps-box-shadow-size: 0 3px 6px;
+$eps-box-shadow-size-1: 0 2px 3px 1px;
+$eps-box-shadow-size-2: 0 4px 10px;
+$eps-box-shadow-size-3: 2px 8px 23px 3px;
+
+$eps-box-shadow-alpha-unit-dark: 0.15;
+
+:root {
+ --color-box-shadow-color: rgba(0, 0, 0, 0.05);
+}
+
+.eps-theme-dark {
+ --color-box-shadow-color: rgba(0, 0, 0, 0.1);
+}
+
+// shadow presets
+// todo: temp values, map to semantics when semantics (use casing) is concluded.
+$eps-box-shadow: $eps-box-shadow-size var(--color-box-shadow-color);
+$eps-box-shadow-1: $eps-box-shadow-size-1 var(--color-box-shadow-color);
+$eps-box-shadow-2: $eps-box-shadow-size-2 var(--color-box-shadow-color);
+$eps-box-shadow-3: $eps-box-shadow-size-3 var(--color-box-shadow-color);
diff --git a/packages/ui/src/utils.js b/packages/ui/src/utils.js
new file mode 100644
index 0000000..e61ccfd
--- /dev/null
+++ b/packages/ui/src/utils.js
@@ -0,0 +1,18 @@
+export function pxToRem(pixels) {
+ if (!pixels) {
+ return;
+ }
+
+ return `${pixels * 0.0625}rem`;
+}
+
+export function arrayToClassName(array) {
+ return array.filter((classItem) => '' !== classItem).join(' ');
+}
+
+export function stringToRemValues(string) {
+ return string
+ .split(' ')
+ .map((value) => pxToRem(value))
+ .join(' ');
+}